Add unit test for the Settings API Bubble.
[chromium-blink-merge.git] / ash / sticky_keys / sticky_keys_overlay.cc
blobe91caf4ab8753a552014bf697d947a4de0fbe240
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 "ash/sticky_keys/sticky_keys_overlay.h"
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"
25 namespace ash {
27 namespace {
29 // Horizontal offset of the overlay from the top left of the screen.
30 const int kHorizontalOverlayOffset = 18;
32 // Vertical offset of the overlay from the top left of the screen.
33 const int kVerticalOverlayOffset = 18;
35 // Font style used for modifier key labels.
36 const ui::ResourceBundle::FontStyle kKeyLabelFontStyle =
37 ui::ResourceBundle::LargeFont;
39 // Duration of slide animation when overlay is shown or hidden.
40 const int kSlideAnimationDurationMs = 100;
44 ///////////////////////////////////////////////////////////////////////////////
45 // StickyKeyOverlayLabel
46 class StickyKeyOverlayLabel : public views::Label {
47 public:
48 explicit StickyKeyOverlayLabel(const std::string& key_name);
50 virtual ~StickyKeyOverlayLabel();
52 StickyKeyState state() const { return state_; }
54 void SetKeyState(StickyKeyState state);
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;
63 StickyKeyState state_;
65 DISALLOW_COPY_AND_ASSIGN(StickyKeyOverlayLabel);
68 StickyKeyOverlayLabel::StickyKeyOverlayLabel(const std::string& key_name)
69 : state_(STICKY_KEY_STATE_DISABLED) {
70 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
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));
81 StickyKeyOverlayLabel::~StickyKeyOverlayLabel() {
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);
102 SetEnabledColor(label_color);
103 SetDisabledColor(label_color);
104 SetFontList(font_list().DeriveWithStyle(style));
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);
118 ///////////////////////////////////////////////////////////////////////////////
119 // StickyKeyOverlayLabel
120 class StickyKeysOverlayView : public views::WidgetDelegateView {
121 public:
122 StickyKeysOverlayView();
124 virtual ~StickyKeysOverlayView();
126 // views::WidgetDelegateView overrides:
127 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
129 void SetKeyState(ui::EventFlags modifier, StickyKeyState state);
131 StickyKeyState GetKeyState(ui::EventFlags modifier);
133 void SetModifierVisible(ui::EventFlags modifier, bool visible);
135 private:
136 void AddKeyLabel(ui::EventFlags modifier, const std::string& key_label);
138 typedef std::map<ui::EventFlags, StickyKeyOverlayLabel*> ModifierLabelMap;
139 ModifierLabelMap modifier_label_map_;
141 DISALLOW_COPY_AND_ASSIGN(StickyKeysOverlayView);
144 StickyKeysOverlayView::StickyKeysOverlayView() {
145 const gfx::Font& font =
146 ui::ResourceBundle::GetSharedInstance().GetFont(kKeyLabelFontStyle);
147 int font_size = font.GetFontSize();
148 int font_padding = font.GetHeight() - font.GetBaseline();
150 // Text should have a margin of 0.5 times the font size on each side, so
151 // the spacing between two labels will be the same as the font size.
152 int horizontal_spacing = font_size / 2;
153 int vertical_spacing = font_size / 2 - font_padding;
154 int child_spacing = font_size - 2 * font_padding;
156 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
157 horizontal_spacing,
158 vertical_spacing,
159 child_spacing));
160 AddKeyLabel(ui::EF_CONTROL_DOWN,
161 l10n_util::GetStringUTF8(IDS_ASH_CONTROL_KEY));
162 AddKeyLabel(ui::EF_ALT_DOWN,
163 l10n_util::GetStringUTF8(IDS_ASH_ALT_KEY));
164 AddKeyLabel(ui::EF_SHIFT_DOWN,
165 l10n_util::GetStringUTF8(IDS_ASH_SHIFT_KEY));
166 AddKeyLabel(ui::EF_ALTGR_DOWN,
167 l10n_util::GetStringUTF8(IDS_ASH_ALTGR_KEY));
170 StickyKeysOverlayView::~StickyKeysOverlayView() {}
172 void StickyKeysOverlayView::OnPaint(gfx::Canvas* canvas) {
173 SkPaint paint;
174 paint.setStyle(SkPaint::kFill_Style);
175 paint.setColor(SkColorSetARGB(0xB3, 0x55, 0x55, 0x55));
176 canvas->DrawRoundRect(GetLocalBounds(), 2, paint);
177 views::WidgetDelegateView::OnPaint(canvas);
180 void StickyKeysOverlayView::SetKeyState(ui::EventFlags modifier,
181 StickyKeyState state) {
182 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
183 DCHECK(it != modifier_label_map_.end());
184 if (it != modifier_label_map_.end()) {
185 StickyKeyOverlayLabel* label = it->second;
186 label->SetKeyState(state);
190 StickyKeyState StickyKeysOverlayView::GetKeyState(ui::EventFlags modifier) {
191 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
192 DCHECK(it != modifier_label_map_.end());
193 return it->second->state();
196 void StickyKeysOverlayView::SetModifierVisible(ui::EventFlags modifier,
197 bool visible) {
198 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
199 DCHECK(it != modifier_label_map_.end());
200 it->second->SetVisible(visible);
203 void StickyKeysOverlayView::AddKeyLabel(ui::EventFlags modifier,
204 const std::string& key_label) {
205 StickyKeyOverlayLabel* label = new StickyKeyOverlayLabel(key_label);
206 AddChildView(label);
207 modifier_label_map_[modifier] = label;
210 ///////////////////////////////////////////////////////////////////////////////
211 // StickyKeysOverlay
212 StickyKeysOverlay::StickyKeysOverlay()
213 : is_visible_(false),
214 overlay_view_(new StickyKeysOverlayView),
215 widget_size_(overlay_view_->GetPreferredSize()) {
216 views::Widget::InitParams params;
217 params.type = views::Widget::InitParams::TYPE_POPUP;
218 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
219 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
220 params.accept_events = false;
221 params.can_activate = false;
222 params.keep_on_top = true;
223 params.remove_standard_frame = true;
224 params.delegate = overlay_view_;
225 params.bounds = CalculateOverlayBounds();
226 params.parent = Shell::GetContainer(
227 Shell::GetTargetRootWindow(),
228 internal::kShellWindowId_OverlayContainer);
229 overlay_widget_.reset(new views::Widget);
230 overlay_widget_->Init(params);
231 overlay_widget_->SetVisibilityChangedAnimationsEnabled(false);
232 overlay_widget_->SetContentsView(overlay_view_);
233 overlay_widget_->GetNativeView()->SetName("StickyKeysOverlay");
236 StickyKeysOverlay::~StickyKeysOverlay() {}
238 void StickyKeysOverlay::Show(bool visible) {
239 if (is_visible_ == visible)
240 return;
242 is_visible_ = visible;
243 if (is_visible_)
244 overlay_widget_->Show();
245 overlay_widget_->SetBounds(CalculateOverlayBounds());
247 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
248 animator->AddObserver(this);
250 // Ensure transform is correct before beginning animation.
251 if (!animator->is_animating()) {
252 int sign = is_visible_ ? -1 : 1;
253 gfx::Transform transform;
254 transform.Translate(
255 sign * (widget_size_.width() + kHorizontalOverlayOffset), 0);
256 overlay_widget_->GetLayer()->SetTransform(transform);
259 ui::ScopedLayerAnimationSettings settings(animator);
260 settings.SetPreemptionStrategy(
261 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
262 settings.SetTweenType(visible ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN);
263 settings.SetTransitionDuration(
264 base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs));
266 overlay_widget_->GetLayer()->SetTransform(gfx::Transform());
269 void StickyKeysOverlay::SetModifierVisible(ui::EventFlags modifier,
270 bool visible) {
271 overlay_view_->SetModifierVisible(modifier, visible);
272 widget_size_ = overlay_view_->GetPreferredSize();
275 void StickyKeysOverlay::SetModifierKeyState(ui::EventFlags modifier,
276 StickyKeyState state) {
277 overlay_view_->SetKeyState(modifier, state);
280 StickyKeyState StickyKeysOverlay::GetModifierKeyState(
281 ui::EventFlags modifier) {
282 return overlay_view_->GetKeyState(modifier);
285 gfx::Rect StickyKeysOverlay::CalculateOverlayBounds() {
286 int x = is_visible_ ? kHorizontalOverlayOffset : -widget_size_.width();
287 return gfx::Rect(gfx::Point(x, kVerticalOverlayOffset), widget_size_);
290 void StickyKeysOverlay::OnLayerAnimationEnded(
291 ui::LayerAnimationSequence* sequence) {
292 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
293 if (animator)
294 animator->RemoveObserver(this);
295 if (!is_visible_)
296 overlay_widget_->Hide();
299 void StickyKeysOverlay::OnLayerAnimationAborted(
300 ui::LayerAnimationSequence* sequence) {
301 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
302 if (animator)
303 animator->RemoveObserver(this);
306 void StickyKeysOverlay::OnLayerAnimationScheduled(
307 ui::LayerAnimationSequence* sequence) {
310 } // namespace ash