yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
canvas_menu.h
Go to the documentation of this file.
1#ifndef YAZE_APP_GUI_CANVAS_CANVAS_MENU_H
2#define YAZE_APP_GUI_CANVAS_CANVAS_MENU_H
3
4#include <functional>
5#include <optional>
6#include <string>
7#include <vector>
8
9#include "imgui/imgui.h"
10
11namespace yaze {
12namespace gui {
13
24 kEditorSpecific = 0, // Highest priority - editor-specific actions
25 kBitmapPalette = 10, // Medium priority - bitmap/palette operations
26 kCanvasProperties = 20, // Low priority - canvas settings
27 kDebug = 30 // Lowest priority - debug/performance
28};
29
37 // Unique popup identifier for ImGui
38 std::string popup_id;
39
40 // Callback that renders the popup content (should call
41 // ImGui::BeginPopup/EndPopup)
42 std::function<void()> render_callback;
43
44 // Whether to automatically open the popup when menu item is selected
46
47 // Whether the popup should persist across frames until explicitly closed
49
50 // Default constructor
52
53 // Constructor for simple popups
54 CanvasPopupDefinition(const std::string& id, std::function<void()> callback)
55 : popup_id(id), render_callback(std::move(callback)) {}
56};
57
65 // Display label for the menu item
66 std::string label;
67
68 // Optional icon (Material Design icon name or Unicode glyph)
69 std::string icon;
70
71 // Optional keyboard shortcut display (e.g., "Ctrl+S")
72 std::string shortcut;
73
74 // Optional hover tooltip. On an armed confirm-gated item it replaces the
75 // default "This cannot be undone." warning.
76 std::string tooltip;
77
78 // Callback invoked when menu item is selected
79 std::function<void()> callback;
80
81 // Optional popup definition - if present, popup will be managed automatically
82 std::optional<CanvasPopupDefinition> popup;
83
84 // Condition to determine if menu item is enabled
85 std::function<bool()> enabled_condition = []() {
86 return true;
87 };
88
89 // Condition to determine if menu item is visible
90 std::function<bool()> visible_condition = []() {
91 return true;
92 };
93
94 // Optional checked state for toggle-like menu items.
95 std::function<bool()> checked_condition;
96
97 // Nested submenu items
98 std::vector<CanvasMenuItem> subitems;
99
100 // Color for the menu item label
101 ImVec4 color = ImVec4(1, 1, 1, 1);
102
103 // Whether to show a separator after this item
104 bool separator_after = false;
105
106 // Destructive action (delete, forget, close-with-unsaved-changes). The label
107 // renders in gui::GetErrorColor() and overrides `color`.
108 bool destructive = false;
109
110 // Two-step confirmation ("click again to confirm"). The first click arms the
111 // item: the menu stays open and the label becomes "Confirm <label>?". The
112 // second click runs the callback and closes the menu. Closing the menu or
113 // clicking another confirm-gated item disarms it. Label such items with a
114 // trailing "..." (see docs/internal/gui/context-menus.md).
116
117 // Default constructor
118 CanvasMenuItem() = default;
119
120 // Simple menu item constructor
121 CanvasMenuItem(const std::string& lbl, std::function<void()> cb)
122 : label(lbl), callback(std::move(cb)) {}
123
124 // Menu item with icon
125 CanvasMenuItem(const std::string& lbl, const std::string& ico,
126 std::function<void()> cb)
127 : label(lbl), icon(ico), callback(std::move(cb)) {}
128
129 // Menu item with icon and shortcut
130 CanvasMenuItem(const std::string& lbl, const std::string& ico,
131 std::function<void()> cb, const std::string& sc)
132 : label(lbl), icon(ico), callback(std::move(cb)), shortcut(sc) {}
133
134 // Helper to create a destructive item. With `confirm` true the callback only
135 // runs after the two-step confirmation described on requires_confirmation.
136 static CanvasMenuItem Destructive(const std::string& lbl,
137 const std::string& ico,
138 std::function<void()> cb,
139 bool confirm = true,
140 const std::string& sc = "") {
141 CanvasMenuItem item(lbl, ico, std::move(cb), sc);
142 item.destructive = true;
143 item.requires_confirmation = confirm;
144 return item;
145 }
146
147 // Helper to create a disabled menu item
148 static CanvasMenuItem Disabled(const std::string& lbl) {
149 CanvasMenuItem item;
150 item.label = lbl;
151 item.enabled_condition = []() {
152 return false;
153 };
154 return item;
155 }
156
157 // Helper to create a conditional menu item
158 static CanvasMenuItem Conditional(const std::string& lbl,
159 std::function<void()> cb,
160 std::function<bool()> condition) {
161 CanvasMenuItem item;
162 item.label = lbl;
163 item.callback = std::move(cb);
164 item.enabled_condition = std::move(condition);
165 return item;
166 }
167
168 // Helper to create a menu item with popup
169 static CanvasMenuItem WithPopup(const std::string& lbl,
170 const std::string& popup_id,
171 std::function<void()> render_callback) {
172 CanvasMenuItem item;
173 item.label = lbl;
174 item.popup = CanvasPopupDefinition(popup_id, std::move(render_callback));
175 return item;
176 }
177};
178
186 // Optional section title (rendered as colored text)
187 std::string title;
188
189 // Color for section title
190 ImVec4 title_color = ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
191
192 // Menu items in this section
193 std::vector<CanvasMenuItem> items;
194
195 // Whether to show a separator after this section
196 bool separator_after = true;
197
198 // Priority for ordering sections (lower values render first)
200
201 // Default constructor
202 CanvasMenuSection() = default;
203
204 // Constructor with title
205 explicit CanvasMenuSection(const std::string& t) : title(t) {}
206
207 // Constructor with title and items
208 CanvasMenuSection(const std::string& t,
209 const std::vector<CanvasMenuItem>& its)
210 : title(t), items(its) {}
211
212 // Constructor with title, items, and priority
213 CanvasMenuSection(const std::string& t,
214 const std::vector<CanvasMenuItem>& its,
216 : title(t), items(its), priority(prio) {}
217};
218
225 // Menu sections (rendered in order)
226 std::vector<CanvasMenuSection> sections;
227
228 // Whether the menu is enabled
229 bool enabled = true;
230
231 // Default constructor
233
234 // Constructor with sections
235 explicit CanvasMenuDefinition(const std::vector<CanvasMenuSection>& secs)
236 : sections(secs) {}
237
238 // Add a section
239 void AddSection(const CanvasMenuSection& section) {
240 sections.push_back(section);
241 }
242
243 // Add items without a section title
244 void AddItems(const std::vector<CanvasMenuItem>& items) {
245 CanvasMenuSection section;
246 section.items = items;
247 section.separator_after = false;
248 sections.push_back(section);
249 }
250};
251
257
265 public:
266 // Record that the item `id` was rendered on `frame`. Disarms a stale arm.
267 void NoteRendered(ImGuiID id, int frame);
268
269 // True when `id` is armed and was rendered on the previous or current frame.
270 bool IsArmed(ImGuiID id, int frame) const;
271
272 // Handle a click on `id`. Returns true when the action should run (second
273 // click on an armed item); otherwise arms `id` and returns false.
274 bool Click(ImGuiID id, int frame);
275
276 void Reset() {
277 armed_id_ = 0;
278 last_frame_ = -1;
279 }
280
281 ImGuiID armed_id() const { return armed_id_; }
282
283 private:
284 ImGuiID armed_id_ = 0;
285 int last_frame_ = -1;
286};
287
288// Process-wide confirm state shared by every RenderMenuItem call.
290
291// Label shown on an armed confirm-gated item: "Confirm <label>?" with any
292// trailing "..." or ellipsis removed.
293std::string ConfirmLabel(const std::string& label);
294
306 public:
311
312 private:
313 int pushed_ = 0;
314};
315
316// Value of a two-float style var before the first PushStyleVar of it that is
317// still on the style stack; the current value when nothing pushed it.
318ImVec2 BaseStyleVarVec2(ImGuiStyleVar idx);
319
320// ==================== Free Function API ====================
321
330void RenderMenuItem(
331 const CanvasMenuItem& item,
332 std::function<void(const std::string&, std::function<void()>)>
333 popup_opened_callback = nullptr);
334
344 const CanvasMenuSection& section,
345 std::function<void(const std::string&, std::function<void()>)>
346 popup_opened_callback = nullptr);
347
358 const CanvasMenuDefinition& menu,
359 std::function<void(const std::string&, std::function<void()>)>
360 popup_opened_callback = nullptr);
361
362} // namespace gui
363} // namespace yaze
364
365#endif // YAZE_APP_GUI_CANVAS_CANVAS_MENU_H
Arming state for confirm-gated menu items (ImGui-free, testable).
bool IsArmed(ImGuiID id, int frame) const
bool Click(ImGuiID id, int frame)
void NoteRendered(ImGuiID id, int frame)
Gives one popup the app's normal spacing.
PopupStyleScope(const PopupStyleScope &)=delete
PopupStyleScope & operator=(const PopupStyleScope &)=delete
MenuConfirmState & GetMenuConfirmState()
MenuSectionPriority
Menu section priority for controlling rendering order.
Definition canvas_menu.h:23
void RenderCanvasMenu(const CanvasMenuDefinition &menu, std::function< void(const std::string &, std::function< void()>)> popup_opened_callback)
Render a complete menu definition.
std::string ConfirmLabel(const std::string &label)
void RenderMenuSection(const CanvasMenuSection &section, std::function< void(const std::string &, std::function< void()>)> popup_opened_callback)
Render a menu section.
ImVec2 BaseStyleVarVec2(ImGuiStyleVar idx)
void RenderMenuItem(const CanvasMenuItem &item, std::function< void(const std::string &, std::function< void()>)> popup_opened_callback)
Render a single menu item.
Complete menu definition.
std::vector< CanvasMenuSection > sections
void AddItems(const std::vector< CanvasMenuItem > &items)
void AddSection(const CanvasMenuSection &section)
CanvasMenuDefinition(const std::vector< CanvasMenuSection > &secs)
Declarative menu item definition.
Definition canvas_menu.h:64
std::function< bool()> checked_condition
Definition canvas_menu.h:95
std::vector< CanvasMenuItem > subitems
Definition canvas_menu.h:98
CanvasMenuItem(const std::string &lbl, const std::string &ico, std::function< void()> cb, const std::string &sc)
std::function< bool()> enabled_condition
Definition canvas_menu.h:85
CanvasMenuItem(const std::string &lbl, const std::string &ico, std::function< void()> cb)
static CanvasMenuItem Conditional(const std::string &lbl, std::function< void()> cb, std::function< bool()> condition)
std::function< void()> callback
Definition canvas_menu.h:79
std::optional< CanvasPopupDefinition > popup
Definition canvas_menu.h:82
static CanvasMenuItem Destructive(const std::string &lbl, const std::string &ico, std::function< void()> cb, bool confirm=true, const std::string &sc="")
CanvasMenuItem(const std::string &lbl, std::function< void()> cb)
static CanvasMenuItem WithPopup(const std::string &lbl, const std::string &popup_id, std::function< void()> render_callback)
std::function< bool()> visible_condition
Definition canvas_menu.h:90
static CanvasMenuItem Disabled(const std::string &lbl)
Menu section grouping related menu items.
CanvasMenuSection(const std::string &t, const std::vector< CanvasMenuItem > &its, MenuSectionPriority prio)
CanvasMenuSection(const std::string &t, const std::vector< CanvasMenuItem > &its)
CanvasMenuSection(const std::string &t)
std::vector< CanvasMenuItem > items
MenuSectionPriority priority
Declarative popup definition for menu items.
Definition canvas_menu.h:36
CanvasPopupDefinition(const std::string &id, std::function< void()> callback)
Definition canvas_menu.h:54
std::function< void()> render_callback
Definition canvas_menu.h:42