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

Side by Side Diff: chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.mm

Issue 2263863002: Remove implementation of Panels on OSes other than ChromeOS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: CR feedback Created 4 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h"
6
7 #import <Cocoa/Cocoa.h>
8
9 #include "base/logging.h"
10 #include "base/mac/scoped_nsautorelease_pool.h"
11 #import "chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.h"
12 #import "chrome/browser/ui/panels/panel_constants.h"
13 #include "chrome/grit/generated_resources.h"
14 #include "grit/theme_resources.h"
15 #include "ui/base/cocoa/cocoa_base_utils.h"
16 #import "ui/base/cocoa/hover_image_button.h"
17 #import "ui/base/cocoa/nsview_additions.h"
18 #include "ui/base/l10n/l10n_util_mac.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/image/image.h"
21 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
22
23 // 'Glint' is a glowing light animation on the titlebar to attract user's
24 // attention. Numbers are arbitrary, based on several tries.
25 const double kGlintAnimationDuration = 1.5;
26 const double kGlintRepeatIntervalSeconds = 1.0;
27 const int kNumberOfGlintRepeats = 4; // 5 total, including initial flash.
28
29 // Used to implement TestingAPI
30 static NSEvent* MakeMouseEvent(NSEventType type,
31 NSPoint point,
32 int modifierFlags,
33 int clickCount) {
34 return [NSEvent mouseEventWithType:type
35 location:point
36 modifierFlags:modifierFlags
37 timestamp:0
38 windowNumber:0
39 context:nil
40 eventNumber:0
41 clickCount:clickCount
42 pressure:0.0];
43 }
44
45 // Test drag controller - does not contain a nested message loop, directly
46 // invokes the dragStarted/dragProgress instead.
47 @interface TestDragController : MouseDragController {
48 @private
49 BOOL dragStarted_;
50 }
51 - (void)mouseDragged:(NSEvent*)event;
52 @end
53
54 @implementation TestDragController
55 // Bypass nested message loop for tests. There is no need to check for
56 // threshold here as the base class does because tests only simulate a single
57 // 'mouse drag' to the destination point.
58 - (void)mouseDragged:(NSEvent*)event {
59 if (!dragStarted_) {
60 [[self client] dragStarted:[self initialMouseLocation]];
61 dragStarted_ = YES;
62 }
63
64 [[self client] dragProgress:[event locationInWindow]];
65 }
66 @end
67
68 @implementation PanelTitlebarOverlayView
69 // Sometimes we do not want to bring chrome window to foreground when we click
70 // on any part of the titlebar. To do this, we first postpone the window
71 // reorder here (shouldDelayWindowOrderingForEvent is called during when mouse
72 // button is pressed but before mouseDown: is dispatched) and then complete
73 // canceling the reorder by [NSApp preventWindowOrdering] in mouseDown handler
74 // of this view.
75 - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent*)theEvent {
76 disableReordering_ = ![controller_ canBecomeKeyWindow];
77 return disableReordering_;
78 }
79
80 - (void)mouseDown:(NSEvent*)event {
81 if (disableReordering_)
82 [NSApp preventWindowOrdering];
83 disableReordering_ = NO;
84 // Continue bubbling the event up the chain of responders.
85 [super mouseDown:event];
86 }
87
88 - (BOOL)acceptsFirstMouse:(NSEvent*)event {
89 return YES;
90 }
91 @end
92
93 @implementation RepaintAnimation
94 - (id)initWithView:(NSView*)targetView duration:(double) duration {
95 if ((self = [super initWithDuration:duration
96 animationCurve:NSAnimationEaseInOut])) {
97 [self setAnimationBlockingMode:NSAnimationNonblocking];
98 targetView_ = targetView;
99 }
100 return self;
101 }
102
103 - (void)setCurrentProgress:(NSAnimationProgress)progress {
104 [super setCurrentProgress:progress];
105 [targetView_ setNeedsDisplay:YES];
106 }
107 @end
108
109
110 @implementation PanelTitlebarViewCocoa
111
112 - (id)initWithFrame:(NSRect)frame {
113 if ((self = [super initWithFrame:frame]))
114 dragController_.reset([[MouseDragController alloc] initWithClient:self]);
115 return self;
116 }
117
118 - (void)dealloc {
119 [[NSNotificationCenter defaultCenter] removeObserver:self];
120 [self stopGlintAnimation];
121 [super dealloc];
122 }
123
124 - (void)onCloseButtonClick:(id)sender {
125 [controller_ closePanel];
126 }
127
128 - (void)onMinimizeButtonClick:(id)sender {
129 [controller_ minimizeButtonClicked:[[NSApp currentEvent] modifierFlags]];
130 }
131
132 - (void)onRestoreButtonClick:(id)sender {
133 [controller_ restoreButtonClicked:[[NSApp currentEvent] modifierFlags]];
134 }
135
136 - (void)drawRect:(NSRect)rect {
137 if (isDrawingAttention_) {
138 NSColor* attentionColor = [NSColor colorWithCalibratedRed:0x53/255.0
139 green:0xa9/255.0
140 blue:0x3f/255.0
141 alpha:1.0];
142 [attentionColor set];
143 NSRectFillUsingOperation([self bounds], NSCompositeSourceOver);
144
145 if ([glintAnimation_ isAnimating]) {
146 base::scoped_nsobject<NSGradient> glint([NSGradient alloc]);
147 float currentAlpha = 0.8 * [glintAnimation_ currentValue];
148 NSColor* startColor = [NSColor colorWithCalibratedWhite:1.0
149 alpha:currentAlpha];
150 NSColor* endColor = [NSColor colorWithCalibratedWhite:1.0
151 alpha:0.0];
152 [glint initWithColorsAndLocations:
153 startColor, 0.0, startColor, 0.3, endColor, 1.0, nil];
154 NSRect bounds = [self bounds];
155 [glint drawInRect:bounds relativeCenterPosition:NSZeroPoint];
156 }
157 } else {
158 BOOL isActive = [[self window] isMainWindow];
159
160 // If titlebar is close to minimized state or is at minimized state and only
161 // shows a few pixels, change the color to something light and add border.
162 NSRect windowFrame = [[self window] frame];
163 if (NSHeight(windowFrame) < 8) {
164 NSColor* lightBackgroundColor =
165 [NSColor colorWithCalibratedRed:0xf5/255.0
166 green:0xf4/255.0
167 blue:0xf0/255.0
168 alpha:1.0];
169 [lightBackgroundColor set];
170 NSRectFill([self bounds]);
171
172 NSColor* borderColor =
173 [NSColor colorWithCalibratedRed:0xc9/255.0
174 green:0xc9/255.0
175 blue:0xc9/255.0
176 alpha:1.0];
177 [borderColor set];
178 NSFrameRect([self bounds]);
179 } else {
180 // use solid black-ish colors.
181 NSColor* backgroundColor = isActive ?
182 [NSColor colorWithCalibratedRed:0x3a/255.0
183 green:0x3d/255.0
184 blue:0x3d/255.0
185 alpha:1.0] :
186 [NSColor colorWithCalibratedRed:0x7a/255.0
187 green:0x7c/255.0
188 blue:0x7c/255.0
189 alpha:1.0];
190
191 [backgroundColor set];
192 NSRectFill([self bounds]);
193 }
194 }
195
196 NSColor* titleColor = [NSColor colorWithCalibratedRed:0xf9/255.0
197 green:0xf9/255.0
198 blue:0xf9/255.0
199 alpha:1.0];
200 [title_ setTextColor:titleColor];
201 }
202
203 - (void)attach {
204 // Interface Builder can not put a view as a sibling of contentView,
205 // so need to do it here. Placing ourself as the last child of the
206 // internal view allows us to draw on top of the titlebar.
207 // Note we must use [controller_ window] here since we have not been added
208 // to the view hierarchy yet.
209 NSView* contentView = [[controller_ window] contentView];
210 NSView* rootView = [contentView superview];
211 [rootView addSubview:self];
212
213 // Figure out the rectangle of the titlebar and set us on top of it.
214 // The titlebar covers window's root view where not covered by contentView.
215 // Compute the titlebar frame in coordinate system of the window's root view.
216 // NSWindow
217 // |
218 // ___root_view____
219 // | |
220 // contentView titlebar
221 NSSize titlebarSize = NSMakeSize(0, panel::kTitlebarHeight);
222 titlebarSize = [contentView convertSize:titlebarSize toView:rootView];
223 NSRect rootViewBounds = [[self superview] bounds];
224 NSRect titlebarFrame =
225 NSMakeRect(NSMinX(rootViewBounds),
226 NSMaxY(rootViewBounds) - titlebarSize.height,
227 NSWidth(rootViewBounds),
228 titlebarSize.height);
229 [self setFrame:titlebarFrame];
230
231 [title_ setFont:[[NSFontManager sharedFontManager]
232 fontWithFamily:@"Arial"
233 traits:NSBoldFontMask
234 weight:0
235 size:14.0]];
236 [title_ setDrawsBackground:NO];
237
238 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
239
240 [self initializeImageButton:customCloseButton_
241 image:rb.GetNativeImageNamed(IDR_PANEL_CLOSE).ToNSImage()
242 hoverImage:rb.GetNativeImageNamed(IDR_PANEL_CLOSE_H).ToNSImage()
243 pressedImage:rb.GetNativeImageNamed(IDR_PANEL_CLOSE_C).ToNSImage()
244 toolTip:l10n_util::GetNSStringWithFixup(IDS_PANEL_CLOSE_TOOLTIP)];
245
246 // Iniitalize the minimize and restore buttons.
247 [self initializeImageButton:minimizeButton_
248 image:rb.GetNativeImageNamed(IDR_PANEL_MINIMIZE).ToNSImage()
249 hoverImage:rb.GetNativeImageNamed(IDR_PANEL_MINIMIZE_H).ToNSImage()
250 pressedImage:rb.GetNativeImageNamed(IDR_PANEL_MINIMIZE_C).ToNSImage()
251 toolTip:l10n_util::GetNSStringWithFixup(IDS_PANEL_MINIMIZE_TOOLTIP)];
252
253 [self initializeImageButton:restoreButton_
254 image:rb.GetNativeImageNamed(IDR_PANEL_RESTORE).ToNSImage()
255 hoverImage:rb.GetNativeImageNamed(IDR_PANEL_RESTORE_H).ToNSImage()
256 pressedImage:rb.GetNativeImageNamed(IDR_PANEL_RESTORE_C).ToNSImage()
257 toolTip:l10n_util::GetNSStringWithFixup(IDS_PANEL_RESTORE_TOOLTIP)];
258
259 [controller_ updateTitleBarMinimizeRestoreButtonVisibility];
260
261 [self updateCustomButtonsLayout];
262
263 // Set autoresizing behavior: glued to edges on left, top and right.
264 [self setAutoresizingMask:(NSViewMinYMargin | NSViewWidthSizable)];
265
266 [[NSNotificationCenter defaultCenter]
267 addObserver:self
268 selector:@selector(didChangeFrame:)
269 name:NSViewFrameDidChangeNotification
270 object:self];
271 [[NSNotificationCenter defaultCenter]
272 addObserver:self
273 selector:@selector(didChangeMainWindow:)
274 name:NSWindowDidBecomeMainNotification
275 object:[self window]];
276 [[NSNotificationCenter defaultCenter]
277 addObserver:self
278 selector:@selector(didChangeMainWindow:)
279 name:NSWindowDidResignMainNotification
280 object:[self window]];
281 }
282
283 - (void)initializeImageButton:(HoverImageButton*)button
284 image:(NSImage*)image
285 hoverImage:(NSImage*)hoverImage
286 pressedImage:(NSImage*)pressedImage
287 toolTip:(NSString*)toolTip {
288 [button setDefaultImage:image];
289 [button setHoverImage:hoverImage];
290 [button setPressedImage:pressedImage];
291 [button setToolTip:toolTip];
292 [[button cell] setHighlightsBy:NSNoCellMask];
293 }
294
295 - (void)setTitle:(NSString*)newTitle {
296 [title_ setStringValue:newTitle];
297 [self updateIconAndTitleLayout];
298 }
299
300 - (void)setIcon:(NSView*)newIcon {
301 [icon_ removeFromSuperview];
302 icon_ = newIcon;
303 if (icon_) {
304 [self addSubview:icon_ positioned:NSWindowBelow relativeTo:overlay_];
305 [icon_ setWantsLayer:YES];
306 }
307 [self updateIconAndTitleLayout];
308 }
309
310 - (NSView*)icon {
311 return icon_;
312 }
313
314 - (void)setMinimizeButtonVisibility:(BOOL)visible {
315 [minimizeButton_ setHidden:!visible];
316 }
317
318 - (void)setRestoreButtonVisibility:(BOOL)visible {
319 [restoreButton_ setHidden:!visible];
320 }
321
322 - (void)updateCustomButtonsLayout {
323 NSRect bounds = [self bounds];
324 NSRect closeButtonFrame = [customCloseButton_ frame];
325 closeButtonFrame.size.width = panel::kPanelButtonSize;
326 closeButtonFrame.size.height = panel::kPanelButtonSize;
327 closeButtonFrame.origin.x =
328 NSWidth(bounds) - NSWidth(closeButtonFrame) - panel::kButtonPadding;
329 closeButtonFrame.origin.y =
330 (NSHeight(bounds) - NSHeight(closeButtonFrame)) / 2;
331 [customCloseButton_ setFrame:closeButtonFrame];
332
333 NSRect buttonFrame = [minimizeButton_ frame];
334 buttonFrame.size.width = panel::kPanelButtonSize;
335 buttonFrame.size.height = panel::kPanelButtonSize;
336 buttonFrame.origin.x =
337 closeButtonFrame.origin.x - NSWidth(buttonFrame) - panel::kButtonPadding;
338 buttonFrame.origin.y = (NSHeight(bounds) - NSHeight(buttonFrame)) / 2;
339 [minimizeButton_ setFrame:buttonFrame];
340 [restoreButton_ setFrame:buttonFrame];
341 }
342
343 - (void)updateIconAndTitleLayout {
344 NSRect iconFrame = [icon_ frame];
345 // NSTextField for title_ is set to Layout:Truncate, LineBreaks:TruncateTail
346 // in Interface Builder so it is sized in a single-line mode.
347 [title_ sizeToFit];
348 NSRect titleFrame = [title_ frame];
349 // Only one of minimize/restore button is visible at a time so just allow for
350 // the width of one of them.
351 NSRect minimizeRestoreButtonFrame = [minimizeButton_ frame];
352 NSRect bounds = [self bounds];
353
354 // Place the icon and title at the left edge of the titlebar.
355 int iconWidth = NSWidth(iconFrame);
356 int titleWidth = NSWidth(titleFrame);
357 int availableWidth = minimizeRestoreButtonFrame.origin.x -
358 panel::kTitleAndButtonPadding;
359
360 int paddings = panel::kTitlebarLeftPadding + panel::kIconAndTitlePadding;
361 if (paddings + iconWidth + titleWidth > availableWidth)
362 titleWidth = availableWidth - iconWidth - paddings;
363 if (titleWidth < 0)
364 titleWidth = 0;
365
366 iconFrame.origin.x = panel::kTitlebarLeftPadding;
367 iconFrame.origin.y = (NSHeight(bounds) - NSHeight(iconFrame)) / 2;
368 [icon_ setFrame:iconFrame];
369
370 titleFrame.origin.x = paddings + iconWidth;
371 // In bottom-heavy text labels, let's compensate for occasional integer
372 // rounding to avoid text label to feel too low.
373 titleFrame.origin.y = (NSHeight(bounds) - NSHeight(titleFrame)) / 2 + 2;
374 titleFrame.size.width = titleWidth;
375 [title_ setFrame:titleFrame];
376 }
377
378 // PanelManager controls size/position of the window.
379 - (BOOL)mouseDownCanMoveWindow {
380 return NO;
381 }
382
383 - (BOOL)acceptsFirstMouse:(NSEvent*)event {
384 return YES;
385 }
386
387 - (void)didChangeFrame:(NSNotification*)notification {
388 // Update buttons first because title layout depends on buttons layout.
389 [self updateCustomButtonsLayout];
390 [self updateIconAndTitleLayout];
391 }
392
393 - (void)didChangeMainWindow:(NSNotification*)notification {
394 [self setNeedsDisplay:YES];
395 }
396
397 - (void)mouseDown:(NSEvent*)event {
398 [dragController_ mouseDown:event];
399 }
400
401 - (void)mouseUp:(NSEvent*)event {
402 [dragController_ mouseUp:event];
403
404 if ([event clickCount] == 1)
405 [controller_ onTitlebarMouseClicked:[event modifierFlags]];
406 else if ([event clickCount] == 2)
407 [controller_ onTitlebarDoubleClicked:[event modifierFlags]];
408 }
409
410 - (void)mouseDragged:(NSEvent*)event {
411 [dragController_ mouseDragged:event];
412 }
413
414 // MouseDragControllerClient implementaiton
415
416 - (void)prepareForDrag {
417 }
418
419 - (void)dragStarted:(NSPoint)initialMouseLocation {
420 NSPoint initialMouseLocationScreen = ui::ConvertPointFromWindowToScreen(
421 [self window], initialMouseLocation);
422 [controller_ startDrag:initialMouseLocationScreen];
423 }
424
425 - (void)dragEnded:(BOOL)cancelled {
426 [controller_ endDrag:cancelled];
427 }
428
429 - (void)dragProgress:(NSPoint)mouseLocation {
430 NSPoint mouseLocationScreen = ui::ConvertPointFromWindowToScreen(
431 [self window], mouseLocation);
432 [controller_ drag:mouseLocationScreen];
433 }
434
435 - (void)cleanupAfterDrag {
436 }
437
438 // End of MouseDragControllerClient implementaiton
439
440 - (void)drawAttention {
441 if (isDrawingAttention_)
442 return;
443 isDrawingAttention_ = YES;
444
445 [self startGlintAnimation];
446 }
447
448 - (void)stopDrawingAttention {
449 if (!isDrawingAttention_)
450 return;
451 isDrawingAttention_ = NO;
452
453 [self stopGlintAnimation];
454 [self setNeedsDisplay:YES];
455 }
456
457 - (BOOL)isDrawingAttention {
458 return isDrawingAttention_;
459 }
460
461 - (void)startGlintAnimation {
462 glintCounter_ = 0;
463 [self restartGlintAnimation:nil];
464 }
465
466 - (void)stopGlintAnimation {
467 if (glintAnimationTimer_.get()) {
468 [glintAnimationTimer_ invalidate];
469 glintAnimationTimer_.reset();
470 }
471 if ([glintAnimation_ isAnimating])
472 [glintAnimation_ stopAnimation];
473 }
474
475 - (void)restartGlintAnimation:(NSTimer*)timer {
476 if (!glintAnimation_.get()) {
477 glintAnimation_.reset(
478 [[RepaintAnimation alloc] initWithView:self
479 duration:kGlintAnimationDuration]);
480 [glintAnimation_ setDelegate:self];
481 }
482 [glintAnimation_ startAnimation];
483 }
484
485 // NSAnimationDelegate method.
486 - (void)animationDidEnd:(NSAnimation*)animation {
487 if (animation != glintAnimation_.get())
488 return;
489 if (glintCounter_ >= kNumberOfGlintRepeats)
490 return;
491 glintCounter_++;
492 // Restart after a timeout.
493 glintAnimationTimer_.reset([[NSTimer
494 scheduledTimerWithTimeInterval:kGlintRepeatIntervalSeconds
495 target:self
496 selector:@selector(restartGlintAnimation:)
497 userInfo:nil
498 repeats:NO] retain]);
499 }
500
501 // NSAnimationDelegate method.
502 - (float)animation:(NSAnimation *)animation
503 valueForProgress:(NSAnimationProgress)progress {
504 if (animation != glintAnimation_.get())
505 return progress;
506
507 // Converts 0..1 progression into a sharper raise/fall.
508 float result = progress < 0.5 ? progress : 1.0 - progress;
509 result = 4.0 * result * result;
510 return result;
511 }
512
513 // (Private/TestingAPI)
514 - (PanelWindowControllerCocoa*)controller {
515 return controller_;
516 }
517
518 - (NSTextField*)title {
519 return title_;
520 }
521
522 - (void)simulateCloseButtonClick {
523 [[customCloseButton_ cell] performClick:customCloseButton_];
524 }
525
526 - (void)pressLeftMouseButtonTitlebar:(NSPoint)mouseLocation
527 modifiers:(int)modifierFlags {
528 // Override the drag controller. It's ok to create a new one for each drag.
529 dragController_.reset([[TestDragController alloc] initWithClient:self]);
530 // Convert from Cocoa's screen coordinates to base coordinates since the mouse
531 // event takes base (NSWindow) coordinates.
532 NSPoint mouseLocationWindow = ui::ConvertPointFromScreenToWindow(
533 [self window], mouseLocation);
534 NSEvent* event = MakeMouseEvent(NSLeftMouseDown, mouseLocationWindow,
535 modifierFlags, 0);
536 [self mouseDown:event];
537 }
538
539 - (void)releaseLeftMouseButtonTitlebar:(int)modifierFlags {
540 NSEvent* event = MakeMouseEvent(NSLeftMouseUp, NSZeroPoint, modifierFlags, 1);
541 [self mouseUp:event];
542 }
543
544 - (void)dragTitlebar:(NSPoint)mouseLocation {
545 // Convert from Cocoa's screen coordinates to base coordinates since the mouse
546 // event takes base (NSWindow) coordinates.
547 NSPoint mouseLocationWindow = ui::ConvertPointFromScreenToWindow(
548 [self window], mouseLocation);
549 NSEvent* event =
550 MakeMouseEvent(NSLeftMouseDragged, mouseLocationWindow, 0, 0);
551 [self mouseDragged:event];
552 }
553
554 - (void)cancelDragTitlebar {
555 [self dragEnded:YES];
556 }
557
558 - (void)finishDragTitlebar {
559 [self dragEnded:NO];
560 }
561
562 - (NSButton*)closeButton {
563 return closeButton_;
564 }
565
566 - (NSButton*)minimizeButton {
567 return minimizeButton_;
568 }
569
570 - (NSButton*)restoreButton {
571 return restoreButton_;
572 }
573
574 @end
575
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h ('k') | chrome/browser/ui/cocoa/panels/panel_utils_cocoa.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698