summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authorjrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-30 20:59:53 +0000
committerjrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-30 20:59:53 +0000
commitfdc04cc5d7d91c38efcfb6c9f7881930e4baa1c0 (patch)
tree914d030330c7221ed57b81f8146283ef08abdddb /chrome/browser/cocoa
parent7cd363601dfdaad7d3c9a36f4a4085e5e039fa05 (diff)
downloadchromium_src-fdc04cc5d7d91c38efcfb6c9f7881930e4baa1c0.zip
chromium_src-fdc04cc5d7d91c38efcfb6c9f7881930e4baa1c0.tar.gz
chromium_src-fdc04cc5d7d91c38efcfb6c9f7881930e4baa1c0.tar.bz2
Vertical scrolling arrows in bookmark bar folder windows when needed.
pdfs from Cole. BUG=42026 TEST=\ 1) Small folders --> no arrows. 2) Big folders --> arrow at bottom initially. 3) Move browser to bottom of screen so a small folder falls off the bottom and has an arrow. Open it and gently use scroll wheel to scroll. Make sure transition to "no arrow" looks good. Close and reopen. Scroll super-fast. Make sure it ends up in the same nice place. 4) Open big big folder. Scroll so top goes offscreen so you now have 2 scroll arrows. Use scroll wheel to gently go up and down (arrow hides and shows). Make sure transitions OK. Scroll all the way so bottom arrow disappears. Gently up and down; watch for transitions. Now FAST up and down. Make sure destination looks OK. BookmarkBarFolderWindow.xib change: BookmarkBarFolderWindowScrollView border turned off. Review URL: http://codereview.chromium.org/1813003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46114 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_controller.h12
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_controller.mm100
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm34
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_window.h9
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_window.mm44
5 files changed, 187 insertions, 12 deletions
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller.h b/chrome/browser/cocoa/bookmark_bar_folder_controller.h
index 8b88253..59efa65 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_controller.h
+++ b/chrome/browser/cocoa/bookmark_bar_folder_controller.h
@@ -64,6 +64,9 @@
// always visible.
BOOL scrollable_;
+ BOOL scrollUpArrowShown_;
+ BOOL scrollDownArrowShown_;
+
// The main view of this window (where the buttons go).
IBOutlet BookmarkBarFolderView* mainView_;
@@ -100,6 +103,10 @@
// Amount to scroll by on each timer fire. Can be + or -.
CGFloat verticalScrollDelta_;
+
+ // We need to know the size of the vertical scrolling arrows so we
+ // can obscure/unobscure them.
+ CGFloat verticalScrollArrowHeight_;
}
// Designated initializer.
@@ -150,5 +157,10 @@
- (id)folderTarget;
- (void)configureWindowLevel;
- (void)performOneScroll:(CGFloat)delta;
+
+// Return YES if we can scroll up or down.
+- (BOOL)canScrollUp;
+- (BOOL)canScrollDown;
+
@end
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller.mm b/chrome/browser/cocoa/bookmark_bar_folder_controller.mm
index 2250e42c..39797d6 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_controller.mm
+++ b/chrome/browser/cocoa/bookmark_bar_folder_controller.mm
@@ -4,6 +4,7 @@
#import "chrome/browser/cocoa/bookmark_bar_folder_controller.h"
#include "base/mac_util.h"
+#include "base/nsimage_cache_mac.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
@@ -40,7 +41,6 @@ const CGFloat kBookmarkBarFolderScrollWheelAmount =
// by at least this much.
const CGFloat kScrollViewContentWidthMargin = 2;
-
// When constraining a scrolling bookmark bar folder window to the
// screen, shrink the "constrain" by this much vertically. Currently
// this is 0.0 to avoid a problem with tracking areas leaving the
@@ -62,6 +62,9 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
// Return the new width (so that the window can be adjusted, if necessary).
- (CGFloat)adjustButtonWidths;
+// Show or hide the scroll arrows at the top/bottom of the window.
+- (void)showOrHideScrollArrows;
+
@end
@implementation BookmarkBarFolderController
@@ -78,6 +81,9 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
barController_ = barController; // WEAK
buttons_.reset([[NSMutableArray alloc] init]);
folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]);
+ NSImage* image = nsimage_cache::ImageNamed(@"menu_overflow_up.pdf");
+ DCHECK(image);
+ verticalScrollArrowHeight_ = [image size].height;
[self configureWindow];
hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]);
if (scrollable_)
@@ -334,6 +340,11 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
NSHeight(windowFrame)))];
}
+ // If scrollable, show the arrows.
+ if (scrollable_) {
+ [self showOrHideScrollArrows];
+ }
+
// Finally pop me up.
[self configureWindowLevel];
}
@@ -364,6 +375,81 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
return width;
}
+- (BOOL)canScrollUp {
+ // If removal of an arrow would make things "finished", state as
+ // such.
+ CGFloat scrollY = [scrollView_ documentVisibleRect].origin.y;
+ if (scrollUpArrowShown_)
+ scrollY -= verticalScrollArrowHeight_;
+
+ if (scrollY <= 0)
+ return NO;
+ return YES;
+}
+
+- (BOOL)canScrollDown {
+ CGFloat arrowAdjustment = 0.0;
+
+ // We do NOT adjust based on the scrollDOWN arrow. This keeps
+ // things from "jumping"; if removal of the down arrow (at the top
+ // of the window) would cause a scroll to end, we'll end.
+ if (scrollUpArrowShown_)
+ arrowAdjustment += verticalScrollArrowHeight_;
+
+ NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin;
+ NSRect documentRect = [[scrollView_ documentView] frame];
+
+ // If we are exactly the right height, return no. We need this
+ // extra conditional in the case where we've just scrolled/grown
+ // into position.
+ if (NSHeight([[self window] frame]) == NSHeight(documentRect))
+ return NO;
+
+ if ((scrollPosition.y + NSHeight([[self window] frame])) >=
+ (NSHeight(documentRect) + arrowAdjustment)) {
+ return NO;
+ }
+ return YES;
+}
+
+- (void)showOrHideScrollArrows {
+ NSRect frame = [scrollView_ frame];
+ CGFloat scrollDelta = 0.0;
+ BOOL canScrollDown = [self canScrollDown];
+ BOOL canScrollUp = [self canScrollUp];
+
+ if (canScrollUp != scrollUpArrowShown_) {
+ if (scrollUpArrowShown_) {
+ frame.origin.y -= verticalScrollArrowHeight_;
+ frame.size.height += verticalScrollArrowHeight_;
+ scrollDelta = verticalScrollArrowHeight_;
+ } else {
+ frame.origin.y += verticalScrollArrowHeight_;
+ frame.size.height -= verticalScrollArrowHeight_;
+ scrollDelta = -verticalScrollArrowHeight_;
+ }
+ }
+ if (canScrollDown != scrollDownArrowShown_) {
+ if (scrollDownArrowShown_) {
+ frame.size.height += verticalScrollArrowHeight_;
+ } else {
+ frame.size.height -= verticalScrollArrowHeight_;
+ }
+ }
+ scrollUpArrowShown_ = canScrollUp;
+ scrollDownArrowShown_ = canScrollDown;
+ [scrollView_ setFrame:frame];
+
+ // Adjust scroll based on new frame. For example, if we make room
+ // for an arrow at the bottom, adjust the scroll so the topmost item
+ // is still fully visible.
+ if (scrollDelta) {
+ NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin;
+ scrollPosition.y -= scrollDelta;
+ [[scrollView_ documentView] scrollPoint:scrollPosition];
+ }
+}
+
#pragma mark BookmarkButtonControllerProtocol
- (void)addButtonForNode:(const BookmarkNode*)node
@@ -559,6 +645,10 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
windowFrame.size.height += growAmount;
windowFrame.size.height = std::min(NSHeight(windowFrame),
screenHeightMinusMargin);
+ // Watch out for a finish that isn't the full height of the screen.
+ // We get here if using the scroll wheel to scroll by small amounts.
+ windowFrame.size.height = std::min(NSHeight(windowFrame),
+ NSHeight([mainView_ frame]));
// Don't allow scrolling to make the window smaller, ever. This
// conditional is important when processing scrollWheel events.
if (windowFrame.size.height > [[self window] frame].size.height) {
@@ -575,12 +665,16 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
(windowFrame.size.height == screenHeightMinusMargin))) {
[self endScroll];
- // If the entire view is now visible the window is no longer scrollable.
- if (NSHeight([mainView_ visibleRect]) == NSHeight([mainView_ bounds])) {
+ // If we can't scroll either up or down we are completely done.
+ // For example, perhaps we've scrolled a little and grown the
+ // window on-screen until there is now room for everything.
+ if (![self canScrollUp] && ![self canScrollDown]) {
scrollable_ = NO;
[self removeScrollTracking];
}
}
+
+ [self showOrHideScrollArrows];
}
// Perform a scroll of the window on the screen.
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm
index 65b0c90..26c1746 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm
@@ -81,6 +81,10 @@
@end
+namespace {
+const int kLotsOfNodesCount = 150;
+};
+
class BookmarkBarFolderControllerTest : public CocoaTest {
public:
BrowserTestHelper helper_;
@@ -130,12 +134,14 @@ class BookmarkBarFolderControllerTest : public CocoaTest {
}
// Add LOTS of nodes to our model if needed (e.g. scrolling).
- void AddLotsOfNodes() {
+ // Returns the number of nodes added.
+ int AddLotsOfNodes() {
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- for (int i = 0; i < 150; i++) {
+ for (int i = 0; i < kLotsOfNodesCount; i++) {
model->AddURL(folderA_, folderA_->GetChildCount(), L"repeated title",
GURL("http://www.google.com/repeated/url"));
}
+ return kLotsOfNodesCount;
}
@@ -151,7 +157,6 @@ class BookmarkBarFolderControllerTest : public CocoaTest {
[c window]; // Force nib load.
return c;
}
-
};
TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
@@ -328,7 +333,7 @@ TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) {
TEST_F(BookmarkBarFolderControllerTest, SimpleScroll) {
scoped_nsobject<BookmarkBarFolderController> bbfc;
- AddLotsOfNodes();
+ int nodecount = AddLotsOfNodes();
bbfc.reset(SimpleBookmarkBarFolderController());
EXPECT_TRUE(bbfc.get());
[bbfc showWindow:bbfc.get()];
@@ -337,6 +342,10 @@ TEST_F(BookmarkBarFolderControllerTest, SimpleScroll) {
EXPECT_LT(NSHeight([[bbfc window] frame]),
NSHeight([[NSScreen mainScreen] frame]));
+ // Verify the logic used by the scroll arrow code.
+ EXPECT_TRUE([bbfc canScrollUp]);
+ EXPECT_FALSE([bbfc canScrollDown]);
+
// Scroll it up. Make sure the window has gotten bigger each time.
// Also, for each scroll, make sure our hit test finds a new button
// (to confirm the content area changed).
@@ -345,24 +354,35 @@ TEST_F(BookmarkBarFolderControllerTest, SimpleScroll) {
CGFloat height = NSHeight([[bbfc window] frame]);
[bbfc performOneScroll:60];
EXPECT_GT(NSHeight([[bbfc window] frame]), height);
- NSView* hit = [[[bbfc window] contentView] hitTest:NSMakePoint(10, 10)];
+ NSView* hit = [[[bbfc window] contentView] hitTest:NSMakePoint(22, 22)];
EXPECT_NE(hit, savedHit);
savedHit = hit;
}
// Keep scrolling up; make sure we never get bigger than the screen.
// Also confirm we never scroll the window off the screen.
+ bool bothAtOnce = false;
NSRect screenFrame = [[NSScreen mainScreen] frame];
- for (int i=0; i<100; i++) {
+ for (int i = 0; i < nodecount; i++) {
[bbfc performOneScroll:60];
EXPECT_TRUE(NSContainsRect(screenFrame,
[[bbfc window] frame]));
+ // Make sure, sometime during our scroll, we have the ability to
+ // scroll in either direction.
+ if ([bbfc canScrollUp] &&
+ [bbfc canScrollDown])
+ bothAtOnce = true;
}
+ EXPECT_TRUE(bothAtOnce);
+
+ // Once we've scrolled to the end, our only option should be to scroll back.
+ EXPECT_FALSE([bbfc canScrollUp]);
+ EXPECT_TRUE([bbfc canScrollDown]);
// Now scroll down and make sure the window size does not change.
// Also confirm we never scroll the window off the screen the other
// way.
- for (int i=0; i<200; i++) {
+ for (int i=0; i<nodecount+50; i++) {
CGFloat height = NSHeight([[bbfc window] frame]);
[bbfc performOneScroll:-60];
EXPECT_EQ(height, NSHeight([[bbfc window] frame]));
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_window.h b/chrome/browser/cocoa/bookmark_bar_folder_window.h
index c35bd2e3..7337521 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_window.h
+++ b/chrome/browser/cocoa/bookmark_bar_folder_window.h
@@ -6,6 +6,9 @@
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_FOLDER_WINDOW_H_
#import <Cocoa/Cocoa.h>
+#import "base/cocoa_protocols_mac.h"
+#include "base/scoped_nsobject.h"
+
// Window for a bookmark folder "menu". This menu pops up when you
// click on a bookmark button that represents a folder of bookmarks.
@@ -15,7 +18,11 @@
// Content view for the above window. "Stock" other than the drawing
// of rounded corners. Only used in the nib.
-@interface BookmarkBarFolderWindowContentView : NSView
+@interface BookmarkBarFolderWindowContentView : NSView {
+ // Arrows to show ability to scroll up and down as needed.
+ scoped_nsobject<NSImage> arrowUpImage_;
+ scoped_nsobject<NSImage> arrowDownImage_;
+}
@end
// Scroll view that contains the main view (where the buttons go).
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_window.mm b/chrome/browser/cocoa/bookmark_bar_folder_window.mm
index 732bed1..841fa7c 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_window.mm
+++ b/chrome/browser/cocoa/bookmark_bar_folder_window.mm
@@ -5,6 +5,7 @@
#import "chrome/browser/cocoa/bookmark_bar_folder_window.h"
#import "base/logging.h"
+#include "base/nsimage_cache_mac.h"
#import "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/bookmark_bar_folder_controller.h"
#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
@@ -38,6 +39,46 @@ const CGFloat kViewCornerRadius = 4.0;
@implementation BookmarkBarFolderWindowContentView
+- (void)awakeFromNib {
+ arrowUpImage_.reset([nsimage_cache::ImageNamed(@"menu_overflow_up.pdf")
+ retain]);
+ arrowDownImage_.reset([nsimage_cache::ImageNamed(@"menu_overflow_down.pdf")
+ retain]);
+}
+
+// Draw the arrows at the top and bottom of the folder window as a
+// visual indication that scrolling is possible. We always draw the
+// scrolling arrows; when not relevant (e.g. when not scrollable), the
+// scroll view overlaps me and the arrows aren't visible.
+- (void)drawScrollArrows:(NSRect)rect {
+ NSRect visibleRect = [self bounds];
+
+ // On top
+ [arrowUpImage_ setFlipped:[self isFlipped]];
+ NSRect imageRect = NSZeroRect;
+ imageRect.size = [arrowUpImage_ size];
+ NSRect drawRect = NSOffsetRect(
+ imageRect,
+ (NSWidth(visibleRect) - NSWidth(imageRect)) / 2,
+ NSHeight(visibleRect) - NSHeight(imageRect));
+ [arrowUpImage_ drawInRect:drawRect
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+
+ // On bottom
+ [arrowDownImage_ setFlipped:[self isFlipped]];
+ imageRect = NSZeroRect;
+ imageRect.size = [arrowDownImage_ size];
+ drawRect = NSOffsetRect(imageRect,
+ (NSWidth(visibleRect) - NSWidth(imageRect)) / 2,
+ 0);
+ [arrowDownImage_ drawInRect:drawRect
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+}
+
- (void)drawRect:(NSRect)rect {
NSRect bounds = [self bounds];
// Like NSMenus, only the bottom corners are rounded.
@@ -71,6 +112,8 @@ const CGFloat kViewCornerRadius = 4.0;
glowColor, 0.75,
nil]);
[gradient drawInBezierPath:bezier angle:0.0];
+
+ [self drawScrollArrows:rect];
}
@end
@@ -89,5 +132,4 @@ const CGFloat kViewCornerRadius = 4.0;
[[[self window] windowController] scrollWheel:theEvent];
}
-
@end