1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsPrerequisites.h"
6#include "GUI/BsGUIDropDownMenu.h"
7#include "GUI/BsShortcutKey.h"
8
9namespace bs
10{
11 /** @addtogroup GUI-Internal
12 * @{
13 */
14
15 class GUIMenuItem;
16
17 /** Used for comparing GUI menu items in order to determine the order in which they are presented. */
18 struct GUIMenuItemComparer
19 {
20 bool operator() (const GUIMenuItem* const& a, const GUIMenuItem* const& b) const;
21 };
22
23 /** Holds information about a single element in a GUI menu. */
24 class BS_EXPORT GUIMenuItem
25 {
26 public:
27 /**
28 * Constructs a new non-separator menu item.
29 *
30 * @param[in] parent Parent item, if any.
31 * @param[in] name Name of the item to be displayed.
32 * @param[in] callback Callback to be triggered when menu items is selected.
33 * @param[in] priority Priority that determines the order of this element compared to its siblings.
34 * @param[in] seqIdx Sequential index of the menu item that specifies in what order was it added to the menu
35 * compared to other items.
36 * @param[in] key Keyboard shortcut that can be used for triggering the menu item.
37 */
38 GUIMenuItem(GUIMenuItem* parent, const String& name, std::function<void()> callback,
39 INT32 priority, UINT32 seqIdx, const ShortcutKey& key);
40
41 /**
42 * Constructs a new separator menu item.
43 *
44 * @param[in] parent Parent item, if any.
45 * @param[in] priority Priority that determines the order of this element compared to its siblings.
46 * @param[in] seqIdx Sequential index of the menu item that specifies in what order was it added to the menu
47 * compared to other items.
48 */
49 GUIMenuItem(GUIMenuItem* parent, INT32 priority, UINT32 seqIdx);
50 ~GUIMenuItem();
51
52 /** Registers a new child with the item. */
53 void addChild(GUIMenuItem* child) { mChildren.insert(child); }
54
55 /** Returns number of child menu items. */
56 UINT32 getNumChildren() const { return (UINT32)mChildren.size(); }
57
58 /** Returns the parent menu item, or null if none. */
59 GUIMenuItem* getParent() const { return mParent; }
60
61 /** Returns name of the menu item. Empty if separator. */
62 const String& getName() const { return mName; }
63
64 /** Returns callback that will trigger when menu item is selected. Null for separators. */
65 std::function<void()> getCallback() const { return mCallback; }
66
67 /** Returns a keyboard shortcut that may be used for triggering the menu item callback. */
68 const ShortcutKey& getShortcut() const { return mShortcut; }
69
70 /** Checks is the menu item a separator or a normal named menu item. */
71 bool isSeparator() const { return mIsSeparator; }
72
73 /** Attempts to find a child menu item with the specified name. Only direct descendants are searched. */
74 const GUIMenuItem* findChild(const String& name) const;
75
76 /** Removes the first child with the specified name. */
77 void removeChild(const String& name);
78
79 /** Removes the specified child. */
80 void removeChild(const GUIMenuItem* item);
81
82 private:
83 friend class GUIMenu;
84 friend struct GUIMenuItemComparer;
85
86 /** @copydoc GUIMenuitem::findChild(const WString& name) const */
87 GUIMenuItem* findChild(const String& name);
88
89 GUIMenuItem* mParent;
90 bool mIsSeparator;
91 String mName;
92 std::function<void()> mCallback;
93 INT32 mPriority;
94 ShortcutKey mShortcut;
95 UINT32 mSeqIdx;
96 Set<GUIMenuItem*, GUIMenuItemComparer> mChildren;
97 };
98
99 /**
100 * Class that allows creation of menus with drop down functionality.
101 * Menu consists out of a number of top level elements, each of which opens
102 * a drop down menu which may internally hold a deeper hierarchy of menus.
103 *
104 * @note
105 * When specifying menu items you must provide a path. Path must be formated in a certain way. All path elements must
106 * be separated by /, for example "View/Toolbars/Find". "View" would be the top level path element, "Toolbars" a child
107 * in its menu that opens up its own submenu, and "Find" a child in the "Toolbars" sub-menu with an optional callback.
108 * @note
109 * This is an abstract class and you should provide specialized implementations for specific menu types.
110 */
111 class BS_EXPORT GUIMenu
112 {
113 public:
114 GUIMenu();
115 virtual ~GUIMenu();
116
117 /**
118 * Adds a new menu item with the specified callback.
119 *
120 * @param[in] path Path that determines where to add the element. See class information on how to specify
121 * paths. All sub-elements of a path will be added automatically.
122 * @param[in] callback Callback that triggers when the path element is selected.
123 * @param[in] priority Priority determines the position of the menu item relative to its siblings. Higher
124 * priority means it will be placed earlier in the menu.
125 * @param[in] key Keyboard shortcut that can be used for triggering the menu item.
126 * @return A menu item object that you may use for removing the menu item later. Its lifetime is
127 * managed internally.
128 */
129 GUIMenuItem* addMenuItem(const String& path, std::function<void()> callback, INT32 priority, const ShortcutKey& key = ShortcutKey::NONE);
130
131 /**
132 * Adds a new separator menu item with the specified callback.
133 *
134 * @param[in] path Path that determines where to add the element. See class information on how to specify
135 * paths. All sub-elements of a path will be added automatically.
136 * @param[in] priority Priority determines the position of the menu item relative to its siblings. Higher
137 * priority means it will be placed earlier in the menu.
138 * @return A menu item object that you may use for removing the menu item later. Its lifetime is
139 * managed internally.
140 */
141 GUIMenuItem* addSeparator(const String& path, INT32 priority);
142
143 /** Returns a menu item at the specified path, or null if one is not found. */
144 GUIMenuItem* getMenuItem(const String& path);
145
146 /** Removes the specified menu item from the path. If the menu item has any sub-menus they will also be removed. */
147 void removeMenuItem(const GUIMenuItem* item);
148
149 /**
150 * Normally menu items use values from their paths as their names. However path labels don't provide a way of
151 * localizing the menu item. This method allows you to set specific names (different from path labels) to each menu
152 * item. All the values are localized so they will also be updated according to the string table.
153 *
154 * @param[in] menuItemLabel The menu item label. (for example if you have a menu like "View/Toolbars/Find, this
155 * parameter would be either "View", "Toolbars" or "Find" depending which entry you
156 * want to localize)
157 * @param[in] localizedName Localized string with the name.
158 */
159 void setLocalizedName(const String& menuItemLabel, const HString& localizedName);
160
161 /** Returns data used for initializing a drop down list, for all elements. */
162 GUIDropDownData getDropDownData() const;
163 protected:
164 /** Adds a menu item at the specified path, as a normal button or as a separator. */
165 GUIMenuItem* addMenuItemInternal(const String& path, std::function<void()> callback, bool isSeparator,
166 INT32 priority, const ShortcutKey& key);
167
168 /** Return drop down data for the specified menu. */
169 GUIDropDownData getDropDownDataInternal(const GUIMenuItem& menu) const;
170
171 GUIMenuItem mRootElement;
172 UnorderedMap<String, HString> mLocalizedEntryNames;
173 UINT32 mNextIdx;
174 };
175
176 /** @} */
177}