| // Copyright 2022 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_WM_MODE_PIE_MENU_VIEW_H_ |
| #define ASH_WM_MODE_PIE_MENU_VIEW_H_ |
| |
| #include <stack> |
| #include <string> |
| #include <vector> |
| |
| #include "base/containers/flat_map.h" |
| #include "ui/base/metadata/metadata_header_macros.h" |
| #include "ui/views/view.h" |
| |
| namespace gfx { |
| struct VectorIcon; |
| } // namespace gfx |
| |
| namespace views { |
| class ImageButton; |
| } // namespace views |
| |
| namespace ash { |
| |
| class PieMenuButton; |
| class PieMenuView; |
| |
| // ----------------------------------------------------------------------------- |
| // PieSubMenuContainerView: |
| |
| // Defines a container for buttons representing menu items in a pie menu. |
| class PieSubMenuContainerView : public views::View { |
| public: |
| METADATA_HEADER(PieSubMenuContainerView); |
| |
| PieSubMenuContainerView(const PieSubMenuContainerView&) = delete; |
| PieSubMenuContainerView& operator=(const PieSubMenuContainerView&) = delete; |
| ~PieSubMenuContainerView() override; |
| |
| // Adds a new menu item button with the given `button_id`, |
| // `button_label_text`, and an optional `icon` (if non-null). The `button_id` |
| // must be unique among all the IDs of the current existing buttons hosted by |
| // parent `PieMenuView` and all its sub menus. |
| void AddMenuButton(int button_id, |
| const std::u16string& button_label_text, |
| const gfx::VectorIcon* icon); |
| |
| private: |
| friend class PieMenuView; |
| |
| explicit PieSubMenuContainerView(PieMenuView* owner_menu_view); |
| |
| // The parent owner pie menu that hosts this container. Not null. |
| PieMenuView* const owner_menu_view_; |
| |
| // The buttons on this container, which will be painted as slices of a circle |
| // in their same order in this vector. |
| std::vector<PieMenuButton*> buttons_; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // PieMenuView: |
| |
| // Defines a pie menu that lists its menu items as radial slices of a circle. |
| // Each menu item button can open its sub menu with its own buttons, replacing |
| // the current content of this pie view. A back button is then shown to go back |
| // to the previous sub menu in the stack. There is always a main menu container |
| // at all times. |
| class PieMenuView : public views::View { |
| public: |
| METADATA_HEADER(PieMenuView); |
| |
| // Defines an interface for the delegate of this class which will be informed |
| // when a button on this pie view is pressed. |
| class Delegate { |
| public: |
| // Called when the button with the given `button_id` is pressed. |
| virtual void OnPieMenuButtonPressed(int button_id) = 0; |
| |
| protected: |
| virtual ~Delegate() = default; |
| }; |
| |
| explicit PieMenuView(Delegate* delegate); |
| PieMenuView(const PieMenuView&) = delete; |
| PieMenuView& operator=(const PieMenuView&) = delete; |
| ~PieMenuView() override; |
| |
| PieSubMenuContainerView* main_menu_container() { |
| return main_menu_container_; |
| } |
| |
| // Returns the `PieSubMenuContainerView` that the button whose ID is |
| // `button_id` opens when pressed if any, or creates one for it and associates |
| // it with that button. A button with `button_id` must exist in this pie menu. |
| PieSubMenuContainerView* GetOrAddSubMenuForButton(int button_id); |
| |
| // views::View: |
| void Layout() override; |
| void AddedToWidget() override; |
| void OnThemeChanged() override; |
| |
| private: |
| friend class PieSubMenuContainerView; |
| |
| // Called when the given `button` is added on any of the sub menu containers |
| // hosted by this view. |
| void OnPieMenuButtonAdded(PieMenuButton* button); |
| |
| // Called when the given `button` is pressed. This will inform the `delegate_` |
| // via the `OnPieMenuButtonPressed()` API. |
| void OnPieMenuButtonPressed(PieMenuButton* button); |
| |
| // Opens the given `sub_menu` by making it the only visible sub menu container |
| // which visually replaces the contents of this pie view with the buttons |
| // hosted by the given `sub_menu`. The `back_button_` will be shown to allow |
| // the user to go back to the previous sub menu in `active_sub_menus_stack_` |
| // (if any) or to the `main_menu_container_`. |
| void OpenSubMenu(PieSubMenuContainerView* sub_menu); |
| |
| // If there are active sub menus in `active_sub_menus_stack_`, this function |
| // pops the top-most one such that the previous sub menu shows. Finally when |
| // there are no more sub menus, the `main_menu_container_` will show, and the |
| // `back_button_` will hide. |
| void MaybePopSubMenu(); |
| |
| // The delegate of this view which takes care of handling button presses. Not |
| // null. |
| Delegate* const delegate_; |
| |
| // The container hosting the buttons on the main menu of this view. When this |
| // is visible, `active_sub_menus_stack_` should be empty, and `back_button_` |
| // should be hidden. |
| PieSubMenuContainerView* const main_menu_container_; |
| |
| // Since a button on a sub menu can open another sub menu and so on, we keep |
| // a stack of currently active sub menus (other than the main menu), so that |
| // pressing on `back_button_` pops the top-most sub menu to show the previous |
| // one, until there are no more active sub menus, at which point |
| // `main_menu_container_` shows up and `back_button_` hides. |
| std::stack<PieSubMenuContainerView*> active_sub_menus_stack_; |
| |
| views::ImageButton* const back_button_; |
| |
| // Maps all the buttons on all sub menu containers of this view by their IDs. |
| base::flat_map</*button_id=*/int, PieMenuButton*> buttons_by_id_; |
| }; |
| |
| } // namespace ash |
| |
| #endif // ASH_WM_MODE_PIE_MENU_VIEW_H_ |