123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/app_list/views/search_result_actions_view.h"
- #include <stddef.h>
- #include <algorithm>
- #include <memory>
- #include "ash/app_list/app_list_util.h"
- #include "ash/app_list/views/search_result_actions_view_delegate.h"
- #include "ash/app_list/views/search_result_view.h"
- #include "ash/constants/ash_features.h"
- #include "ash/public/cpp/app_list/app_list_color_provider.h"
- #include "ash/public/cpp/app_list/app_list_config.h"
- #include "ash/public/cpp/app_list/vector_icons/vector_icons.h"
- #include "ash/public/cpp/style/scoped_light_mode_as_default.h"
- #include "ash/style/icon_button.h"
- #include "base/bind.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "ui/base/resource/resource_bundle.h"
- #include "ui/gfx/canvas.h"
- #include "ui/gfx/geometry/insets.h"
- #include "ui/gfx/image/image_skia_operations.h"
- #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
- #include "ui/views/animation/ink_drop.h"
- #include "ui/views/animation/ink_drop_highlight.h"
- #include "ui/views/border.h"
- #include "ui/views/controls/button/image_button.h"
- #include "ui/views/controls/button/md_text_button.h"
- #include "ui/views/controls/highlight_path_generator.h"
- #include "ui/views/layout/box_layout.h"
- namespace ash {
- namespace {
- constexpr int kActionButtonBetweenSpacing = 8;
- } // namespace
- // SearchResultActionButton renders the button defined by SearchResult::Action.
- class SearchResultActionButton : public IconButton {
- public:
- SearchResultActionButton(SearchResultActionsView* parent,
- const SearchResult::Action& action,
- PressedCallback callback,
- Type type,
- const gfx::VectorIcon* icon,
- const std::u16string& accessible_name);
- SearchResultActionButton(const SearchResultActionButton&) = delete;
- SearchResultActionButton& operator=(const SearchResultActionButton&) = delete;
- ~SearchResultActionButton() override {}
- // IconButton:
- void OnGestureEvent(ui::GestureEvent* event) override;
- void OnThemeChanged() override;
- // Updates the button visibility upon state change of the button or the
- // search result view associated with it.
- void UpdateOnStateChanged();
- private:
- // views::ImageButton:
- void OnPaintBackground(gfx::Canvas* canvas) override;
- int GetButtonRadius() const;
- const char* GetClassName() const override;
- SearchResultActionsView* parent_;
- const bool visible_on_hover_;
- bool to_be_activate_by_long_press_ = false;
- };
- SearchResultActionButton::SearchResultActionButton(
- SearchResultActionsView* parent,
- const SearchResult::Action& action,
- PressedCallback callback,
- Type type,
- const gfx::VectorIcon* icon,
- const std::u16string& accessible_name)
- : IconButton(callback,
- type,
- icon,
- action.tooltip_text,
- /*is_togglable=*/false,
- /*has_border=*/false),
- parent_(parent),
- visible_on_hover_(action.visible_on_hover) {
- SetFocusBehavior(FocusBehavior::ALWAYS);
- SetVisible(!visible_on_hover_);
- }
- void SearchResultActionButton::OnGestureEvent(ui::GestureEvent* event) {
- switch (event->type()) {
- case ui::ET_GESTURE_LONG_PRESS:
- to_be_activate_by_long_press_ = true;
- event->SetHandled();
- break;
- case ui::ET_GESTURE_END:
- if (to_be_activate_by_long_press_) {
- NotifyClick(*event);
- SetState(STATE_NORMAL);
- to_be_activate_by_long_press_ = false;
- event->SetHandled();
- }
- break;
- default:
- break;
- }
- if (!event->handled())
- Button::OnGestureEvent(event);
- }
- void SearchResultActionButton::OnThemeChanged() {
- absl::optional<ScopedLightModeAsDefault> default_light_mode;
- // Non-productivity launcher search UI has light background.
- if (!features::IsProductivityLauncherEnabled())
- default_light_mode.emplace();
- IconButton::OnThemeChanged();
- }
- void SearchResultActionButton::UpdateOnStateChanged() {
- // Show button if the associated result row is hovered or selected, or one
- // of the action buttons is selected.
- if (visible_on_hover_)
- SetVisible(parent_->IsSearchResultHoveredOrSelected());
- }
- void SearchResultActionButton::OnPaintBackground(gfx::Canvas* canvas) {
- if (HasFocus() || parent_->GetSelectedAction() == tag()) {
- PaintFocusRing(canvas, GetLocalBounds().CenterPoint(), GetButtonRadius());
- }
- }
- int SearchResultActionButton::GetButtonRadius() const {
- return width() / 2;
- }
- const char* SearchResultActionButton::GetClassName() const {
- return "SearchResultActionButton";
- }
- SearchResultActionsView::SearchResultActionsView(
- SearchResultActionsViewDelegate* delegate)
- : delegate_(delegate) {
- DCHECK(delegate_);
- SetLayoutManager(std::make_unique<views::BoxLayout>(
- views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
- kActionButtonBetweenSpacing));
- }
- SearchResultActionsView::~SearchResultActionsView() {}
- void SearchResultActionsView::SetActions(const SearchResult::Actions& actions) {
- if (selected_action_.has_value())
- selected_action_.reset();
- subscriptions_.clear();
- RemoveAllChildViews();
- for (size_t i = 0; i < actions.size(); ++i)
- CreateImageButton(actions[i], i);
- PreferredSizeChanged();
- }
- bool SearchResultActionsView::IsValidActionIndex(size_t action_index) const {
- return action_index < GetActionCount();
- }
- bool SearchResultActionsView::IsSearchResultHoveredOrSelected() const {
- return delegate_->IsSearchResultHoveredOrSelected();
- }
- void SearchResultActionsView::HideActions() {
- for (views::View* child : children())
- child->SetVisible(false);
- }
- void SearchResultActionsView::UpdateButtonsOnStateChanged() {
- for (views::View* child : children())
- static_cast<SearchResultActionButton*>(child)->UpdateOnStateChanged();
- }
- const char* SearchResultActionsView::GetClassName() const {
- return "SearchResultActionsView";
- }
- bool SearchResultActionsView::SelectInitialAction(bool reverse_tab_order) {
- if (GetActionCount() == 0)
- return false;
- if (reverse_tab_order) {
- selected_action_ = GetActionCount() - 1;
- } else {
- selected_action_.reset();
- }
- UpdateButtonsOnStateChanged();
- return selected_action_.has_value();
- }
- bool SearchResultActionsView::SelectNextAction(bool reverse_tab_order) {
- if (GetActionCount() == 0)
- return false;
- // For reverse tab order, consider moving to non-selected state.
- if (reverse_tab_order) {
- if (!selected_action_.has_value())
- return false;
- if (selected_action_.value() == 0) {
- ClearSelectedAction();
- return true;
- }
- }
- const int next_index =
- selected_action_.value_or(-1) + (reverse_tab_order ? -1 : 1);
- if (!IsValidActionIndex(next_index))
- return false;
- selected_action_ = next_index;
- UpdateButtonsOnStateChanged();
- return true;
- }
- views::View* SearchResultActionsView::GetSelectedView() {
- DCHECK(HasSelectedAction());
- int selected_action = GetSelectedAction();
- for (views::View* child : children()) {
- if (static_cast<views::Button*>(child)->tag() == selected_action)
- return child;
- }
- return nullptr;
- }
- void SearchResultActionsView::ClearSelectedAction() {
- selected_action_.reset();
- UpdateButtonsOnStateChanged();
- }
- int SearchResultActionsView::GetSelectedAction() const {
- return selected_action_.value_or(-1);
- }
- bool SearchResultActionsView::HasSelectedAction() const {
- return selected_action_.has_value();
- }
- void SearchResultActionsView::CreateImageButton(
- const SearchResult::Action& action,
- int action_index) {
- const gfx::VectorIcon* icon = nullptr;
- switch (action.type) {
- case SearchResultActionType::kRemove:
- icon = &ash::kSearchResultRemoveIcon;
- break;
- case ash::SearchResultActionType::kAppend:
- icon = &ash::kSearchResultAppendIcon;
- break;
- case ash::SearchResultActionType::kSearchResultActionTypeMax:
- NOTREACHED();
- }
- DCHECK(icon);
- auto* const button = AddChildView(std::make_unique<SearchResultActionButton>(
- this, action,
- base::BindRepeating(
- &SearchResultActionsViewDelegate::OnSearchResultActionActivated,
- base::Unretained(delegate_), action_index),
- features::IsProductivityLauncherEnabled()
- ? IconButton::Type::kSmallFloating
- : IconButton::Type::kMediumFloating,
- icon, action.tooltip_text));
- button->set_tag(action_index);
- subscriptions_.push_back(button->AddStateChangedCallback(
- base::BindRepeating(&SearchResultActionsView::UpdateButtonsOnStateChanged,
- base::Unretained(this))));
- }
- size_t SearchResultActionsView::GetActionCount() const {
- return children().size();
- }
- void SearchResultActionsView::ChildVisibilityChanged(views::View* child) {
- PreferredSizeChanged();
- }
- } // namespace ash
|