// Copyright 2023 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_STYLE_DROP_DOWN_CHECKBOX_H_
#define ASH_STYLE_DROP_DOWN_CHECKBOX_H_
#include <memory>
#include "ash/ash_export.h"
#include "base/scoped_observation.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/models/list_model.h"
#include "ui/base/models/list_selection_model.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/widget/unique_widget_ptr.h"
namespace views {
class ImageView;
class Label;
} // namespace views
namespace ash {
// A label button has a drop-down list of checkboxes that can be accessed by
// clicking the arrow button. The data model of the drop down checkboxes is a
// `ui::ListModel` with `std::u16string` type.
class ASH_EXPORT DropDownCheckbox : public views::Button,
public views::WidgetObserver {
METADATA_HEADER(DropDownCheckbox, views::Button)
public:
using ItemModel = ui::ListModel<std::u16string>;
using SelectedIndices = ui::ListSelectionModel::SelectedIndices;
using SelectedItems = std::vector<std::u16string>;
DropDownCheckbox(const std::u16string& title, ItemModel* model);
DropDownCheckbox(const DropDownCheckbox&) = delete;
DropDownCheckbox& operator=(const DropDownCheckbox&) = delete;
~DropDownCheckbox() override;
// The action which will be taken after the drop-down menu is closed.
void SetSelectedAction(base::RepeatingClosure callback);
SelectedIndices GetSelectedIndices() const;
SelectedItems GetSelectedItems() const;
// Returns whether or not the menu is currently running.
bool IsMenuRunning() const;
// views::Button:
void SetCallback(PressedCallback callback) override;
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
void OnBlur() override;
void AddedToWidget() override;
void RemovedFromWidget() override;
void Layout(PassKey) override;
// WidgetObserver:
void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& bounds) override;
private:
class SelectionModel;
class MenuView;
class EventHandler;
// Gets expected menu bounds according to combox location.
gfx::Rect GetExpectedMenuBounds() const;
// Called when the arrow button is pressed.
void OnDropDownCheckboxPressed();
// Shows/Closes the drop down menu.
void ShowDropDownMenu();
void CloseDropDownMenu();
// Called when the selections are made and the menu is closed.
void OnPerformAction();
// Reference to the data model.
raw_ptr<ItemModel> model_;
const raw_ptr<views::Label> title_ = nullptr;
const raw_ptr<views::ImageView> drop_down_arrow_ = nullptr;
// The selection model that manages the selections.
std::unique_ptr<SelectionModel> selection_model_;
// The action that will be taken after closing the drop down menu.
base::RepeatingClosure callback_;
// A handler handles mouse and touch event happening outside drop down
// checkbox. This is mainly used to decide if we should close it.
std::unique_ptr<EventHandler> event_handler_;
// Drop down menu view owned by menu widget.
raw_ptr<MenuView> menu_view_ = nullptr;
// Drop down menu widget.
views::UniqueWidgetPtr menu_;
// The last time that the menu closed. This is used to avoid re-opening the
// menu while clicking on the arrow button to close the menu.
base::TimeTicks closed_time_;
base::ScopedObservation<views::Widget, views::WidgetObserver>
widget_observer_{this};
};
} // namespace ash
#endif // ASH_STYLE_DROP_DOWN_CHECKBOX_H_