Chromium Code Reviews| Index: chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.mm |
| diff --git a/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.mm b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7b0d9de8bda33bc450bef42fe9420796f3fea446 |
| --- /dev/null |
| +++ b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.mm |
| @@ -0,0 +1,210 @@ |
| +// Copyright (c) 2011 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/logging.h" // for NOTREACHED() |
| +#include "base/mac/mac_util.h" |
| +#include "base/sys_string_conversions.h" |
| +#include "chrome/app/chrome_command_ids.h" |
| +#include "chrome/browser/ui/browser.h" |
| +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| +#import "chrome/browser/ui/cocoa/animatable_view.h" |
| +#import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| +#include "chrome/browser/ui/cocoa/event_utils.h" |
| +#import "chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h" |
| +#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
| +#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" |
| +#include "ui/base/models/accelerator_cocoa.h" |
| +#include "ui/base/l10n/l10n_util_mac.h" |
| +#include "chrome/app/chrome_command_ids.h" |
|
Nico
2011/09/15 04:37:32
alphabetize includes
jeremya
2011/09/15 06:33:28
Done.
|
| +#include "grit/generated_resources.h" |
| +#import "chrome/browser/ui/cocoa/hyperlink_text_view.h" |
| + |
| +namespace { |
|
Nico
2011/09/15 04:37:32
const has implicit internal linkage, no need for a
jeremya
2011/09/15 06:33:28
Done.
|
| +const int kPaddingPx = 8; |
| +const int kInitialDelayMs = 3800; |
| +const int kSlideOutDurationMs = 700; |
| +} |
| + |
| +@interface FullscreenExitBubbleController (PrivateMethods) |
| +// Sets |exitLabel_| based on |exitLabelPlaceholder_|, sets |
|
Nico
2011/09/15 04:37:32
nit: break after ,
jeremya
2011/09/15 06:33:28
Done.
|
| +// |exitLabelPlaceholder_| to nil. |
| +- (void)initializeLabel; |
| + |
| +- (void)hideSoon; |
| + |
| +// Returns the Accelerator for the Toggle Fullscreen menu item. |
| ++ (ui::AcceleratorCocoa)toggleFullscreenAccelerator; |
| + |
| +// Returns a string representation fit for display of |
| +// |+toggleFullscreenAccelerator|. |
|
Nico
2011/09/15 04:37:32
objc methods don't need || since they have a prefi
jeremya
2011/09/15 06:33:28
Done.
|
| ++ (NSString*)keyCommandString; |
| + |
| ++ (NSString*)keyCombinationForAccelerator:(const ui::AcceleratorCocoa&)item; |
| +@end |
| + |
| +@implementation FullscreenExitBubbleController |
| + |
| +- (id)initWithOwner:(BrowserWindowController*)owner browser:(Browser*)browser { |
| + if ((self = [super initWithNibName:@"FullscreenExitBubble" |
| + bundle:base::mac::MainAppBundle()])) { |
| + browser_ = browser; |
| + owner_ = owner; |
| + } |
| + return self; |
| +} |
| + |
| +- (void)awakeFromNib { |
| + [self initializeLabel]; |
| + [self hideSoon]; |
| +} |
| + |
| +// Called when someone clicks on the embedded link. |
| +- (BOOL) textView:(NSTextView*)textView |
| + clickedOnLink:(id)link |
| + atIndex:(NSUInteger)charIndex { |
| + // TODO there's probably a better way to invoke this. |
|
Nico
2011/09/15 04:37:32
Remove TODO. this is good as is
jeremya
2011/09/15 06:33:28
Done.
|
| + browser_->ExecuteCommand(IDC_FULLSCREEN); |
| + return YES; |
| +} |
| + |
| +- (void)hideTimerFire:(NSTimer*)timer { |
|
Nico
2011/09/15 04:37:32
hideTimerFired?
jeremya
2011/09/15 06:33:28
Done.
|
| + NSRect endFrame = [[self view] frame]; |
| + endFrame.origin.y += endFrame.size.height; |
| + endFrame.size.height = 0; |
| + NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: |
| + [self view], NSViewAnimationTargetKey, |
| + [NSValue valueWithRect:endFrame], NSViewAnimationEndFrameKey, nil]; |
| + |
| + NSViewAnimation* animation = |
| + [[NSViewAnimation alloc] |
| + initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]]; |
| + [animation gtm_setDuration:kSlideOutDurationMs/1000.0 |
| + eventMask:NSLeftMouseUpMask]; |
| + [animation setDelegate:self]; |
| + [animation startAnimation]; |
| + hideAnimation_ = animation; |
| +} |
| + |
| +- (void)animationDidEnd:(NSAnimation*)animation { |
| + if (animation == hideAnimation_) { |
| + [hideAnimation_ autorelease]; |
|
Nico
2011/09/15 04:37:32
.reset()?
jeremya
2011/09/15 06:33:28
Done.
|
| + hideAnimation_ = nil; |
| + } |
| + |
| + [owner_ setShowFloatingChrome:YES]; |
| +} |
| + |
| +- (AnimatableView*)animatableView { |
| + return static_cast<AnimatableView*>([self view]); |
| +} |
| + |
| +- (void)dealloc { |
| + // TODO one or more of these things may be unnecessary. |
|
Nico
2011/09/15 04:37:32
Don't add non-actionable TODOs, see the TODO secti
jeremya
2011/09/15 06:33:28
Forgot to remove this. Oops.
|
| + [[self animatableView] stopAnimation]; |
| + [hideAnimation_ stopAnimation]; |
| + [hideTimer_ invalidate]; |
| + [super dealloc]; |
| +} |
| + |
| +@end |
| + |
| +@implementation FullscreenExitBubbleController (PrivateMethods) |
| + |
| +- (void)initializeLabel { |
| + // Replace the label placeholder NSTextField with the real label NSTextView. |
| + // The former doesn't show links in a nice way, but the latter can't be added |
| + // in IB without a containing scroll view, so create the NSTextView |
| + // programmatically. |
| + exitLabel_.reset([[HyperlinkTextView alloc] |
| + initWithFrame:[exitLabelPlaceholder_ frame]]); |
| + [exitLabel_.get() setAutoresizingMask: |
| + [exitLabelPlaceholder_ autoresizingMask]]; |
| + [[exitLabelPlaceholder_ superview] |
| + replaceSubview:exitLabelPlaceholder_ with:exitLabel_.get()]; |
| + exitLabelPlaceholder_ = nil; // Now released. |
| + [exitLabel_.get() setDelegate:self]; |
| + |
| + NSString *message = l10n_util::GetNSStringF(IDS_EXIT_FULLSCREEN_MODE, |
| + base::SysNSStringToUTF16([[self class] keyCommandString])); |
| + |
| + HyperlinkTextView* view = (HyperlinkTextView*)exitLabel_.get(); |
| + [view setMessageAndLink:@"" |
|
Nico
2011/09/15 04:37:32
Just say [exitLabel_.get() setFoo] here and get ri
jeremya
2011/09/15 06:33:28
Done.
|
| + withLink:message |
| + atOffset:0 |
| + font:[NSFont systemFontOfSize:18] |
| + messageColor:[NSColor whiteColor] |
| + linkColor:[NSColor whiteColor]]; |
| + |
| + [exitLabel_.get() sizeToFit]; |
| + NSLayoutManager* lm = [exitLabel_.get() layoutManager]; |
|
Nico
2011/09/15 04:37:32
no abbreviations
jeremya
2011/09/15 06:33:28
Done.
|
| + NSTextContainer* tc = [exitLabel_.get() textContainer]; |
| + [lm ensureLayoutForTextContainer:tc]; |
| + NSRect tcFrame = [lm usedRectForTextContainer:tc]; |
|
Nico
2011/09/15 04:37:32
yikes. just sizeForAttributes is too far off?
jeremya
2011/09/15 06:33:28
It's consistently 10px off; it seems to add space
|
| + NSRect frame = [[self view] frame]; |
| + NSSize textSize = tcFrame.size; |
| + frame.size.width = textSize.width + 2 * kPaddingPx; |
|
Nico
2011/09/15 04:37:32
NSInsetRect
jeremya
2011/09/15 06:33:28
How should I use that function?
Nico
2011/09/15 20:09:14
frame = NSInsetRect(frame, -kPaddingPx, 0) I think
|
| + [[self view] setFrame:frame]; |
| + frame = tcFrame; |
| + frame.origin.x = frame.origin.y = kPaddingPx; |
| + [exitLabel_.get() setFrame:frame]; |
| +} |
| + |
| +// This looks at the Main Menu and determines what the user has set as the |
| +// key combination for quit. It then gets the modifiers and builds an object |
| +// to hold the data. |
| ++ (ui::AcceleratorCocoa)toggleFullscreenAccelerator { |
|
Nico
2011/09/15 04:37:32
This parses like "toggle fullscreen accelerator".
jeremya
2011/09/15 06:33:28
Done.
|
| + NSMenu* mainMenu = [NSApp mainMenu]; |
| + // Get the application menu (i.e. Chromium). |
| + for (NSMenuItem* menu in [mainMenu itemArray]) { |
| + for (NSMenuItem* item in [[menu submenu] itemArray]) { |
| + // Find the toggle presentation mode item. |
| + if ([item tag] == IDC_PRESENTATION_MODE) { |
| + return ui::AcceleratorCocoa([item keyEquivalent], |
| + [item keyEquivalentModifierMask]); |
| + } |
| + } |
| + } |
| + // Default to Cmd+Shift+F. |
| + return ui::AcceleratorCocoa(@"f", NSCommandKeyMask|NSShiftKeyMask); |
| +} |
| + |
| +// This looks at the Main Menu and determines what the user has set as the |
| +// key combination for quit. It then gets the modifiers and builds a string |
| +// to display them. |
| ++ (NSString*)keyCommandString { |
| + ui::AcceleratorCocoa accelerator = [[self class] toggleFullscreenAccelerator]; |
| + return [[self class] keyCombinationForAccelerator:accelerator]; |
| +} |
| + |
| ++ (NSString*)keyCombinationForAccelerator:(const ui::AcceleratorCocoa&)item { |
| + NSMutableString* string = [NSMutableString string]; |
| + NSUInteger modifiers = item.modifiers(); |
| + |
| + if (modifiers & NSCommandKeyMask) |
| + [string appendString:@"\u2318"]; |
| + if (modifiers & NSControlKeyMask) |
| + [string appendString:@"\u2303"]; |
| + if (modifiers & NSAlternateKeyMask) |
| + [string appendString:@"\u2325"]; |
| + BOOL isUpperCase = [[NSCharacterSet uppercaseLetterCharacterSet] |
| + characterIsMember:[item.characters() characterAtIndex:0]]; |
| + if (modifiers & NSShiftKeyMask || isUpperCase) |
| + [string appendString:@"\u21E7"]; |
| + |
| + [string appendString:[item.characters() uppercaseString]]; |
| + return string; |
| +} |
| + |
| +- (void)hideSoon { |
| + hideTimer_.reset( |
| + [[NSTimer scheduledTimerWithTimeInterval:kInitialDelayMs/1000.0 |
| + target:self |
| + selector:@selector(hideTimerFire:) |
| + userInfo:nil |
| + repeats:NO] retain]); |
| +} |
| + |
| +@end |