Skip to content

Commit 16f6c09

Browse files
committed
Refactor menu API to use constructors and std::optional
Replaces factory methods with constructors for Menu and MenuItem, updates all usages to use std::make_shared. MenuItem label, icon, and tooltip now use std::optional<std::string> for better nullability and platform consistency. Updates C API, platform implementations, and documentation to reflect these changes.
1 parent df8a6c4 commit 16f6c09

File tree

10 files changed

+279
-208
lines changed

10 files changed

+279
-208
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ cmake ..
5555
cmake --build . --config Release
5656
```
5757

58+
## Development
59+
60+
### Code Formatting
61+
62+
Format the codebase using clang-format:
63+
64+
```bash
65+
clang-format -i **/*.cpp **/*.h **/*.mm
66+
```
67+
5868
## Language Bindings
5969

6070
Currently available language bindings for nativeapi:

examples/menu_example/main.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,21 @@ int main() {
1111

1212
try {
1313
// Create a menu
14-
auto menu = Menu::Create();
14+
auto menu = std::make_shared<Menu>();
1515
std::cout << "Created menu with ID: " << menu->id << std::endl;
1616

1717
// Create menu items with different types
18-
auto fileItem = MenuItem::Create("New File", MenuItemType::Normal);
19-
auto separatorItem = MenuItem::CreateSeparator();
20-
auto checkboxItem = MenuItem::Create("Word Wrap", MenuItemType::Checkbox);
21-
auto radioItem1 = MenuItem::Create("View Mode 1", MenuItemType::Radio);
22-
auto radioItem2 = MenuItem::Create("View Mode 2", MenuItemType::Radio);
23-
auto exitItem = MenuItem::Create("Exit", MenuItemType::Normal);
18+
auto fileItem =
19+
std::make_shared<MenuItem>("New File", MenuItemType::Normal);
20+
auto separatorItem =
21+
std::make_shared<MenuItem>("", MenuItemType::Separator);
22+
auto checkboxItem =
23+
std::make_shared<MenuItem>("Word Wrap", MenuItemType::Checkbox);
24+
auto radioItem1 =
25+
std::make_shared<MenuItem>("View Mode 1", MenuItemType::Radio);
26+
auto radioItem2 =
27+
std::make_shared<MenuItem>("View Mode 2", MenuItemType::Radio);
28+
auto exitItem = std::make_shared<MenuItem>("Exit", MenuItemType::Normal);
2429

2530
// Set up radio group
2631
radioItem1->SetRadioGroup(1);
@@ -127,11 +132,11 @@ int main() {
127132

128133
// Demonstrate submenu
129134
std::cout << "\n=== Testing Submenu ===" << std::endl;
130-
auto submenu = Menu::Create();
135+
auto submenu = std::make_shared<Menu>();
131136
auto submenuItem1 =
132-
MenuItem::Create("Submenu Item 1", MenuItemType::Normal);
137+
std::make_shared<MenuItem>("Submenu Item 1", MenuItemType::Normal);
133138
auto submenuItem2 =
134-
MenuItem::Create("Submenu Item 2", MenuItemType::Normal);
139+
std::make_shared<MenuItem>("Submenu Item 2", MenuItemType::Normal);
135140

136141
submenuItem1->AddListener<MenuItemClickedEvent>(
137142
[](const MenuItemClickedEvent& event) {
@@ -148,7 +153,8 @@ int main() {
148153
submenu->AddItem(submenuItem1);
149154
submenu->AddItem(submenuItem2);
150155

151-
auto submenuParent = MenuItem::Create("Tools", MenuItemType::Submenu);
156+
auto submenuParent =
157+
std::make_shared<MenuItem>("Tools", MenuItemType::Submenu);
152158
submenuParent->SetSubmenu(submenu);
153159

154160
// Add submenu event listeners

examples/tray_icon_example/main.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,11 @@ int main() {
7272
});
7373

7474
// Create context menu
75-
auto context_menu = Menu::Create();
75+
auto context_menu = std::make_shared<Menu>();
7676

7777
// Add menu items
78-
auto status_item = MenuItem::Create("Status: Running", MenuItemType::Normal);
78+
auto status_item =
79+
std::make_shared<MenuItem>("Status: Running", MenuItemType::Normal);
7980
status_item->AddListener<MenuItemClickedEvent>(
8081
[](const MenuItemClickedEvent& event) {
8182
std::cout << "Status clicked from context menu" << std::endl;
@@ -86,7 +87,8 @@ int main() {
8687
context_menu->AddSeparator();
8788

8889
// Add settings item
89-
auto settings_item = MenuItem::Create("Settings...", MenuItemType::Normal);
90+
auto settings_item =
91+
std::make_shared<MenuItem>("Settings...", MenuItemType::Normal);
9092
settings_item->AddListener<MenuItemClickedEvent>(
9193
[](const MenuItemClickedEvent& event) {
9294
std::cout << "Settings clicked from context menu" << std::endl;
@@ -95,7 +97,7 @@ int main() {
9597
context_menu->AddItem(settings_item);
9698

9799
// Add about item
98-
auto about_item = MenuItem::Create("About", MenuItemType::Normal);
100+
auto about_item = std::make_shared<MenuItem>("About", MenuItemType::Normal);
99101
about_item->AddListener<MenuItemClickedEvent>(
100102
[](const MenuItemClickedEvent& event) {
101103
std::cout << "About clicked from context menu" << std::endl;
@@ -107,7 +109,7 @@ int main() {
107109
context_menu->AddSeparator();
108110

109111
// Add exit item
110-
auto exit_item = MenuItem::Create("Exit", MenuItemType::Normal);
112+
auto exit_item = std::make_shared<MenuItem>("Exit", MenuItemType::Normal);
111113
bool* should_exit = new bool(false);
112114
exit_item->AddListener<MenuItemClickedEvent>(
113115
[should_exit](const MenuItemClickedEvent& event) {

examples/window_example/main.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ int main() {
9090
tray_icon.SetVisible(true);
9191

9292
// Create context menu
93-
auto context_menu = Menu::Create();
93+
auto context_menu = std::make_shared<Menu>();
9494

9595
context_menu->AddListener<MenuOpenedEvent>(
9696
[](const MenuOpenedEvent& event) {
@@ -104,7 +104,7 @@ int main() {
104104

105105
// Add menu items
106106
auto show_window_item =
107-
MenuItem::Create("Show Window", MenuItemType::Normal);
107+
std::make_shared<MenuItem>("Show Window", MenuItemType::Normal);
108108
show_window_item->AddListener<MenuItemClickedEvent>(
109109
[window_ptr](const MenuItemClickedEvent& event) {
110110
std::cout << "Show Window clicked from context menu" << std::endl;
@@ -116,7 +116,7 @@ int main() {
116116
context_menu->AddItem(show_window_item);
117117

118118
auto hide_window_item =
119-
MenuItem::Create("Hide Window", MenuItemType::Normal);
119+
std::make_shared<MenuItem>("Hide Window", MenuItemType::Normal);
120120
hide_window_item->AddListener<MenuItemClickedEvent>(
121121
[window_ptr](const MenuItemClickedEvent& event) {
122122
std::cout << "Hide Window clicked from context menu" << std::endl;
@@ -130,7 +130,7 @@ int main() {
130130
context_menu->AddSeparator();
131131

132132
// Add about item
133-
auto about_item = MenuItem::Create("About", MenuItemType::Normal);
133+
auto about_item = std::make_shared<MenuItem>("About", MenuItemType::Normal);
134134
about_item->AddListener<MenuItemClickedEvent>(
135135
[](const MenuItemClickedEvent& event) {
136136
std::cout << "About clicked from context menu" << std::endl;
@@ -139,19 +139,19 @@ int main() {
139139
context_menu->AddItem(about_item);
140140

141141
// Create Tools submenu with submenu event handling
142-
auto tools_submenu = Menu::Create();
142+
auto tools_submenu = std::make_shared<Menu>();
143143

144144
// Add items to tools submenu
145145
auto clear_cache_item =
146-
MenuItem::Create("Clear Cache", MenuItemType::Normal);
146+
std::make_shared<MenuItem>("Clear Cache", MenuItemType::Normal);
147147
clear_cache_item->AddListener<MenuItemClickedEvent>(
148148
[](const MenuItemClickedEvent& event) {
149149
std::cout << "Clear Cache clicked from submenu" << std::endl;
150150
});
151151
tools_submenu->AddItem(clear_cache_item);
152152

153153
auto reset_settings_item =
154-
MenuItem::Create("Reset Settings", MenuItemType::Normal);
154+
std::make_shared<MenuItem>("Reset Settings", MenuItemType::Normal);
155155
reset_settings_item->AddListener<MenuItemClickedEvent>(
156156
[](const MenuItemClickedEvent& event) {
157157
std::cout << "Reset Settings clicked from submenu" << std::endl;
@@ -161,7 +161,7 @@ int main() {
161161
tools_submenu->AddSeparator();
162162

163163
auto debug_mode_item =
164-
MenuItem::Create("Debug Mode", MenuItemType::Checkbox);
164+
std::make_shared<MenuItem>("Debug Mode", MenuItemType::Checkbox);
165165
debug_mode_item->SetState(MenuItemState::Unchecked);
166166
debug_mode_item->AddListener<MenuItemClickedEvent>(
167167
[debug_mode_item](const MenuItemClickedEvent& event) {
@@ -178,7 +178,8 @@ int main() {
178178
tools_submenu->AddItem(debug_mode_item);
179179

180180
// Create the submenu parent item
181-
auto tools_item = MenuItem::Create("Tools", MenuItemType::Submenu);
181+
auto tools_item =
182+
std::make_shared<MenuItem>("Tools", MenuItemType::Submenu);
182183
tools_item->SetSubmenu(tools_submenu);
183184

184185
// Add submenu event listeners
@@ -201,12 +202,12 @@ int main() {
201202

202203
// Add preferences section (not a submenu, just a label)
203204
auto preferences_item =
204-
MenuItem::Create("Preferences", MenuItemType::Normal);
205+
std::make_shared<MenuItem>("Preferences", MenuItemType::Normal);
205206
context_menu->AddItem(preferences_item);
206207

207208
// Add checkbox menu items
208209
auto auto_start_item =
209-
MenuItem::Create("Auto Start", MenuItemType::Checkbox);
210+
std::make_shared<MenuItem>("Auto Start", MenuItemType::Checkbox);
210211
auto_start_item->SetState(MenuItemState::Checked); // Initially checked
211212
auto_start_item->AddListener<MenuItemClickedEvent>(
212213
[auto_start_item](const MenuItemClickedEvent& event) {
@@ -222,8 +223,8 @@ int main() {
222223
});
223224
context_menu->AddItem(auto_start_item);
224225

225-
auto notifications_item =
226-
MenuItem::Create("Show Notifications", MenuItemType::Checkbox);
226+
auto notifications_item = std::make_shared<MenuItem>(
227+
"Show Notifications", MenuItemType::Checkbox);
227228
notifications_item->SetState(
228229
MenuItemState::Unchecked); // Initially unchecked
229230
notifications_item->AddListener<MenuItemClickedEvent>(
@@ -241,7 +242,8 @@ int main() {
241242
context_menu->AddItem(notifications_item);
242243

243244
// Add three-state checkbox example
244-
auto sync_item = MenuItem::Create("Sync Status", MenuItemType::Checkbox);
245+
auto sync_item =
246+
std::make_shared<MenuItem>("Sync Status", MenuItemType::Checkbox);
245247
sync_item->SetState(MenuItemState::Mixed); // Initially mixed/indeterminate
246248
sync_item->AddListener<MenuItemClickedEvent>(
247249
[sync_item](const MenuItemClickedEvent& event) {
@@ -275,11 +277,12 @@ int main() {
275277
context_menu->AddSeparator();
276278

277279
// Add radio button group for theme selection
278-
auto theme_label = MenuItem::Create("Theme:", MenuItemType::Normal);
280+
auto theme_label =
281+
std::make_shared<MenuItem>("Theme:", MenuItemType::Normal);
279282
context_menu->AddItem(theme_label);
280283

281284
auto light_theme_item =
282-
MenuItem::Create("Light Theme", MenuItemType::Radio);
285+
std::make_shared<MenuItem>("Light Theme", MenuItemType::Radio);
283286
light_theme_item->SetRadioGroup(0); // Group 0
284287
light_theme_item->SetState(MenuItemState::Checked); // Default selection
285288
light_theme_item->AddListener<MenuItemClickedEvent>(
@@ -289,7 +292,8 @@ int main() {
289292
});
290293
context_menu->AddItem(light_theme_item);
291294

292-
auto dark_theme_item = MenuItem::Create("Dark Theme", MenuItemType::Radio);
295+
auto dark_theme_item =
296+
std::make_shared<MenuItem>("Dark Theme", MenuItemType::Radio);
293297
dark_theme_item->SetRadioGroup(0); // Same group as light theme
294298
dark_theme_item->AddListener<MenuItemClickedEvent>(
295299
[dark_theme_item](const MenuItemClickedEvent& event) {
@@ -298,7 +302,8 @@ int main() {
298302
});
299303
context_menu->AddItem(dark_theme_item);
300304

301-
auto auto_theme_item = MenuItem::Create("Auto Theme", MenuItemType::Radio);
305+
auto auto_theme_item =
306+
std::make_shared<MenuItem>("Auto Theme", MenuItemType::Radio);
302307
auto_theme_item->SetRadioGroup(0); // Same group
303308
auto_theme_item->AddListener<MenuItemClickedEvent>(
304309
[auto_theme_item](const MenuItemClickedEvent& event) {
@@ -311,7 +316,7 @@ int main() {
311316
context_menu->AddSeparator();
312317

313318
// Add exit item
314-
auto exit_item = MenuItem::Create("Exit", MenuItemType::Normal);
319+
auto exit_item = std::make_shared<MenuItem>("Exit", MenuItemType::Normal);
315320
exit_item->AddListener<MenuItemClickedEvent>(
316321
[&window_manager](const MenuItemClickedEvent& event) {
317322
std::cout << "Exit clicked from context menu" << std::endl;

src/capi/menu_c.cpp

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ native_menu_item_t native_menu_item_create(const char* text,
158158
return nullptr;
159159

160160
try {
161-
auto item = MenuItem::Create(text, convert_menu_item_type(type));
161+
auto item = std::make_shared<MenuItem>(text, convert_menu_item_type(type));
162162
void* handle = item.get();
163163
g_menu_items[handle] = item; // Store shared_ptr to keep object alive
164164
return static_cast<native_menu_item_t>(handle);
@@ -169,7 +169,7 @@ native_menu_item_t native_menu_item_create(const char* text,
169169

170170
native_menu_item_t native_menu_item_create_separator(void) {
171171
try {
172-
auto item = MenuItem::CreateSeparator();
172+
auto item = std::make_shared<MenuItem>("", MenuItemType::Separator);
173173
void* handle = item.get();
174174
g_menu_items[handle] = item; // Store shared_ptr to keep object alive
175175
return static_cast<native_menu_item_t>(handle);
@@ -220,12 +220,16 @@ native_menu_item_type_t native_menu_item_get_type(native_menu_item_t item) {
220220
}
221221

222222
void native_menu_item_set_label(native_menu_item_t item, const char* label) {
223-
if (!item || !label)
223+
if (!item)
224224
return;
225225

226226
try {
227227
auto menu_item = static_cast<MenuItem*>(item);
228-
menu_item->SetLabel(label);
228+
if (label) {
229+
menu_item->SetLabel(std::string(label));
230+
} else {
231+
menu_item->SetLabel(std::nullopt);
232+
}
229233
} catch (...) {
230234
// Ignore exceptions
231235
}
@@ -237,7 +241,13 @@ char* native_menu_item_get_label(native_menu_item_t item) {
237241

238242
try {
239243
auto menu_item = static_cast<MenuItem*>(item);
240-
std::string text = menu_item->GetLabel();
244+
auto textOpt = menu_item->GetLabel();
245+
246+
if (!textOpt.has_value()) {
247+
return nullptr;
248+
}
249+
250+
const std::string& text = textOpt.value();
241251

242252
// Allocate C string and copy content
243253
char* result = static_cast<char*>(malloc(text.length() + 1));
@@ -251,12 +261,16 @@ char* native_menu_item_get_label(native_menu_item_t item) {
251261
}
252262

253263
void native_menu_item_set_icon(native_menu_item_t item, const char* icon) {
254-
if (!item || !icon)
264+
if (!item)
255265
return;
256266

257267
try {
258268
auto menu_item = static_cast<MenuItem*>(item);
259-
menu_item->SetIcon(icon);
269+
if (icon) {
270+
menu_item->SetIcon(std::string(icon));
271+
} else {
272+
menu_item->SetIcon(std::nullopt);
273+
}
260274
} catch (...) {
261275
// Ignore exceptions
262276
}
@@ -268,7 +282,13 @@ char* native_menu_item_get_icon(native_menu_item_t item) {
268282

269283
try {
270284
auto menu_item = static_cast<MenuItem*>(item);
271-
std::string icon = menu_item->GetIcon();
285+
auto iconOpt = menu_item->GetIcon();
286+
287+
if (!iconOpt.has_value()) {
288+
return nullptr;
289+
}
290+
291+
const std::string& icon = iconOpt.value();
272292

273293
// Allocate C string and copy content
274294
char* result = static_cast<char*>(malloc(icon.length() + 1));
@@ -283,12 +303,16 @@ char* native_menu_item_get_icon(native_menu_item_t item) {
283303

284304
void native_menu_item_set_tooltip(native_menu_item_t item,
285305
const char* tooltip) {
286-
if (!item || !tooltip)
306+
if (!item)
287307
return;
288308

289309
try {
290310
auto menu_item = static_cast<MenuItem*>(item);
291-
menu_item->SetTooltip(tooltip);
311+
if (tooltip) {
312+
menu_item->SetTooltip(std::string(tooltip));
313+
} else {
314+
menu_item->SetTooltip(std::nullopt);
315+
}
292316
} catch (...) {
293317
// Ignore exceptions
294318
}
@@ -300,7 +324,13 @@ char* native_menu_item_get_tooltip(native_menu_item_t item) {
300324

301325
try {
302326
auto menu_item = static_cast<MenuItem*>(item);
303-
std::string tooltip = menu_item->GetTooltip();
327+
auto tooltipOpt = menu_item->GetTooltip();
328+
329+
if (!tooltipOpt.has_value()) {
330+
return nullptr;
331+
}
332+
333+
const std::string& tooltip = tooltipOpt.value();
304334

305335
// Allocate C string and copy content
306336
char* result = static_cast<char*>(malloc(tooltip.length() + 1));
@@ -630,7 +660,7 @@ bool native_menu_item_trigger(native_menu_item_t item) {
630660

631661
native_menu_t native_menu_create(void) {
632662
try {
633-
auto menu = Menu::Create();
663+
auto menu = std::make_shared<Menu>();
634664
void* handle = menu.get();
635665
g_menus[handle] = menu; // Store shared_ptr to keep object alive
636666
return static_cast<native_menu_t>(handle);

0 commit comments

Comments
 (0)