OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" | 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" |
6 | 6 |
7 #include "app/mac/nsimage_cache.h" | |
8 #include "base/mac/mac_util.h" | 7 #include "base/mac/mac_util.h" |
9 #include "base/sys_string_conversions.h" | 8 #include "base/sys_string_conversions.h" |
10 #include "chrome/browser/bookmarks/bookmark_model.h" | 9 #include "chrome/browser/bookmarks/bookmark_model.h" |
11 #include "chrome/browser/bookmarks/bookmark_utils.h" | 10 #include "chrome/browser/bookmarks/bookmark_utils.h" |
12 #import "chrome/browser/themes/browser_theme_provider.h" | 11 #import "chrome/browser/themes/browser_theme_provider.h" |
13 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" | 12 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" |
14 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" | 13 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" |
15 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h" | 14 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h" |
16 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h" | 15 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h" |
17 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h" | 16 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h" |
| 17 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h" |
18 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" | 18 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" |
19 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 19 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
20 #import "chrome/browser/ui/cocoa/event_utils.h" | 20 #import "chrome/browser/ui/cocoa/event_utils.h" |
21 | 21 |
| 22 using bookmarks::kBookmarkBarMenuCornerRadius; |
| 23 |
22 namespace { | 24 namespace { |
23 | 25 |
24 // Frequency of the scrolling timer in seconds. | 26 // Frequency of the scrolling timer in seconds. |
25 const NSTimeInterval kBookmarkBarFolderScrollInterval = 0.1; | 27 const NSTimeInterval kBookmarkBarFolderScrollInterval = 0.1; |
26 | 28 |
27 // Amount to scroll by per timer fire. We scroll rather slowly; to | 29 // Amount to scroll by per timer fire. We scroll rather slowly; to |
28 // accomodate we do several at a time. | 30 // accomodate we do several at a time. |
29 const CGFloat kBookmarkBarFolderScrollAmount = | 31 const CGFloat kBookmarkBarFolderScrollAmount = |
30 3 * bookmarks::kBookmarkButtonVerticalSpan; | 32 3 * bookmarks::kBookmarkButtonVerticalSpan; |
31 | 33 |
32 // Amount to scroll for each scroll wheel delta. | 34 // Amount to scroll for each scroll wheel roll. |
33 const CGFloat kBookmarkBarFolderScrollWheelAmount = | 35 const CGFloat kBookmarkBarFolderScrollWheelAmount = |
34 1 * bookmarks::kBookmarkButtonVerticalSpan; | 36 1 * bookmarks::kBookmarkButtonVerticalSpan; |
35 | 37 |
36 // When constraining a scrolling bookmark bar folder window to the | 38 // Determining adjustments to the layout of the folder menu window in response |
37 // screen, shrink the "constrain" by this much vertically. Currently | 39 // to resizing and scrolling relies on many visual factors. The following |
38 // this is 0.0 to avoid a problem with tracking areas leaving the | 40 // struct is used to pass around these factors to the several support |
39 // window, but should probably be 8.0 or something. | 41 // functions involved in the adjustment calculations and application. |
40 // TODO(jrg): http://crbug.com/36225 | 42 struct LayoutMetrics { |
41 const CGFloat kScrollWindowVerticalMargin = 0.0; | 43 // Metrics applied during the final layout adjustments to the window, |
| 44 // the main visible content view, and the menu content view (i.e. the |
| 45 // scroll view). |
| 46 CGFloat windowLeft; |
| 47 NSSize windowSize; |
| 48 // The proposed and then final scrolling adjustment made to the scrollable |
| 49 // area of the folder menu. This may be modified during the window layout |
| 50 // primarily as a result of hiding or showing the scroll arrows. |
| 51 CGFloat scrollDelta; |
| 52 NSRect windowFrame; |
| 53 NSRect visibleFrame; |
| 54 NSRect scrollerFrame; |
| 55 NSPoint scrollPoint; |
| 56 // The difference between 'could' and 'can' in these next four data members |
| 57 // is this: 'could' represents the previous condition for scrollability |
| 58 // while 'can' represents what the new condition will be for scrollability. |
| 59 BOOL couldScrollUp; |
| 60 BOOL canScrollUp; |
| 61 BOOL couldScrollDown; |
| 62 BOOL canScrollDown; |
| 63 // Determines the optimal time during folder menu layout when the contents |
| 64 // of the button scroll area should be scrolled in order to prevent |
| 65 // flickering. |
| 66 BOOL preScroll; |
| 67 |
| 68 // Intermediate metrics used in determining window vertical layout changes. |
| 69 CGFloat deltaWindowHeight; |
| 70 CGFloat deltaWindowY; |
| 71 CGFloat deltaVisibleHeight; |
| 72 CGFloat deltaVisibleY; |
| 73 CGFloat deltaScrollerHeight; |
| 74 CGFloat deltaScrollerY; |
| 75 |
| 76 // Convenience metrics used in multiple functions (carried along here in |
| 77 // order to eliminate the need to calculate in multiple places and |
| 78 // reduce the possibility of bugs). |
| 79 CGFloat minimumY; |
| 80 CGFloat oldWindowY; |
| 81 CGFloat folderY; |
| 82 CGFloat folderTop; |
| 83 |
| 84 LayoutMetrics(CGFloat windowLeft, NSSize windowSize, CGFloat scrollDelta) : |
| 85 windowLeft(windowLeft), |
| 86 windowSize(windowSize), |
| 87 scrollDelta(scrollDelta), |
| 88 couldScrollUp(NO), |
| 89 canScrollUp(NO), |
| 90 couldScrollDown(NO), |
| 91 canScrollDown(NO), |
| 92 preScroll(NO), |
| 93 deltaWindowHeight(0.0), |
| 94 deltaWindowY(0.0), |
| 95 deltaVisibleHeight(0.0), |
| 96 deltaVisibleY(0.0), |
| 97 deltaScrollerHeight(0.0), |
| 98 deltaScrollerY(0.0), |
| 99 oldWindowY(0.0), |
| 100 folderY(0.0), |
| 101 folderTop(0.0) {} |
| 102 }; |
42 | 103 |
43 } // namespace | 104 } // namespace |
44 | 105 |
45 @interface BookmarkBarFolderController(Private) | 106 @interface BookmarkBarFolderController(Private) |
46 - (void)configureWindow; | 107 - (void)configureWindow; |
47 - (void)addOrUpdateScrollTracking; | 108 - (void)addOrUpdateScrollTracking; |
48 - (void)removeScrollTracking; | 109 - (void)removeScrollTracking; |
49 - (void)endScroll; | 110 - (void)endScroll; |
50 - (void)addScrollTimerWithDelta:(CGFloat)delta; | 111 - (void)addScrollTimerWithDelta:(CGFloat)delta; |
51 | 112 |
| 113 // Helper function to configureWindow which performs a basic layout of |
| 114 // the window subviews, in particular the menu buttons and the window width. |
| 115 - (void)layOutWindowWithHeight:(CGFloat)height; |
| 116 |
52 // Determine the best button width (which will be the widest button or the | 117 // Determine the best button width (which will be the widest button or the |
53 // maximum allowable button width, whichever is less) and resize all buttons. | 118 // maximum allowable button width, whichever is less) and resize all buttons. |
54 // Return the new width (so that the window can be adjusted, if necessary). | 119 // Return the new width so that the window can be adjusted. |
55 - (CGFloat)adjustButtonWidths; | 120 - (CGFloat)adjustButtonWidths; |
56 | 121 |
57 // Returns the total menu height needed to display |buttonCount| buttons. | 122 // Returns the total menu height needed to display |buttonCount| buttons. |
58 // Does not do any fancy tricks like trimming the height to fit on the screen. | 123 // Does not do any fancy tricks like trimming the height to fit on the screen. |
59 - (int)windowHeightForButtonCount:(int)buttonCount; | 124 - (int)menuHeightForButtonCount:(int)buttonCount; |
60 | 125 |
61 // Adjust the height and horizontal position of the window such that the | 126 // Adjust layout of the folder menu window components, showing/hiding the |
62 // scroll arrows are shown as needed and the window appears completely | 127 // scroll up/down arrows, and resizing as necessary for a proper disaplay. |
63 // on screen. | 128 // In order to reduce window flicker, all layout changes are deferred until |
64 - (void)adjustWindowForHeight:(int)windowHeight; | 129 // the final step of the adjustment. To accommodate this deferral, window |
| 130 // height and width changes needed by callers to this function pass their |
| 131 // desired window changes in |size|. When scrolling is to be performed |
| 132 // any scrolling change is given by |scrollDelta|. The ultimate amount of |
| 133 // scrolling may be different from |scrollDelta| in order to accommodate |
| 134 // changes in the scroller view layout. These proposed window adjustments |
| 135 // are passed to helper functions using a LayoutMetrics structure. |
| 136 // |
| 137 // This function should be called when: 1) initially setting up a folder menu |
| 138 // window, 2) responding to scrolling of the contents (which may affect the |
| 139 // height of the window), 3) addition or removal of bookmark items (such as |
| 140 // during cut/paste/delete/drag/drop operations). |
| 141 - (void)adjustWindowLeft:(CGFloat)windowLeft |
| 142 size:(NSSize)windowSize |
| 143 scrollingBy:(CGFloat)scrollDelta; |
65 | 144 |
66 // Show or hide the scroll arrows at the top/bottom of the window. | 145 // Support function for adjustWindowLeft:size:scrollingBy: which initializes |
67 - (void)showOrHideScrollArrows; | 146 // the layout adjustments by gathering current folder menu window and subviews |
| 147 // positions and sizes. This information is set in the |layoutMetrics| |
| 148 // structure. |
| 149 - (void)gatherMetrics:(LayoutMetrics*)layoutMetrics; |
| 150 |
| 151 // Support function for adjustWindowLeft:size:scrollingBy: which calculates |
| 152 // the changes which must be applied to the folder menu window and subviews |
| 153 // positions and sizes. |layoutMetrics| contains the proposed window size |
| 154 // and scrolling along with the other current window and subview layout |
| 155 // information. The values in |layoutMetrics| are then adjusted to |
| 156 // accommodate scroll arrow presentation and window growth. |
| 157 - (void)adjustMetrics:(LayoutMetrics*)layoutMetrics; |
| 158 |
| 159 // Support function for adjustMetrics: which calculates the layout changes |
| 160 // required to accommodate changes in the position and scrollability |
| 161 // of the top of the folder menu window. |
| 162 - (void)adjustMetricsForMenuTopChanges:(LayoutMetrics*)layoutMetrics; |
| 163 |
| 164 // Support function for adjustMetrics: which calculates the layout changes |
| 165 // required to accommodate changes in the position and scrollability |
| 166 // of the bottom of the folder menu window. |
| 167 - (void)adjustMetricsForMenuBottomChanges:(LayoutMetrics*)layoutMetrics; |
| 168 |
| 169 // Support function for adjustWindowLeft:size:scrollingBy: which applies |
| 170 // the layout adjustments to the folder menu window and subviews. |
| 171 - (void)applyMetrics:(LayoutMetrics*)layoutMetrics; |
| 172 |
| 173 // This function is called when buttons are added or removed from the folder |
| 174 // menu, and which may require a change in the layout of the folder menu |
| 175 // window. Such layout changes may include horizontal placement, width, |
| 176 // height, and scroller visibility changes. (This function calls through |
| 177 // to -[adjustWindowLeft:size:scrollingBy:].) |
| 178 // |buttonCount| should contain the updated count of menu buttons. |
| 179 - (void)adjustWindowForButtonCount:(NSUInteger)buttonCount; |
| 180 |
| 181 // A helper function which takes the desired amount to scroll, given by |
| 182 // |scrollDelta|, and calculates the actual scrolling change to be applied |
| 183 // taking into account the layout of the folder menu window and any |
| 184 // changes in it's scrollability. (For example, when scrolling down and the |
| 185 // top-most menu item is coming into view we will only scroll enough for |
| 186 // that item to be completely presented, which may be less than the |
| 187 // scroll amount requested.) |
| 188 - (CGFloat)determineFinalScrollDelta:(CGFloat)scrollDelta; |
68 | 189 |
69 // |point| is in the base coordinate system of the destination window; | 190 // |point| is in the base coordinate system of the destination window; |
70 // it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be | 191 // it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be |
71 // made and inserted into the new location while leaving the bookmark in | 192 // made and inserted into the new location while leaving the bookmark in |
72 // the old location, otherwise move the bookmark by removing from its old | 193 // the old location, otherwise move the bookmark by removing from its old |
73 // location and inserting into the new location. | 194 // location and inserting into the new location. |
74 - (BOOL)dragBookmark:(const BookmarkNode*)sourceNode | 195 - (BOOL)dragBookmark:(const BookmarkNode*)sourceNode |
75 to:(NSPoint)point | 196 to:(NSPoint)point |
76 copy:(BOOL)copy; | 197 copy:(BOOL)copy; |
77 | 198 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 | 245 |
125 parentController_.reset([parentController retain]); | 246 parentController_.reset([parentController retain]); |
126 if (!parentController_) | 247 if (!parentController_) |
127 [self setSubFolderGrowthToRight:YES]; | 248 [self setSubFolderGrowthToRight:YES]; |
128 else | 249 else |
129 [self setSubFolderGrowthToRight:[parentController | 250 [self setSubFolderGrowthToRight:[parentController |
130 subFolderGrowthToRight]]; | 251 subFolderGrowthToRight]]; |
131 barController_ = barController; // WEAK | 252 barController_ = barController; // WEAK |
132 buttons_.reset([[NSMutableArray alloc] init]); | 253 buttons_.reset([[NSMutableArray alloc] init]); |
133 folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); | 254 folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); |
134 NSImage* image = app::mac::GetCachedImageWithName(@"menu_overflow_up.pdf"); | |
135 DCHECK(image); | |
136 verticalScrollArrowHeight_ = [image size].height; | |
137 [self configureWindow]; | 255 [self configureWindow]; |
138 hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]); | 256 hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]); |
139 } | 257 } |
140 return self; | 258 return self; |
141 } | 259 } |
142 | 260 |
143 - (void)dealloc { | 261 - (void)dealloc { |
144 // The button is no longer part of the menu path. | 262 // The button is no longer part of the menu path. |
145 [parentButton_ forceButtonBorderToStayOnAlways:NO]; | 263 [parentButton_ forceButtonBorderToStayOnAlways:NO]; |
146 [parentButton_ setNeedsDisplay]; | 264 [parentButton_ setNeedsDisplay]; |
147 | 265 |
148 [self removeScrollTracking]; | 266 [self removeScrollTracking]; |
149 [self endScroll]; | 267 [self endScroll]; |
150 [hoverState_ draggingExited]; | 268 [hoverState_ draggingExited]; |
151 | 269 |
152 // Delegate pattern does not retain; make sure pointers to us are removed. | 270 // Delegate pattern does not retain; make sure pointers to us are removed. |
153 for (BookmarkButton* button in buttons_.get()) { | 271 for (BookmarkButton* button in buttons_.get()) { |
154 [button setDelegate:nil]; | 272 [button setDelegate:nil]; |
155 [button setTarget:nil]; | 273 [button setTarget:nil]; |
156 [button setAction:nil]; | 274 [button setAction:nil]; |
157 } | 275 } |
158 | 276 |
159 // Note: we don't need to | 277 // Note: we don't need to |
160 // [NSObject cancelPreviousPerformRequestsWithTarget:self]; | 278 // [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
161 // Because all of our performSelector: calls use withDelay: which | 279 // Because all of our performSelector: calls use withDelay: which |
162 // retains us. | 280 // retains us. |
163 [super dealloc]; | 281 [super dealloc]; |
164 } | 282 } |
165 | 283 |
| 284 - (void)awakeFromNib { |
| 285 NSRect windowFrame = [[self window] frame]; |
| 286 NSRect scrollViewFrame = [scrollView_ frame]; |
| 287 padding_ = NSWidth(windowFrame) - NSWidth(scrollViewFrame); |
| 288 verticalScrollArrowHeight_ = NSHeight([scrollUpArrowView_ frame]); |
| 289 } |
| 290 |
166 // Overriden from NSWindowController to call childFolderWillShow: before showing | 291 // Overriden from NSWindowController to call childFolderWillShow: before showing |
167 // the window. | 292 // the window. |
168 - (void)showWindow:(id)sender { | 293 - (void)showWindow:(id)sender { |
169 [barController_ childFolderWillShow:self]; | 294 [barController_ childFolderWillShow:self]; |
170 [super showWindow:sender]; | 295 [super showWindow:sender]; |
171 } | 296 } |
172 | 297 |
173 - (BookmarkButton*)parentButton { | 298 - (BookmarkButton*)parentButton { |
174 return parentButton_.get(); | 299 return parentButton_.get(); |
175 } | 300 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 urlString.c_str()]; | 394 urlString.c_str()]; |
270 [button setToolTip:tooltip]; | 395 [button setToolTip:tooltip]; |
271 } | 396 } |
272 } else { | 397 } else { |
273 [button setEnabled:NO]; | 398 [button setEnabled:NO]; |
274 [button setBordered:NO]; | 399 [button setBordered:NO]; |
275 } | 400 } |
276 return button; | 401 return button; |
277 } | 402 } |
278 | 403 |
279 // Exposed for testing. | |
280 - (NSView*)mainView { | |
281 return mainView_; | |
282 } | |
283 | |
284 - (id)folderTarget { | 404 - (id)folderTarget { |
285 return folderTarget_.get(); | 405 return folderTarget_.get(); |
286 } | 406 } |
287 | 407 |
288 | 408 |
289 // Our parent controller is another BookmarkBarFolderController, so | 409 // Our parent controller is another BookmarkBarFolderController, so |
290 // our window is to the right or left of it. We use a little overlap | 410 // our window is to the right or left of it. We use a little overlap |
291 // since it looks much more menu-like than with none. If we would | 411 // since it looks much more menu-like than with none. If we would |
292 // grow off the screen, switch growth to the other direction. Growth | 412 // grow off the screen, switch growth to the other direction. Growth |
293 // direction sticks for folder windows which are descendents of us. | 413 // direction sticks for folder windows which are descendents of us. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 // is bottom of button's parent view. | 467 // is bottom of button's parent view. |
348 NSPoint buttonBottomLeftInScreen = | 468 NSPoint buttonBottomLeftInScreen = |
349 [[parentButton_ window] | 469 [[parentButton_ window] |
350 convertBaseToScreen:[parentButton_ | 470 convertBaseToScreen:[parentButton_ |
351 convertPoint:NSZeroPoint toView:nil]]; | 471 convertPoint:NSZeroPoint toView:nil]]; |
352 NSPoint bookmarkBarBottomLeftInScreen = | 472 NSPoint bookmarkBarBottomLeftInScreen = |
353 [[parentButton_ window] | 473 [[parentButton_ window] |
354 convertBaseToScreen:[[parentButton_ superview] | 474 convertBaseToScreen:[[parentButton_ superview] |
355 convertPoint:NSZeroPoint toView:nil]]; | 475 convertPoint:NSZeroPoint toView:nil]]; |
356 newWindowTopLeft = NSMakePoint(buttonBottomLeftInScreen.x, | 476 newWindowTopLeft = NSMakePoint(buttonBottomLeftInScreen.x, |
357 bookmarkBarBottomLeftInScreen.y); | 477 bookmarkBarBottomLeftInScreen.y + |
| 478 bookmarks::kBookmarkBarMenuOffset); |
358 // Make sure the window is on-screen; if not, push left. It is | 479 // Make sure the window is on-screen; if not, push left. It is |
359 // intentional that top level folders "push left" slightly | 480 // intentional that top level folders "push left" slightly |
360 // different than subfolders. | 481 // different than subfolders. |
361 NSRect screenFrame = [[[parentButton_ window] screen] frame]; | 482 NSRect screenFrame = [[[parentButton_ window] screen] frame]; |
362 CGFloat spillOff = (newWindowTopLeft.x + windowWidth) - NSMaxX(screenFrame); | 483 CGFloat spillOff = (newWindowTopLeft.x + windowWidth) - NSMaxX(screenFrame); |
363 if (spillOff > 0.0) { | 484 if (spillOff > 0.0) { |
364 newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff, | 485 newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff, |
365 NSMinX(screenFrame)); | 486 NSMinX(screenFrame)); |
366 } | 487 } |
367 } else { | 488 } else { |
368 // Parent is a folder; grow right/left. | 489 // Parent is a folder; grow right/left. |
369 newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth]; | 490 newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth]; |
370 NSPoint top = NSMakePoint(0, (NSMaxY([parentButton_ frame]) + | 491 NSPoint topOfWindow = NSMakePoint(0, |
371 bookmarks::kBookmarkVerticalPadding)); | 492 (NSMaxY([parentButton_ frame]) + |
372 NSPoint topOfWindow = | 493 bookmarks::kBookmarkVerticalPadding)); |
373 [[parentButton_ window] | 494 topOfWindow = [[parentButton_ window] |
374 convertBaseToScreen:[[parentButton_ superview] | 495 convertBaseToScreen:[[parentButton_ superview] |
375 convertPoint:top toView:nil]]; | 496 convertPoint:topOfWindow toView:nil]]; |
376 newWindowTopLeft.y = topOfWindow.y; | 497 newWindowTopLeft.y = topOfWindow.y; |
377 } | 498 } |
378 return newWindowTopLeft; | 499 return newWindowTopLeft; |
379 } | 500 } |
380 | 501 |
381 // Set our window level to the right spot so we're above the menubar, dock, etc. | 502 // Set our window level to the right spot so we're above the menubar, dock, etc. |
382 // Factored out so we can override/noop in a unit test. | 503 // Factored out so we can override/noop in a unit test. |
383 - (void)configureWindowLevel { | 504 - (void)configureWindowLevel { |
384 [[self window] setLevel:NSPopUpMenuWindowLevel]; | 505 [[self window] setLevel:NSPopUpMenuWindowLevel]; |
385 } | 506 } |
386 | 507 |
387 - (int)windowHeightForButtonCount:(int)buttonCount { | 508 - (int)menuHeightForButtonCount:(int)buttonCount { |
| 509 // This does not take into account any padding which may be required at the |
| 510 // top and/or bottom of the window. |
388 return (buttonCount * bookmarks::kBookmarkButtonVerticalSpan) + | 511 return (buttonCount * bookmarks::kBookmarkButtonVerticalSpan) + |
389 bookmarks::kBookmarkVerticalPadding; | 512 bookmarks::kBookmarkVerticalPadding; |
390 } | 513 } |
391 | 514 |
392 - (void)adjustWindowForHeight:(int)windowHeight { | 515 - (void)adjustWindowLeft:(CGFloat)windowLeft |
393 // Adjust all button widths to be consistent, determine the best size for | 516 size:(NSSize)windowSize |
394 // the window, and set the window frame. | 517 scrollingBy:(CGFloat)scrollDelta { |
395 CGFloat windowWidth = | 518 // Callers of this function should make adjustments to the vertical |
396 [self adjustButtonWidths] + | 519 // attributes of the folder view only (height, scroll position). |
397 (2 * bookmarks::kBookmarkSubMenuHorizontalPadding); | 520 // This function will then make appropriate layout adjustments in order |
| 521 // to accommodate screen/dock margins, scroll-up and scroll-down arrow |
| 522 // presentation, etc. |
| 523 // The 4 views whose vertical height and origins may be adjusted |
| 524 // by this function are: |
| 525 // 1) window, 2) visible content view, 3) scroller view, 4) folder view. |
| 526 |
| 527 LayoutMetrics layoutMetrics(windowLeft, windowSize, scrollDelta); |
| 528 [self gatherMetrics:&layoutMetrics]; |
| 529 [self adjustMetrics:&layoutMetrics]; |
| 530 [self applyMetrics:&layoutMetrics]; |
| 531 } |
| 532 |
| 533 - (void)gatherMetrics:(LayoutMetrics*)layoutMetrics { |
| 534 LayoutMetrics& metrics(*layoutMetrics); |
| 535 NSWindow* window = [self window]; |
| 536 metrics.windowFrame = [window frame]; |
| 537 metrics.visibleFrame = [visibleView_ frame]; |
| 538 metrics.scrollerFrame = [scrollView_ frame]; |
| 539 metrics.scrollPoint = [scrollView_ documentVisibleRect].origin; |
| 540 metrics.scrollPoint.y -= metrics.scrollDelta; |
| 541 metrics.couldScrollUp = ![scrollUpArrowView_ isHidden]; |
| 542 metrics.couldScrollDown = ![scrollDownArrowView_ isHidden]; |
| 543 |
| 544 metrics.deltaWindowHeight = 0.0; |
| 545 metrics.deltaWindowY = 0.0; |
| 546 metrics.deltaVisibleHeight = 0.0; |
| 547 metrics.deltaVisibleY = 0.0; |
| 548 metrics.deltaScrollerHeight = 0.0; |
| 549 metrics.deltaScrollerY = 0.0; |
| 550 |
| 551 metrics.minimumY = NSMinY([[window screen] visibleFrame]) + |
| 552 bookmarks::kScrollWindowVerticalMargin; |
| 553 metrics.oldWindowY = NSMinY(metrics.windowFrame); |
| 554 metrics.folderY = |
| 555 metrics.scrollerFrame.origin.y + metrics.visibleFrame.origin.y + |
| 556 metrics.oldWindowY - metrics.scrollPoint.y; |
| 557 metrics.folderTop = metrics.folderY + NSHeight([folderView_ frame]); |
| 558 } |
| 559 |
| 560 - (void)adjustMetrics:(LayoutMetrics*)layoutMetrics { |
| 561 LayoutMetrics& metrics(*layoutMetrics); |
| 562 NSScreen* screen = [[self window] screen]; |
| 563 CGFloat effectiveFolderY = metrics.folderY; |
| 564 if (!metrics.couldScrollUp && !metrics.couldScrollDown) |
| 565 effectiveFolderY -= metrics.windowSize.height; |
| 566 metrics.canScrollUp = effectiveFolderY < metrics.minimumY; |
| 567 CGFloat maximumY = |
| 568 NSMaxY([screen frame]) - bookmarks::kScrollWindowVerticalMargin; |
| 569 metrics.canScrollDown = metrics.folderTop > maximumY; |
| 570 |
| 571 // Accommodate changes in the bottom of the menu. |
| 572 [self adjustMetricsForMenuTopChanges:layoutMetrics]; |
| 573 |
| 574 // Accommodate changes in the top of the menu. |
| 575 [self adjustMetricsForMenuBottomChanges:layoutMetrics]; |
| 576 |
| 577 metrics.scrollerFrame.origin.y += metrics.deltaScrollerY; |
| 578 metrics.scrollerFrame.size.height += metrics.deltaScrollerHeight; |
| 579 metrics.visibleFrame.origin.y += metrics.deltaVisibleY; |
| 580 metrics.visibleFrame.size.height += metrics.deltaVisibleHeight; |
| 581 metrics.preScroll = metrics.canScrollUp && !metrics.couldScrollUp && |
| 582 metrics.scrollDelta == 0.0 && metrics.deltaWindowHeight >= 0.0; |
| 583 metrics.windowFrame.origin.y += metrics.deltaWindowY; |
| 584 metrics.windowFrame.origin.x = metrics.windowLeft; |
| 585 metrics.windowFrame.size.height += metrics.deltaWindowHeight; |
| 586 metrics.windowFrame.size.width = metrics.windowSize.width; |
| 587 } |
| 588 |
| 589 - (void)adjustMetricsForMenuTopChanges:(LayoutMetrics*)layoutMetrics { |
| 590 LayoutMetrics& metrics(*layoutMetrics); |
| 591 if (metrics.canScrollUp) { |
| 592 if (!metrics.couldScrollUp) { |
| 593 // Couldn't -> Can |
| 594 metrics.deltaWindowY = -metrics.oldWindowY; |
| 595 metrics.deltaWindowHeight = -metrics.deltaWindowY; |
| 596 metrics.deltaVisibleY = metrics.minimumY; |
| 597 metrics.deltaVisibleHeight = -metrics.deltaVisibleY; |
| 598 metrics.deltaScrollerY = verticalScrollArrowHeight_; |
| 599 metrics.deltaScrollerHeight = -metrics.deltaScrollerY; |
| 600 // Adjust the scroll delta if we've grown the window and it is |
| 601 // now scroll-up-able, but don't adjust it factor if we've |
| 602 // scrolled down and it wasn't scroll-up-able but now is. |
| 603 if (metrics.canScrollDown == metrics.couldScrollDown) { |
| 604 CGFloat deltaScroll = metrics.deltaWindowY + metrics.deltaScrollerY + |
| 605 metrics.deltaVisibleY; |
| 606 metrics.scrollPoint.y += deltaScroll + metrics.windowSize.height; |
| 607 } |
| 608 } else if (!metrics.canScrollDown && metrics.windowSize.height > 0.0) { |
| 609 metrics.scrollPoint.y += metrics.windowSize.height; |
| 610 } |
| 611 } else { |
| 612 if (metrics.couldScrollUp) { |
| 613 // Could -> Can't |
| 614 metrics.deltaWindowY = metrics.folderY - metrics.oldWindowY; |
| 615 metrics.deltaWindowHeight = -metrics.deltaWindowY; |
| 616 metrics.deltaVisibleY = -bookmarks::kScrollWindowVerticalMargin; |
| 617 metrics.deltaVisibleHeight = -metrics.deltaVisibleY; |
| 618 metrics.deltaScrollerY = -verticalScrollArrowHeight_; |
| 619 metrics.deltaScrollerHeight = -metrics.deltaScrollerY; |
| 620 // Adjust the scroll delta if we are no longer scroll-up-able |
| 621 // and the scroll-down-able-ness hasn't changed. |
| 622 if (metrics.canScrollDown == metrics.couldScrollDown) { |
| 623 CGFloat deltaScroll = metrics.deltaWindowY + metrics.deltaScrollerY + |
| 624 metrics.deltaVisibleY; |
| 625 metrics.scrollPoint.y += deltaScroll; |
| 626 } |
| 627 } else { |
| 628 // Couldn't -> Can't |
| 629 // Check for menu height change by looking at the relative tops of the |
| 630 // menu folder and the window folder, which previously would have been |
| 631 // the same. |
| 632 metrics.deltaWindowY = NSMaxY(metrics.windowFrame) - metrics.folderTop; |
| 633 metrics.deltaWindowHeight = -metrics.deltaWindowY; |
| 634 } |
| 635 } |
| 636 } |
| 637 |
| 638 - (void)adjustMetricsForMenuBottomChanges:(LayoutMetrics*)layoutMetrics { |
| 639 LayoutMetrics& metrics(*layoutMetrics); |
| 640 if (metrics.canScrollDown == metrics.couldScrollDown) { |
| 641 if (!metrics.canScrollDown) { |
| 642 // Not scroll-down-able but the menu top has changed. |
| 643 metrics.deltaWindowHeight += metrics.scrollDelta; |
| 644 } |
| 645 } else { |
| 646 if (metrics.canScrollDown) { |
| 647 // Couldn't -> Can |
| 648 metrics.deltaWindowHeight += (NSMaxY([[[self window] screen] frame]) - |
| 649 NSMaxY(metrics.windowFrame)); |
| 650 metrics.deltaVisibleHeight -= bookmarks::kScrollWindowVerticalMargin; |
| 651 metrics.deltaScrollerHeight -= verticalScrollArrowHeight_; |
| 652 } else { |
| 653 // Could -> Can't |
| 654 metrics.deltaWindowHeight -= bookmarks::kScrollWindowVerticalMargin; |
| 655 metrics.deltaVisibleHeight += bookmarks::kScrollWindowVerticalMargin; |
| 656 metrics.deltaScrollerHeight += verticalScrollArrowHeight_; |
| 657 } |
| 658 } |
| 659 } |
| 660 |
| 661 - (void)applyMetrics:(LayoutMetrics*)layoutMetrics { |
| 662 LayoutMetrics& metrics(*layoutMetrics); |
| 663 // Hide or show the scroll arrows. |
| 664 if (metrics.canScrollUp != metrics.couldScrollUp) |
| 665 [scrollUpArrowView_ setHidden:metrics.couldScrollUp]; |
| 666 if (metrics.canScrollDown != metrics.couldScrollDown) |
| 667 [scrollDownArrowView_ setHidden:metrics.couldScrollDown]; |
| 668 |
| 669 // Adjust the geometry. The order is important because of sizer dependencies. |
| 670 [scrollView_ setFrame:metrics.scrollerFrame]; |
| 671 [visibleView_ setFrame:metrics.visibleFrame]; |
| 672 // This little bit of trickery handles the one special case where |
| 673 // the window is now scroll-up-able _and_ going to be resized -- scroll |
| 674 // first in order to prevent flashing. |
| 675 if (metrics.preScroll) |
| 676 [[scrollView_ documentView] scrollPoint:metrics.scrollPoint]; |
| 677 |
| 678 [[self window] setFrame:metrics.windowFrame display:YES]; |
| 679 |
| 680 // In all other cases we defer scrolling until the window has been resized |
| 681 // in order to prevent flashing. |
| 682 if (!metrics.preScroll) |
| 683 [[scrollView_ documentView] scrollPoint:metrics.scrollPoint]; |
| 684 |
| 685 if (metrics.canScrollUp != metrics.couldScrollUp || |
| 686 metrics.canScrollDown != metrics.couldScrollDown || |
| 687 metrics.scrollDelta != 0.0) { |
| 688 if (metrics.canScrollUp || metrics.canScrollDown) |
| 689 [self addOrUpdateScrollTracking]; |
| 690 else |
| 691 [self removeScrollTracking]; |
| 692 } |
| 693 } |
| 694 |
| 695 - (void)adjustWindowForButtonCount:(NSUInteger)buttonCount { |
| 696 NSRect folderFrame = [folderView_ frame]; |
| 697 CGFloat newMenuHeight = |
| 698 (CGFloat)[self menuHeightForButtonCount:[buttons_ count]]; |
| 699 CGFloat deltaMenuHeight = newMenuHeight - NSHeight(folderFrame); |
| 700 // If the height has changed then also change the origin, and adjust the |
| 701 // scroll (if scrolling). |
| 702 if ([self canScrollUp]) { |
| 703 NSPoint scrollPoint = [scrollView_ documentVisibleRect].origin; |
| 704 scrollPoint.y += deltaMenuHeight; |
| 705 [[scrollView_ documentView] scrollPoint:scrollPoint]; |
| 706 } |
| 707 folderFrame.size.height += deltaMenuHeight; |
| 708 [folderView_ setFrameSize:folderFrame.size]; |
| 709 CGFloat windowWidth = [self adjustButtonWidths] + padding_; |
398 NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth]; | 710 NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth]; |
399 NSSize windowSize = NSMakeSize(windowWidth, windowHeight); | 711 CGFloat left = newWindowTopLeft.x; |
400 windowSize = [scrollView_ convertSize:windowSize toView:nil]; | 712 NSSize newSize = NSMakeSize(windowWidth, deltaMenuHeight); |
401 NSWindow* window = [self window]; | 713 [self adjustWindowLeft:left size:newSize scrollingBy:0.0]; |
402 // If the window is already visible then make sure its top remains stable. | |
403 BOOL windowAlreadyShowing = [window isVisible]; | |
404 CGFloat deltaY = windowHeight - NSHeight([mainView_ frame]); | |
405 if (windowAlreadyShowing) { | |
406 NSRect oldFrame = [window frame]; | |
407 newWindowTopLeft.y = oldFrame.origin.y + NSHeight(oldFrame); | |
408 } | |
409 NSRect windowFrame = NSMakeRect(newWindowTopLeft.x, | |
410 newWindowTopLeft.y - windowHeight, windowSize.width, windowHeight); | |
411 // Make the scrolled content be the right size (full size). | |
412 NSRect mainViewFrame = NSMakeRect(0, 0, NSWidth(windowFrame) - | |
413 bookmarks::kScrollViewContentWidthMargin, NSHeight(windowFrame)); | |
414 [mainView_ setFrame:mainViewFrame]; | |
415 // Make sure the window fits on the screen. If not, constrain. | |
416 // We'll scroll to allow the user to see all the content. | |
417 NSRect screenFrame = [[[self window] screen] frame]; | |
418 screenFrame = NSInsetRect(screenFrame, 0, kScrollWindowVerticalMargin); | |
419 BOOL wasScrollable = scrollable_; | |
420 if (!NSContainsRect(screenFrame, windowFrame)) { | |
421 scrollable_ = YES; | |
422 windowFrame = NSIntersectionRect(screenFrame, windowFrame); | |
423 } else { | |
424 scrollable_ = NO; | |
425 } | |
426 [window setFrame:windowFrame display:NO]; | |
427 if (wasScrollable != scrollable_) { | |
428 // If scrollability changed then rework visibility of the scroll arrows | |
429 // and the scroll offset of the menu view. | |
430 NSSize windowLocalSize = | |
431 [scrollView_ convertSize:windowFrame.size fromView:nil]; | |
432 CGFloat scrollPointY = NSHeight(mainViewFrame) - windowLocalSize.height + | |
433 bookmarks::kBookmarkVerticalPadding; | |
434 [mainView_ scrollPoint:NSMakePoint(0, scrollPointY)]; | |
435 [self showOrHideScrollArrows]; | |
436 [self addOrUpdateScrollTracking]; | |
437 } else if (scrollable_ && windowAlreadyShowing) { | |
438 // If the window was already showing and is still scrollable then make | |
439 // sure the main view moves upward, not downward so that the content | |
440 // at the bottom of the menu, not the top, appears to move. | |
441 // The edge case is when the menu is scrolled all the way to top (hence | |
442 // the test of scrollDownArrowShown_) - don't scroll then. | |
443 NSView* superView = [mainView_ superview]; | |
444 DCHECK([superView isKindOfClass:[NSClipView class]]); | |
445 NSClipView* clipView = static_cast<NSClipView*>(superView); | |
446 CGFloat scrollPointY = [clipView bounds].origin.y + | |
447 bookmarks::kBookmarkVerticalPadding; | |
448 if (scrollDownArrowShown_ || deltaY > 0.0) | |
449 scrollPointY += deltaY; | |
450 [mainView_ scrollPoint:NSMakePoint(0, scrollPointY)]; | |
451 } | |
452 [window display]; | |
453 } | 714 } |
454 | 715 |
455 // Determine window size and position. | 716 // Determine window size and position. |
456 // Create buttons for all our nodes. | 717 // Create buttons for all our nodes. |
457 // TODO(jrg): break up into more and smaller routines for easier unit testing. | 718 // TODO(jrg): break up into more and smaller routines for easier unit testing. |
458 - (void)configureWindow { | 719 - (void)configureWindow { |
459 const BookmarkNode* node = [parentButton_ bookmarkNode]; | 720 const BookmarkNode* node = [parentButton_ bookmarkNode]; |
460 DCHECK(node); | 721 DCHECK(node); |
461 int startingIndex = [[parentButton_ cell] startingChildIndex]; | 722 int startingIndex = [[parentButton_ cell] startingChildIndex]; |
462 DCHECK_LE(startingIndex, node->GetChildCount()); | 723 DCHECK_LE(startingIndex, node->GetChildCount()); |
463 // Must have at least 1 button (for "empty") | 724 // Must have at least 1 button (for "empty") |
464 int buttons = std::max(node->GetChildCount() - startingIndex, 1); | 725 int buttons = std::max(node->GetChildCount() - startingIndex, 1); |
465 | 726 |
466 // Prelim height of the window. We'll trim later as needed. | 727 // Prelim height of the window. We'll trim later as needed. |
467 int height = [self windowHeightForButtonCount:buttons]; | 728 int height = [self menuHeightForButtonCount:buttons]; |
468 // We'll need this soon... | 729 // We'll need this soon... |
469 [self window]; | 730 [self window]; |
470 | 731 |
471 // TODO(jrg): combine with frame code in bookmark_bar_controller.mm | 732 // TODO(jrg): combine with frame code in bookmark_bar_controller.mm |
472 // http://crbug.com/35966 | 733 // http://crbug.com/35966 |
473 NSRect buttonsOuterFrame = NSMakeRect( | 734 NSRect buttonsOuterFrame = NSMakeRect( |
474 bookmarks::kBookmarkSubMenuHorizontalPadding, | 735 0, |
475 (height - bookmarks::kBookmarkButtonVerticalSpan), | 736 (height - bookmarks::kBookmarkButtonVerticalSpan), |
476 bookmarks::kDefaultBookmarkWidth, | 737 bookmarks::kDefaultBookmarkWidth, |
477 bookmarks::kBookmarkButtonHeight); | 738 bookmarks::kBookmarkButtonHeight); |
478 | 739 |
479 // TODO(jrg): combine with addNodesToButtonList: code from | 740 // TODO(jrg): combine with addNodesToButtonList: code from |
480 // bookmark_bar_controller.mm (but use y offset) | 741 // bookmark_bar_controller.mm (but use y offset) |
481 // http://crbug.com/35966 | 742 // http://crbug.com/35966 |
482 if (!node->GetChildCount()) { | 743 if (!node->GetChildCount()) { |
483 // If no children we are the empty button. | 744 // If no children we are the empty button. |
484 BookmarkButton* button = [self makeButtonForNode:nil | 745 BookmarkButton* button = [self makeButtonForNode:nil |
485 frame:buttonsOuterFrame]; | 746 frame:buttonsOuterFrame]; |
486 [buttons_ addObject:button]; | 747 [buttons_ addObject:button]; |
487 [mainView_ addSubview:button]; | 748 [folderView_ addSubview:button]; |
488 } else { | 749 } else { |
489 for (int i = startingIndex; | 750 for (int i = startingIndex; |
490 i < node->GetChildCount(); | 751 i < node->GetChildCount(); |
491 i++) { | 752 i++) { |
492 const BookmarkNode* child = node->GetChild(i); | 753 const BookmarkNode* child = node->GetChild(i); |
493 BookmarkButton* button = [self makeButtonForNode:child | 754 BookmarkButton* button = [self makeButtonForNode:child |
494 frame:buttonsOuterFrame]; | 755 frame:buttonsOuterFrame]; |
495 [buttons_ addObject:button]; | 756 [buttons_ addObject:button]; |
496 [mainView_ addSubview:button]; | 757 [folderView_ addSubview:button]; |
497 buttonsOuterFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan; | 758 buttonsOuterFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan; |
498 } | 759 } |
499 } | 760 } |
| 761 [self layOutWindowWithHeight:height]; |
| 762 } |
500 | 763 |
501 [self adjustWindowForHeight:height]; | 764 - (void)layOutWindowWithHeight:(CGFloat)height { |
502 // Finally pop me up. | 765 // Lay out the window by adjusting all button widths to be consistent, then |
| 766 // base the window width on this ideal button width. |
| 767 CGFloat buttonWidth = [self adjustButtonWidths]; |
| 768 CGFloat windowWidth = buttonWidth + padding_; |
| 769 NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth]; |
| 770 // Make sure as much of a submenu is exposed (which otherwise would be a |
| 771 // problem if the parent button is close to the bottom of the screen). |
| 772 if ([parentController_ isKindOfClass:[self class]]) { |
| 773 newWindowTopLeft.y = MAX(newWindowTopLeft.y, |
| 774 height + bookmarks::kScrollWindowVerticalMargin); |
| 775 } |
| 776 NSWindow* window = [self window]; |
| 777 NSRect windowFrame = NSMakeRect(newWindowTopLeft.x, |
| 778 newWindowTopLeft.y - height, |
| 779 windowWidth, height); |
| 780 [window setFrame:windowFrame display:NO]; |
| 781 NSRect folderFrame = NSMakeRect(0, 0, windowWidth, height); |
| 782 [folderView_ setFrame:folderFrame]; |
| 783 NSSize newSize = NSMakeSize(windowWidth, 0.0); |
| 784 [self adjustWindowLeft:newWindowTopLeft.x size:newSize scrollingBy:0.0]; |
| 785 [window display]; |
503 [self configureWindowLevel]; | 786 [self configureWindowLevel]; |
504 } | 787 } |
505 | 788 |
506 // TODO(mrossetti): See if the following can be moved into view's viewWillDraw:. | 789 // TODO(mrossetti): See if the following can be moved into view's viewWillDraw:. |
507 - (CGFloat)adjustButtonWidths { | 790 - (CGFloat)adjustButtonWidths { |
508 CGFloat width = bookmarks::kBookmarkMenuButtonMinimumWidth; | 791 CGFloat width = bookmarks::kBookmarkMenuButtonMinimumWidth; |
509 // Use the cell's size as the base for determining the desired width of the | 792 // Use the cell's size as the base for determining the desired width of the |
510 // button rather than the button's current width. -[cell cellSize] always | 793 // button rather than the button's current width. -[cell cellSize] always |
511 // returns the 'optimum' size of the cell based on the cell's contents even | 794 // returns the 'optimum' size of the cell based on the cell's contents even |
512 // if it's less than the current button size. Relying on the button size | 795 // if it's less than the current button size. Relying on the button size |
513 // would result in buttons that could only get wider but we want to handle | 796 // would result in buttons that could only get wider but we want to handle |
514 // the case where the widest button gets removed from a folder menu. | 797 // the case where the widest button gets removed from a folder menu. |
515 for (BookmarkButton* button in buttons_.get()) | 798 for (BookmarkButton* button in buttons_.get()) |
516 width = std::max(width, [[button cell] cellSize].width); | 799 width = std::max(width, [[button cell] cellSize].width); |
517 width = std::min(width, bookmarks::kBookmarkMenuButtonMaximumWidth); | 800 width = std::min(width, bookmarks::kBookmarkMenuButtonMaximumWidth); |
518 // Things look and feel more menu-like if all the buttons are the | 801 // Things look and feel more menu-like if all the buttons are the |
519 // full width of the window, especially if there are submenus. | 802 // full width of the window, especially if there are submenus. |
520 for (BookmarkButton* button in buttons_.get()) { | 803 for (BookmarkButton* button in buttons_.get()) { |
521 NSRect buttonFrame = [button frame]; | 804 NSRect buttonFrame = [button frame]; |
522 buttonFrame.size.width = width; | 805 buttonFrame.size.width = width; |
523 [button setFrame:buttonFrame]; | 806 [button setFrame:buttonFrame]; |
524 } | 807 } |
525 return width; | 808 return width; |
526 } | 809 } |
527 | 810 |
528 - (BOOL)canScrollUp { | |
529 // If removal of an arrow would make things "finished", state as | |
530 // such. | |
531 CGFloat scrollY = [scrollView_ documentVisibleRect].origin.y; | |
532 if (scrollUpArrowShown_) | |
533 scrollY -= verticalScrollArrowHeight_; | |
534 | |
535 if (scrollY <= 0) | |
536 return NO; | |
537 return YES; | |
538 } | |
539 | |
540 - (BOOL)canScrollDown { | |
541 CGFloat arrowAdjustment = 0.0; | |
542 | |
543 // We do NOT adjust based on the scrollDOWN arrow. This keeps | |
544 // things from "jumping"; if removal of the down arrow (at the top | |
545 // of the window) would cause a scroll to end, we'll end. | |
546 if (scrollUpArrowShown_) | |
547 arrowAdjustment += verticalScrollArrowHeight_; | |
548 | |
549 NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; | |
550 NSRect documentRect = [[scrollView_ documentView] frame]; | |
551 | |
552 // If we are exactly the right height, return no. We need this | |
553 // extra conditional in the case where we've just scrolled/grown | |
554 // into position. | |
555 if (NSHeight([[self window] frame]) == NSHeight(documentRect)) | |
556 return NO; | |
557 | |
558 if ((scrollPosition.y + NSHeight([[self window] frame])) >= | |
559 (NSHeight(documentRect) + arrowAdjustment)) { | |
560 return NO; | |
561 } | |
562 return YES; | |
563 } | |
564 | |
565 - (void)showOrHideScrollArrows { | |
566 NSRect frame = [scrollView_ frame]; | |
567 CGFloat scrollDelta = 0.0; | |
568 BOOL canScrollDown = [self canScrollDown]; | |
569 BOOL canScrollUp = [self canScrollUp]; | |
570 | |
571 if (canScrollUp != scrollUpArrowShown_) { | |
572 if (scrollUpArrowShown_) { | |
573 frame.origin.y -= verticalScrollArrowHeight_; | |
574 frame.size.height += verticalScrollArrowHeight_; | |
575 scrollDelta = verticalScrollArrowHeight_; | |
576 } else { | |
577 frame.origin.y += verticalScrollArrowHeight_; | |
578 frame.size.height -= verticalScrollArrowHeight_; | |
579 scrollDelta = -verticalScrollArrowHeight_; | |
580 } | |
581 } | |
582 if (canScrollDown != scrollDownArrowShown_) { | |
583 if (scrollDownArrowShown_) { | |
584 frame.size.height += verticalScrollArrowHeight_; | |
585 } else { | |
586 frame.size.height -= verticalScrollArrowHeight_; | |
587 } | |
588 } | |
589 scrollUpArrowShown_ = canScrollUp; | |
590 scrollDownArrowShown_ = canScrollDown; | |
591 [scrollView_ setFrame:frame]; | |
592 | |
593 // Adjust scroll based on new frame. For example, if we make room | |
594 // for an arrow at the bottom, adjust the scroll so the topmost item | |
595 // is still fully visible. | |
596 if (scrollDelta) { | |
597 NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; | |
598 scrollPosition.y -= scrollDelta; | |
599 [[scrollView_ documentView] scrollPoint:scrollPosition]; | |
600 } | |
601 } | |
602 | |
603 - (BOOL)scrollable { | |
604 return scrollable_; | |
605 } | |
606 | |
607 // Start a "scroll up" timer. | 811 // Start a "scroll up" timer. |
608 - (void)beginScrollWindowUp { | 812 - (void)beginScrollWindowUp { |
609 [self addScrollTimerWithDelta:kBookmarkBarFolderScrollAmount]; | 813 [self addScrollTimerWithDelta:kBookmarkBarFolderScrollAmount]; |
610 } | 814 } |
611 | 815 |
612 // Start a "scroll down" timer. | 816 // Start a "scroll down" timer. |
613 - (void)beginScrollWindowDown { | 817 - (void)beginScrollWindowDown { |
614 [self addScrollTimerWithDelta:-kBookmarkBarFolderScrollAmount]; | 818 [self addScrollTimerWithDelta:-kBookmarkBarFolderScrollAmount]; |
615 } | 819 } |
616 | 820 |
617 // End a scrolling timer. Can be called excessively with no harm. | 821 // End a scrolling timer. Can be called excessively with no harm. |
618 - (void)endScroll { | 822 - (void)endScroll { |
619 if (scrollTimer_) { | 823 if (scrollTimer_) { |
620 [scrollTimer_ invalidate]; | 824 [scrollTimer_ invalidate]; |
621 scrollTimer_ = nil; | 825 scrollTimer_ = nil; |
622 verticalScrollDelta_ = 0; | 826 verticalScrollDelta_ = 0; |
623 } | 827 } |
624 } | 828 } |
625 | 829 |
626 // Perform a single scroll of the specified amount. | 830 // Perform a single scroll of the specified amount. |
627 // Scroll up: | |
628 // Scroll the documentView by the growth amount. | |
629 // If we cannot grow the window, simply scroll the documentView. | |
630 // If we can grow the window up without falling off the screen, do it. | |
631 // Scroll down: | |
632 // Never change the window size; only scroll the documentView. | |
633 - (void)performOneScroll:(CGFloat)delta { | 831 - (void)performOneScroll:(CGFloat)delta { |
634 NSRect windowFrame = [[self window] frame]; | 832 CGFloat finalDelta = [self determineFinalScrollDelta:delta]; |
635 NSRect screenFrame = [[[self window] screen] frame]; | 833 if (finalDelta > 0.0 || finalDelta < 0.0) { |
| 834 if (buttonThatMouseIsIn_) |
| 835 [buttonThatMouseIsIn_ toggleButtonBorderingWhileMouseInside]; |
| 836 NSRect windowFrame = [[self window] frame]; |
| 837 NSSize newSize = NSMakeSize(NSWidth(windowFrame), 0.0); |
| 838 [self adjustWindowLeft:windowFrame.origin.x |
| 839 size:newSize |
| 840 scrollingBy:finalDelta]; |
| 841 } |
| 842 } |
636 | 843 |
637 // First scroll the "document" area. | 844 - (CGFloat)determineFinalScrollDelta:(CGFloat)delta { |
638 NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; | 845 if (delta > 0.0 && ![scrollUpArrowView_ isHidden] || |
639 scrollPosition.y -= delta; | 846 delta < 0.0 && ![scrollDownArrowView_ isHidden]) { |
640 [[scrollView_ documentView] scrollPoint:scrollPosition]; | 847 NSWindow* window = [self window]; |
| 848 NSRect windowFrame = [window frame]; |
| 849 NSScreen* screen = [window screen]; |
| 850 NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; |
| 851 CGFloat scrollY = scrollPosition.y; |
| 852 NSRect scrollerFrame = [scrollView_ frame]; |
| 853 CGFloat scrollerY = NSMinY(scrollerFrame); |
| 854 NSRect visibleFrame = [visibleView_ frame]; |
| 855 CGFloat visibleY = NSMinY(visibleFrame); |
| 856 CGFloat windowY = NSMinY(windowFrame); |
| 857 CGFloat offset = scrollerY + visibleY + windowY; |
641 | 858 |
642 if (buttonThatMouseIsIn_) | 859 if (delta > 0.0) { |
643 [buttonThatMouseIsIn_ toggleButtonBorderingWhileMouseInside]; | 860 // Scrolling up. |
644 | 861 CGFloat minimumY = NSMinY([screen visibleFrame]) + |
645 // We update the window size after shifting the scroll to avoid a race. | 862 bookmarks::kScrollWindowVerticalMargin; |
646 CGFloat screenHeightMinusMargin = (NSHeight(screenFrame) - | 863 CGFloat maxUpDelta = scrollY - offset + minimumY; |
647 (2 * kScrollWindowVerticalMargin)); | 864 delta = MIN(delta, maxUpDelta); |
648 if (delta) { | 865 } else { |
649 // If we can, grow the window (up). | 866 // Scrolling down. |
650 if (NSHeight(windowFrame) < screenHeightMinusMargin) { | 867 NSRect screenFrame = [screen frame]; |
651 CGFloat growAmount = delta; | 868 CGFloat topOfScreen = NSMaxY(screenFrame); |
652 // Don't scroll more than enough to "finish". | 869 NSRect folderFrame = [folderView_ frame]; |
653 if (scrollPosition.y < 0) | 870 CGFloat folderHeight = NSHeight(folderFrame); |
654 growAmount += scrollPosition.y; | 871 CGFloat folderTop = folderHeight - scrollY + offset; |
655 windowFrame.size.height += growAmount; | 872 CGFloat maxDownDelta = |
656 windowFrame.size.height = std::min(NSHeight(windowFrame), | 873 topOfScreen - folderTop - bookmarks::kScrollWindowVerticalMargin; |
657 screenHeightMinusMargin); | 874 delta = MAX(delta, maxDownDelta); |
658 // Watch out for a finish that isn't the full height of the screen. | |
659 // We get here if using the scroll wheel to scroll by small amounts. | |
660 windowFrame.size.height = std::min(NSHeight(windowFrame), | |
661 NSHeight([mainView_ frame])); | |
662 // Don't allow scrolling to make the window smaller, ever. This | |
663 // conditional is important when processing scrollWheel events. | |
664 if (windowFrame.size.height > [[self window] frame].size.height) { | |
665 [[self window] setFrame:windowFrame display:YES]; | |
666 [self addOrUpdateScrollTracking]; | |
667 } | |
668 } | 875 } |
| 876 } else { |
| 877 delta = 0.0; |
669 } | 878 } |
670 | 879 return delta; |
671 // If we're at either end, happiness. | |
672 if ((scrollPosition.y <= 0) || | |
673 ((scrollPosition.y + NSHeight(windowFrame) >= | |
674 NSHeight([mainView_ frame])) && | |
675 (windowFrame.size.height == screenHeightMinusMargin))) { | |
676 [self endScroll]; | |
677 | |
678 // If we can't scroll either up or down we are completely done. | |
679 // For example, perhaps we've scrolled a little and grown the | |
680 // window on-screen until there is now room for everything. | |
681 if (![self canScrollUp] && ![self canScrollDown]) { | |
682 scrollable_ = NO; | |
683 [self removeScrollTracking]; | |
684 } | |
685 } | |
686 | |
687 [self showOrHideScrollArrows]; | |
688 } | 880 } |
689 | 881 |
690 // Perform a scroll of the window on the screen. | 882 // Perform a scroll of the window on the screen. |
691 // Called by a timer when scrolling. | 883 // Called by a timer when scrolling. |
692 - (void)performScroll:(NSTimer*)timer { | 884 - (void)performScroll:(NSTimer*)timer { |
693 DCHECK(verticalScrollDelta_); | 885 DCHECK(verticalScrollDelta_); |
694 [self performOneScroll:verticalScrollDelta_]; | 886 [self performOneScroll:verticalScrollDelta_]; |
695 } | 887 } |
696 | 888 |
697 | 889 |
(...skipping 11 matching lines...) Expand all Loading... |
709 userInfo:nil | 901 userInfo:nil |
710 repeats:YES]; | 902 repeats:YES]; |
711 } | 903 } |
712 | 904 |
713 // Called as a result of our tracking area. Warning: on the main | 905 // Called as a result of our tracking area. Warning: on the main |
714 // screen (of a single-screened machine), the minimum mouse y value is | 906 // screen (of a single-screened machine), the minimum mouse y value is |
715 // 1, not 0. Also, we do not get events when the mouse is above the | 907 // 1, not 0. Also, we do not get events when the mouse is above the |
716 // menubar (to be fixed by setting the proper window level; see | 908 // menubar (to be fixed by setting the proper window level; see |
717 // initializer). | 909 // initializer). |
718 - (void)mouseMoved:(NSEvent*)theEvent { | 910 - (void)mouseMoved:(NSEvent*)theEvent { |
719 DCHECK([theEvent window] == [self window]); | 911 NSWindow* window = [theEvent window]; |
| 912 DCHECK(window == [self window]); |
720 | 913 |
721 NSPoint eventScreenLocation = | 914 NSPoint eventScreenLocation = |
722 [[theEvent window] convertBaseToScreen:[theEvent locationInWindow]]; | 915 [window convertBaseToScreen:[theEvent locationInWindow]]; |
723 | 916 |
724 // We use frame (not visibleFrame) since our bookmark folder is on | 917 // Base hot spot calculations on the positions of the scroll arrow views. |
725 // TOP of the menubar. | 918 NSRect testRect = [scrollDownArrowView_ frame]; |
726 NSRect visibleRect = [[[self window] screen] frame]; | 919 NSPoint testPoint = [visibleView_ convertPoint:testRect.origin |
727 CGFloat closeToTopOfScreen = NSMaxY(visibleRect) - | 920 toView:nil]; |
728 verticalScrollArrowHeight_; | 921 testPoint = [window convertBaseToScreen:testPoint]; |
729 CGFloat closeToBottomOfScreen = NSMinY(visibleRect) + | 922 CGFloat closeToTopOfScreen = testPoint.y; |
730 verticalScrollArrowHeight_; | |
731 | 923 |
732 if (eventScreenLocation.y <= closeToBottomOfScreen) { | 924 testRect = [scrollUpArrowView_ frame]; |
| 925 testPoint = [visibleView_ convertPoint:testRect.origin toView:nil]; |
| 926 testPoint = [window convertBaseToScreen:testPoint]; |
| 927 CGFloat closeToBottomOfScreen = testPoint.y + testRect.size.height; |
| 928 if (eventScreenLocation.y <= closeToBottomOfScreen && |
| 929 ![scrollUpArrowView_ isHidden]) { |
733 [self beginScrollWindowUp]; | 930 [self beginScrollWindowUp]; |
734 } else if (eventScreenLocation.y > closeToTopOfScreen) { | 931 } else if (eventScreenLocation.y > closeToTopOfScreen && |
| 932 ![scrollDownArrowView_ isHidden]) { |
735 [self beginScrollWindowDown]; | 933 [self beginScrollWindowDown]; |
736 } else { | 934 } else { |
737 [self endScroll]; | 935 [self endScroll]; |
738 } | 936 } |
739 } | 937 } |
740 | 938 |
741 - (void)mouseExited:(NSEvent*)theEvent { | 939 - (void)mouseExited:(NSEvent*)theEvent { |
742 [self endScroll]; | 940 [self endScroll]; |
743 } | 941 } |
744 | 942 |
(...skipping 14 matching lines...) Expand all Loading... |
759 } | 957 } |
760 | 958 |
761 // Remove the tracking area associated with scrolling. | 959 // Remove the tracking area associated with scrolling. |
762 - (void)removeScrollTracking { | 960 - (void)removeScrollTracking { |
763 if (scrollTrackingArea_.get()) { | 961 if (scrollTrackingArea_.get()) { |
764 [[[self window] contentView] removeTrackingArea:scrollTrackingArea_]; | 962 [[[self window] contentView] removeTrackingArea:scrollTrackingArea_]; |
765 } | 963 } |
766 scrollTrackingArea_.reset(); | 964 scrollTrackingArea_.reset(); |
767 } | 965 } |
768 | 966 |
769 // Delegate callback. | |
770 - (void)windowWillClose:(NSNotification*)notification { | |
771 // If a "hover open" is pending when the bookmark bar folder is | |
772 // closed, be sure it gets cancelled. | |
773 [NSObject cancelPreviousPerformRequestsWithTarget:self]; | |
774 | |
775 [barController_ childFolderWillClose:self]; | |
776 [self closeBookmarkFolder:self]; | |
777 [self autorelease]; | |
778 } | |
779 | |
780 // Close the old hover-open bookmark folder, and open a new one. We | 967 // Close the old hover-open bookmark folder, and open a new one. We |
781 // do both in one step to allow for a delay in closing the old one. | 968 // do both in one step to allow for a delay in closing the old one. |
782 // See comments above kDragHoverCloseDelay (bookmark_bar_controller.h) | 969 // See comments above kDragHoverCloseDelay (bookmark_bar_controller.h) |
783 // for more details. | 970 // for more details. |
784 - (void)openBookmarkFolderFromButtonAndCloseOldOne:(id)sender { | 971 - (void)openBookmarkFolderFromButtonAndCloseOldOne:(id)sender { |
785 // If an old submenu exists, close it immediately. | 972 // If an old submenu exists, close it immediately. |
786 [self closeBookmarkFolder:sender]; | 973 [self closeBookmarkFolder:sender]; |
787 | 974 |
788 // Open a new one if meaningful. | 975 // Open a new one if meaningful. |
789 if ([sender isFolder]) | 976 if ([sender isFolder]) |
790 [folderTarget_ openBookmarkFolderFromButton:sender]; | 977 [folderTarget_ openBookmarkFolderFromButton:sender]; |
791 } | 978 } |
792 | 979 |
793 - (NSArray*)buttons { | 980 - (NSArray*)buttons { |
794 return buttons_.get(); | 981 return buttons_.get(); |
795 } | 982 } |
796 | 983 |
797 - (void)close { | 984 - (void)close { |
798 [folderController_ close]; | 985 [folderController_ close]; |
799 [super close]; | 986 [super close]; |
800 } | 987 } |
801 | 988 |
802 - (void)scrollWheel:(NSEvent *)theEvent { | 989 - (void)scrollWheel:(NSEvent *)theEvent { |
803 if (scrollable_) { | 990 if (![scrollUpArrowView_ isHidden] || ![scrollDownArrowView_ isHidden]) { |
804 // We go negative since an NSScrollView has a flipped coordinate frame. | 991 // We go negative since an NSScrollView has a flipped coordinate frame. |
805 CGFloat amt = kBookmarkBarFolderScrollWheelAmount * -[theEvent deltaY]; | 992 CGFloat amt = kBookmarkBarFolderScrollWheelAmount * -[theEvent deltaY]; |
806 [self performOneScroll:amt]; | 993 [self performOneScroll:amt]; |
807 } | 994 } |
808 } | 995 } |
809 | 996 |
810 #pragma mark Actions Forwarded to Parent BookmarkBarController | 997 #pragma mark Actions Forwarded to Parent BookmarkBarController |
811 | 998 |
812 - (IBAction)openBookmark:(id)sender { | 999 - (IBAction)openBookmark:(id)sender { |
813 [barController_ openBookmark:sender]; | 1000 [barController_ openBookmark:sender]; |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
919 // exist in the future). | 1106 // exist in the future). |
920 // http://crbug.com/35966 | 1107 // http://crbug.com/35966 |
921 - (int)indexForDragToPoint:(NSPoint)point { | 1108 - (int)indexForDragToPoint:(NSPoint)point { |
922 // Identify which buttons we are between. For now, assume a button | 1109 // Identify which buttons we are between. For now, assume a button |
923 // location is at the center point of its view, and that an exact | 1110 // location is at the center point of its view, and that an exact |
924 // match means "place before". | 1111 // match means "place before". |
925 // TODO(jrg): revisit position info based on UI team feedback. | 1112 // TODO(jrg): revisit position info based on UI team feedback. |
926 // dropLocation is in bar local coordinates. | 1113 // dropLocation is in bar local coordinates. |
927 // http://crbug.com/36276 | 1114 // http://crbug.com/36276 |
928 NSPoint dropLocation = | 1115 NSPoint dropLocation = |
929 [mainView_ convertPoint:point | 1116 [folderView_ convertPoint:point |
930 fromView:[[self window] contentView]]; | 1117 fromView:[[self window] contentView]]; |
931 BookmarkButton* buttonToTheTopOfDraggedButton = nil; | 1118 BookmarkButton* buttonToTheTopOfDraggedButton = nil; |
932 // Buttons are laid out in this array from top to bottom (screen | 1119 // Buttons are laid out in this array from top to bottom (screen |
933 // wise), which means "biggest y" --> "smallest y". | 1120 // wise), which means "biggest y" --> "smallest y". |
934 for (BookmarkButton* button in buttons_.get()) { | 1121 for (BookmarkButton* button in buttons_.get()) { |
935 CGFloat midpoint = NSMidY([button frame]); | 1122 CGFloat midpoint = NSMidY([button frame]); |
936 if (dropLocation.y > midpoint) { | 1123 if (dropLocation.y > midpoint) { |
937 break; | 1124 break; |
938 } | 1125 } |
939 buttonToTheTopOfDraggedButton = button; | 1126 buttonToTheTopOfDraggedButton = button; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
993 else | 1180 else |
994 [self bookmarkModel]->Move(sourceNode, destParent, destIndex); | 1181 [self bookmarkModel]->Move(sourceNode, destParent, destIndex); |
995 wasCopiedOrMoved = YES; | 1182 wasCopiedOrMoved = YES; |
996 // Movement of a node triggers observers (like us) to rebuild the | 1183 // Movement of a node triggers observers (like us) to rebuild the |
997 // bar so we don't have to do so explicitly. | 1184 // bar so we don't have to do so explicitly. |
998 } | 1185 } |
999 | 1186 |
1000 return wasCopiedOrMoved; | 1187 return wasCopiedOrMoved; |
1001 } | 1188 } |
1002 | 1189 |
| 1190 #pragma mark NSWindowDelegate Functions |
| 1191 |
| 1192 - (void)windowWillClose:(NSNotification*)notification { |
| 1193 // If a "hover open" is pending when the bookmark bar folder is |
| 1194 // closed, be sure it gets cancelled. |
| 1195 [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
| 1196 |
| 1197 [self endScroll]; // Just in case we were scrolling. |
| 1198 [barController_ childFolderWillClose:self]; |
| 1199 [self closeBookmarkFolder:self]; |
| 1200 [self autorelease]; |
| 1201 } |
| 1202 |
1003 #pragma mark BookmarkButtonDelegate Protocol | 1203 #pragma mark BookmarkButtonDelegate Protocol |
1004 | 1204 |
1005 - (void)fillPasteboard:(NSPasteboard*)pboard | 1205 - (void)fillPasteboard:(NSPasteboard*)pboard |
1006 forDragOfButton:(BookmarkButton*)button { | 1206 forDragOfButton:(BookmarkButton*)button { |
1007 [[self folderTarget] fillPasteboard:pboard forDragOfButton:button]; | 1207 [[self folderTarget] fillPasteboard:pboard forDragOfButton:button]; |
1008 | 1208 |
1009 // Close our folder menu and submenus since we know we're going to be dragged. | 1209 // Close our folder menu and submenus since we know we're going to be dragged. |
1010 [self closeBookmarkFolder:self]; | 1210 [self closeBookmarkFolder:self]; |
1011 } | 1211 } |
1012 | 1212 |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1273 // which is where the new button will be located. | 1473 // which is where the new button will be located. |
1274 newButtonFrame = [button frame]; | 1474 newButtonFrame = [button frame]; |
1275 NSRect buttonFrame = [button frame]; | 1475 NSRect buttonFrame = [button frame]; |
1276 buttonFrame.origin.y += bookmarks::kBookmarkButtonVerticalSpan; | 1476 buttonFrame.origin.y += bookmarks::kBookmarkButtonVerticalSpan; |
1277 [button setFrame:buttonFrame]; | 1477 [button setFrame:buttonFrame]; |
1278 } | 1478 } |
1279 [[button cell] mouseExited:nil]; // De-highlight. | 1479 [[button cell] mouseExited:nil]; // De-highlight. |
1280 BookmarkButton* newButton = [self makeButtonForNode:node | 1480 BookmarkButton* newButton = [self makeButtonForNode:node |
1281 frame:newButtonFrame]; | 1481 frame:newButtonFrame]; |
1282 [buttons_ insertObject:newButton atIndex:buttonIndex]; | 1482 [buttons_ insertObject:newButton atIndex:buttonIndex]; |
1283 [mainView_ addSubview:newButton]; | 1483 [folderView_ addSubview:newButton]; |
1284 | 1484 |
1285 // Close any child folder(s) which may still be open. | 1485 // Close any child folder(s) which may still be open. |
1286 [self closeBookmarkFolder:self]; | 1486 [self closeBookmarkFolder:self]; |
1287 | 1487 |
1288 // Prelim height of the window. We'll trim later as needed. | 1488 [self adjustWindowForButtonCount:[buttons_ count]]; |
1289 int height = [self windowHeightForButtonCount:[buttons_ count]]; | |
1290 [self adjustWindowForHeight:height]; | |
1291 } | 1489 } |
1292 | 1490 |
1293 // More code which essentially duplicates that of BookmarkBarController. | 1491 // More code which essentially duplicates that of BookmarkBarController. |
1294 // TODO(mrossetti,jrg): http://crbug.com/35966 | 1492 // TODO(mrossetti,jrg): http://crbug.com/35966 |
1295 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { | 1493 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { |
1296 DCHECK([urls count] == [titles count]); | 1494 DCHECK([urls count] == [titles count]); |
1297 BOOL nodesWereAdded = NO; | 1495 BOOL nodesWereAdded = NO; |
1298 // Figure out where these new bookmarks nodes are to be added. | 1496 // Figure out where these new bookmarks nodes are to be added. |
1299 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point]; | 1497 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point]; |
1300 BookmarkModel* bookmarkModel = [self bookmarkModel]; | 1498 BookmarkModel* bookmarkModel = [self bookmarkModel]; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1387 // http://crbug.com/54324 | 1585 // http://crbug.com/54324 |
1388 for (NSButton* button in buttons_.get()) { | 1586 for (NSButton* button in buttons_.get()) { |
1389 if ([button showsBorderOnlyWhileMouseInside]) { | 1587 if ([button showsBorderOnlyWhileMouseInside]) { |
1390 [button setShowsBorderOnlyWhileMouseInside:NO]; | 1588 [button setShowsBorderOnlyWhileMouseInside:NO]; |
1391 [button setShowsBorderOnlyWhileMouseInside:YES]; | 1589 [button setShowsBorderOnlyWhileMouseInside:YES]; |
1392 } | 1590 } |
1393 } | 1591 } |
1394 | 1592 |
1395 [oldButton setDelegate:nil]; | 1593 [oldButton setDelegate:nil]; |
1396 [oldButton removeFromSuperview]; | 1594 [oldButton removeFromSuperview]; |
1397 if (animate && !ignoreAnimations_) | |
1398 NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint, | |
1399 NSZeroSize, nil, nil, nil); | |
1400 [buttons_ removeObjectAtIndex:buttonIndex]; | 1595 [buttons_ removeObjectAtIndex:buttonIndex]; |
1401 for (NSInteger i = 0; i < buttonIndex; ++i) { | 1596 for (NSInteger i = 0; i < buttonIndex; ++i) { |
1402 BookmarkButton* button = [buttons_ objectAtIndex:i]; | 1597 BookmarkButton* button = [buttons_ objectAtIndex:i]; |
1403 NSRect buttonFrame = [button frame]; | 1598 NSRect buttonFrame = [button frame]; |
1404 buttonFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan; | 1599 buttonFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan; |
1405 [button setFrame:buttonFrame]; | 1600 [button setFrame:buttonFrame]; |
1406 } | 1601 } |
1407 // Search for and adjust submenus, if necessary. | 1602 // Search for and adjust submenus, if necessary. |
1408 NSInteger buttonCount = [buttons_ count]; | 1603 NSInteger buttonCount = [buttons_ count]; |
1409 if (buttonCount) { | 1604 if (buttonCount) { |
1410 BookmarkButton* subButton = [folderController_ parentButton]; | 1605 BookmarkButton* subButton = [folderController_ parentButton]; |
1411 for (NSInteger i = buttonIndex; i < buttonCount; ++i) { | 1606 for (NSInteger i = buttonIndex; i < buttonCount; ++i) { |
1412 BookmarkButton* aButton = [buttons_ objectAtIndex:i]; | 1607 BookmarkButton* aButton = [buttons_ objectAtIndex:i]; |
1413 // If this button is showing its menu then we need to move the menu, too. | 1608 // If this button is showing its menu then we need to move the menu, too. |
1414 if (aButton == subButton) | 1609 if (aButton == subButton) |
1415 [folderController_ offsetFolderMenuWindow:NSMakeSize(0.0, | 1610 [folderController_ offsetFolderMenuWindow:NSMakeSize(0.0, |
1416 bookmarks::kBookmarkBarHeight)]; | 1611 bookmarks::kBookmarkBarHeight)]; |
1417 } | 1612 } |
1418 } else { | 1613 } else { |
1419 // If all nodes have been removed from this folder then add in the | 1614 // If all nodes have been removed from this folder then add in the |
1420 // 'empty' placeholder button. | 1615 // 'empty' placeholder button. |
1421 NSRect buttonFrame = | 1616 NSRect buttonFrame = |
1422 NSMakeRect(bookmarks::kBookmarkSubMenuHorizontalPadding, | 1617 NSMakeRect(0, |
1423 bookmarks::kBookmarkButtonHeight - | 1618 bookmarks::kBookmarkButtonHeight - |
1424 (bookmarks::kBookmarkBarHeight - | 1619 (bookmarks::kBookmarkBarHeight - |
1425 bookmarks::kBookmarkVerticalPadding), | 1620 bookmarks::kBookmarkVerticalPadding), |
1426 bookmarks::kDefaultBookmarkWidth, | 1621 bookmarks::kDefaultBookmarkWidth, |
1427 (bookmarks::kBookmarkBarHeight - | 1622 (bookmarks::kBookmarkBarHeight - |
1428 2 * bookmarks::kBookmarkVerticalPadding)); | 1623 2 * bookmarks::kBookmarkVerticalPadding)); |
1429 BookmarkButton* button = [self makeButtonForNode:nil | 1624 BookmarkButton* button = [self makeButtonForNode:nil |
1430 frame:buttonFrame]; | 1625 frame:buttonFrame]; |
1431 [buttons_ addObject:button]; | 1626 [buttons_ addObject:button]; |
1432 [mainView_ addSubview:button]; | 1627 [folderView_ addSubview:button]; |
1433 buttonCount = 1; | 1628 buttonCount = 1; |
1434 } | 1629 } |
1435 | 1630 |
1436 // Propose a height for the window. We'll trim later as needed. | 1631 [self adjustWindowForButtonCount:buttonCount]; |
1437 [self adjustWindowForHeight:[self windowHeightForButtonCount:buttonCount]]; | 1632 |
| 1633 if (animate && !ignoreAnimations_) |
| 1634 NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint, |
| 1635 NSZeroSize, nil, nil, nil); |
1438 } | 1636 } |
1439 | 1637 |
1440 - (id<BookmarkButtonControllerProtocol>)controllerForNode: | 1638 - (id<BookmarkButtonControllerProtocol>)controllerForNode: |
1441 (const BookmarkNode*)node { | 1639 (const BookmarkNode*)node { |
1442 // See if we are holding this node, otherwise see if it is in our | 1640 // See if we are holding this node, otherwise see if it is in our |
1443 // hierarchy of visible folder menus. | 1641 // hierarchy of visible folder menus. |
1444 if ([parentButton_ bookmarkNode] == node) | 1642 if ([parentButton_ bookmarkNode] == node) |
1445 return self; | 1643 return self; |
1446 return [folderController_ controllerForNode:node]; | 1644 return [folderController_ controllerForNode:node]; |
1447 } | 1645 } |
1448 | 1646 |
1449 #pragma mark TestingAPI Only | 1647 #pragma mark TestingAPI Only |
1450 | 1648 |
| 1649 - (BOOL)canScrollUp { |
| 1650 return ![scrollUpArrowView_ isHidden]; |
| 1651 } |
| 1652 |
| 1653 - (BOOL)canScrollDown { |
| 1654 return ![scrollDownArrowView_ isHidden]; |
| 1655 } |
| 1656 |
| 1657 - (CGFloat)verticalScrollArrowHeight { |
| 1658 return verticalScrollArrowHeight_; |
| 1659 } |
| 1660 |
| 1661 - (NSView*)visibleView { |
| 1662 return visibleView_; |
| 1663 } |
| 1664 |
| 1665 - (NSView*)scrollView { |
| 1666 return scrollView_; |
| 1667 } |
| 1668 |
| 1669 - (NSView*)folderView { |
| 1670 return folderView_; |
| 1671 } |
| 1672 |
1451 - (void)setIgnoreAnimations:(BOOL)ignore { | 1673 - (void)setIgnoreAnimations:(BOOL)ignore { |
1452 ignoreAnimations_ = ignore; | 1674 ignoreAnimations_ = ignore; |
1453 } | 1675 } |
1454 | 1676 |
1455 - (BookmarkButton*)buttonThatMouseIsIn { | 1677 - (BookmarkButton*)buttonThatMouseIsIn { |
1456 return buttonThatMouseIsIn_; | 1678 return buttonThatMouseIsIn_; |
1457 } | 1679 } |
1458 | 1680 |
1459 @end // BookmarkBarFolderController | 1681 @end // BookmarkBarFolderController |
OLD | NEW |