// Copyright 2020 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/accessibility/floating_menu_button.h"
#include <utility>
#include "ash/style/ash_color_id.h"
#include "ash/style/color_util.h"
#include "ash/style/style_util.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/models/image_model.h"
#include "ui/color/color_id.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
#include "ui/gfx/vector_icon_utils.h"
#include "ui/views/accessibility/view_accessibility.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"
#include "ui/views/animation/ink_drop_mask.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/highlight_path_generator.h"
namespace ash {
FloatingMenuButton::FloatingMenuButton() {
SetImageHorizontalAlignment(ALIGN_CENTER);
SetImageVerticalAlignment(ALIGN_MIDDLE);
SetFlipCanvasOnPaintForRTLUI(false);
StyleUtil::SetUpInkDropForButton(this);
views::InstallCircleHighlightPathGenerator(this);
UpdateAccessibleProperties();
}
FloatingMenuButton::FloatingMenuButton(views::Button::PressedCallback callback,
const gfx::VectorIcon& icon,
int accessible_name_id,
bool flip_for_rtl)
: FloatingMenuButton(std::move(callback),
icon,
accessible_name_id,
flip_for_rtl,
/*size=*/kTrayItemSize,
/*draw_highlight=*/true,
/*is_a11y_togglable=*/true) {
UpdateAccessibleProperties();
}
FloatingMenuButton::FloatingMenuButton(views::Button::PressedCallback callback,
const gfx::VectorIcon& icon,
int accessible_name_id,
bool flip_for_rtl,
int size,
bool draw_highlight,
bool is_a11y_togglable)
: views::ImageButton(std::move(callback)),
icon_(&icon),
size_(size),
draw_highlight_(draw_highlight),
is_a11y_togglable_(is_a11y_togglable) {
SetImageHorizontalAlignment(ALIGN_CENTER);
SetImageVerticalAlignment(ALIGN_MIDDLE);
UpdateImage();
SetFlipCanvasOnPaintForRTLUI(flip_for_rtl);
SetPreferredSize(gfx::Size(size_, size_));
StyleUtil::SetUpInkDropForButton(this);
views::InstallCircleHighlightPathGenerator(this);
SetTooltipText(l10n_util::GetStringUTF16(accessible_name_id));
views::FocusRing::Get(this)->SetColorId(ui::kColorAshFocusRing);
UpdateAccessibleProperties();
}
FloatingMenuButton::~FloatingMenuButton() = default;
void FloatingMenuButton::SetVectorIcon(const gfx::VectorIcon& icon) {
if (icon_ == &icon) {
return;
}
icon_ = &icon;
UpdateImage();
}
bool FloatingMenuButton::GetA11yTogglable() const {
return is_a11y_togglable_;
}
void FloatingMenuButton::SetA11yTogglable(bool a11y_togglable) {
if (a11y_togglable == is_a11y_togglable_) {
return;
}
is_a11y_togglable_ = a11y_togglable;
UpdateAccessibleProperties();
OnPropertyChanged(&is_a11y_togglable_, views::kPropertyEffectsPaint);
}
bool FloatingMenuButton::GetDrawHighlight() const {
return draw_highlight_;
}
void FloatingMenuButton::SetDrawHighlight(bool draw_highlight) {
if (draw_highlight_ == draw_highlight) {
return;
}
draw_highlight_ = draw_highlight;
OnPropertyChanged(&draw_highlight_, views::kPropertyEffectsPaint);
}
bool FloatingMenuButton::GetToggled() const {
return toggled_;
}
void FloatingMenuButton::SetToggled(bool toggled) {
if (toggled_ == toggled) {
return;
}
toggled_ = toggled;
UpdateAccessibleProperties();
UpdateImage();
OnPropertyChanged(&toggled_, views::PropertyEffects::kPropertyEffectsPaint);
}
void FloatingMenuButton::PaintButtonContents(gfx::Canvas* canvas) {
if (draw_highlight_) {
gfx::Rect rect(GetContentsBounds());
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setColor(GetColorProvider()->GetColor(
toggled_ ? kColorAshControlBackgroundColorActive
: kColorAshControlBackgroundColorInactive));
flags.setStyle(cc::PaintFlags::kFill_Style);
canvas->DrawCircle(gfx::PointF(rect.CenterPoint()), size_ / 2, flags);
}
views::ImageButton::PaintButtonContents(canvas);
}
gfx::Size FloatingMenuButton::CalculatePreferredSize(
const views::SizeBounds& available_size) const {
return gfx::Size(size_, size_);
}
void FloatingMenuButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
if (!GetEnabled()) {
return;
}
views::ImageButton::GetAccessibleNodeData(node_data);
}
void FloatingMenuButton::UpdateImage() {
DCHECK(icon_);
const ui::ColorId icon_color_id =
toggled_ ? kColorAshButtonIconColorPrimary : kColorAshButtonIconColor;
SetImageModel(views::Button::STATE_NORMAL,
ui::ImageModel::FromVectorIcon(*icon_, icon_color_id));
SetImageModel(
views::Button::STATE_DISABLED,
ui::ImageModel::FromVectorIcon(*icon_, kColorAshButtonIconDisabledColor));
}
void FloatingMenuButton::UpdateAccessibleProperties() {
GetViewAccessibility().SetRole(is_a11y_togglable_
? ax::mojom::Role::kToggleButton
: ax::mojom::Role::kButton);
GetViewAccessibility().SetCheckedState(toggled_
? ax::mojom::CheckedState::kTrue
: ax::mojom::CheckedState::kFalse);
}
BEGIN_METADATA(FloatingMenuButton)
ADD_PROPERTY_METADATA(bool, A11yTogglable)
ADD_PROPERTY_METADATA(bool, DrawHighlight)
ADD_PROPERTY_METADATA(bool, Toggled)
END_METADATA
} // namespace ash