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/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"
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
{
48 explicit StickyKeyOverlayLabel(const std::string
& key_name
);
50 virtual ~StickyKeyOverlayLabel();
52 StickyKeyState
state() const { return state_
; }
54 void SetKeyState(StickyKeyState state
);
57 // views::Label overrides:
58 virtual void PaintText(gfx::Canvas
* canvas
,
59 const base::string16
& text
,
60 const gfx::Rect
& text_bounds
,
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);
77 SetEnabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF));
78 SetDisabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF));
81 StickyKeyOverlayLabel::~StickyKeyOverlayLabel() {
84 void StickyKeyOverlayLabel::SetKeyState(StickyKeyState state
) {
89 case STICKY_KEY_STATE_ENABLED
:
90 style
= gfx::Font::NORMAL
;
91 label_color
= SkColorSetA(enabled_color(), 0xFF);
93 case STICKY_KEY_STATE_LOCKED
:
94 style
= gfx::Font::UNDERLINE
;
95 label_color
= SkColorSetA(enabled_color(), 0xFF);
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
,
111 views::Label::PaintText(canvas
,
114 flags
| gfx::Canvas::NO_SUBPIXEL_RENDERING
);
118 ///////////////////////////////////////////////////////////////////////////////
119 // StickyKeyOverlayLabel
120 class StickyKeysOverlayView
: public views::WidgetDelegateView
{
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
);
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
,
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
) {
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
,
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
);
207 modifier_label_map_
[modifier
] = label
;
210 ///////////////////////////////////////////////////////////////////////////////
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
)
242 is_visible_
= 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
;
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
,
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();
294 animator
->RemoveObserver(this);
296 overlay_widget_
->Hide();
299 void StickyKeysOverlay::OnLayerAnimationAborted(
300 ui::LayerAnimationSequence
* sequence
) {
301 ui::LayerAnimator
* animator
= overlay_widget_
->GetLayer()->GetAnimator();
303 animator
->RemoveObserver(this);
306 void StickyKeysOverlay::OnLayerAnimationScheduled(
307 ui::LayerAnimationSequence
* sequence
) {