summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-26 20:20:51 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-26 20:20:51 +0000
commit71f4c1dc80499f254b9f06e510002ff3b43a87e0 (patch)
tree6eeb8693a47e7990e5bb3995812e2fa641bcda09 /chrome/browser/cocoa
parent7cc6c0ba59df63f9f084f8cdfc695fa7b4ae1823 (diff)
downloadchromium_src-71f4c1dc80499f254b9f06e510002ff3b43a87e0.zip
chromium_src-71f4c1dc80499f254b9f06e510002ff3b43a87e0.tar.gz
chromium_src-71f4c1dc80499f254b9f06e510002ff3b43a87e0.tar.bz2
Updates to clean up default theme and add hover states.
Path by Cole. BUG=http://crbug.com/18573;http://crbug.com/18574;http://crbug.com/18360;http://crbug.com/18438 TEST=none Review URL: http://codereview.chromium.org/165499 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24512 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/background_gradient_view.mm2
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller.mm2
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm50
-rw-r--r--chrome/browser/cocoa/browser_window_controller_unittest.mm2
-rw-r--r--chrome/browser/cocoa/download_item_cell.mm6
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.h11
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.mm119
-rw-r--r--chrome/browser/cocoa/gradient_button_cell_unittest.mm22
-rw-r--r--chrome/browser/cocoa/status_bubble_mac.mm35
-rw-r--r--chrome/browser/cocoa/status_bubble_mac_unittest.mm25
-rw-r--r--chrome/browser/cocoa/tab_cell.mm32
-rw-r--r--chrome/browser/cocoa/tab_controller.h4
-rw-r--r--chrome/browser/cocoa/tab_controller.mm26
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.h12
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.mm70
-rw-r--r--chrome/browser/cocoa/tab_strip_view.mm2
-rw-r--r--chrome/browser/cocoa/tab_view.h7
-rw-r--r--chrome/browser/cocoa/tab_view.mm188
-rw-r--r--chrome/browser/cocoa/tab_view_unittest.mm5
-rw-r--r--chrome/browser/cocoa/toolbar_controller.h4
-rw-r--r--chrome/browser/cocoa/toolbar_controller.mm33
21 files changed, 505 insertions, 152 deletions
diff --git a/chrome/browser/cocoa/background_gradient_view.mm b/chrome/browser/cocoa/background_gradient_view.mm
index df3527a..de35705 100644
--- a/chrome/browser/cocoa/background_gradient_view.mm
+++ b/chrome/browser/cocoa/background_gradient_view.mm
@@ -5,7 +5,7 @@
#include "chrome/browser/cocoa/background_gradient_view.h"
#define kToolbarTopOffset 12
-#define kToolbarMaxHeight 128
+#define kToolbarMaxHeight 100
@implementation BackgroundGradientView
@synthesize showsDivider = showsDivider_;
diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm
index 84cbbd3..ed45bcc 100644
--- a/chrome/browser/cocoa/bookmark_bar_controller.mm
+++ b/chrome/browser/cocoa/bookmark_bar_controller.mm
@@ -45,7 +45,7 @@
namespace {
// Our height, when opened.
-const int kBookmarkBarHeight = 30;
+const int kBookmarkBarHeight = 28;
// Magic numbers from Cole
const CGFloat kDefaultBookmarkWidth = 150.0;
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
index 03c6146..33e5b6b 100644
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ b/chrome/browser/cocoa/browser_window_controller.mm
@@ -96,6 +96,7 @@ willPositionSheet:(NSWindow*)sheet
// Repositions the windows subviews.
- (void)layoutSubviews;
+
@end
@@ -927,8 +928,6 @@ willPositionSheet:(NSWindow*)sheet
- (void)userChangedTheme {
[self setTheme];
[self applyTheme];
-
- [tabStripController_ userChangedTheme];
}
- (GTMTheme *)gtm_themeForWindow:(NSWindow*)window {
@@ -1133,6 +1132,7 @@ willPositionSheet:(NSWindow*)sheet
[theme_ backgroundPatternColorForStyle:GTMThemeStyleWindow
state:[[self window] isMainWindow]];
[[self window] setBackgroundColor:color];
+ [tabStripController_ applyTheme];
}
// Private method to layout browser window subviews. Positions the toolbar and
@@ -1229,36 +1229,45 @@ willPositionSheet:(NSWindow*)sheet
[theme setValue:frameImage
forAttribute:@"backgroundImage"
style:GTMThemeStyleWindow
- state:YES];
+ state:GTMThemeStateActiveWindow];
- NSColor* tabTextColor = [NSColor blackColor];
+ NSColor* tabTextColor =
+ provider->GetNSColor(BrowserThemeProvider::COLOR_TAB_TEXT);
[theme setValue:tabTextColor
forAttribute:@"textColor"
style:GTMThemeStyleToolBar
- state:YES];
+ state:GTMThemeStateActiveWindow];
- NSColor* tabInactiveTextColor = [NSColor grayColor];
+ NSColor* tabInactiveTextColor =
+ provider->GetNSColor(BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT);
[theme setValue:tabInactiveTextColor
forAttribute:@"textColor"
- style:GTMThemeStyleToolBar
- state:NO];
+ style:GTMThemeStyleTabBarDeselected
+ state:GTMThemeStateActiveWindow];
- NSColor* bookmarkBarTextColor = [NSColor blackColor];
+ NSColor* bookmarkBarTextColor =
+ provider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
[theme setValue:bookmarkBarTextColor
forAttribute:@"textColor"
style:GTMThemeStyleBookmarksBarButton
- state:YES];
+ state:GTMThemeStateActiveWindow];
[theme setValue:frameInactiveImage
forAttribute:@"backgroundImage"
style:GTMThemeStyleWindow
- state:NO];
+ state:0];
NSImage* toolbarImage = provider->GetNSImageNamed(IDR_THEME_TOOLBAR);
[theme setValue:toolbarImage
forAttribute:@"backgroundImage"
style:GTMThemeStyleToolBar
- state:YES];
+ state:GTMThemeStateActiveWindow];
+ NSImage* toolbarBackgroundImage =
+ provider->GetNSImageNamed(IDR_THEME_TAB_BACKGROUND);
+ [theme setValue:toolbarBackgroundImage
+ forAttribute:@"backgroundImage"
+ style:GTMThemeStyleTabBarDeselected
+ state:GTMThemeStateActiveWindow];
NSImage* toolbarButtonImage =
provider->GetNSImageNamed(IDR_THEME_BUTTON_BACKGROUND);
@@ -1266,7 +1275,7 @@ willPositionSheet:(NSWindow*)sheet
[theme setValue:toolbarButtonImage
forAttribute:@"backgroundImage"
style:GTMThemeStyleToolBarButton
- state:YES];
+ state:GTMThemeStateActiveWindow];
} else {
NSColor* startColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.0];
NSColor* endColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.3];
@@ -1277,12 +1286,12 @@ willPositionSheet:(NSWindow*)sheet
[theme setValue:gradient
forAttribute:@"gradient"
style:GTMThemeStyleToolBarButton
- state:YES];
+ state:GTMThemeStateActiveWindow];
[theme setValue:gradient
forAttribute:@"gradient"
style:GTMThemeStyleToolBarButton
- state:NO];
+ state:GTMThemeStateActiveWindow];
}
NSColor* toolbarButtonIconColor =
@@ -1290,13 +1299,20 @@ willPositionSheet:(NSWindow*)sheet
[theme setValue:toolbarButtonIconColor
forAttribute:@"iconColor"
style:GTMThemeStyleToolBarButton
- state:YES];
+ state:GTMThemeStateActiveWindow];
NSColor* toolbarButtonBorderColor = toolbarButtonIconColor;
[theme setValue:toolbarButtonBorderColor
forAttribute:@"borderColor"
style:GTMThemeStyleToolBar
- state:YES];
+ state:GTMThemeStateActiveWindow];
+
+ NSColor* toolbarBackgroundColor =
+ provider->GetNSColor(BrowserThemeProvider::COLOR_TOOLBAR);
+ [theme setValue:toolbarBackgroundColor
+ forAttribute:@"backgroundColor"
+ style:GTMThemeStyleToolBar
+ state:GTMThemeStateActiveWindow];
return theme;
}
diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm
index 743c90c..68273e6 100644
--- a/chrome/browser/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/browser_window_controller_unittest.mm
@@ -192,7 +192,7 @@ TEST_F(BrowserWindowControllerTest, TestResizeViews) {
[tabstrip setFrame:tabstripFrame];
// Make sure each view is as tall as we expect.
- ASSERT_EQ(39, NSHeight([toolbar frame]));
+ ASSERT_EQ(36, NSHeight([toolbar frame]));
ASSERT_EQ(0, NSHeight([infobar frame]));
// Force a layout and check each view's frame.
diff --git a/chrome/browser/cocoa/download_item_cell.mm b/chrome/browser/cocoa/download_item_cell.mm
index 7c82b2b..3890807 100644
--- a/chrome/browser/cocoa/download_item_cell.mm
+++ b/chrome/browser/cocoa/download_item_cell.mm
@@ -333,8 +333,9 @@ const int kCompleteAnimationDuration = 2.5;
controlView:controlView
outerPath:buttonOuterPath
innerPath:buttonInnerPath
- showHighlightGradient:[self isMouseOverButtonPart]
showClickedGradient:[self isButtonPartPressed]
+ showHighlightGradient:[self isMouseOverButtonPart]
+ hoverAlpha:0.0
active:active
cellFrame:cellFrame];
@@ -342,8 +343,9 @@ const int kCompleteAnimationDuration = 2.5;
controlView:controlView
outerPath:dropdownOuterPath
innerPath:dropdownInnerPath
- showHighlightGradient:[self isMouseOverDropdownPart]
showClickedGradient:[self isDropdownPartPressed]
+ showHighlightGradient:[self isMouseOverDropdownPart]
+ hoverAlpha:0.0
active:active
cellFrame:cellFrame];
diff --git a/chrome/browser/cocoa/gradient_button_cell.h b/chrome/browser/cocoa/gradient_button_cell.h
index e9b4e79..79be6ff 100644
--- a/chrome/browser/cocoa/gradient_button_cell.h
+++ b/chrome/browser/cocoa/gradient_button_cell.h
@@ -34,7 +34,8 @@ typedef NSInteger ButtonType;
BOOL isMouseInside_;
scoped_nsobject<NSTrackingArea> trackingArea_;
BOOL shouldTheme_;
- scoped_nsobject<NSGradient> gradient_;
+ CGFloat hoverAlpha_; // 0-1. Controls the alpha during mouse hover
+ NSTimeInterval lastHoverUpdate_;
scoped_nsobject<NSImage> underlayImage_;
}
@@ -45,8 +46,9 @@ typedef NSInteger ButtonType;
controlView:(NSView*)controlView
outerPath:(NSBezierPath*)outerPath
innerPath:(NSBezierPath*)innerPath
- showHighlightGradient:(BOOL)showHighlightGradient
showClickedGradient:(BOOL)showClickedGradient
+ showHighlightGradient:(BOOL)showHighlightGradient
+ hoverAlpha:(CGFloat)hoverAlpha
active:(BOOL)active
cellFrame:(NSRect)cellFrame;
@@ -54,6 +56,11 @@ typedef NSInteger ButtonType;
- (NSImage*)underlayImage;
- (void)setUnderlayImage:(NSImage*)image;
+// Let the view know when the mouse moves in and out. A timer will update
+// the current hoverAlpha_ based on these events.
+- (void)setMouseInside:(BOOL)flag animate:(BOOL)animate;
+
+@property(assign, nonatomic)CGFloat hoverAlpha;
@end
@interface GradientButtonCell(TestingAPI)
diff --git a/chrome/browser/cocoa/gradient_button_cell.mm b/chrome/browser/cocoa/gradient_button_cell.mm
index 17d4998..df2a7c9 100644
--- a/chrome/browser/cocoa/gradient_button_cell.mm
+++ b/chrome/browser/cocoa/gradient_button_cell.mm
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import "base/scoped_nsobject.h"
#include "chrome/browser/cocoa/gradient_button_cell.h"
#import "third_party/GTM/AppKit/GTMTheme.h"
-#import "base/scoped_nsobject.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
@interface GradientButtonCell (Private)
- (void)sharedInit;
@@ -12,8 +13,48 @@
inView:(NSView*)controlView;
@end
+static const NSTimeInterval kAnimationShowDuration = 0.2;
+static const NSTimeInterval kAnimationHideDuration = 0.4;
@implementation GradientButtonCell
+@synthesize hoverAlpha = hoverAlpha_;
+
+- (void)adjustHoverValue {
+ NSTimeInterval thisUpdate = [NSDate timeIntervalSinceReferenceDate];
+
+ NSTimeInterval elapsed = thisUpdate - lastHoverUpdate_;
+
+ CGFloat opacity = [self hoverAlpha];
+ if (isMouseInside_) {
+ opacity += elapsed / kAnimationShowDuration;
+ } else {
+ opacity -= elapsed / kAnimationHideDuration;
+ }
+
+ if (!isMouseInside_ && opacity < 0) {
+ opacity = 0;
+ } else if (isMouseInside_ && opacity > 1) {
+ opacity = 1;
+ } else {
+ [self performSelector:_cmd withObject:nil afterDelay:0.02];
+ }
+ lastHoverUpdate_ = thisUpdate;
+ [self setHoverAlpha:opacity];
+
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (void)setMouseInside:(BOOL)flag animate:(BOOL)animated {
+ isMouseInside_ = flag;
+ if (animated) {
+ lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
+ [self adjustHoverValue];
+ } else {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ [self setHoverAlpha:flag ? 1.0 : 0.0];
+ }
+ [[self controlView] setNeedsDisplay:YES];
+}
// For nib instantiations
- (id)initWithCoder:(NSCoder*)decoder {
@@ -33,10 +74,6 @@
- (void)sharedInit {
shouldTheme_ = YES;
- NSColor* startColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.666];
- NSColor* endColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.333];
- gradient_.reset([[NSGradient alloc]
- initWithColorsAndLocations:startColor, 0.33, endColor, 1.0, nil]);
}
- (void)setShouldTheme:(BOOL)shouldTheme {
@@ -59,13 +96,11 @@
}
- (void)mouseEntered:(NSEvent *)theEvent {
- isMouseInside_ = YES;
- [[self controlView] setNeedsDisplay:YES];
+ [self setMouseInside:YES animate:YES];
}
- (void)mouseExited:(NSEvent *)theEvent {
- isMouseInside_ = NO;
- [[self controlView] setNeedsDisplay:YES];
+ [self setMouseInside:NO animate:YES];
}
- (BOOL)isMouseInside {
@@ -102,13 +137,11 @@
controlView:(NSView*)controlView
outerPath:(NSBezierPath*)outerPath
innerPath:(NSBezierPath*)innerPath
- showHighlightGradient:(BOOL)showHighlightGradient
showClickedGradient:(BOOL)showClickedGradient
+ showHighlightGradient:(BOOL)showHighlightGradient
+ hoverAlpha:(CGFloat)hoverAlpha
active:(BOOL)active
cellFrame:(NSRect)cellFrame {
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.25] set];
- [outerPath stroke];
-
NSImage* backgroundImage =
[theme backgroundImageForStyle:GTMThemeStyleToolBarButton state:YES];
@@ -129,45 +162,68 @@
}
}
- if (!showClickedGradient && showHighlightGradient) {
+ BOOL isCustomTheme = backgroundImage != nil;
+
+ if (!showClickedGradient && [self isEnabled]) {
[NSGraphicsContext saveGraphicsState];
[innerPath addClip];
// Draw the inner glow.
- [innerPath setLineWidth:2];
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.9] setStroke];
- [innerPath stroke];
-
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.9] setStroke];
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setFill];
+ if (hoverAlpha > 0) {
+ [innerPath setLineWidth:2];
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2 * hoverAlpha] setStroke];
+ [innerPath stroke];
+ }
// Draw the top inner highlight.
NSAffineTransform* highlightTransform = [NSAffineTransform transform];
[highlightTransform translateXBy:1 yBy:1];
scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]);
[highlightPath transformUsingAffineTransform:highlightTransform];
-
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setStroke];
[highlightPath stroke];
- [gradient_ drawInBezierPath:innerPath angle:90.0];
+ CGFloat startAlpha = 0.6 + 0.3 * hoverAlpha;
+ CGFloat endAlpha = 0.333 * hoverAlpha;
+
+ if (isCustomTheme) {
+ startAlpha = 0.2 + 0.35 * hoverAlpha;
+ endAlpha = 0.333 * hoverAlpha;
+ }
+
+ NSColor* startColor =
+ [NSColor colorWithCalibratedWhite:1.0
+ alpha:startAlpha];
+ NSColor* endColor =
+ [NSColor colorWithCalibratedWhite:1.0 - 0.15 * hoverAlpha
+ alpha:endAlpha];
+ scoped_nsobject<NSBezierPath> gradient([[NSGradient alloc]
+ initWithColorsAndLocations:startColor, hoverAlpha * 0.33,
+ endColor, 1.0, nil]);
+
+ [gradient drawInBezierPath:innerPath angle:90.0];
[NSGraphicsContext restoreGraphicsState];
}
+ // Draw the outer stroke
NSColor* stroke = [theme strokeColorForStyle:GTMThemeStyleToolBarButton
state:active];
+
+ if (showClickedGradient) {
+ stroke = [NSColor colorWithCalibratedWhite:0.0 alpha:0.3];
+ }
[stroke setStroke];
[innerPath setLineWidth:1];
[innerPath stroke];
}
-
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
// Constants from Cole. Will kConstant them once the feedback loop
// is complete.
NSRect drawFrame = NSInsetRect(cellFrame, 1.5, 1.5);
- NSRect innerFrame = NSInsetRect(cellFrame, 2, 2);
+ NSRect innerFrame = NSInsetRect(cellFrame, 2, 1);
ButtonType type = [[(NSControl*)controlView cell] tag];
switch (type) {
case kMiddleButtonType:
@@ -212,8 +268,9 @@
controlView:controlView
outerPath:outerPath
innerPath:innerPath
- showHighlightGradient:YES
showClickedGradient:pressed
+ showHighlightGradient:[self isHighlighted]
+ hoverAlpha:[self hoverAlpha]
active:active
cellFrame:cellFrame];
}
@@ -243,9 +300,14 @@
CGContextRef context =
(CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]);
+ NSColor* color = [theme iconColorForStyle:GTMThemeStyleToolBarButton
+ state:YES];
+
if (isTemplate) {
scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
- [shadow setShadowColor:[NSColor whiteColor]];
+ NSColor *shadowColor = [color gtm_legibleTextColor];
+ shadowColor = [shadowColor colorWithAlphaComponent:0.25];
+ [shadow setShadowColor:shadowColor];
[shadow setShadowOffset:NSMakeSize(0, -1.0)];
[shadow setShadowBlurRadius:1.0];
[shadow set];
@@ -256,14 +318,13 @@
CGContextBeginTransparencyLayer(context, 0);
NSRect imageRect = NSZeroRect;
imageRect.size = [[self image] size];
+ NSRect drawRect = [self imageRectForBounds:cellFrame];
[[self image] setFlipped:[controlView isFlipped]];
- [[self image] drawInRect:[self imageRectForBounds:cellFrame]
+ [[self image] drawInRect:drawRect
fromRect:imageRect
operation:NSCompositeSourceOver
fraction:[self isEnabled] ? 1.0 : 0.5];
if (isTemplate) {
- NSColor* color = [theme iconColorForStyle:GTMThemeStyleToolBarButton
- state:YES];
if (color) {
[color set];
NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop);
diff --git a/chrome/browser/cocoa/gradient_button_cell_unittest.mm b/chrome/browser/cocoa/gradient_button_cell_unittest.mm
index 3e0f162..e9229a7 100644
--- a/chrome/browser/cocoa/gradient_button_cell_unittest.mm
+++ b/chrome/browser/cocoa/gradient_button_cell_unittest.mm
@@ -9,6 +9,10 @@
#import "chrome/browser/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
+@interface GradientButtonCell (HoverValueTesting)
+- (void)adjustHoverValue;
+@end
+
namespace {
class GradientButtonCellTest : public testing::Test {
@@ -36,7 +40,25 @@ TEST_F(GradientButtonCellTest, AddRemove) {
// Test drawing, mostly to ensure nothing leaks or crashes.
TEST_F(GradientButtonCellTest, Display) {
+ [[view_ cell] setHoverAlpha:0.0];
+ [view_ display];
+ [[view_ cell] setHoverAlpha:0.5];
[view_ display];
+ [[view_ cell] setHoverAlpha:1.0];
+ [view_ display];
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(GradientButtonCellTest, Hover) {
+ GradientButtonCell* cell = [view_ cell];
+ [cell setMouseInside:YES animate:NO];
+ EXPECT_EQ([[view_ cell] hoverAlpha], 1.0);
+
+ [cell setMouseInside:NO animate:YES];
+ CGFloat alpha1 = [cell hoverAlpha];
+ [cell adjustHoverValue];
+ CGFloat alpha2 = [cell hoverAlpha];
+ EXPECT_TRUE(alpha2 < alpha1);
}
// Tracking rects
diff --git a/chrome/browser/cocoa/status_bubble_mac.mm b/chrome/browser/cocoa/status_bubble_mac.mm
index 67b920b..a415421 100644
--- a/chrome/browser/cocoa/status_bubble_mac.mm
+++ b/chrome/browser/cocoa/status_bubble_mac.mm
@@ -9,6 +9,8 @@
#include "base/sys_string_conversions.h"
#include "googleurl/src/gurl.h"
#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+#import "third_party/GTM/AppKit/GTMTheme.h"
namespace {
@@ -49,10 +51,12 @@ enum BubbleStyle {
@private
NSString* content_;
BubbleStyle style_;
+ NSWindow* parent_;
}
- (void)setContent:(NSString*)content;
- (void)setStyle:(BubbleStyle)style;
+- (void)setParent:(NSWindow*)parent;
- (NSFont*)font;
@end
@@ -220,6 +224,8 @@ void StatusBubbleMac::Create() {
StatusBubbleViewCocoa* view =
[[[StatusBubbleViewCocoa alloc] initWithFrame:NSZeroRect] autorelease];
+ [view setParent:parent_];
+
[window_ setContentView:view];
[parent_ addChildWindow:window_ ordered:NSWindowAbove];
@@ -263,6 +269,16 @@ void StatusBubbleMac::FadeOut() {
[self setNeedsDisplay:YES];
}
+- (void)setParent:(NSWindow*)parent {
+ [parent_ autorelease];
+ parent_ = [parent retain];
+ [self setNeedsDisplay:YES];
+}
+
+- (GTMTheme*)gtm_theme {
+ return [parent_ gtm_theme];
+}
+
- (NSFont*)font {
return [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
}
@@ -300,13 +316,24 @@ void StatusBubbleMac::FadeOut() {
// Background / Edge
NSRect bounds = [self bounds];
+ bounds = NSInsetRect(bounds, 0.5, 0.5);
NSBezierPath *border = [NSBezierPath gtm_bezierPathWithRoundRect:bounds
topLeftCornerRadius:tl_radius
topRightCornerRadius:tr_radius
bottomLeftCornerRadius:bl_radius
bottomRightCornerRadius:br_radius];
- [[NSColor colorWithDeviceWhite:kWindowFill alpha:1.0f] set];
+ NSColor* color =
+ [[self gtm_theme] backgroundColorForStyle:GTMThemeStyleToolBar
+ state:GTMThemeStateActiveWindow];
+
+ // workaround for default theme
+ // TODO(alcor) next GTM update return nil for background color if not set;
+ if ([color isEqual:[NSColor colorWithCalibratedWhite:0.5 alpha:1.0]])
+ color = nil;
+ if (!color)
+ color = [NSColor colorWithCalibratedWhite:0.9 alpha:1.0];
+ [color set];
[border fill];
border = [NSBezierPath gtm_bezierPathWithRoundRect:bounds
@@ -319,11 +346,11 @@ void StatusBubbleMac::FadeOut() {
[border stroke];
// Text
-
+ NSColor* textColor = [color gtm_legibleTextColor];
NSFont* textFont = [self font];
NSShadow* textShadow = [[[NSShadow alloc] init] autorelease];
- [textShadow setShadowBlurRadius:1.5f];
- [textShadow setShadowColor:[NSColor whiteColor]];
+ [textShadow setShadowBlurRadius:0.0f];
+ [textShadow setShadowColor:[textColor gtm_legibleTextColor]];
[textShadow setShadowOffset:NSMakeSize(0.0f, -1.0f)];
NSDictionary* textDict = [NSDictionary dictionaryWithObjectsAndKeys:
diff --git a/chrome/browser/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/cocoa/status_bubble_mac_unittest.mm
index b0fa87b..b4697875 100644
--- a/chrome/browser/cocoa/status_bubble_mac_unittest.mm
+++ b/chrome/browser/cocoa/status_bubble_mac_unittest.mm
@@ -10,6 +10,16 @@
#include "chrome/browser/cocoa/status_bubble_mac.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
+#import "third_party/GTM/AppKit/GTMTheme.h"
+
+@interface StatusBubbleMacTestWindowDelegate : NSObject <GTMThemeDelegate>;
+@end
+@implementation StatusBubbleMacTestWindowDelegate
+- (GTMTheme *)gtm_themeForWindow:(NSWindow *)window {
+ NSLog(@"gettheme");
+ return [[[GTMTheme alloc] init] autorelease];
+}
+@end
class StatusBubbleMacTest : public testing::Test {
public:
@@ -29,11 +39,24 @@ class StatusBubbleMacTest : public testing::Test {
NSString* GetURLText() {
return bubble_->url_text_;
}
-
+ NSWindow* GetWindow() {
+ return bubble_->window_;
+ }
+ NSWindow* GetParent() {
+ return bubble_->parent_;
+ }
CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc...
scoped_ptr<StatusBubbleMac> bubble_;
};
+TEST_F(StatusBubbleMacTest, Theme) {
+ bubble_->SetStatus(L"Theme test"); // Creates the window
+ [GetParent() setDelegate:
+ [[[StatusBubbleMacTestWindowDelegate alloc] init] autorelease]];
+ EXPECT_TRUE([GetParent() gtm_theme] != nil);
+ EXPECT_TRUE([[GetWindow() contentView] gtm_theme] != nil);
+}
+
TEST_F(StatusBubbleMacTest, SetStatus) {
bubble_->SetStatus(L"");
bubble_->SetStatus(L"This is a test");
diff --git a/chrome/browser/cocoa/tab_cell.mm b/chrome/browser/cocoa/tab_cell.mm
index 326f1f7..6823e3b 100644
--- a/chrome/browser/cocoa/tab_cell.mm
+++ b/chrome/browser/cocoa/tab_cell.mm
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/tab_cell.h"
#import "third_party/GTM/AppKit/GTMTheme.h"
#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+
@implementation TabCell
- (id)initTextCell:(NSString *)aString {
@@ -18,7 +20,7 @@
- (NSBackgroundStyle)interiorBackgroundStyle {
return [[[self controlView] gtm_theme]
- interiorBackgroundStyleForStyle:GTMThemeStyleTabBarSelected
+ interiorBackgroundStyleForStyle:GTMThemeStyleToolBar
state:GTMThemeStateActiveWindow];
}
@@ -37,6 +39,34 @@
inView:controlView];
}
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
+ GTMTheme* theme = [[self controlView] gtm_theme];
+ NSColor* textColor = [theme textColorForStyle:GTMThemeStyleToolBar
+ state:[self isHighlighted]];
+
+ scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
+ [textShadow setShadowBlurRadius:0.0f];
+ [textShadow setShadowColor:[textColor gtm_legibleTextColor]];
+ [textShadow setShadowOffset:NSMakeSize(0.0f, -1.0f)];
+
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [self font], NSFontAttributeName,
+ textColor, NSForegroundColorAttributeName,
+ textShadow.get(), NSShadowAttributeName,
+ nil];
+
+ [[self title] drawInRect:[self titleRectForBounds:cellFrame]
+ withAttributes:attributes];
+
+ NSRect imageBounds = NSZeroRect;
+ imageBounds.size = [[self image] size];
+ [[self image] drawInRect:[self imageRectForBounds:cellFrame]
+ fromRect:imageBounds
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+}
+
- (void)highlight:(BOOL)flag
withFrame:(NSRect)cellFrame
inView:(NSView *)controlView {
diff --git a/chrome/browser/cocoa/tab_controller.h b/chrome/browser/cocoa/tab_controller.h
index bffdf7f..565c95c 100644
--- a/chrome/browser/cocoa/tab_controller.h
+++ b/chrome/browser/cocoa/tab_controller.h
@@ -35,8 +35,8 @@ enum TabLoadingState {
@interface TabController : NSViewController {
@private
- IBOutlet NSButton* backgroundButton_;
IBOutlet NSView* iconView_;
+ IBOutlet NSTextField* titleView_;
IBOutlet NSMenu* contextMenu_;
IBOutlet NSButton* closeButton_;
@@ -74,6 +74,8 @@ enum TabLoadingState {
- (void)setIconView:(NSView*)iconView;
- (NSView*)iconView;
+// (Re)apply the current theme.
+- (void)applyTheme;
@end
@interface TabController(TestingAPI)
diff --git a/chrome/browser/cocoa/tab_controller.mm b/chrome/browser/cocoa/tab_controller.mm
index cff9f81..96d7e5d 100644
--- a/chrome/browser/cocoa/tab_controller.mm
+++ b/chrome/browser/cocoa/tab_controller.mm
@@ -7,6 +7,7 @@
#import "chrome/browser/cocoa/tab_controller.h"
#import "chrome/browser/cocoa/tab_controller_target.h"
#import "chrome/browser/cocoa/tab_view.h"
+#import "third_party/GTM/AppKit/GTMTheme.h"
@interface TabController(Private)
- (void)updateVisibility;
@@ -53,7 +54,7 @@
selected_ = selected;
[(TabView *)[self view] setState:selected];
[self updateVisibility];
- [[self view] setNeedsDisplay:YES];
+ [self applyTheme];
}
// Called when the tab's nib is done loading and all outlets are hooked up.
@@ -61,9 +62,6 @@
// Ensure we don't show favicon if the tab is already too small to begin with.
[self updateVisibility];
[(id)iconView_ setImage:nsimage_cache::ImageNamed(@"nav.pdf")];
- [[self view] addSubview:backgroundButton_
- positioned:NSWindowBelow
- relativeTo:nil];
[self internalSetSelected:selected_];
}
@@ -91,7 +89,7 @@
}
- (void)setTitle:(NSString *)title {
- [backgroundButton_ setToolTip:title];
+ [[self view] setToolTip:title];
[super setTitle:title];
}
@@ -119,7 +117,7 @@
}
- (NSString *)toolTip {
- return [backgroundButton_ toolTip];
+ return [[self view] toolTip];
}
// Return a rough approximation of the number of icons we could fit in the
@@ -168,4 +166,20 @@
[self updateVisibility];
}
+- (void)applyTheme {
+ GTMTheme* theme = [[self view] gtm_theme];
+ NSColor* color = nil;
+ if (!selected_) {
+ color = [theme textColorForStyle:GTMThemeStyleTabBarDeselected
+ state:GTMThemeStateActiveWindow];
+ }
+ // Default to the selected text color unless told otherwise.
+ if (!color) {
+ color = [theme textColorForStyle:GTMThemeStyleToolBar
+ state:GTMThemeStateActiveWindow];
+ }
+
+ [titleView_ setTextColor:color ? color : [NSColor textColor]];
+ [[self view] setNeedsDisplay:YES];
+}
@end
diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h
index 06db772..24fee3b 100644
--- a/chrome/browser/cocoa/tab_strip_controller.h
+++ b/chrome/browser/cocoa/tab_strip_controller.h
@@ -72,11 +72,9 @@ class ToolbarModel;
// width should be used, this will have a value of |kUseFullAvailableWidth|.
float availableResizeWidth_;
// A tracking area that's the size of the tab strip used to be notified
- // when the mouse leaves the tab strip. It's installed when the user clicks
- // the close box of a tab and is removed when they move the mouse outside
- // of the strip. When they do, we resize the tabs to use all available
- // space.
- scoped_nsobject<NSTrackingArea> closeTabTrackingArea_;
+ // when the mouse moves in the tab strip
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+ TabView* hoveredTab_; // weak. Tab that the mouse is hovering over
// Array of subviews which are permanent (and which should never be removed),
// such as the new-tab button, but *not* the tabs themselves.
@@ -129,8 +127,8 @@ class ToolbarModel;
// Force the tabs to rearrange themselves to reflect the current model.
- (void)layoutTabs;
-// The user changed the theme.
-- (void)userChangedTheme;
+// The user changed the theme, or theme state changed.
+- (void)applyTheme;
// Default height for tabs.
+ (CGFloat)defaultTabHeight;
diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm
index 466ec30..b4b41cf 100644
--- a/chrome/browser/cocoa/tab_strip_controller.mm
+++ b/chrome/browser/cocoa/tab_strip_controller.mm
@@ -47,7 +47,6 @@ static const float kUseFullAvailableWidth = -1.0;
@end
@interface TabStripController(Private)
-- (void)installTrackingArea;
- (BOOL)useFullWidthForLayout;
- (void)addSubviewToPermanentList:(NSView*)aView;
- (void)regenerateSubviewList;
@@ -83,7 +82,6 @@ static const float kUseFullAvailableWidth = -1.0;
[newTabButton_ setAction:@selector(commandDispatch:)];
[newTabButton_ setTag:IDC_NEW_TAB];
targetFrames_.reset([[NSMutableDictionary alloc] init]);
- [tabView_ setWantsLayer:YES];
dragBlockingView_.reset([[TabStripControllerDragBlockingView alloc]
initWithFrame:NSZeroRect]);
[self addSubviewToPermanentList:dragBlockingView_];
@@ -100,13 +98,23 @@ static const float kUseFullAvailableWidth = -1.0;
selector:@selector(tabViewFrameChanged:)
name:NSViewFrameDidChangeNotification
object:tabView_];
+
+ trackingArea_.reset([[NSTrackingArea alloc]
+ initWithRect:NSZeroRect // Ignored by NSTrackingInVisibleRect
+ options:NSTrackingMouseEnteredAndExited |
+ NSTrackingMouseMoved |
+ NSTrackingActiveAlways |
+ NSTrackingInVisibleRect
+ owner:self
+ userInfo:nil]);
+ [tabView_ addTrackingArea:trackingArea_.get()];
}
return self;
}
- (void)dealloc {
- if (closeTabTrackingArea_.get())
- [tabView_ removeTrackingArea:closeTabTrackingArea_.get()];
+ if (trackingArea_.get())
+ [tabView_ removeTrackingArea:trackingArea_.get()];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
@@ -229,6 +237,9 @@ static const float kUseFullAvailableWidth = -1.0;
// is the TabView that is potentially going away.
- (void)closeTab:(id)sender {
DCHECK([sender isKindOfClass:[NSView class]]);
+ if ([hoveredTab_ isEqual:sender]) {
+ hoveredTab_ = nil;
+ }
int index = [self indexForTabView:sender];
if (tabModel_->ContainsIndex(index)) {
TabContents* contents = tabModel_->GetTabContentsAt(index);
@@ -240,7 +251,6 @@ static const float kUseFullAvailableWidth = -1.0;
// TODO(pinkerton): re-visit when handling tab overflow.
NSView* penultimateTab = [self viewAtIndex:[tabArray_ count] - 2];
availableResizeWidth_ = NSMaxX([penultimateTab frame]);
- [self installTrackingArea];
tabModel_->CloseTabContentsAt(index);
} else {
// Use the standard window close if this is the last tab
@@ -335,7 +345,7 @@ static const float kUseFullAvailableWidth = -1.0;
for (TabController* tab in tabArray_.get()) {
BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_];
NSRect tabFrame = [[tab view] frame];
- tabFrame.size.height = [[self class] defaultTabHeight];
+ tabFrame.size.height = [[self class] defaultTabHeight] + 1;
tabFrame.origin.y = 0;
tabFrame.origin.x = offset;
@@ -563,6 +573,10 @@ static const float kUseFullAvailableWidth = -1.0;
NSView* tab = [self viewAtIndex:index];
[tab removeFromSuperview];
+ if ([hoveredTab_ isEqual:tab]) {
+ hoveredTab_ = nil;
+ }
+
NSValue *identifier = [NSValue valueWithPointer:tab];
[targetFrames_ removeObjectForKey:identifier];
@@ -747,9 +761,9 @@ static const float kUseFullAvailableWidth = -1.0;
tabModel_->InsertTabContentsAt(index, contents, true, false);
}
-- (void)userChangedTheme {
+- (void)applyTheme {
for (TabController* tab in tabArray_.get()) {
- [[tab view] setNeedsDisplay:YES];
+ [tab applyTheme];
}
}
@@ -766,34 +780,38 @@ static const float kUseFullAvailableWidth = -1.0;
return availableResizeWidth_ == kUseFullAvailableWidth;
}
-// Call to install a tracking area that reports mouseEnter/Exit messages so
-// we can track when the mouse leaves the tab view after closing a tab with
-// the mouse. Don't install another tracking rect if one is already there.
-- (void)installTrackingArea {
- if (closeTabTrackingArea_.get())
- return;
- // Note that we pass |NSTrackingInVisibleRect| so the rect is actually
- // ignored.
- closeTabTrackingArea_.reset([[NSTrackingArea alloc]
- initWithRect:[tabView_ bounds]
- options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
- NSTrackingInVisibleRect
- owner:self
- userInfo:nil]);
- [tabView_ addTrackingArea:closeTabTrackingArea_.get()];
+- (void)mouseMoved:(NSEvent *)event {
+ // Use hit test to figure out what view we are hovering over.
+ TabView* targetView = (TabView*)[tabView_ hitTest:[event locationInWindow]];
+ if (![targetView isKindOfClass:[TabView class]]) {
+ if ([[targetView superview] isKindOfClass:[TabView class]]) {
+ targetView = (TabView*)[targetView superview];
+ } else {
+ targetView = nil;
+ }
+ }
+
+ if (hoveredTab_ != targetView) {
+ [hoveredTab_ mouseExited:nil]; // We don't pass event because moved events
+ [targetView mouseEntered:nil]; // don't have valid tracking areas
+ hoveredTab_ = targetView;
+ } else {
+ [hoveredTab_ mouseMoved:event];
+ }
}
- (void)mouseEntered:(NSEvent*)event {
- // Do nothing.
+ [self mouseMoved:event];
}
// Called when the tracking area is in effect which means we're tracking to
// see if the user leaves the tab strip with their mouse. When they do,
// reset layout to use all available width.
- (void)mouseExited:(NSEvent*)event {
- [tabView_ removeTrackingArea:closeTabTrackingArea_.get()];
- closeTabTrackingArea_.reset(nil);
availableResizeWidth_ = kUseFullAvailableWidth;
+
+ [hoveredTab_ mouseExited:event];
+ hoveredTab_ = nil;
[self layoutTabs];
}
diff --git a/chrome/browser/cocoa/tab_strip_view.mm b/chrome/browser/cocoa/tab_strip_view.mm
index 59b48e0..398e6a3 100644
--- a/chrome/browser/cocoa/tab_strip_view.mm
+++ b/chrome/browser/cocoa/tab_strip_view.mm
@@ -22,7 +22,7 @@
NSRect boundsRect = [self bounds];
NSRect borderRect, contentRect;
NSDivideRect(boundsRect, &borderRect, &contentRect, 1, NSMinYEdge);
- [[NSColor colorWithCalibratedWhite:0.0 alpha:0.3] set];
+ [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
}
diff --git a/chrome/browser/cocoa/tab_view.h b/chrome/browser/cocoa/tab_view.h
index fe6e567..2595ea2 100644
--- a/chrome/browser/cocoa/tab_view.h
+++ b/chrome/browser/cocoa/tab_view.h
@@ -24,7 +24,7 @@
IBOutlet NSButton* closeButton_;
// Tracking area for close button mouseover images.
- scoped_nsobject<NSTrackingArea> trackingArea_;
+ scoped_nsobject<NSTrackingArea> closeTrackingArea_;
// All following variables are valid for the duration of a drag.
// These are released on mouseUp:
@@ -32,6 +32,10 @@
BOOL tabWasDragged_; // Has the tab been dragged?
BOOL draggingWithinTabStrip_; // Did drag stay in the current tab strip?
BOOL chromeIsVisible_;
+ BOOL isMouseInside_; // Is the mouse hovering over?
+ CGFloat hoverAlpha_; // How strong the mouse hover state is.
+ NSTimeInterval lastHoverUpdate_; // Time the hover value was last updated.
+ NSPoint hoverPoint_; // Current location of hover in view coords.
NSTimeInterval tearTime_; // Time since tear happened
NSPoint tearOrigin_; // Origin of the tear rect
@@ -51,6 +55,7 @@
NSCellStateValue state_;
}
@property(assign) NSCellStateValue state;
+@property(assign, nonatomic)CGFloat hoverAlpha;
@end
#endif // CHROME_BROWSER_COCOA_TAB_VIEW_H_
diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm
index c5bc791..62ae9b8 100644
--- a/chrome/browser/cocoa/tab_view.mm
+++ b/chrome/browser/cocoa/tab_view.mm
@@ -13,9 +13,13 @@ static const CGFloat kInsetMultiplier = 2.0/3.0;
static const CGFloat kControlPoint1Multiplier = 1.0/3.0;
static const CGFloat kControlPoint2Multiplier = 3.0/8.0;
+static const NSTimeInterval kAnimationShowDuration = 0.2;
+static const NSTimeInterval kAnimationHideDuration = 0.4;
+
@implementation TabView
@synthesize state = state_;
+@synthesize hoverAlpha = hoverAlpha_;
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
@@ -34,18 +38,18 @@ static const CGFloat kControlPoint2Multiplier = 3.0/8.0;
// to the |closeButton_| view, but we'll handle the message ourself.
// The mouseover is always enabled, because the close button works
// regardless of key/main/active status.
- trackingArea_.reset(
+ closeTrackingArea_.reset(
[[NSTrackingArea alloc] initWithRect:[closeButton_ bounds]
options:NSTrackingMouseEnteredAndExited |
NSTrackingActiveAlways
owner:self
userInfo:nil]);
- [closeButton_ addTrackingArea:trackingArea_.get()];
+ [closeButton_ addTrackingArea:closeTrackingArea_.get()];
}
- (void)dealloc {
// [self gtm_unregisterForThemeNotifications];
- [closeButton_ removeTrackingArea:trackingArea_.get()];
+ [closeButton_ removeTrackingArea:closeTrackingArea_.get()];
[super dealloc];
}
@@ -56,16 +60,57 @@ static const CGFloat kControlPoint2Multiplier = 3.0/8.0;
return YES;
}
+- (void)adjustHoverValue {
+ NSTimeInterval thisUpdate = [NSDate timeIntervalSinceReferenceDate];
+
+ NSTimeInterval elapsed = thisUpdate - lastHoverUpdate_;
+
+ CGFloat opacity = [self hoverAlpha];
+ if (isMouseInside_) {
+ opacity += elapsed / kAnimationShowDuration;
+ } else {
+ opacity -= elapsed / kAnimationHideDuration;
+ }
+
+ if (!isMouseInside_ && opacity < 0) {
+ opacity = 0;
+ } else if (isMouseInside_ && opacity > 1) {
+ opacity = 1;
+ } else {
+ [self performSelector:_cmd withObject:nil afterDelay:0.02];
+ }
+ lastHoverUpdate_ = thisUpdate;
+ [self setHoverAlpha:opacity];
+
+ [self setNeedsDisplay:YES];
+}
+
- (void)mouseEntered:(NSEvent *)theEvent {
- // We only set up one tracking area, so we know any mouseEntered:
- // messages are for close button mouseovers.
- [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar_h.pdf")];
+ if ([theEvent trackingArea] == closeTrackingArea_) {
+ [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar_h.pdf")];
+ } else {
+ lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
+ isMouseInside_ = YES;
+ [self adjustHoverValue];
+ [self setNeedsDisplay:YES];
+ }
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent {
+ hoverPoint_ = [self convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+ [self setNeedsDisplay:YES];
}
- (void)mouseExited:(NSEvent *)theEvent {
- // We only set up one tracking area, so we know any mouseExited:
- // messages are for close button mouseovers.
- [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar.pdf")];
+ if ([theEvent trackingArea] == closeTrackingArea_) {
+ [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar.pdf")];
+ } else {
+ lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
+ isMouseInside_ = NO;
+ [self adjustHoverValue];
+ [self setNeedsDisplay:YES];
+ }
}
// Determines which view a click in our frame actually hit. It's either this
@@ -426,11 +471,11 @@ static const double kDragStartDistance = 3.0;
// Inset by 0.5 in order to draw on pixels rather than on borders (which would
// cause blurry pixels). Decrease height by 1 in order to move away from the
// edge for the dark shadow.
- rect = NSInsetRect(rect, 0.5, -0.5);
+ rect = NSInsetRect(rect, -0.5, -0.5);
rect.origin.y -= 1;
- NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect));
- NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect));
+ NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect) + 2);
+ NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect) + 2);
NSPoint topRight =
NSMakePoint(NSMaxX(rect) - kInsetMultiplier * NSHeight(rect),
NSMaxY(rect));
@@ -444,7 +489,7 @@ static const double kDragStartDistance = 3.0;
// Outset many of these values by 1 to cause the fill to bleed outside the
// clip area.
NSBezierPath *path = [NSBezierPath bezierPath];
- [path moveToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y + 1)];
+ [path moveToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y - 2)];
[path lineToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y)];
[path lineToPoint:bottomLeft];
[path curveToPoint:topLeft
@@ -459,30 +504,7 @@ static const double kDragStartDistance = 3.0;
controlPoint2:NSMakePoint(bottomRight.x - baseControlPointOutset,
bottomRight.y)];
[path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y)];
- [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y + 1)];
-
- if (selected) {
- // Stroke with a translucent black.
- [[NSColor colorWithCalibratedWhite:0.0 alpha:active ? 0.5 : 0.3] set];
- [[NSGraphicsContext currentContext] saveGraphicsState];
- scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
- [shadow setShadowOffset:NSMakeSize(2, -1)];
- [shadow setShadowBlurRadius:2.0];
- [path fill];
- [[NSGraphicsContext currentContext] restoreGraphicsState];
- } else {
- // Stroke with a translucent black.
- [[NSBezierPath bezierPathWithRect:NSOffsetRect([self bounds], 0, 1)]
- addClip];
-
- [[NSColor colorWithCalibratedWhite:0.0 alpha:active ? 0.3 : 0.1] set];
- }
-
- [[NSGraphicsContext currentContext] saveGraphicsState];
- [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
- [path setLineWidth:selected ? 2.0 : 1.0];
- [path stroke];
- [[NSGraphicsContext currentContext] restoreGraphicsState];
+ [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y - 2)];
GTMTheme *theme = [self gtm_theme];
@@ -491,34 +513,102 @@ static const double kDragStartDistance = 3.0;
[theme backgroundPatternColorForStyle:GTMThemeStyleWindow
state:GTMThemeStateActiveWindow];
if (windowColor) {
- NSPoint phase = [self patternPhase];
[windowColor set];
+
+ [[NSGraphicsContext currentContext] setPatternPhase:[self patternPhase]];
+ } else {
+ NSPoint phase = [self patternPhase];
+ phase.y += 1;
[[NSGraphicsContext currentContext] setPatternPhase:phase];
+ [[NSColor windowBackgroundColor] set];
+ }
+
+ [path fill];
+
+ NSColor *tabColor =
+ [theme backgroundPatternColorForStyle:GTMThemeStyleTabBarDeselected
+ state:GTMThemeStateActiveWindow];
+ if (tabColor) {
+ [tabColor set];
+ [[NSGraphicsContext currentContext] setPatternPhase:[self patternPhase]];
} else {
- [[NSColor colorWithCalibratedWhite:0.6 alpha:1.0] set];
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.3] set];
}
[path fill];
+
}
- // Draw the background.
[[NSGraphicsContext currentContext] saveGraphicsState];
- CGContextRef context =
- (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]);
- CGContextBeginTransparencyLayer(context, 0);
- if (!selected)
- CGContextSetAlpha(context, 0.5);
[path addClip];
- [super drawRect:rect];
- CGContextEndTransparencyLayer(context);
+ if (selected || hoverAlpha_ > 0) {
+ // Draw the background.
+ CGFloat backgroundAlpha = hoverAlpha_ * 0.5;
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ CGContextRef context =
+ (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]);
+ CGContextBeginTransparencyLayer(context, 0);
+ if (!selected)
+ CGContextSetAlpha(context, backgroundAlpha);
+ [path addClip];
+ [super drawRect:rect];
+
+ // Draw a mouse hover gradient for the default themes
+ if (!selected) {
+ if (![theme backgroundImageForStyle:GTMThemeStyleTabBarDeselected
+ state:GTMThemeStateActiveWindow]) {
+ scoped_nsobject<NSGradient> glow([NSGradient alloc]);
+ [glow initWithStartingColor:[NSColor colorWithCalibratedWhite:1.0
+ alpha:1.0 *
+ hoverAlpha_]
+ endingColor:[NSColor colorWithCalibratedWhite:1.0
+ alpha:0.0]];
+
+ NSPoint point = hoverPoint_;
+ point.y = NSHeight(rect);
+ [glow drawFromCenter:point
+ radius:0
+ toCenter:point
+ radius:NSWidth(rect)/3
+ options:NSGradientDrawsBeforeStartingLocation];
+
+ [glow drawInBezierPath:path relativeCenterPosition:hoverPoint_];
+ }
+ }
+
+ CGContextEndTransparencyLayer(context);
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+ }
+
+ // Draw the top inner highlight.
+ NSAffineTransform* highlightTransform = [NSAffineTransform transform];
+ [highlightTransform translateXBy:1 yBy:-1];
+ scoped_nsobject<NSBezierPath> highlightPath([path copy]);
+ [highlightPath transformUsingAffineTransform:highlightTransform];
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2 + 0.3 * hoverAlpha_]
+ setStroke];
+ [highlightPath stroke];
+
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+
+ // Draw the top stroke.
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ if (selected) {
+ [[NSColor colorWithDeviceWhite:0.0 alpha:active ? 0.3 : 0.15] set];
+ } else {
+ [[NSColor colorWithDeviceWhite:0.0 alpha:active ? 0.2 : 0.15] set];
+ [[NSBezierPath bezierPathWithRect:NSOffsetRect(rect, 0, 2.5)] addClip];
+ }
+ [path setLineWidth:1.0];
+ [path stroke];
[[NSGraphicsContext currentContext] restoreGraphicsState];
// Draw the bottom border.
if (!selected) {
[path addClip];
NSRect borderRect, contentRect;
- NSDivideRect(rect, &borderRect, &contentRect, 1, NSMinYEdge);
- [[NSColor colorWithCalibratedWhite:0.0 alpha:0.4] set];
+ NSDivideRect(rect, &borderRect, &contentRect, 2.5, NSMinYEdge);
+ [[NSColor colorWithDeviceWhite:0.0 alpha:active ? 0.3 : 0.15] set];
NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
}
[[NSGraphicsContext currentContext] restoreGraphicsState];
diff --git a/chrome/browser/cocoa/tab_view_unittest.mm b/chrome/browser/cocoa/tab_view_unittest.mm
index 74d5040..44cf629 100644
--- a/chrome/browser/cocoa/tab_view_unittest.mm
+++ b/chrome/browser/cocoa/tab_view_unittest.mm
@@ -33,6 +33,11 @@ TEST_F(TabViewTest, AddRemove) {
// Test drawing, mostly to ensure nothing leaks or crashes.
TEST_F(TabViewTest, Display) {
+ [view_ setHoverAlpha:0.0];
+ [view_ display];
+ [view_ setHoverAlpha:0.5];
+ [view_ display];
+ [view_ setHoverAlpha:1.0];
[view_ display];
}
diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h
index 31aafc4..07eccac 100644
--- a/chrome/browser/cocoa/toolbar_controller.h
+++ b/chrome/browser/cocoa/toolbar_controller.h
@@ -62,6 +62,10 @@ class ToolbarView;
// See comments in awakeFromNib for more info.
scoped_nsobject<AutocompleteTextField> locationBarRetainer_;
+ // Tracking area for mouse enter/exit/moved in the toolbar.
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+ NSButton* hoveredButton_; // weak. Button under the mouse cursor.
+
IBOutlet NSMenu* pageMenu_;
IBOutlet NSMenu* wrenchMenu_;
diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm
index 1bcf8a4..f21f790 100644
--- a/chrome/browser/cocoa/toolbar_controller.mm
+++ b/chrome/browser/cocoa/toolbar_controller.mm
@@ -25,10 +25,10 @@
static NSString* const kStarredImageName = @"starred.pdf";
// Height of the toolbar in pixels when the bookmark bar is closed.
-static const float kBaseToolbarHeight = 39.0;
+static const float kBaseToolbarHeight = 36.0;
// Overlap (in pixels) between the toolbar and the bookmark bar.
-static const float kBookmarkBarOverlap = 5.0;
+static const float kBookmarkBarOverlap = 7.0;
@interface ToolbarController(Private)
- (void)initCommandStatus:(CommandUpdater*)commands;
@@ -150,6 +150,35 @@ class PrefObserverBridge : public NotificationObserver {
// the retain count of the location bar; use of the scoped object
// helps us remember to release it.
locationBarRetainer_.reset([locationBar_ retain]);
+ trackingArea_.reset(
+ [[NSTrackingArea alloc] initWithRect:NSZeroRect // Ignored
+ options:NSTrackingMouseMoved |
+ NSTrackingInVisibleRect |
+ NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways
+ owner:self
+ userInfo:nil]);
+ [[self view] addTrackingArea:trackingArea_.get()];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ [[hoveredButton_ cell] setMouseInside:NO animate:YES];
+ hoveredButton_ = nil;
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent {
+ NSButton *targetView = (NSButton *)[[self view]
+ hitTest:[theEvent locationInWindow]];
+ if (![targetView isKindOfClass:[NSButton class]]) targetView = nil;
+ if (hoveredButton_ != targetView) {
+ [[hoveredButton_ cell] setMouseInside:NO animate:YES];
+ [[targetView cell] setMouseInside:YES animate:YES];
+ hoveredButton_ = targetView;
+ }
+}
+
+- (void)mouseEntered:(NSEvent*)event {
+ [self mouseMoved:event];
}
- (void)resizeView:(NSView*)view newHeight:(float)height {