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"
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/compositor/scoped_layer_animation_settings.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/gfx/font_list.h"
17 #include "ui/views/border.h"
18 #include "ui/views/controls/label.h"
19 #include "ui/views/layout/box_layout.h"
20 #include "ui/views/view.h"
21 #include "ui/views/widget/widget.h"
22 #include "ui/views/widget/widget_delegate.h"
28 // Horizontal offset of the overlay from the top left of the screen.
29 const int kHorizontalOverlayOffset = 18;
31 // Vertical offset of the overlay from the top left of the screen.
32 const int kVerticalOverlayOffset = 18;
34 // Spacing between overlay contents and border.
35 const int kHorizontalBorderSpacing = 9;
36 const int kVerticalBorderSpacing = 4;
38 // Spacing between modifier key labels.
39 const int kKeyLabelSpacing = 7;
41 // Duration of slide animation when overlay is shown or hidden.
42 const int kSlideAnimationDurationMs = 100;
46 ///////////////////////////////////////////////////////////////////////////////
47 // StickyKeyOverlayLabel
48 class StickyKeyOverlayLabel : public views::Label {
50 explicit StickyKeyOverlayLabel(const std::string& key_name);
52 virtual ~StickyKeyOverlayLabel();
54 StickyKeyState state() const { return state_; }
56 void SetKeyState(StickyKeyState state);
59 // views::Label overrides:
60 virtual void PaintText(gfx::Canvas* canvas,
61 const base::string16& text,
62 const gfx::Rect& text_bounds,
65 StickyKeyState state_;
67 DISALLOW_COPY_AND_ASSIGN(StickyKeyOverlayLabel);
70 StickyKeyOverlayLabel::StickyKeyOverlayLabel(const std::string& key_name)
71 : state_(STICKY_KEY_STATE_DISABLED) {
72 SetText(base::UTF8ToUTF16(key_name));
73 SetHorizontalAlignment(gfx::ALIGN_LEFT);
75 font_list().DeriveFontListWithSize(18));
76 SetAutoColorReadabilityEnabled(false);
78 SetEnabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF));
79 SetDisabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF));
82 StickyKeyOverlayLabel::~StickyKeyOverlayLabel() {
85 void StickyKeyOverlayLabel::SetKeyState(StickyKeyState state) {
90 case STICKY_KEY_STATE_ENABLED:
91 style = gfx::Font::NORMAL;
92 label_color = SkColorSetA(enabled_color(), 0xFF);
94 case STICKY_KEY_STATE_LOCKED:
95 style = gfx::Font::UNDERLINE;
96 label_color = SkColorSetA(enabled_color(), 0xFF);
99 style = gfx::Font::NORMAL;
100 label_color = SkColorSetA(enabled_color(), 0x80);
103 SetEnabledColor(label_color);
104 SetDisabledColor(label_color);
105 SetFontList(font_list().DeriveFontListWithSizeDeltaAndStyle(0, style));
108 void StickyKeyOverlayLabel::PaintText(gfx::Canvas* canvas,
109 const base::string16& text,
110 const gfx::Rect& text_bounds,
112 views::Label::PaintText(canvas,
115 flags | gfx::Canvas::NO_SUBPIXEL_RENDERING);
119 ///////////////////////////////////////////////////////////////////////////////
120 // StickyKeyOverlayLabel
121 class StickyKeysOverlayView : public views::WidgetDelegateView {
123 StickyKeysOverlayView();
125 virtual ~StickyKeysOverlayView();
127 // views::WidgetDelegateView overrides:
128 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
130 void SetKeyState(ui::EventFlags modifier, StickyKeyState state);
132 StickyKeyState GetKeyState(ui::EventFlags modifier);
135 void AddKeyLabel(ui::EventFlags modifier, const std::string& key_label);
137 typedef std::map<ui::EventFlags, StickyKeyOverlayLabel*> ModifierLabelMap;
138 ModifierLabelMap modifier_label_map_;
140 DISALLOW_COPY_AND_ASSIGN(StickyKeysOverlayView);
143 StickyKeysOverlayView::StickyKeysOverlayView() {
144 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
145 kHorizontalBorderSpacing,
146 kVerticalBorderSpacing,
148 AddKeyLabel(ui::EF_CONTROL_DOWN,
149 l10n_util::GetStringUTF8(IDS_ASH_CONTROL_KEY));
150 AddKeyLabel(ui::EF_ALT_DOWN,
151 l10n_util::GetStringUTF8(IDS_ASH_ALT_KEY));
152 AddKeyLabel(ui::EF_SHIFT_DOWN,
153 l10n_util::GetStringUTF8(IDS_ASH_SHIFT_KEY));
156 StickyKeysOverlayView::~StickyKeysOverlayView() {}
158 void StickyKeysOverlayView::OnPaint(gfx::Canvas* canvas) {
160 paint.setStyle(SkPaint::kFill_Style);
161 paint.setColor(SkColorSetARGB(0xB3, 0x55, 0x55, 0x55));
162 canvas->DrawRoundRect(GetLocalBounds(), 2, paint);
163 views::WidgetDelegateView::OnPaint(canvas);
166 void StickyKeysOverlayView::SetKeyState(ui::EventFlags modifier,
167 StickyKeyState state) {
168 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
169 DCHECK(it != modifier_label_map_.end());
170 if (it != modifier_label_map_.end()) {
171 StickyKeyOverlayLabel* label = it->second;
172 label->SetKeyState(state);
176 StickyKeyState StickyKeysOverlayView::GetKeyState(ui::EventFlags modifier) {
177 ModifierLabelMap::iterator it = modifier_label_map_.find(modifier);
178 DCHECK(it != modifier_label_map_.end());
179 return it->second->state();
182 void StickyKeysOverlayView::AddKeyLabel(ui::EventFlags modifier,
183 const std::string& key_label) {
184 StickyKeyOverlayLabel* label = new StickyKeyOverlayLabel(key_label);
186 modifier_label_map_[modifier] = label;
189 ///////////////////////////////////////////////////////////////////////////////
191 StickyKeysOverlay::StickyKeysOverlay()
192 : is_visible_(false),
193 overlay_view_(new StickyKeysOverlayView),
194 widget_size_(overlay_view_->GetPreferredSize()) {
195 views::Widget::InitParams params;
196 params.type = views::Widget::InitParams::TYPE_POPUP;
197 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
198 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
199 params.accept_events = false;
200 params.can_activate = false;
201 params.keep_on_top = true;
202 params.remove_standard_frame = true;
203 params.delegate = overlay_view_;
204 params.bounds = CalculateOverlayBounds();
205 params.parent = Shell::GetContainer(
206 Shell::GetTargetRootWindow(),
207 internal::kShellWindowId_OverlayContainer);
208 overlay_widget_.reset(new views::Widget);
209 overlay_widget_->Init(params);
210 overlay_widget_->SetVisibilityChangedAnimationsEnabled(false);
211 overlay_widget_->SetContentsView(overlay_view_);
212 overlay_widget_->GetNativeView()->SetName("StickyKeysOverlay");
215 StickyKeysOverlay::~StickyKeysOverlay() {}
217 void StickyKeysOverlay::Show(bool visible) {
218 if (is_visible_ == visible)
221 is_visible_ = visible;
223 overlay_widget_->Show();
224 overlay_widget_->SetBounds(CalculateOverlayBounds());
226 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
227 animator->AddObserver(this);
229 // Ensure transform is correct before beginning animation.
230 if (!animator->is_animating()) {
231 int sign = is_visible_ ? -1 : 1;
232 gfx::Transform transform;
234 sign * (widget_size_.width() + kHorizontalOverlayOffset), 0);
235 overlay_widget_->GetLayer()->SetTransform(transform);
238 ui::ScopedLayerAnimationSettings settings(animator);
239 settings.SetPreemptionStrategy(
240 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
241 settings.SetTweenType(visible ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN);
242 settings.SetTransitionDuration(
243 base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs));
245 overlay_widget_->GetLayer()->SetTransform(gfx::Transform());
248 void StickyKeysOverlay::SetModifierKeyState(ui::EventFlags modifier,
249 StickyKeyState state) {
250 overlay_view_->SetKeyState(modifier, state);
253 StickyKeyState StickyKeysOverlay::GetModifierKeyState(
254 ui::EventFlags modifier) {
255 return overlay_view_->GetKeyState(modifier);
258 gfx::Rect StickyKeysOverlay::CalculateOverlayBounds() {
259 int x = is_visible_ ? kHorizontalOverlayOffset : -widget_size_.width();
260 return gfx::Rect(gfx::Point(x, kVerticalOverlayOffset), widget_size_);
263 void StickyKeysOverlay::OnLayerAnimationEnded(
264 ui::LayerAnimationSequence* sequence) {
265 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
267 animator->RemoveObserver(this);
269 overlay_widget_->Hide();
272 void StickyKeysOverlay::OnLayerAnimationAborted(
273 ui::LayerAnimationSequence* sequence) {
274 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
276 animator->RemoveObserver(this);
279 void StickyKeysOverlay::OnLayerAnimationScheduled(
280 ui::LayerAnimationSequence* sequence) {