Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(715)

Unified Diff: chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.mm

Issue 7890056: FullscreenExitBubble temp UI for Mac. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..606295b1578b7e2eecc195dcba5c7c68bec21bc9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.mm
@@ -0,0 +1,405 @@
+// 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"
+#include "grit/generated_resources.h"
+
+namespace {
+// Durations set to match the default SlideAnimation duration.
+const float kAnimateOpenDuration = 0.12;
+const float kAnimateCloseDuration = 0.12;
+
+// The baseline shift for text in the NSTextView.
+const float kTextBaselineShift = -1.0;
+}
+
+// This simple subclass of |NSTextView| just doesn't show the (text) cursor
+// (|NSTextView| displays the cursor with full keyboard accessibility enabled).
+/*@interface InfoBarTextView : NSTextView
+- (void)fixupCursor;
+@end
+
+@implementation InfoBarTextView
+
+// Never draw the insertion point (otherwise, it shows up without any user
+// action if full keyboard accessibility is enabled).
+- (BOOL)shouldDrawInsertionPoint {
+ return NO;
+}
+
+- (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
+ granularity:(NSSelectionGranularity)granularity {
+ // Do not allow selections.
+ return NSMakeRange(0, 0);
+}
+
+// Convince NSTextView to not show an I-Beam cursor when the cursor is over the
+// text view but not over actual text.
+//
+// http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg10791.html
+// "NSTextView sets the cursor over itself dynamically, based on considerations
+// including the text under the cursor. It does so in -mouseEntered:,
+// -mouseMoved:, and -cursorUpdate:, so those would be points to consider
+// overriding."
+- (void)mouseMoved:(NSEvent*)e {
+ [super mouseMoved:e];
+ [self fixupCursor];
+}
+
+- (void)mouseEntered:(NSEvent*)e {
+ [super mouseEntered:e];
+ [self fixupCursor];
+}
+
+- (void)cursorUpdate:(NSEvent*)e {
+ [super cursorUpdate:e];
+ [self fixupCursor];
+}
+
+- (void)fixupCursor {
+ if ([[NSCursor currentCursor] isEqual:[NSCursor IBeamCursor]])
+ [[NSCursor arrowCursor] set];
+}
+
+@end*/
+
+@interface FullscreenExitBubbleController (PrivateMethods)
+// Sets |exitLabel_| based on |exitLabelPlaceholder_|, sets |exitLabelPlaceholder_| to nil.
+- (void)initializeLabel;
+
+// Sets the info bar message to the specified |message|, with a hypertext
+// style link. |link| will be inserted into message at |linkOffset|.
+- (void)setLabelToMessage:(NSString*)message
+ withLink:(NSString*)link
+ atOffset:(NSUInteger)linkOffset;
+
+- (void)showButtons:(BOOL)shown;
+- (void)hideSoon;
+
+// Returns the Accelerator for the Toggle Fullscreen menu item.
++ (ui::AcceleratorCocoa)toggleFullscreenAccelerator;
+
+// Returns a string representation fit for display of |+toggleFullscreenAccelerator|.
++ (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;
+}
+
+// All infobars have an icon, so we set up the icon in the base class
+// awakeFromNib.
+- (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.
+ browser_->ExecuteCommand(IDC_FULLSCREEN);
+ return YES;
+}
+
+// Called when someone clicks on the ok button.
+- (void)allow:(id)sender {
+ [self showButtons:NO];
+ //browser_->OnAcceptFullscreenPermission(url_);
+ [self hideSoon];
+}
+
+- (void)hideTimerFire:(NSTimer*)timer {
+ // TODO why aren't we using animateClosed?
+ NSRect endFrame = [[self view] frame];
+ endFrame.origin.y += endFrame.size.height;
+ float duration = 0.3;
+ NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ [self view], NSViewAnimationTargetKey,
+ [NSValue valueWithRect:endFrame], NSViewAnimationEndFrameKey, nil];
+
+ NSViewAnimation* animation =
+ [[NSViewAnimation alloc]
+ initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
+ [animation gtm_setDuration:duration
+ eventMask:NSLeftMouseUpMask];
+ [animation setDelegate:self];
+ [animation startAnimation];
+ hideAnimation_ = animation;
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ if (animation == hideAnimation_) {
+ [hideAnimation_ autorelease];
+ hideAnimation_ = nil;
+ }
+
+ [owner_ setShowFloatingChrome:YES];
+}
+
+// Called when someone clicks on the cancel button.
+- (void)deny:(id)sender {
+ //[owner_ setFullscreen:NO forURL:GURL() showButtons:NO];
+}
+
+- (AnimatableView*)animatableView {
+ return static_cast<AnimatableView*>([self view]);
+}
+
+- (void)open {
+ // Simply reset the frame size to its opened size, forcing a relayout.
+ CGFloat finalHeight = [[self view] frame].size.height;
+ [[self animatableView] setHeight:finalHeight];
+}
+
+- (void)animateOpen {
+ // Force the frame size to be 0 and then start an animation.
+ NSRect frame = [[self view] frame];
+ CGFloat finalHeight = frame.size.height;
+ frame.size.height = 0;
+ [[self view] setFrame:frame];
+ [[self animatableView] animateToNewHeight:finalHeight
+ duration:kAnimateOpenDuration];
+}
+
+- (void)close {
+ // Stop any running animations.
+ [[self animatableView] stopAnimation];
+}
+
+- (void)animateClosed {
+ // Start animating closed. We will receive a notification when the animation
+ // is done, at which point we can remove our view from the hierarchy and
+ // notify the delegate that the infobar was closed.
+ [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration];
+
+ // The owner called this method to close the infobar, so there will
+ // be no need to forward future remove events to the owner.
+ owner_ = NULL;
+}
+
+- (void)setLabelToMessage:(NSString*)message {
+ NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
+ NSFont* font = [NSFont labelFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ [attributes setObject:font
+ forKey:NSFontAttributeName];
+ [attributes setObject:[NSCursor arrowCursor]
+ forKey:NSCursorAttributeName];
+ [attributes setObject:[NSNumber numberWithFloat:kTextBaselineShift]
+ forKey:NSBaselineOffsetAttributeName];
+ scoped_nsobject<NSAttributedString> attributedString(
+ [[NSAttributedString alloc] initWithString:message
+ attributes:attributes]);
+ [[exitLabel_.get() textStorage] setAttributedString:attributedString];
+}
+
+- (void)dealloc {
+ // TODO one or more of these things may be unnecessary.
+ [[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.
+ NSRect frame = [exitLabelPlaceholder_ frame];
+ frame.size.width = frame.size.height = 0;
+ exitLabel_.reset([[NSTextView alloc]
+ initWithFrame:[exitLabelPlaceholder_ frame]]);
+ //[exitLabel_.get() setAutoresizingMask:[exitLabelPlaceholder_ autoresizingMask]];
+ [[exitLabelPlaceholder_ superview]
+ replaceSubview:exitLabelPlaceholder_ with:exitLabel_.get()];
+ exitLabelPlaceholder_ = nil; // Now released.
+ [exitLabel_.get() setDelegate:self];
+ [exitLabel_.get() setEditable:NO];
+ [exitLabel_.get() setDrawsBackground:NO];
+ //[exitLabel_.get() setHorizontallyResizable:NO];
+ [exitLabel_.get() setVerticallyResizable:NO];
+
+ NSMutableDictionary* linkAttributes = [NSMutableDictionary dictionary];
+ [linkAttributes setObject:[NSCursor arrowCursor]
+ forKey:NSCursorAttributeName];
+ NSFont* font = [NSFont labelFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ [linkAttributes setObject:font
+ forKey:NSFontAttributeName];
+ [linkAttributes setObject:[NSColor whiteColor]
+ forKey:NSForegroundColorAttributeName];
+ [linkAttributes setObject:[NSCursor pointingHandCursor]
+ forKey:NSCursorAttributeName];
+ [linkAttributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
+ forKey:NSUnderlineStyleAttributeName];
+ [linkAttributes setObject:[NSString string] // dummy value
+ forKey:NSLinkAttributeName];
+
+ [exitLabel_.get() setLinkTextAttributes:linkAttributes];
+ NSString *message = l10n_util::GetNSStringF(IDS_EXIT_FULLSCREEN_MODE,
+ base::SysNSStringToUTF16([[self class] keyCommandString]));
+ [self setLabelToMessage:@"" withLink:message atOffset:0];
+ //[self view].frame = [exitLabel_ 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 {
+ 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)showButtons:(BOOL)show_buttons {
+ [exitLabel_ setHidden:show_buttons];
+ [allowButton_ setHidden:!show_buttons];
+ [denyButton_ setHidden:!show_buttons];
+}
+
+- (void)hideSoon {
+ // TODO probably don't need to retain?
+ hideTimer_.reset(
+ [[NSTimer scheduledTimerWithTimeInterval:2.3
+ target:self
+ selector:@selector(hideTimerFire:)
+ userInfo:nil
+ repeats:NO] retain]);
+}
+
+// TODO(joth): This method factors out some common functionality between the
+// various derived infobar classes, however the class hierarchy itself could
+// use refactoring to reduce this duplication. http://crbug.com/38924
+- (void)setLabelToMessage:(NSString*)message
+ withLink:(NSString*)link
+ atOffset:(NSUInteger)linkOffset {
+ if (linkOffset == std::wstring::npos) {
+ // linkOffset == std::wstring::npos means the link should be right-aligned,
+ // which is not supported on Mac (http://crbug.com/47728).
+ NOTIMPLEMENTED();
+ linkOffset = [message length];
+ }
+ // Create an attributes dictionary for the entire message. We have
+ // to explicitly set the control's font. We also override the cursor to give
+ // us the normal cursor rather than the text insertion cursor.
+ NSMutableDictionary* linkAttributes = [NSMutableDictionary dictionary];
+ [linkAttributes setObject:[NSCursor arrowCursor]
+ forKey:NSCursorAttributeName];
+ NSFont* font = [NSFont labelFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ [linkAttributes setObject:font
+ forKey:NSFontAttributeName];
+
+ // Create the attributed string for the main message text.
+ scoped_nsobject<NSMutableAttributedString> infoText(
+ [[NSMutableAttributedString alloc] initWithString:message]);
+ [infoText.get() addAttributes:linkAttributes
+ range:NSMakeRange(0, [infoText.get() length])];
+ // Add additional attributes to style the link text appropriately as
+ // well as linkify it.
+ [linkAttributes setObject:[NSColor whiteColor]
+ forKey:NSForegroundColorAttributeName];
+ [linkAttributes setObject:[NSNumber numberWithBool:YES]
+ forKey:NSUnderlineStyleAttributeName];
+ [linkAttributes setObject:[NSCursor pointingHandCursor]
+ forKey:NSCursorAttributeName];
+ [linkAttributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
+ forKey:NSUnderlineStyleAttributeName];
+ [linkAttributes setObject:[NSString string] // dummy value
+ forKey:NSLinkAttributeName];
+
+ // Insert the link text into the string at the appropriate offset.
+ scoped_nsobject<NSAttributedString> attributedString(
+ [[NSAttributedString alloc] initWithString:link
+ attributes:linkAttributes]);
+ [infoText.get() insertAttributedString:attributedString.get()
+ atIndex:linkOffset];
+ // The entire text needs a baseline shift.
+ [infoText addAttribute:NSBaselineOffsetAttributeName
+ value:[NSNumber numberWithDouble:kTextBaselineShift]
+ range:NSMakeRange(0, [infoText length])];
+
+ // Update the label view with the new text.
+ [[exitLabel_.get() textStorage] setAttributedString:infoText];
+
+ [exitLabel_.get() sizeToFit];
+ NSRect frame = [[self view] frame];
+ NSLog(@"%f", frame.size.width);
+ frame.size.width = [link widthForHeight:0 attributes:linkAttributes];
+ //frame.size.width = [exitLabel_ frame].size.width;
+ NSLog(@"%f", [exitLabel_ frame].size.width);
+ [[self view] setFrame:frame];
+ NSLog(@"%f", [[self view] frame].size.width);
jeremya 2011/09/14 22:56:48 here
+}
+
+@end
« no previous file with comments | « chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h ('k') | chrome/browser/ui/cocoa/fullscreen_exit_bubble_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698