|
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 "button.h" |
|
34 #include "toolkit.h" |
|
35 #include "../common/context.h" |
|
36 #include "../ui/window.h" |
|
37 |
|
38 UcxList *menus; |
|
39 UcxList *current; |
|
40 |
|
41 void ui_menu(char *label) { |
|
42 // free current menu hierarchy |
|
43 ucx_list_free(current); |
|
44 |
|
45 // create menu |
|
46 UiMenu *menu = malloc(sizeof(UiMenu)); |
|
47 menu->item.add_to = (ui_menu_add_f)add_menu_widget; |
|
48 |
|
49 menu->label = label; |
|
50 menu->items = NULL; |
|
51 menu->parent = NULL; |
|
52 |
|
53 current = ucx_list_prepend(NULL, menu); |
|
54 menus = ucx_list_append(menus, menu); |
|
55 |
|
56 } |
|
57 |
|
58 void ui_submenu(char *label) { |
|
59 UiMenu *menu = malloc(sizeof(UiMenu)); |
|
60 menu->item.add_to = (ui_menu_add_f)add_menu_widget; |
|
61 |
|
62 menu->label = label; |
|
63 menu->items = NULL; |
|
64 menu->parent = NULL; |
|
65 |
|
66 // add submenu to current menu |
|
67 UiMenu *cm = current->data; |
|
68 cm->items = ucx_list_append(cm->items, menu); |
|
69 |
|
70 // set the submenu to current menu |
|
71 current = ucx_list_prepend(current, menu); |
|
72 } |
|
73 |
|
74 void ui_submenu_end() { |
|
75 if(ucx_list_size(current) < 2) { |
|
76 return; |
|
77 } |
|
78 current = ucx_list_remove(current, 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 |
|
110 void ui_checkitem(char *label, ui_callback f, void *userdata) { |
|
111 if(!current) { |
|
112 return; |
|
113 } |
|
114 |
|
115 UiCheckItem *item = malloc(sizeof(UiCheckItem)); |
|
116 item->item.add_to = (ui_menu_add_f)add_checkitem_widget; |
|
117 item->label = label; |
|
118 item->callback = f; |
|
119 item->userdata = userdata; |
|
120 |
|
121 UiMenu *cm = current->data; |
|
122 cm->items = ucx_list_append(cm->items, item); |
|
123 } |
|
124 |
|
125 void ui_checkitem_nv(char *label, char *vname) { |
|
126 if(!current) { |
|
127 return; |
|
128 } |
|
129 |
|
130 UiCheckItemNV *item = malloc(sizeof(UiCheckItemNV)); |
|
131 item->item.add_to = (ui_menu_add_f)add_checkitemnv_widget; |
|
132 item->varname = vname; |
|
133 item->label = label; |
|
134 |
|
135 UiMenu *cm = current->data; |
|
136 cm->items = ucx_list_append(cm->items, item); |
|
137 } |
|
138 |
|
139 |
|
140 // private menu functions |
|
141 void ui_create_menubar(UiObject *obj) { |
|
142 if(!menus) { |
|
143 return; |
|
144 } |
|
145 |
|
146 Widget menubar = XmCreateMenuBar(obj->widget, "main_list", NULL, 0); |
|
147 XtManageChild(menubar); |
|
148 |
|
149 UcxList *ls = menus; |
|
150 int menu_index = 0; |
|
151 while(ls) { |
|
152 UiMenu *menu = ls->data; |
|
153 menu_index += menu->item.add_to(menubar, menu_index, &menu->item, obj); |
|
154 |
|
155 ls = ls->next; |
|
156 } |
|
157 } |
|
158 |
|
159 int add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { |
|
160 UiMenu *menu = (UiMenu*)item; |
|
161 |
|
162 Widget menuItem = XtVaCreateManagedWidget( |
|
163 menu->label, |
|
164 xmCascadeButtonWidgetClass, |
|
165 parent, |
|
166 NULL); |
|
167 Widget m = XmVaCreateSimplePulldownMenu(parent, menu->label, i, NULL, NULL); |
|
168 |
|
169 UcxList *ls = menu->items; |
|
170 int menu_index = 0; |
|
171 while(ls) { |
|
172 UiMenuItemI *mi = ls->data; |
|
173 menu_index += mi->add_to(m, menu_index, mi, obj); |
|
174 ls = ls->next; |
|
175 } |
|
176 |
|
177 return 1; |
|
178 } |
|
179 |
|
180 int add_menuitem_widget( |
|
181 Widget parent, |
|
182 int i, |
|
183 UiMenuItemI *item, |
|
184 UiObject *obj) |
|
185 { |
|
186 UiMenuItem *mi = (UiMenuItem*)item; |
|
187 |
|
188 Arg args[1]; |
|
189 XmString label = XmStringCreateLocalized(mi->label); |
|
190 XtSetArg(args[0], XmNlabelString, label); |
|
191 |
|
192 Widget mitem = XtCreateManagedWidget( |
|
193 "menubutton", |
|
194 xmPushButtonWidgetClass, |
|
195 parent, |
|
196 args, |
|
197 1); |
|
198 XmStringFree(label); |
|
199 |
|
200 if(mi->callback != NULL) { |
|
201 UiEventData *event = ucx_mempool_malloc( |
|
202 obj->ctx->mempool, |
|
203 sizeof(UiEventData)); |
|
204 event->obj = obj; |
|
205 event->user_data = mi->userdata; |
|
206 event->callback = mi->callback; |
|
207 XtAddCallback(mitem, XmNactivateCallback, ui_menu_event_wrapper, event); |
|
208 } |
|
209 |
|
210 return 1; |
|
211 } |
|
212 |
|
213 int add_menuseparator_widget( |
|
214 Widget parent, |
|
215 int i, |
|
216 UiMenuItemI *item, |
|
217 UiObject *obj) |
|
218 { |
|
219 Widget s = XmCreateSeparatorGadget (parent, "menu_separator", NULL, 0); |
|
220 XtManageChild(s); |
|
221 return 1; |
|
222 } |
|
223 |
|
224 int add_checkitem_widget( |
|
225 Widget parent, |
|
226 int i, |
|
227 UiMenuItemI *item, |
|
228 UiObject *obj) |
|
229 { |
|
230 UiCheckItem *ci = (UiCheckItem*)item; |
|
231 |
|
232 Arg args[3]; |
|
233 XmString label = XmStringCreateLocalized(ci->label); |
|
234 XtSetArg(args[0], XmNlabelString, label); |
|
235 XtSetArg(args[1], XmNvisibleWhenOff, 1); |
|
236 Widget checkbox = XtCreateManagedWidget( |
|
237 "menutogglebutton", |
|
238 xmToggleButtonWidgetClass, |
|
239 parent, |
|
240 args, |
|
241 2); |
|
242 XmStringFree(label); |
|
243 |
|
244 if(ci->callback) { |
|
245 UiEventData *event = ucx_mempool_malloc( |
|
246 obj->ctx->mempool, |
|
247 sizeof(UiEventData)); |
|
248 event->obj = obj; |
|
249 event->user_data = ci->userdata; |
|
250 event->callback = ci->callback; |
|
251 XtAddCallback( |
|
252 checkbox, |
|
253 XmNvalueChangedCallback, |
|
254 (XtCallbackProc)ui_toggle_button_callback, |
|
255 event); |
|
256 } |
|
257 |
|
258 return 1; |
|
259 } |
|
260 |
|
261 int add_checkitemnv_widget( |
|
262 Widget parent, |
|
263 int i, |
|
264 UiMenuItemI *item, |
|
265 UiObject *obj) |
|
266 { |
|
267 UiCheckItemNV *ci = (UiCheckItemNV*)item; |
|
268 |
|
269 Arg args[3]; |
|
270 XmString label = XmStringCreateLocalized(ci->label); |
|
271 XtSetArg(args[0], XmNlabelString, label); |
|
272 XtSetArg(args[1], XmNvisibleWhenOff, 1); |
|
273 Widget checkbox = XtCreateManagedWidget( |
|
274 "menutogglebutton", |
|
275 xmToggleButtonWidgetClass, |
|
276 parent, |
|
277 args, |
|
278 2); |
|
279 XmStringFree(label); |
|
280 |
|
281 UiVar *var = uic_getvar(obj, ci->varname); |
|
282 if(!var) { |
|
283 ui_window_addint(obj, ci->varname); |
|
284 var = uic_getvar(obj, ci->varname); |
|
285 } |
|
286 if(var->type == 1) { |
|
287 UiInteger *value = var->value; |
|
288 value->obj = checkbox; |
|
289 value->get = ui_toggle_button_get; |
|
290 value->set = ui_toggle_button_set; |
|
291 value = 0; |
|
292 } else { |
|
293 // TODO: error message |
|
294 } |
|
295 } |
|
296 |
|
297 |
|
298 void ui_menu_event_wrapper(Widget widget, XtPointer udata, XtPointer cdata) { |
|
299 UiEventData *event = udata; |
|
300 UiEvent e; |
|
301 e.obj = event->obj; |
|
302 e.window = event->obj->window; |
|
303 // TODO: e.document |
|
304 e.intval = 0; |
|
305 event->callback(&e, event->user_data); |
|
306 } |