Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/controls/button/toggle_button.h" | 5 #include "ui/views/controls/button/toggle_button.h" |
| 6 | 6 |
| 7 #include "third_party/skia/include/core/SkDrawLooper.h" | 7 #include "third_party/skia/include/core/SkDrawLooper.h" |
| 8 #include "third_party/skia/include/core/SkPaint.h" | 8 #include "third_party/skia/include/core/SkPaint.h" |
| 9 #include "ui/gfx/canvas.h" | 9 #include "ui/gfx/canvas.h" |
| 10 #include "ui/gfx/color_palette.h" | 10 #include "ui/gfx/color_palette.h" |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 const int kThumbHorizontalMargin = 4; | 27 const int kThumbHorizontalMargin = 4; |
| 28 // Margin from top/bottom edge of thumb to top/bottom edge of view. | 28 // Margin from top/bottom edge of thumb to top/bottom edge of view. |
| 29 const int kThumbVerticalMargin = 3; | 29 const int kThumbVerticalMargin = 3; |
| 30 | 30 |
| 31 // TODO(estade): get the base color (black) from the theme? | 31 // TODO(estade): get the base color (black) from the theme? |
| 32 const SkColor kTrackOffColor = | 32 const SkColor kTrackOffColor = |
| 33 SkColorSetA(SK_ColorBLACK, gfx::kDisabledControlAlpha); | 33 SkColorSetA(SK_ColorBLACK, gfx::kDisabledControlAlpha); |
| 34 | 34 |
| 35 } // namespace | 35 } // namespace |
| 36 | 36 |
| 37 // Class representing the thumb. When the thumb is clicked it is separated into | |
| 38 // its own layer and the ink drop layer is made a child of the thumb layer | |
| 39 // allowing the two to animate in sync. | |
| 40 class ToggleButton::ThumbView : public views::View { | |
| 41 public: | |
| 42 ThumbView(views::View* parent) : color_ratio_(0.) { | |
|
sadrul
2016/10/13 03:30:23
explicit
Or may be better: AddChild() from the ca
varkha
2016/10/13 17:04:56
I like your second choice more. Done.
| |
| 43 parent->AddChildView(this); | |
| 44 } | |
| 45 ~ThumbView() override {} | |
| 46 | |
| 47 void AddInkDropLayer(ui::Layer* ink_drop_layer) { | |
| 48 SetPaintToLayer(true); | |
| 49 layer()->SetFillsBoundsOpaquely(false); | |
| 50 layer()->Add(ink_drop_layer); | |
| 51 } | |
| 52 | |
| 53 void RemoveInkDropLayer(ui::Layer* ink_drop_layer) { | |
| 54 layer()->Remove(ink_drop_layer); | |
| 55 SetPaintToLayer(false); | |
| 56 } | |
| 57 | |
| 58 void Update(const gfx::Rect& bounds, double color_ratio) { | |
| 59 SetBoundsRect(bounds); | |
| 60 color_ratio_ = color_ratio; | |
| 61 SchedulePaint(); | |
| 62 } | |
| 63 | |
| 64 private: | |
| 65 // views::View: | |
| 66 const char* GetClassName() const override { | |
| 67 return "ToggleButton::ThumbView"; | |
| 68 } | |
| 69 | |
| 70 void OnPaint(gfx::Canvas* canvas) override { | |
| 71 std::vector<gfx::ShadowValue> shadows; | |
| 72 shadows.emplace_back(gfx::Vector2d(0, 1), 4.f, | |
| 73 SkColorSetA(SK_ColorBLACK, 0x99)); | |
| 74 SkPaint thumb_paint; | |
| 75 thumb_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows)); | |
| 76 thumb_paint.setStyle(SkPaint::kFill_Style); | |
| 77 thumb_paint.setAntiAlias(true); | |
| 78 const SkColor thumb_on_color = GetNativeTheme()->GetSystemColor( | |
| 79 ui::NativeTheme::kColorId_ProminentButtonColor); | |
| 80 // TODO(estade): get this color from the theme? | |
| 81 const SkColor thumb_off_color = SK_ColorWHITE; | |
| 82 const SkAlpha blend = static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio_); | |
| 83 thumb_paint.setColor( | |
| 84 color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend)); | |
| 85 gfx::Rect thumb_bounds = GetLocalBounds(); | |
| 86 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin)); | |
| 87 canvas->DrawCircle(gfx::RectF(thumb_bounds).CenterPoint(), | |
| 88 thumb_bounds.height() / 2.f, thumb_paint); | |
| 89 } | |
| 90 | |
| 91 // Color ratio between 0 and 1 that controls the thumb color. | |
| 92 double color_ratio_; | |
| 93 | |
| 94 DISALLOW_COPY_AND_ASSIGN(ThumbView); | |
| 95 }; | |
| 96 | |
| 37 ToggleButton::ToggleButton(ButtonListener* listener) | 97 ToggleButton::ToggleButton(ButtonListener* listener) |
| 38 : CustomButton(listener), is_on_(false), slide_animation_(this) { | 98 : CustomButton(listener), |
| 99 is_on_(false), | |
| 100 slide_animation_(this), | |
| 101 thumb_view_(new ToggleButton::ThumbView(this)) { | |
| 39 slide_animation_.SetSlideDuration(80 /* ms */); | 102 slide_animation_.SetSlideDuration(80 /* ms */); |
| 40 slide_animation_.SetTweenType(gfx::Tween::LINEAR); | 103 slide_animation_.SetTweenType(gfx::Tween::LINEAR); |
| 41 SetBorder(Border::CreateEmptyBorder( | 104 SetBorder(Border::CreateEmptyBorder( |
| 42 gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin))); | 105 gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin))); |
| 43 SetInkDropMode(InkDropMode::ON); | 106 SetInkDropMode(InkDropMode::ON); |
| 44 set_has_ink_drop_action_on_click(true); | 107 set_has_ink_drop_action_on_click(true); |
| 45 } | 108 } |
| 46 | 109 |
| 47 ToggleButton::~ToggleButton() {} | 110 ToggleButton::~ToggleButton() { |
| 111 thumb_view_.reset(); | |
| 112 } | |
| 48 | 113 |
| 49 void ToggleButton::SetIsOn(bool is_on, bool animate) { | 114 void ToggleButton::SetIsOn(bool is_on, bool animate) { |
| 50 if (is_on_ == is_on) | 115 if (is_on_ == is_on) |
| 51 return; | 116 return; |
| 52 | 117 |
| 53 is_on_ = is_on; | 118 is_on_ = is_on; |
| 54 if (!animate) | 119 if (!animate) |
| 55 slide_animation_.Reset(is_on_ ? 1.0 : 0.0); | 120 slide_animation_.Reset(is_on_ ? 1.0 : 0.0); |
| 56 else if (is_on_) | 121 else if (is_on_) |
| 57 slide_animation_.Show(); | 122 slide_animation_.Show(); |
| 58 else | 123 else |
| 59 slide_animation_.Hide(); | 124 slide_animation_.Hide(); |
| 60 } | 125 } |
| 61 | 126 |
| 62 gfx::Size ToggleButton::GetPreferredSize() const { | 127 gfx::Size ToggleButton::GetPreferredSize() const { |
| 63 gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight); | 128 gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight); |
| 64 if (border()) | 129 if (border()) |
| 65 rect.Inset(-border()->GetInsets()); | 130 rect.Inset(-border()->GetInsets()); |
| 66 return rect.size(); | 131 return rect.size(); |
| 67 } | 132 } |
| 68 | 133 |
| 134 const char* ToggleButton::GetClassName() const { | |
| 135 return "ToggleButton"; | |
| 136 } | |
| 137 | |
| 69 void ToggleButton::OnPaint(gfx::Canvas* canvas) { | 138 void ToggleButton::OnPaint(gfx::Canvas* canvas) { |
| 70 SkAlpha blend = | 139 const double color_ratio = slide_animation_.GetCurrentValue(); |
| 71 static_cast<SkAlpha>(SK_AlphaOPAQUE * slide_animation_.GetCurrentValue()); | 140 SkAlpha blend = static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio); |
| 72 | 141 |
| 73 // Track. | 142 // Track. |
| 74 gfx::RectF track_rect(GetContentsBounds()); | 143 gfx::RectF track_rect(GetContentsBounds()); |
| 75 SkPaint track_paint; | 144 SkPaint track_paint; |
| 76 track_paint.setAntiAlias(true); | 145 track_paint.setAntiAlias(true); |
| 77 const SkColor track_on_color = | 146 const SkColor track_on_color = |
| 78 SkColorSetA(GetNativeTheme()->GetSystemColor( | 147 SkColorSetA(GetNativeTheme()->GetSystemColor( |
| 79 ui::NativeTheme::kColorId_ProminentButtonColor), | 148 ui::NativeTheme::kColorId_ProminentButtonColor), |
| 80 0xFF / 2); | 149 0xFF / 2); |
| 81 track_paint.setColor( | 150 track_paint.setColor( |
| 82 color_utils::AlphaBlend(track_on_color, kTrackOffColor, blend)); | 151 color_utils::AlphaBlend(track_on_color, kTrackOffColor, blend)); |
| 83 canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint); | 152 canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint); |
| 84 | |
| 85 // Thumb. | |
| 86 gfx::Rect thumb_bounds = GetThumbBounds(); | |
| 87 SkPaint thumb_paint; | |
| 88 std::vector<gfx::ShadowValue> shadows; | |
| 89 shadows.emplace_back(gfx::Vector2d(0, 1), 4.f, | |
| 90 SkColorSetA(SK_ColorBLACK, 0x99)); | |
| 91 thumb_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows)); | |
| 92 thumb_paint.setStyle(SkPaint::kFill_Style); | |
| 93 thumb_paint.setAntiAlias(true); | |
| 94 const SkColor thumb_on_color = GetNativeTheme()->GetSystemColor( | |
| 95 ui::NativeTheme::kColorId_ProminentButtonColor); | |
| 96 // TODO(estade): get this color from the theme? | |
| 97 const SkColor thumb_off_color = SK_ColorWHITE; | |
| 98 thumb_paint.setColor( | |
| 99 color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend)); | |
| 100 canvas->DrawCircle(gfx::RectF(thumb_bounds).CenterPoint(), | |
| 101 thumb_bounds.height() / 2.f, thumb_paint); | |
| 102 } | 153 } |
| 103 | 154 |
| 104 void ToggleButton::NotifyClick(const ui::Event& event) { | 155 void ToggleButton::NotifyClick(const ui::Event& event) { |
| 105 SetIsOn(!is_on(), true); | 156 SetIsOn(!is_on(), true); |
| 106 CustomButton::NotifyClick(event); | 157 CustomButton::NotifyClick(event); |
| 107 } | 158 } |
| 108 | 159 |
| 160 void ToggleButton::OnBoundsChanged(const gfx::Rect& previous_bounds) { | |
| 161 UpdateThumb(); | |
| 162 } | |
| 163 | |
| 109 void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) { | 164 void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) { |
| 110 SchedulePaint(); | 165 SchedulePaint(); |
| 111 } | 166 } |
| 112 | 167 |
| 168 void ToggleButton::AddInkDropLayer(ui::Layer* ink_drop_layer) { | |
| 169 thumb_view_->AddInkDropLayer(ink_drop_layer); | |
| 170 UpdateThumb(); | |
| 171 SchedulePaint(); | |
| 172 } | |
| 173 | |
| 174 void ToggleButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { | |
| 175 thumb_view_->RemoveInkDropLayer(ink_drop_layer); | |
| 176 SchedulePaint(); | |
| 177 } | |
| 178 | |
| 113 std::unique_ptr<InkDropRipple> ToggleButton::CreateInkDropRipple() const { | 179 std::unique_ptr<InkDropRipple> ToggleButton::CreateInkDropRipple() const { |
| 114 return CreateDefaultInkDropRipple(GetThumbBounds().CenterPoint()); | 180 const int radius = (kTrackHeight + kTrackVerticalMargin * 2) / 2; |
| 181 return CreateDefaultInkDropRipple(gfx::Point(radius, radius)); | |
| 115 } | 182 } |
| 116 | 183 |
| 117 SkColor ToggleButton::GetInkDropBaseColor() const { | 184 SkColor ToggleButton::GetInkDropBaseColor() const { |
| 118 return is_on() | 185 return is_on() |
| 119 ? GetNativeTheme()->GetSystemColor( | 186 ? GetNativeTheme()->GetSystemColor( |
| 120 ui::NativeTheme::kColorId_ProminentButtonColor) | 187 ui::NativeTheme::kColorId_ProminentButtonColor) |
| 121 : kTrackOffColor; | 188 : kTrackOffColor; |
| 122 } | 189 } |
| 123 | 190 |
| 124 bool ToggleButton::ShouldShowInkDropHighlight() const { | 191 bool ToggleButton::ShouldShowInkDropHighlight() const { |
| 125 return false; | 192 return false; |
| 126 } | 193 } |
| 127 | 194 |
| 128 void ToggleButton::AnimationProgressed(const gfx::Animation* animation) { | 195 void ToggleButton::AnimationProgressed(const gfx::Animation* animation) { |
| 129 if (animation == &slide_animation_) | 196 if (animation == &slide_animation_) { |
| 197 UpdateThumb(); | |
| 130 SchedulePaint(); | 198 SchedulePaint(); |
|
sadrul
2016/10/13 03:30:23
Now that the thumb is a separate View, it would be
varkha
2016/10/13 17:04:56
Acknowledged. Added a TODO for a possible followup
| |
| 131 else | 199 return; |
| 132 CustomButton::AnimationProgressed(animation); | 200 } |
| 201 CustomButton::AnimationProgressed(animation); | |
| 133 } | 202 } |
| 134 | 203 |
| 135 gfx::Rect ToggleButton::GetThumbBounds() const { | 204 gfx::Rect ToggleButton::GetThumbBounds() const { |
| 136 gfx::Rect thumb_bounds = GetLocalBounds(); | 205 gfx::Rect thumb_bounds = GetLocalBounds(); |
| 137 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin)); | 206 thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin)); |
| 138 thumb_bounds.set_x(thumb_bounds.x() + | 207 thumb_bounds.set_x(thumb_bounds.x() + |
| 139 slide_animation_.GetCurrentValue() * | 208 slide_animation_.GetCurrentValue() * |
| 140 (thumb_bounds.width() - thumb_bounds.height())); | 209 (thumb_bounds.width() - thumb_bounds.height())); |
| 141 // The thumb is a circle, so the width should match the height. | 210 // The thumb is a circle, so the width should match the height. |
| 142 thumb_bounds.set_width(thumb_bounds.height()); | 211 thumb_bounds.set_width(thumb_bounds.height()); |
| 143 thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds)); | 212 thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds)); |
| 144 return thumb_bounds; | 213 return thumb_bounds; |
| 145 } | 214 } |
| 146 | 215 |
| 216 void ToggleButton::UpdateThumb() { | |
| 217 gfx::Rect thumb_bounds = GetThumbBounds(); | |
| 218 thumb_bounds.Inset(gfx::Insets(-kThumbVerticalMargin)); | |
| 219 thumb_view_->Update(thumb_bounds, slide_animation_.GetCurrentValue()); | |
| 220 } | |
| 221 | |
| 147 } // namespace views | 222 } // namespace views |
| OLD | NEW |