Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ash / sticky_keys / sticky_keys_overlay.cc
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 "ash/sticky_keys/sticky_keys_overlay.h"
6
7 #include "ash/shell.h"
8 #include "ash/shell_window_ids.h"
9 #include "ash/sticky_keys/sticky_keys_controller.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "grit/ash_strings.h"
13 #include "ui/base/l10n/l10n_util.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/compositor/scoped_layer_animation_settings.h"
16 #include "ui/gfx/canvas.h"
17 #include "ui/gfx/font_list.h"
18 #include "ui/views/border.h"
19 #include "ui/views/controls/label.h"
20 #include "ui/views/layout/box_layout.h"
21 #include "ui/views/view.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/widget/widget_delegate.h"
24
25 namespace ash {
26
27 namespace {
28
29 // Horizontal offset of the overlay from the top left of the screen.
30 const int kHorizontalOverlayOffset = 18;
31
32 // Vertical offset of the overlay from the top left of the screen.
33 const int kVerticalOverlayOffset = 18;
34
35 // Font style used for modifier key labels.
36 const ui::ResourceBundle::FontStyle kKeyLabelFontStyle =
37     ui::ResourceBundle::LargeFont;
38
39 // Duration of slide animation when overlay is shown or hidden.
40 const int kSlideAnimationDurationMs = 100;
41
42 }
43
44 ///////////////////////////////////////////////////////////////////////////////
45 //  StickyKeyOverlayLabel
46 class StickyKeyOverlayLabel : public views::Label {
47  public:
48   explicit StickyKeyOverlayLabel(const std::string& key_name);
49
50   virtual ~StickyKeyOverlayLabel();
51
52   StickyKeyState state() const { return state_; }
53
54   void SetKeyState(StickyKeyState state);
55
56  private:
57   // views::Label overrides:
58   virtual void PaintText(gfx::Canvas* canvas,
59                          const base::string16& text,
60                          const gfx::Rect& text_bounds,
61                          int flags) OVERRIDE;
62
63   StickyKeyState state_;
64
65   DISALLOW_COPY_AND_ASSIGN(StickyKeyOverlayLabel);
66 };
67
68 StickyKeyOverlayLabel::StickyKeyOverlayLabel(const std::string& key_name)
69     : state_(STICKY_KEY_STATE_DISABLED) {
70   ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
71
72   SetText(base::UTF8ToUTF16(key_name));
73   SetHorizontalAlignment(gfx::ALIGN_LEFT);
74   SetFontList(rb->GetFontList(kKeyLabelFontStyle));
75   SetAutoColorReadabilityEnabled(false);
76   SetFocusable(false);
77   SetEnabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF));
78   SetDisabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF));
79 }
80
81 StickyKeyOverlayLabel::~StickyKeyOverlayLabel() {
82 }
83
84 void StickyKeyOverlayLabel::SetKeyState(StickyKeyState state) {
85   state_ = state;
86   SkColor label_color;
87   int style;
88   switch (state) {
89     case STICKY_KEY_STATE_ENABLED:
90       style = gfx::Font::NORMAL;
91       label_color = SkColorSetA(enabled_color(), 0xFF);
92       break;
93     case STICKY_KEY_STATE_LOCKED:
94       style = gfx::Font::UNDERLINE;
95       label_color = SkColorSetA(enabled_color(), 0xFF);
96       break;
97     default:
98       style = gfx::Font::NORMAL;
99       label_color = SkColorSetA(enabled_color(), 0x80);
100   }
101
102   SetEnabledColor(label_color);
103   SetDisabledColor(label_color);
104   SetFontList(font_list().DeriveWithStyle(style));
105 }
106
107 void StickyKeyOverlayLabel::PaintText(gfx::Canvas* canvas,
108                                       const base::string16& text,
109                                       const gfx::Rect& text_bounds,
110                                       int flags) {
111   views::Label::PaintText(canvas,
112                           text,
113                           text_bounds,
114                           flags | gfx::Canvas::NO_SUBPIXEL_RENDERING);
115 }
116
117
118 ///////////////////////////////////////////////////////////////////////////////
119 //  StickyKeyOverlayLabel
120 class StickyKeysOverlayView : public views::WidgetDelegateView {
121  public:
122   StickyKeysOverlayView();
123
124   virtual ~StickyKeysOverlayView();
125
126   // views::WidgetDelegateView overrides:
127   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
128
129   void SetKeyState(ui::EventFlags modifier, StickyKeyState state);
130
131   StickyKeyState GetKeyState(ui::EventFlags modifier);
132
133   void SetModifierVisible(ui::EventFlags modifier, bool visible);
134   bool GetModifierVisible(ui::EventFlags modifier);
135
136  private:
137   void AddKeyLabel(ui::EventFlags modifier, const std::string& key_label);
138
139   typedef std::map<ui::EventFlags, StickyKeyOverlayLabel*> ModifierLabelMap;
140   ModifierLabelMap modifier_label_map_;
141
142   DISALLOW_COPY_AND_ASSIGN(StickyKeysOverlayView);
143 };
144
145 StickyKeysOverlayView::StickyKeysOverlayView() {
146   const gfx::Font& font =
147       ui::ResourceBundle::GetSharedInstance().GetFont(kKeyLabelFontStyle);
148   int font_size = font.GetFontSize();
149   int font_padding = font.GetHeight() - font.GetBaseline();
150
151   // Text should have a margin of 0.5 times the font size on each side, so
152   // the spacing between two labels will be the same as the font size.
153   int horizontal_spacing = font_size / 2;
154   int vertical_spacing = font_size / 2 - font_padding;
155   int child_spacing = font_size - 2 * font_padding;
156
157   SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
158                                         horizontal_spacing,
159                                         vertical_spacing,
160                                         child_spacing));
161   AddKeyLabel(ui::EF_CONTROL_DOWN,
162               l10n_util::GetStringUTF8(IDS_ASH_CONTROL_KEY));
163   AddKeyLabel(ui::EF_ALT_DOWN,
164               l10n_util::GetStringUTF8(IDS_ASH_ALT_KEY));
165   AddKeyLabel(ui::EF_SHIFT_DOWN,
166               l10n_util::GetStringUTF8(IDS_ASH_SHIFT_KEY));
167   AddKeyLabel(ui::EF_ALTGR_DOWN,
168               l10n_util::GetStringUTF8(IDS_ASH_ALTGR_KEY));
169   AddKeyLabel(ui::EF_MOD3_DOWN,
170               l10n_util::GetStringUTF8(IDS_ASH_MOD3_KEY));
171 }
172
173 StickyKeysOverlayView::~StickyKeysOverlayView() {}
174
175 void StickyKeysOverlayView::OnPaint(gfx::Canvas* canvas) {
176   SkPaint paint;
177   paint.setStyle(SkPaint::kFill_Style);
178   paint.setColor(SkColorSetARGB(0xB3, 0x55, 0x55, 0x55));
179   canvas->DrawRoundRect(GetLocalBounds(), 2, paint);
180   views::WidgetDelegateView::OnPaint(canvas);
181 }
182
183 void StickyKeysOverlayView::SetKeyState(ui::EventFlags modifier,
184                                         StickyKeyState state) {
185   ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
186   DCHECK(it != modifier_label_map_.end());
187   if (it != modifier_label_map_.end()) {
188     StickyKeyOverlayLabel* label = it->second;
189     label->SetKeyState(state);
190   }
191 }
192
193 StickyKeyState StickyKeysOverlayView::GetKeyState(ui::EventFlags modifier) {
194   ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
195   DCHECK(it != modifier_label_map_.end());
196   return it->second->state();
197 }
198
199 void StickyKeysOverlayView::SetModifierVisible(ui::EventFlags modifier,
200                                                bool visible) {
201   ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
202   DCHECK(it != modifier_label_map_.end());
203   it->second->SetVisible(visible);
204 }
205
206 bool StickyKeysOverlayView::GetModifierVisible(ui::EventFlags modifier) {
207   ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
208   DCHECK(it != modifier_label_map_.end());
209   return it->second->visible();
210 }
211
212 void StickyKeysOverlayView::AddKeyLabel(ui::EventFlags modifier,
213                                         const std::string& key_label) {
214   StickyKeyOverlayLabel* label = new StickyKeyOverlayLabel(key_label);
215   AddChildView(label);
216   modifier_label_map_[modifier] = label;
217 }
218
219 ///////////////////////////////////////////////////////////////////////////////
220 //  StickyKeysOverlay
221 StickyKeysOverlay::StickyKeysOverlay()
222     : is_visible_(false),
223       overlay_view_(new StickyKeysOverlayView),
224       widget_size_(overlay_view_->GetPreferredSize()) {
225   views::Widget::InitParams params;
226   params.type = views::Widget::InitParams::TYPE_POPUP;
227   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
228   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
229   params.accept_events = false;
230   params.can_activate = false;
231   params.keep_on_top = true;
232   params.remove_standard_frame = true;
233   params.delegate = overlay_view_;
234   params.bounds = CalculateOverlayBounds();
235   params.parent = Shell::GetContainer(Shell::GetTargetRootWindow(),
236                                       kShellWindowId_OverlayContainer);
237   overlay_widget_.reset(new views::Widget);
238   overlay_widget_->Init(params);
239   overlay_widget_->SetVisibilityChangedAnimationsEnabled(false);
240   overlay_widget_->SetContentsView(overlay_view_);
241   overlay_widget_->GetNativeView()->SetName("StickyKeysOverlay");
242 }
243
244 StickyKeysOverlay::~StickyKeysOverlay() {}
245
246 void StickyKeysOverlay::Show(bool visible) {
247   if (is_visible_ == visible)
248     return;
249
250   is_visible_ = visible;
251   if (is_visible_)
252     overlay_widget_->Show();
253   overlay_widget_->SetBounds(CalculateOverlayBounds());
254
255   ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
256   animator->AddObserver(this);
257
258   // Ensure transform is correct before beginning animation.
259   if (!animator->is_animating()) {
260     int sign = is_visible_ ? -1 : 1;
261     gfx::Transform transform;
262     transform.Translate(
263         sign * (widget_size_.width() + kHorizontalOverlayOffset), 0);
264     overlay_widget_->GetLayer()->SetTransform(transform);
265   }
266
267   ui::ScopedLayerAnimationSettings settings(animator);
268   settings.SetPreemptionStrategy(
269       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
270   settings.SetTweenType(visible ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN);
271   settings.SetTransitionDuration(
272       base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs));
273
274   overlay_widget_->GetLayer()->SetTransform(gfx::Transform());
275 }
276
277 void StickyKeysOverlay::SetModifierVisible(ui::EventFlags modifier,
278                                            bool visible) {
279   overlay_view_->SetModifierVisible(modifier, visible);
280   widget_size_ = overlay_view_->GetPreferredSize();
281 }
282
283 bool StickyKeysOverlay::GetModifierVisible(ui::EventFlags modifier) {
284   return overlay_view_->GetModifierVisible(modifier);
285 }
286
287 void StickyKeysOverlay::SetModifierKeyState(ui::EventFlags modifier,
288                                             StickyKeyState state) {
289   overlay_view_->SetKeyState(modifier, state);
290 }
291
292 StickyKeyState StickyKeysOverlay::GetModifierKeyState(
293     ui::EventFlags modifier) {
294   return overlay_view_->GetKeyState(modifier);
295 }
296
297 gfx::Rect StickyKeysOverlay::CalculateOverlayBounds() {
298   int x = is_visible_ ? kHorizontalOverlayOffset : -widget_size_.width();
299   return gfx::Rect(gfx::Point(x, kVerticalOverlayOffset), widget_size_);
300 }
301
302 void StickyKeysOverlay::OnLayerAnimationEnded(
303     ui::LayerAnimationSequence* sequence) {
304   ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
305   if (animator)
306     animator->RemoveObserver(this);
307   if (!is_visible_)
308     overlay_widget_->Hide();
309 }
310
311 void StickyKeysOverlay::OnLayerAnimationAborted(
312     ui::LayerAnimationSequence* sequence) {
313   ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
314   if (animator)
315     animator->RemoveObserver(this);
316 }
317
318 void StickyKeysOverlay::OnLayerAnimationScheduled(
319     ui::LayerAnimationSequence* sequence) {
320 }
321
322 }  // namespace ash