|
[Allegro5] Popup menu fails to display |
utz000
Member #16,715
July 2017
|
Hi, it's me again with another native dialogs problem. This time, it's al_popup_menu() giving me trouble. The example below should display a simple popup menu on left mouse click. al_popup_menu() returns true indicating it was successful, but no popup menu is actually displayed, except in some rare circumstances. It tends to work on the very first run after compiling for the first time, but not afterwards. Occasionally the menu also shows up if I do a short drag to the lower left before releasing the mouse button. Unlike with the other issue, registering mouse events and using that to detect the button press will not help here. So I'm pretty sure I'm doing something wrong. For reference, my setup is Debian/GTK 3.22/Allegro 5.2.2. 1#include <iostream>
2#include <allegro5/allegro.h>
3#include <allegro5/allegro_native_dialog.h>
4
5int main(int argc, char **argv){
6
7 if (!al_init()) {
8 std::cout << "Allegro initialization failed.\n";
9 return -1;
10 }
11
12 ALLEGRO_DISPLAY *display;
13 ALLEGRO_TIMER *timer;
14 ALLEGRO_EVENT_QUEUE *queue;
15 ALLEGRO_MOUSE_STATE mouse;
16 ALLEGRO_MENU *menu;
17 ALLEGRO_EVENT event;
18
19 if (!al_init_native_dialog_addon()) {
20 std::cout << "Failed to initialize native dialogs.\n";
21 return -1;
22 }
23
24#ifdef ALLEGRO_GTK_TOPLEVEL
25 al_set_new_display_flags(ALLEGRO_GTK_TOPLEVEL);
26#endif
27
28 display = al_create_display(640, 480);
29 if (!display) {
30 std::cout << "Failed to initialize display.\n";
31 al_uninstall_system();
32 return -1;
33 }
34
35 if (!al_install_mouse()) {
36 std::cout << "Failed to initialize keyboard.\n";
37 al_destroy_display(display);
38 al_uninstall_system();
39 return -1;
40 }
41
42 timer = al_create_timer(1.0f/25.0f);
43 if (!timer) {
44 std::cout << "Failed to initialize timer.\n";
45 al_destroy_display(display);
46 al_uninstall_system();
47 return -1;
48 }
49
50 menu = al_create_popup_menu();
51 al_append_menu_item(menu, "Option", 1, 0, nullptr, nullptr);
52 bool menuDisplayed = false;
53
54 queue = al_create_event_queue();
55
56 if(!queue) {
57 std::cout << "Failed to initialize event queue.\n";
58 al_destroy_timer(timer);
59 al_destroy_display(display);
60 al_uninstall_system();
61 return -1;
62 }
63 al_register_event_source(queue, al_get_display_event_source(display));
64 al_register_event_source(queue, al_get_timer_event_source(timer));
65// al_register_event_source(queue, al_get_mouse_event_source());
66 al_start_timer(timer);
67
68 while (true) {
69
70 al_wait_for_event(queue, &event);
71
72 //neither this nor the timed version work
73// if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
74//
75// if (event.mouse.button == 1 && !menuDisplayed) {
76//
77// if (al_popup_menu(menu, display)) std::cout << "Displaying menu... or not\n";
78// else std::cout << "Displaying menu failed";
79// menuDisplayed = true;
80// }
81// else menuDisplayed = false;
82// }
83
84 if (event.type == ALLEGRO_EVENT_TIMER) {
85
86 al_get_mouse_state(&mouse);
87
88 if (mouse.buttons & 1 && !menuDisplayed) {
89
90 if (al_popup_menu(menu, display)) std::cout << "Displaying menu... or not\n";
91 else std::cout << "Displaying menu failed";
92 menuDisplayed = true;
93 }
94 else if (mouse.buttons & 2) menuDisplayed = false;
95 }
96
97 else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break;
98 }
99
100 al_destroy_event_queue(queue);
101 al_destroy_timer(timer);
102 al_destroy_menu(menu);
103 al_destroy_display(display);
104 al_uninstall_system();
105 return 0;
106}
|
Eric Johnson
Member #14,841
January 2013
|
Take a look at ex_menu.c for a working example of creating context menus. It is located in the examples directory of wherever you built Allegro 5. ex_menu.c 1#include "allegro5/allegro.h"
2#include "allegro5/allegro_native_dialog.h"
3#include "allegro5/allegro_image.h"
4#include <stdio.h>
5#include <math.h>
6
7#include "common.c"
8
9/* The following is a list of menu item ids. They can be any non-zero, positive
10 * integer. A menu item must have an id in order for it to generate an event.
11 * Also, each menu item's id should be unique to get well defined results.
12 */
13enum {
14 FILE_ID = 1,
15 FILE_OPEN_ID,
16 FILE_RESIZE_ID,
17 FILE_FULLSCREEN_ID,
18 FILE_CLOSE_ID,
19 FILE_EXIT_ID,
20 DYNAMIC_ID,
21 DYNAMIC_CHECKBOX_ID,
22 DYNAMIC_DISABLED_ID,
23 DYNAMIC_DELETE_ID,
24 DYNAMIC_CREATE_ID,
25 HELP_ABOUT_ID
26};
27
28/* This is one way to define a menu. The entire system, nested menus and all,
29 * can be defined by this single array.
30 */
31ALLEGRO_MENU_INFO main_menu_info[] = {
32 ALLEGRO_START_OF_MENU("&File", FILE_ID),
33 { "&Open", FILE_OPEN_ID, 0, NULL },
34 ALLEGRO_MENU_SEPARATOR,
35 { "E&xit", FILE_EXIT_ID, 0, NULL },
36 ALLEGRO_END_OF_MENU,
37
38 ALLEGRO_START_OF_MENU("&Dynamic Options", DYNAMIC_ID),
39 { "&Checkbox", DYNAMIC_CHECKBOX_ID, ALLEGRO_MENU_ITEM_CHECKED, NULL },
40 { "&Disabled", DYNAMIC_DISABLED_ID, ALLEGRO_MENU_ITEM_DISABLED, NULL },
41 { "DELETE ME!", DYNAMIC_DELETE_ID, 0, NULL },
42 { "Click Me", DYNAMIC_CREATE_ID, 0, NULL },
43 ALLEGRO_END_OF_MENU,
44
45 ALLEGRO_START_OF_MENU("&Help", 0),
46 { "&About", HELP_ABOUT_ID, 0, NULL },
47 ALLEGRO_END_OF_MENU,
48
49 ALLEGRO_END_OF_MENU
50};
51
52/* This is the menu on the secondary windows. */
53ALLEGRO_MENU_INFO child_menu_info[] = {
54 ALLEGRO_START_OF_MENU("&File", 0),
55 { "&Close", FILE_CLOSE_ID, 0, NULL },
56 ALLEGRO_END_OF_MENU,
57 ALLEGRO_END_OF_MENU
58};
59
60int main(int argc, char **argv)
61{
62 const int initial_width = 320;
63 const int initial_height = 200;
64 int windows_menu_height = 0;
65 int dcount = 0;
66
67 ALLEGRO_DISPLAY *display;
68 ALLEGRO_MENU *menu;
69 ALLEGRO_EVENT_QUEUE *queue;
70 ALLEGRO_TIMER *timer;
71 bool redraw = true;
72 bool menu_visible = true;
73 ALLEGRO_MENU *pmenu;
74 ALLEGRO_BITMAP *bg;
75
76 (void)argc;
77 (void)argv;
78
79 if (!al_init()) {
80 abort_example("Could not init Allegro.\n");
81 }
82 if (!al_init_native_dialog_addon()) {
83 abort_example("Could not init the native dialog addon.\n");
84 }
85 al_init_image_addon();
86 al_install_keyboard();
87 al_install_mouse();
88
89 queue = al_create_event_queue();
90
91#ifdef ALLEGRO_GTK_TOPLEVEL
92 /* ALLEGRO_GTK_TOPLEVEL is necessary for menus with GTK. */
93 al_set_new_display_flags(ALLEGRO_RESIZABLE | ALLEGRO_GTK_TOPLEVEL);
94#else
95 al_set_new_display_flags(ALLEGRO_RESIZABLE);
96#endif
97 display = al_create_display(initial_width, initial_height);
98 if (!display) {
99 abort_example("Error creating display\n");
100 }
101 al_set_window_title(display, "ex_menu - Main Window");
102
103 menu = al_build_menu(main_menu_info);
104 if (!menu) {
105 abort_example("Error creating menu\n");
106 }
107
108 /* Add an icon to the Help/About item. Note that Allegro assumes ownership
109 * of the bitmap. */
110 al_set_menu_item_icon(menu, HELP_ABOUT_ID, al_load_bitmap("data/icon.tga"));
111
112 if (!al_set_display_menu(display, menu)) {
113 /* Since the menu could not be attached to the window, then treat it as
114 * a popup menu instead. */
115 pmenu = al_clone_menu_for_popup(menu);
116 al_destroy_menu(menu);
117 menu = pmenu;
118 }
119 else {
120 /* Create a simple popup menu used when right clicking. */
121 pmenu = al_create_popup_menu();
122 if (pmenu) {
123 al_append_menu_item(pmenu, "&Open", FILE_OPEN_ID, 0, NULL, NULL);
124 al_append_menu_item(pmenu, "&Resize", FILE_RESIZE_ID, 0, NULL, NULL);
125 al_append_menu_item(pmenu, "&Fullscreen window", FILE_FULLSCREEN_ID, 0, NULL, NULL);
126 al_append_menu_item(pmenu, "E&xit", FILE_EXIT_ID, 0, NULL, NULL);
127 }
128 }
129
130 timer = al_create_timer(1.0 / 60);
131
132 al_register_event_source(queue, al_get_display_event_source(display));
133 al_register_event_source(queue, al_get_default_menu_event_source());
134 al_register_event_source(queue, al_get_keyboard_event_source());
135 al_register_event_source(queue, al_get_mouse_event_source());
136 al_register_event_source(queue, al_get_timer_event_source(timer));
137
138 bg = al_load_bitmap("data/mysha.pcx");
139
140 al_start_timer(timer);
141
142 while (true) {
143 ALLEGRO_EVENT event;
144
145 if (redraw && al_is_event_queue_empty(queue)) {
146 redraw = false;
147 if (bg) {
148 float t = al_get_timer_count(timer) * 0.1;
149 float sw = al_get_bitmap_width(bg);
150 float sh = al_get_bitmap_height(bg);
151 float dw = al_get_display_width(display);
152 float dh = al_get_display_height(display);
153 float cx = dw/2;
154 float cy = dh/2;
155 dw *= 1.2 + 0.2 * cos(t);
156 dh *= 1.2 + 0.2 * cos(1.1 * t);
157 al_draw_scaled_bitmap(bg, 0, 0, sw, sh,
158 cx - dw/2, cy - dh/2, dw, dh, 0);
159 }
160 al_flip_display();
161 }
162
163 al_wait_for_event(queue, &event);
164
165 if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
166 if (event.display.source == display) {
167 /* Closing the primary display */
168 break;
169 }
170 else {
171 /* Closing a secondary display */
172 al_set_display_menu(event.display.source, NULL);
173 al_destroy_display(event.display.source);
174 }
175 }
176 else if (event.type == ALLEGRO_EVENT_MENU_CLICK) {
177 /* data1: id
178 * data2: display (could be null)
179 * data3: menu (could be null)
180 */
181 if (event.user.data2 == (intptr_t) display) {
182 /* The main window. */
183 if (event.user.data1 == FILE_OPEN_ID) {
184 ALLEGRO_DISPLAY *d = al_create_display(320, 240);
185 if (d) {
186 ALLEGRO_MENU *menu = al_build_menu(child_menu_info);
187 al_set_display_menu(d, menu);
188 al_clear_to_color(al_map_rgb(0,0,0));
189 al_flip_display();
190 al_register_event_source(queue, al_get_display_event_source(d));
191 al_set_target_backbuffer(display);
192 al_set_window_title(d, "ex_menu - Child Window");
193 }
194 }
195 else if (event.user.data1 == DYNAMIC_CHECKBOX_ID) {
196 al_set_menu_item_flags(menu, DYNAMIC_DISABLED_ID, al_get_menu_item_flags(menu, DYNAMIC_DISABLED_ID) ^ ALLEGRO_MENU_ITEM_DISABLED);
197 al_set_menu_item_caption(menu, DYNAMIC_DISABLED_ID,
198 (al_get_menu_item_flags(menu, DYNAMIC_DISABLED_ID) & ALLEGRO_MENU_ITEM_DISABLED) ?
199 "&Disabled" : "&Enabled");
200 }
201 else if (event.user.data1 == DYNAMIC_DELETE_ID) {
202 al_remove_menu_item(menu, DYNAMIC_DELETE_ID);
203 }
204 else if (event.user.data1 == DYNAMIC_CREATE_ID) {
205 if (dcount < 5) {
206 char new_name[10];
207
208 ++dcount;
209 if (dcount == 1) {
210 /* append a separator */
211 al_append_menu_item(al_find_menu(menu, DYNAMIC_ID), NULL, 0, 0, NULL, NULL);
212 }
213
214 sprintf(new_name, "New #%d", dcount);
215 al_append_menu_item(al_find_menu(menu, DYNAMIC_ID), new_name, 0, 0, NULL, NULL);
216
217 if (dcount == 5) {
218 /* disable the option */
219 al_set_menu_item_flags(menu, DYNAMIC_CREATE_ID, ALLEGRO_MENU_ITEM_DISABLED);
220 }
221 }
222 }
223 else if (event.user.data1 == HELP_ABOUT_ID) {
224 al_show_native_message_box(display, "About", "ex_menu",
225 "This is a sample program that shows how to use menus",
226 "OK", 0);
227 }
228 else if (event.user.data1 == FILE_EXIT_ID) {
229 break;
230 }
231 else if (event.user.data1 == FILE_RESIZE_ID) {
232 int w = al_get_display_width(display) * 2;
233 int h = al_get_display_height(display) * 2;
234 if (w > 960)
235 w = 960;
236 if (h > 600)
237 h = 600;
238 if (menu_visible)
239 al_resize_display(display, w, h + windows_menu_height);
240 else
241 al_resize_display(display, w, h);
242 }
243 else if (event.user.data1 == FILE_FULLSCREEN_ID) {
244 int flags = al_get_display_flags(display);
245 bool value = (flags & ALLEGRO_FULLSCREEN_WINDOW) ? true : false;
246 al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, !value);
247 }
248 }
249 else {
250 /* The child window */
251 if (event.user.data1 == FILE_CLOSE_ID) {
252 ALLEGRO_DISPLAY *d = (ALLEGRO_DISPLAY *) event.user.data2;
253 if (d) {
254 al_set_display_menu(d, NULL);
255 al_destroy_display(d);
256 }
257 }
258 }
259 }
260 else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
261 /* Popup a context menu on a right click. */
262 if (event.mouse.display == display && event.mouse.button == 2) {
263 if (pmenu)
264 al_popup_menu(pmenu, display);
265 }
266 }
267 else if (event.type == ALLEGRO_EVENT_KEY_CHAR) {
268 /* Toggle the menu if the spacebar is pressed */
269 if (event.keyboard.display == display) {
270 if (event.keyboard.unichar == ' ') {
271 if (menu_visible)
272 al_remove_display_menu(display);
273 else
274 al_set_display_menu(display, menu);
275
276 menu_visible = !menu_visible;
277 }
278 }
279 }
280 else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) {
281 al_acknowledge_resize(display);
282 redraw = true;
283
284#ifdef ALLEGRO_WINDOWS
285 /* XXX The Windows implementation currently uses part of the client's
286 * height to render the window. This triggers a resize event, which
287 * can be trapped and used to compute the menu height, and then
288 * resize the display again to what we expect it to be.
289 */
290 if (event.display.source == display && windows_menu_height == 0) {
291 windows_menu_height = initial_height - al_get_display_height(display);
292 al_resize_display(display, initial_width, initial_height + windows_menu_height);
293 }
294#endif
295 }
296 else if (event.type == ALLEGRO_EVENT_TIMER) {
297 redraw = true;
298 }
299 }
300
301 /* You must remove the menu before destroying the display to free resources */
302 al_set_display_menu(display, NULL);
303
304 return 0;
305}
common.c 1#include <stdio.h>
2#include <stdarg.h>
3
4#ifdef ALLEGRO_ANDROID
5 #include "allegro5/allegro_android.h"
6#endif
7
8void init_platform_specific(void);
9void abort_example(char const *format, ...);
10void open_log(void);
11void open_log_monospace(void);
12void close_log(bool wait_for_user);
13void log_printf(char const *format, ...);
14
15void init_platform_specific(void)
16{
17#ifdef ALLEGRO_ANDROID
18 al_install_touch_input();
19 al_android_set_apk_file_interface();
20#endif
21}
22
23#ifdef ALLEGRO_POPUP_EXAMPLES
24
25#include "allegro5/allegro_native_dialog.h"
26
27ALLEGRO_TEXTLOG *textlog = NULL;
28
29void abort_example(char const *format, ...)
30{
31 char str[1024];
32 va_list args;
33 ALLEGRO_DISPLAY *display;
34
35 va_start(args, format);
36 vsnprintf(str, sizeof str, format, args);
37 va_end(args);
38
39 if (al_init_native_dialog_addon()) {
40 display = al_is_system_installed() ? al_get_current_display() : NULL;
41 al_show_native_message_box(display, "Error", "Cannot run example", str, NULL, 0);
42 }
43 else {
44 fprintf(stderr, "%s", str);
45 }
46 exit(1);
47}
48
49void open_log(void)
50{
51 if (al_init_native_dialog_addon()) {
52 textlog = al_open_native_text_log("Log", 0);
53 }
54}
55
56void open_log_monospace(void)
57{
58 if (al_init_native_dialog_addon()) {
59 textlog = al_open_native_text_log("Log", ALLEGRO_TEXTLOG_MONOSPACE);
60 }
61}
62
63void close_log(bool wait_for_user)
64{
65 if (textlog && wait_for_user) {
66 ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
67 al_register_event_source(queue, al_get_native_text_log_event_source(
68 textlog));
69 al_wait_for_event(queue, NULL);
70 al_destroy_event_queue(queue);
71 }
72
73 al_close_native_text_log(textlog);
74 textlog = NULL;
75}
76
77void log_printf(char const *format, ...)
78{
79 char str[1024];
80 va_list args;
81 va_start(args, format);
82 vsnprintf(str, sizeof str, format, args);
83 va_end(args);
84 al_append_native_text_log(textlog, "%s", str);
85}
86
87#else
88
89void abort_example(char const *format, ...)
90{
91 va_list args;
92 va_start(args, format);
93 vfprintf(stderr, format, args);
94 va_end(args);
95 exit(1);
96}
97
98void open_log(void)
99{
100}
101
102void open_log_monospace(void)
103{
104}
105
106void close_log(bool wait_for_user)
107{
108 (void)wait_for_user;
109}
110
111void log_printf(char const *format, ...)
112{
113 va_list args;
114 va_start(args, format);
115 #ifdef ALLEGRO_ANDROID
116 char x[1024];
117 vsnprintf(x, sizeof x, format, args);
118 ALLEGRO_TRACE_CHANNEL_LEVEL("log", 1)(x);
119 #else
120 vprintf(format, args);
121 #endif
122 va_end(args);
123}
124
125#endif
126
127/* vim: set sts=3 sw=3 et: */
|
utz000
Member #16,715
July 2017
|
I already looked at the example, of course, but I can't wrap my head around it. The only major difference I can spot is that the example code listens for a MOUSE_BUTTON_UP event, rather than a MOUSE_BUTTON_DOWN event. Sure enough, if I register mouse events and listen for a MOUSE_BUTTON_UP event, it works... if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { if (event.mouse.button == 1 && !menuDisplayed) { if (al_popup_menu(menu, display)) std::cout << "Displaying menu... or not\n"; else std::cout << "Displaying menu failed"; menuDisplayed = true; } else menuDisplayed = false; } ... but only in this minimal example, not in my actual code. Still, I don't get why it won't work with MOUSE_BUTTON_DOWN or the the timed version. As mentioned, al_popup_menu() does return true, it just doesn't show the menu. Also, no MENU_CLICK events are generated, in any case. Anyway, I'm trying to break the minimal example with MOUSE_BUTTON_UP at the moment, will report back later if I find something. Update:
Update 3: |
Eric Johnson
Member #14,841
January 2013
|
I'm not too familiar with the native dialog addon nor its functions, so I'm not sure why it's giving you so much trouble. I'm glad you found a workaround though. Hopefully someone more knowledgeable can help you further.
|
utz000
Member #16,715
July 2017
|
Well, for now all my Allegro problems are solved Aside from these, working with the library has been a breeze so far. The interface is very well design imo, and the documentation is great, too. Concerning the problems, I guess they're partially due to the fact that I'm still a programming novice. On the other hand I guess that the native_dialog add-on simply doesn't get used that much, especially not with GTK - most game designers will probably design their own menus. So some corner cases might simply have slipped under the radar. Anyway, I'll look a bit more into these issues and try to find out what exactly is going on before opening some issues on github. I guess a bunch of Allegro devs might be on holiday at the moment anyway |
|