Skip to content

Commit 32602a6

Browse files
committed
Refactor menu event API to use event listeners
Replace callback-based menu and menu item events with a listener-based API. Update C and C++ interfaces to support adding/removing event listeners for menu item selection, state changes, and menu open/close events. Update examples to use new listener API. Remove legacy callback methods.
1 parent 8c02260 commit 32602a6

File tree

13 files changed

+842
-328
lines changed

13 files changed

+842
-328
lines changed

CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ add_subdirectory(src)
88
# Add example programs subdirectory
99
add_subdirectory(examples/display_example)
1010
add_subdirectory(examples/keyboard_example)
11-
add_subdirectory(examples/window_example)
11+
add_subdirectory(examples/menu_example)
12+
add_subdirectory(examples/menu_c_example)
1213
add_subdirectory(examples/tray_icon_example)
1314
add_subdirectory(examples/tray_icon_c_example)
15+
add_subdirectory(examples/window_example)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
project(menu_c_example)
3+
4+
set(CMAKE_C_STANDARD 11)
5+
6+
# Include the nativeapi headers
7+
include_directories(${CMAKE_SOURCE_DIR}/../../include)
8+
9+
# Add the executable
10+
add_executable(menu_c_example main.c)
11+
12+
# Link against the nativeapi library
13+
target_link_libraries(menu_c_example nativeapi)
14+
15+
# Platform-specific settings
16+
if(APPLE)
17+
find_library(COCOA_LIBRARY Cocoa)
18+
target_link_libraries(menu_c_example ${COCOA_LIBRARY})
19+
elseif(WIN32)
20+
target_link_libraries(menu_c_example user32 kernel32)
21+
elseif(UNIX)
22+
find_package(PkgConfig REQUIRED)
23+
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
24+
target_include_directories(menu_c_example PRIVATE ${GTK3_INCLUDE_DIRS})
25+
target_link_libraries(menu_c_example ${GTK3_LIBRARIES})
26+
endif()

examples/menu_c_example/main.c

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include "../../src/capi/menu_c.h"
5+
#include "../../src/capi/app_runner_c.h"
6+
7+
// Event callback functions
8+
void on_menu_item_selected(const void* event, void* user_data) {
9+
const native_menu_item_selected_event_t* selected_event = (const native_menu_item_selected_event_t*)event;
10+
const char* item_name = (const char*)user_data;
11+
12+
printf("[EVENT] Menu item selected: %s (ID: %ld, Text: %s)\n",
13+
item_name, selected_event->item_id, selected_event->item_text);
14+
}
15+
16+
void on_menu_item_state_changed(const void* event, void* user_data) {
17+
const native_menu_item_state_changed_event_t* state_event = (const native_menu_item_state_changed_event_t*)event;
18+
const char* item_name = (const char*)user_data;
19+
20+
printf("[EVENT] Menu item state changed: %s (ID: %ld, Checked: %s)\n",
21+
item_name, state_event->item_id, state_event->checked ? "true" : "false");
22+
}
23+
24+
void on_menu_will_open(const void* event, void* user_data) {
25+
const native_menu_will_open_event_t* open_event = (const native_menu_will_open_event_t*)event;
26+
const char* menu_name = (const char*)user_data;
27+
28+
printf("[EVENT] Menu will open: %s (ID: %ld)\n", menu_name, open_event->menu_id);
29+
}
30+
31+
void on_menu_will_close(const void* event, void* user_data) {
32+
const native_menu_will_close_event_t* close_event = (const native_menu_will_close_event_t*)event;
33+
const char* menu_name = (const char*)user_data;
34+
35+
printf("[EVENT] Menu will close: %s (ID: %ld)\n", menu_name, close_event->menu_id);
36+
}
37+
38+
int main() {
39+
printf("=== Menu C API Event System Example ===\n");
40+
41+
// Create a menu
42+
native_menu_t menu = native_menu_create();
43+
if (!menu) {
44+
printf("Failed to create menu\n");
45+
return 1;
46+
}
47+
48+
printf("Created menu successfully\n");
49+
50+
// Create menu items
51+
native_menu_item_t file_item = native_menu_item_create("New File", NATIVE_MENU_ITEM_TYPE_NORMAL);
52+
native_menu_item_t checkbox_item = native_menu_item_create("Word Wrap", NATIVE_MENU_ITEM_TYPE_CHECKBOX);
53+
native_menu_item_t radio_item1 = native_menu_item_create("View Mode 1", NATIVE_MENU_ITEM_TYPE_RADIO);
54+
native_menu_item_t radio_item2 = native_menu_item_create("View Mode 2", NATIVE_MENU_ITEM_TYPE_RADIO);
55+
native_menu_item_t exit_item = native_menu_item_create("Exit", NATIVE_MENU_ITEM_TYPE_NORMAL);
56+
57+
if (!file_item || !checkbox_item || !radio_item1 || !radio_item2 || !exit_item) {
58+
printf("Failed to create menu items\n");
59+
native_menu_destroy(menu);
60+
return 1;
61+
}
62+
63+
// Set up radio group
64+
native_menu_item_set_radio_group(radio_item1, 1);
65+
native_menu_item_set_radio_group(radio_item2, 1);
66+
native_menu_item_set_checked(radio_item1, true);
67+
68+
// Set keyboard accelerators
69+
native_keyboard_accelerator_t ctrl_n = { NATIVE_ACCELERATOR_MODIFIER_CTRL, "N" };
70+
native_keyboard_accelerator_t ctrl_q = { NATIVE_ACCELERATOR_MODIFIER_CTRL, "Q" };
71+
native_menu_item_set_accelerator(file_item, &ctrl_n);
72+
native_menu_item_set_accelerator(exit_item, &ctrl_q);
73+
74+
printf("Setting up event listeners using new event system...\n");
75+
76+
// Add event listeners using the new event system
77+
int file_listener = native_menu_item_add_listener(file_item, NATIVE_MENU_ITEM_EVENT_SELECTED,
78+
on_menu_item_selected, (void*)"New File");
79+
80+
int checkbox_select_listener = native_menu_item_add_listener(checkbox_item, NATIVE_MENU_ITEM_EVENT_SELECTED,
81+
on_menu_item_selected, (void*)"Word Wrap");
82+
83+
int checkbox_state_listener = native_menu_item_add_listener(checkbox_item, NATIVE_MENU_ITEM_EVENT_STATE_CHANGED,
84+
on_menu_item_state_changed, (void*)"Word Wrap");
85+
86+
int radio1_state_listener = native_menu_item_add_listener(radio_item1, NATIVE_MENU_ITEM_EVENT_STATE_CHANGED,
87+
on_menu_item_state_changed, (void*)"View Mode 1");
88+
89+
int radio2_state_listener = native_menu_item_add_listener(radio_item2, NATIVE_MENU_ITEM_EVENT_STATE_CHANGED,
90+
on_menu_item_state_changed, (void*)"View Mode 2");
91+
92+
int exit_listener = native_menu_item_add_listener(exit_item, NATIVE_MENU_ITEM_EVENT_SELECTED,
93+
on_menu_item_selected, (void*)"Exit");
94+
95+
// Add menu event listeners
96+
int menu_open_listener = native_menu_add_listener(menu, NATIVE_MENU_EVENT_WILL_OPEN,
97+
on_menu_will_open, (void*)"Main Menu");
98+
99+
int menu_close_listener = native_menu_add_listener(menu, NATIVE_MENU_EVENT_WILL_CLOSE,
100+
on_menu_will_close, (void*)"Main Menu");
101+
102+
// Check if listeners were added successfully
103+
if (file_listener == -1 || checkbox_select_listener == -1 || checkbox_state_listener == -1 ||
104+
radio1_state_listener == -1 || radio2_state_listener == -1 || exit_listener == -1 ||
105+
menu_open_listener == -1 || menu_close_listener == -1) {
106+
printf("Failed to add some event listeners\n");
107+
} else {
108+
printf("All event listeners added successfully\n");
109+
printf("Listener IDs: file=%d, checkbox_select=%d, checkbox_state=%d, radio1=%d, radio2=%d, exit=%d, menu_open=%d, menu_close=%d\n",
110+
file_listener, checkbox_select_listener, checkbox_state_listener,
111+
radio1_state_listener, radio2_state_listener, exit_listener,
112+
menu_open_listener, menu_close_listener);
113+
}
114+
115+
// Add items to menu
116+
native_menu_add_item(menu, file_item);
117+
native_menu_add_separator(menu);
118+
native_menu_add_item(menu, checkbox_item);
119+
native_menu_add_separator(menu);
120+
native_menu_add_item(menu, radio_item1);
121+
native_menu_add_item(menu, radio_item2);
122+
native_menu_add_separator(menu);
123+
native_menu_add_item(menu, exit_item);
124+
125+
printf("Menu created with %zu items\n", native_menu_get_item_count(menu));
126+
127+
// Demonstrate programmatic triggering
128+
printf("\n=== Testing Programmatic Event Triggering ===\n");
129+
130+
printf("Triggering file item...\n");
131+
native_menu_item_trigger(file_item);
132+
133+
printf("Triggering checkbox item...\n");
134+
native_menu_item_trigger(checkbox_item);
135+
136+
printf("Triggering checkbox item again...\n");
137+
native_menu_item_trigger(checkbox_item);
138+
139+
printf("Switching radio button...\n");
140+
native_menu_item_trigger(radio_item2);
141+
142+
printf("Triggering exit item...\n");
143+
native_menu_item_trigger(exit_item);
144+
145+
// Demonstrate listener removal
146+
printf("\n=== Testing Listener Removal ===\n");
147+
148+
printf("Removing checkbox state listener...\n");
149+
if (native_menu_item_remove_listener(checkbox_item, checkbox_state_listener)) {
150+
printf("Checkbox state listener removed successfully\n");
151+
} else {
152+
printf("Failed to remove checkbox state listener\n");
153+
}
154+
155+
printf("Triggering checkbox item after removing state listener...\n");
156+
native_menu_item_trigger(checkbox_item);
157+
158+
// Show menu as context menu (this may not work in console applications)
159+
printf("\n=== Attempting to Show Context Menu ===\n");
160+
printf("Note: Context menu display may not work in console applications\n");
161+
162+
if (native_menu_show_as_context_menu(menu, 100, 100)) {
163+
printf("Context menu shown successfully\n");
164+
} else {
165+
printf("Failed to show context menu (expected in console app)\n");
166+
}
167+
168+
// Test additional functionality
169+
printf("\n=== Testing Additional Functionality ===\n");
170+
171+
native_menu_item_t additional_item = native_menu_item_create("Additional Test", NATIVE_MENU_ITEM_TYPE_NORMAL);
172+
173+
// Test that we can add multiple listeners for the same event
174+
int additional_listener1 = native_menu_item_add_listener(additional_item, NATIVE_MENU_ITEM_EVENT_SELECTED,
175+
on_menu_item_selected, (void*)"Additional Test 1");
176+
int additional_listener2 = native_menu_item_add_listener(additional_item, NATIVE_MENU_ITEM_EVENT_SELECTED,
177+
on_menu_item_selected, (void*)"Additional Test 2");
178+
179+
printf("Added multiple listeners for the same event\n");
180+
printf("Triggering item with multiple listeners...\n");
181+
native_menu_item_trigger(additional_item);
182+
183+
// Remove one listener
184+
native_menu_item_remove_listener(additional_item, additional_listener1);
185+
printf("Removed first listener, triggering again...\n");
186+
native_menu_item_trigger(additional_item);
187+
188+
native_menu_item_destroy(additional_item);
189+
190+
printf("\n=== Event System Demo Complete ===\n");
191+
printf("This example demonstrates:\n");
192+
printf("1. Creating menus and menu items with different types\n");
193+
printf("2. Using the new event listener API with native_menu_item_add_listener()\n");
194+
printf("3. Handling NATIVE_MENU_ITEM_EVENT_SELECTED and NATIVE_MENU_ITEM_EVENT_STATE_CHANGED\n");
195+
printf("4. Handling NATIVE_MENU_EVENT_WILL_OPEN and NATIVE_MENU_EVENT_WILL_CLOSE\n");
196+
printf("5. Programmatic event triggering\n");
197+
printf("6. Event listener removal with native_menu_item_remove_listener()\n");
198+
printf("7. Multiple listeners for the same event type\n");
199+
200+
// Cleanup
201+
native_menu_item_destroy(file_item);
202+
native_menu_item_destroy(checkbox_item);
203+
native_menu_item_destroy(radio_item1);
204+
native_menu_item_destroy(radio_item2);
205+
native_menu_item_destroy(exit_item);
206+
native_menu_destroy(menu);
207+
208+
return 0;
209+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
project(menu_example)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
6+
# Include the nativeapi headers
7+
include_directories(${CMAKE_SOURCE_DIR}/../../include)
8+
9+
# Add the executable
10+
add_executable(menu_example main.cpp)
11+
12+
# Link against the nativeapi library
13+
target_link_libraries(menu_example nativeapi)
14+
15+
# Platform-specific settings
16+
if(APPLE)
17+
find_library(COCOA_LIBRARY Cocoa)
18+
target_link_libraries(menu_example ${COCOA_LIBRARY})
19+
elseif(WIN32)
20+
target_link_libraries(menu_example user32 kernel32)
21+
elseif(UNIX)
22+
find_package(PkgConfig REQUIRED)
23+
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
24+
target_include_directories(menu_example PRIVATE ${GTK3_INCLUDE_DIRS})
25+
target_link_libraries(menu_example ${GTK3_LIBRARIES})
26+
endif()

0 commit comments

Comments
 (0)