chromium/ash/system/accessibility/floating_menu_button.cc

// 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