diff --git a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc index 9af25ca7f384f..2706bfc8a6c23 100644 --- a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc +++ b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc @@ -542,13 +542,8 @@ class BluetoothDetailedView : public TrayDetailsView { tri_view()->SetContainerVisible(TriView::Container::END, true); - // TODO(tdanderson): Move common toggle-creation logic to TrayPopupUtils. - // See crbug.com/614453. - toggle_ = new views::ToggleButton(this); - toggle_->SetFocusForPlatform(); - toggle_->SetAccessibleName( - ui::ResourceBundle::GetSharedInstance().GetLocalizedString( - IDS_ASH_STATUS_TRAY_BLUETOOTH)); + toggle_ = TrayPopupUtils::CreateToggleButton( + this, IDS_ASH_STATUS_TRAY_BLUETOOTH); tri_view()->AddView(TriView::Container::END, toggle_); settings_ = CreateSettingsButton(login_); diff --git a/ash/common/system/chromeos/ime_menu/ime_list_view.cc b/ash/common/system/chromeos/ime_menu/ime_list_view.cc index dd1ae9e33afe6..ce61439c7d5b5 100644 --- a/ash/common/system/chromeos/ime_menu/ime_list_view.cc +++ b/ash/common/system/chromeos/ime_menu/ime_list_view.cc @@ -223,11 +223,8 @@ class MaterialKeyboardStatusRowView : public views::View { tri_view->AddView(TriView::Container::CENTER, label_); // The on-screen keyboard toggle button. - toggle_ = new views::ToggleButton(listener_); - toggle_->SetFocusForPlatform(); - toggle_->SetAccessibleName( - ui::ResourceBundle::GetSharedInstance().GetLocalizedString( - IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD)); + toggle_ = TrayPopupUtils::CreateToggleButton( + listener_, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD); tri_view->AddView(TriView::Container::END, toggle_); } diff --git a/ash/common/system/chromeos/network/network_list_md.cc b/ash/common/system/chromeos/network/network_list_md.cc index 09dc70776ad3d..1470a769a6e11 100644 --- a/ash/common/system/chromeos/network/network_list_md.cc +++ b/ash/common/system/chromeos/network/network_list_md.cc @@ -51,8 +51,6 @@ namespace { const int kSectionHeaderRowSize = 48; const int kSectionHeaderRowVerticalInset = 4; const int kSectionHeaderRowLeftInset = 18; -const int kSectionHeaderRowRightInset = 14; -const int kSectionHeaderRowChildSpacing = 14; bool IsProhibitedByPolicy(const chromeos::NetworkState* network) { if (!NetworkTypePattern::WiFi().MatchesType(network->type())) @@ -134,14 +132,14 @@ class NetworkListViewMd::SectionHeaderRowView : public views::View, // https://crbug.com/614453. TrayPopupUtils::ConfigureAsStickyHeader(this); container_ = new views::View; - container_->SetBorder(views::CreateEmptyBorder( - 0, kSectionHeaderRowLeftInset, 0, kSectionHeaderRowRightInset)); + container_->SetBorder( + views::CreateEmptyBorder(0, kSectionHeaderRowLeftInset, 0, 0)); views::FillLayout* layout = new views::FillLayout; SetLayoutManager(layout); AddChildView(container_); - views::BoxLayout* container_layout = new views::BoxLayout( - views::BoxLayout::kHorizontal, 0, 0, kSectionHeaderRowChildSpacing); + views::BoxLayout* container_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); container_layout->set_cross_axis_alignment( views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); container_->SetLayoutManager(container_layout); @@ -160,12 +158,8 @@ class NetworkListViewMd::SectionHeaderRowView : public views::View, } void AddToggleButton(bool enabled) { - toggle_ = new views::ToggleButton(this); - toggle_->SetAccessibleName(l10n_util::GetStringUTF16(title_id_)); + toggle_ = TrayPopupUtils::CreateToggleButton(this, title_id_); toggle_->SetIsOn(enabled, false); - // TODO(varkha): Implement focus painter for toggle. See - // https://crbug.com/652677 for context. - toggle_->SetFocusForPlatform(); container_->AddChildView(toggle_); } diff --git a/ash/common/system/tray/tray_constants.cc b/ash/common/system/tray/tray_constants.cc index b0f71b1aa8a6a..0138c85606dad 100644 --- a/ash/common/system/tray/tray_constants.cc +++ b/ash/common/system/tray/tray_constants.cc @@ -55,6 +55,8 @@ const SkColor kTrayPopupHoverBackgroundColor = SkColorSetRGB(0xe4, 0xe4, 0xe4); const int kTrayPopupScrollSeparatorHeight = 15; const int kTrayRoundedBorderRadius = 2; +const int kTrayToggleButtonWidth = 68; + const SkColor kBackgroundColor = SkColorSetRGB(0xfe, 0xfe, 0xfe); const SkColor kHoverBackgroundColor = SkColorSetRGB(0xf3, 0xf3, 0xf3); const SkColor kPublicAccountBackgroundColor = SkColorSetRGB(0xf8, 0xe5, 0xb6); diff --git a/ash/common/system/tray/tray_constants.h b/ash/common/system/tray/tray_constants.h index 5aa1e335d6a6f..b325b41229b79 100644 --- a/ash/common/system/tray/tray_constants.h +++ b/ash/common/system/tray/tray_constants.h @@ -62,6 +62,9 @@ extern const int kTrayRoundedBorderRadius; // The padding used on the left and right of labels. extern const int kTrayPopupLabelHorizontalPadding; +// The width of ToggleButton views including any border padding. +extern const int kTrayToggleButtonWidth; + extern const SkColor kBackgroundColor; extern const SkColor kHoverBackgroundColor; extern const SkColor kPublicAccountBackgroundColor; diff --git a/ash/common/system/tray/tray_popup_utils.cc b/ash/common/system/tray/tray_popup_utils.cc index 189cb3cd691db..d0dd7177ed9ed 100644 --- a/ash/common/system/tray/tray_popup_utils.cc +++ b/ash/common/system/tray/tray_popup_utils.cc @@ -15,6 +15,7 @@ #include "ash/common/system/tray/tray_popup_label_button.h" #include "ash/common/system/tray/tray_popup_label_button_border.h" #include "ash/common/wm_shell.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" @@ -25,12 +26,14 @@ #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/button/md_text_button.h" +#include "ui/views/controls/button/toggle_button.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/separator.h" #include "ui/views/controls/slider.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/painter.h" namespace ash { @@ -251,6 +254,24 @@ views::Slider* TrayPopupUtils::CreateSlider(views::SliderListener* listener) { return slider; } +views::ToggleButton* TrayPopupUtils::CreateToggleButton( + views::ButtonListener* listener, + int accessible_name_id) { + views::ToggleButton* toggle = new views::ToggleButton(listener); + const gfx::Size toggle_size(toggle->GetPreferredSize()); + const int vertical_padding = (kMenuButtonSize - toggle_size.height()) / 2; + const int horizontal_padding = + (kTrayToggleButtonWidth - toggle_size.width()) / 2; + toggle->SetBorder(views::CreateEmptyBorder( + gfx::Insets(vertical_padding, horizontal_padding))); + // TODO(tdanderson): Update the focus rect color, border thickness, and + // location for material design. + toggle->SetFocusPainter(views::Painter::CreateSolidFocusPainter( + kFocusBorderColor, gfx::Insets(1))); + toggle->SetAccessibleName(l10n_util::GetStringUTF16(accessible_name_id)); + return toggle; +} + void TrayPopupUtils::ConfigureAsStickyHeader(views::View* view) { view->set_id(VIEW_ID_STICKY_HEADER); view->set_background( diff --git a/ash/common/system/tray/tray_popup_utils.h b/ash/common/system/tray/tray_popup_utils.h index 910acb36e56d3..404c23c9143ff 100644 --- a/ash/common/system/tray/tray_popup_utils.h +++ b/ash/common/system/tray/tray_popup_utils.h @@ -25,6 +25,7 @@ class LayoutManager; class Separator; class Slider; class SliderListener; +class ToggleButton; } // namespace views namespace ash { @@ -91,6 +92,11 @@ class TrayPopupUtils { // with a FillLayout. static views::Slider* CreateSlider(views::SliderListener* listener); + // Returns a ToggleButton that has been configured for system menu layout. + static views::ToggleButton* CreateToggleButton( + views::ButtonListener* listener, + int accessible_name_id); + // Sets up |view| to be a sticky header in a tray detail scroll view. static void ConfigureAsStickyHeader(views::View* view); diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc index c8ff2d8fb5b8f..7ce350d863239 100644 --- a/ui/views/controls/button/toggle_button.cc +++ b/ui/views/controls/button/toggle_button.cc @@ -10,9 +10,11 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" +#include "ui/gfx/geometry/rect_conversions.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/border.h" +#include "ui/views/painter.h" namespace views { @@ -24,11 +26,8 @@ const int kTrackWidth = 28; // Margins from edge of track to edge of view. const int kTrackVerticalMargin = 5; const int kTrackHorizontalMargin = 6; -// Margin from edge of thumb to closest edge of view. Note that the thumb -// margins must be sufficiently large to allow space for the shadow. -const int kThumbHorizontalMargin = 4; -// Margin from top/bottom edge of thumb to top/bottom edge of view. -const int kThumbVerticalMargin = 3; +// Inset from the rounded edge of the thumb to the rounded edge of the track. +const int kThumbInset = 2; } // namespace @@ -51,6 +50,13 @@ class ToggleButton::ThumbView : public InkDropHostView { .Offset(gfx::Vector2d(kShadowOffsetX, kShadowOffsetY)); } + protected: + // views::View: + bool CanProcessEventsWithinSubtree() const override { + // Make the thumb behave as part of the parent for event handling. + return false; + } + private: static const int kShadowOffsetX = 0; static const int kShadowOffsetY = 1; @@ -108,10 +114,9 @@ ToggleButton::ToggleButton(ButtonListener* listener) thumb_view_(new ThumbView()) { slide_animation_.SetSlideDuration(80 /* ms */); slide_animation_.SetTweenType(gfx::Tween::LINEAR); - SetBorder(CreateEmptyBorder( - gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin))); AddChildView(thumb_view_); SetInkDropMode(InkDropMode::ON); + SetFocusForPlatform(); set_has_ink_drop_action_on_click(true); } @@ -136,9 +141,27 @@ void ToggleButton::SetIsOn(bool is_on, bool animate) { } } +void ToggleButton::SetFocusPainter(std::unique_ptr focus_painter) { + focus_painter_ = std::move(focus_painter); +} + +gfx::Size ToggleButton::GetPreferredSize() const { + gfx::Rect rect(kTrackWidth, kTrackHeight); + rect.Inset(gfx::Insets(-kTrackVerticalMargin, -kTrackHorizontalMargin)); + if (border()) + rect.Inset(-border()->GetInsets()); + return rect.size(); +} + +gfx::Rect ToggleButton::GetTrackBounds() const { + gfx::Rect track_bounds(GetContentsBounds()); + track_bounds.ClampToCenteredSize(gfx::Size(kTrackWidth, kTrackHeight)); + return track_bounds; +} + gfx::Rect ToggleButton::GetThumbBounds() const { - gfx::Rect thumb_bounds = GetLocalBounds(); - thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin)); + gfx::Rect thumb_bounds(GetTrackBounds()); + thumb_bounds.Inset(gfx::Insets(-kThumbInset)); thumb_bounds.set_x(thumb_bounds.x() + slide_animation_.GetCurrentValue() * (thumb_bounds.width() - thumb_bounds.height())); @@ -161,13 +184,6 @@ SkColor ToggleButton::GetTrackColor(bool is_on) const { return SkColorSetA(GetNativeTheme()->GetSystemColor(color_id), kTrackAlpha); } -gfx::Size ToggleButton::GetPreferredSize() const { - gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight); - if (border()) - rect.Inset(-border()->GetInsets()); - return rect.size(); -} - const char* ToggleButton::GetClassName() const { return kViewClassName; } @@ -175,8 +191,9 @@ const char* ToggleButton::GetClassName() const { void ToggleButton::OnPaint(gfx::Canvas* canvas) { // Paint the toggle track. To look sharp even at fractional scale factors, // round up to pixel boundaries. + canvas->Save(); float dsf = canvas->UndoDeviceScaleFactor(); - gfx::RectF track_rect(GetContentsBounds()); + gfx::RectF track_rect(GetTrackBounds()); track_rect.Scale(dsf); track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect)); SkPaint track_paint; @@ -186,11 +203,21 @@ void ToggleButton::OnPaint(gfx::Canvas* canvas) { GetTrackColor(true), GetTrackColor(false), static_cast(SK_AlphaOPAQUE * color_ratio))); canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint); + canvas->Restore(); + + Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); } -void ToggleButton::NotifyClick(const ui::Event& event) { - SetIsOn(!is_on(), true); - CustomButton::NotifyClick(event); +void ToggleButton::OnFocus() { + CustomButton::OnFocus(); + if (focus_painter_) + SchedulePaint(); +} + +void ToggleButton::OnBlur() { + CustomButton::OnBlur(); + if (focus_painter_) + SchedulePaint(); } void ToggleButton::OnBoundsChanged(const gfx::Rect& previous_bounds) { @@ -209,6 +236,11 @@ void ToggleButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { node_data->AddStateFlag(ui::AX_STATE_CHECKED); } +void ToggleButton::NotifyClick(const ui::Event& event) { + SetIsOn(!is_on(), true); + CustomButton::NotifyClick(event); +} + void ToggleButton::AddInkDropLayer(ui::Layer* ink_drop_layer) { thumb_view_->AddInkDropLayer(ink_drop_layer); } diff --git a/ui/views/controls/button/toggle_button.h b/ui/views/controls/button/toggle_button.h index eb8efadfbd22a..452dd80601e3c 100644 --- a/ui/views/controls/button/toggle_button.h +++ b/ui/views/controls/button/toggle_button.h @@ -10,6 +10,8 @@ namespace views { +class Painter; + // This view presents a button that has two states: on and off. This is similar // to a checkbox but has no text and looks more like a two-state horizontal // slider. @@ -23,11 +25,19 @@ class VIEWS_EXPORT ToggleButton : public CustomButton { void SetIsOn(bool is_on, bool animate); bool is_on() const { return is_on_; } + void SetFocusPainter(std::unique_ptr focus_painter); + + // views::View: + gfx::Size GetPreferredSize() const override; + private: friend class TestToggleButton; class ThumbView; - // Calculates the bounding box for the thumb (the circle). + // Calculates and returns the bounding box for the track. + gfx::Rect GetTrackBounds() const; + + // Calculates and returns the bounding box for the thumb (the circle). gfx::Rect GetThumbBounds() const; // Updates position and color of the thumb. @@ -35,14 +45,17 @@ class VIEWS_EXPORT ToggleButton : public CustomButton { SkColor GetTrackColor(bool is_on) const; - // CustomButton: - gfx::Size GetPreferredSize() const override; + // views::View: const char* GetClassName() const override; void OnPaint(gfx::Canvas* canvas) override; - void NotifyClick(const ui::Event& event) override; + void OnFocus() override; + void OnBlur() override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnNativeThemeChanged(const ui::NativeTheme* theme) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + + // CustomButton: + void NotifyClick(const ui::Event& event) override; void AddInkDropLayer(ui::Layer* ink_drop_layer) override; void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; std::unique_ptr CreateInkDrop() override; @@ -55,6 +68,7 @@ class VIEWS_EXPORT ToggleButton : public CustomButton { bool is_on_; gfx::SlideAnimation slide_animation_; ThumbView* thumb_view_; + std::unique_ptr focus_painter_; DISALLOW_COPY_AND_ASSIGN(ToggleButton); };