| 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; |