OLD | NEW |
---|---|
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 Loading... | |
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 |
OLD | NEW |