# HG changeset patch # User Olaf Wintermann # Date 1763195095 -3600 # Node ID 0484fc666c1dffb3c9e8fe3a04b0b2948fb0d68c # Parent 0d488f04078d13807d87cf153a33c6269104735f implement spinbox value binding (Motif) diff -r 0d488f04078d -r 0484fc666c1d application/main.c --- a/application/main.c Fri Nov 14 22:02:00 2025 +0100 +++ b/application/main.c Sat Nov 15 09:24:55 2025 +0100 @@ -921,6 +921,7 @@ UiList *list; UiInteger *spinner; UiInteger *tab; + UiDouble *num; } WData; @@ -975,6 +976,7 @@ wdata->list = ui_list_new(obj->ctx, NULL); wdata->spinner = ui_int_new(obj->ctx, NULL); wdata->tab = ui_int_new(obj->ctx, NULL); + wdata->num = ui_double_new(obj->ctx, "num"); obj->window = wdata; ui_list_append(wdata->list, "List Item 1"); @@ -1012,7 +1014,7 @@ ui_tab(obj, "Tab 4") { ui_grid(obj, .margin = 10) { - ui_spinbox(obj, .varname = "num1"); + ui_spinbox(obj, .varname = "num"); } } } diff -r 0d488f04078d -r 0484fc666c1d ui/motif/button.c --- a/ui/motif/button.c Fri Nov 14 22:02:00 2025 +0100 +++ b/ui/motif/button.c Sat Nov 15 09:24:55 2025 +0100 @@ -77,7 +77,7 @@ XtAddCallback( button, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_eventdata, + (XtCallbackProc)ui_destroy_data, eventdata); } @@ -224,7 +224,7 @@ XtAddCallback( widget, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_eventdata, + (XtCallbackProc)ui_destroy_data, event); } @@ -341,7 +341,7 @@ XtAddCallback( rbutton, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_eventdata, + (XtCallbackProc)ui_destroy_data, event); } @@ -411,7 +411,7 @@ XtAddCallback( button, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_eventdata, + (XtCallbackProc)ui_destroy_data, event); XmStringFree(label); diff -r 0d488f04078d -r 0484fc666c1d ui/motif/entry.c --- a/ui/motif/entry.c Fri Nov 14 22:02:00 2025 +0100 +++ b/ui/motif/entry.c Sat Nov 15 09:24:55 2025 +0100 @@ -106,46 +106,160 @@ textfield = children[i]; } } - + UiSpinBox *data = malloc(sizeof(UiSpinBox)); data->obj = obj; data->textfield = textfield; data->var = var; data->vartype = vartype; + data->obs = NULL; data->onchange = args->onchange; data->onchangedata = args->onchangedata; - data->last_value = 0; + data->value = 0; data->min = min; data->max = max; data->increment = args->step; data->digits = args->digits; + UiObserver **obs = NULL; + if(var) { + double value = 0; + switch(vartype) { + default: break; + case UI_VAR_INTEGER: { + UiInteger *i = var->value; + i->get = ui_spinbutton_getint; + i->set = ui_spinbutton_setint; + i->obj = data; + value = (double)i->value; + obs = &i->observers; + break; + } + case UI_VAR_DOUBLE: { + UiDouble *d = var->value; + d->get = ui_spinbutton_getdouble; + d->set = ui_spinbutton_setdouble; + d->obj = data; + value = d->value; + obs = &d->observers; + break; + } + case UI_VAR_RANGE: { + UiRange *r = var->value; + r->get = ui_spinbutton_getrangeval; + r->set = ui_spinbutton_setrangeval; + r->setrange = ui_spinbutton_setrange; + r->setextent = ui_spinbutton_setextent; + r->obj = data; + value = r->value; + obs = &r->observers; + break; + } + } + ui_spinbox_set_value(data, value); + } + data->obs = obs; + XtAddCallback( spinbox, XmNvalueChangedCallback, (XtCallbackProc)ui_spinbox_value_changed, data); + XtAddCallback( + spinbox, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_data, + data); + XmTextFieldSetString(textfield, "0"); return spinbox; } +void ui_spinbox_set_value(UiSpinBox *spinbox, double value) { + if(value < spinbox->min) { + value = spinbox->min; + } + if(value > spinbox->max) { + value = spinbox->max; + } + + char buf[32]; + snprintf(buf, 32, "%.*f", spinbox->digits, spinbox->value); + XmTextFieldSetString(spinbox->textfield, buf); + spinbox->value = value; +} + void ui_spinbox_value_changed(Widget widget, UiSpinBox *spinbox, XmSpinBoxCallbackStruct *cb) { - char buf[32]; + Boolean update_value = TRUE; + double value = spinbox->value; switch(cb->reason) { - case 62: { - spinbox->last_value += spinbox->increment; - snprintf(buf, 32, "%.*f", spinbox->digits, spinbox->last_value); - XmTextFieldSetString(spinbox->textfield, buf); + case XmCR_OK: { + update_value = FALSE; break; } - case 63: { - spinbox->last_value -= spinbox->increment; - snprintf(buf, 32, "%.*f", spinbox->digits, spinbox->last_value); - XmTextFieldSetString(spinbox->textfield, buf); + case XmCR_SPIN_NEXT: { + value += spinbox->increment; + break; + } + case XmCR_SPIN_PRIOR: { + value -= spinbox->increment; break; } } + + if(update_value) { + ui_spinbox_set_value(spinbox, value); + } } + +int64_t ui_spinbutton_getint(UiInteger *i) { + UiSpinBox *spinbox = i->obj; + i->value = (int64_t)spinbox->value; + return i->value; +} + +void ui_spinbutton_setint(UiInteger *i, int64_t val) { + UiSpinBox *spinbox = i->obj; + ui_spinbox_set_value(spinbox, (double)val); + i->value = spinbox->value; +} + +double ui_spinbutton_getdouble(UiDouble *d) { + UiSpinBox *spinbox = d->obj; + d->value = spinbox->value; + return d->value; +} + +void ui_spinbutton_setdouble(UiDouble *d, double val) { + UiSpinBox *spinbox = d->obj; + ui_spinbox_set_value(spinbox, val); + d->value = spinbox->value; +} + +double ui_spinbutton_getrangeval(UiRange *r) { + UiSpinBox *spinbox = r->obj; + r->value = spinbox->value; + return r->value; +} + +void ui_spinbutton_setrangeval(UiRange *r, double val) { + UiSpinBox *spinbox = r->obj; + ui_spinbox_set_value(spinbox, val); + r->value = spinbox->value; +} +void ui_spinbutton_setrange(UiRange *r, double min, double max) { + UiSpinBox *spinbox = r->obj; + spinbox->min = min; + spinbox->max = max; + r->min = min; + r->max = max; +} + +void ui_spinbutton_setextent(UiRange *r, double extent) { + UiSpinBox *spinbox = r->obj; + spinbox->increment = extent; + r->extent = extent; +} diff -r 0d488f04078d -r 0484fc666c1d ui/motif/entry.h --- a/ui/motif/entry.h Fri Nov 14 22:02:00 2025 +0100 +++ b/ui/motif/entry.h Sat Nov 15 09:24:55 2025 +0100 @@ -44,17 +44,31 @@ Widget textfield; UiVar *var; UiVarType vartype; + UiObserver **obs; ui_callback onchange; void* onchangedata; - double last_value; + double value; double min; double max; double increment; int digits; } UiSpinBox; + +void ui_spinbox_set_value(UiSpinBox *spinbox, double value); void ui_spinbox_value_changed(Widget widget, UiSpinBox *spinbox, XmSpinBoxCallbackStruct *cb); +int64_t ui_spinbutton_getint(UiInteger *i); +void ui_spinbutton_setint(UiInteger *i, int64_t val); + +double ui_spinbutton_getdouble(UiDouble *d); +void ui_spinbutton_setdouble(UiDouble *d, double val); + +double ui_spinbutton_getrangeval(UiRange *r); +void ui_spinbutton_setrangeval(UiRange *r, double val); +void ui_spinbutton_setrange(UiRange *r, double min, double max); +void ui_spinbutton_setextent(UiRange *r, double extent); + #ifdef __cplusplus } #endif diff -r 0d488f04078d -r 0484fc666c1d ui/motif/menu.c --- a/ui/motif/menu.c Fri Nov 14 22:02:00 2025 +0100 +++ b/ui/motif/menu.c Sat Nov 15 09:24:55 2025 +0100 @@ -145,7 +145,7 @@ XtAddCallback( mitem, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_eventdata, + (XtCallbackProc)ui_destroy_data, eventdata); } @@ -337,7 +337,7 @@ XtAddCallback( mitem, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_eventdata, + (XtCallbackProc)ui_destroy_data, eventdata); } diff -r 0d488f04078d -r 0484fc666c1d ui/motif/text.c --- a/ui/motif/text.c Fri Nov 14 22:02:00 2025 +0100 +++ b/ui/motif/text.c Sat Nov 15 09:24:55 2025 +0100 @@ -1018,7 +1018,7 @@ XtAddCallback( pathbar->widget, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_eventdata, + (XtCallbackProc)ui_destroy_data, eventdata); } diff -r 0d488f04078d -r 0484fc666c1d ui/motif/toolkit.c --- a/ui/motif/toolkit.c Fri Nov 14 22:02:00 2025 +0100 +++ b/ui/motif/toolkit.c Sat Nov 15 09:24:55 2025 +0100 @@ -325,7 +325,7 @@ 4); } -void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d) { +void ui_destroy_data(Widget w, XtPointer data, XtPointer d) { free(data); } diff -r 0d488f04078d -r 0484fc666c1d ui/motif/toolkit.h --- a/ui/motif/toolkit.h Fri Nov 14 22:02:00 2025 +0100 +++ b/ui/motif/toolkit.h Sat Nov 15 09:24:55 2025 +0100 @@ -93,7 +93,7 @@ void ui_secondary_event_loop(int *loop); void ui_window_dark_theme(Display *dp, Window window); -void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d); +void ui_destroy_data(Widget w, XtPointer data, XtPointer d); void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) ; void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups);