Add ICU message format support
[chromium-blink-merge.git] / ash / sticky_keys / sticky_keys_overlay.cc
blob3826f7350027df4c23f7a5e510c500a2cd9663b7
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 ~StickyKeyOverlayLabel() override;
52 StickyKeyState state() const { return state_; }
54 void SetKeyState(StickyKeyState state);
56 private:
57 StickyKeyState state_;
59 DISALLOW_COPY_AND_ASSIGN(StickyKeyOverlayLabel);
62 StickyKeyOverlayLabel::StickyKeyOverlayLabel(const std::string& key_name)
63 : state_(STICKY_KEY_STATE_DISABLED) {
64 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
66 SetText(base::UTF8ToUTF16(key_name));
67 SetHorizontalAlignment(gfx::ALIGN_LEFT);
68 SetFontList(rb->GetFontList(kKeyLabelFontStyle));
69 SetAutoColorReadabilityEnabled(false);
70 SetFocusable(false);
71 SetEnabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF));
72 SetDisabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF));
73 SetSubpixelRenderingEnabled(false);
76 StickyKeyOverlayLabel::~StickyKeyOverlayLabel() {
79 void StickyKeyOverlayLabel::SetKeyState(StickyKeyState state) {
80 state_ = state;
81 SkColor label_color;
82 int style;
83 switch (state) {
84 case STICKY_KEY_STATE_ENABLED:
85 style = gfx::Font::NORMAL;
86 label_color = SkColorSetA(enabled_color(), 0xFF);
87 break;
88 case STICKY_KEY_STATE_LOCKED:
89 style = gfx::Font::UNDERLINE;
90 label_color = SkColorSetA(enabled_color(), 0xFF);
91 break;
92 default:
93 style = gfx::Font::NORMAL;
94 label_color = SkColorSetA(enabled_color(), 0x80);
97 SetEnabledColor(label_color);
98 SetDisabledColor(label_color);
99 SetFontList(font_list().DeriveWithStyle(style));
102 ///////////////////////////////////////////////////////////////////////////////
103 // StickyKeysOverlayView
104 class StickyKeysOverlayView : public views::View {
105 public:
106 // This object is not owned by the views hiearchy or by the widget. The
107 // StickyKeysOverlay is the only class that should create and destroy this
108 // view.
109 StickyKeysOverlayView();
111 ~StickyKeysOverlayView() override;
113 // views::View overrides:
114 void OnPaint(gfx::Canvas* canvas) override;
116 void SetKeyState(ui::EventFlags modifier, StickyKeyState state);
118 StickyKeyState GetKeyState(ui::EventFlags modifier);
120 void SetModifierVisible(ui::EventFlags modifier, bool visible);
121 bool GetModifierVisible(ui::EventFlags modifier);
123 private:
124 void AddKeyLabel(ui::EventFlags modifier, const std::string& key_label);
126 typedef std::map<ui::EventFlags, StickyKeyOverlayLabel*> ModifierLabelMap;
127 ModifierLabelMap modifier_label_map_;
129 DISALLOW_COPY_AND_ASSIGN(StickyKeysOverlayView);
132 StickyKeysOverlayView::StickyKeysOverlayView() {
133 // The parent StickyKeysOverlay object owns this view.
134 set_owned_by_client();
136 const gfx::Font& font =
137 ui::ResourceBundle::GetSharedInstance().GetFont(kKeyLabelFontStyle);
138 int font_size = font.GetFontSize();
139 int font_padding = font.GetHeight() - font.GetBaseline();
141 // Text should have a margin of 0.5 times the font size on each side, so
142 // the spacing between two labels will be the same as the font size.
143 int horizontal_spacing = font_size / 2;
144 int vertical_spacing = font_size / 2 - font_padding;
145 int child_spacing = font_size - 2 * font_padding;
147 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
148 horizontal_spacing,
149 vertical_spacing,
150 child_spacing));
151 AddKeyLabel(ui::EF_CONTROL_DOWN,
152 l10n_util::GetStringUTF8(IDS_ASH_CONTROL_KEY));
153 AddKeyLabel(ui::EF_ALT_DOWN,
154 l10n_util::GetStringUTF8(IDS_ASH_ALT_KEY));
155 AddKeyLabel(ui::EF_SHIFT_DOWN,
156 l10n_util::GetStringUTF8(IDS_ASH_SHIFT_KEY));
157 AddKeyLabel(ui::EF_COMMAND_DOWN,
158 l10n_util::GetStringUTF8(IDS_ASH_SEARCH_KEY));
159 AddKeyLabel(ui::EF_ALTGR_DOWN,
160 l10n_util::GetStringUTF8(IDS_ASH_ALTGR_KEY));
161 AddKeyLabel(ui::EF_MOD3_DOWN,
162 l10n_util::GetStringUTF8(IDS_ASH_MOD3_KEY));
165 StickyKeysOverlayView::~StickyKeysOverlayView() {}
167 void StickyKeysOverlayView::OnPaint(gfx::Canvas* canvas) {
168 SkPaint paint;
169 paint.setStyle(SkPaint::kFill_Style);
170 paint.setColor(SkColorSetARGB(0xB3, 0x55, 0x55, 0x55));
171 canvas->DrawRoundRect(GetLocalBounds(), 2, paint);
172 views::View::OnPaint(canvas);
175 void StickyKeysOverlayView::SetKeyState(ui::EventFlags modifier,
176 StickyKeyState state) {
177 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
178 DCHECK(it != modifier_label_map_.end());
179 if (it != modifier_label_map_.end()) {
180 StickyKeyOverlayLabel* label = it->second;
181 label->SetKeyState(state);
185 StickyKeyState StickyKeysOverlayView::GetKeyState(ui::EventFlags modifier) {
186 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
187 DCHECK(it != modifier_label_map_.end());
188 return it->second->state();
191 void StickyKeysOverlayView::SetModifierVisible(ui::EventFlags modifier,
192 bool visible) {
193 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
194 DCHECK(it != modifier_label_map_.end());
195 it->second->SetVisible(visible);
198 bool StickyKeysOverlayView::GetModifierVisible(ui::EventFlags modifier) {
199 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
200 DCHECK(it != modifier_label_map_.end());
201 return it->second->visible();
204 void StickyKeysOverlayView::AddKeyLabel(ui::EventFlags modifier,
205 const std::string& key_label) {
206 StickyKeyOverlayLabel* label = new StickyKeyOverlayLabel(key_label);
207 AddChildView(label);
208 modifier_label_map_[modifier] = label;
211 ///////////////////////////////////////////////////////////////////////////////
212 // StickyKeysOverlay
213 StickyKeysOverlay::StickyKeysOverlay()
214 : is_visible_(false),
215 overlay_view_(new StickyKeysOverlayView),
216 widget_size_(overlay_view_->GetPreferredSize()) {
217 views::Widget::InitParams params;
218 params.type = views::Widget::InitParams::TYPE_POPUP;
219 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
220 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
221 params.accept_events = false;
222 params.keep_on_top = true;
223 params.remove_standard_frame = true;
224 params.bounds = CalculateOverlayBounds();
225 params.parent = Shell::GetContainer(Shell::GetTargetRootWindow(),
226 kShellWindowId_OverlayContainer);
227 overlay_widget_.reset(new views::Widget);
228 overlay_widget_->Init(params);
229 overlay_widget_->SetVisibilityChangedAnimationsEnabled(false);
230 overlay_widget_->SetContentsView(overlay_view_.get());
231 overlay_widget_->GetNativeView()->SetName("StickyKeysOverlay");
234 StickyKeysOverlay::~StickyKeysOverlay() {}
236 void StickyKeysOverlay::Show(bool visible) {
237 if (is_visible_ == visible)
238 return;
240 is_visible_ = visible;
241 if (is_visible_)
242 overlay_widget_->Show();
243 overlay_widget_->SetBounds(CalculateOverlayBounds());
245 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
246 animator->AddObserver(this);
248 // Ensure transform is correct before beginning animation.
249 if (!animator->is_animating()) {
250 int sign = is_visible_ ? -1 : 1;
251 gfx::Transform transform;
252 transform.Translate(
253 sign * (widget_size_.width() + kHorizontalOverlayOffset), 0);
254 overlay_widget_->GetLayer()->SetTransform(transform);
257 ui::ScopedLayerAnimationSettings settings(animator);
258 settings.SetPreemptionStrategy(
259 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
260 settings.SetTweenType(visible ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN);
261 settings.SetTransitionDuration(
262 base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs));
264 overlay_widget_->GetLayer()->SetTransform(gfx::Transform());
267 void StickyKeysOverlay::SetModifierVisible(ui::EventFlags modifier,
268 bool visible) {
269 overlay_view_->SetModifierVisible(modifier, visible);
270 widget_size_ = overlay_view_->GetPreferredSize();
273 bool StickyKeysOverlay::GetModifierVisible(ui::EventFlags modifier) {
274 return overlay_view_->GetModifierVisible(modifier);
277 void StickyKeysOverlay::SetModifierKeyState(ui::EventFlags modifier,
278 StickyKeyState state) {
279 overlay_view_->SetKeyState(modifier, state);
282 StickyKeyState StickyKeysOverlay::GetModifierKeyState(
283 ui::EventFlags modifier) {
284 return overlay_view_->GetKeyState(modifier);
287 views::Widget* StickyKeysOverlay::GetWidgetForTesting() {
288 return overlay_widget_.get();
291 gfx::Rect StickyKeysOverlay::CalculateOverlayBounds() {
292 int x = is_visible_ ? kHorizontalOverlayOffset : -widget_size_.width();
293 return gfx::Rect(gfx::Point(x, kVerticalOverlayOffset), widget_size_);
296 void StickyKeysOverlay::OnLayerAnimationEnded(
297 ui::LayerAnimationSequence* sequence) {
298 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
299 if (animator)
300 animator->RemoveObserver(this);
301 if (!is_visible_)
302 overlay_widget_->Hide();
305 void StickyKeysOverlay::OnLayerAnimationAborted(
306 ui::LayerAnimationSequence* sequence) {
307 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
308 if (animator)
309 animator->RemoveObserver(this);
312 void StickyKeysOverlay::OnLayerAnimationScheduled(
313 ui::LayerAnimationSequence* sequence) {
316 } // namespace ash