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}