#include "ash/style/tab_slider_button.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/style/color_util.h"
#include "ash/style/style_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/border.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
namespace ash {
namespace {
constexpr ui::ColorId kSelectedColorId =
cros_tokens::kCrosSysSystemOnPrimaryContainer;
constexpr ui::ColorId kDisabledSelectedColorId =
cros_tokens::kCrosSysSystemOnPrimaryContainerDisabled;
constexpr ui::ColorId kUnselectedColorId = cros_tokens::kCrosSysOnSurface;
constexpr ui::ColorId kDisabledUnselectedColorId =
cros_tokens::kCrosSysDisabled;
constexpr int kFocusRingPadding = 2;
constexpr int kIconButtonSize = 32;
constexpr int kIconSize = 20;
constexpr int kIconSliderInternalBorderPadding = 2;
constexpr int kIconSliderBetweenButtonsSpacing = 0;
constexpr int kLabelButtonHeight = 32;
constexpr int kLabelButtonMinWidth = 80;
constexpr int kLabelSliderInternalBorderPadding = 2;
constexpr int kLabelSliderBetweenButtonsSpacing = 0;
constexpr gfx::Insets kLabelButtonBorderInsets = gfx::Insets::VH(6, 16);
constexpr int kIconLabelSliderInternalBorderPadding = 4;
constexpr int kIconLabelSliderBetweenButtonsSpacing = 0;
}
TabSliderButton::TabSliderButton(PressedCallback callback)
: views::Button(std::move(callback)) {
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
auto* focus_ring = views::FocusRing::Get(this);
focus_ring->SetColorId(cros_tokens::kCrosSysFocusRing);
const float halo_inset =
focus_ring->GetHaloThickness() / 2.f + kFocusRingPadding;
focus_ring->SetHaloInset(-halo_inset);
focus_ring->SetPathGenerator(
std::make_unique<views::PillHighlightPathGenerator>());
views::InstallPillHighlightPathGenerator(this);
}
TabSliderButton::~TabSliderButton() = default;
void TabSliderButton::AddedToSlider(TabSlider* tab_slider) {
DCHECK(tab_slider);
tab_slider_ = tab_slider;
}
void TabSliderButton::SetSelected(bool selected) {
if (selected_ == selected) {
return;
}
selected_ = selected;
if (selected_ && tab_slider_) {
tab_slider_->OnButtonSelected(this);
}
OnSelectedChanged();
}
SkColor TabSliderButton::GetColorIdOnButtonState() {
const bool enabled = GetEnabled();
return selected()
? (enabled ? kSelectedColorId : kDisabledSelectedColorId)
: (enabled ? kUnselectedColorId : kDisabledUnselectedColorId);
}
void TabSliderButton::NotifyClick(const ui::Event& event) {
SetSelected(true);
views::Button::NotifyClick(event);
}
absl::optional<TabSlider::LayoutParams>
TabSliderButton::GetRecommendedSliderLayout() const {
return absl::nullopt;
}
BEGIN_METADATA(TabSliderButton, views::Button)
END_METADATA
IconSliderButton::IconSliderButton(PressedCallback callback,
const gfx::VectorIcon* icon,
const std::u16string& tooltip_text)
: TabSliderButton(std::move(callback)), icon_(icon) {
SetPreferredSize(gfx::Size(kIconButtonSize, kIconButtonSize));
SetTooltipText(tooltip_text);
auto* focus_ring = views::FocusRing::Get(this);
focus_ring->SetPathGenerator(
std::make_unique<views::CircleHighlightPathGenerator>(-gfx::Insets(
focus_ring->GetHaloThickness() / 2 + kFocusRingPadding)));
views::InstallCircleHighlightPathGenerator(this);
}
IconSliderButton::~IconSliderButton() = default;
void IconSliderButton::OnSelectedChanged() {
SchedulePaint();
}
absl::optional<TabSlider::LayoutParams>
IconSliderButton::GetRecommendedSliderLayout() const {
return TabSlider::LayoutParams{kIconSliderInternalBorderPadding,
kIconSliderBetweenButtonsSpacing};
}
void IconSliderButton::OnThemeChanged() {
views::View::OnThemeChanged();
SchedulePaint();
}
void IconSliderButton::PaintButtonContents(gfx::Canvas* canvas) {
DCHECK(GetWidget());
const gfx::ImageSkia img = gfx::CreateVectorIcon(
*icon_, kIconSize,
GetColorProvider()->GetColor(GetColorIdOnButtonState()));
const int origin_offset = (kIconButtonSize - kIconSize) / 2;
canvas->DrawImageInt(img, origin_offset, origin_offset);
}
BEGIN_METADATA(IconSliderButton, TabSliderButton)
END_METADATA
LabelSliderButton::LabelSliderButton(PressedCallback callback,
const std::u16string& text,
const std::u16string& tooltip_text)
: TabSliderButton(std::move(callback)),
label_(AddChildView(std::make_unique<views::Label>(text))) {
SetBorder(views::CreateEmptyBorder(kLabelButtonBorderInsets));
SetUseDefaultFillLayout(true);
SetTooltipText(tooltip_text);
SetAccessibleName(text);
label_->SetAutoColorReadabilityEnabled(false);
}
LabelSliderButton::~LabelSliderButton() = default;
absl::optional<TabSlider::LayoutParams>
LabelSliderButton::GetRecommendedSliderLayout() const {
return TabSlider::LayoutParams{kLabelSliderInternalBorderPadding,
kLabelSliderBetweenButtonsSpacing};
}
void LabelSliderButton::UpdateLabelColor() {
label_->SetEnabledColorId(GetColorIdOnButtonState());
SchedulePaint();
}
void LabelSliderButton::OnSelectedChanged() {
UpdateLabelColor();
}
int LabelSliderButton::GetHeightForWidth(int w) const {
return kLabelButtonHeight;
}
gfx::Size LabelSliderButton::CalculatePreferredSize() const {
return gfx::Size(
std::max(label_->GetPreferredSize().width() + GetInsets().width(),
kLabelButtonMinWidth),
kLabelButtonHeight);
}
void LabelSliderButton::StateChanged(ButtonState old_state) {
if (old_state != ButtonState::STATE_DISABLED &&
GetState() != ButtonState::STATE_DISABLED) {
return;
}
UpdateLabelColor();
}
BEGIN_METADATA(LabelSliderButton, TabSliderButton)
END_METADATA
IconLabelSliderButton::IconLabelSliderButton(PressedCallback callback,
const gfx::VectorIcon* icon,
const std::u16string& text,
const std::u16string& tooltip_text)
: TabSliderButton(std::move(callback)),
image_view_(AddChildView(std::make_unique<views::ImageView>())),
label_(AddChildView(std::make_unique<views::Label>(text))) {
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical,
gfx::Insets::VH(8, 16),
8));
DCHECK(icon);
image_view_->SetImage(ui::ImageModel::FromImageGenerator(
base::BindRepeating(
[](TabSliderButton* tab_slider_button,
const gfx::VectorIcon* vector_icon, const ui::ColorProvider*) {
return gfx::CreateVectorIcon(
*vector_icon, kIconSize,
tab_slider_button->GetColorProvider()->GetColor(
tab_slider_button->GetColorIdOnButtonState()));
},
this, icon),
gfx::Size(kIconSize, kIconSize)));
label_->SetAutoColorReadabilityEnabled(false);
SetAccessibleName(text);
SetTooltipText(tooltip_text);
}
IconLabelSliderButton::~IconLabelSliderButton() = default;
absl::optional<TabSlider::LayoutParams>
IconLabelSliderButton::GetRecommendedSliderLayout() const {
return TabSlider::LayoutParams{kIconLabelSliderInternalBorderPadding,
kIconLabelSliderBetweenButtonsSpacing};
}
void IconLabelSliderButton::UpdateColors() {
label_->SetEnabledColorId(GetColorIdOnButtonState());
SchedulePaint();
}
void IconLabelSliderButton::OnSelectedChanged() {
UpdateColors();
}
BEGIN_METADATA(IconLabelSliderButton, TabSliderButton)
END_METADATA
}