|
1 /* |
|
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2014 Olaf Wintermann. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
26 * POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #include <stdio.h> |
|
30 #include <stdlib.h> |
|
31 |
|
32 #include "menu.h" |
|
33 #include "toolkit.h" |
|
34 #include "../common/context.h" |
|
35 #include "../ui/window.h" |
|
36 |
|
37 UcxList *menus; |
|
38 UcxList *current; |
|
39 |
|
40 void ui_menu(char *label) { |
|
41 // free current menu hierarchy |
|
42 ucx_list_free(current); |
|
43 |
|
44 // create menu |
|
45 UiMenu *menu = malloc(sizeof(UiMenu)); |
|
46 menu->item.add_to = (ui_menu_add_f)add_menu_widget; |
|
47 |
|
48 menu->label = label; |
|
49 menu->items = NULL; |
|
50 menu->parent = NULL; |
|
51 |
|
52 current = ucx_list_prepend(NULL, menu); |
|
53 menus = ucx_list_append(menus, menu); |
|
54 |
|
55 } |
|
56 |
|
57 void ui_submenu(char *label) { |
|
58 UiMenu *menu = malloc(sizeof(UiMenu)); |
|
59 menu->item.add_to = (ui_menu_add_f)add_menu_widget; |
|
60 |
|
61 menu->label = label; |
|
62 menu->items = NULL; |
|
63 menu->parent = NULL; |
|
64 |
|
65 // add submenu to current menu |
|
66 UiMenu *cm = current->data; |
|
67 cm->items = ucx_list_append(cm->items, menu); |
|
68 |
|
69 // set the submenu to current menu |
|
70 current = ucx_list_prepend(current, menu); |
|
71 } |
|
72 |
|
73 void ui_submenu_end() { |
|
74 if(ucx_list_size(current) < 2) { |
|
75 return; |
|
76 } |
|
77 current = ucx_list_remove(current, current); |
|
78 UcxList *c = current; |
|
79 } |
|
80 |
|
81 void ui_menuitem(char *label, ui_callback f, void *userdata) { |
|
82 if(!current) { |
|
83 return; |
|
84 } |
|
85 |
|
86 UiMenuItem *item = malloc(sizeof(UiMenuItem)); |
|
87 item->item.add_to = (ui_menu_add_f)add_menuitem_widget; |
|
88 |
|
89 item->label = label; |
|
90 item->userdata = userdata; |
|
91 item->callback = f; |
|
92 |
|
93 UiMenu *cm = current->data; |
|
94 cm->items = ucx_list_append(cm->items, item); |
|
95 } |
|
96 |
|
97 void ui_menuseparator() { |
|
98 if(!current) { |
|
99 return; |
|
100 } |
|
101 |
|
102 UiMenuItemI *item = malloc(sizeof(UiMenuItemI)); |
|
103 item->add_to = (ui_menu_add_f)add_menuseparator_widget; |
|
104 |
|
105 UiMenu *cm = current->data; |
|
106 cm->items = ucx_list_append(cm->items, item); |
|
107 } |
|
108 |
|
109 void ui_checkitem(char *label, ui_callback f, void *userdata) { |
|
110 if(!current) { |
|
111 return; |
|
112 } |
|
113 |
|
114 UiCheckItem *item = malloc(sizeof(UiCheckItem)); |
|
115 item->item.add_to = (ui_menu_add_f)add_checkitem_widget; |
|
116 item->label = label; |
|
117 item->callback = f; |
|
118 item->userdata = userdata; |
|
119 |
|
120 UiMenu *cm = current->data; |
|
121 cm->items = ucx_list_append(cm->items, item); |
|
122 } |
|
123 |
|
124 void ui_checkitem_nv(char *label, char *vname) { |
|
125 if(!current) { |
|
126 return; |
|
127 } |
|
128 |
|
129 UiCheckItemNV *item = malloc(sizeof(UiCheckItemNV)); |
|
130 item->item.add_to = (ui_menu_add_f)add_checkitemnv_widget; |
|
131 item->varname = vname; |
|
132 item->label = label; |
|
133 |
|
134 UiMenu *cm = current->data; |
|
135 cm->items = ucx_list_append(cm->items, item); |
|
136 } |
|
137 |
|
138 // private menu functions |
|
139 GtkWidget *ui_create_menubar(UiObject *obj) { |
|
140 if(menus == NULL) { |
|
141 return NULL; |
|
142 } |
|
143 |
|
144 GtkWidget *mb = gtk_menu_bar_new(); |
|
145 |
|
146 UcxList *ls = menus; |
|
147 while(ls) { |
|
148 UiMenu *menu = ls->data; |
|
149 menu->item.add_to(mb, &menu->item, obj); |
|
150 |
|
151 ls = ls->next; |
|
152 } |
|
153 |
|
154 return mb; |
|
155 } |
|
156 |
|
157 void add_menu_widget(GtkWidget *parent, UiMenuItemI *item, UiObject *obj) { |
|
158 UiMenu *menu = (UiMenu*)item; |
|
159 |
|
160 GtkWidget *menu_widget = gtk_menu_new(); |
|
161 GtkWidget *menu_item = gtk_menu_item_new_with_label(menu->label); |
|
162 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu_widget); |
|
163 |
|
164 UcxList *ls = menu->items; |
|
165 while(ls) { |
|
166 UiMenuItemI *i = ls->data; |
|
167 i->add_to(menu_widget, i, obj); |
|
168 |
|
169 ls = ls->next; |
|
170 } |
|
171 |
|
172 gtk_menu_shell_append(GTK_MENU_SHELL(parent), menu_item); |
|
173 } |
|
174 |
|
175 void add_menuitem_widget(GtkWidget *parent, UiMenuItemI *item, UiObject *obj) { |
|
176 UiMenuItem *i = (UiMenuItem*)item; |
|
177 |
|
178 //GtkWidget *widget = gtk_menu_item_new_with_label(i->title); |
|
179 GtkWidget *widget = gtk_menu_item_new_with_mnemonic(i->label); |
|
180 |
|
181 if(i->callback != NULL) { |
|
182 UiEventData *event = malloc(sizeof(UiEventData)); |
|
183 event->obj = obj; |
|
184 event->user_data = i->userdata; |
|
185 event->callback = i->callback; |
|
186 |
|
187 g_signal_connect( |
|
188 widget, |
|
189 "activate", |
|
190 G_CALLBACK(ui_menu_event_wrapper), |
|
191 event); |
|
192 } |
|
193 |
|
194 gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); |
|
195 } |
|
196 |
|
197 void add_menuitem_st_widget( |
|
198 GtkWidget *parent, |
|
199 UiMenuItemI *item, |
|
200 UiObject *obj) |
|
201 { |
|
202 UiStMenuItem *i = (UiStMenuItem*)item; |
|
203 |
|
204 GtkWidget *widget = gtk_image_menu_item_new_from_stock(i->stockid, NULL); |
|
205 |
|
206 if(i->callback != NULL) { |
|
207 UiEventData *event = malloc(sizeof(UiEventData)); |
|
208 event->obj = obj; |
|
209 event->user_data = i->userdata; |
|
210 event->callback = i->callback; |
|
211 |
|
212 g_signal_connect( |
|
213 widget, |
|
214 "activate", |
|
215 G_CALLBACK(ui_menu_event_wrapper), |
|
216 event); |
|
217 } |
|
218 |
|
219 gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); |
|
220 } |
|
221 |
|
222 void add_menuseparator_widget( |
|
223 GtkWidget *parent, |
|
224 UiMenuItemI *item, |
|
225 UiObject *obj) |
|
226 { |
|
227 gtk_menu_shell_append( |
|
228 GTK_MENU_SHELL(parent), |
|
229 gtk_separator_menu_item_new()); |
|
230 } |
|
231 |
|
232 void add_checkitem_widget(GtkWidget *p, UiMenuItemI *item, UiObject *obj) { |
|
233 UiCheckItem *ci = (UiCheckItem*)item; |
|
234 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); |
|
235 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); |
|
236 |
|
237 if(ci->callback) { |
|
238 UiEventData *event = malloc(sizeof(UiEventData)); |
|
239 event->obj = obj; |
|
240 event->user_data = ci->userdata; |
|
241 event->callback = ci->callback; |
|
242 |
|
243 g_signal_connect( |
|
244 widget, |
|
245 "toggled", |
|
246 G_CALLBACK(ui_menu_event_toggled), |
|
247 event); |
|
248 } |
|
249 } |
|
250 |
|
251 void add_checkitemnv_widget(GtkWidget *p, UiMenuItemI *item, UiObject *obj) { |
|
252 UiCheckItemNV *ci = (UiCheckItemNV*)item; |
|
253 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); |
|
254 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); |
|
255 |
|
256 UiVar *var = uic_getvar(obj, ci->varname); |
|
257 if(!var) { |
|
258 ui_window_addint(obj, ci->varname); |
|
259 var = uic_getvar(obj, ci->varname); |
|
260 } |
|
261 if(var->type == 1) { |
|
262 UiInteger *value = var->value; |
|
263 value->obj = widget; |
|
264 value->get = ui_checkitem_get; |
|
265 value->set = ui_checkitem_set; |
|
266 value = 0; |
|
267 } else { |
|
268 // TODO: error message |
|
269 } |
|
270 } |
|
271 |
|
272 |
|
273 |
|
274 void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) { |
|
275 UiEvent evt; |
|
276 evt.obj = event->obj; |
|
277 evt.window = event->obj->window; |
|
278 evt.document = NULL; |
|
279 evt.intval = 0; |
|
280 event->callback(&evt, event->user_data); |
|
281 } |
|
282 |
|
283 void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) { |
|
284 UiEvent evt; |
|
285 evt.obj = event->obj; |
|
286 evt.window = event->obj->window; |
|
287 evt.document = NULL; |
|
288 evt.intval = gtk_check_menu_item_get_active(ci); |
|
289 event->callback(&evt, event->user_data); |
|
290 } |
|
291 |
|
292 int ui_checkitem_get(UiInteger *i) { |
|
293 int state = gtk_check_menu_item_get_active(i->obj); |
|
294 i->value = state; |
|
295 return state; |
|
296 } |
|
297 |
|
298 void ui_checkitem_set(UiInteger *i, int value) { |
|
299 i->value = value; |
|
300 gtk_check_menu_item_set_active(i->obj, value); |
|
301 } |