OLD | NEW |
---|---|
(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 #include "ash/wm/maximize_bubble_controller.h" | |
6 | |
7 #include "ash/shell.h" | |
8 #include "ash/shell_window_ids.h" | |
9 #include "ash/wm/window_animations.h" | |
10 #include "ash/wm/workspace/frame_maximize_button.h" | |
11 #include "base/bind.h" | |
12 #include "base/message_loop.h" | |
13 #include "base/timer.h" | |
14 #include "grit/ash_strings.h" | |
15 #include "grit/ui_resources.h" | |
16 #include "ui/aura/event.h" | |
17 #include "ui/aura/focus_manager.h" | |
18 #include "ui/aura/window.h" | |
19 #include "ui/base/l10n/l10n_util.h" | |
20 #include "ui/base/resource/resource_bundle.h" | |
21 #include "ui/gfx/canvas.h" | |
22 #include "ui/gfx/screen.h" | |
23 #include "ui/views/bubble/bubble_delegate.h" | |
24 #include "ui/views/bubble/bubble_frame_view.h" | |
25 #include "ui/views/controls/button/button.h" | |
26 #include "ui/views/controls/button/image_button.h" | |
27 #include "ui/views/controls/label.h" | |
28 #include "ui/views/events/event.h" | |
29 #include "ui/views/layout/box_layout.h" | |
30 #include "ui/views/widget/widget.h" | |
31 | |
32 namespace { | |
33 | |
34 // The spacing between two buttons. | |
35 const int kLayoutSpacing = -1; | |
msw
2012/08/03 19:58:55
Why did this become negative since a previous Patc
| |
36 | |
37 // The background color | |
38 const SkColor kBubbleBackgroundColor = 0xc8141414; | |
39 | |
40 // The text color within the bubble | |
msw
2012/08/03 19:58:55
nit: add a period.
| |
41 const SkColor kBubbleTextColor = SK_ColorWHITE; | |
42 | |
43 // The line width of the bubble. | |
44 const int kLineWidth = 1; | |
45 | |
46 // The pixel dimensions of the arrow. | |
47 const int kArrowHeight = 10; | |
48 const int kArrowWidth = 20; | |
49 | |
50 // The delay of the bubble appearance. | |
51 const int kBubbleAppearanceDelayMS = 200; | |
52 const int kAnimationDurationForPopupMS = 200; | |
53 | |
54 class MaximizeBubbleBorder : public views::BubbleBorder { | |
55 public: | |
56 MaximizeBubbleBorder(views::View* content_view, views::View* anchor); | |
57 | |
58 virtual ~MaximizeBubbleBorder() {} | |
59 | |
60 // Overridden from views::BubbleBorder to match the design specs. | |
61 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, | |
62 const gfx::Size& contents_size) const OVERRIDE; | |
63 | |
64 // Overridden from views::Border | |
65 virtual void Paint(const views::View& view, | |
66 gfx::Canvas* canvas) const OVERRIDE; | |
67 private: | |
68 views::View* anchor_; | |
69 views::View* content_view_; | |
70 | |
71 DISALLOW_COPY_AND_ASSIGN(MaximizeBubbleBorder); | |
72 }; | |
73 | |
74 MaximizeBubbleBorder::MaximizeBubbleBorder(views::View* content_view, | |
75 views::View* anchor) | |
76 : views::BubbleBorder(views::BubbleBorder::TOP_RIGHT, | |
77 views::BubbleBorder::NO_SHADOW), | |
78 anchor_(anchor), | |
79 content_view_(content_view) { | |
80 set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | |
81 } | |
82 | |
83 gfx::Rect MaximizeBubbleBorder::GetBounds( | |
84 const gfx::Rect& position_relative_to, | |
85 const gfx::Size& contents_size) const { | |
86 gfx::Size border_size(contents_size); | |
87 gfx::Insets insets; | |
88 GetInsets(&insets); | |
89 border_size.Enlarge(insets.width(), insets.height()); | |
90 | |
91 // Position the bubble to center the box on the anchor. | |
92 int x = (-border_size.width() + anchor_->width())/2; | |
93 // Position the bubble under the anchor, overlapping the arrow with it. | |
94 int y = anchor_->height() - insets.top(); | |
95 | |
96 gfx::Point view_origin(x, y); | |
97 views::View::ConvertPointToScreen(anchor_, &view_origin); | |
98 | |
99 return gfx::Rect(view_origin, border_size); | |
100 } | |
101 | |
102 void MaximizeBubbleBorder::Paint(const views::View& view, | |
103 gfx::Canvas* canvas) const { | |
104 gfx::Insets inset; | |
105 GetInsets(&inset); | |
106 | |
107 // Draw the border line around everything. | |
108 int y = inset.top(); | |
109 // Top | |
110 canvas->FillRect(gfx::Rect(inset.left(), | |
111 y - kLineWidth, | |
112 content_view_->width(), | |
113 kLineWidth), | |
114 kBubbleBackgroundColor); | |
115 // Bottom | |
116 canvas->FillRect(gfx::Rect(inset.left(), | |
117 y + content_view_->height(), | |
118 content_view_->width(), | |
119 kLineWidth), | |
120 kBubbleBackgroundColor); | |
121 // Left | |
122 canvas->FillRect(gfx::Rect(inset.left() - kLineWidth, | |
123 y - kLineWidth, | |
124 kLineWidth, | |
125 content_view_->height() + 2 * kLineWidth), | |
126 kBubbleBackgroundColor); | |
127 // Right | |
128 canvas->FillRect(gfx::Rect(inset.left() + content_view_->width(), | |
129 y - kLineWidth, | |
130 kLineWidth, | |
131 content_view_->height() + 2 * kLineWidth), | |
132 kBubbleBackgroundColor); | |
133 | |
134 // Draw the arrow afterwards covering the border. | |
135 SkPath path; | |
136 path.incReserve(4); | |
137 // The center of the tip should be in the middle of the button. | |
138 int tip_x = inset.left() + content_view_->width() / 2; | |
139 int left_base_x = tip_x - kArrowWidth / 2; | |
140 int left_base_y = y; | |
141 int tip_y = left_base_y - kArrowHeight; | |
142 path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); | |
143 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); | |
144 path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), | |
145 SkIntToScalar(left_base_y)); | |
146 | |
147 SkPaint paint; | |
148 paint.setStyle(SkPaint::kFill_Style); | |
149 paint.setColor(kBubbleBackgroundColor); | |
150 canvas->DrawPath(path, paint); | |
151 } | |
152 | |
153 } // namespace | |
154 | |
155 namespace ash { | |
156 | |
157 class BubbleContentsButtonRow; | |
158 class BubbleContentsView; | |
159 | |
160 // The image button gets overridden to be able to capture mouse hover events. | |
161 // The constructor also assigns all button states and | |
msw
2012/08/03 19:58:55
nit: "and"...
| |
162 class BubbleDialogButton : public views::ImageButton { | |
163 public: | |
164 explicit BubbleDialogButton( | |
165 BubbleContentsButtonRow* button_row_listener, | |
166 int normal_image, | |
167 int hovered_image, | |
168 int pressed_image); | |
169 virtual ~BubbleDialogButton() {} | |
170 | |
171 // CustomButton overrides: | |
172 virtual void OnMouseCaptureLost() OVERRIDE; | |
173 virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE; | |
174 virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE; | |
175 | |
176 private: | |
177 // The creating class which needs to get notified in case of a hover event. | |
178 BubbleContentsButtonRow* button_row_; | |
179 | |
180 DISALLOW_COPY_AND_ASSIGN(BubbleDialogButton); | |
181 }; | |
182 | |
183 // The class which creates and manages the bubble menu element. | |
184 // It creates a 'bubble border' and the content accordingly. | |
185 // Note: Since the SnapSizer will show animations on top of the maximize button | |
186 // this menu gets created as a separate window and the SnapSizer will be | |
187 // created underneath this window. | |
188 class MaximizeBubbleController::Bubble : public views::BubbleDelegateView { | |
189 public: | |
190 explicit Bubble(MaximizeBubbleController* owner); | |
191 virtual ~Bubble(); | |
192 | |
193 // The window of the menu under which the SnapSizer will get created. | |
194 aura::Window* GetBubbleWindow(); | |
195 | |
196 // Overridden from views::BubbleDelegateView. | |
197 virtual gfx::Rect GetAnchorRect() const OVERRIDE; | |
198 | |
199 // Overridden from View. | |
200 virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE; | |
201 virtual void OnClickedOutsideView() OVERRIDE; | |
202 | |
203 // Overridden from views::View. | |
204 virtual gfx::Size GetPreferredSize() OVERRIDE; | |
205 | |
206 // Overridden from views::Widget::Observer. | |
207 virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE; | |
208 | |
209 // Called from the controller class to indicate that the menu should get | |
210 // destroyed. | |
211 virtual void ControllerRequestsCloseAndDelete(); | |
212 | |
213 // Called from the owning class to change the menu content to the given | |
214 // |snap_type| so that the user knows what is selected. | |
215 void SetSnapType(workspace::SnapType snap_type); | |
216 | |
217 // Get the owning MaximizeBubbleController. This might return NULL in case | |
218 // of an asynchronous shutdown. | |
219 MaximizeBubbleController* controller() const { return owner_; } | |
220 | |
221 private: | |
222 // True if the shut down has been initiated. | |
223 bool shutting_down_; | |
224 | |
225 // Our owning class. | |
226 MaximizeBubbleController* owner_; | |
227 | |
228 // The widget which contains our menu and the bubble border. | |
229 views::Widget* bubble_widget_; | |
230 | |
231 // The content accessor of the menu. | |
232 BubbleContentsView* contents_view_; | |
233 | |
234 DISALLOW_COPY_AND_ASSIGN(Bubble); | |
235 }; | |
236 | |
237 // A class that creates all buttons and put them into a view. | |
238 class BubbleContentsButtonRow | |
239 : public views::View, | |
240 public views::ButtonListener { | |
241 public: | |
242 explicit BubbleContentsButtonRow(MaximizeBubbleController::Bubble* bubble); | |
243 | |
244 virtual ~BubbleContentsButtonRow() {} | |
245 | |
246 // Overridden from ButtonListener. | |
247 virtual void ButtonPressed(views::Button* sender, | |
248 const views::Event& event) OVERRIDE; | |
249 // Called from BubbleDialogButton. | |
250 void ButtonHovered(BubbleDialogButton* sender); | |
251 | |
252 private: | |
253 // The owning object which gets notifications. | |
254 MaximizeBubbleController::Bubble* bubble_; | |
255 | |
256 // The created buttons for our menu. | |
257 BubbleDialogButton* left_button_; | |
258 BubbleDialogButton* minimize_button_; | |
259 BubbleDialogButton* right_button_; | |
260 | |
261 DISALLOW_COPY_AND_ASSIGN(BubbleContentsButtonRow); | |
262 }; | |
263 | |
264 // A class which creates the content of the bubble: The buttons, and the label. | |
265 class BubbleContentsView : public views::View { | |
266 public: | |
267 explicit BubbleContentsView(MaximizeBubbleController::Bubble* bubble); | |
268 | |
269 virtual ~BubbleContentsView() {} | |
270 | |
271 // Set the label content to reflect the currently selected |snap_type|. | |
272 // This function can be executed through the frame maximize button as well as | |
273 // through hover operations. | |
274 void SetSnapType(workspace::SnapType snap_type); | |
275 | |
276 private: | |
277 // The owning class. | |
278 MaximizeBubbleController::Bubble* bubble_; | |
279 | |
280 // The object which owns all the buttons. | |
281 BubbleContentsButtonRow* buttons_view_; | |
282 | |
283 // The label object which shows the user the selected action. | |
284 views::Label* label_view_; | |
285 | |
286 DISALLOW_COPY_AND_ASSIGN(BubbleContentsView); | |
287 }; | |
288 | |
289 BubbleDialogButton::BubbleDialogButton( | |
290 BubbleContentsButtonRow* button_row, | |
291 int normal_image, | |
292 int hovered_image, | |
293 int pressed_image) | |
294 : views::ImageButton(button_row), | |
295 button_row_(button_row) { | |
296 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
297 SetImage(views::CustomButton::BS_NORMAL, rb.GetImageSkiaNamed(normal_image)); | |
298 SetImage(views::CustomButton::BS_HOT, rb.GetImageSkiaNamed(hovered_image)); | |
299 SetImage(views::CustomButton::BS_PUSHED, | |
300 rb.GetImageSkiaNamed(pressed_image)); | |
301 button_row->AddChildView(this); | |
302 } | |
303 | |
304 void BubbleDialogButton::OnMouseCaptureLost() { | |
305 button_row_->ButtonHovered(NULL); | |
306 views::ImageButton::OnMouseCaptureLost(); | |
307 } | |
308 | |
309 void BubbleDialogButton::OnMouseEntered( | |
310 const views::MouseEvent& event) { | |
311 button_row_->ButtonHovered(this); | |
312 views::ImageButton::OnMouseEntered(event); | |
313 } | |
314 | |
315 void BubbleDialogButton::OnMouseExited( | |
316 const views::MouseEvent& event) { | |
317 button_row_->ButtonHovered(NULL); | |
318 views::ImageButton::OnMouseExited(event); | |
319 } | |
320 | |
321 MaximizeBubbleController::Bubble::Bubble(MaximizeBubbleController* owner) | |
322 : views::BubbleDelegateView(owner->frame_maximize_button(), | |
323 views::BubbleBorder::TOP_RIGHT), | |
324 shutting_down_(false), | |
325 owner_(owner), | |
326 bubble_widget_(NULL), | |
327 contents_view_(NULL) { | |
328 set_margins(gfx::Insets()); | |
329 | |
330 // The window needs to be owned by the root so that the SnapSizer does not | |
331 // cover it upon animation. | |
332 aura::Window* parent = Shell::GetContainer( | |
333 Shell::GetActiveRootWindow(), | |
334 internal::kShellWindowId_LauncherContainer); | |
335 set_parent_window(parent); | |
336 | |
337 set_notify_enter_exit_on_child(true); | |
338 set_try_mirroring_arrow(false); | |
339 SetPaintToLayer(true); | |
340 SetFillsBoundsOpaquely(false); | |
341 set_color(kBubbleBackgroundColor); | |
342 set_close_on_deactivate(false); | |
343 set_background( | |
344 views::Background::CreateSolidBackground(kBubbleBackgroundColor)); | |
345 | |
346 SetLayoutManager(new views::BoxLayout( | |
347 views::BoxLayout::kVertical, 0, 0, kLayoutSpacing)); | |
348 | |
349 contents_view_ = new BubbleContentsView(this); | |
350 AddChildView(contents_view_); | |
351 | |
352 // Note that the returned widget has an observer which points to our | |
353 // functions. | |
354 bubble_widget_ = views::BubbleDelegateView::CreateBubble(this); | |
355 | |
356 SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | |
357 bubble_widget_->non_client_view()->frame_view()->set_background(NULL); | |
358 | |
359 MaximizeBubbleBorder* bubble_border = new MaximizeBubbleBorder( | |
360 this, | |
361 anchor_view()); | |
362 GetBubbleFrameView()->SetBubbleBorder(bubble_border); | |
363 GetBubbleFrameView()->set_background(NULL); | |
364 | |
365 // Recalculate size with new border. | |
366 SizeToContents(); | |
367 | |
368 // Setup animation. | |
369 ash::SetWindowVisibilityAnimationType( | |
370 bubble_widget_->GetNativeWindow(), | |
371 ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); | |
372 ash::SetWindowVisibilityAnimationTransition( | |
373 bubble_widget_->GetNativeWindow(), | |
374 ash::ANIMATE_BOTH); | |
375 ash::SetWindowVisibilityAnimationDuration( | |
376 bubble_widget_->GetNativeWindow(), | |
377 base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS)); | |
378 | |
379 Show(); | |
380 // We don't want to lose the focus on our parent window because the button | |
381 // would otherwise lose the highlight when the "helper bubble" is shown. | |
382 views::Widget* widget = | |
383 owner_->frame_maximize_button()->parent()->GetWidget(); | |
384 if (widget) { | |
385 aura::Window* parent_window = widget->GetNativeWindow(); | |
386 parent_window->GetFocusManager()->SetFocusedWindow(parent_window, NULL); | |
387 } | |
388 } | |
389 | |
390 MaximizeBubbleController::Bubble::~Bubble() { | |
391 LOG(ERROR) << "~Bubble"; | |
392 } | |
393 | |
394 aura::Window* MaximizeBubbleController::Bubble::GetBubbleWindow() { | |
395 return bubble_widget_ ? bubble_widget_->GetNativeWindow() : NULL; | |
396 } | |
397 | |
398 gfx::Rect MaximizeBubbleController::Bubble::GetAnchorRect() const OVERRIDE { | |
399 if (!owner_) | |
400 return gfx::Rect(); | |
401 | |
402 gfx::Rect anchor_rect = | |
403 owner_->frame_maximize_button()->GetBoundsInScreen(); | |
404 return anchor_rect; | |
405 } | |
406 | |
407 void MaximizeBubbleController::Bubble::OnMouseExited( | |
408 const views::MouseEvent& event) OVERRIDE { | |
409 if (!owner_ || shutting_down_) | |
410 return; | |
411 // When we leave the bubble, we might be still be in gesture mode or over | |
412 // the maximize button. So only close if none of the other cases apply. | |
413 if (!owner_->frame_maximize_button()->is_snap_enabled()) { | |
414 gfx::Point screen_location = gfx::Screen::GetCursorScreenPoint(); | |
415 if (!owner_->frame_maximize_button()->GetBoundsInScreen().Contains( | |
416 screen_location)) { | |
417 owner_->RequestDestructionThroughOwner(); | |
418 } | |
419 } | |
420 } | |
421 | |
422 void MaximizeBubbleController::Bubble::OnClickedOutsideView() OVERRIDE { | |
423 if (!owner_ || shutting_down_) | |
424 return; | |
425 // Don't destroy the menu when the click happened while the user is | |
426 // performing a dragging operation. | |
427 if (!owner_->frame_maximize_button()->is_snap_enabled()) | |
428 owner_->RequestDestructionThroughOwner(); | |
429 } | |
430 | |
431 gfx::Size MaximizeBubbleController::Bubble::GetPreferredSize() OVERRIDE { | |
432 return contents_view_->GetPreferredSize(); | |
433 } | |
434 | |
435 void MaximizeBubbleController::Bubble::OnWidgetClosing( | |
436 views::Widget* widget) OVERRIDE { | |
437 if (bubble_widget_ != widget) | |
438 return; | |
439 | |
440 if (owner_) { | |
441 // If the bubble destruction was triggered by some other external influence | |
442 // then ourselves, the owner needs to be informed that the menu is gone. | |
443 shutting_down_ = true; | |
444 owner_->RequestDestructionThroughOwner(); | |
445 owner_ = NULL; | |
446 } | |
447 // Remove any existing observers. | |
448 bubble_widget_->RemoveObserver(this); | |
449 anchor_widget()->RemoveObserver(this); | |
450 } | |
451 | |
452 void MaximizeBubbleController::Bubble::ControllerRequestsCloseAndDelete() { | |
453 // This only gets called from the owning base class once it is deleted. | |
454 if (shutting_down_) | |
455 return; | |
456 shutting_down_ = true; | |
457 owner_ = NULL; | |
458 | |
459 // Close the widget asynchronously. | |
460 bubble_widget_->Close(); | |
461 } | |
462 | |
463 void MaximizeBubbleController::Bubble::SetSnapType( | |
464 workspace::SnapType snap_type) { | |
465 if (contents_view_) | |
466 contents_view_->SetSnapType(snap_type); | |
467 } | |
468 | |
469 BubbleContentsButtonRow::BubbleContentsButtonRow( | |
470 MaximizeBubbleController::Bubble* bubble) | |
471 : bubble_(bubble), | |
472 left_button_(NULL), | |
473 minimize_button_(NULL), | |
474 right_button_(NULL) { | |
475 SetLayoutManager(new views::BoxLayout( | |
476 views::BoxLayout::kHorizontal, 0, 0, kLayoutSpacing)); | |
477 set_background( | |
478 views::Background::CreateSolidBackground(kBubbleBackgroundColor)); | |
479 | |
480 left_button_ = new BubbleDialogButton( | |
481 this, | |
482 IDR_AURA_WINDOW_POSITION_LEFT, | |
483 IDR_AURA_WINDOW_POSITION_LEFT_H, | |
484 IDR_AURA_WINDOW_POSITION_LEFT_P); | |
485 minimize_button_ = new BubbleDialogButton( | |
486 this, | |
487 IDR_AURA_WINDOW_POSITION_MIDDLE, | |
488 IDR_AURA_WINDOW_POSITION_MIDDLE_H, | |
489 IDR_AURA_WINDOW_POSITION_MIDDLE_P); | |
490 right_button_ = new BubbleDialogButton( | |
491 this, | |
492 IDR_AURA_WINDOW_POSITION_RIGHT, | |
493 IDR_AURA_WINDOW_POSITION_RIGHT_H, | |
494 IDR_AURA_WINDOW_POSITION_RIGHT_P); | |
495 } | |
496 | |
497 // Overridden from ButtonListener. | |
msw
2012/08/03 19:58:55
nit: move comment to declaration.
| |
498 void BubbleContentsButtonRow::ButtonPressed( | |
499 views::Button* sender, | |
500 const views::Event& event) { | |
501 // While shutting down, the connection to the owner might already be | |
msw
2012/08/03 19:58:55
nit: this comment fits on one line.
| |
502 // broken. | |
503 if (!bubble_->controller()) | |
504 return; | |
505 if (sender == left_button_) | |
506 bubble_->controller()->OnButtonClicked(workspace::SNAP_LEFT); | |
msw
2012/08/03 19:58:55
Please keep terminology consistent, rename the con
| |
507 else if (sender == minimize_button_) | |
508 bubble_->controller()->OnButtonClicked(workspace::SNAP_MINIMIZE); | |
509 else if (sender == right_button_) | |
510 bubble_->controller()->OnButtonClicked(workspace::SNAP_RIGHT); | |
511 else { | |
msw
2012/08/03 19:58:55
Remove the braces or add them to the other blocks
| |
512 NOTREACHED() << "Unknown button pressed."; | |
513 } | |
514 } | |
515 | |
516 // Called from BubbleDialogButton. | |
msw
2012/08/03 19:58:55
nit: move comment to declaration.
| |
517 void BubbleContentsButtonRow::ButtonHovered( | |
msw
2012/08/03 19:58:55
nit: this signature fits on one line.
| |
518 BubbleDialogButton* sender) { | |
519 // While shutting down, the connection to the owner might already be | |
msw
2012/08/03 19:58:55
nit: this comment fits on one line.
| |
520 // broken. | |
521 if (!bubble_->controller()) | |
522 return; | |
523 if (sender == left_button_) | |
524 bubble_->controller()->OnButtonHover(workspace::SNAP_LEFT); | |
525 else if (sender == minimize_button_) | |
526 bubble_->controller()->OnButtonHover(workspace::SNAP_MINIMIZE); | |
527 else if (sender == right_button_) | |
528 bubble_->controller()->OnButtonHover(workspace::SNAP_RIGHT); | |
529 else | |
530 bubble_->controller()->OnButtonHover(workspace::SNAP_NONE); | |
531 } | |
532 | |
533 BubbleContentsView::BubbleContentsView( | |
534 MaximizeBubbleController::Bubble* bubble) | |
535 : bubble_(bubble), | |
536 buttons_view_(NULL), | |
537 label_view_(NULL) { | |
538 SetLayoutManager(new views::BoxLayout( | |
539 views::BoxLayout::kVertical, 0, 0, kLayoutSpacing)); | |
540 set_background( | |
541 views::Background::CreateSolidBackground(kBubbleBackgroundColor)); | |
542 | |
543 buttons_view_ = new BubbleContentsButtonRow(bubble); | |
544 AddChildView(buttons_view_); | |
545 | |
546 label_view_ = new views::Label(); | |
547 SetSnapType(workspace::SNAP_NONE); | |
548 label_view_->SetHorizontalAlignment(views::Label::ALIGN_CENTER); | |
549 label_view_->SetBackgroundColor(kBubbleBackgroundColor); | |
550 label_view_->SetEnabledColor(kBubbleTextColor); | |
551 AddChildView(label_view_); | |
552 } | |
553 | |
554 // Set the label content to reflect the currently selected |snap_type|. | |
555 // This function can be executed through the frame maximize button as well as | |
556 // through hover operations. | |
557 void BubbleContentsView::SetSnapType( | |
558 workspace::SnapType snap_type) { | |
559 if (!bubble_->controller()) | |
560 return; | |
561 | |
562 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
563 switch (snap_type) { | |
564 case workspace::SNAP_LEFT: | |
565 label_view_->SetText(rb.GetLocalizedString(IDS_ASH_SNAP_WINDOW_LEFT)); | |
566 return; | |
msw
2012/08/03 19:58:55
nit: break instead of return here and below.
| |
567 case workspace::SNAP_RIGHT: | |
568 label_view_->SetText(rb.GetLocalizedString(IDS_ASH_SNAP_WINDOW_RIGHT)); | |
569 return; | |
570 case workspace::SNAP_MAXIMIZE: | |
571 DCHECK(!bubble_->controller()->is_maximized()); | |
572 label_view_->SetText(rb.GetLocalizedString(IDS_ASH_MAXIMIZE_WINDOW)); | |
573 return; | |
574 case workspace::SNAP_MINIMIZE: | |
575 label_view_->SetText(rb.GetLocalizedString(IDS_ASH_MINIMIZE_WINDOW)); | |
576 return; | |
577 case workspace::SNAP_RESTORE: | |
578 DCHECK(bubble_->controller()->is_maximized()); | |
579 label_view_->SetText(rb.GetLocalizedString(IDS_ASH_RESTORE_WINDOW)); | |
580 return; | |
581 default: | |
582 // If nothing is selected, we automatically select the click operation. | |
583 label_view_->SetText(rb.GetLocalizedString( | |
584 bubble_->controller()->is_maximized() ? IDS_ASH_RESTORE_WINDOW : | |
585 IDS_ASH_MAXIMIZE_WINDOW)); | |
586 return; | |
587 } | |
588 } | |
589 | |
590 MaximizeBubbleController::MaximizeBubbleController( | |
591 FrameMaximizeButton* frame_maximize_button, | |
592 bool is_maximized) | |
593 : frame_maximize_button_(frame_maximize_button), | |
594 bubble_(NULL), | |
595 is_maximized_(is_maximized) { | |
596 // Create the task which will create the bubble delayed. | |
597 base::OneShotTimer<MaximizeBubbleController>* new_timer = | |
598 new base::OneShotTimer<MaximizeBubbleController>(); | |
599 new_timer->Start( | |
600 FROM_HERE, | |
601 base::TimeDelta::FromMilliseconds(kBubbleAppearanceDelayMS), | |
602 this, | |
603 &MaximizeBubbleController::CreateBubble); | |
604 timer_.reset(new_timer); | |
605 } | |
606 | |
607 MaximizeBubbleController::~MaximizeBubbleController() { | |
608 // Note: The destructor only gets initiated through the owner. | |
609 timer_.reset(NULL); | |
610 if (bubble_) { | |
611 bubble_->ControllerRequestsCloseAndDelete(); | |
612 bubble_ = NULL; | |
613 } | |
614 } | |
615 | |
616 void MaximizeBubbleController::SetSnapType(workspace::SnapType snap_type) { | |
617 if (bubble_) | |
618 bubble_->SetSnapType(snap_type); | |
619 } | |
620 | |
621 aura::Window* MaximizeBubbleController::GetBubbleWindow() { | |
622 return bubble_ ? bubble_->GetBubbleWindow() : NULL; | |
623 } | |
624 | |
625 void MaximizeBubbleController::DelayCreation() { | |
626 if (timer_.get() && timer_->IsRunning()) | |
627 timer_->Reset(); | |
628 } | |
629 | |
630 void MaximizeBubbleController::OnButtonClicked(workspace::SnapType snap_type) { | |
631 frame_maximize_button_->ExecuteSnapAndCloseMenu(snap_type); | |
632 } | |
633 | |
634 void MaximizeBubbleController::OnButtonHover( | |
635 workspace::SnapType snap_type) { | |
636 frame_maximize_button_->SnapButtonHovered(snap_type); | |
637 } | |
638 | |
639 void MaximizeBubbleController::RequestDestructionThroughOwner() { | |
640 // Tell the parent to destroy us (if this didn't happen yet). | |
641 if (timer_.get()) { | |
642 timer_.reset(NULL); | |
643 // Informs the owner that the menu is gone and requests |this| destruction. | |
644 frame_maximize_button_->DestroyMaximizeMenu(); | |
645 // Note: After this call |this| is destroyed. | |
646 } | |
647 } | |
648 | |
649 void MaximizeBubbleController::CreateBubble() { | |
650 if (!bubble_) | |
651 bubble_ = new Bubble(this); | |
652 | |
653 timer_->Stop(); | |
654 } | |
655 | |
656 } // namespace ash | |
OLD | NEW |