// Aseprite UI Library // Copyright (C) 2020-2022 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. #ifndef UI_MENU_H_INCLUDED #define UI_MENU_H_INCLUDED #pragma once #include "obs/signal.h" #include "ui/register_message.h" #include "ui/separator.h" #include "ui/widget.h" #include "ui/window.h" #include namespace ui { class MenuBoxWindow; class MenuItem; class Timer; struct MenuBaseData; class Menu : public Widget { public: Menu(); ~Menu(); void showPopup(const gfx::Point& pos, Display* parentDisplay); Widget* findItemById(const char* id) const; // Returns the MenuItem that has as submenu this menu. MenuItem* getOwnerMenuItem() { return m_menuitem; } obs::signal OpenPopup; protected: virtual void onPaint(PaintEvent& ev) override; virtual void onResize(ResizeEvent& ev) override; virtual void onSizeHint(SizeHintEvent& ev) override; virtual void onOpenPopup(); private: void setOwnerMenuItem(MenuItem* ownerMenuItem) { m_menuitem = ownerMenuItem; } void closeAll(); MenuItem* getHighlightedItem(); void highlightItem(MenuItem* menuitem, bool click, bool open_submenu, bool select_first_child); void unhighlightItem(); MenuItem* m_menuitem; // From where the menu was open friend class MenuBox; friend class MenuItem; }; class MenuBox : public Widget { public: MenuBox(WidgetType type = kMenuBoxWidget); ~MenuBox(); Menu* getMenu(); void setMenu(Menu* menu); MenuBaseData* getBase() { return m_base.get(); } // Closes all menu-boxes and goes back to the normal state of the // menu-bar. void cancelMenuLoop(); protected: virtual bool onProcessMessage(Message* msg) override; virtual void onResize(ResizeEvent& ev) override; virtual void onSizeHint(SizeHintEvent& ev) override; MenuBaseData* createBase(); private: void closePopup(); void startFilteringMouseDown(); void stopFilteringMouseDown(); std::unique_ptr m_base; friend class Menu; friend class MenuItem; }; class MenuBar : public MenuBox { public: enum class ProcessTopLevelShortcuts { kNo, kYes }; MenuBar(ProcessTopLevelShortcuts processShortcuts); bool processTopLevelShortcuts() const { return m_processTopLevelShortcuts; } static bool expandOnMouseover(); static void setExpandOnMouseover(bool state); private: // True if we should open top-level menus with Alt+mnemonic (this // flag is not used by Aseprite), top-level menus are opened with // the ShowMenu command now. bool m_processTopLevelShortcuts; static bool m_expandOnMouseover; }; class MenuItem : public Widget { public: MenuItem(const std::string& text); ~MenuItem(); Menu* getSubmenu(); void setSubmenu(Menu* submenu); // Open the submenu of this menu item (the menu item should be // positioned in a correct position on the screen). void openSubmenu(); bool isHighlighted() const; void setHighlighted(bool state); // Returns true if the MenuItem has a submenu. bool hasSubmenu() const; // Returns true if the submenu is opened. bool hasSubmenuOpened() const { return (m_submenu_menubox != nullptr); } // Returns the menu-box where the sub-menu has been opened, or // just nullptr if the sub-menu is closed. MenuBox* getSubmenuContainer() const { return m_submenu_menubox; } void executeClick(); void validateItem(); // Fired when the menu item is clicked. obs::signal Click; protected: bool onProcessMessage(Message* msg) override; void onInitTheme(InitThemeEvent& ev) override; void onPaint(PaintEvent& ev) override; void onSizeHint(SizeHintEvent& ev) override; virtual void onClick(); virtual void onValidate(); bool inBar() const; private: void openSubmenu(bool select_first); void closeSubmenu(bool last_of_close_chain); void startTimer(); void stopTimer(); bool m_highlighted; // Is it highlighted? Menu* m_submenu; // The sub-menu MenuBox* m_submenu_menubox; // The opened menubox for this menu-item std::unique_ptr m_submenu_timer; // Timer to open the submenu friend class Menu; friend class MenuBox; friend class MenuBoxWindow; }; class MenuSeparator : public Separator { public: MenuSeparator() : Separator("", HORIZONTAL) { } }; class MenuBoxWindow : public Window { public: MenuBoxWindow(MenuItem* menuitem = nullptr); ~MenuBoxWindow(); MenuBox* menubox() { return &m_menubox; } protected: bool onProcessMessage(Message* msg) override; private: MenuBox m_menubox; MenuItem* m_menuitem; }; extern RegisterMessage kOpenMenuItemMessage; extern RegisterMessage kCloseMenuItemMessage; extern RegisterMessage kClosePopupMessage; extern RegisterMessage kExecuteMenuItemMessage; } // namespace ui #endif