summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-08 21:09:29 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-08 21:09:29 +0000
commit1a3e0967c5a0cbfb6bee4a63b49955acbb6b387e (patch)
tree1c90b017ca427ecc4a66e1a41cd2d44682f9f223 /chrome/browser
parent63d23bb1410837f9fdc300b4b5c0a3470724c8d6 (diff)
downloadchromium_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.h10
-rw-r--r--chrome/browser/cocoa/blocked_popup_container_controller.mm72
-rw-r--r--chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm7
-rw-r--r--chrome/browser/cocoa/bubble_view.h65
-rw-r--r--chrome/browser/cocoa/bubble_view.mm123
-rw-r--r--chrome/browser/cocoa/bubble_view_unittest.mm71
-rw-r--r--chrome/browser/cocoa/status_bubble_mac.mm166
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