-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added the new class QsSlider to create the new slider for QsRevamp
In this CL, we added a new class QsSlider to create the new slider for the QsRevamp project. Also, a ReadOnlySlider class is added to create the read-only slider for keyboard brightness toast. These two classes will replace the old base slider SystemSlider and ReadOnlySlider defined in UnifiedSliderView. The colors for some parts of the slider are going to be updated once the spec is ready. For a11y, the tooltip is to be added and the focus ring may be updated too. Light mode QuickSettingsSlider v.s. base Slider on main page and audio subpage: https://screenshot.googleplex.com/8LuRYiv8viaREQj Dark mode: https://screenshot.googleplex.com/6TjUZVkiwhuuesC Note that the implementation will be in a separate CL, so only the slider itself is changed in the above screenshots. The icon button will be modified in the implementation. Bug: b/251723605 Change-Id: I6e3228ac44ae6b6279b18ffdedf07e91b0261c8e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3994174 Reviewed-by: Alex Newcomer <newcomer@chromium.org> Commit-Queue: Sylvie Liu <sylvieliu@chromium.org> Reviewed-by: Jiaming Cheng <jiamingc@chromium.org> Cr-Commit-Position: refs/heads/main@{#1067670}
- Loading branch information
Sylvie Liu
authored and
Chromium LUCI CQ
committed
Nov 4, 2022
1 parent
6802fd2
commit 2a93223
Showing
5 changed files
with
335 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "ash/system/unified/quick_settings_slider.h" | ||
|
||
#include "ash/constants/ash_features.h" | ||
#include "ash/style/ash_color_provider.h" | ||
#include "ash/style/color_util.h" | ||
#include "base/notreached.h" | ||
#include "cc/paint/paint_flags.h" | ||
#include "ui/base/metadata/metadata_impl_macros.h" | ||
#include "ui/chromeos/styles/cros_tokens_color_mappings.h" | ||
#include "ui/color/color_id.h" | ||
#include "ui/color/color_provider.h" | ||
#include "ui/events/event.h" | ||
#include "ui/gfx/canvas.h" | ||
#include "ui/gfx/geometry/rect.h" | ||
#include "ui/views/controls/slider.h" | ||
|
||
namespace ash { | ||
|
||
namespace { | ||
|
||
// The thickness of the empty slider. | ||
constexpr int kEmptySliderThickness = 4; | ||
|
||
// The thickness of the full slider. | ||
constexpr int kFullSliderThickness = 32; | ||
|
||
// The radius used to draw the rounded empty slider ends. | ||
constexpr float kEmptySliderRoundedRadius = 2.f; | ||
constexpr float kEmptySliderWidth = 2 * kEmptySliderRoundedRadius; | ||
|
||
// The radius used to draw the rounded full slider ends. | ||
constexpr float kFullSliderRoundedRadius = 16.f; | ||
constexpr float kFullSliderWidth = 2 * kFullSliderRoundedRadius; | ||
|
||
// The radius used to draw the rounded corner for active/inactive slider on the | ||
// audio subpage. | ||
constexpr float kActiveRadioSliderRoundedRadius = 16.f; | ||
// TODO(b/256705775): Replace the actual radius value once the spec is updated. | ||
constexpr float kInactiveRadioSliderRoundedRadius = 8.f; | ||
|
||
// TODO(b/256705775): Replace the value once the spec is updated. | ||
// The thickness of the focus ring border. | ||
constexpr int kLineThickness = 2; | ||
// The gap between the focus ring and the slider. | ||
constexpr int kFocusOffset = 2; | ||
|
||
float GetSliderRoundedCornerRadius(QuickSettingsSlider::Style slider_style) { | ||
switch (slider_style) { | ||
case QuickSettingsSlider::Style::kDefault: | ||
return kFullSliderRoundedRadius; | ||
case QuickSettingsSlider::Style::kRadioActive: | ||
return kActiveRadioSliderRoundedRadius; | ||
case QuickSettingsSlider::Style::kRadioInactive: | ||
return kInactiveRadioSliderRoundedRadius; | ||
default: | ||
NOTREACHED(); | ||
} | ||
} | ||
|
||
} // namespace | ||
|
||
QuickSettingsSlider::QuickSettingsSlider(views::SliderListener* listener, | ||
Style slider_style) | ||
: views::Slider(listener), slider_style_(slider_style) { | ||
if (!features::IsQsRevampEnabled()) | ||
return; | ||
SetValueIndicatorRadius(kFullSliderRoundedRadius); | ||
SetFocusBehavior(FocusBehavior::ALWAYS); | ||
} | ||
|
||
QuickSettingsSlider::~QuickSettingsSlider() = default; | ||
|
||
void QuickSettingsSlider::SetSliderStyle(Style style) { | ||
if (slider_style_ == style) | ||
return; | ||
|
||
slider_style_ = style; | ||
|
||
if (slider_style_ == Style::kRadioInactive) | ||
SetFocusBehavior(FocusBehavior::NEVER); | ||
|
||
SchedulePaint(); | ||
} | ||
|
||
SkColor QuickSettingsSlider::GetThumbColor() const { | ||
// TODO(b/256705775): Updates the color when QsRevamp is disabled but Jelly is | ||
// enabled. | ||
if (!features::IsQsRevampEnabled()) { | ||
using Type = AshColorProvider::ContentLayerType; | ||
return AshColorProvider::Get()->GetContentLayerColor( | ||
(style() == RenderingStyle::kMinimalStyle) ? Type::kSliderColorInactive | ||
: Type::kSliderColorActive); | ||
} | ||
|
||
switch (slider_style_) { | ||
case Style::kDefault: | ||
case Style::kRadioActive: | ||
return GetColorProvider()->GetColor( | ||
static_cast<ui::ColorId>(cros_tokens::kCrosSysSysPrimaryContainer)); | ||
case Style::kRadioInactive: | ||
return GetColorProvider()->GetColor( | ||
static_cast<ui::ColorId>(cros_tokens::kCrosSysDisabled)); | ||
default: | ||
NOTREACHED(); | ||
} | ||
} | ||
|
||
SkColor QuickSettingsSlider::GetTroughColor() const { | ||
// TODO(b/256705775): Updates the color when QsRevamp is disabled but Jelly is | ||
// enabled. | ||
if (!features::IsQsRevampEnabled()) | ||
return ColorUtil::GetSecondToneColor(GetThumbColor()); | ||
|
||
switch (slider_style_) { | ||
case Style::kDefault: | ||
return GetColorProvider()->GetColor( | ||
static_cast<ui::ColorId>(cros_tokens::kCrosSysSysOnBase)); | ||
case Style::kRadioActive: | ||
return GetColorProvider()->GetColor( | ||
static_cast<ui::ColorId>(cros_tokens::kCrosSysHighlightShape)); | ||
case Style::kRadioInactive: | ||
return GetColorProvider()->GetColor( | ||
static_cast<ui::ColorId>(cros_tokens::kCrosSysDisabled)); | ||
default: | ||
NOTREACHED(); | ||
} | ||
} | ||
|
||
void QuickSettingsSlider::OnPaint(gfx::Canvas* canvas) { | ||
// Paints the `QuickSettingsSlider`. If the feature is not enabled, use | ||
// `Slider::OnPaint()`. | ||
if (!ash::features::IsQsRevampEnabled()) { | ||
views::Slider::OnPaint(canvas); | ||
return; | ||
} | ||
|
||
const gfx::Rect content = GetContentsBounds(); | ||
const int width = content.width() - kFullSliderWidth; | ||
const int full_width = GetAnimatingValue() * width + kFullSliderWidth; | ||
const int x = content.x(); | ||
const int y = content.height() / 2 - kFullSliderThickness / 2; | ||
|
||
gfx::Rect empty_slider_rect; | ||
float empty_slider_radius; | ||
switch (slider_style_) { | ||
case Style::kDefault: { | ||
const int empty_width = | ||
width + kFullSliderRoundedRadius - full_width + kEmptySliderWidth; | ||
const int x_empty = x + full_width - kEmptySliderRoundedRadius; | ||
const int y_empty = content.height() / 2 - kEmptySliderThickness / 2; | ||
|
||
empty_slider_rect = | ||
gfx::Rect(x_empty, y_empty, empty_width, kEmptySliderThickness); | ||
empty_slider_radius = kEmptySliderRoundedRadius; | ||
break; | ||
} | ||
case Style::kRadioActive: | ||
case Style::kRadioInactive: { | ||
empty_slider_rect = | ||
gfx::Rect(x, y, content.width(), kFullSliderThickness); | ||
empty_slider_radius = GetSliderRoundedCornerRadius(slider_style_); | ||
break; | ||
} | ||
default: | ||
NOTREACHED(); | ||
} | ||
|
||
cc::PaintFlags slider_flags; | ||
slider_flags.setAntiAlias(true); | ||
|
||
slider_flags.setColor(GetTroughColor()); | ||
canvas->DrawRoundRect(empty_slider_rect, empty_slider_radius, slider_flags); | ||
|
||
slider_flags.setColor(GetThumbColor()); | ||
canvas->DrawRoundRect(gfx::Rect(x, y, full_width, kFullSliderThickness), | ||
GetSliderRoundedCornerRadius(slider_style_), | ||
slider_flags); | ||
|
||
// Paints the focusing ring for the slider. It should be painted last to be | ||
// on the top. | ||
if (HasFocus()) { | ||
cc::PaintFlags highlight_border; | ||
highlight_border.setColor(GetColorProvider()->GetColor( | ||
static_cast<ui::ColorId>(cros_tokens::kCrosSysPrimary))); | ||
highlight_border.setAntiAlias(true); | ||
highlight_border.setStyle(cc::PaintFlags::kStroke_Style); | ||
highlight_border.setStrokeWidth(kLineThickness); | ||
canvas->DrawRoundRect(gfx::Rect(x - kFocusOffset, y - kFocusOffset, | ||
full_width + 2 * kFocusOffset, | ||
kFullSliderThickness + 2 * kFocusOffset), | ||
kFullSliderRoundedRadius, highlight_border); | ||
} | ||
} | ||
|
||
ReadOnlySlider::ReadOnlySlider(Style slider_style) | ||
: QuickSettingsSlider(/*listener=*/nullptr, slider_style) {} | ||
|
||
ReadOnlySlider::~ReadOnlySlider() = default; | ||
|
||
bool ReadOnlySlider::CanAcceptEvent(const ui::Event& event) { | ||
return false; | ||
} | ||
|
||
BEGIN_METADATA(QuickSettingsSlider, views::View) | ||
END_METADATA | ||
|
||
BEGIN_METADATA(ReadOnlySlider, views::View) | ||
END_METADATA | ||
|
||
} // namespace ash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef ASH_SYSTEM_UNIFIED_QUICK_SETTINGS_SLIDER_H_ | ||
#define ASH_SYSTEM_UNIFIED_QUICK_SETTINGS_SLIDER_H_ | ||
|
||
#include "ash/ash_export.h" | ||
#include "ui/views/controls/slider.h" | ||
|
||
namespace gfx { | ||
class Canvas; | ||
} // namespace gfx | ||
|
||
namespace views { | ||
class View; | ||
} // namespace views | ||
|
||
namespace ui { | ||
class Event; | ||
} // namespace ui | ||
|
||
namespace ash { | ||
|
||
// This slider view is used in quick settings in the status area. It will be | ||
// used in the `QuickSettingsView` and `TrayBubbleView`. This slider view | ||
// supports different styles. `kDefault` slider is used in `QuickSettingsView` | ||
// and in `TrayBubbleView`. `kRadioActive` slider will be used for the active | ||
// input/output device in `AudioDetailedView`. `kRadioInactive` slider will be | ||
// used for the inactive device in `AudioDetailedView`. | ||
class ASH_EXPORT QuickSettingsSlider : public views::Slider { | ||
public: | ||
METADATA_HEADER(QuickSettingsSlider); | ||
|
||
// Represents the style of the slider. | ||
enum class Style { | ||
// Represents the slider where the full part is a rounded corner rectangle | ||
// with a height of `kFullSliderThickness`, and the empty part is a rounded | ||
// corner rectangle with a height of `kEmptySliderThickness`. These two | ||
// parts are center-aligned horizontally. The ends of both parts have fully | ||
// rounded corners. | ||
kDefault, | ||
// Represents the style where both the full part and the empty part of the | ||
// slider have a height of `kFullSliderThickness`. The ends are fully | ||
// rounded. | ||
kRadioActive, | ||
// Represents the style where the full part and the empty part also have the | ||
// same height of `kFullSliderThickness`, except that the ends are not fully | ||
// rounded but have a radius of `kInactiveRadioSliderRoundedRadius`. | ||
kRadioInactive | ||
}; | ||
|
||
QuickSettingsSlider(views::SliderListener* listener, Style slider_style); | ||
QuickSettingsSlider(const QuickSettingsSlider&) = delete; | ||
QuickSettingsSlider& operator=(const QuickSettingsSlider&) = delete; | ||
~QuickSettingsSlider() override; | ||
|
||
// Setter and Getter of the slider style. Schedules paint after setting the | ||
// style since styles and colors may change for the radio sliders because of | ||
// the active status change. If the slider is the `kRadioInactive`, also | ||
// disables the focus behavior for it. | ||
void SetSliderStyle(Style style); | ||
Style slider_style() const { return slider_style_; } | ||
|
||
private: | ||
// views::Slider: | ||
SkColor GetThumbColor() const override; | ||
SkColor GetTroughColor() const override; | ||
|
||
// views::View: | ||
void OnPaint(gfx::Canvas* canvas) override; | ||
|
||
Style slider_style_; | ||
}; | ||
|
||
// A slider that ignores inputs. This will be used in the | ||
// `UnifiedKeyboardBrightnessView` and `UnifiedKeyboardBacklightToggleView`. | ||
class ASH_EXPORT ReadOnlySlider : public QuickSettingsSlider { | ||
public: | ||
METADATA_HEADER(ReadOnlySlider); | ||
|
||
explicit ReadOnlySlider(Style slider_style); | ||
ReadOnlySlider(const ReadOnlySlider&) = delete; | ||
ReadOnlySlider& operator=(const ReadOnlySlider&) = delete; | ||
~ReadOnlySlider() override; | ||
|
||
private: | ||
// views::View: | ||
bool CanAcceptEvent(const ui::Event& event) override; | ||
}; | ||
|
||
} // namespace ash | ||
|
||
#endif // ASH_SYSTEM_UNIFIED_QUICK_SETTINGS_SLIDER_H_ |
Oops, something went wrong.