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.
5 #include "athena/wm/overview_toolbar.h"
7 #include "athena/resources/grit/athena_resources.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/time/time.h"
11 #include "ui/aura/window.h"
12 #include "ui/base/resource/resource_bundle.h"
13 #include "ui/compositor/closure_animation_observer.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"
23 const int kActionButtonImageSize
= 54;
24 const int kActionButtonTextSize
= 20;
25 const int kActionButtonPaddingFromRight
= 32;
30 class ActionButton
: public ui::LayerDelegate
{
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);
41 virtual ~ActionButton() {}
43 static void DestroyAfterFadeout(scoped_ptr
<ActionButton
> button
) {
44 ui::Layer
* layer
= button
->layer();
45 ui::ScopedLayerAnimationSettings
settings(layer
->GetAnimator());
46 settings
.AddObserver(new ui::ClosureAnimationObserver(
47 base::Bind(&ActionButton::DestroyImmediately
, base::Passed(&button
))));
51 void SetPosition(const gfx::Point
& position
) {
54 gfx::Size(kActionButtonImageSize
,
55 kActionButtonImageSize
+ kActionButtonTextSize
)));
58 ui::Layer
* layer() { return layer_
.get(); }
61 static void DestroyImmediately(scoped_ptr
<ActionButton
> button
) {
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_
,
76 kActionButtonImageSize
,
77 kActionButtonImageSize
,
78 kActionButtonTextSize
),
80 gfx::Canvas::TEXT_ALIGN_CENTER
,
84 virtual void OnDelegatedFrameDamage(
85 const gfx::Rect
& damage_rect_in_dip
) OVERRIDE
{}
87 virtual void OnDeviceScaleFactorChanged(float device_scale_factor
) OVERRIDE
{}
88 virtual base::Closure
PrepareForLayerBoundsChange() OVERRIDE
{
89 return base::Closure();
93 base::string16 label_
;
94 scoped_ptr
<ui::Layer
> layer_
;
96 DISALLOW_COPY_AND_ASSIGN(ActionButton
);
99 OverviewToolbar::OverviewToolbar(aura::Window
* container
)
101 disabled_action_bitfields_(0),
102 close_(new ActionButton(IDR_ATHENA_OVERVIEW_TRASH
, "Close")),
103 split_(new ActionButton(IDR_ATHENA_OVERVIEW_SPLIT
, "Split")),
104 current_action_(ACTION_TYPE_NONE
),
105 container_bounds_(container
->bounds()) {
106 const int kPaddingFromBottom
= 200;
107 const int kPaddingBetweenButtons
= 200;
109 int x
= container_bounds_
.right() -
110 (kActionButtonPaddingFromRight
+ kActionButtonImageSize
);
111 int y
= container_bounds_
.bottom() -
112 (kPaddingFromBottom
+ kActionButtonImageSize
);
113 split_
->SetPosition(gfx::Point(x
, y
));
114 y
-= kPaddingBetweenButtons
;
115 close_
->SetPosition(gfx::Point(x
, y
));
117 container
->layer()->Add(split_
->layer());
118 container
->layer()->Add(close_
->layer());
121 OverviewToolbar::~OverviewToolbar() {
122 // If the buttons are visible, then fade them out, instead of destroying them
125 ActionButton::DestroyAfterFadeout(split_
.Pass());
126 ActionButton::DestroyAfterFadeout(close_
.Pass());
130 OverviewToolbar::ActionType
OverviewToolbar::GetHighlightAction(
131 const ui::GestureEvent
& event
) const {
132 if (IsActionEnabled(ACTION_TYPE_SPLIT
) &&
133 IsEventOverButton(split_
.get(), event
))
134 return ACTION_TYPE_SPLIT
;
135 if (IsActionEnabled(ACTION_TYPE_CLOSE
) &&
136 IsEventOverButton(close_
.get(), event
))
137 return ACTION_TYPE_CLOSE
;
138 return ACTION_TYPE_NONE
;
141 void OverviewToolbar::SetHighlightAction(ActionType action
) {
142 CHECK(IsActionEnabled(action
));
143 if (current_action_
== action
)
145 current_action_
= action
;
149 TransformButton(close_
.get());
150 TransformButton(split_
.get());
154 void OverviewToolbar::ShowActionButtons() {
156 ToggleActionButtonsVisibility();
159 void OverviewToolbar::HideActionButtons() {
161 ToggleActionButtonsVisibility();
164 void OverviewToolbar::DisableAction(ActionType action
) {
165 CHECK_NE(current_action_
, action
);
166 disabled_action_bitfields_
|= (1u << action
);
169 void OverviewToolbar::ToggleActionButtonsVisibility() {
171 TransformButton(close_
.get());
172 TransformButton(split_
.get());
175 bool OverviewToolbar::IsActionEnabled(ActionType action
) const {
176 return !(disabled_action_bitfields_
& (1u << action
));
179 bool OverviewToolbar::IsEventOverButton(ActionButton
* button
,
180 const ui::GestureEvent
& event
) const {
181 const int kBoundsInsetForTarget
= 30;
182 gfx::RectF bounds
= button
->layer()->bounds();
183 bounds
.Inset(-kBoundsInsetForTarget
, -kBoundsInsetForTarget
);
184 return bounds
.Contains(event
.location());
187 gfx::Transform
OverviewToolbar::ComputeTransformFor(
188 ActionButton
* button
) const {
190 return gfx::Transform();
192 const float kHighlightScale
= 1.5;
193 bool button_is_highlighted
=
194 (current_action_
== ACTION_TYPE_CLOSE
&& button
== close_
.get()) ||
195 (current_action_
== ACTION_TYPE_SPLIT
&& button
== split_
.get());
196 gfx::Transform transform
;
197 if (button_is_highlighted
) {
198 transform
.Translate(-kActionButtonImageSize
* (kHighlightScale
- 1) / 2, 0);
199 transform
.Scale(kHighlightScale
, kHighlightScale
);
204 void OverviewToolbar::TransformButton(ActionButton
* button
) {
205 ui::ScopedLayerAnimationSettings
split_settings(
206 button
->layer()->GetAnimator());
207 split_settings
.SetTweenType(gfx::Tween::SMOOTH_IN_OUT
);
208 button
->layer()->SetTransform(ComputeTransformFor(button
));
209 bool button_is_enabled
=
210 (button
== close_
.get() && IsActionEnabled(ACTION_TYPE_CLOSE
)) ||
211 (button
== split_
.get() && IsActionEnabled(ACTION_TYPE_SPLIT
));
212 button
->layer()->SetOpacity((button_is_enabled
&& shown_
) ? 1 : 0);
215 } // namespace athena