Chromium Code Reviews| Index: ash/sticky_keys/sticky_keys_overlay.cc |
| diff --git a/ash/sticky_keys/sticky_keys_overlay.cc b/ash/sticky_keys/sticky_keys_overlay.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..48d5d25d1c09dd9389bfebdd81674a6ca938bc97 |
| --- /dev/null |
| +++ b/ash/sticky_keys/sticky_keys_overlay.cc |
| @@ -0,0 +1,281 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "ash/sticky_keys/sticky_keys_overlay.h" |
| + |
| +#include "ash/shell.h" |
| +#include "ash/shell_window_ids.h" |
| +#include "ash/sticky_keys/sticky_keys_controller.h" |
| +#include "base/strings/string_util.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "grit/ash_strings.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/compositor/scoped_layer_animation_settings.h" |
| +#include "ui/gfx/canvas.h" |
| +#include "ui/gfx/font_list.h" |
| +#include "ui/views/border.h" |
| +#include "ui/views/controls/label.h" |
| +#include "ui/views/layout/box_layout.h" |
| +#include "ui/views/view.h" |
| +#include "ui/views/widget/widget.h" |
| +#include "ui/views/widget/widget_delegate.h" |
| + |
| +namespace ash { |
| + |
| +namespace { |
| + |
| +// Horizontal offset of the overlay from the top left of the screen. |
| +const int kHorizontalOverlayOffset = 18; |
| + |
| +// Vertical offset of the overlay from the top left of the screen. |
| +const int kVerticalOverlayOffset = 18; |
| + |
| +// Spacing between overlay contents and border. |
| +const int kHorizontalBorderSpacing = 9; |
| +const int kVerticalBorderSpacing = 4; |
| + |
| +// Spacing between modifier key labels. |
| +const int kKeyLabelSpacing = 7; |
| + |
| +// Duration of slide animation when overlay is shown or hidden. |
| +const int kSlideAnimationDurationMs = 100; |
| + |
| +} |
| + |
| +/////////////////////////////////////////////////////////////////////////////// |
| +// StickyKeyOverlayLabel |
| +class StickyKeyOverlayLabel : public views::Label { |
| + public: |
| + explicit StickyKeyOverlayLabel(const std::string& key_name); |
| + |
| + virtual ~StickyKeyOverlayLabel(); |
| + |
| + void SetKeyState(StickyKeyState state); |
| + |
| + StickyKeyState state() { return state_; } |
|
James Cook
2014/01/15 22:53:53
nit: const, and usually we put these above the Set
Tim Song
2014/01/16 00:01:59
Done.
|
| + |
| + private: |
| + virtual void PaintText(gfx::Canvas* canvas, |
|
James Cook
2014/01/15 22:53:53
nit: comment what class you are overriding, like "
Tim Song
2014/01/16 00:01:59
Done.
|
| + const base::string16& text, |
| + const gfx::Rect& text_bounds, |
| + int flags) OVERRIDE; |
| + |
| + StickyKeyState state_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(StickyKeyOverlayLabel); |
| +}; |
| + |
| +StickyKeyOverlayLabel::StickyKeyOverlayLabel(const std::string& key_name) |
| + : state_(STICKY_KEY_STATE_DISABLED) { |
| + SetText(base::UTF8ToUTF16(key_name)); |
| + SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| + SetFontList( |
| + font_list().DeriveFontListWithSize(18)); |
| + SetAutoColorReadabilityEnabled(false); |
| + SetFocusable(false); |
| + SetEnabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF)); |
| + SetDisabledColor(SkColorSetARGB(0x80, 0xFF, 0xFF, 0xFF)); |
| + set_border(views::Border::CreateEmptyBorder(0, 0, 0, 0)); |
|
James Cook
2014/01/15 22:53:53
I'm a bit confused -- this adds an empty, zero-wid
Tim Song
2014/01/16 00:01:59
Done. I wanted to ensure the insets to be zero, bu
|
| +} |
| + |
| +StickyKeyOverlayLabel::~StickyKeyOverlayLabel() { |
| +} |
| + |
| +void StickyKeyOverlayLabel::SetKeyState(StickyKeyState state) { |
| + state_ = state; |
| + SkColor label_color; |
| + int style; |
| + switch (state) { |
| + case STICKY_KEY_STATE_ENABLED: |
| + style = gfx::Font::NORMAL; |
| + label_color = SkColorSetA(enabled_color(), 0xFF); |
| + break; |
| + case STICKY_KEY_STATE_LOCKED: |
| + style = gfx::Font::UNDERLINE; |
| + label_color = SkColorSetA(enabled_color(), 0xFF); |
| + break; |
| + default: |
| + style = gfx::Font::NORMAL; |
| + label_color = SkColorSetA(enabled_color(), 0x80); |
| + } |
| + |
| + SetEnabledColor(label_color); |
| + SetDisabledColor(label_color); |
| + SetFontList(font_list().DeriveFontListWithSizeDeltaAndStyle(0, style)); |
| +} |
| + |
| +void StickyKeyOverlayLabel::PaintText(gfx::Canvas* canvas, |
| + const base::string16& text, |
| + const gfx::Rect& text_bounds, |
| + int flags) { |
| + views::Label::PaintText(canvas, |
| + text, |
| + text_bounds, |
| + flags | gfx::Canvas::NO_SUBPIXEL_RENDERING); |
| +} |
| + |
| + |
| +/////////////////////////////////////////////////////////////////////////////// |
| +// StickyKeyOverlayLabel |
| +class StickyKeysOverlayView : public views::WidgetDelegateView { |
| + public: |
| + StickyKeysOverlayView(); |
| + |
| + virtual ~StickyKeysOverlayView(); |
| + |
| + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; |
|
James Cook
2014/01/15 22:53:53
nit: comment what you are overriding
Tim Song
2014/01/16 00:01:59
Done.
|
| + |
| + void SetKeyState(StickyKeyModifier modifier, StickyKeyState state); |
| + |
| + StickyKeyState GetKeyState(StickyKeyModifier modifier); |
| + |
| + private: |
| + void AddKeyLabel(StickyKeyModifier modifier, const std::string& key_label); |
| + |
| + typedef std::map<StickyKeyModifier, StickyKeyOverlayLabel*> ModifierLabelMap; |
| + ModifierLabelMap modifier_label_map_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(StickyKeysOverlayView); |
| +}; |
| + |
| +StickyKeysOverlayView::StickyKeysOverlayView() { |
| + SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, |
| + kHorizontalBorderSpacing, |
| + kVerticalBorderSpacing, |
| + kKeyLabelSpacing)); |
| + AddKeyLabel(STICKY_KEY_CONTROL, |
| + l10n_util::GetStringUTF8(IDS_ASH_STICKY_KEY_CONTROL)); |
| + AddKeyLabel(STICKY_KEY_ALT, |
| + l10n_util::GetStringUTF8(IDS_ASH_STICKY_KEY_ALT)); |
| + AddKeyLabel(STICKY_KEY_SHIFT, |
| + l10n_util::GetStringUTF8(IDS_ASH_STICKY_KEY_SHIFT)); |
| +} |
| + |
| +StickyKeysOverlayView::~StickyKeysOverlayView() {} |
| + |
| +void StickyKeysOverlayView::OnPaint(gfx::Canvas* canvas) { |
| + SkPaint paint; |
| + paint.setStyle(SkPaint::kFill_Style); |
| + paint.setColor(SkColorSetARGB(0xB3, 0x55, 0x55, 0x55)); |
| + canvas->DrawRoundRect(GetLocalBounds(), 2, paint); |
| + views::WidgetDelegateView::OnPaint(canvas); |
| +} |
| + |
| +void StickyKeysOverlayView::SetKeyState(StickyKeyModifier modifier, |
| + StickyKeyState state) { |
| + ModifierLabelMap::iterator it = modifier_label_map_.find(modifier); |
| + DCHECK(it != modifier_label_map_.end()); |
| + if (it != modifier_label_map_.end()) { |
| + StickyKeyOverlayLabel* label = it->second; |
| + label->SetKeyState(state); |
| + } |
| +} |
| + |
| +StickyKeyState StickyKeysOverlayView::GetKeyState(StickyKeyModifier modifier) { |
| + ModifierLabelMap::iterator it = modifier_label_map_.find(modifier); |
| + DCHECK(it != modifier_label_map_.end()); |
| + return it->second->state(); |
| +} |
| + |
| +void StickyKeysOverlayView::AddKeyLabel(StickyKeyModifier modifier, |
| + const std::string& key_label) { |
| + StickyKeyOverlayLabel* label = new StickyKeyOverlayLabel(key_label); |
| + AddChildView(label); |
| + modifier_label_map_[modifier] = label; |
| +} |
| + |
| +/////////////////////////////////////////////////////////////////////////////// |
| +// StickyKeysOverlay |
| +StickyKeysOverlay::StickyKeysOverlay() |
| + : is_showing_(false), |
| + overlay_view_(new StickyKeysOverlayView) { |
| + widget_size_ = overlay_view_->GetPreferredSize(); |
| + |
| + views::Widget::InitParams params; |
| + params.type = views::Widget::InitParams::TYPE_POPUP; |
| + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| + params.accept_events = false; |
| + params.can_activate = false; |
| + params.keep_on_top = true; |
| + params.remove_standard_frame = true; |
| + params.delegate = overlay_view_; |
| + params.bounds = gfx::Rect(gfx::Point(0, 0), widget_size_); |
| + params.parent = Shell::GetContainer( |
| + Shell::GetTargetRootWindow(), |
| + internal::kShellWindowId_OverlayContainer); |
| + overlay_widget_.reset(new views::Widget); |
| + overlay_widget_->Init(params); |
| + overlay_widget_->SetVisibilityChangedAnimationsEnabled(false); |
| + overlay_widget_->SetContentsView(overlay_view_); |
| + overlay_widget_->GetNativeView()->SetName("StickyKeysOverlay"); |
| + |
| + overlay_widget_->GetLayer()->SetTransform(CalculateOverlayTransform()); |
| +} |
| + |
| +StickyKeysOverlay::~StickyKeysOverlay() {} |
| + |
| +void StickyKeysOverlay::Show(bool visible) { |
| + if (is_showing_ == visible) |
| + return; |
| + |
| + is_showing_ = visible; |
| + if (is_showing_) |
| + overlay_widget_->Show(); |
| + |
| + ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator(); |
| + if (animator) |
|
James Cook
2014/01/15 22:53:53
Is animator ever null? I don't think so, and prob
Tim Song
2014/01/16 00:01:59
Done.
|
| + animator->AddObserver(this); |
| + |
| + ui::ScopedLayerAnimationSettings settings(animator); |
| + settings.SetPreemptionStrategy( |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| + settings.SetTweenType(gfx::Tween::EASE_IN_OUT); |
|
James Cook
2014/01/15 22:53:53
You might want to use EASE_OUT here, or EASE_OUT a
Tim Song
2014/01/16 00:01:59
Done. The mock is using the CSS animation transiti
|
| + settings.SetTransitionDuration( |
| + base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs)); |
| + |
| + overlay_widget_->GetLayer()->SetTransform(CalculateOverlayTransform()); |
| +} |
| + |
| +void StickyKeysOverlay::SetModifierKeyState(StickyKeyModifier modifier, |
| + StickyKeyState state) { |
| + overlay_view_->SetKeyState(modifier, state); |
| +} |
| + |
| +StickyKeyState StickyKeysOverlay::GetModifierKeyState( |
| + StickyKeyModifier modifier) { |
| + return overlay_view_->GetKeyState(modifier); |
| +} |
| + |
| +gfx::Transform StickyKeysOverlay::CalculateOverlayTransform() { |
|
James Cook
2014/01/15 22:53:53
This doesn't seem quite right. It looks like the w
Tim Song
2014/01/16 00:01:59
Done. What about the hidden case? Is it okay to le
James Cook
2014/01/16 00:46:20
I think we generally set it back to the identity t
Tim Song
2014/01/16 01:59:45
Done. The widget bounds is now updated whenever we
|
| + gfx::Transform transform; |
| + if (is_showing_) |
| + transform.Translate(kHorizontalBorderSpacing, kVerticalBorderSpacing); |
| + else |
| + transform.Translate(-widget_size_.width(), kVerticalBorderSpacing); |
| + return transform; |
| +} |
| + |
| +void StickyKeysOverlay::OnLayerAnimationEnded( |
| + ui::LayerAnimationSequence* sequence) { |
| + ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator(); |
| + if (animator) |
| + animator->RemoveObserver(this); |
| + if (!is_showing_) |
| + overlay_widget_->Hide(); |
| +} |
| + |
| +void StickyKeysOverlay::OnLayerAnimationAborted( |
| + ui::LayerAnimationSequence* sequence) { |
| + ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator(); |
| + if (animator) |
| + animator->RemoveObserver(this); |
| + overlay_widget_->GetLayer()->SetTransform(CalculateOverlayTransform()); |
| +} |
| + |
| +void StickyKeysOverlay::OnLayerAnimationScheduled( |
| + ui::LayerAnimationSequence* sequence) { |
| +} |
| + |
| +} // ash |
|
James Cook
2014/01/15 22:53:53
"namespace ash"
Tim Song
2014/01/16 00:01:59
Done.
|