diff options
author | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-08 21:09:29 +0000 |
---|---|---|
committer | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-08 21:09:29 +0000 |
commit | 1a3e0967c5a0cbfb6bee4a63b49955acbb6b387e (patch) | |
tree | 1c90b017ca427ecc4a66e1a41cd2d44682f9f223 /chrome/browser | |
parent | 63d23bb1410837f9fdc300b4b5c0a3470724c8d6 (diff) | |
download | chromium_src-1a3e0967c5a0cbfb6bee4a63b49955acbb6b387e.zip chromium_src-1a3e0967c5a0cbfb6bee4a63b49955acbb6b387e.tar.gz chromium_src-1a3e0967c5a0cbfb6bee4a63b49955acbb6b387e.tar.bz2 |
Pretty-up the blocked popup view by sharing code from the status bubble. Blocked Popup view is now themed as well.
BUG=20815
TEST=popup blocking and status bubble still work.
Review URL: http://codereview.chromium.org/196043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25662 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/cocoa/blocked_popup_container_controller.h | 10 | ||||
-rw-r--r-- | chrome/browser/cocoa/blocked_popup_container_controller.mm | 72 | ||||
-rw-r--r-- | chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm | 7 | ||||
-rw-r--r-- | chrome/browser/cocoa/bubble_view.h | 65 | ||||
-rw-r--r-- | chrome/browser/cocoa/bubble_view.mm | 123 | ||||
-rw-r--r-- | chrome/browser/cocoa/bubble_view_unittest.mm | 71 | ||||
-rw-r--r-- | chrome/browser/cocoa/status_bubble_mac.mm | 166 |
7 files changed, 337 insertions, 177 deletions
diff --git a/chrome/browser/cocoa/blocked_popup_container_controller.h b/chrome/browser/cocoa/blocked_popup_container_controller.h index 267b893..1df895c 100644 --- a/chrome/browser/cocoa/blocked_popup_container_controller.h +++ b/chrome/browser/cocoa/blocked_popup_container_controller.h @@ -11,6 +11,8 @@ #include "base/scoped_ptr.h" #include "chrome/browser/blocked_popup_container.h" +@class BubbleView; + // Controller for the blocked popup view. Communicates with the cross-platform // code via a C++ bridge class, below. The BlockedPopupContainer class doesn't // really "own" the bridge, it just keeps a pointer to it and calls Destroy() on @@ -25,7 +27,10 @@ @private scoped_ptr<BlockedPopupContainerView> bridge_; BlockedPopupContainer* container_; // Weak. "owns" me. - scoped_nsobject<NSView> view_; + scoped_nsobject<BubbleView> view_; + scoped_nsobject<NSButton> closeButton_; + // Tracking area for close button mouseover images. + scoped_nsobject<NSTrackingArea> closeTrackingArea_; IBOutlet NSPopUpButton* popupButton_; } @@ -44,8 +49,7 @@ @end @interface BlockedPopupContainerController(ForTesting) -- (NSView*)view; -- (NSPopUpButton*)popupButton; +- (BubbleView*)view; - (IBAction)closePopup:(id)sender; - (NSMenu*)buildMenu; - (void)setContainer:(BlockedPopupContainer*)container; diff --git a/chrome/browser/cocoa/blocked_popup_container_controller.mm b/chrome/browser/cocoa/blocked_popup_container_controller.mm index dcf836f..6c0ff04 100644 --- a/chrome/browser/cocoa/blocked_popup_container_controller.mm +++ b/chrome/browser/cocoa/blocked_popup_container_controller.mm @@ -6,13 +6,12 @@ #include "app/l10n_util.h" #include "base/sys_string_conversions.h" +#import "chrome/browser/cocoa/bubble_view.h" #include "chrome/browser/cocoa/nsimage_cache.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "grit/generated_resources.h" -#import "chrome/browser/cocoa/background_gradient_view.h" - // A C++ bridge class that manages the interaction between the C++ interface // and the Objective-C view controller that implements the popup blocker. class BlockedPopupContainerViewBridge : public BlockedPopupContainerView { @@ -50,6 +49,7 @@ class BlockedPopupContainerViewBridge : public BlockedPopupContainerView { } - (void)dealloc { + [closeButton_ removeTrackingArea:closeTrackingArea_.get()]; [view_ removeFromSuperview]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; @@ -68,10 +68,14 @@ class BlockedPopupContainerViewBridge : public BlockedPopupContainerView { static const float kCloseBoxPaddingY = 2.0; static const float kLabelPaddingX = 5.0; + NSWindow* window = [[self containingView] window]; + // Create it below the parent's bottom edge so we can animate it into place. NSRect startFrame = NSMakeRect(0.0, -kHeight, kWidth, kHeight); - view_.reset([[BackgroundGradientView alloc] initWithFrame:startFrame]); + view_.reset([[BubbleView alloc] initWithFrame:startFrame + themeProvider:window]); [view_ setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin]; + [view_ setCornerFlags:kRoundedTopLeftCorner | kRoundedTopRightCorner]; // Create the text label and position it. We'll resize it later when the // label gets updated. The view owns the label, we only hold a weak reference. @@ -88,11 +92,11 @@ class BlockedPopupContainerViewBridge : public BlockedPopupContainerView { [popupButton_ setPreferredEdge:NSMaxYEdge]; // TODO(pinkerton): no matter what, the arrows always draw in the middle // of the button. We can turn off the arrows entirely, but then will the - // user ever know to click it? Leave them on for now. - //[[popupButton_ cell] setArrowPosition:NSPopUpNoArrow]; + // user ever know to click it? + [[popupButton_ cell] setArrowPosition:NSPopUpNoArrow]; [[popupButton_ cell] setAltersStateOfSelectedItem:NO]; // If we don't add this, no title will ever display. - [popupButton_ addItemWithTitle:@"placeholder"]; + [popupButton_ addItemWithTitle:@""]; [view_ addSubview:popupButton_]; // Register for notifications that the menu is about to display so we can @@ -108,14 +112,28 @@ class BlockedPopupContainerViewBridge : public BlockedPopupContainerView { kCloseBoxPaddingY, kCloseBoxSize, kCloseBoxSize); - NSButton* close = [[[NSButton alloc] initWithFrame:closeFrame] autorelease]; - [close setAutoresizingMask:NSViewMinXMargin]; - [close setImage:nsimage_cache::ImageNamed(@"close_bar.pdf")]; - [close setAlternateImage:nsimage_cache::ImageNamed(@"close_bar_p.pdf")]; - [close setBordered:NO]; - [close setTarget:self]; - [close setAction:@selector(closePopup:)]; - [view_ addSubview:close]; + closeButton_.reset([[NSButton alloc] initWithFrame:closeFrame]); + [closeButton_ setAutoresizingMask:NSViewMinXMargin]; + [closeButton_ setButtonType:NSMomentaryChangeButton]; + [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar.pdf")]; + [closeButton_ + setAlternateImage:nsimage_cache::ImageNamed(@"close_bar_p.pdf")]; + [closeButton_ setBordered:NO]; + [closeButton_ setTarget:self]; + [closeButton_ setAction:@selector(closePopup:)]; + [view_ addSubview:closeButton_]; + + // Set up the tracking rect for the close button mouseover. Add it + // 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. + closeTrackingArea_.reset( + [[NSTrackingArea alloc] initWithRect:[closeButton_ bounds] + options:NSTrackingMouseEnteredAndExited | + NSTrackingActiveAlways + owner:self + userInfo:nil]); + [closeButton_ addTrackingArea:closeTrackingArea_.get()]; } // Returns the C++ brige object. @@ -127,7 +145,10 @@ class BlockedPopupContainerViewBridge : public BlockedPopupContainerView { // so that it stays around as the RWHVMac is created/destroyed during // navigation. - (NSView*)containingView { - return container_->GetConstrainingContents(NULL)->view()->GetNativeView(); + NSView* view = nil; + if (container_) + view = container_->GetConstrainingContents(NULL)->view()->GetNativeView(); + return view; } - (void)show { @@ -185,7 +206,7 @@ class BlockedPopupContainerViewBridge : public BlockedPopupContainerView { l10n_util::GetStringUTF16(IDS_POPUPS_UNBLOCKED)); } [self resizeWithLabel:label]; - [popupButton_ setTitle:label]; + [view_ setContent:label]; } // Called when the user selects an item from the popup menu. The tag, if below @@ -284,19 +305,28 @@ void GetURLAndTitleForPopup( [[notify object] setMenu:menu]; } -- (NSView*)view { +// Only used for testing. +- (BubbleView*)view { return view_.get(); } -- (NSPopUpButton*)popupButton { - return popupButton_; -} - // Only used for testing. - (void)setContainer:(BlockedPopupContainer*)container { container_ = container; } +// Called when the mouse enters the tracking rect for the close box. +- (void)mouseEntered:(NSEvent *)theEvent { + if ([theEvent trackingArea] == closeTrackingArea_) + [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar_h.pdf")]; +} + +// Called when the mouse exits the tracking rect for the close box. +- (void)mouseExited:(NSEvent *)theEvent { + if ([theEvent trackingArea] == closeTrackingArea_) + [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar.pdf")]; +} + @end //--------------------------------------------------------------------------- diff --git a/chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm b/chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm index 623ee27..54c6ca0 100644 --- a/chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm +++ b/chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm @@ -9,7 +9,7 @@ #include "base/scoped_nsautorelease_pool.h" #import "chrome/browser/cocoa/blocked_popup_container_controller.h" #include "chrome/browser/cocoa/browser_test_helper.h" -#import "chrome/browser/cocoa/cocoa_test_helper.h" +#include "chrome/browser/cocoa/cocoa_test_helper.h" #include "chrome/browser/renderer_host/test/test_render_view_host.h" #include "net/base/net_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -62,6 +62,7 @@ class BlockedPopupContainerControllerTest : public RenderViewHostTestHarness { } base::ScopedNSAutoreleasePool pool; + CocoaTestHelper cocoa_helper_; BlockedPopupContainer* container_; BlockedPopupContainerController* cocoa_controller_; }; @@ -77,11 +78,11 @@ TEST_F(BlockedPopupContainerControllerTest, BasicPopupBlock) { EXPECT_FALSE(container_->IsHostWhitelisted(0)); // Ensure the view has been displayed. If it has a superview, then ShowView() - // has been called on the bridge. If the button has a string, then + // has been called on the bridge. If the bubble has a string, then // UpdateLabel() has been called. EXPECT_TRUE([cocoa_controller_ view]); EXPECT_TRUE([[cocoa_controller_ view] superview]); - EXPECT_TRUE([[[cocoa_controller_ popupButton] title] length] > 0); + EXPECT_TRUE([[[cocoa_controller_ view] content] length] > 0); // Validate the menu. It should have 4 items (the dummy title item, 1 poupup, // a separator, 1 host). diff --git a/chrome/browser/cocoa/bubble_view.h b/chrome/browser/cocoa/bubble_view.h new file mode 100644 index 0000000..761c5a8 --- /dev/null +++ b/chrome/browser/cocoa/bubble_view.h @@ -0,0 +1,65 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" + +// A view class that looks like a "bubble" with rounded corners and displays +// text inside. Can be themed with a GTMTheme object. To put flush +// against the sides of a window, the corner flags can be adjusted. + +@protocol GTMThemeDelegate; + +// Constants that define where the bubble will have a rounded corner. If +// not set, the corner will be square. +enum { + kRoundedTopLeftCorner = 1, + kRoundedTopRightCorner = 1 << 1, + kRoundedBottomLeftCorner = 1 << 2, + kRoundedBottomRightCorner = 1 << 3, + kRoundedAllCorners = kRoundedTopLeftCorner & kRoundedTopRightCorner & + kRoundedBottomLeftCorner & kRoundedBottomRightCorner +}; + +// Constants that affect where the text is positioned within the view. They +// are exposed in case anyone needs to use the padding to set the content string +// length appropriately based on available space (such as eliding a URL). +enum { + kBubbleViewTextPositionX = 4, + kBubbleViewTextPositionY = 2 +}; + +@interface BubbleView : NSView { + @private + scoped_nsobject<NSString> content_; + unsigned long cornerFlags_; + // The window from which we get the theme used to draw. In some cases, + // it might not be the window we're in. As a result, this may or may not + // directly own us, so it needs to be weak to prevent a cycle. + NSWindow* themeProvider_; +} + +// Designated initializer. |provider| is the window from which we get the +// current theme to draw text and backgrounds. If nil, the current window will +// be checked. Defaults to all corners being rounded. The caller needs to +// ensure |provider| can't go away as it will not be retained. +- (id)initWithFrame:(NSRect)frame themeProvider:(NSWindow*)provider; + +// Sets the string displayed in the bubble. A copy of the string is made. +- (void)setContent:(NSString*)content; + +// Sets which corners will be rounded. +- (void)setCornerFlags:(unsigned long)flags; + +// The font used to display the content string. +- (NSFont*)font; + +@end + +// APIs exposed only for testing. +@interface BubbleView(TestingOnly) +- (NSString*)content; +- (unsigned long)cornerFlags; +@end diff --git a/chrome/browser/cocoa/bubble_view.mm b/chrome/browser/cocoa/bubble_view.mm new file mode 100644 index 0000000..1a536c9 --- /dev/null +++ b/chrome/browser/cocoa/bubble_view.mm @@ -0,0 +1,123 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/cocoa/bubble_view.h" + +#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h" +#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h" +#import "third_party/GTM/AppKit/GTMTheme.h" + +// The roundedness of the edges of our bubble. +const int kBubbleCornerRadius = 4.0f; +const float kWindowEdge = 0.7f; + +@implementation BubbleView + +// Designated initializer. |provider| is the window from which we get the +// current theme to draw text and backgrounds. If nil, the current window will +// be checked. Defaults to all corners being rounded. The caller needs to +// ensure |provider| can't go away as it will not be retained. +- (id)initWithFrame:(NSRect)frame themeProvider:(NSWindow*)provider { + if ((self = [super initWithFrame:frame])) { + cornerFlags_ = kRoundedAllCorners; + themeProvider_ = provider; + } + return self; +} + +// Sets the string displayed in the bubble. A copy of the string is made. +- (void)setContent:(NSString*)content { + content_.reset([content copy]); + [self setNeedsDisplay:YES]; +} + +// Sets which corners will be rounded. +- (void)setCornerFlags:(unsigned long)flags { + cornerFlags_ = flags; + [self setNeedsDisplay:YES]; +} + +- (NSString*)content { + return content_.get(); +} + +- (unsigned long)cornerFlags { + return cornerFlags_; +} + +// The font used to display the content string. +- (NSFont*)font { + return [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; +} + +// Asks the given theme provider for its theme. If there isn't one specified, +// check the window we are in. May still return nil if the window doesn't +// support themeing. +- (GTMTheme*)gtm_theme { + GTMTheme* theme = [themeProvider_ gtm_theme]; + if (!theme) + theme = [[self window] gtm_theme]; + return theme; +} + +// Draws the themed background and the text. Will draw a gray bg if no theme. +- (void)drawRect:(NSRect)rect { + float topLeftRadius = + cornerFlags_ & kRoundedTopLeftCorner ? kBubbleCornerRadius : 0; + float topRightRadius = + cornerFlags_ & kRoundedTopRightCorner ? kBubbleCornerRadius : 0; + float bottomLeftRadius = + cornerFlags_ & kRoundedBottomLeftCorner ? kBubbleCornerRadius : 0; + float bottomRightRadius = + cornerFlags_ & kRoundedBottomRightCorner ? kBubbleCornerRadius : 0; + + GTMTheme* theme = [self gtm_theme]; + + // Background / Edge + + NSRect bounds = [self bounds]; + bounds = NSInsetRect(bounds, 0.5, 0.5); + NSBezierPath* border = + [NSBezierPath gtm_bezierPathWithRoundRect:bounds + topLeftCornerRadius:topLeftRadius + topRightCornerRadius:topRightRadius + bottomLeftCornerRadius:bottomLeftRadius + bottomRightCornerRadius:bottomRightRadius]; + + NSColor* color = + [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]; + + [[NSColor colorWithDeviceWhite:kWindowEdge alpha:1.0f] set]; + [border stroke]; + + // Text + NSColor* textColor = [theme textColorForStyle:GTMThemeStyleToolBar + state:GTMThemeStateActiveWindow]; + NSFont* textFont = [self font]; + scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]); + [textShadow setShadowBlurRadius:0.0f]; + [textShadow setShadowColor:[textColor gtm_legibleTextColor]]; + [textShadow setShadowOffset:NSMakeSize(0.0f, -1.0f)]; + + NSDictionary* textDict = [NSDictionary dictionaryWithObjectsAndKeys: + textColor, NSForegroundColorAttributeName, + textFont, NSFontAttributeName, + textShadow.get(), NSShadowAttributeName, + nil]; + [content_ drawAtPoint:NSMakePoint(kBubbleViewTextPositionX, + kBubbleViewTextPositionY) + withAttributes:textDict]; +} + +@end diff --git a/chrome/browser/cocoa/bubble_view_unittest.mm b/chrome/browser/cocoa/bubble_view_unittest.mm new file mode 100644 index 0000000..2c949b5 --- /dev/null +++ b/chrome/browser/cocoa/bubble_view_unittest.mm @@ -0,0 +1,71 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/bubble_view.h" +#include "chrome/browser/cocoa/cocoa_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +class BubbleViewTest : public PlatformTest { + public: + BubbleViewTest() { + NSRect frame = NSMakeRect(0, 0, 50, 50); + view_.reset([[BubbleView alloc] initWithFrame:frame + themeProvider:cocoa_helper_.window()]); + [cocoa_helper_.contentView() addSubview:view_.get()]; + [view_ setContent:@"Hi there, I'm a bubble view"]; + } + + CocoaTestHelper cocoa_helper_; + scoped_nsobject<BubbleView> view_; +}; + +// Test adding/removing from the view hierarchy, mostly to ensure nothing +// leaks or crashes. +TEST_F(BubbleViewTest, AddRemove) { + EXPECT_EQ(cocoa_helper_.contentView(), [view_ superview]); + [view_.get() removeFromSuperview]; + EXPECT_FALSE([view_ superview]); +} + +// Test drawing, mostly to ensure nothing leaks or crashes. +TEST_F(BubbleViewTest, Display) { + [view_ display]; +} + +// Test a nil themeProvider in init. +TEST_F(BubbleViewTest, NilThemeProvider) { + NSRect frame = NSMakeRect(0, 0, 50, 50); + view_.reset([[BubbleView alloc] initWithFrame:frame + themeProvider:nil]); + [cocoa_helper_.contentView() addSubview:view_.get()]; + [view_ display]; +} + +// Make sure things don't go haywire when given invalid or long strings. +TEST_F(BubbleViewTest, SetContent) { + [view_ setContent:nil]; + EXPECT_TRUE([view_ content] == nil); + [view_ setContent:@""]; + EXPECT_TRUE([[view_ content] isEqualToString:@""]); + NSString* str = @"This is a really really long string that's just too long"; + [view_ setContent:str]; + EXPECT_TRUE([[view_ content] isEqualToString:str]); +} + +TEST_F(BubbleViewTest, CornerFlags) { + // Set some random flags just to check. + [view_ setCornerFlags:kRoundedTopRightCorner | kRoundedTopLeftCorner]; + EXPECT_EQ([view_ cornerFlags], + (unsigned long)kRoundedTopRightCorner | kRoundedTopLeftCorner); + // Set no flags (all 4 draw corners are square). + [view_ setCornerFlags:0]; + EXPECT_EQ([view_ cornerFlags], 0UL); + // Set all bits. Meaningless past the first 4, but harmless to set too many. + [view_ setCornerFlags:0xFFFFFFFF]; + EXPECT_EQ([view_ cornerFlags], 0xFFFFFFFF); +} diff --git a/chrome/browser/cocoa/status_bubble_mac.mm b/chrome/browser/cocoa/status_bubble_mac.mm index 2db160f..529ea81 100644 --- a/chrome/browser/cocoa/status_bubble_mac.mm +++ b/chrome/browser/cocoa/status_bubble_mac.mm @@ -7,6 +7,7 @@ #include "app/gfx/text_elider.h" #include "base/string_util.h" #include "base/sys_string_conversions.h" +#import "chrome/browser/cocoa/bubble_view.h" #include "googleurl/src/gurl.h" #import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h" #import "third_party/GTM/AppKit/GTMNSColor+Luminance.h" @@ -23,14 +24,6 @@ const float kWindowWidthPercent = 1.0f/3.0f; const int kMousePadding = 20; const int kTextPadding = 3; -const int kTextPositionX = 4; -const int kTextPositionY = 2; - -const float kWindowFill = 0.8f; -const float kWindowEdge = 0.7f; - -// The roundedness of the edges of our bubble. -const int kBubbleCornerRadius = 4.0f; // How long each fade should last for. const int kShowFadeDuration = 0.120f; @@ -41,25 +34,6 @@ const int kHideFadeDuration = 0.200f; // TODO(avi): // - do display delay -enum BubbleStyle { - STYLE_BOTTOM, // Hanging off the bottom of the parent window - STYLE_FLOATING, // Between BOTTOM and STANDARD - STYLE_STANDARD // Nestled in the corner of the parent window -}; - -@interface StatusBubbleViewCocoa : NSView { - @private - NSString* content_; - BubbleStyle style_; - NSWindow* parent_; -} - -- (void)setContent:(NSString*)content; -- (void)setStyle:(BubbleStyle)style; -- (void)setParent:(NSWindow*)parent; -- (NSFont*)font; -@end - StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate) : parent_(parent), delegate_(delegate), @@ -86,7 +60,7 @@ void StatusBubbleMac::SetURL(const GURL& url, const std::wstring& languages) { NSRect frame = [window_ frame]; int text_width = static_cast<int>(frame.size.width - - kTextPositionX - + kBubbleViewTextPositionX - kTextPadding); NSFont* font = [[window_ contentView] font]; gfx::Font font_chr = @@ -177,18 +151,21 @@ void StatusBubbleMac::MouseMoved() { // and mate to the edges of the tab content). if (offset >= NSHeight(window_frame)) { offset = NSHeight(window_frame); - [[window_ contentView] setStyle:STYLE_BOTTOM]; + [[window_ contentView] setCornerFlags: + kRoundedBottomLeftCorner | kRoundedBottomRightCorner]; } else if (offset > 0) { - [[window_ contentView] setStyle:STYLE_FLOATING]; + [[window_ contentView] setCornerFlags: + kRoundedTopRightCorner | kRoundedBottomLeftCorner | + kRoundedBottomRightCorner]; } else { - [[window_ contentView] setStyle:STYLE_STANDARD]; + [[window_ contentView] setCornerFlags:kRoundedTopRightCorner]; } offset_ = offset; window_frame.origin.y -= offset; } else { offset_ = 0; - [[window_ contentView] setStyle:STYLE_STANDARD]; + [[window_ contentView] setCornerFlags:kRoundedTopRightCorner]; } // |delegate_| can be nil during unit tests. @@ -222,10 +199,12 @@ void StatusBubbleMac::Create() { [window_ setOpaque:NO]; [window_ setHasShadow:NO]; - StatusBubbleViewCocoa* view = - [[[StatusBubbleViewCocoa alloc] initWithFrame:NSZeroRect] autorelease]; - [view setParent:parent_]; - + // We do not need to worry about the bubble outliving |parent_| because our + // teardown sequence in BWC guarantees that |parent_| outlives the status + // bubble and that the StatusBubble is torn down completely prior to the + // window going away. + scoped_nsobject<BubbleView> view( + [[BubbleView alloc] initWithFrame:NSZeroRect themeProvider:parent_]); [window_ setContentView:view]; [parent_ addChildWindow:window_ ordered:NSWindowAbove]; @@ -233,7 +212,7 @@ void StatusBubbleMac::Create() { [window_ setAlphaValue:0.0f]; offset_ = 0; - [view setStyle:STYLE_STANDARD]; + [view setCornerFlags:kRoundedTopRightCorner]; MouseMoved(); } @@ -251,116 +230,3 @@ void StatusBubbleMac::FadeOut() { [NSAnimationContext endGrouping]; } -@implementation StatusBubbleViewCocoa - -- (void)dealloc { - [parent_ release]; - [content_ release]; - [super dealloc]; -} - -- (void)setContent:(NSString*)content { - [content_ autorelease]; - content_ = [content copy]; - [self setNeedsDisplay:YES]; -} - -- (void)setStyle:(BubbleStyle)style { - style_ = style; - [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]]; -} - -- (void)drawRect:(NSRect)rect { - float tl_radius, tr_radius, bl_radius, br_radius; - - switch (style_) { - case STYLE_BOTTOM: - tl_radius = 0.0f; - tr_radius = 0.0f; - bl_radius = kBubbleCornerRadius; - br_radius = kBubbleCornerRadius; - break; - case STYLE_FLOATING: - tl_radius = 0.0f; - tr_radius = kBubbleCornerRadius; - bl_radius = kBubbleCornerRadius; - br_radius = kBubbleCornerRadius; - break; - case STYLE_STANDARD: - tl_radius = 0.0f; - tr_radius = kBubbleCornerRadius; - bl_radius = 0.0f; - br_radius = 0.0f; - break; - default: - NOTREACHED(); - tl_radius = 0.0f; - tr_radius = 0.0f; - bl_radius = 0.0f; - br_radius = 0.0f; - } - - // 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* 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 - topLeftCornerRadius:tl_radius - topRightCornerRadius:tr_radius - bottomLeftCornerRadius:bl_radius - bottomRightCornerRadius:br_radius]; - - [[NSColor colorWithDeviceWhite:kWindowEdge alpha:1.0f] set]; - [border stroke]; - - // Text - NSColor* textColor = [color gtm_legibleTextColor]; - NSFont* textFont = [self font]; - NSShadow* textShadow = [[[NSShadow alloc] init] autorelease]; - [textShadow setShadowBlurRadius:0.0f]; - [textShadow setShadowColor:[textColor gtm_legibleTextColor]]; - [textShadow setShadowOffset:NSMakeSize(0.0f, -1.0f)]; - - NSDictionary* textDict = [NSDictionary dictionaryWithObjectsAndKeys: - textColor, NSForegroundColorAttributeName, - textFont, NSFontAttributeName, - textShadow, NSShadowAttributeName, - nil]; - [content_ drawAtPoint:NSMakePoint(kTextPositionX, kTextPositionY) - withAttributes:textDict]; -} - -@end |