|
Allegro 5.1.8 Native Menus OSX |
Malcolm Harrow
Member #15,833
December 2014
|
Hi I'm trying to create a native menu in OS X with the following structure: File I can't get this to work .. neither recent item appears, I get: File What have I done wrong ? ALLEGRO_MENU *menu = al_create_menu(); if ((menu == NULL) || (file_menu == NULL) || (recent_menu == NULL)) |
Trent Gamblin
Member #261
April 2000
|
Post a complete example in <code> tags.
|
Malcolm Harrow
Member #15,833
December 2014
|
Many thanks for taking an interest in my issue. Here is the code. I've also attached some screenshots showing what I get and another showing the effect I want (sub-menu item from Xcode). 1//
2// main.c
3// TestAllegro
4//
5// Created by Malcolm on 20/12/14.
6//
7// Trying to get:
8// File
9// Open
10// Open Recent > Recent 1
11// Recent 2
12// Exit
13//
14//
15// Get:
16// File
17// Open
18// Open Recent
19// Exit
20//
21//
22
23#include <stdio.h>
24#include <allegro5/allegro.h>
25#include <allegro5/allegro_native_dialog.h>
26
27void handleError(char *e)
28{
29 printf("%s\n", e);
30 exit(1);
31}
32
33int main(int argc, char **argv)
34{
35 if (!al_init()) handleError("Error al_init");
36
37 ALLEGRO_DISPLAY *display = al_create_display(640, 480);
38 if (!display) handleError("Error al_create_display");
39
40 if (!al_install_keyboard()) handleError("Error al_install_keyboard");
41
42 ALLEGRO_MENU *menu = al_create_menu();
43 ALLEGRO_MENU *file_menu = al_create_menu();
44 ALLEGRO_MENU *recent_menu = al_create_menu();
45
46 if ((menu == NULL) || (file_menu == NULL) || (recent_menu == NULL)) handleError("Error al_create_menu");
47
48 al_append_menu_item(recent_menu, "Recent 1", 14, 0, NULL, NULL);
49 al_append_menu_item(recent_menu, "Recent 2", 15, 0, NULL, NULL);
50
51 al_append_menu_item(file_menu, "&Open", 1, 0, NULL, NULL);
52 al_append_menu_item(file_menu, "Open Recent...", 2, 0, NULL, recent_menu);
53 al_append_menu_item(file_menu, "Exit", 3, 0, NULL, NULL);
54
55 al_append_menu_item(menu, "File", 0, 0, NULL, file_menu);
56
57 al_set_display_menu(display, menu);
58
59
60 ALLEGRO_EVENT_QUEUE *events = al_create_event_queue();
61 al_register_event_source(events, al_get_display_event_source(display));
62 al_register_event_source(events, al_get_default_menu_event_source());
63
64 bool quited = false;
65
66 while (!quited)
67 {
68 ALLEGRO_EVENT event;
69
70 al_wait_for_event(events, &event);
71 switch (event.type)
72 {
73 case ALLEGRO_EVENT_DISPLAY_CLOSE:
74 quited = true;
75 break;
76
77 case ALLEGRO_EVENT_MENU_CLICK:
78 if (event.user.data1 == 3) quited = true;
79 break;
80 }
81 }
82
83 return 0;
84}
85END_OF_MAIN();
|
Trent Gamblin
Member #261
April 2000
|
One thing you're not doing is calling al_init_native_dialog_addon(). That doesn't seem to fix the issue but is necessary. I compiled your example with Allegro debug libraries and it crashes without that. I'll look further for the rest of the problem. EDIT: Are you able to compile Allegro for OS X yourself? Well maybe that's a dumb question since there are no binaries. Try the attached patch and let me know how it works.
|
Malcolm Harrow
Member #15,833
December 2014
|
Thanks .. I added this in too, but it didn't seem to make any difference on my copy either. // start of snippet ... int main(int argc, char **argv) { if (!al_init()) handleError("Error al_init"); if (!al_init_native_dialog_addon()) handleError("Error al_init_native_dialog_addon"); ALLEGRO_DISPLAY *display = al_create_display(640, 480); if (!display) handleError("Error al_create_display"); // end of snippet ... EDIT: I just saw your edit. Yes, I compiled the libraries myself. Let me try this later. Many thanks! |
Todd Cope
Member #998
November 2000
|
This discussion might be relevant. There are some patches in that thread that never got accepted. I'm not sure whether or not any other work has been done on the menu code since then. At that point in time, the OS X implementation was pretty broken. |
Malcolm Harrow
Member #15,833
December 2014
|
Sorry that took a while .. I'd forgotten how I'd compiled the libraries Interestingly, I could only get a good compile by getting the source from git, the copy on the download section gave me a runtime error. Not sure why this would be the case. Anyway .. success !!! The patch appears to work .. I will test further! Attached are screen shots when you initially select the menu then when you hover over the popup. Thank you so much! To the point above, how do we make sure this patch is included in the next release ? Is there a daily/weekly build process ? Regards |
Trent Gamblin
Member #261
April 2000
|
Thanks. Please let me know how your further testing goes. I'll commit this to git now. We haven't done a release in a few months but there has been some talk about it. My recommendation is to use git until we do.
|
Malcolm Harrow
Member #15,833
December 2014
|
I thought I would try al_build_menu() .. I copied the menu structure from the online manual. I don't get an "About" item under the help menu .. but I do get the items from sub menu repeated again .. see screenshots. Did we just break this ? Regards 1//
2// main.c
3// TestAllegro
4//
5// Created by Malcolm on 20/12/14.
6//
7// Trying to get:
8// File
9// Open
10// Open Recent > Recent 1
11// Recent 2
12// Exit
13//
14//
15// Get:
16// File
17// Open
18// Open Recent
19// Exit
20//
21//
22
23#include <stdio.h>
24#include <allegro5/allegro.h>
25#include <allegro5/allegro_native_dialog.h>
26
27void handleError(char *e)
28{
29 printf("%s\n", e);
30 exit(1);
31}
32
33int main(int argc, char **argv)
34{
35 if (!al_init()) handleError("Error al_init");
36 if (!al_init_native_dialog_addon()) handleError("Error al_init_native_dialog_addon");
37
38
39 ALLEGRO_DISPLAY *display = al_create_display(640, 480);
40 if (!display) handleError("Error al_create_display");
41
42
43
44 if (!al_install_keyboard()) handleError("Error al_install_keyboard");
45
46// Building menu manually now works
47//
48// ALLEGRO_MENU *menu = al_create_menu();
49// ALLEGRO_MENU *file_menu = al_create_menu();
50// ALLEGRO_MENU *recent_menu = al_create_menu();
51//
52// if ((menu == NULL) || (file_menu == NULL) || (recent_menu == NULL)) handleError("Error al_create_menu");
53//
54// al_append_menu_item(recent_menu, "Recent 1", 14, 0, NULL, NULL);
55// al_append_menu_item(recent_menu, "Recent 2", 15, 0, NULL, NULL);
56//
57// al_append_menu_item(file_menu, "&Open", 1, 0, NULL, NULL);
58// al_append_menu_item(file_menu, "Open Recent...", 2, 0, NULL, recent_menu);
59// al_append_menu_item(file_menu, "Exit", 3, 0, NULL, NULL);
60//
61// al_append_menu_item(menu, "File", 0, 0, NULL, file_menu);
62
63 ALLEGRO_MENU_INFO menu_info[] = {
64 ALLEGRO_START_OF_MENU("&File", 1),
65 { "&Open", 2, 0, NULL },
66 ALLEGRO_START_OF_MENU("Open &Recent...", 3),
67 { "Recent 1", 4, 0, NULL },
68 { "Recent 2", 5, 0, NULL },
69 ALLEGRO_END_OF_MENU,
70 ALLEGRO_MENU_SEPARATOR,
71 { "E&xit", 6, 0, NULL },
72 ALLEGRO_END_OF_MENU,
73 ALLEGRO_START_OF_MENU("&Help", 7),
74 {"&About", 8, 0, NULL },
75 ALLEGRO_END_OF_MENU,
76 ALLEGRO_END_OF_MENU
77 };
78
79 ALLEGRO_MENU *menu = al_build_menu(menu_info);
80
81 al_set_display_menu(display, menu);
82
83
84 ALLEGRO_EVENT_QUEUE *events = al_create_event_queue();
85 al_register_event_source(events, al_get_display_event_source(display));
86 al_register_event_source(events, al_get_default_menu_event_source());
87
88 bool quited = false;
89
90 while (!quited)
91 {
92 ALLEGRO_EVENT event;
93
94 al_wait_for_event(events, &event);
95 switch (event.type)
96 {
97 case ALLEGRO_EVENT_DISPLAY_CLOSE:
98 quited = true;
99 break;
100
101 case ALLEGRO_EVENT_MENU_CLICK:
102 if (event.user.data1 == 3) quited = true;
103 break;
104 }
105 }
106
107 return 0;
108}
109END_OF_MAIN();
|
Trent Gamblin
Member #261
April 2000
|
Going to look at this now. Will edit post later. EDIT: BTW, you shouldn't be using END_OF_MAIN() with Allegro 5. EDIT: Looks like it was doing the same thing before, so we didn't add any new problems that I know of. I'll try to fix it.
|
Malcolm Harrow
Member #15,833
December 2014
|
No END_OF_MAIN is good news .. One less warning message from Xcode ! |
Trent Gamblin
Member #261
April 2000
|
Try this patch. It was kind of a fluke that submenus sort of worked at all before. EDIT: Please do a thorough check if you can.
|
Malcolm Harrow
Member #15,833
December 2014
|
Brilliant! Works with the sample program .. plus works with my actual project .. which has some crazy popups. See attached. I suggest you push both into GIT .. even if there are further issues, it works much better than before. I will continue to do further testing. Many thanks again ! |
Trent Gamblin
Member #261
April 2000
|
Thanks, it's now in git. Let me know if you have further problems.
|
Malcolm Harrow
Member #15,833
December 2014
|
Hi, This may or may not be related. I'm trying to use al_set_menu_item_flag. The output from the code below is: Flag ALLEGRO_MENU_ITEM_CHECKBOX 1 Is al_set_menu_item_flags working, or am I confused? Regards 1//
2// main.c
3// TestAllegro
4//
5
6#include <stdio.h>
7#include <allegro5/allegro.h>
8#include <allegro5/allegro_native_dialog.h>
9
10void handleError(char *e)
11{
12 printf("%s\n", e);
13 exit(1);
14}
15
16int main(int argc, char **argv)
17{
18 if (!al_init()) handleError("Error al_init");
19 if (!al_init_native_dialog_addon()) handleError("Error al_init_native_dialog_addon");
20
21
22 ALLEGRO_DISPLAY *display = al_create_display(640, 480);
23 if (!display) handleError("Error al_create_display");
24
25 if (!al_install_keyboard()) handleError("Error al_install_keyboard");
26
27 // Building menu manually now works
28 //
29 // ALLEGRO_MENU *menu = al_create_menu();
30 // ALLEGRO_MENU *file_menu = al_create_menu();
31 // ALLEGRO_MENU *recent_menu = al_create_menu();
32 //
33 // if ((menu == NULL) || (file_menu == NULL) || (recent_menu == NULL)) handleError("Error al_create_menu");
34 //
35 // al_append_menu_item(recent_menu, "Recent 1", 14, 0, NULL, NULL);
36 // al_append_menu_item(recent_menu, "Recent 2", 15, 0, NULL, NULL);
37 //
38 // al_append_menu_item(file_menu, "&Open", 1, 0, NULL, NULL);
39 // al_append_menu_item(file_menu, "Open Recent...", 2, 0, NULL, recent_menu);
40 // al_append_menu_item(file_menu, "Exit", 3, 0, NULL, NULL);
41 //
42 // al_append_menu_item(menu, "File", 0, 0, NULL, file_menu);
43
44 ALLEGRO_MENU_INFO menu_info[] = {
45 ALLEGRO_START_OF_MENU("&File", 1),
46 { "&Open", 2, ALLEGRO_MENU_ITEM_CHECKBOX, NULL },
47 ALLEGRO_START_OF_MENU("Open &Recent...", 3),
48 { "Recent 1", 4, 0, NULL },
49 { "Recent 2", 5, 0, NULL },
50 ALLEGRO_END_OF_MENU,
51 ALLEGRO_MENU_SEPARATOR,
52 { "E&xit", 6, 0, NULL },
53 ALLEGRO_END_OF_MENU,
54 ALLEGRO_START_OF_MENU("&Help", 7),
55 {"&About", 8, 0, NULL },
56 ALLEGRO_END_OF_MENU,
57 ALLEGRO_END_OF_MENU
58 };
59
60 ALLEGRO_MENU *menu = al_build_menu(menu_info);
61
62 al_set_display_menu(display, menu);
63
64
65 ALLEGRO_EVENT_QUEUE *events = al_create_event_queue();
66 al_register_event_source(events, al_get_display_event_source(display));
67 al_register_event_source(events, al_get_default_menu_event_source());
68
69 printf("Flag ALLEGRO_MENU_ITEM_CHECKBOX %d\n", ALLEGRO_MENU_ITEM_CHECKBOX);
70 printf("Flag ALLEGRO_MENU_ITEM_CHECKED %d\n", ALLEGRO_MENU_ITEM_CHECKED);
71 printf("Flags | %d\n", ALLEGRO_MENU_ITEM_CHECKBOX | ALLEGRO_MENU_ITEM_CHECKED);
72
73
74 printf("Should have a flag of 1 as defined as a checkbox. 1=%d\n", al_get_menu_item_flags(menu, 2));
75 al_toggle_menu_item_flags(menu, 2, ALLEGRO_MENU_ITEM_CHECKED);
76 printf("After toggle of CHECKED flag, should be 3=%d\n", al_get_menu_item_flags(menu, 2));
77 al_set_menu_item_flags(menu, 2, ALLEGRO_MENU_ITEM_CHECKED | ALLEGRO_MENU_ITEM_CHECKBOX);
78 printf("After using set with a bitwise or should be 3= %d\n", al_get_menu_item_flags(menu, 2));
79 al_set_menu_item_flags(menu, 2, 3);
80 printf("After directly setting the flags to 3, value should be 3=%d\n", al_get_menu_item_flags(menu, 2));
81
82
83 bool quited = false;
84
85 while (!quited)
86 {
87 ALLEGRO_EVENT event;
88
89 al_wait_for_event(events, &event);
90 switch (event.type)
91 {
92 case ALLEGRO_EVENT_DISPLAY_CLOSE:
93 quited = true;
94 break;
95 case ALLEGRO_EVENT_MENU_CLICK:
96 printf("Clicked %ld\n", event.user.data1);
97 if (event.user.data1 == 6) quited = true;
98 break;
99 }
100 }
101
102 return 0;
103}
|
Trent Gamblin
Member #261
April 2000
|
The documentation on the flags states that ALLEGRO_MENU_ITEM_CHECKBOX can only be set at the time of creation. Might have something to do with it. Check the code in addons/native_dialog if in doubt.
|
Malcolm Harrow
Member #15,833
December 2014
|
Ok, I looked at the following code snippet from line 535 in menu.c - the function al_set_menu_item_flags(). As its the first time looking or changing this code, I’ll explain my thought process in detail. This looks like cross-platform code .. and I only have OS X 1/* Function: al_set_menu_item_flags
2 */
3void al_set_menu_item_flags(ALLEGRO_MENU *menu, int pos, int flags)
4{
5 ALLEGRO_MENU_ITEM *item;
6
7 ASSERT(menu);
8
9 item = interpret_menu_id_param(&menu, &pos);
10
11 if (item) {
12 /* The CHECKBOX flag is read-only after the menu is created, and
13 * the CHECKED flag can only be set if it is a CHECKBOX.
14 */
15 flags &= ~ALLEGRO_MENU_ITEM_CHECKBOX; // Note 1
16 if (!(item->flags & ALLEGRO_MENU_ITEM_CHECKBOX)) { // Note 2
17 flags &= ~ALLEGRO_MENU_ITEM_CHECKED;
18 }
19
20 item->flags = flags; // Note 3
21 _al_update_menu_item_at(item, pos);
22 }
23}
Note 1 .. changes the flags parameter to clear the CHECKBOX flag So .. I think the issue is that line commented “Note 1" always clears the CHECKBOX flag I think the intended behaviour is that item->flags remains a checkbox if set and cannot be changed, so I think the function needs to be changed to: 1/* Function: al_set_menu_item_flags
2 */
3void al_set_menu_item_flags(ALLEGRO_MENU *menu, int pos, int flags)
4{
5 ALLEGRO_MENU_ITEM *item;
6
7 ASSERT(menu);
8
9 item = interpret_menu_id_param(&menu, &pos);
10
11 if (item) {
12 /* The CHECKBOX flag is read-only after the menu is created, and
13 * the CHECKED flag can only be set if it is a CHECKBOX.
14 */
15 if (item->flags & ALLEGRO_MENU_ITEM_CHECKBOX)
16 {
17 flags |= ALLEGRO_MENU_ITEM_CHECKBOX;
18 }
19 else
20 {
21 flags &= ~ALLEGRO_MENU_ITEM_CHECKED;
22 flags &= ~ALLEGRO_MENU_ITEM_CHECKBOX;
23 }
24
25 item->flags = flags;
26 _al_update_menu_item_at(item, pos);
27 }
28}
I’ve attached a diff file diff menu.c.orig menu.c > al_set_menu_item_flags.patch
What do you think ? |
Trent Gamblin
Member #261
April 2000
|
Looks good, will commit. Thank you.
|
|