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

Side by Side Diff: chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.mm

Issue 7740044: Implement fullscreen info bubble on Win and Mac (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: respond to comments Created 9 years, 2 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import <Cocoa/Cocoa.h> 5 #import <Cocoa/Cocoa.h>
6 6
7 #include "base/logging.h" // for NOTREACHED() 7 #include "base/logging.h" // for NOTREACHED()
8 #include "base/mac/mac_util.h" 8 #include "base/mac/mac_util.h"
9 #include "base/sys_string_conversions.h" 9 #include "base/sys_string_conversions.h"
10 #include "base/utf_string_conversions.h"
10 #include "chrome/app/chrome_command_ids.h" 11 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/ui/browser.h" 12 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 13 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
13 #import "chrome/browser/ui/cocoa/animatable_view.h"
14 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 14 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
15 #include "chrome/browser/ui/cocoa/event_utils.h" 15 #include "chrome/browser/ui/cocoa/event_utils.h"
16 #import "chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h" 16 #import "chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h"
17 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h" 17 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
18 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
19 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
18 #include "grit/generated_resources.h" 20 #include "grit/generated_resources.h"
19 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" 21 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
20 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" 22 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
23 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
21 #include "ui/base/models/accelerator_cocoa.h" 24 #include "ui/base/models/accelerator_cocoa.h"
22 #include "ui/base/l10n/l10n_util_mac.h" 25 #include "ui/base/l10n/l10n_util_mac.h"
23 26
24 const int kPaddingPx = 8;
25 const int kInitialDelayMs = 3800; 27 const int kInitialDelayMs = 3800;
26 const int kSlideOutDurationMs = 700; 28 const int kHideDurationMs = 700;
29
30 @interface OneClickHyperlinkTextView : HyperlinkTextView
31 @end
32 @implementation OneClickHyperlinkTextView
33 - (BOOL)acceptsFirstMouse:(NSEvent*)event {
34 return YES;
35 }
36 @end
27 37
28 @interface FullscreenExitBubbleController (PrivateMethods) 38 @interface FullscreenExitBubbleController (PrivateMethods)
29 // Sets |exitLabel_| based on |exitLabelPlaceholder_|, 39 // Sets |exitLabel_| based on |exitLabelPlaceholder_|,
30 // sets |exitLabelPlaceholder_| to nil. 40 // sets |exitLabelPlaceholder_| to nil.
31 - (void)initializeLabel; 41 - (void)initializeLabel;
32 42
33 - (void)hideSoon; 43 - (void)hideSoon;
34 44
35 // Returns the Accelerator for the Toggle Fullscreen menu item. 45 // Returns the Accelerator for the Toggle Fullscreen menu item.
36 + (ui::AcceleratorCocoa)acceleratorForToggleFullscreen; 46 + (ui::AcceleratorCocoa)acceleratorForToggleFullscreen;
37 47
38 // Returns a string representation fit for display of 48 // Returns a string representation fit for display of
39 // +acceleratorForToggleFullscreen. 49 // +acceleratorForToggleFullscreen.
40 + (NSString*)keyCommandString; 50 + (NSString*)keyCommandString;
41 51
42 + (NSString*)keyCombinationForAccelerator:(const ui::AcceleratorCocoa&)item; 52 + (NSString*)keyCombinationForAccelerator:(const ui::AcceleratorCocoa&)item;
43 @end 53 @end
44 54
45 @implementation FullscreenExitBubbleController 55 @implementation FullscreenExitBubbleController
46 56
47 - (id)initWithOwner:(BrowserWindowController*)owner browser:(Browser*)browser { 57 - (id)initWithOwner:(BrowserWindowController*)owner
48 if ((self = [super initWithNibName:@"FullscreenExitBubble" 58 browser:(Browser*)browser
49 bundle:base::mac::MainAppBundle()])) { 59 forURL:(const GURL&)url
60 askPermission:(BOOL)askPermission {
61 NSString* nibPath =
62 [base::mac::MainAppBundle() pathForResource:@"FullscreenExitBubble"
63 ofType:@"nib"];
Scott Hess - ex-Googler 2011/10/13 20:30:27 Indentation.
64 if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
50 browser_ = browser; 65 browser_ = browser;
51 owner_ = owner; 66 owner_ = owner;
67 url_ = url;
68 showButtons_ = askPermission;
52 } 69 }
53 return self; 70 return self;
54 } 71 }
55 72
56 - (void)awakeFromNib { 73 - (void)allow:(id)sender {
57 [self initializeLabel]; 74 [self hideButtons];
75 browser_->OnAcceptFullscreenPermission(url_);
58 [self hideSoon]; 76 [self hideSoon];
59 } 77 }
60 78
79 - (void)deny:(id)sender {
80 browser_->ToggleFullscreenMode(false);
81 }
82
83 - (void)hideButtons {
84 [allowButton_ setHidden:YES];
85 [denyButton_ setHidden:YES];
86 [exitLabel_ setHidden:NO];
87 }
88
89 // We want this to be a child of a browser window. addChildWindow:
90 // (called from this function) will bring the window on-screen;
91 // unfortunately, [NSWindowController showWindow:] will also bring it
92 // on-screen (but will cause unexpected changes to the window's
93 // position). We cannot have an addChildWindow: and a subsequent
94 // showWindow:. Thus, we have our own version.
95 - (void)showWindow {
96 NSWindow* window = [self window]; // completes nib load
Scott Hess - ex-Googler 2011/10/13 20:30:27 I'd make this InfoBubbleWindow*, then use that in
koz (OOO until 15th September) 2011/10/14 00:35:16 Done.
97 [bubble_ setArrowLocation:info_bubble::kNoArrow];
98 [(InfoBubbleWindow*)[self window] setCanBecomeKey:NO];
Scott Hess - ex-Googler 2011/10/13 20:30:27 If I were REALLY pedantic I'd say -setCanBecomeKey
koz (OOO until 15th September) 2011/10/14 00:35:16 Done.
99 if (!showButtons_) {
100 [self hideButtons];
101 [self hideSoon];
102 }
103 NSRect windowFrame = [owner_ window].frame;
104 [tweaker_ tweakUI:[self window]];
105 [self positionInWindowAtTop:NSHeight(windowFrame) width:NSWidth(windowFrame)];
106 [[owner_ window] addChildWindow:window ordered:NSWindowAbove];
107
108 [window orderFront:self];
109 }
110
111 - (void)awakeFromNib {
112 NSString* title =
113 l10n_util::GetNSStringF(IDS_FULLSCREEN_INFOBAR_REQUEST_PERMISSION,
114 UTF8ToUTF16(url_.host()));
115 [messageLabel_ setStringValue:title];
116 [self initializeLabel];
117 }
118
61 - (void)positionInWindowAtTop:(CGFloat)maxY width:(CGFloat)maxWidth { 119 - (void)positionInWindowAtTop:(CGFloat)maxY width:(CGFloat)maxWidth {
62 NSRect bubbleFrame = [[self view] frame]; 120 NSRect windowFrame = [self window].frame;
63 bubbleFrame.origin.x = (int)(maxWidth/2 - NSWidth(bubbleFrame)/2); 121 NSPoint origin = windowFrame.origin;
Scott Hess - ex-Googler 2011/10/13 20:30:27 You just overwrite origin below.
koz (OOO until 15th September) 2011/10/14 00:35:16 Done.
64 bubbleFrame.origin.y = maxY - NSHeight(bubbleFrame); 122 origin.x = (int)(maxWidth/2 - NSWidth(windowFrame)/2);
65 [[self view] setFrame:bubbleFrame]; 123 origin.y = maxY - NSHeight(windowFrame);
124 origin.y -= fullscreen_exit_bubble::kBubbleOffsetY;
125 [[self window] setFrameOrigin:origin];
66 } 126 }
67 127
68 // Called when someone clicks on the embedded link. 128 // Called when someone clicks on the embedded link.
69 - (BOOL) textView:(NSTextView*)textView 129 - (BOOL) textView:(NSTextView*)textView
70 clickedOnLink:(id)link 130 clickedOnLink:(id)link
71 atIndex:(NSUInteger)charIndex { 131 atIndex:(NSUInteger)charIndex {
72 browser_->ExecuteCommand(IDC_FULLSCREEN); 132 browser_->ExecuteCommand(IDC_FULLSCREEN);
73 return YES; 133 return YES;
74 } 134 }
75 135
76 - (void)hideTimerFired:(NSTimer*)timer { 136 - (void)hideTimerFired:(NSTimer*)timer {
77 NSRect endFrame = [[self view] frame]; 137 [NSAnimationContext beginGrouping];
78 endFrame.origin.y += endFrame.size.height; 138 [[NSAnimationContext currentContext]
79 endFrame.size.height = 0; 139 gtm_setDuration:kHideDurationMs/1000.0
Scott Hess - ex-Googler 2011/10/13 20:30:27 Any reason not to just have kHideDuration just be
koz (OOO until 15th September) 2011/10/14 00:35:16 Done.
80 NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: 140 eventMask:NSLeftMouseUpMask|NSLeftMouseDownMask];
81 [self view], NSViewAnimationTargetKey, 141 [[[self window] animator] setAlphaValue:0.0];
82 [NSValue valueWithRect:endFrame], NSViewAnimationEndFrameKey, nil]; 142 [NSAnimationContext endGrouping];
83 143 return;
Scott Hess - ex-Googler 2011/10/13 20:30:27 Extraneous return.
84 NSViewAnimation* animation =
85 [[NSViewAnimation alloc]
86 initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
87 [animation gtm_setDuration:kSlideOutDurationMs/1000.0
88 eventMask:NSLeftMouseUpMask];
89 [animation setDelegate:self];
90 [animation startAnimation];
91 hideAnimation_.reset(animation);
92 } 144 }
93 145
94 - (void)animationDidEnd:(NSAnimation*)animation { 146 - (void)animationDidEnd:(NSAnimation*)animation {
95 if (animation == hideAnimation_.get()) { 147 if (animation == hideAnimation_.get()) {
96 hideAnimation_.reset(); 148 hideAnimation_.reset();
97 } 149 }
98 } 150 }
99 151
100 - (AnimatableView*)animatableView {
101 return static_cast<AnimatableView*>([self view]);
102 }
103
104 - (void)dealloc { 152 - (void)dealloc {
105 [hideAnimation_.get() stopAnimation]; 153 [hideAnimation_.get() stopAnimation];
106 [hideTimer_ invalidate]; 154 [hideTimer_ invalidate];
107 [super dealloc]; 155 [super dealloc];
108 } 156 }
109 157
110 @end 158 @end
111 159
112 @implementation FullscreenExitBubbleController (PrivateMethods) 160 @implementation FullscreenExitBubbleController (PrivateMethods)
113 161
114 - (void)initializeLabel { 162 - (void)initializeLabel {
115 // Replace the label placeholder NSTextField with the real label NSTextView. 163 // Replace the label placeholder NSTextField with the real label NSTextView.
116 // The former doesn't show links in a nice way, but the latter can't be added 164 // The former doesn't show links in a nice way, but the latter can't be added
117 // in IB without a containing scroll view, so create the NSTextView 165 // in IB without a containing scroll view, so create the NSTextView
118 // programmatically. 166 // programmatically.
119 exitLabel_.reset([[HyperlinkTextView alloc] 167 exitLabel_.reset([[OneClickHyperlinkTextView alloc]
120 initWithFrame:[exitLabelPlaceholder_ frame]]); 168 initWithFrame:[exitLabelPlaceholder_ frame]]);
121 [exitLabel_.get() setAutoresizingMask: 169 [exitLabel_.get() setAutoresizingMask:
122 [exitLabelPlaceholder_ autoresizingMask]]; 170 [exitLabelPlaceholder_ autoresizingMask]];
171 [exitLabel_.get() setHidden:[exitLabelPlaceholder_ isHidden]];
123 [[exitLabelPlaceholder_ superview] 172 [[exitLabelPlaceholder_ superview]
124 replaceSubview:exitLabelPlaceholder_ with:exitLabel_.get()]; 173 replaceSubview:exitLabelPlaceholder_ with:exitLabel_.get()];
125 exitLabelPlaceholder_ = nil; // Now released. 174 exitLabelPlaceholder_ = nil; // Now released.
126 [exitLabel_.get() setDelegate:self]; 175 [exitLabel_.get() setDelegate:self];
127 176
128 NSString *message = l10n_util::GetNSStringF(IDS_EXIT_FULLSCREEN_MODE, 177 NSString *message = l10n_util::GetNSStringF(IDS_EXIT_FULLSCREEN_MODE,
129 base::SysNSStringToUTF16([[self class] keyCommandString])); 178 base::SysNSStringToUTF16([[self class] keyCommandString]));
130 179
180 NSFont* font = [NSFont systemFontOfSize:
181 [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
131 [(HyperlinkTextView*)exitLabel_.get() 182 [(HyperlinkTextView*)exitLabel_.get()
132 setMessageAndLink:@"" 183 setMessageAndLink:@""
133 withLink:message 184 withLink:message
134 atOffset:0 185 atOffset:0
135 font:[NSFont systemFontOfSize:18] 186 font:font
136 messageColor:[NSColor whiteColor] 187 messageColor:[NSColor blackColor]
137 linkColor:[NSColor whiteColor]]; 188 linkColor:[NSColor blueColor]];
189 [exitLabel_.get() setAlignment:NSRightTextAlignment];
138 190
139 [exitLabel_.get() sizeToFit]; 191 NSRect labelFrame = [exitLabel_ frame];
140 NSLayoutManager* layoutManager = [exitLabel_.get() layoutManager]; 192
141 NSTextContainer* textContainer = [exitLabel_.get() textContainer]; 193 // NSTextView's sizeToFit: method seems to enjoy wrapping lines. Temporarily
194 // set the size large to force it not to.
195 NSRect windowFrame = [[self window] frame];
196 [exitLabel_ setFrameSize:NSMakeSize(NSWidth(windowFrame),
197 NSHeight(windowFrame))];
Scott Hess - ex-Googler 2011/10/13 20:30:27 How about windowFrame.size?
koz (OOO until 15th September) 2011/10/14 00:35:16 Done.
198 NSLayoutManager* layoutManager = [exitLabel_ layoutManager];
199 NSTextContainer* textContainer = [exitLabel_ textContainer];
142 [layoutManager ensureLayoutForTextContainer:textContainer]; 200 [layoutManager ensureLayoutForTextContainer:textContainer];
143 NSRect textFrame = [layoutManager usedRectForTextContainer:textContainer]; 201 NSRect textFrame = [layoutManager usedRectForTextContainer:textContainer];
144 NSRect frame = [[self view] frame]; 202
145 NSSize textSize = textFrame.size; 203 labelFrame.origin.x += NSWidth(labelFrame) - NSWidth(textFrame);
146 frame.size.width = textSize.width + 2 * kPaddingPx; 204 labelFrame.size = textFrame.size;
147 [[self view] setFrame:frame]; 205 [exitLabel_ setFrame:labelFrame];
148 textFrame.origin.x = textFrame.origin.y = kPaddingPx;
149 [exitLabel_.get() setFrame:textFrame];
150 } 206 }
151 207
152 // This looks at the Main Menu and determines what the user has set as the 208 // This looks at the Main Menu and determines what the user has set as the
153 // key combination for quit. It then gets the modifiers and builds an object 209 // key combination for quit. It then gets the modifiers and builds an object
154 // to hold the data. 210 // to hold the data.
155 + (ui::AcceleratorCocoa)acceleratorForToggleFullscreen { 211 + (ui::AcceleratorCocoa)acceleratorForToggleFullscreen {
156 NSMenu* mainMenu = [NSApp mainMenu]; 212 NSMenu* mainMenu = [NSApp mainMenu];
157 // Get the application menu (i.e. Chromium). 213 // Get the application menu (i.e. Chromium).
158 for (NSMenuItem* menu in [mainMenu itemArray]) { 214 for (NSMenuItem* menu in [mainMenu itemArray]) {
159 for (NSMenuItem* item in [[menu submenu] itemArray]) { 215 for (NSMenuItem* item in [[menu submenu] itemArray]) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 - (void)hideSoon { 255 - (void)hideSoon {
200 hideTimer_.reset( 256 hideTimer_.reset(
201 [[NSTimer scheduledTimerWithTimeInterval:kInitialDelayMs/1000.0 257 [[NSTimer scheduledTimerWithTimeInterval:kInitialDelayMs/1000.0
202 target:self 258 target:self
203 selector:@selector(hideTimerFired:) 259 selector:@selector(hideTimerFired:)
204 userInfo:nil 260 userInfo:nil
205 repeats:NO] retain]); 261 repeats:NO] retain]);
206 } 262 }
207 263
208 @end 264 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698