--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/motif/entry.c Sat Dec 13 15:58:58 2025 +0100 @@ -0,0 +1,281 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "entry.h" + + +UIWIDGET ui_spinbox_create(UiObject *obj, UiSpinBoxArgs *args) { + Arg xargs[16]; + int n = 0; + + double min = args->min; + double max = args->max != 0 ? args->max : 1000; + + UiVar *var = NULL; + UiVarType vartype = 0; + if(args->varname) { + var = uic_get_var(obj->ctx, args->varname); + if(var) { + vartype = var->type; + } else { + var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, args->varname, UI_VAR_RANGE); + vartype = UI_VAR_RANGE; + } + } + + if(!var) { + if(args->intvalue) { + var = uic_widget_var(obj->ctx, obj->ctx, args->intvalue, NULL, UI_VAR_INTEGER); + vartype = UI_VAR_INTEGER; + } else if(args->doublevalue) { + var = uic_widget_var(obj->ctx, obj->ctx, args->doublevalue, NULL, UI_VAR_DOUBLE); + vartype = UI_VAR_DOUBLE; + } else if(args->rangevalue) { + var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, NULL, UI_VAR_RANGE); + vartype = UI_VAR_RANGE; + } + } + + if(vartype == UI_VAR_RANGE) { + UiRange *r = var->value; + min = r->min; + max = r->max; + } + if(args->step == 0) { + args->step = 1; + } + + UiContainerPrivate *ctn = ui_obj_container(obj); + UiLayout layout = UI_ARGS2LAYOUT(args); + + + XtSetArg(xargs[n], XmNminimumValue, 0); n++; + XtSetArg(xargs[n], XmNmaximumValue, 100); n++; + XtSetArg(xargs[n], XmNincrementValue, 1); n++; + XtSetArg(xargs[n], XmNspinBoxChildType, XmNUMERIC); n++; + + Widget parent = ui_container_prepare(ctn, &layout, xargs, &n); + + char *name = args->name ? (char*)args->name : "button"; + Widget spinbox = XmCreateSimpleSpinBox(parent, name, xargs, n); + XtManageChild(spinbox); + ui_container_add(ctn, spinbox); + + ui_set_widget_groups(obj->ctx, spinbox, args->states); + + WidgetList children; + Cardinal num_children; + unsigned char type; + + Widget textfield = NULL; + XtVaGetValues( + spinbox, + XmNchildren, &children, + XmNnumChildren, &num_children, + NULL); + + for(int i = 0;i<num_children;i++) { + XtVaGetValues(children[i], XmNspinBoxChildType, &type, NULL); + Widget w = children[i]; + if(type == XmNUMERIC) { + 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->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) { + Boolean update_value = TRUE; + double value = spinbox->value; + switch(cb->reason) { + case XmCR_OK: { + update_value = FALSE; + break; + } + 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); + + UiEvent event; + event.obj = spinbox->obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + event.eventdata = NULL; + event.eventdatatype = 0; + event.intval = (int64_t)value; + event.set = ui_get_setop(); + + if(spinbox->onchange) { + spinbox->onchange(&event, spinbox->onchangedata); + } + + UiObserver *obs = *spinbox->obs; + ui_notify_evt(*spinbox->obs, &event); + } +} + +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; +}