ui/gtk/menu.c

changeset 849
63623ef950e5
parent 836
5a8485ff7f54
child 850
3e1c3f4e2ad4
equal deleted inserted replaced
848:5a4b72489111 849:63623ef950e5
41 #include "../ui/window.h" 41 #include "../ui/window.h"
42 #include "container.h" 42 #include "container.h"
43 43
44 #include <cx/linked_list.h> 44 #include <cx/linked_list.h>
45 #include <cx/array_list.h> 45 #include <cx/array_list.h>
46 #include <cx/printf.h>
46 47
47 #if GTK_MAJOR_VERSION <= 3 48 #if GTK_MAJOR_VERSION <= 3
48 49
49 static ui_menu_add_f createMenuItem[] = { 50 static ui_menu_add_f createMenuItem[] = {
50 /* UI_MENU */ add_menu_widget, 51 /* UI_MENU */ add_menu_widget,
485 UiMenuCheckItem *checkitem = (UiMenuCheckItem*)item; 486 UiMenuCheckItem *checkitem = (UiMenuCheckItem*)item;
486 487
487 // TODO 488 // TODO
488 } 489 }
489 490
490 void ui_gmenu_add_radioitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { 491
491 492
493 typedef struct UiCallbackData {
494 ui_callback callback;
495 void *userdata;
496 } UiCallbackData;
497
498 static void radiogroup_remove_binding(void *obj) {
499 UiMenuRadioGroup *group = obj;
500 if(group->var) {
501 UiInteger *i = group->var->value;
502 CxList *bindings = i->obj;
503 if(bindings) {
504 (void)cxListFindRemove(bindings, obj);
505 }
506 }
507 }
508
509 static void ui_action_set_state(UiInteger *i, int64_t value) {
510
511 }
512
513 static int64_t ui_action_get_state(UiInteger *i) {
514 return 0;
515 }
516
517 static UiMenuRadioGroup* create_radio_group(UiObject *obj, UiMenuRadioItem *item, GSimpleAction *action) {
518 UiMenuRadioGroup *group = cxZalloc(obj->ctx->allocator, sizeof(UiMenuRadioGroup));
519 group->callbacks = cxArrayListCreate(obj->ctx->allocator, NULL, sizeof(UiCallbackData), 8);
520 group->var = uic_create_var(ui_global_context(), item->varname, UI_VAR_INTEGER);
521 group->obj = obj;
522 group->action = action;
523 if(group->var) {
524 UiInteger *i = group->var->value;
525 CxList *bindings = i->obj;
526 if(!bindings) {
527 bindings = cxLinkedListCreate(group->var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS);
528 i->obj = bindings;
529 i->set = ui_action_set_state;
530 i->get = ui_action_get_state;
531 }
532 cxListAdd(bindings, group);
533 // the destruction of the toplevel obj must remove the binding
534 uic_context_add_destructor(obj->ctx, radiogroup_remove_binding, group);
535 }
536 return group;
537 }
538
539 static void stateful_action_activate(
540 GSimpleAction *action,
541 GVariant *state,
542 UiMenuRadioGroup *group)
543 {
544 g_simple_action_set_state(action, state);
545
546 UiVar *var = group->var;
547 if(!var) {
548 return;
549 }
550 UiInteger *i = var->value;
551
552 gsize len;
553 const char *s = g_variant_get_string(state, &len);
554 cxstring value = cx_strn(s, len);
555 int v;
556 if(!cx_strtoi(value, &v, 10)) {
557 i->value = v;
558 }
559
560 UiEvent event;
561 event.obj = group->obj;
562 event.window = event.obj->window;
563 event.document = event.obj->ctx->document;
564 event.eventdata = NULL;
565 event.eventdatatype = 0;
566 event.intval = v;
567 event.set = 0;
568
569 CxIterator iter = cxListIterator(group->callbacks);
570 cx_foreach(UiCallbackData *, cb, iter) {
571 if(cb->callback) {
572 cb->callback(&event, cb->userdata);
573 }
574 }
575
576 UiObserver *obs = i->observers;
577 while(obs) {
578 if(obs->callback) {
579 obs->callback(&event, obs->data);
580 }
581 obs = obs->next;
582 }
583 }
584
585
586
587 void ui_gmenu_add_radioitem(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) {
588 UiMenuRadioItem *i = (UiMenuRadioItem*)item;
589
590 if(!i->varname) {
591 return;
592 }
593
594 // All radio buttons with the name varname use the same GAction
595 UiMenuRadioGroup *group = NULL;
596 GAction *action = g_action_map_lookup_action(obj->ctx->action_map, i->varname);
597 if(!action) {
598 GVariant *state = g_variant_new_string("0");
599 GSimpleAction *newAction = g_simple_action_new_stateful(i->varname, G_VARIANT_TYPE_STRING, state);
600 g_action_map_add_action(obj->ctx->action_map, G_ACTION(newAction));
601
602 group = create_radio_group(obj, i, newAction);
603 g_object_set_data(G_OBJECT(newAction), "ui_radiogroup", group);
604
605 g_signal_connect(
606 newAction,
607 "change-state",
608 G_CALLBACK(stateful_action_activate),
609 group);
610 } else {
611 group = g_object_get_data(G_OBJECT(action), "ui_radiogroup");
612 if(!group) {
613 fprintf(stderr, "Error: missing ui_radiogroup property for action %s\n", i->varname);
614 return; // error, should not happen
615 }
616 }
617
618 size_t item_index = cxListSize(group->callbacks);
619
620 UiCallbackData cb;
621 cb.callback = i->callback;
622 cb.userdata = i->userdata;
623 cxListAdd(group->callbacks, &cb);
624
625
626 cxmutstr action_name = cx_asprintf("win.%s::%d", i->varname, (int)item_index);
627 g_menu_append(parent, i->label, action_name.ptr);
628 free(action_name.ptr);
492 } 629 }
493 630
494 static void menuitem_list_remove_binding(void *obj) { 631 static void menuitem_list_remove_binding(void *obj) {
495 UiActiveGMenuItemList *ls = obj; 632 UiActiveGMenuItemList *ls = obj;
496 UiList *list = ls->var->value; 633 UiList *list = ls->var->value;

mercurial