| Index: ui/views/focus/focus_manager.cc
|
| diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc
|
| index 80a4dc8d6bdd0c7b67ee984e6081e434cebe6db1..7d43a449cbd568999cb26d7971ddb7d5b955b251 100644
|
| --- a/ui/views/focus/focus_manager.cc
|
| +++ b/ui/views/focus/focus_manager.cc
|
| @@ -15,6 +15,8 @@
|
| #include "ui/base/ime/text_input_client.h"
|
| #include "ui/events/event.h"
|
| #include "ui/events/keycodes/keyboard_codes.h"
|
| +#include "ui/gfx/canvas.h"
|
| +#include "ui/native_theme/native_theme.h"
|
| #include "ui/views/focus/focus_manager_delegate.h"
|
| #include "ui/views/focus/focus_search.h"
|
| #include "ui/views/focus/view_storage.h"
|
| @@ -26,6 +28,71 @@
|
|
|
| namespace views {
|
|
|
| +namespace internal {
|
| +
|
| +// The stroke width of the focus border in dp.
|
| +const int kFocusBorderThickness = 2;
|
| +
|
| +// The corner radius of the focus border roundrect.
|
| +const int kFocusBorderCornerRadius = 3;
|
| +
|
| +// MdFocusRing is a View that is parented to the currently focused View.
|
| +// It paints a ring around the view to indicate focus, and extends slightly
|
| +// beyond the bounds of the view. By having a single focus ring per
|
| +// FocusManager, we reduce the number of views and layers as well as the
|
| +// number of focus change observers.
|
| +class MdFocusRing : public View {
|
| + public:
|
| + MdFocusRing() {
|
| + // A layer is necessary to paint beyond the parent's bounds.
|
| + SetPaintToLayer(true);
|
| + layer()->SetFillsBoundsOpaquely(false);
|
| + set_owned_by_client();
|
| + }
|
| + ~MdFocusRing() override {}
|
| +
|
| + void Install(views::View* focused_view) {
|
| + focused_view->AddChildView(this);
|
| + Layout();
|
| + }
|
| +
|
| + void Uninstall(views::View* unfocused_view) {
|
| + if (parent() != unfocused_view)
|
| + return;
|
| + parent()->RemoveChildView(this);
|
| + }
|
| +
|
| + // View:
|
| + bool CanProcessEventsWithinSubtree() const override { return false; }
|
| +
|
| + void Layout() override {
|
| + // The focus ring handles its own sizing, which is simply to fill the parent
|
| + // and extend a little beyond its borders.
|
| + gfx::Rect focus_bounds = parent()->GetLocalBounds();
|
| + focus_bounds.Inset(gfx::Insets(-kFocusBorderThickness));
|
| + SetBoundsRect(focus_bounds);
|
| + }
|
| +
|
| + void OnPaint(gfx::Canvas* canvas) override {
|
| + SkPaint paint;
|
| + paint.setAntiAlias(true);
|
| + paint.setColor(
|
| + SkColorSetA(GetNativeTheme()->GetSystemColor(
|
| + ui::NativeTheme::kColorId_FocusedBorderColor),
|
| + 0x66));
|
| + paint.setStyle(SkPaint::kStroke_Style);
|
| + paint.setStrokeWidth(kFocusBorderThickness);
|
| + gfx::RectF rect(GetLocalBounds());
|
| + rect.Inset(gfx::InsetsF(kFocusBorderThickness / 2.f));
|
| + canvas->DrawRoundRect(rect, kFocusBorderCornerRadius, paint);
|
| + }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(MdFocusRing);
|
| +};
|
| +
|
| +} // namespace internal
|
| +
|
| bool FocusManager::arrow_key_traversal_enabled_ = false;
|
|
|
| FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
|
| @@ -36,7 +103,8 @@ FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
|
| shortcut_handling_suspended_(false),
|
| focus_change_reason_(kReasonDirectFocusChange),
|
| is_changing_focus_(false),
|
| - keyboard_accessible_(false) {
|
| + keyboard_accessible_(false),
|
| + focus_ring_(nullptr) {
|
| DCHECK(widget_);
|
| stored_focused_view_storage_id_ =
|
| ViewStorage::GetInstance()->CreateStorageID();
|
| @@ -322,14 +390,23 @@ void FocusManager::SetFocusedViewWithReason(
|
|
|
| View* old_focused_view = focused_view_;
|
| focused_view_ = view;
|
| - if (old_focused_view)
|
| + if (old_focused_view) {
|
| old_focused_view->Blur();
|
| + if (focus_ring_)
|
| + focus_ring_->Uninstall(old_focused_view);
|
| + }
|
| // Also make |focused_view_| the stored focus view. This way the stored focus
|
| // view is remembered if focus changes are requested prior to a show or while
|
| // hidden.
|
| SetStoredFocusView(focused_view_);
|
| - if (focused_view_)
|
| + if (focused_view_) {
|
| focused_view_->Focus();
|
| + if (focused_view_->should_use_md_focus_ring()) {
|
| + if (!focus_ring_)
|
| + focus_ring_.reset(new internal::MdFocusRing());
|
| + focus_ring_->Install(focused_view_);
|
| + }
|
| + }
|
|
|
| FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
|
| OnDidChangeFocus(old_focused_view, focused_view_));
|
|
|