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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import <Cocoa/Cocoa.h>
6
7 #include "base/logging.h" // for NOTREACHED()
8 #include "base/mac/mac_util.h"
9 #include "base/sys_string_conversions.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/ui/browser.h"
12 #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"
15 #include "chrome/browser/ui/cocoa/event_utils.h"
16 #import "chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h"
17 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
18 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
19 #include "ui/base/models/accelerator_cocoa.h"
20 #include "ui/base/l10n/l10n_util_mac.h"
21 #include "chrome/app/chrome_command_ids.h"
22 #include "grit/generated_resources.h"
23
24 namespace {
25 // Durations set to match the default SlideAnimation duration.
26 const float kAnimateOpenDuration = 0.12;
27 const float kAnimateCloseDuration = 0.12;
28
29 // The baseline shift for text in the NSTextView.
30 const float kTextBaselineShift = -1.0;
31 }
32
33 // This simple subclass of |NSTextView| just doesn't show the (text) cursor
34 // (|NSTextView| displays the cursor with full keyboard accessibility enabled).
35 /*@interface InfoBarTextView : NSTextView
36 - (void)fixupCursor;
37 @end
38
39 @implementation InfoBarTextView
40
41 // Never draw the insertion point (otherwise, it shows up without any user
42 // action if full keyboard accessibility is enabled).
43 - (BOOL)shouldDrawInsertionPoint {
44 return NO;
45 }
46
47 - (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
48 granularity:(NSSelectionGranularity)granularity {
49 // Do not allow selections.
50 return NSMakeRange(0, 0);
51 }
52
53 // Convince NSTextView to not show an I-Beam cursor when the cursor is over the
54 // text view but not over actual text.
55 //
56 // http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg10791.html
57 // "NSTextView sets the cursor over itself dynamically, based on considerations
58 // including the text under the cursor. It does so in -mouseEntered:,
59 // -mouseMoved:, and -cursorUpdate:, so those would be points to consider
60 // overriding."
61 - (void)mouseMoved:(NSEvent*)e {
62 [super mouseMoved:e];
63 [self fixupCursor];
64 }
65
66 - (void)mouseEntered:(NSEvent*)e {
67 [super mouseEntered:e];
68 [self fixupCursor];
69 }
70
71 - (void)cursorUpdate:(NSEvent*)e {
72 [super cursorUpdate:e];
73 [self fixupCursor];
74 }
75
76 - (void)fixupCursor {
77 if ([[NSCursor currentCursor] isEqual:[NSCursor IBeamCursor]])
78 [[NSCursor arrowCursor] set];
79 }
80
81 @end*/
82
83 @interface FullscreenExitBubbleController (PrivateMethods)
84 // Sets |exitLabel_| based on |exitLabelPlaceholder_|, sets |exitLabelPlaceholde r_| to nil.
85 - (void)initializeLabel;
86
87 // Sets the info bar message to the specified |message|, with a hypertext
88 // style link. |link| will be inserted into message at |linkOffset|.
89 - (void)setLabelToMessage:(NSString*)message
90 withLink:(NSString*)link
91 atOffset:(NSUInteger)linkOffset;
92
93 - (void)showButtons:(BOOL)shown;
94 - (void)hideSoon;
95
96 // Returns the Accelerator for the Toggle Fullscreen menu item.
97 + (ui::AcceleratorCocoa)toggleFullscreenAccelerator;
98
99 // Returns a string representation fit for display of |+toggleFullscreenAccelera tor|.
100 + (NSString*)keyCommandString;
101
102 + (NSString*)keyCombinationForAccelerator:(const ui::AcceleratorCocoa&)item;
103 @end
104
105 @implementation FullscreenExitBubbleController
106
107 - (id)initWithOwner:(BrowserWindowController*)owner browser:(Browser*)browser {
108 if ((self = [super initWithNibName:@"FullscreenExitBubble"
109 bundle:base::mac::MainAppBundle()])) {
110 browser_ = browser;
111 owner_ = owner;
112 }
113 return self;
114 }
115
116 // All infobars have an icon, so we set up the icon in the base class
117 // awakeFromNib.
118 - (void)awakeFromNib {
119 [self initializeLabel];
120 [self hideSoon];
121 }
122
123 // Called when someone clicks on the embedded link.
124 - (BOOL) textView:(NSTextView*)textView
125 clickedOnLink:(id)link
126 atIndex:(NSUInteger)charIndex {
127 // TODO there's probably a better way to invoke this.
128 browser_->ExecuteCommand(IDC_FULLSCREEN);
129 return YES;
130 }
131
132 // Called when someone clicks on the ok button.
133 - (void)allow:(id)sender {
134 [self showButtons:NO];
135 //browser_->OnAcceptFullscreenPermission(url_);
136 [self hideSoon];
137 }
138
139 - (void)hideTimerFire:(NSTimer*)timer {
140 // TODO why aren't we using animateClosed?
141 NSRect endFrame = [[self view] frame];
142 endFrame.origin.y += endFrame.size.height;
143 float duration = 0.3;
144 NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
145 [self view], NSViewAnimationTargetKey,
146 [NSValue valueWithRect:endFrame], NSViewAnimationEndFrameKey, nil];
147
148 NSViewAnimation* animation =
149 [[NSViewAnimation alloc]
150 initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
151 [animation gtm_setDuration:duration
152 eventMask:NSLeftMouseUpMask];
153 [animation setDelegate:self];
154 [animation startAnimation];
155 hideAnimation_ = animation;
156 }
157
158 - (void)animationDidEnd:(NSAnimation*)animation {
159 if (animation == hideAnimation_) {
160 [hideAnimation_ autorelease];
161 hideAnimation_ = nil;
162 }
163
164 [owner_ setShowFloatingChrome:YES];
165 }
166
167 // Called when someone clicks on the cancel button.
168 - (void)deny:(id)sender {
169 //[owner_ setFullscreen:NO forURL:GURL() showButtons:NO];
170 }
171
172 - (AnimatableView*)animatableView {
173 return static_cast<AnimatableView*>([self view]);
174 }
175
176 - (void)open {
177 // Simply reset the frame size to its opened size, forcing a relayout.
178 CGFloat finalHeight = [[self view] frame].size.height;
179 [[self animatableView] setHeight:finalHeight];
180 }
181
182 - (void)animateOpen {
183 // Force the frame size to be 0 and then start an animation.
184 NSRect frame = [[self view] frame];
185 CGFloat finalHeight = frame.size.height;
186 frame.size.height = 0;
187 [[self view] setFrame:frame];
188 [[self animatableView] animateToNewHeight:finalHeight
189 duration:kAnimateOpenDuration];
190 }
191
192 - (void)close {
193 // Stop any running animations.
194 [[self animatableView] stopAnimation];
195 }
196
197 - (void)animateClosed {
198 // Start animating closed. We will receive a notification when the animation
199 // is done, at which point we can remove our view from the hierarchy and
200 // notify the delegate that the infobar was closed.
201 [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration];
202
203 // The owner called this method to close the infobar, so there will
204 // be no need to forward future remove events to the owner.
205 owner_ = NULL;
206 }
207
208 - (void)setLabelToMessage:(NSString*)message {
209 NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
210 NSFont* font = [NSFont labelFontOfSize:
211 [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
212 [attributes setObject:font
213 forKey:NSFontAttributeName];
214 [attributes setObject:[NSCursor arrowCursor]
215 forKey:NSCursorAttributeName];
216 [attributes setObject:[NSNumber numberWithFloat:kTextBaselineShift]
217 forKey:NSBaselineOffsetAttributeName];
218 scoped_nsobject<NSAttributedString> attributedString(
219 [[NSAttributedString alloc] initWithString:message
220 attributes:attributes]);
221 [[exitLabel_.get() textStorage] setAttributedString:attributedString];
222 }
223
224 - (void)dealloc {
225 // TODO one or more of these things may be unnecessary.
226 [[self animatableView] stopAnimation];
227 [hideAnimation_ stopAnimation];
228 [hideTimer_ invalidate];
229 [super dealloc];
230 }
231
232 @end
233
234 @implementation FullscreenExitBubbleController (PrivateMethods)
235
236 - (void)initializeLabel {
237 // Replace the label placeholder NSTextField with the real label NSTextView.
238 // The former doesn't show links in a nice way, but the latter can't be added
239 // in IB without a containing scroll view, so create the NSTextView
240 // programmatically.
241 NSRect frame = [exitLabelPlaceholder_ frame];
242 frame.size.width = frame.size.height = 0;
243 exitLabel_.reset([[NSTextView alloc]
244 initWithFrame:[exitLabelPlaceholder_ frame]]);
245 //[exitLabel_.get() setAutoresizingMask:[exitLabelPlaceholder_ autoresizingMas k]];
246 [[exitLabelPlaceholder_ superview]
247 replaceSubview:exitLabelPlaceholder_ with:exitLabel_.get()];
248 exitLabelPlaceholder_ = nil; // Now released.
249 [exitLabel_.get() setDelegate:self];
250 [exitLabel_.get() setEditable:NO];
251 [exitLabel_.get() setDrawsBackground:NO];
252 //[exitLabel_.get() setHorizontallyResizable:NO];
253 [exitLabel_.get() setVerticallyResizable:NO];
254
255 NSMutableDictionary* linkAttributes = [NSMutableDictionary dictionary];
256 [linkAttributes setObject:[NSCursor arrowCursor]
257 forKey:NSCursorAttributeName];
258 NSFont* font = [NSFont labelFontOfSize:
259 [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
260 [linkAttributes setObject:font
261 forKey:NSFontAttributeName];
262 [linkAttributes setObject:[NSColor whiteColor]
263 forKey:NSForegroundColorAttributeName];
264 [linkAttributes setObject:[NSCursor pointingHandCursor]
265 forKey:NSCursorAttributeName];
266 [linkAttributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
267 forKey:NSUnderlineStyleAttributeName];
268 [linkAttributes setObject:[NSString string] // dummy value
269 forKey:NSLinkAttributeName];
270
271 [exitLabel_.get() setLinkTextAttributes:linkAttributes];
272 NSString *message = l10n_util::GetNSStringF(IDS_EXIT_FULLSCREEN_MODE,
273 base::SysNSStringToUTF16([[self class] keyCommandString]));
274 [self setLabelToMessage:@"" withLink:message atOffset:0];
275 //[self view].frame = [exitLabel_ frame];
276 }
277
278 // This looks at the Main Menu and determines what the user has set as the
279 // key combination for quit. It then gets the modifiers and builds an object
280 // to hold the data.
281 + (ui::AcceleratorCocoa)toggleFullscreenAccelerator {
282 NSMenu* mainMenu = [NSApp mainMenu];
283 // Get the application menu (i.e. Chromium).
284 for (NSMenuItem* menu in [mainMenu itemArray]) {
285 for (NSMenuItem* item in [[menu submenu] itemArray]) {
286 // Find the toggle presentation mode item.
287 if ([item tag] == IDC_PRESENTATION_MODE) {
288 return ui::AcceleratorCocoa([item keyEquivalent],
289 [item keyEquivalentModifierMask]);
290 }
291 }
292 }
293 // Default to Cmd+Shift+F.
294 return ui::AcceleratorCocoa(@"f", NSCommandKeyMask|NSShiftKeyMask);
295 }
296
297 // This looks at the Main Menu and determines what the user has set as the
298 // key combination for quit. It then gets the modifiers and builds a string
299 // to display them.
300 + (NSString*)keyCommandString {
301 ui::AcceleratorCocoa accelerator = [[self class] toggleFullscreenAccelerator];
302 return [[self class] keyCombinationForAccelerator:accelerator];
303 }
304
305 + (NSString*)keyCombinationForAccelerator:(const ui::AcceleratorCocoa&)item {
306 NSMutableString* string = [NSMutableString string];
307 NSUInteger modifiers = item.modifiers();
308
309 if (modifiers & NSCommandKeyMask)
310 [string appendString:@"\u2318"];
311 if (modifiers & NSControlKeyMask)
312 [string appendString:@"\u2303"];
313 if (modifiers & NSAlternateKeyMask)
314 [string appendString:@"\u2325"];
315 BOOL isUpperCase = [[NSCharacterSet uppercaseLetterCharacterSet]
316 characterIsMember:[item.characters() characterAtIndex:0]];
317 if (modifiers & NSShiftKeyMask || isUpperCase)
318 [string appendString:@"\u21E7"];
319
320 [string appendString:[item.characters() uppercaseString]];
321 return string;
322 }
323
324 - (void)showButtons:(BOOL)show_buttons {
325 [exitLabel_ setHidden:show_buttons];
326 [allowButton_ setHidden:!show_buttons];
327 [denyButton_ setHidden:!show_buttons];
328 }
329
330 - (void)hideSoon {
331 // TODO probably don't need to retain?
332 hideTimer_.reset(
333 [[NSTimer scheduledTimerWithTimeInterval:2.3
334 target:self
335 selector:@selector(hideTimerFire:)
336 userInfo:nil
337 repeats:NO] retain]);
338 }
339
340 // TODO(joth): This method factors out some common functionality between the
341 // various derived infobar classes, however the class hierarchy itself could
342 // use refactoring to reduce this duplication. http://crbug.com/38924
343 - (void)setLabelToMessage:(NSString*)message
344 withLink:(NSString*)link
345 atOffset:(NSUInteger)linkOffset {
346 if (linkOffset == std::wstring::npos) {
347 // linkOffset == std::wstring::npos means the link should be right-aligned,
348 // which is not supported on Mac (http://crbug.com/47728).
349 NOTIMPLEMENTED();
350 linkOffset = [message length];
351 }
352 // Create an attributes dictionary for the entire message. We have
353 // to explicitly set the control's font. We also override the cursor to give
354 // us the normal cursor rather than the text insertion cursor.
355 NSMutableDictionary* linkAttributes = [NSMutableDictionary dictionary];
356 [linkAttributes setObject:[NSCursor arrowCursor]
357 forKey:NSCursorAttributeName];
358 NSFont* font = [NSFont labelFontOfSize:
359 [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
360 [linkAttributes setObject:font
361 forKey:NSFontAttributeName];
362
363 // Create the attributed string for the main message text.
364 scoped_nsobject<NSMutableAttributedString> infoText(
365 [[NSMutableAttributedString alloc] initWithString:message]);
366 [infoText.get() addAttributes:linkAttributes
367 range:NSMakeRange(0, [infoText.get() length])];
368 // Add additional attributes to style the link text appropriately as
369 // well as linkify it.
370 [linkAttributes setObject:[NSColor whiteColor]
371 forKey:NSForegroundColorAttributeName];
372 [linkAttributes setObject:[NSNumber numberWithBool:YES]
373 forKey:NSUnderlineStyleAttributeName];
374 [linkAttributes setObject:[NSCursor pointingHandCursor]
375 forKey:NSCursorAttributeName];
376 [linkAttributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
377 forKey:NSUnderlineStyleAttributeName];
378 [linkAttributes setObject:[NSString string] // dummy value
379 forKey:NSLinkAttributeName];
380
381 // Insert the link text into the string at the appropriate offset.
382 scoped_nsobject<NSAttributedString> attributedString(
383 [[NSAttributedString alloc] initWithString:link
384 attributes:linkAttributes]);
385 [infoText.get() insertAttributedString:attributedString.get()
386 atIndex:linkOffset];
387 // The entire text needs a baseline shift.
388 [infoText addAttribute:NSBaselineOffsetAttributeName
389 value:[NSNumber numberWithDouble:kTextBaselineShift]
390 range:NSMakeRange(0, [infoText length])];
391
392 // Update the label view with the new text.
393 [[exitLabel_.get() textStorage] setAttributedString:infoText];
394
395 [exitLabel_.get() sizeToFit];
396 NSRect frame = [[self view] frame];
397 NSLog(@"%f", frame.size.width);
398 frame.size.width = [link widthForHeight:0 attributes:linkAttributes];
399 //frame.size.width = [exitLabel_ frame].size.width;
400 NSLog(@"%f", [exitLabel_ frame].size.width);
401 [[self view] setFrame:frame];
402 NSLog(@"%f", [[self view] frame].size.width);
jeremya 2011/09/14 22:56:48 here
403 }
404
405 @end
OLDNEW
« 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