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/common/system/tray/tray_background_view.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ash/common/ash_constants.h" | |
10 #include "ash/common/material_design/material_design_controller.h" | |
11 #include "ash/common/shelf/shelf_constants.h" | |
12 #include "ash/common/shelf/wm_shelf.h" | |
13 #include "ash/common/shelf/wm_shelf_util.h" | |
14 #include "ash/common/system/tray/system_tray.h" | |
15 #include "ash/common/system/tray/tray_constants.h" | |
16 #include "ash/common/system/tray/tray_event_filter.h" | |
17 #include "ash/common/wm_shell.h" | |
18 #include "ash/common/wm_window.h" | |
19 #include "ash/public/cpp/shell_window_ids.h" | |
20 #include "ash/resources/grit/ash_resources.h" | |
21 #include "base/memory/ptr_util.h" | |
22 #include "ui/accessibility/ax_node_data.h" | |
23 #include "ui/base/nine_image_painter_factory.h" | |
24 #include "ui/compositor/layer.h" | |
25 #include "ui/compositor/layer_animation_element.h" | |
26 #include "ui/compositor/scoped_layer_animation_settings.h" | |
27 #include "ui/events/event_constants.h" | |
28 #include "ui/gfx/animation/tween.h" | |
29 #include "ui/gfx/canvas.h" | |
30 #include "ui/gfx/geometry/rect.h" | |
31 #include "ui/gfx/geometry/size.h" | |
32 #include "ui/gfx/image/image_skia.h" | |
33 #include "ui/gfx/image/image_skia_operations.h" | |
34 #include "ui/gfx/nine_image_painter.h" | |
35 #include "ui/gfx/scoped_canvas.h" | |
36 #include "ui/gfx/skia_util.h" | |
37 #include "ui/gfx/transform.h" | |
38 #include "ui/views/animation/flood_fill_ink_drop_ripple.h" | |
39 #include "ui/views/animation/ink_drop_highlight.h" | |
40 #include "ui/views/animation/ink_drop_mask.h" | |
41 #include "ui/views/background.h" | |
42 #include "ui/views/layout/box_layout.h" | |
43 #include "ui/wm/core/window_animations.h" | |
44 | |
45 namespace { | |
46 | |
47 const int kAnimationDurationForPopupMs = 200; | |
48 | |
49 // Duration of opacity animation for visibility changes. | |
50 const int kAnimationDurationForVisibilityMs = 250; | |
51 | |
52 // When becoming visible delay the animation so that StatusAreaWidgetDelegate | |
53 // can animate sibling views out of the position to be occuped by the | |
54 // TrayBackgroundView. | |
55 const int kShowAnimationDelayMs = 100; | |
56 | |
57 // Additional padding used to adjust the user-visible size of status tray | |
58 // and overview button dark background. | |
59 const int kBackgroundAdjustPadding = 3; | |
60 | |
61 // Switches left and right insets if RTL mode is active. | |
62 void MirrorInsetsIfNecessary(gfx::Insets* insets) { | |
63 if (base::i18n::IsRTL()) { | |
64 insets->Set(insets->top(), insets->right(), insets->bottom(), | |
65 insets->left()); | |
66 } | |
67 } | |
68 | |
69 // Returns background insets relative to the contents bounds of the view and | |
70 // mirrored if RTL mode is active. | |
71 gfx::Insets GetMirroredBackgroundInsets(ash::ShelfAlignment shelf_alignment) { | |
72 gfx::Insets insets; | |
73 if (IsHorizontalAlignment(shelf_alignment)) { | |
74 insets.Set(0, ash::kHitRegionPadding, 0, | |
75 ash::kHitRegionPadding + ash::kSeparatorWidth); | |
76 } else { | |
77 insets.Set(ash::kHitRegionPadding, 0, | |
78 ash::kHitRegionPadding + ash::kSeparatorWidth, 0); | |
79 } | |
80 MirrorInsetsIfNecessary(&insets); | |
81 return insets; | |
82 } | |
83 | |
84 } // namespace | |
85 | |
86 using views::TrayBubbleView; | |
87 | |
88 namespace ash { | |
89 | |
90 // static | |
91 const char TrayBackgroundView::kViewClassName[] = "tray/TrayBackgroundView"; | |
92 | |
93 // Used to track when the anchor widget changes position on screen so that the | |
94 // bubble position can be updated. | |
95 class TrayBackgroundView::TrayWidgetObserver : public views::WidgetObserver { | |
96 public: | |
97 explicit TrayWidgetObserver(TrayBackgroundView* host) : host_(host) {} | |
98 | |
99 void OnWidgetBoundsChanged(views::Widget* widget, | |
100 const gfx::Rect& new_bounds) override { | |
101 host_->AnchorUpdated(); | |
102 } | |
103 | |
104 void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override { | |
105 host_->AnchorUpdated(); | |
106 } | |
107 | |
108 private: | |
109 TrayBackgroundView* host_; | |
110 | |
111 DISALLOW_COPY_AND_ASSIGN(TrayWidgetObserver); | |
112 }; | |
113 | |
114 class TrayBackground : public views::Background { | |
115 public: | |
116 TrayBackground(TrayBackgroundView* tray_background_view, bool draws_active) | |
117 : tray_background_view_(tray_background_view), | |
118 draws_active_(draws_active), | |
119 color_(SK_ColorTRANSPARENT) {} | |
120 | |
121 ~TrayBackground() override {} | |
122 | |
123 void set_color(SkColor color) { color_ = color; } | |
124 | |
125 private: | |
126 WmShelf* GetShelf() const { return tray_background_view_->shelf(); } | |
127 | |
128 void PaintMaterial(gfx::Canvas* canvas, views::View* view) const { | |
129 cc::PaintFlags background_flags; | |
130 background_flags.setAntiAlias(true); | |
131 background_flags.setColor(color_); | |
132 gfx::Insets insets = | |
133 GetMirroredBackgroundInsets(GetShelf()->GetAlignment()); | |
134 gfx::Rect bounds = view->GetLocalBounds(); | |
135 bounds.Inset(insets); | |
136 canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, background_flags); | |
137 | |
138 if (draws_active_ && tray_background_view_->is_active()) { | |
139 cc::PaintFlags highlight_flags; | |
140 highlight_flags.setAntiAlias(true); | |
141 highlight_flags.setColor(kShelfButtonActivatedHighlightColor); | |
142 canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, highlight_flags); | |
143 } | |
144 } | |
145 | |
146 void PaintNonMaterial(gfx::Canvas* canvas, views::View* view) const { | |
147 const static int kImageTypeDefault = 0; | |
148 // TODO(estade): leftover type which should be removed along with the rest | |
149 // of pre-MD code. | |
150 // const static int kImageTypeOnBlack = 1; | |
151 const static int kImageTypePressed = 2; | |
152 const static int kNumStates = 3; | |
153 | |
154 const static int kImageHorizontal = 0; | |
155 const static int kImageVertical = 1; | |
156 const static int kNumOrientations = 2; | |
157 | |
158 const int kGridSizeForPainter = 9; | |
159 | |
160 const int kImages[kNumOrientations][kNumStates][kGridSizeForPainter] = { | |
161 { | |
162 // Horizontal | |
163 IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ), | |
164 IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ_ONBLACK), | |
165 IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ_PRESSED), | |
166 }, | |
167 { | |
168 // Vertical | |
169 IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL), | |
170 IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL_ONBLACK), | |
171 IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL_PRESSED), | |
172 }}; | |
173 | |
174 WmShelf* shelf = GetShelf(); | |
175 const int orientation = IsHorizontalAlignment(shelf->GetAlignment()) | |
176 ? kImageHorizontal | |
177 : kImageVertical; | |
178 | |
179 int state = kImageTypeDefault; | |
180 if (draws_active_ && tray_background_view_->is_active()) | |
181 state = kImageTypePressed; | |
182 else | |
183 state = kImageTypeDefault; | |
184 | |
185 ui::CreateNineImagePainter(kImages[orientation][state]) | |
186 ->Paint(canvas, view->GetLocalBounds()); | |
187 } | |
188 | |
189 // Overridden from views::Background. | |
190 void Paint(gfx::Canvas* canvas, views::View* view) const override { | |
191 if (MaterialDesignController::IsShelfMaterial()) | |
192 PaintMaterial(canvas, view); | |
193 else | |
194 PaintNonMaterial(canvas, view); | |
195 } | |
196 | |
197 // Reference to the TrayBackgroundView for which this is a background. | |
198 TrayBackgroundView* tray_background_view_; | |
199 | |
200 // Determines whether we should draw an active background for the view when it | |
201 // is active. This is used in non-MD mode. In material design mode, an active | |
202 // ink drop ripple would indicate if the view is active or not. | |
203 // TODO(mohsen): This is used only in non-MD version. Remove when non-MD code | |
204 // is removed (see https://crbug.com/614453). | |
205 bool draws_active_; | |
206 | |
207 SkColor color_; | |
208 | |
209 DISALLOW_COPY_AND_ASSIGN(TrayBackground); | |
210 }; | |
211 | |
212 TrayBackgroundView::TrayContainer::TrayContainer(ShelfAlignment alignment) | |
213 : alignment_(alignment) { | |
214 UpdateLayout(); | |
215 } | |
216 | |
217 void TrayBackgroundView::TrayContainer::SetAlignment(ShelfAlignment alignment) { | |
218 if (alignment_ == alignment) | |
219 return; | |
220 alignment_ = alignment; | |
221 UpdateLayout(); | |
222 } | |
223 | |
224 void TrayBackgroundView::TrayContainer::SetMargin(int main_axis_margin, | |
225 int cross_axis_margin) { | |
226 main_axis_margin_ = main_axis_margin; | |
227 cross_axis_margin_ = cross_axis_margin; | |
228 UpdateLayout(); | |
229 } | |
230 | |
231 void TrayBackgroundView::TrayContainer::ChildPreferredSizeChanged( | |
232 views::View* child) { | |
233 PreferredSizeChanged(); | |
234 } | |
235 | |
236 void TrayBackgroundView::TrayContainer::ChildVisibilityChanged(View* child) { | |
237 PreferredSizeChanged(); | |
238 } | |
239 | |
240 void TrayBackgroundView::TrayContainer::ViewHierarchyChanged( | |
241 const ViewHierarchyChangedDetails& details) { | |
242 if (details.parent == this) | |
243 PreferredSizeChanged(); | |
244 } | |
245 | |
246 void TrayBackgroundView::TrayContainer::UpdateLayout() { | |
247 bool is_horizontal = IsHorizontalAlignment(alignment_); | |
248 | |
249 // Adjust the size of status tray dark background by adding additional | |
250 // empty border. | |
251 views::BoxLayout::Orientation orientation = | |
252 is_horizontal ? views::BoxLayout::kHorizontal | |
253 : views::BoxLayout::kVertical; | |
254 | |
255 if (ash::MaterialDesignController::IsShelfMaterial()) { | |
256 const int hit_region_with_separator = kHitRegionPadding + kSeparatorWidth; | |
257 gfx::Insets insets( | |
258 is_horizontal | |
259 ? gfx::Insets(0, kHitRegionPadding, 0, hit_region_with_separator) | |
260 : gfx::Insets(kHitRegionPadding, 0, hit_region_with_separator, 0)); | |
261 MirrorInsetsIfNecessary(&insets); | |
262 SetBorder(views::CreateEmptyBorder(insets)); | |
263 } else { | |
264 SetBorder(views::CreateEmptyBorder(gfx::Insets(kBackgroundAdjustPadding))); | |
265 } | |
266 | |
267 int horizontal_margin = main_axis_margin_; | |
268 int vertical_margin = cross_axis_margin_; | |
269 if (!is_horizontal) | |
270 std::swap(horizontal_margin, vertical_margin); | |
271 views::BoxLayout* layout = | |
272 new views::BoxLayout(orientation, horizontal_margin, vertical_margin, 0); | |
273 | |
274 if (!ash::MaterialDesignController::IsShelfMaterial()) | |
275 layout->SetDefaultFlex(1); | |
276 layout->set_minimum_cross_axis_size(kTrayItemSize); | |
277 views::View::SetLayoutManager(layout); | |
278 | |
279 PreferredSizeChanged(); | |
280 } | |
281 | |
282 //////////////////////////////////////////////////////////////////////////////// | |
283 // TrayBackgroundView | |
284 | |
285 TrayBackgroundView::TrayBackgroundView(WmShelf* wm_shelf) | |
286 // Note the ink drop style is ignored. | |
287 : ActionableView(nullptr, TrayPopupInkDropStyle::FILL_BOUNDS), | |
288 wm_shelf_(wm_shelf), | |
289 tray_container_(NULL), | |
290 shelf_alignment_(SHELF_ALIGNMENT_BOTTOM), | |
291 background_(NULL), | |
292 is_active_(false), | |
293 separator_visible_(true), | |
294 widget_observer_(new TrayWidgetObserver(this)) { | |
295 DCHECK(wm_shelf_); | |
296 set_notify_enter_exit_on_child(true); | |
297 set_ink_drop_base_color(kShelfInkDropBaseColor); | |
298 set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); | |
299 | |
300 tray_container_ = new TrayContainer(shelf_alignment_); | |
301 SetContents(tray_container_); | |
302 tray_event_filter_.reset(new TrayEventFilter); | |
303 | |
304 SetPaintToLayer(); | |
305 layer()->SetFillsBoundsOpaquely(false); | |
306 // Start the tray items not visible, because visibility changes are animated. | |
307 views::View::SetVisible(false); | |
308 } | |
309 | |
310 TrayBackgroundView::~TrayBackgroundView() { | |
311 if (GetWidget()) | |
312 GetWidget()->RemoveObserver(widget_observer_.get()); | |
313 StopObservingImplicitAnimations(); | |
314 } | |
315 | |
316 void TrayBackgroundView::Initialize() { | |
317 GetWidget()->AddObserver(widget_observer_.get()); | |
318 } | |
319 | |
320 // static | |
321 void TrayBackgroundView::InitializeBubbleAnimations( | |
322 views::Widget* bubble_widget) { | |
323 WmWindow* window = WmWindow::Get(bubble_widget->GetNativeWindow()); | |
324 window->SetVisibilityAnimationType( | |
325 ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); | |
326 window->SetVisibilityAnimationTransition(::wm::ANIMATE_HIDE); | |
327 window->SetVisibilityAnimationDuration( | |
328 base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMs)); | |
329 } | |
330 | |
331 void TrayBackgroundView::SetVisible(bool visible) { | |
332 if (visible == layer()->GetTargetVisibility()) | |
333 return; | |
334 | |
335 if (visible) { | |
336 // The alignment of the shelf can change while the TrayBackgroundView is | |
337 // hidden. Reset the offscreen transform so that the animation to becoming | |
338 // visible reflects the current layout. | |
339 HideTransformation(); | |
340 // SetVisible(false) is defered until the animation for hiding is done. | |
341 // Otherwise the view is immediately hidden and the animation does not | |
342 // render. | |
343 views::View::SetVisible(true); | |
344 // If SetVisible(true) is called while animating to not visible, then | |
345 // views::View::SetVisible(true) is a no-op. When the previous animation | |
346 // ends layer->SetVisible(false) is called. To prevent this | |
347 // layer->SetVisible(true) immediately interrupts the animation of this | |
348 // property, and keeps the layer visible. | |
349 layer()->SetVisible(true); | |
350 } | |
351 | |
352 ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); | |
353 animation.SetTransitionDuration( | |
354 base::TimeDelta::FromMilliseconds(kAnimationDurationForVisibilityMs)); | |
355 animation.SetPreemptionStrategy( | |
356 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
357 | |
358 if (visible) { | |
359 animation.SetTweenType(gfx::Tween::EASE_OUT); | |
360 // Show is delayed so as to allow time for other children of | |
361 // StatusAreaWidget to begin animating to their new positions. | |
362 layer()->GetAnimator()->SchedulePauseForProperties( | |
363 base::TimeDelta::FromMilliseconds(kShowAnimationDelayMs), | |
364 ui::LayerAnimationElement::OPACITY | | |
365 ui::LayerAnimationElement::TRANSFORM); | |
366 layer()->SetOpacity(1.0f); | |
367 gfx::Transform transform; | |
368 transform.Translate(0.0f, 0.0f); | |
369 layer()->SetTransform(transform); | |
370 } else { | |
371 // Listen only to the hide animation. As we cannot turn off visibility | |
372 // until the animation is over. | |
373 animation.AddObserver(this); | |
374 animation.SetTweenType(gfx::Tween::EASE_IN); | |
375 layer()->SetOpacity(0.0f); | |
376 layer()->SetVisible(false); | |
377 HideTransformation(); | |
378 } | |
379 } | |
380 | |
381 const char* TrayBackgroundView::GetClassName() const { | |
382 return kViewClassName; | |
383 } | |
384 | |
385 void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) { | |
386 PreferredSizeChanged(); | |
387 } | |
388 | |
389 void TrayBackgroundView::GetAccessibleNodeData(ui::AXNodeData* node_data) { | |
390 ActionableView::GetAccessibleNodeData(node_data); | |
391 node_data->SetName(GetAccessibleNameForTray()); | |
392 } | |
393 | |
394 void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) { | |
395 // Return focus to the login view. See crbug.com/120500. | |
396 views::View* v = GetNextFocusableView(); | |
397 if (v) | |
398 v->AboutToRequestFocusFromTabTraversal(reverse); | |
399 } | |
400 | |
401 std::unique_ptr<views::InkDropRipple> TrayBackgroundView::CreateInkDropRipple() | |
402 const { | |
403 return base::MakeUnique<views::FloodFillInkDropRipple>( | |
404 size(), GetBackgroundInsets(), GetInkDropCenterBasedOnLastEvent(), | |
405 GetInkDropBaseColor(), ink_drop_visible_opacity()); | |
406 } | |
407 | |
408 std::unique_ptr<views::InkDropHighlight> | |
409 TrayBackgroundView::CreateInkDropHighlight() const { | |
410 gfx::Rect bounds = GetBackgroundBounds(); | |
411 // Currently, we don't handle view resize. To compensate for that, enlarge the | |
412 // bounds by two tray icons so that the hightlight looks good even if two more | |
413 // icons are added when it is visible. Note that ink drop mask handles resize | |
414 // correctly, so the extra highlight would be clipped. | |
415 // TODO(mohsen): Remove this extra size when resize is handled properly (see | |
416 // https://crbug.com/669253). | |
417 const int icon_size = kTrayIconSize + 2 * kTrayImageItemPadding; | |
418 bounds.set_width(bounds.width() + 2 * icon_size); | |
419 bounds.set_height(bounds.height() + 2 * icon_size); | |
420 std::unique_ptr<views::InkDropHighlight> highlight( | |
421 new views::InkDropHighlight(bounds.size(), 0, | |
422 gfx::RectF(bounds).CenterPoint(), | |
423 GetInkDropBaseColor())); | |
424 highlight->set_visible_opacity(kTrayPopupInkDropHighlightOpacity); | |
425 return highlight; | |
426 } | |
427 | |
428 void TrayBackgroundView::OnGestureEvent(ui::GestureEvent* event) { | |
429 // If there is no ink drop, show "touch feedback". | |
430 // TODO(mohsen): This is used only in non-MD version. Remove when non-MD code | |
431 // is removed (see https://crbug.com/614453). | |
432 if (ink_drop_mode() == InkDropMode::OFF) { | |
433 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { | |
434 SetIsActive(true); | |
435 } else if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || | |
436 event->type() == ui::ET_GESTURE_TAP_CANCEL) { | |
437 SetIsActive(false); | |
438 } | |
439 } | |
440 ActionableView::OnGestureEvent(event); | |
441 } | |
442 | |
443 void TrayBackgroundView::SetContents(views::View* contents) { | |
444 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); | |
445 AddChildView(contents); | |
446 } | |
447 | |
448 void TrayBackgroundView::SetContentsBackground(bool draws_active) { | |
449 background_ = new TrayBackground(this, draws_active); | |
450 tray_container_->set_background(background_); | |
451 } | |
452 | |
453 void TrayBackgroundView::SetShelfAlignment(ShelfAlignment alignment) { | |
454 shelf_alignment_ = alignment; | |
455 tray_container_->SetAlignment(alignment); | |
456 } | |
457 | |
458 void TrayBackgroundView::OnImplicitAnimationsCompleted() { | |
459 // If there is another animation in the queue, the reverse animation was | |
460 // triggered before the completion of animating to invisible. Do not turn off | |
461 // the visibility so that the next animation may render. The value of | |
462 // layer()->GetTargetVisibility() can be incorrect if the hide animation was | |
463 // aborted to schedule an animation to become visible. As the new animation | |
464 // is not yet added to the queue. crbug.com/374236 | |
465 if (layer()->GetAnimator()->is_animating() || layer()->GetTargetVisibility()) | |
466 return; | |
467 views::View::SetVisible(false); | |
468 } | |
469 | |
470 bool TrayBackgroundView::RequiresNotificationWhenAnimatorDestroyed() const { | |
471 // This is needed so that OnImplicitAnimationsCompleted() is called even upon | |
472 // destruction of the animator. This can occure when parallel animations | |
473 // caused by ScreenRotationAnimator end before the animations of | |
474 // TrayBackgroundView. This allows for a proper update to the visual state of | |
475 // the view. (crbug.com/476667) | |
476 return true; | |
477 } | |
478 | |
479 void TrayBackgroundView::HideTransformation() { | |
480 gfx::Transform transform; | |
481 if (IsHorizontalAlignment(shelf_alignment_)) | |
482 transform.Translate(width(), 0.0f); | |
483 else | |
484 transform.Translate(0.0f, height()); | |
485 layer()->SetTransform(transform); | |
486 } | |
487 | |
488 TrayBubbleView::AnchorAlignment TrayBackgroundView::GetAnchorAlignment() const { | |
489 if (shelf_alignment_ == SHELF_ALIGNMENT_LEFT) | |
490 return TrayBubbleView::ANCHOR_ALIGNMENT_LEFT; | |
491 if (shelf_alignment_ == SHELF_ALIGNMENT_RIGHT) | |
492 return TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT; | |
493 return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM; | |
494 } | |
495 | |
496 void TrayBackgroundView::SetIsActive(bool is_active) { | |
497 if (is_active_ == is_active) | |
498 return; | |
499 is_active_ = is_active; | |
500 AnimateInkDrop(is_active_ ? views::InkDropState::ACTIVATED | |
501 : views::InkDropState::DEACTIVATED, | |
502 nullptr); | |
503 if (!background_) | |
504 return; | |
505 // TODO(mohsen): This is needed for non-MD version. Remove when non-MD code is | |
506 // removed (see https://crbug.com/614453). | |
507 SchedulePaint(); | |
508 } | |
509 | |
510 void TrayBackgroundView::UpdateBubbleViewArrow( | |
511 views::TrayBubbleView* bubble_view) { | |
512 // Nothing to do here. | |
513 } | |
514 | |
515 void TrayBackgroundView::UpdateShelfItemBackground(SkColor color) { | |
516 if (background_) { | |
517 background_->set_color(color); | |
518 SchedulePaint(); | |
519 } | |
520 } | |
521 | |
522 views::View* TrayBackgroundView::GetBubbleAnchor() const { | |
523 return tray_container_; | |
524 } | |
525 | |
526 gfx::Insets TrayBackgroundView::GetBubbleAnchorInsets() const { | |
527 gfx::Insets anchor_insets = GetBubbleAnchor()->GetInsets(); | |
528 gfx::Insets tray_bg_insets = GetInsets(); | |
529 if (GetAnchorAlignment() == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) { | |
530 return gfx::Insets(-tray_bg_insets.top(), anchor_insets.left(), | |
531 -tray_bg_insets.bottom(), anchor_insets.right()); | |
532 } else { | |
533 return gfx::Insets(anchor_insets.top(), -tray_bg_insets.left(), | |
534 anchor_insets.bottom(), -tray_bg_insets.right()); | |
535 } | |
536 } | |
537 | |
538 std::unique_ptr<views::InkDropMask> TrayBackgroundView::CreateInkDropMask() | |
539 const { | |
540 return base::MakeUnique<views::RoundRectInkDropMask>( | |
541 size(), GetBackgroundInsets(), kTrayRoundedBorderRadius); | |
542 } | |
543 | |
544 bool TrayBackgroundView::ShouldEnterPushedState(const ui::Event& event) { | |
545 if (is_active_) | |
546 return false; | |
547 | |
548 return ActionableView::ShouldEnterPushedState(event); | |
549 } | |
550 | |
551 bool TrayBackgroundView::PerformAction(const ui::Event& event) { | |
552 return false; | |
553 } | |
554 | |
555 void TrayBackgroundView::HandlePerformActionResult(bool action_performed, | |
556 const ui::Event& event) { | |
557 // When an action is performed, ink drop ripple is handled in SetIsActive(). | |
558 if (action_performed) | |
559 return; | |
560 ActionableView::HandlePerformActionResult(action_performed, event); | |
561 } | |
562 | |
563 void TrayBackgroundView::OnPaintFocus(gfx::Canvas* canvas) { | |
564 // The tray itself expands to the right and bottom edge of the screen to make | |
565 // sure clicking on the edges brings up the popup. However, the focus border | |
566 // should be only around the container. | |
567 gfx::RectF paint_bounds; | |
568 paint_bounds = gfx::RectF(GetBackgroundBounds()); | |
569 paint_bounds.Inset(gfx::Insets(-kFocusBorderThickness)); | |
570 canvas->DrawSolidFocusRect(paint_bounds, kFocusBorderColor, | |
571 kFocusBorderThickness); | |
572 } | |
573 | |
574 void TrayBackgroundView::OnPaint(gfx::Canvas* canvas) { | |
575 ActionableView::OnPaint(canvas); | |
576 if (shelf()->GetBackgroundType() == | |
577 ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT || | |
578 !separator_visible_) { | |
579 return; | |
580 } | |
581 // In the given |canvas|, for a horizontal shelf draw a separator line to the | |
582 // right or left of the TrayBackgroundView when the system is LTR or RTL | |
583 // aligned, respectively. For a vertical shelf draw the separator line | |
584 // underneath the items instead. | |
585 const gfx::Rect local_bounds = GetLocalBounds(); | |
586 const SkColor color = SkColorSetA(SK_ColorWHITE, 0x4D); | |
587 | |
588 if (IsHorizontalAlignment(shelf_alignment_)) { | |
589 const gfx::PointF point( | |
590 base::i18n::IsRTL() ? 0 : (local_bounds.width() - kSeparatorWidth), | |
591 (GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2); | |
592 const gfx::Vector2dF vector(0, kTrayItemSize); | |
593 canvas->Draw1pxLine(point, point + vector, color); | |
594 } else { | |
595 const gfx::PointF point((GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2, | |
596 local_bounds.height() - kSeparatorWidth); | |
597 const gfx::Vector2dF vector(kTrayItemSize, 0); | |
598 canvas->Draw1pxLine(point, point + vector, color); | |
599 } | |
600 } | |
601 | |
602 gfx::Insets TrayBackgroundView::GetBackgroundInsets() const { | |
603 gfx::Insets insets = GetMirroredBackgroundInsets(shelf_alignment_); | |
604 | |
605 // |insets| are relative to contents bounds. Change them to be relative to | |
606 // local bounds. | |
607 gfx::Insets local_contents_insets = | |
608 GetLocalBounds().InsetsFrom(GetContentsBounds()); | |
609 MirrorInsetsIfNecessary(&local_contents_insets); | |
610 insets += local_contents_insets; | |
611 | |
612 return insets; | |
613 } | |
614 | |
615 gfx::Rect TrayBackgroundView::GetBackgroundBounds() const { | |
616 gfx::Insets insets = GetBackgroundInsets(); | |
617 gfx::Rect bounds = GetLocalBounds(); | |
618 bounds.Inset(insets); | |
619 return bounds; | |
620 } | |
621 | |
622 } // namespace ash | |
OLD | NEW |