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

Side by Side Diff: ash/wm/maximize_bubble_controller.cc

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

Powered by Google App Engine
This is Rietveld 408576698