ui/gtk/menu.c

changeset 431
bb7da585debc
parent 400
a1946c97de09
child 435
883a569cc9a3
equal deleted inserted replaced
169:fe49cff3c571 431:bb7da585debc
32 #include <stdarg.h> 32 #include <stdarg.h>
33 33
34 #include "menu.h" 34 #include "menu.h"
35 #include "toolkit.h" 35 #include "toolkit.h"
36 #include "../common/context.h" 36 #include "../common/context.h"
37 #include "../common/menu.h"
38 #include "../common/types.h"
37 #include "../ui/properties.h" 39 #include "../ui/properties.h"
38 #include "../ui/window.h" 40 #include "../ui/window.h"
39 #include "container.h" 41 #include "container.h"
40 42
41 static UcxList *menus; 43 #include <cx/linked_list.h>
42 static UcxList *current; 44 #include <cx/array_list.h>
43 45
44 void ui_menu(char *label) { 46 #if GTK_MAJOR_VERSION <= 3
45 // free current menu hierarchy 47
46 ucx_list_free(current); 48 static ui_menu_add_f createMenuItem[] = {
47 49 /* UI_MENU */ add_menu_widget,
48 // create menu 50 /* UI_MENU_ITEM */ add_menuitem_widget,
49 UiMenu *menu = malloc(sizeof(UiMenu)); 51 /* UI_MENU_CHECK_ITEM */ add_checkitem_widget,
50 menu->item.add_to = (ui_menu_add_f)add_menu_widget; 52 /* UI_MENU_RADIO_ITEM */ add_radioitem_widget,
51 53 /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget,
52 menu->label = label; 54 /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget,
53 menu->items = NULL; 55 /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget,
54 menu->parent = NULL; 56 /* UI_MENU_SEPARATOR */ add_menuseparator_widget
55 57 };
56 current = ucx_list_prepend(NULL, menu);
57 menus = ucx_list_append(menus, menu);
58
59 }
60
61 void ui_submenu(char *label) {
62 UiMenu *menu = malloc(sizeof(UiMenu));
63 menu->item.add_to = (ui_menu_add_f)add_menu_widget;
64
65 menu->label = label;
66 menu->items = NULL;
67 menu->parent = NULL;
68
69 // add submenu to current menu
70 UiMenu *cm = current->data;
71 cm->items = ucx_list_append(cm->items, menu);
72
73 // set the submenu to current menu
74 current = ucx_list_prepend(current, menu);
75 }
76
77 void ui_submenu_end() {
78 if(ucx_list_size(current) < 2) {
79 return;
80 }
81 current = ucx_list_remove(current, current);
82 //UcxList *c = current;
83 }
84
85 void ui_menuitem(char *label, ui_callback f, void *userdata) {
86 ui_menuitem_gr(label, f, userdata, -1);
87 }
88
89 void ui_menuitem_st(char *stockid, ui_callback f, void *userdata) {
90 ui_menuitem_stgr(stockid, f, userdata, -1);
91 }
92
93 void ui_menuitem_gr(char *label, ui_callback f, void *userdata, ...) {
94 if(!current) {
95 return;
96 }
97
98 UiMenuItem *item = malloc(sizeof(UiMenuItem));
99 item->item.add_to = (ui_menu_add_f)add_menuitem_widget;
100
101 item->label = label;
102 item->userdata = userdata;
103 item->callback = f;
104 item->groups = NULL;
105
106 // add groups
107 va_list ap;
108 va_start(ap, userdata);
109 int group;
110 while((group = va_arg(ap, int)) != -1) {
111 item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group);
112 }
113 va_end(ap);
114
115 UiMenu *cm = current->data;
116 cm->items = ucx_list_append(cm->items, item);
117 }
118
119 void ui_menuitem_stgr(char *stockid, ui_callback f, void *userdata, ...) {
120 if(!current) {
121 return;
122 }
123
124 UiStMenuItem *item = malloc(sizeof(UiStMenuItem));
125 item->item.add_to = (ui_menu_add_f)add_menuitem_st_widget;
126
127 item->stockid = stockid;
128 item->userdata = userdata;
129 item->callback = f;
130 item->groups = NULL;
131
132 // add groups
133 va_list ap;
134 va_start(ap, userdata);
135 int group;
136 while((group = va_arg(ap, int)) != -1) {
137 item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group);
138 }
139 va_end(ap);
140
141 UiMenu *cm = current->data;
142 cm->items = ucx_list_append(cm->items, item);
143 }
144
145 void ui_menuseparator() {
146 if(!current) {
147 return;
148 }
149
150 UiMenuItemI *item = malloc(sizeof(UiMenuItemI));
151 item->add_to = (ui_menu_add_f)add_menuseparator_widget;
152
153 UiMenu *cm = current->data;
154 cm->items = ucx_list_append(cm->items, item);
155 }
156
157 void ui_checkitem(char *label, ui_callback f, void *userdata) {
158 if(!current) {
159 return;
160 }
161
162 UiCheckItem *item = malloc(sizeof(UiCheckItem));
163 item->item.add_to = (ui_menu_add_f)add_checkitem_widget;
164 item->label = label;
165 item->callback = f;
166 item->userdata = userdata;
167
168 UiMenu *cm = current->data;
169 cm->items = ucx_list_append(cm->items, item);
170 }
171
172 void ui_checkitem_nv(char *label, char *vname) {
173 if(!current) {
174 return;
175 }
176
177 UiCheckItemNV *item = malloc(sizeof(UiCheckItemNV));
178 item->item.add_to = (ui_menu_add_f)add_checkitemnv_widget;
179 item->varname = vname;
180 item->label = label;
181
182 UiMenu *cm = current->data;
183 cm->items = ucx_list_append(cm->items, item);
184 }
185
186 void ui_menuitem_list(UiList *items, ui_callback f, void *userdata) {
187 if(!current) {
188 return;
189 }
190
191 UiMenuItemList *item = malloc(sizeof(UiMenuItemList));
192 item->item.add_to = (ui_menu_add_f)add_menuitem_list_widget;
193 item->callback = f;
194 item->userdata = userdata;
195 item->list = items;
196
197 UiMenu *cm = current->data;
198 cm->items = ucx_list_append(cm->items, item);
199 }
200 58
201 // private menu functions 59 // private menu functions
202 GtkWidget *ui_create_menubar(UiObject *obj) { 60 GtkWidget *ui_create_menubar(UiObject *obj) {
203 if(menus == NULL) { 61 UiMenu *menus_begin = uic_get_menu_list();
62 if(menus_begin == NULL) {
204 return NULL; 63 return NULL;
205 } 64 }
206 65
207 GtkWidget *mb = gtk_menu_bar_new(); 66 GtkWidget *mb = gtk_menu_bar_new();
208 67
209 UcxList *ls = menus; 68 UiMenu *ls = menus_begin;
210 while(ls) { 69 while(ls) {
211 UiMenu *menu = ls->data; 70 UiMenu *menu = ls;
212 menu->item.add_to(mb, 0, &menu->item, obj); 71 add_menu_widget(mb, 0, &menu->item, obj);
213 72
214 ls = ls->next; 73 ls = (UiMenu*)ls->item.next;
215 } 74 }
216 75
217 return mb; 76 return mb;
77 }
78
79 void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj) {
80 UiMenuItemI *it = menu->items_begin;
81 int index = 0;
82 while(it) {
83 createMenuItem[it->type](parent, index, it, obj);
84 it = it->next;
85 index++;
86 }
218 } 87 }
219 88
220 void add_menu_widget(GtkWidget *parent, int i, UiMenuItemI *item, UiObject *obj) { 89 void add_menu_widget(GtkWidget *parent, int i, UiMenuItemI *item, UiObject *obj) {
221 UiMenu *menu = (UiMenu*)item; 90 UiMenu *menu = (UiMenu*)item;
222 91
223 GtkWidget *menu_widget = gtk_menu_new(); 92 GtkWidget *menu_widget = gtk_menu_new();
224 GtkWidget *menu_item = gtk_menu_item_new_with_mnemonic(menu->label); 93 GtkWidget *menu_item = gtk_menu_item_new_with_mnemonic(menu->label);
225 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu_widget); 94 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu_widget);
226 95
227 UcxList *ls = menu->items; 96 ui_add_menu_items(menu_widget, i, menu, obj);
228 int index = 0; 97
229 while(ls) {
230 UiMenuItemI *i = ls->data;
231 i->add_to(menu_widget, index, i, obj);
232
233 ls = ls->next;
234 index++;
235 }
236 98
237 gtk_menu_shell_append(GTK_MENU_SHELL(parent), menu_item); 99 gtk_menu_shell_append(GTK_MENU_SHELL(parent), menu_item);
238 } 100 }
239 101
240 void add_menuitem_widget(GtkWidget *parent, int index, UiMenuItemI *item, UiObject *obj) { 102 void add_menuitem_widget(GtkWidget *parent, int index, UiMenuItemI *item, UiObject *obj) {
247 UiEventData *event = malloc(sizeof(UiEventData)); 109 UiEventData *event = malloc(sizeof(UiEventData));
248 event->obj = obj; 110 event->obj = obj;
249 event->userdata = i->userdata; 111 event->userdata = i->userdata;
250 event->callback = i->callback; 112 event->callback = i->callback;
251 event->value = 0; 113 event->value = 0;
114 event->customdata = NULL;
252 115
253 g_signal_connect( 116 g_signal_connect(
254 widget, 117 widget,
255 "activate", 118 "activate",
256 G_CALLBACK(ui_menu_event_wrapper), 119 G_CALLBACK(ui_menu_event_wrapper),
263 } 126 }
264 127
265 gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); 128 gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
266 129
267 if(i->groups) { 130 if(i->groups) {
268 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups); 131 CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups);
269 } 132 cxListAddArray(groups, i->groups, i->ngroups);
270 } 133 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups);
271 134 cxListDestroy(groups);
135 }
136 }
137
138 /*
272 void add_menuitem_st_widget( 139 void add_menuitem_st_widget(
273 GtkWidget *parent, 140 GtkWidget *parent,
274 int index, 141 int index,
275 UiMenuItemI *item, 142 UiMenuItemI *item,
276 UiObject *obj) 143 UiObject *obj)
302 169
303 if(i->groups) { 170 if(i->groups) {
304 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups); 171 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups);
305 } 172 }
306 } 173 }
174 */
307 175
308 void add_menuseparator_widget( 176 void add_menuseparator_widget(
309 GtkWidget *parent, 177 GtkWidget *parent,
310 int index, 178 int index,
311 UiMenuItemI *item, 179 UiMenuItemI *item,
315 GTK_MENU_SHELL(parent), 183 GTK_MENU_SHELL(parent),
316 gtk_separator_menu_item_new()); 184 gtk_separator_menu_item_new());
317 } 185 }
318 186
319 void add_checkitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { 187 void add_checkitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
320 UiCheckItem *ci = (UiCheckItem*)item; 188 UiMenuCheckItem *ci = (UiMenuCheckItem*)item;
321 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); 189 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
322 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); 190 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget);
323 191
324 if(ci->callback) { 192 if(ci->callback) {
325 UiEventData *event = malloc(sizeof(UiEventData)); 193 UiEventData *event = malloc(sizeof(UiEventData));
326 event->obj = obj; 194 event->obj = obj;
327 event->userdata = ci->userdata; 195 event->userdata = ci->userdata;
328 event->callback = ci->callback; 196 event->callback = ci->callback;
329 event->value = 0; 197 event->value = 0;
330 198 event->customdata = NULL;
199
331 g_signal_connect( 200 g_signal_connect(
332 widget, 201 widget,
333 "toggled", 202 "toggled",
334 G_CALLBACK(ui_menu_event_toggled), 203 G_CALLBACK(ui_menu_event_toggled),
335 event); 204 event);
339 G_CALLBACK(ui_destroy_userdata), 208 G_CALLBACK(ui_destroy_userdata),
340 event); 209 event);
341 } 210 }
342 } 211 }
343 212
213 void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
214 // TODO
215 }
216
217 /*
344 void add_checkitemnv_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { 218 void add_checkitemnv_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
345 UiCheckItemNV *ci = (UiCheckItemNV*)item; 219 UiCheckItemNV *ci = (UiCheckItemNV*)item;
346 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); 220 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
347 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); 221 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget);
348 222
355 value = 0; 229 value = 0;
356 } else { 230 } else {
357 // TODO: error 231 // TODO: error
358 } 232 }
359 } 233 }
234 */
360 235
361 void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { 236 void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
362 UiMenuItemList *il = (UiMenuItemList*)item; 237 UiMenuItemList *il = (UiMenuItemList*)item;
363 UcxMempool *mp = obj->ctx->mempool; 238 const CxAllocator *a = obj->ctx->allocator;
364 239
365 UiActiveMenuItemList *ls = ucx_mempool_malloc( 240 UiActiveMenuItemList *ls = cxMalloc(
366 mp, 241 a,
367 sizeof(UiActiveMenuItemList)); 242 sizeof(UiActiveMenuItemList));
368 243
369 ls->object = obj; 244 ls->object = obj;
370 ls->menu = GTK_MENU_SHELL(p); 245 ls->menu = GTK_MENU_SHELL(p);
371 ls->index = index; 246 ls->index = index;
372 ls->oldcount = 0; 247 ls->oldcount = 0;
373 ls->list = il->list; 248 ls->getvalue = il->getvalue;
249
250 UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
251 ls->list = var->value;
252
374 ls->callback = il->callback; 253 ls->callback = il->callback;
375 ls->userdata = il->userdata; 254 ls->userdata = il->userdata;
376 255
377 ls->list->observers = ui_add_observer( 256 UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls);
378 ls->list->observers, 257 ls->list->observers = ui_obsvlist_add(ls->list->observers, observer);
379 (ui_callback)ui_update_menuitem_list, 258 uic_list_register_observer_destructor(obj->ctx, ls->list, observer);
380 ls);
381 259
382 ui_update_menuitem_list(NULL, ls); 260 ui_update_menuitem_list(NULL, ls);
383 } 261 }
384 262
385 263
396 mi = mi->next; 274 mi = mi->next;
397 i++; 275 i++;
398 } 276 }
399 } 277 }
400 278
401 char *str = ui_list_first(list->list); 279 void* elm = ui_list_first(list->list);
402 if(str) { 280 if(elm) {
403 GtkWidget *widget = gtk_separator_menu_item_new(); 281 GtkWidget *widget = gtk_separator_menu_item_new();
404 gtk_menu_shell_insert(list->menu, widget, list->index); 282 gtk_menu_shell_insert(list->menu, widget, list->index);
405 gtk_widget_show(widget); 283 gtk_widget_show(widget);
406 } 284 }
285
286 ui_getvaluefunc getvalue = list->getvalue;
407 int i = 1; 287 int i = 1;
408 while(str) { 288 while(elm) {
409 GtkWidget *widget = gtk_menu_item_new_with_label(str); 289 char *label = (char*) (getvalue ? getvalue(elm, 0) : elm);
290
291 GtkWidget *widget = gtk_menu_item_new_with_label(label);
410 gtk_menu_shell_insert(list->menu, widget, list->index + i); 292 gtk_menu_shell_insert(list->menu, widget, list->index + i);
411 gtk_widget_show(widget); 293 gtk_widget_show(widget);
412 294
413 if(list->callback) { 295 if(list->callback) {
414 // TODO: use mempool
415 UiEventData *event = malloc(sizeof(UiEventData)); 296 UiEventData *event = malloc(sizeof(UiEventData));
416 event->obj = list->object; 297 event->obj = list->object;
417 event->userdata = list->userdata; 298 event->userdata = list->userdata;
418 event->callback = list->callback; 299 event->callback = list->callback;
419 event->value = i - 1; 300 event->value = i - 1;
301 event->customdata = elm;
420 302
421 g_signal_connect( 303 g_signal_connect(
422 widget, 304 widget,
423 "activate", 305 "activate",
424 G_CALLBACK(ui_menu_event_wrapper), 306 G_CALLBACK(ui_menu_event_wrapper),
428 "destroy", 310 "destroy",
429 G_CALLBACK(ui_destroy_userdata), 311 G_CALLBACK(ui_destroy_userdata),
430 event); 312 event);
431 } 313 }
432 314
433 str = ui_list_next(list->list); 315 elm = ui_list_next(list->list);
434 i++; 316 i++;
435 } 317 }
436 318
437 list->oldcount = i; 319 list->oldcount = i;
438 } 320 }
440 void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) { 322 void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) {
441 UiEvent evt; 323 UiEvent evt;
442 evt.obj = event->obj; 324 evt.obj = event->obj;
443 evt.window = event->obj->window; 325 evt.window = event->obj->window;
444 evt.document = event->obj->ctx->document; 326 evt.document = event->obj->ctx->document;
445 evt.eventdata = NULL; 327 evt.eventdata = event->customdata;
446 evt.intval = event->value; 328 evt.intval = event->value;
447 event->callback(&evt, event->userdata); 329 event->callback(&evt, event->userdata);
448 } 330 }
449 331
450 void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) { 332 void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) {
471 353
472 /* 354 /*
473 * widget menu functions 355 * widget menu functions
474 */ 356 */
475 357
358 UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, UIWIDGET widget) {
359 GtkWidget *menu_widget = gtk_menu_new();
360 ui_add_menu_items(menu_widget, 0, builder->menus_begin, obj);
361 return GTK_MENU(menu_widget);
362 }
363
476 static gboolean ui_button_press_event(GtkWidget *widget, GdkEvent *event, GtkMenu *menu) { 364 static gboolean ui_button_press_event(GtkWidget *widget, GdkEvent *event, GtkMenu *menu) {
477 if(event->type == GDK_BUTTON_PRESS) { 365 if(event->type == GDK_BUTTON_PRESS) {
478 GdkEventButton *e = (GdkEventButton*)event; 366 GdkEventButton *e = (GdkEventButton*)event;
479 if(e->button == 3) { 367 if(e->button == 3) {
480 gtk_widget_show_all(GTK_WIDGET(menu)); 368 gtk_widget_show_all(GTK_WIDGET(menu));
481 ui_contextmenu_popup(menu); 369 ui_contextmenu_popup(menu, widget, 0, 0);
482 return TRUE;
483 } 370 }
484 } 371 }
485 return FALSE; 372 return FALSE;
486 } 373 }
487 374
488 UIMENU ui_contextmenu(UiObject *obj) { 375 void ui_widget_set_contextmenu(GtkWidget *widget, GtkMenu *menu) {
489 UiContainer *ct = uic_get_current_container(obj);
490 return ui_contextmenu_w(obj, ct->current);
491 }
492
493 UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) {
494 UiContainer *ct = uic_get_current_container(obj);
495
496 GtkMenu *menu = GTK_MENU(gtk_menu_new());
497 g_signal_connect(widget, "button-press-event", (GCallback) ui_button_press_event, menu); 376 g_signal_connect(widget, "button-press-event", (GCallback) ui_button_press_event, menu);
498 377 }
499 ct->menu = menu; 378
500 return menu; 379 void ui_contextmenu_popup(UIMENU menu, GtkWidget *widget, int x, int y) {
501 }
502
503 void ui_contextmenu_popup(UIMENU menu) {
504 #if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 16 380 #if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 16
505 gtk_menu_popup_at_pointer(menu, NULL); 381 gtk_menu_popup_at_pointer(menu, NULL);
506 #else 382 #else
507 gtk_menu_popup(menu, NULL, NULL, 0, 0, 0, gtk_get_current_event_time()); 383 gtk_menu_popup(menu, NULL, NULL, 0, 0, 0, gtk_get_current_event_time());
508 #endif 384 #endif
509 } 385 }
510 386
511 void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata) { 387 #endif /* GTK_MAJOR_VERSION <= 3 */
512 ui_widget_menuitem_gr(obj, label, f, userdata, -1); 388
513 } 389
514 390
515 void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...) { 391 #if GTK_MAJOR_VERSION >= 4
516 UiContainer *ct = uic_get_current_container(obj); 392
517 if(!ct->menu) { 393
518 return; 394
519 } 395 static ui_gmenu_add_f createMenuItem[] = {
520 396 /* UI_MENU */ ui_gmenu_add_menu,
521 // add groups 397 /* UI_MENU_ITEM */ ui_gmenu_add_menuitem,
522 UcxList *groups = NULL; 398 /* UI_MENU_CHECK_ITEM */ ui_gmenu_add_checkitem,
523 va_list ap; 399 /* UI_MENU_RADIO_ITEM */ ui_gmenu_add_radioitem,
524 va_start(ap, userdata); 400 /* UI_MENU_ITEM_LIST */ ui_gmenu_add_menuitem_list,
525 int group; 401 /* UI_MENU_CHECKITEM_LIST */ ui_gmenu_add_menuitem_list,
526 while((group = va_arg(ap, int)) != -1) { 402 /* UI_MENU_RADIOITEM_LIST */ ui_gmenu_add_menuitem_list,
527 ucx_list_append(groups, (void*)(intptr_t)group); 403 /* UI_MENU_SEPARATOR */ ui_gmenu_add_menuseparator
528 } 404 };
529 va_end(ap); 405
530 406 void ui_gmenu_add_menu_items(GMenu *parent, int i, UiMenu *menu, UiObject *obj) {
531 // create menuitem 407 UiMenuItemI *it = menu->items_begin;
532 GtkWidget *widget = gtk_menu_item_new_with_mnemonic(label); 408 int index = 0;
533 gtk_widget_show(widget); 409 int index_section = 0;
534 410 GMenu *section = NULL;
535 if(f) { 411 while(it) {
412 if(it->type == UI_MENU_SEPARATOR) {
413 section = g_menu_new();
414 g_menu_append_section(parent, NULL, G_MENU_MODEL(section));
415 index++;
416 index_section = 0;
417 } else {
418 if(section) {
419 createMenuItem[it->type](section, index_section++, it, obj);
420 } else {
421 createMenuItem[it->type](parent, index++, it, obj);
422 }
423 }
424 it = it->next;
425 }
426 }
427
428 void ui_gmenu_add_menu(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) {
429 UiMenu *mi = (UiMenu*)item;
430 GMenu *menu = g_menu_new();
431 ui_gmenu_add_menu_items(menu, 0, mi, obj);
432 g_menu_append_submenu(parent, mi->label, G_MENU_MODEL(menu));
433 }
434
435 static void action_enable(GSimpleAction *action, int enabled) {
436 g_simple_action_set_enabled(action, enabled);
437 }
438
439 void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) {
440 UiMenuItem *i = (UiMenuItem*)item;
441
442 GSimpleAction *action = g_simple_action_new(item->id, NULL);
443 g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
444
445 if(i->groups) {
446 CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups);
447 cxListAddArray(groups, i->groups, i->ngroups);
448 uic_add_group_widget(obj->ctx, action, (ui_enablefunc)action_enable, groups);
449 cxListDestroy(groups);
450 }
451
452 if(i->callback != NULL) {
536 UiEventData *event = malloc(sizeof(UiEventData)); 453 UiEventData *event = malloc(sizeof(UiEventData));
537 event->obj = obj; 454 event->obj = obj;
538 event->userdata = userdata; 455 event->userdata = i->userdata;
539 event->callback = f; 456 event->callback = i->callback;
540 event->value = 0; 457 event->value = 0;
541 458 event->customdata = NULL;
542 g_signal_connect( 459
543 widget, 460 g_signal_connect(
461 action,
544 "activate", 462 "activate",
545 G_CALLBACK(ui_menu_event_wrapper), 463 G_CALLBACK(ui_activate_event_wrapper),
546 event); 464 event);
547 g_signal_connect( 465 g_signal_connect(
548 widget, 466 obj->widget,
549 "destroy", 467 "destroy",
550 G_CALLBACK(ui_destroy_userdata), 468 G_CALLBACK(ui_destroy_userdata),
551 event); 469 event);
552 } 470 }
553 471
554 gtk_menu_shell_append(GTK_MENU_SHELL(ct->menu), widget); 472 char action_name[32];
555 473 snprintf(action_name, 32, "win.%s", item->id);
556 if(groups) { 474 g_menu_append(parent, i->label, action_name);
557 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); 475 }
558 } 476
559 } 477 void ui_gmenu_add_menuseparator(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) {
560 478
561 void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) { 479 }
562 ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1); 480
563 } 481 void ui_gmenu_add_checkitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) {
564 482 UiMenuCheckItem *checkitem = (UiMenuCheckItem*)item;
565 void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...) { 483
566 UiContainer *ct = uic_get_current_container(obj); 484 // TODO
567 if(!ct->menu) { 485 }
568 return; 486
569 } 487 void ui_gmenu_add_radioitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) {
570 488
571 // add groups 489 }
572 UcxList *groups = NULL; 490
573 va_list ap; 491 void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) {
574 va_start(ap, userdata); 492 UiMenuItemList *il = (UiMenuItemList*)item;
575 int group; 493
576 while((group = va_arg(ap, int)) != -1) { 494 const CxAllocator *a = obj->ctx->allocator;
577 ucx_list_append(groups, (void*)(intptr_t)group); 495
578 } 496 UiActiveGMenuItemList *ls = cxMalloc(
579 va_end(ap); 497 a,
580 498 sizeof(UiActiveGMenuItemList));
581 // create menuitem 499
582 GtkWidget *widget = gtk_image_menu_item_new_from_stock(stockid, obj->ctx->accel_group); 500 ls->object = obj;
583 gtk_widget_show(widget); 501 ls->menu = p;
584 502 ls->index = index;
585 if(f) { 503 ls->oldcount = 0;
586 UiEventData *event = malloc(sizeof(UiEventData)); 504 ls->getvalue = il->getvalue;
587 event->obj = obj; 505
588 event->userdata = userdata; 506 UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
589 event->callback = f; 507 ls->var = var;
590 event->value = 0; 508 UiList *list = var->value;
591 509
592 g_signal_connect( 510 ls->callback = il->callback;
593 widget, 511 ls->userdata = il->userdata;
594 "activate", 512
595 G_CALLBACK(ui_menu_event_wrapper), 513 UiObserver *observer = ui_observer_new((ui_callback)ui_update_gmenu_item_list, ls);
596 event); 514 list->observers = ui_obsvlist_add(list->observers, observer);
597 g_signal_connect( 515 uic_list_register_observer_destructor(obj->ctx, list, observer);
516
517 GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i"));
518 g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
519 snprintf(ls->action, 32, "win.%s", item->id);
520
521
522 UiEventData *event = malloc(sizeof(UiEventData));
523 event->obj = obj;
524 event->userdata = il->userdata;
525 event->callback = il->callback;
526 event->customdata = var;
527 event->value = 0;
528
529 g_signal_connect(
530 action,
531 "activate",
532 G_CALLBACK(ui_menu_list_item_activate_event_wrapper),
533 event);
534 g_signal_connect(
535 obj->widget,
536 "destroy",
537 G_CALLBACK(ui_destroy_userdata),
538 event);
539
540 ui_update_gmenu_item_list(NULL, ls);
541 }
542
543 void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) {
544 int intval = event->value;
545 if(parameter && g_variant_is_of_type(parameter, G_VARIANT_TYPE_INT32)) {
546 intval = g_variant_get_int32(parameter);
547 }
548
549 UiEvent evt;
550 evt.obj = event->obj;
551 evt.window = event->obj->window;
552 evt.document = event->obj->ctx->document;
553 evt.eventdata = event->customdata;
554 evt.intval = intval;
555 event->callback(&evt, event->userdata);
556 }
557
558 void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) {
559 int index = g_variant_get_int32(parameter);
560 UiVar *var = event->customdata;
561 UiList *list = var->value;
562
563 UiEvent evt;
564 evt.obj = event->obj;
565 evt.window = event->obj->window;
566 evt.document = event->obj->ctx->document;
567 evt.eventdata = ui_list_get(list, index);
568 evt.intval = index;
569 event->callback(&evt, event->userdata);
570
571 }
572
573 void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list) {
574 // remove old items
575 for(int i=0;i<list->oldcount;i++) {
576 g_menu_remove(list->menu, list->index);
577 }
578 UiList *ls = list->var->value;
579
580 // add list items
581 ui_getvaluefunc getvalue = list->getvalue;
582 int i = 0;
583 void* elm = ui_list_first(ls);
584 while(elm) {
585 char *label = (char*) (getvalue ? getvalue(elm, 0) : elm);
586
587 GMenuItem *item = g_menu_item_new(label, NULL);
588 GVariant *v = g_variant_new("i", i);
589 g_menu_item_set_action_and_target_value(item, list->action, v);
590 g_menu_insert_item(list->menu, list->index+i, item);
591
592 elm = ui_list_next(ls);
593 i++;
594 }
595
596 list->oldcount = i;
597 }
598
599
600 /* --------------------- context menu / menubuilder --------------------- */
601
602 static void remove_popover(GtkWidget *object, GtkPopoverMenu *menu) {
603 gtk_widget_unparent(GTK_WIDGET(menu));
604 }
605
606 UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, GtkWidget *widget) {
607 GMenu *menu = g_menu_new();
608 ui_gmenu_add_menu_items(menu, 0, builder->menus_begin, obj);
609 GtkWidget *contextmenu = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
610 gtk_popover_set_has_arrow(GTK_POPOVER(contextmenu), FALSE);
611 gtk_widget_set_halign(contextmenu, GTK_ALIGN_START);
612 gtk_widget_set_parent(GTK_WIDGET(contextmenu), widget);
613 g_signal_connect(
598 widget, 614 widget,
599 "destroy", 615 "destroy",
600 G_CALLBACK(ui_destroy_userdata), 616 G_CALLBACK(remove_popover),
601 event); 617 contextmenu);
602 } 618 return GTK_POPOVER_MENU(contextmenu);
603 619 }
604 gtk_menu_shell_append(GTK_MENU_SHELL(ct->menu), widget); 620
605 621 static void gesture_button_press(GtkGestureClick *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) {
606 if(groups) { 622 gtk_popover_set_pointing_to(GTK_POPOVER(user_data), &(GdkRectangle){ x, y, 0, 0 });
607 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); 623 gtk_popover_popup(GTK_POPOVER(user_data));
608 } 624 }
609 } 625
626 void ui_widget_set_contextmenu(GtkWidget *widget, GtkPopoverMenu *menu) {
627 GtkGesture *gesture = gtk_gesture_click_new();
628 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
629 gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(gesture));
630 g_signal_connect(gesture, "pressed", G_CALLBACK(gesture_button_press), menu);
631 }
632
633 void ui_contextmenu_popup(UIMENU menu, UIWIDGET widget, int x, int y) {
634 gtk_popover_set_pointing_to(GTK_POPOVER(menu), &(GdkRectangle){ x, y, 0, 0 });
635 gtk_popover_popup(GTK_POPOVER(menu));
636 }
637
638 #endif

mercurial