yaze
0.3.2
Link to the Past ROM Editor
Loading...
Searching...
No Matches
menu_builder.cc
Go to the documentation of this file.
1
#include "
app/editor/menu/menu_builder.h
"
2
3
#include "absl/strings/str_cat.h"
4
#include "
app/gui/automation/widget_auto_register.h
"
5
#include "
util/i18n/tr.h
"
6
7
namespace
yaze
{
8
namespace
editor {
9
10
MenuBuilder
&
MenuBuilder::BeginMenu
(
const
char
* label,
const
char
* icon) {
11
Menu
menu;
12
menu.
label
= label;
13
if
(icon) {
14
menu.
icon
= icon;
15
}
16
menus_
.push_back(menu);
17
current_menu_
= &
menus_
.back();
18
return
*
this
;
19
}
20
21
MenuBuilder
&
MenuBuilder::BeginSubMenu
(
const
char
* label,
const
char
* icon,
22
EnabledCheck
enabled) {
23
if
(!
current_menu_
)
24
return
*
this
;
25
26
MenuItem
item;
27
item.
type
=
MenuItem::Type::kSubMenuBegin
;
28
item.
label
= label;
29
if
(icon) {
30
item.
icon
= icon;
31
}
32
item.
enabled
= enabled;
33
current_menu_
->
items
.push_back(item);
34
return
*
this
;
35
}
36
37
MenuBuilder
&
MenuBuilder::EndMenu
() {
38
if
(!
current_menu_
)
39
return
*
this
;
40
41
// Check if we're ending a submenu or top-level menu
42
// We need to track nesting depth to handle nested submenus correctly
43
bool
is_submenu =
false
;
44
int
depth = 0;
45
46
for
(
auto
it =
current_menu_
->
items
.rbegin();
47
it !=
current_menu_
->
items
.rend(); ++it) {
48
if
(it->type ==
MenuItem::Type::kSubMenuEnd
) {
49
depth++;
// Found an end, so we need to skip its matching begin
50
}
else
if
(it->type ==
MenuItem::Type::kSubMenuBegin
) {
51
if
(depth == 0) {
52
// Found an unmatched begin - this is what we're closing
53
is_submenu =
true
;
54
break
;
55
}
56
depth--;
// This begin matches a previous end
57
}
58
}
59
60
if
(is_submenu) {
61
MenuItem
item;
62
item.
type
=
MenuItem::Type::kSubMenuEnd
;
63
current_menu_
->
items
.push_back(item);
64
}
else
{
65
current_menu_
=
nullptr
;
66
}
67
68
return
*
this
;
69
}
70
71
MenuBuilder
&
MenuBuilder::Item
(
const
char
* label,
const
char
* icon,
72
Callback
callback,
const
char
* shortcut,
73
EnabledCheck
enabled,
EnabledCheck
checked) {
74
if
(!
current_menu_
)
75
return
*
this
;
76
77
MenuItem
item;
78
item.
type
=
MenuItem::Type::kItem
;
79
item.
label
= label;
80
if
(icon) {
81
item.
icon
= icon;
82
}
83
if
(shortcut) {
84
item.
shortcut
= shortcut;
85
}
86
item.
callback
= callback;
87
item.
enabled
= enabled;
88
item.
checked
= checked;
89
current_menu_
->
items
.push_back(item);
90
return
*
this
;
91
}
92
93
MenuBuilder
&
MenuBuilder::Item
(
const
char
* label,
Callback
callback,
94
const
char
* shortcut,
EnabledCheck
enabled) {
95
return
Item
(label,
nullptr
, callback, shortcut, enabled,
nullptr
);
96
}
97
98
MenuBuilder
&
MenuBuilder::Separator
() {
99
if
(!
current_menu_
)
100
return
*
this
;
101
102
MenuItem
item;
103
item.
type
=
MenuItem::Type::kSeparator
;
104
current_menu_
->
items
.push_back(item);
105
return
*
this
;
106
}
107
108
MenuBuilder
&
MenuBuilder::DisabledItem
(
const
char
* label,
const
char
* icon) {
109
if
(!
current_menu_
)
110
return
*
this
;
111
112
MenuItem
item;
113
item.
type
=
MenuItem::Type::kDisabled
;
114
item.
label
= label;
115
if
(icon) {
116
item.
icon
= icon;
117
}
118
current_menu_
->
items
.push_back(item);
119
return
*
this
;
120
}
121
122
MenuBuilder
&
MenuBuilder::CustomMenu
(
const
char
* label,
123
Callback
draw_callback) {
124
Menu
menu;
125
menu.
label
= label;
126
menu.
custom_draw
= draw_callback;
127
menu.
is_custom
=
true
;
128
menus_
.push_back(menu);
129
current_menu_
=
nullptr
;
// Custom menus don't use the builder pattern
130
return
*
this
;
131
}
132
133
void
MenuBuilder::Draw
() {
134
for
(
const
auto
& menu :
menus_
) {
135
// Don't add icons to top-level menus as they get cut off
136
std::string menu_label = tr(menu.label.c_str());
137
138
if
(menu.is_custom) {
139
// Custom menu with callback for dynamic content
140
if
(ImGui::BeginMenu(menu_label.c_str())) {
141
if
(menu.custom_draw) {
142
menu.custom_draw();
143
}
144
ImGui::EndMenu();
145
}
146
}
else
{
147
// Standard menu with predefined items
148
if
(ImGui::BeginMenu(menu_label.c_str())) {
149
submenu_stack_
.clear();
// Reset submenu stack for each top-level menu
150
skip_depth_
= 0;
// Reset skip depth
151
for
(
const
auto
& item : menu.items) {
152
DrawMenuItem
(item);
153
}
154
ImGui::EndMenu();
155
}
156
}
157
}
158
}
159
160
void
MenuBuilder::DrawMenuItem
(
const
MenuItem
& item) {
161
switch
(item.
type
) {
162
case
MenuItem::Type::kSeparator
:
163
if
(
skip_depth_
== 0) {
164
ImGui::Separator();
165
}
166
break
;
167
168
case
MenuItem::Type::kDisabled
: {
169
if
(
skip_depth_
== 0) {
170
std::string label =
171
item.
icon
.empty()
172
? std::string(tr(item.
label
.c_str()))
173
: absl::StrCat(item.
icon
,
" "
, tr(item.
label
.c_str()));
174
ImGui::BeginDisabled();
175
ImGui::MenuItem(label.c_str(),
nullptr
,
false
,
false
);
176
ImGui::EndDisabled();
177
}
178
break
;
179
}
180
181
case
MenuItem::Type::kSubMenuBegin
: {
182
// If we're already skipping, increment skip depth and continue
183
if
(
skip_depth_
> 0) {
184
skip_depth_
++;
185
submenu_stack_
.push_back(
false
);
186
break
;
187
}
188
189
std::string label =
190
item.
icon
.empty()
191
? std::string(tr(item.
label
.c_str()))
192
: absl::StrCat(item.
icon
,
" "
, tr(item.
label
.c_str()));
193
194
bool
enabled = !item.
enabled
|| item.
enabled
();
195
bool
opened =
false
;
196
197
if
(!enabled) {
198
// Disabled submenu - show as disabled item but don't open
199
ImGui::BeginDisabled();
200
ImGui::MenuItem(label.c_str(),
nullptr
,
false
,
false
);
201
ImGui::EndDisabled();
202
submenu_stack_
.push_back(
false
);
203
skip_depth_
++;
// Skip contents of disabled submenu
204
}
else
{
205
// BeginMenu returns true if submenu is currently open/visible
206
opened = ImGui::BeginMenu(label.c_str());
207
submenu_stack_
.push_back(opened);
208
if
(!opened) {
209
skip_depth_
++;
// Skip contents of closed submenu
210
}
211
}
212
break
;
213
}
214
215
case
MenuItem::Type::kSubMenuEnd
:
216
// Decrement skip depth if we were skipping
217
if
(
skip_depth_
> 0) {
218
skip_depth_
--;
219
}
220
221
// Pop the stack and call EndMenu only if submenu was opened
222
if
(!
submenu_stack_
.empty()) {
223
bool
was_opened =
submenu_stack_
.back();
224
submenu_stack_
.pop_back();
225
if
(was_opened &&
skip_depth_
== 0) {
226
ImGui::EndMenu();
227
}
228
}
229
break
;
230
231
case
MenuItem::Type::kItem
: {
232
if
(
skip_depth_
> 0) {
233
break
;
// Skip items in closed submenus
234
}
235
236
std::string label =
237
item.
icon
.empty()
238
? std::string(tr(item.
label
.c_str()))
239
: absl::StrCat(item.
icon
,
" "
, tr(item.
label
.c_str()));
240
241
bool
enabled = !item.
enabled
|| item.
enabled
();
242
bool
checked = item.
checked
&& item.
checked
();
243
244
const
char
* shortcut_str =
245
item.
shortcut
.empty() ? nullptr : item.
shortcut
.c_str();
246
247
const
bool
activated =
248
ImGui::MenuItem(label.c_str(), shortcut_str, checked, enabled);
249
if
(item.
label
==
"Save ROM"
|| item.
label
==
"Quit"
) {
250
gui::AutoRegisterLastItem
(
"menuitem"
, item.
label
,
251
"Stable file-menu harness action"
);
252
}
253
if
(activated) {
254
if
(item.
callback
) {
255
item.
callback
();
256
}
257
}
258
break
;
259
}
260
}
261
}
262
263
void
MenuBuilder::Clear
() {
264
menus_
.clear();
265
current_menu_
=
nullptr
;
266
}
267
268
}
// namespace editor
269
}
// namespace yaze
yaze::editor::MenuBuilder
Fluent interface for building ImGui menus with icons.
Definition
menu_builder.h:34
yaze::editor::MenuBuilder::current_menu_
Menu * current_menu_
Definition
menu_builder.h:128
yaze::editor::MenuBuilder::Item
MenuBuilder & Item(const char *label, const char *icon, Callback callback, const char *shortcut=nullptr, EnabledCheck enabled=nullptr, EnabledCheck checked=nullptr)
Add a menu item.
Definition
menu_builder.cc:71
yaze::editor::MenuBuilder::CustomMenu
MenuBuilder & CustomMenu(const char *label, Callback draw_callback)
Add a custom menu with a callback for drawing dynamic content.
Definition
menu_builder.cc:122
yaze::editor::MenuBuilder::Draw
void Draw()
Draw the menu bar (call in main menu bar)
Definition
menu_builder.cc:133
yaze::editor::MenuBuilder::Clear
void Clear()
Clear all menus.
Definition
menu_builder.cc:263
yaze::editor::MenuBuilder::EnabledCheck
std::function< bool()> EnabledCheck
Definition
menu_builder.h:37
yaze::editor::MenuBuilder::skip_depth_
int skip_depth_
Definition
menu_builder.h:132
yaze::editor::MenuBuilder::BeginMenu
MenuBuilder & BeginMenu(const char *label, const char *icon=nullptr)
Begin a top-level menu.
Definition
menu_builder.cc:10
yaze::editor::MenuBuilder::Separator
MenuBuilder & Separator()
Add a separator.
Definition
menu_builder.cc:98
yaze::editor::MenuBuilder::EndMenu
MenuBuilder & EndMenu()
End the current menu/submenu.
Definition
menu_builder.cc:37
yaze::editor::MenuBuilder::BeginSubMenu
MenuBuilder & BeginSubMenu(const char *label, const char *icon=nullptr, EnabledCheck enabled=nullptr)
Begin a submenu.
Definition
menu_builder.cc:21
yaze::editor::MenuBuilder::Callback
std::function< void()> Callback
Definition
menu_builder.h:36
yaze::editor::MenuBuilder::DrawMenuItem
void DrawMenuItem(const MenuItem &item)
Definition
menu_builder.cc:160
yaze::editor::MenuBuilder::menus_
std::vector< Menu > menus_
Definition
menu_builder.h:127
yaze::editor::MenuBuilder::DisabledItem
MenuBuilder & DisabledItem(const char *label, const char *icon=nullptr)
Add a disabled item (grayed out)
Definition
menu_builder.cc:108
yaze::editor::MenuBuilder::submenu_stack_
std::vector< bool > submenu_stack_
Definition
menu_builder.h:131
menu_builder.h
yaze::editor::DungeonSelectionKind::Item
@ Item
yaze::gui::AutoRegisterLastItem
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
Definition
widget_auto_register.cc:26
yaze
Definition
patch_export_usage.cc:8
yaze::editor::MenuBuilder::MenuItem
Definition
menu_builder.h:101
yaze::editor::MenuBuilder::MenuItem::callback
Callback callback
Definition
menu_builder.h:114
yaze::editor::MenuBuilder::MenuItem::shortcut
std::string shortcut
Definition
menu_builder.h:113
yaze::editor::MenuBuilder::MenuItem::type
Type type
Definition
menu_builder.h:110
yaze::editor::MenuBuilder::MenuItem::enabled
EnabledCheck enabled
Definition
menu_builder.h:115
yaze::editor::MenuBuilder::MenuItem::checked
EnabledCheck checked
Definition
menu_builder.h:116
yaze::editor::MenuBuilder::MenuItem::label
std::string label
Definition
menu_builder.h:111
yaze::editor::MenuBuilder::MenuItem::icon
std::string icon
Definition
menu_builder.h:112
yaze::editor::MenuBuilder::MenuItem::Type::kSubMenuEnd
@ kSubMenuEnd
yaze::editor::MenuBuilder::MenuItem::Type::kItem
@ kItem
yaze::editor::MenuBuilder::MenuItem::Type::kDisabled
@ kDisabled
yaze::editor::MenuBuilder::MenuItem::Type::kSubMenuBegin
@ kSubMenuBegin
yaze::editor::MenuBuilder::MenuItem::Type::kSeparator
@ kSeparator
yaze::editor::MenuBuilder::Menu
Definition
menu_builder.h:119
yaze::editor::MenuBuilder::Menu::icon
std::string icon
Definition
menu_builder.h:121
yaze::editor::MenuBuilder::Menu::items
std::vector< MenuItem > items
Definition
menu_builder.h:122
yaze::editor::MenuBuilder::Menu::label
std::string label
Definition
menu_builder.h:120
yaze::editor::MenuBuilder::Menu::custom_draw
Callback custom_draw
Definition
menu_builder.h:123
yaze::editor::MenuBuilder::Menu::is_custom
bool is_custom
Definition
menu_builder.h:124
tr.h
widget_auto_register.h
Automatic widget registration helpers for ImGui Test Engine integration.
src
app
editor
menu
menu_builder.cc
Generated by
1.10.0