OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 "athena/wm/overview_toolbar.h" | |
6 | |
7 #include "athena/common/closure_animation_observer.h" | |
8 #include "base/bind.h" | |
9 #include "base/strings/utf_string_conversions.h" | |
10 #include "base/time/time.h" | |
11 #include "grit/athena_resources.h" | |
12 #include "ui/aura/window.h" | |
13 #include "ui/base/resource/resource_bundle.h" | |
14 #include "ui/compositor/layer.h" | |
15 #include "ui/compositor/layer_delegate.h" | |
16 #include "ui/compositor/scoped_layer_animation_settings.h" | |
17 #include "ui/events/event.h" | |
18 #include "ui/gfx/canvas.h" | |
19 #include "ui/gfx/transform.h" | |
20 | |
21 namespace { | |
22 | |
23 const int kActionButtonImageSize = 54; | |
24 const int kActionButtonTextSize = 20; | |
25 const int kActionButtonPaddingFromRight = 32; | |
26 } | |
27 | |
28 namespace athena { | |
29 | |
30 class ActionButton : public ui::LayerDelegate { | |
Jun Mukai
2014/08/13 17:00:23
got confused, why this is a layer delegate rather
sadrul
2014/08/13 19:25:29
Pretty much, yeah. I considered making this a view
| |
31 public: | |
32 ActionButton(int resource_id, const std::string& label) | |
33 : resource_id_(resource_id), label_(base::UTF8ToUTF16(label)) { | |
34 layer_.reset(new ui::Layer(ui::LAYER_TEXTURED)); | |
35 layer_->set_delegate(this); | |
36 layer_->SetFillsBoundsOpaquely(false); | |
37 layer_->SetVisible(true); | |
38 layer_->SetOpacity(0); | |
39 } | |
40 | |
41 virtual ~ActionButton() {} | |
42 | |
43 static void DestroyAfterFadeout(scoped_ptr<ActionButton> button) { | |
44 ui::Layer* layer = button->layer(); | |
45 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); | |
46 settings.AddObserver(new ClosureAnimationObserver( | |
47 base::Bind(&ActionButton::DestroyImmediately, base::Passed(&button)))); | |
48 layer->SetOpacity(0); | |
49 } | |
50 | |
51 void SetPosition(const gfx::Point& position) { | |
52 layer_->SetBounds( | |
53 gfx::Rect(position, | |
54 gfx::Size(kActionButtonImageSize, | |
55 kActionButtonImageSize + kActionButtonTextSize))); | |
56 } | |
57 | |
58 ui::Layer* layer() { return layer_.get(); } | |
59 | |
60 private: | |
61 static void DestroyImmediately(scoped_ptr<ActionButton> button) { | |
62 button.reset(); | |
63 } | |
64 | |
65 // ui::LayerDelegate: | |
66 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { | |
67 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | |
68 canvas->DrawImageInt(*bundle.GetImageSkiaNamed(resource_id_), 0, 0); | |
69 gfx::ShadowValues shadow; | |
70 shadow.push_back(gfx::ShadowValue(gfx::Point(0, 1), 2, SK_ColorBLACK)); | |
71 shadow.push_back(gfx::ShadowValue(gfx::Point(0, -1), 2, SK_ColorBLACK)); | |
72 canvas->DrawStringRectWithShadows(label_, | |
73 gfx::FontList(), | |
74 SK_ColorWHITE, | |
75 gfx::Rect(0, | |
76 kActionButtonImageSize, | |
77 kActionButtonImageSize, | |
78 kActionButtonTextSize), | |
79 0, | |
80 gfx::Canvas::TEXT_ALIGN_CENTER, | |
81 shadow); | |
82 } | |
83 | |
84 virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {} | |
85 virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE { | |
86 return base::Closure(); | |
87 } | |
88 | |
89 int resource_id_; | |
90 base::string16 label_; | |
91 scoped_ptr<ui::Layer> layer_; | |
92 | |
93 DISALLOW_COPY_AND_ASSIGN(ActionButton); | |
94 }; | |
95 | |
96 OverviewToolbar::OverviewToolbar(aura::Window* container) | |
97 : shown_(false), | |
98 close_(new ActionButton(IDR_ATHENA_OVERVIEW_TRASH, "Close")), | |
99 split_(new ActionButton(IDR_ATHENA_OVERVIEW_SPLIT, "Split")), | |
100 current_action_(ACTION_TYPE_NONE), | |
101 container_bounds_(container->bounds()) { | |
102 const int kPaddingFromBottom = 200; | |
103 const int kPaddingBetweenButtons = 200; | |
104 | |
105 int x = container_bounds_.right() - | |
106 (kActionButtonPaddingFromRight + kActionButtonImageSize); | |
107 int y = container_bounds_.bottom() - | |
108 (kPaddingFromBottom + kActionButtonImageSize); | |
109 split_->SetPosition(gfx::Point(x, y)); | |
110 y -= kPaddingBetweenButtons; | |
111 close_->SetPosition(gfx::Point(x, y)); | |
112 | |
113 container->layer()->Add(split_->layer()); | |
114 container->layer()->Add(close_->layer()); | |
115 } | |
116 | |
117 OverviewToolbar::~OverviewToolbar() { | |
118 // If the buttons are visible, then fade them out, instead of destroying them | |
119 // immediately. | |
120 if (shown_) { | |
121 ActionButton::DestroyAfterFadeout(split_.Pass()); | |
122 ActionButton::DestroyAfterFadeout(close_.Pass()); | |
123 } | |
124 } | |
125 | |
126 OverviewToolbar::ActionType OverviewToolbar::GetHighlightAction( | |
127 const ui::GestureEvent& event) const { | |
128 if (IsEventOverButton(split_.get(), event)) | |
129 return ACTION_TYPE_SPLIT; | |
130 if (IsEventOverButton(close_.get(), event)) | |
131 return ACTION_TYPE_CLOSE; | |
132 return ACTION_TYPE_NONE; | |
133 } | |
134 | |
135 void OverviewToolbar::SetHighlightAction(ActionType action) { | |
136 if (current_action_ == action) | |
137 return; | |
138 current_action_ = action; | |
139 if (!shown_) { | |
140 ShowActionButtons(); | |
141 } else { | |
142 TransformButton(close_.get()); | |
143 TransformButton(split_.get()); | |
144 } | |
145 } | |
146 | |
147 void OverviewToolbar::ShowActionButtons() { | |
148 if (!shown_) | |
149 ToggleActionButtonsVisibility(); | |
150 } | |
151 | |
152 void OverviewToolbar::HideActionButtons() { | |
153 if (shown_) | |
154 ToggleActionButtonsVisibility(); | |
155 } | |
156 | |
157 void OverviewToolbar::ToggleActionButtonsVisibility() { | |
158 shown_ = !shown_; | |
159 TransformButton(close_.get()); | |
160 TransformButton(split_.get()); | |
161 } | |
162 | |
163 bool OverviewToolbar::IsEventOverButton(ActionButton* button, | |
164 const ui::GestureEvent& event) const { | |
165 const int kBoundsInsetForTarget = 30; | |
166 gfx::RectF bounds = button->layer()->bounds(); | |
167 bounds.Inset(-kBoundsInsetForTarget, -kBoundsInsetForTarget); | |
168 return bounds.Contains(event.location()); | |
169 } | |
170 | |
171 gfx::Transform OverviewToolbar::ComputeTransformFor( | |
172 ActionButton* button) const { | |
173 if (!shown_) | |
174 return gfx::Transform(); | |
175 | |
176 const float kHighlightScale = 1.5; | |
177 bool button_is_highlighted = | |
178 (current_action_ == ACTION_TYPE_CLOSE && button == close_.get()) || | |
179 (current_action_ == ACTION_TYPE_SPLIT && button == split_.get()); | |
180 gfx::Transform transform; | |
181 if (button_is_highlighted) { | |
182 transform.Translate(-kActionButtonImageSize * (kHighlightScale - 1) / 2, 0); | |
183 transform.Scale(kHighlightScale, kHighlightScale); | |
184 } | |
185 return transform; | |
186 } | |
187 | |
188 void OverviewToolbar::TransformButton(ActionButton* button) { | |
189 ui::ScopedLayerAnimationSettings split_settings( | |
190 button->layer()->GetAnimator()); | |
191 split_settings.SetTweenType(gfx::Tween::SMOOTH_IN_OUT); | |
192 button->layer()->SetTransform(ComputeTransformFor(button)); | |
193 button->layer()->SetOpacity(shown_ ? 1 : 0); | |
194 } | |
195 | |
196 } // namespace athena | |
OLD | NEW |