OLD | NEW |
---|---|
(Empty) | |
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/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" | |
23 | |
24 namespace ash { | |
25 | |
26 namespace { | |
27 | |
28 // Horizontal offset of the overlay from the top left of the screen. | |
29 const int kHorizontalOverlayOffset = 18; | |
30 | |
31 // Vertical offset of the overlay from the top left of the screen. | |
32 const int kVerticalOverlayOffset = 18; | |
33 | |
34 // Spacing between overlay contents and border. | |
35 const int kHorizontalBorderSpacing = 9; | |
36 const int kVerticalBorderSpacing = 4; | |
37 | |
38 // Spacing between modifier key labels. | |
39 const int kKeyLabelSpacing = 7; | |
40 | |
41 // Duration of slide animation when overlay is shown or hidden. | |
42 const int kSlideAnimationDurationMs = 100; | |
43 | |
44 } | |
45 | |
46 /////////////////////////////////////////////////////////////////////////////// | |
47 // StickyKeyOverlayLabel | |
48 class StickyKeyOverlayLabel : public views::Label { | |
49 public: | |
50 explicit StickyKeyOverlayLabel(const std::string& key_name); | |
51 | |
52 virtual ~StickyKeyOverlayLabel(); | |
53 | |
54 StickyKeyState state() const { return state_; } | |
55 | |
56 void SetKeyState(StickyKeyState state); | |
57 | |
58 private: | |
59 // views::Label overrides: | |
60 virtual void PaintText(gfx::Canvas* canvas, | |
61 const base::string16& text, | |
62 const gfx::Rect& text_bounds, | |
63 int flags) OVERRIDE; | |
64 | |
65 StickyKeyState state_; | |
66 | |
67 DISALLOW_COPY_AND_ASSIGN(StickyKeyOverlayLabel); | |
68 }; | |
69 | |
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); | |
74 SetFontList( | |
75 font_list().DeriveFontListWithSize(18)); | |
76 SetAutoColorReadabilityEnabled(false); | |
77 SetFocusable(false); | |
78 SetEnabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF)); | |
79 SetDisabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF)); | |
80 } | |
81 | |
82 StickyKeyOverlayLabel::~StickyKeyOverlayLabel() { | |
83 } | |
84 | |
85 void StickyKeyOverlayLabel::SetKeyState(StickyKeyState state) { | |
86 state_ = state; | |
87 SkColor label_color; | |
88 int style; | |
89 switch (state) { | |
90 case STICKY_KEY_STATE_ENABLED: | |
91 style = gfx::Font::NORMAL; | |
92 label_color = SkColorSetA(enabled_color(), 0xFF); | |
93 break; | |
94 case STICKY_KEY_STATE_LOCKED: | |
95 style = gfx::Font::UNDERLINE; | |
96 label_color = SkColorSetA(enabled_color(), 0xFF); | |
97 break; | |
98 default: | |
99 style = gfx::Font::NORMAL; | |
100 label_color = SkColorSetA(enabled_color(), 0x80); | |
101 } | |
102 | |
103 SetEnabledColor(label_color); | |
104 SetDisabledColor(label_color); | |
105 SetFontList(font_list().DeriveFontListWithSizeDeltaAndStyle(0, style)); | |
106 } | |
107 | |
108 void StickyKeyOverlayLabel::PaintText(gfx::Canvas* canvas, | |
109 const base::string16& text, | |
110 const gfx::Rect& text_bounds, | |
111 int flags) { | |
112 views::Label::PaintText(canvas, | |
113 text, | |
114 text_bounds, | |
115 flags | gfx::Canvas::NO_SUBPIXEL_RENDERING); | |
116 } | |
117 | |
118 | |
119 /////////////////////////////////////////////////////////////////////////////// | |
120 // StickyKeyOverlayLabel | |
121 class StickyKeysOverlayView : public views::WidgetDelegateView { | |
122 public: | |
123 StickyKeysOverlayView(); | |
124 | |
125 virtual ~StickyKeysOverlayView(); | |
126 | |
127 // views::WidgetDelegateView overrides: | |
128 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; | |
129 | |
130 void SetKeyState(ui::EventFlags modifier, StickyKeyState state); | |
131 | |
132 StickyKeyState GetKeyState(ui::EventFlags modifier); | |
133 | |
134 private: | |
135 void AddKeyLabel(ui::EventFlags modifier, const std::string& key_label); | |
136 | |
137 typedef std::map<ui::EventFlags, StickyKeyOverlayLabel*> ModifierLabelMap; | |
138 ModifierLabelMap modifier_label_map_; | |
139 | |
140 DISALLOW_COPY_AND_ASSIGN(StickyKeysOverlayView); | |
141 }; | |
142 | |
143 StickyKeysOverlayView::StickyKeysOverlayView() { | |
144 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, | |
145 kHorizontalBorderSpacing, | |
146 kVerticalBorderSpacing, | |
147 kKeyLabelSpacing)); | |
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)); | |
154 } | |
155 | |
156 StickyKeysOverlayView::~StickyKeysOverlayView() {} | |
157 | |
158 void StickyKeysOverlayView::OnPaint(gfx::Canvas* canvas) { | |
159 SkPaint paint; | |
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); | |
164 } | |
165 | |
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); | |
173 } | |
174 } | |
175 | |
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(); | |
180 } | |
181 | |
182 void StickyKeysOverlayView::AddKeyLabel(ui::EventFlags modifier, | |
183 const std::string& key_label) { | |
184 StickyKeyOverlayLabel* label = new StickyKeyOverlayLabel(key_label); | |
185 AddChildView(label); | |
186 modifier_label_map_[modifier] = label; | |
187 } | |
188 | |
189 /////////////////////////////////////////////////////////////////////////////// | |
190 // StickyKeysOverlay | |
191 StickyKeysOverlay::StickyKeysOverlay() | |
192 : is_visible_(false), | |
193 overlay_view_(new StickyKeysOverlayView) { | |
194 widget_size_ = overlay_view_->GetPreferredSize(); | |
James Cook
2014/01/16 17:45:59
nit: this could go in the member initializers abov
Tim Song
2014/01/16 19:11:56
Done.
| |
195 | |
196 views::Widget::InitParams params; | |
197 params.type = views::Widget::InitParams::TYPE_POPUP; | |
198 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | |
199 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
200 params.accept_events = false; | |
201 params.can_activate = false; | |
202 params.keep_on_top = true; | |
203 params.remove_standard_frame = true; | |
204 params.delegate = overlay_view_; | |
205 params.bounds = CalculateOverlayBounds(); | |
206 params.parent = Shell::GetContainer( | |
207 Shell::GetTargetRootWindow(), | |
208 internal::kShellWindowId_OverlayContainer); | |
209 overlay_widget_.reset(new views::Widget); | |
210 overlay_widget_->Init(params); | |
211 overlay_widget_->SetVisibilityChangedAnimationsEnabled(false); | |
212 overlay_widget_->SetContentsView(overlay_view_); | |
213 overlay_widget_->GetNativeView()->SetName("StickyKeysOverlay"); | |
214 } | |
215 | |
216 StickyKeysOverlay::~StickyKeysOverlay() {} | |
217 | |
218 void StickyKeysOverlay::Show(bool visible) { | |
219 if (is_visible_ == visible) | |
220 return; | |
221 | |
222 is_visible_ = visible; | |
223 if (is_visible_) | |
224 overlay_widget_->Show(); | |
225 overlay_widget_->SetBounds(CalculateOverlayBounds()); | |
226 | |
227 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator(); | |
228 animator->AddObserver(this); | |
229 | |
230 // Ensure transform is correct before beginning animation. | |
231 if (!animator->is_animating()) { | |
232 int sign = is_visible_ ? -1 : 1; | |
233 gfx::Transform transform; | |
234 transform.Translate( | |
235 sign * (widget_size_.width() + kHorizontalOverlayOffset), 0); | |
James Cook
2014/01/16 17:45:59
Nice use of |sign| to keep the math readable!
Tim Song
2014/01/16 19:11:56
Thanks!
| |
236 overlay_widget_->GetLayer()->SetTransform(transform); | |
237 } | |
238 | |
239 ui::ScopedLayerAnimationSettings settings(animator); | |
240 settings.SetPreemptionStrategy( | |
241 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
242 settings.SetTweenType(visible ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN); | |
243 settings.SetTransitionDuration( | |
244 base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs)); | |
245 | |
246 overlay_widget_->GetLayer()->SetTransform(gfx::Transform()); | |
247 } | |
248 | |
249 void StickyKeysOverlay::SetModifierKeyState(ui::EventFlags modifier, | |
250 StickyKeyState state) { | |
251 overlay_view_->SetKeyState(modifier, state); | |
252 } | |
253 | |
254 StickyKeyState StickyKeysOverlay::GetModifierKeyState( | |
255 ui::EventFlags modifier) { | |
256 return overlay_view_->GetKeyState(modifier); | |
257 } | |
258 | |
259 gfx::Rect StickyKeysOverlay::CalculateOverlayBounds() { | |
260 int x = is_visible_ ? | |
261 kHorizontalOverlayOffset : | |
262 - widget_size_.width() - kHorizontalOverlayOffset; | |
James Cook
2014/01/16 17:45:59
Should this just be "-widget_size.width()"? Isn't
Tim Song
2014/01/16 19:11:56
Done. You're right, I was using the calculation fo
| |
263 return gfx::Rect(gfx::Point(x, kHorizontalOverlayOffset), widget_size_); | |
264 } | |
265 | |
266 void StickyKeysOverlay::OnLayerAnimationEnded( | |
267 ui::LayerAnimationSequence* sequence) { | |
268 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator(); | |
269 if (animator) | |
270 animator->RemoveObserver(this); | |
271 if (!is_visible_) | |
272 overlay_widget_->Hide(); | |
273 } | |
274 | |
275 void StickyKeysOverlay::OnLayerAnimationAborted( | |
276 ui::LayerAnimationSequence* sequence) { | |
277 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator(); | |
278 if (animator) | |
279 animator->RemoveObserver(this); | |
280 } | |
281 | |
282 void StickyKeysOverlay::OnLayerAnimationScheduled( | |
283 ui::LayerAnimationSequence* sequence) { | |
284 } | |
285 | |
286 } // namespace ash | |
OLD | NEW |