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) { |
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 |