From 3ca4e997f197eeeb6befca19ae398e785790c5bf Mon Sep 17 00:00:00 2001 From: "alqahira%ardisson.org" Date: Tue, 16 Dec 2008 03:39:25 +0000 Subject: [PATCH] Bug 418359 - Start drag of background tabs with one click. Patch by Stuart Morgan , r=murph, sr=pink git-svn-id: svn://10.0.0.236/trunk@255533 18797224-902f-48f8-a5cc-f745e15eee43 --- .../camino/src/browser/BrowserTabBarView.h | 7 +- .../camino/src/browser/BrowserTabBarView.mm | 87 +++++++++++++------ mozilla/camino/src/browser/BrowserTabView.h | 5 +- mozilla/camino/src/browser/BrowserTabView.mm | 19 ++-- .../src/browser/BrowserWindowController.mm | 4 +- 5 files changed, 81 insertions(+), 41 deletions(-) diff --git a/mozilla/camino/src/browser/BrowserTabBarView.h b/mozilla/camino/src/browser/BrowserTabBarView.h index 99bd35f0d81..51c65b55e97 100644 --- a/mozilla/camino/src/browser/BrowserTabBarView.h +++ b/mozilla/camino/src/browser/BrowserTabBarView.h @@ -80,8 +80,11 @@ NSMutableArray* mCurrentlySlidingTabs; // strong } -// destroy the tab bar and recreate it from the tabview --(void)rebuildTabBar; +// Should be called when the number, order, or visible range of tabs is changed. +- (void)tabStructureChanged; +// Should be called when only the selected tab has changed. +- (void)tabSelectionChanged; + // return the height the tab bar should be -(float)tabBarHeight; -(BrowserTabViewItem*)tabViewItemAtPoint:(NSPoint)location; diff --git a/mozilla/camino/src/browser/BrowserTabBarView.mm b/mozilla/camino/src/browser/BrowserTabBarView.mm index 115a9e7242f..8050882f81d 100644 --- a/mozilla/camino/src/browser/BrowserTabBarView.mm +++ b/mozilla/camino/src/browser/BrowserTabBarView.mm @@ -56,9 +56,17 @@ #import "NSView+Utils.h" #import "CHSlidingViewAnimation.h" + +enum ETabRebuildReason { + kTabRebuildForSelectionChange, + kTabRebuildForStructureChange +}; + @interface BrowserTabBarView(TabBarViewPrivate) --(void)layoutButtonsPreservingVisibility:(BOOL)preserveVisibility; +-(void)rebuildTabBar:(ETabRebuildReason)reason; +-(void)layoutButtonsPreservingVisibility:(BOOL)preserveVisibility + forChange:(ETabRebuildReason)reason; -(void)loadImages; -(void)drawTabBarBackgroundInRect:(NSRect)rect withActiveTabRect:(NSRect)tabRect; -(void)drawTabBarBackgroundHiliteRectInRect:(NSRect)rect; @@ -113,7 +121,7 @@ const int kEscapeKeyCode = 53; if (self) { mOverflowTabs = NO; // this will not likely have any result here - [self rebuildTabBar]; + [self tabStructureChanged]; [self registerForDraggedTypes:[NSArray arrayWithObjects: kCaminoBookmarkListPBoardType, kWebURLsWithTitlesPboardType, NSStringPboardType, @@ -133,7 +141,7 @@ const int kEscapeKeyCode = 53; // start off with the tabs hidden, and allow our controller to show or hide as appropriate. [self setVisible:NO]; // this needs to be called again since our tabview should be non-nil now - [self rebuildTabBar]; + [self tabStructureChanged]; // When background tabs are finished sliding around the dragging one, we need to perform // certain actions like updating the divider images. [[NSNotificationCenter defaultCenter] addObserver:self @@ -199,7 +207,7 @@ const int kEscapeKeyCode = 53; [super setFrame:frameRect]; // tab buttons probably need to be resized if the frame changes [self unregisterTabButtonsForTracking]; - [self layoutButtonsPreservingVisibility:YES]; + [self layoutButtonsPreservingVisibility:YES forChange:kTabRebuildForStructureChange]; [self registerTabButtonsForTracking]; } @@ -384,9 +392,19 @@ const int kEscapeKeyCode = 53; mButtonDividerImage = [[NSImage imageNamed:@"tab_button_divider"] retain]; } +- (void)tabStructureChanged +{ + [self rebuildTabBar:kTabRebuildForStructureChange]; +} + +- (void)tabSelectionChanged +{ + [self rebuildTabBar:kTabRebuildForSelectionChange]; +} + // construct the tab bar based on the current state of mTabView; // should be called when tabs are first shown. --(void)rebuildTabBar +-(void)rebuildTabBar:(ETabRebuildReason)reason; { if ([self tabIsCurrentlyDragging]) return; @@ -394,7 +412,7 @@ const int kEscapeKeyCode = 53; [self loadImages]; [self unregisterTabButtonsForTracking]; - [self layoutButtonsPreservingVisibility:NO]; + [self layoutButtonsPreservingVisibility:NO forChange:reason]; [self registerTabButtonsForTracking]; [self updateKeyViewLoop]; } @@ -506,11 +524,13 @@ const int kEscapeKeyCode = 53; // remain visible in the new layout if it was previously. If it is NO, then the // tab may or may not stay visible in the new layout. -(void)layoutButtonsPreservingVisibility:(BOOL)preserveVisibility + forChange:(ETabRebuildReason)reason { // before changing anything, get information about the current state BrowserTabViewItem* selectedTab = (BrowserTabViewItem*)[mTabView selectedTabViewItem]; int selectedTabIndex = selectedTab ? [mTabView indexOfTabViewItem:selectedTab] : -1; + int oldLeftmostTabIndex = mLeftMostVisibleTabIndex; // if we aren't currently overflowing, or we were asked to preserve the // visibility of the current tab, make sure the current tab stays visible. BOOL keepCurrentTabVisible = !mOverflowTabs || @@ -527,7 +547,7 @@ const int kEscapeKeyCode = 53; mNumberOfVisibleTabs = (int)floor(widthOfTabBar / kMinTabWidth); widthOfATab = floor(widthOfTabBar / mNumberOfVisibleTabs); if (mNumberOfVisibleTabs + mLeftMostVisibleTabIndex > numberOfTabs) - [self setLeftmostVisibleTabIndex:(numberOfTabs - mNumberOfVisibleTabs)]; + [self scrollTabIndexToVisible:(numberOfTabs - mNumberOfVisibleTabs)]; if (keepCurrentTabVisible && selectedTab) [self scrollTabIndexToVisible:selectedTabIndex]; } @@ -537,14 +557,23 @@ const int kEscapeKeyCode = 53; widthOfATab = (widthOfATab > kMaxTabWidth ? kMaxTabWidth : widthOfATab); } - [self removeAllSubviews]; - [self setOverflowButtonsVisible:mOverflowTabs]; + // If we are doing nothing but changing the selection (without changing the + // visible tabs as a result), we don't need to do a full reconstruction. + BOOL needsFullRebuild = (reason == kTabRebuildForStructureChange) || + (mLeftMostVisibleTabIndex != oldLeftmostTabIndex); - NSRect tabsRect = [self tabsRect]; float extraWidth = 0.0; - if (widthOfATab < kMaxTabWidth) - extraWidth = NSWidth(tabsRect) - widthOfATab * mNumberOfVisibleTabs; - float nextTabXOrigin = NSMinX(tabsRect); + float nextTabXOrigin = 0.0; + if (needsFullRebuild) { + [self removeAllSubviews]; + [self setOverflowButtonsVisible:mOverflowTabs]; + + NSRect tabsRect = [self tabsRect]; + if (widthOfATab < kMaxTabWidth) + extraWidth = NSWidth(tabsRect) - widthOfATab * mNumberOfVisibleTabs; + nextTabXOrigin = NSMinX(tabsRect); + } + for (int i = 0; i < numberOfTabs; i++) { TabButtonView* tabButton = [(BrowserTabViewItem*)[mTabView tabViewItemAtIndex:i] buttonView]; @@ -552,17 +581,23 @@ const int kEscapeKeyCode = 53; if (i < mLeftMostVisibleTabIndex || i >= mLeftMostVisibleTabIndex + mNumberOfVisibleTabs) continue; - [self addSubview:tabButton]; - NSRect tabRect = NSMakeRect(nextTabXOrigin, 0, widthOfATab, [self tabBarHeight]); - // spread the extra width from rounding tab sizes over the leftmost tabs. - if (extraWidth > 0.5) { - extraWidth -= 1.0; - tabRect.size.width += 1.0; + if (needsFullRebuild) { + [self addSubview:tabButton]; + NSRect tabRect = NSMakeRect(nextTabXOrigin, 0, widthOfATab, [self tabBarHeight]); + // spread the extra width from rounding tab sizes over the leftmost tabs. + if (extraWidth > 0.5) { + extraWidth -= 1.0; + tabRect.size.width += 1.0; + } + [tabButton setFrame:tabRect]; + nextTabXOrigin += NSWidth(tabRect); + } else { + // Tab buttons expect setFrame: to be called whenever their selection + // state changes, so call it even when it's not otherwise necessary. + [tabButton setFrame:[tabButton frame]]; } - [tabButton setFrame:tabRect]; [tabButton setDrawsLeftDivider:NO]; [tabButton setDrawsRightDivider:YES]; - nextTabXOrigin += NSWidth(tabRect); } if (selectedTab) { @@ -727,7 +762,7 @@ const int kEscapeKeyCode = 53; { if (index != mLeftMostVisibleTabIndex) { mLeftMostVisibleTabIndex = index; - [self rebuildTabBar]; + [self tabStructureChanged]; } } @@ -780,7 +815,7 @@ const int kEscapeKeyCode = 53; // only change anything if the new state is different from the current state if (show && [self isHidden]) { [self setHidden:NO]; - [self rebuildTabBar]; + [self tabStructureChanged]; // set up tracking rects [self registerTabButtonsForTracking]; } else if (!show && ![self isHidden]) { // being hidden @@ -1164,7 +1199,7 @@ const int kEscapeKeyCode = 53; [animatedTab setDrawsLeftDivider:NO]; if ([mCurrentlySlidingTabs count] == 0 && ![self tabIsCurrentlyDragging]) - [self performSelectorOnMainThread:@selector(rebuildTabBar) withObject:nil waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(tabStructureChanged) withObject:nil waitUntilDone:YES]; } // Called when the dragging tab has been released and is finished animating into its @@ -1181,7 +1216,7 @@ const int kEscapeKeyCode = 53; [self addSubview:mDraggingTab]; } else { - [self rebuildTabBar]; + [self tabStructureChanged]; } [[self window] removeChildWindow:mDraggingTabWindow]; @@ -1234,7 +1269,7 @@ const int kEscapeKeyCode = 53; [mDraggingTabWindow release]; mDraggingTabWindow = nil; - [self performSelector:@selector(rebuildTabBar) withObject:nil afterDelay:0.0]; + [self performSelector:@selector(tabStructureChanged) withObject:nil afterDelay:0.0]; } -(void)tabViewClosedTabViewItem:(BrowserTabViewItem*)closedTabViewItem atIndex:(int)indexOfClosedItem diff --git a/mozilla/camino/src/browser/BrowserTabView.h b/mozilla/camino/src/browser/BrowserTabView.h index 0fab9eab9aa..f7ac3e0fe42 100644 --- a/mozilla/camino/src/browser/BrowserTabView.h +++ b/mozilla/camino/src/browser/BrowserTabView.h @@ -63,6 +63,10 @@ extern NSString* const kTabBarBackgroundDoubleClickedNotification; - (BOOL)barAlwaysVisible; - (void)setBarAlwaysVisible:(BOOL)newSetting; +// Notification that the tab state has changed. +- (void)numberOfTabsChanged; +- (void)selectedTabChanged; + - (void)addTabForURL:(NSString*)aURL referrer:(NSString*)aReferrer inBackground:(BOOL)inBackground; - (BOOL)tabsVisible; @@ -70,7 +74,6 @@ extern NSString* const kTabBarBackgroundDoubleClickedNotification; - (int)numberOfBookmarkableTabViewItems; - (int)indexOfTabViewItemWithURL:(NSString*)aURL; - (BrowserTabViewItem*)itemWithTag:(int)tag; -- (void)refreshTabBar:(BOOL)rebuild; - (BOOL)isVisible; // inform the view that it will be shown or hidden; e.g. prior to showing or hiding the bookmarks - (void)setVisible:(BOOL)show; diff --git a/mozilla/camino/src/browser/BrowserTabView.mm b/mozilla/camino/src/browser/BrowserTabView.mm index 95bb84ca352..35f7259279a 100644 --- a/mozilla/camino/src/browser/BrowserTabView.mm +++ b/mozilla/camino/src/browser/BrowserTabView.mm @@ -215,17 +215,16 @@ NSString* const kTabBarBackgroundDoubleClickedNotification = @"kTabBarBackground /*** Instance Methods ***/ /******************************************/ -// redraws the tab bar, rebuilding it if instructed -- (void)refreshTabBar:(BOOL)rebuild +- (void)numberOfTabsChanged { - // don't bother if it's not even visible - if ([self tabsVisible]) { - if (rebuild) { - [mTabBar rebuildTabBar]; - } else { - [mTabBar setNeedsDisplay:YES]; - } - } + if ([self tabsVisible]) + [mTabBar tabStructureChanged]; +} + +- (void)selectedTabChanged +{ + if ([self tabsVisible]) + [mTabBar tabSelectionChanged]; } // Only to be used with the 2 types of tab view which we use in Camino. diff --git a/mozilla/camino/src/browser/BrowserWindowController.mm b/mozilla/camino/src/browser/BrowserWindowController.mm index 09c8a9b2abe..8f79467b29e 100644 --- a/mozilla/camino/src/browser/BrowserWindowController.mm +++ b/mozilla/camino/src/browser/BrowserWindowController.mm @@ -3616,7 +3616,7 @@ public: // Connect up the new view mBrowserView = [aTabViewItem view]; - [mTabBrowser refreshTabBar:YES]; + [mTabBrowser selectedTabChanged]; // Make the new view the primary content area. [mBrowserView setDelegate:self]; @@ -3642,7 +3642,7 @@ public: - (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)aTabView { [[NSApp delegate] delayedFixCloseMenuItemKeyEquivalents]; - [mTabBrowser refreshTabBar:YES]; + [mTabBrowser numberOfTabsChanged]; // paranoia, to avoid stale mBrowserView pointer (since we don't own it) if ([aTabView numberOfTabViewItems] == 0) mBrowserView = nil;