39 #include "../ui/window.h" |
39 #include "../ui/window.h" |
40 |
40 |
41 #include <cx/linked_list.h> |
41 #include <cx/linked_list.h> |
42 #include <cx/array_list.h> |
42 #include <cx/array_list.h> |
43 |
43 |
44 static ui_menu_add_f createMenuItem[] = { |
|
45 /* UI_MENU */ add_menu_widget, |
|
46 /* UI_MENU_SUBMENU */ add_menu_widget, |
|
47 /* UI_MENU_ITEM */ add_menuitem_widget, |
|
48 /* UI_MENU_STOCK_ITEM */ add_menuitem_st_widget, |
|
49 /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, |
|
50 /* UI_MENU_CHECK_ITEM_NV */ add_checkitemnv_widget, |
|
51 /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, |
|
52 /* UI_MENU_ITEM_LIST_NV */ NULL, // TODO |
|
53 /* UI_MENU_SEPARATOR */ add_menuseparator_widget |
|
54 }; |
|
55 |
|
56 // private menu functions |
|
57 void ui_create_menubar(UiObject *obj) { |
|
58 UiMenu *menus = uic_get_menu_list(); |
|
59 if(!menus) { |
|
60 return; |
|
61 } |
|
62 |
|
63 Widget menubar = XmCreateMenuBar(obj->widget, "main_list", NULL, 0); |
|
64 XtManageChild(menubar); |
|
65 |
|
66 UiMenu *menu = menus; |
|
67 int menu_index = 0; |
|
68 while(menu) { |
|
69 menu_index += add_menu_widget(menubar, menu_index, &menu->item, obj); |
|
70 |
|
71 menu = (UiMenu*)menu->item.next; |
|
72 } |
|
73 } |
|
74 |
|
75 int add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { |
|
76 UiMenu *menu = (UiMenu*)item; |
|
77 |
|
78 Widget menuItem = XtVaCreateManagedWidget( |
|
79 menu->label, |
|
80 xmCascadeButtonWidgetClass, |
|
81 parent, |
|
82 NULL); |
|
83 Widget m = XmVaCreateSimplePulldownMenu(parent, menu->label, i, NULL, NULL); |
|
84 |
|
85 UiMenuItemI *mi = menu->items_begin; |
|
86 int menu_index = 0; |
|
87 while(mi) { |
|
88 menu_index += createMenuItem[mi->type](m, menu_index, mi, obj); |
|
89 mi = mi->next; |
|
90 } |
|
91 |
|
92 return 1; |
|
93 } |
|
94 |
|
95 int add_menuitem_widget( |
|
96 Widget parent, |
|
97 int i, |
|
98 UiMenuItemI *item, |
|
99 UiObject *obj) |
|
100 { |
|
101 UiMenuItem *mi = (UiMenuItem*)item; |
|
102 |
|
103 Arg args[1]; |
|
104 XmString label = XmStringCreateLocalized(mi->label); |
|
105 XtSetArg(args[0], XmNlabelString, label); |
|
106 |
|
107 Widget mitem = XtCreateManagedWidget( |
|
108 "menubutton", |
|
109 xmPushButtonWidgetClass, |
|
110 parent, |
|
111 args, |
|
112 1); |
|
113 XmStringFree(label); |
|
114 |
|
115 if(mi->callback != NULL) { |
|
116 UiEventData *event = cxMalloc( |
|
117 obj->ctx->allocator, |
|
118 sizeof(UiEventData)); |
|
119 event->obj = obj; |
|
120 event->userdata = mi->userdata; |
|
121 event->callback = mi->callback; |
|
122 event->value = 0; |
|
123 XtAddCallback( |
|
124 mitem, |
|
125 XmNactivateCallback, |
|
126 (XtCallbackProc)ui_push_button_callback, |
|
127 event); |
|
128 } |
|
129 |
|
130 if(mi->groups) { |
|
131 uic_add_group_widget(obj->ctx, mitem, (ui_enablefunc)XtSetSensitive, mi->groups); |
|
132 } |
|
133 |
|
134 return 1; |
|
135 } |
|
136 |
|
137 int add_menuitem_st_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { |
|
138 UiStMenuItem *mi = (UiStMenuItem*)item; |
|
139 |
|
140 UiStockItem *si = ui_get_stock_item(mi->stockid); |
|
141 if(!si) { |
|
142 fprintf(stderr, "UI Error: unknown stock id: %s\n", mi->stockid); |
|
143 return 0; |
|
144 } |
|
145 |
|
146 int n = 0; |
|
147 Arg args[4]; |
|
148 XmString label = XmStringCreateLocalized(si->label); |
|
149 XmString at = NULL; |
|
150 |
|
151 XtSetArg(args[n], XmNlabelString, label); |
|
152 n++; |
|
153 if(si->accelerator) { |
|
154 XtSetArg(args[n], XmNaccelerator, si->accelerator); |
|
155 n++; |
|
156 } |
|
157 if(si->accelerator_label) { |
|
158 at = XmStringCreateLocalized(si->accelerator_label); |
|
159 XtSetArg(args[n], XmNacceleratorText, at); |
|
160 n++; |
|
161 } |
|
162 |
|
163 Widget mitem = XtCreateManagedWidget( |
|
164 "menubutton", |
|
165 xmPushButtonWidgetClass, |
|
166 parent, |
|
167 args, |
|
168 n); |
|
169 XmStringFree(label); |
|
170 if(at) { |
|
171 XmStringFree(at); |
|
172 } |
|
173 |
|
174 if(mi->callback != NULL) { |
|
175 UiEventData *event = cxMalloc( |
|
176 obj->ctx->allocator, |
|
177 sizeof(UiEventData)); |
|
178 event->obj = obj; |
|
179 event->userdata = mi->userdata; |
|
180 event->callback = mi->callback; |
|
181 event->value = 0; |
|
182 XtAddCallback( |
|
183 mitem, |
|
184 XmNactivateCallback, |
|
185 (XtCallbackProc)ui_push_button_callback, |
|
186 event); |
|
187 } |
|
188 |
|
189 if(mi->groups) { |
|
190 uic_add_group_widget(obj->ctx, mitem, (ui_enablefunc)XtSetSensitive, mi->groups); |
|
191 } |
|
192 |
|
193 return 1; |
|
194 } |
|
195 |
|
196 int add_menuseparator_widget( |
|
197 Widget parent, |
|
198 int i, |
|
199 UiMenuItemI *item, |
|
200 UiObject *obj) |
|
201 { |
|
202 Widget s = XmCreateSeparatorGadget (parent, "menu_separator", NULL, 0); |
|
203 XtManageChild(s); |
|
204 return 1; |
|
205 } |
|
206 |
|
207 int add_checkitem_widget( |
|
208 Widget parent, |
|
209 int i, |
|
210 UiMenuItemI *item, |
|
211 UiObject *obj) |
|
212 { |
|
213 UiCheckItem *ci = (UiCheckItem*)item; |
|
214 |
|
215 Arg args[3]; |
|
216 XmString label = XmStringCreateLocalized(ci->label); |
|
217 XtSetArg(args[0], XmNlabelString, label); |
|
218 XtSetArg(args[1], XmNvisibleWhenOff, 1); |
|
219 Widget checkbox = XtCreateManagedWidget( |
|
220 "menutogglebutton", |
|
221 xmToggleButtonWidgetClass, |
|
222 parent, |
|
223 args, |
|
224 2); |
|
225 XmStringFree(label); |
|
226 |
|
227 if(ci->callback) { |
|
228 UiEventData *event = cxMalloc( |
|
229 obj->ctx->allocator, |
|
230 sizeof(UiEventData)); |
|
231 event->obj = obj; |
|
232 event->userdata = ci->userdata; |
|
233 event->callback = ci->callback; |
|
234 XtAddCallback( |
|
235 checkbox, |
|
236 XmNvalueChangedCallback, |
|
237 (XtCallbackProc)ui_toggle_button_callback, |
|
238 event); |
|
239 } |
|
240 |
|
241 return 1; |
|
242 } |
|
243 |
|
244 int add_checkitemnv_widget( |
|
245 Widget parent, |
|
246 int i, |
|
247 UiMenuItemI *item, |
|
248 UiObject *obj) |
|
249 { |
|
250 UiCheckItemNV *ci = (UiCheckItemNV*)item; |
|
251 |
|
252 Arg args[3]; |
|
253 XmString label = XmStringCreateLocalized(ci->label); |
|
254 XtSetArg(args[0], XmNlabelString, label); |
|
255 XtSetArg(args[1], XmNvisibleWhenOff, 1); |
|
256 Widget checkbox = XtCreateManagedWidget( |
|
257 "menutogglebutton", |
|
258 xmToggleButtonWidgetClass, |
|
259 parent, |
|
260 args, |
|
261 2); |
|
262 XmStringFree(label); |
|
263 |
|
264 UiVar *var = uic_create_var(obj->ctx, ci->varname, UI_VAR_INTEGER); |
|
265 if(var) { |
|
266 UiInteger *value = var->value; |
|
267 value->obj = checkbox; |
|
268 value->get = ui_toggle_button_get; |
|
269 value->set = ui_toggle_button_set; |
|
270 value = 0; |
|
271 } else { |
|
272 // TODO: error |
|
273 } |
|
274 |
|
275 return 1; |
|
276 } |
|
277 |
|
278 int add_menuitem_list_widget( |
|
279 Widget parent, |
|
280 int i, |
|
281 UiMenuItemI *item, |
|
282 UiObject *obj) |
|
283 { |
|
284 UiMenuItemList *il = (UiMenuItemList*)item; |
|
285 |
|
286 UiActiveMenuItemList *ls = cxMalloc( |
|
287 obj->ctx->allocator, |
|
288 sizeof(UiActiveMenuItemList)); |
|
289 |
|
290 ls->object = obj; |
|
291 ls->menu = parent; |
|
292 ls->index = i; |
|
293 ls->oldcount = 0; |
|
294 ls->list = il->list; |
|
295 ls->callback = il->callback; |
|
296 ls->userdata = il->userdata; |
|
297 |
|
298 ls->list->observers = ui_add_observer( |
|
299 ls->list->observers, |
|
300 (ui_callback)ui_update_menuitem_list, |
|
301 ls); |
|
302 |
|
303 ui_update_menuitem_list(NULL, ls); |
|
304 |
|
305 return 0; |
|
306 } |
|
307 |
|
308 void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { |
|
309 Arg args[4]; |
|
310 |
|
311 // remove old items |
|
312 if(list->oldcount > 0) { |
|
313 Widget *children; |
|
314 int nc; |
|
315 |
|
316 XtVaGetValues( |
|
317 list->menu, |
|
318 XmNchildren, |
|
319 &children, |
|
320 XmNnumChildren, |
|
321 &nc, |
|
322 NULL); |
|
323 |
|
324 for(int i=0;i<list->oldcount;i++) { |
|
325 XtDestroyWidget(children[list->index + i]); |
|
326 } |
|
327 } |
|
328 |
|
329 char *str = ui_list_first(list->list); |
|
330 if(str) { |
|
331 // add separator |
|
332 XtSetArg(args[0], XmNpositionIndex, list->index); |
|
333 Widget s = XmCreateSeparatorGadget (list->menu, "menu_separator", args, 1); |
|
334 XtManageChild(s); |
|
335 } |
|
336 int i = 1; |
|
337 while(str) { |
|
338 XmString label = XmStringCreateLocalized(str); |
|
339 XtSetArg(args[0], XmNlabelString, label); |
|
340 XtSetArg(args[1], XmNpositionIndex, list->index + i); |
|
341 |
|
342 Widget mitem = XtCreateManagedWidget( |
|
343 "menubutton", |
|
344 xmPushButtonWidgetClass, |
|
345 list->menu, |
|
346 args, |
|
347 2); |
|
348 XmStringFree(label); |
|
349 |
|
350 if(list->callback) { |
|
351 // TODO: use mempool |
|
352 UiEventData *event = malloc(sizeof(UiEventData)); |
|
353 event->obj = list->object; |
|
354 event->userdata = list->userdata; |
|
355 event->callback = list->callback; |
|
356 event->value = i - 1; |
|
357 |
|
358 XtAddCallback( |
|
359 mitem, |
|
360 XmNactivateCallback, |
|
361 (XtCallbackProc)ui_push_button_callback, |
|
362 event); |
|
363 } |
|
364 |
|
365 str = ui_list_next(list->list); |
|
366 i++; |
|
367 } |
|
368 |
|
369 list->oldcount = i; |
|
370 } |
|
371 |
|
372 void ui_menu_event_wrapper(Widget widget, XtPointer udata, XtPointer cdata) { |
|
373 UiEventData *event = udata; |
|
374 UiEvent e; |
|
375 e.obj = event->obj; |
|
376 e.window = event->obj->window; |
|
377 e.document = event->obj->ctx->document; |
|
378 e.intval = 0; |
|
379 event->callback(&e, event->userdata); |
|
380 } |
|
381 |
|
382 |
|
383 /* |
|
384 * widget menu functions |
|
385 */ |
|
386 |
|
387 static void ui_popup_handler(Widget widget, XtPointer data, XEvent *event, Boolean *c) { |
|
388 Widget menu = data; |
|
389 XmMenuPosition(menu, (XButtonPressedEvent *)event); |
|
390 XtManageChild(menu); |
|
391 |
|
392 *c = FALSE; |
|
393 } |
|
394 |
|
395 UIMENU ui_contextmenu(UiObject *obj) { |
|
396 UiContainer *ct = uic_get_current_container(obj); |
|
397 if(ct->current) { |
|
398 return ui_contextmenu_w(obj, ct->current); |
|
399 } else { |
|
400 return NULL; // TODO: warn |
|
401 } |
|
402 } |
|
403 |
|
404 UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) { |
|
405 UiContainer *ct = uic_get_current_container(obj); |
|
406 |
|
407 Widget menu = XmCreatePopupMenu(widget, "popup_menu", NULL, 0); |
|
408 ct->menu = menu; |
|
409 |
|
410 XtAddEventHandler(widget, ButtonPressMask, FALSE, ui_popup_handler, menu); |
|
411 |
|
412 return menu; |
|
413 } |
|
414 |
|
415 void ui_contextmenu_popup(UIMENU menu) { |
|
416 |
|
417 } |
|
418 |
|
419 void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata) { |
|
420 ui_widget_menuitem_gr(obj, label, f, userdata, -1); |
|
421 } |
|
422 |
|
423 void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...) { |
|
424 UiContainer *ct = uic_get_current_container(obj); |
|
425 if(!ct->menu) { |
|
426 return; |
|
427 } |
|
428 |
|
429 // add groups |
|
430 CxList *groups = NULL; |
|
431 va_list ap; |
|
432 va_start(ap, userdata); |
|
433 int group; |
|
434 while((group = va_arg(ap, int)) != -1) { |
|
435 if(!groups) { |
|
436 groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16); |
|
437 } |
|
438 cxListAdd(groups, &group); |
|
439 } |
|
440 va_end(ap); |
|
441 |
|
442 // create menuitem |
|
443 Arg args[4]; |
|
444 XmString labelstr = XmStringCreateLocalized(label); |
|
445 XtSetArg(args[0], XmNlabelString, labelstr); |
|
446 |
|
447 Widget item = XmCreatePushButton(ct->menu, "menu_button", args, 1); |
|
448 XtManageChild(item); |
|
449 XmStringFree(labelstr); |
|
450 } |
|
451 |
|
452 void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) { |
|
453 ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1); |
|
454 } |
|
455 |
|
456 void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...) { |
|
457 UiContainer *ct = uic_get_current_container(obj); |
|
458 if(!ct->menu) { |
|
459 return; |
|
460 } |
|
461 |
|
462 // add groups |
|
463 CxList *groups = NULL; |
|
464 va_list ap; |
|
465 va_start(ap, userdata); |
|
466 int group; |
|
467 while((group = va_arg(ap, int)) != -1) { |
|
468 if(!groups) { |
|
469 groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16); |
|
470 } |
|
471 cxListAdd(groups, &group); |
|
472 } |
|
473 va_end(ap); |
|
474 |
|
475 // create menuitem |
|
476 UiStockItem *stockItem = ui_get_stock_item(stockid); |
|
477 Arg args[4]; |
|
478 XmString labelstr = XmStringCreateLocalized(stockItem->label); |
|
479 XtSetArg(args[0], XmNlabelString, labelstr); |
|
480 |
|
481 Widget item = XmCreatePushButton(ct->menu, "menu_button", args, 1); |
|
482 XtManageChild(item); |
|
483 XmStringFree(labelstr); |
|
484 } |
|