UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2025 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "entry.h" 30 31 32 UIWIDGET ui_spinbox_create(UiObject *obj, UiSpinBoxArgs *args) { 33 Arg xargs[16]; 34 int n = 0; 35 36 double min = args->min; 37 double max = args->max != 0 ? args->max : 1000; 38 39 UiVar *var = NULL; 40 UiVarType vartype = 0; 41 if(args->varname) { 42 var = uic_get_var(obj->ctx, args->varname); 43 if(var) { 44 vartype = var->type; 45 } else { 46 var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, args->varname, UI_VAR_RANGE); 47 vartype = UI_VAR_RANGE; 48 } 49 } 50 51 if(!var) { 52 if(args->intvalue) { 53 var = uic_widget_var(obj->ctx, obj->ctx, args->intvalue, NULL, UI_VAR_INTEGER); 54 vartype = UI_VAR_INTEGER; 55 } else if(args->doublevalue) { 56 var = uic_widget_var(obj->ctx, obj->ctx, args->doublevalue, NULL, UI_VAR_DOUBLE); 57 vartype = UI_VAR_DOUBLE; 58 } else if(args->rangevalue) { 59 var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, NULL, UI_VAR_RANGE); 60 vartype = UI_VAR_RANGE; 61 } 62 } 63 64 if(vartype == UI_VAR_RANGE) { 65 UiRange *r = var->value; 66 min = r->min; 67 max = r->max; 68 } 69 if(args->step == 0) { 70 args->step = 1; 71 } 72 73 UiContainerPrivate *ctn = ui_obj_container(obj); 74 UiLayout layout = UI_ARGS2LAYOUT(args); 75 76 77 XtSetArg(xargs[n], XmNminimumValue, 0); n++; 78 XtSetArg(xargs[n], XmNmaximumValue, 100); n++; 79 XtSetArg(xargs[n], XmNincrementValue, 1); n++; 80 XtSetArg(xargs[n], XmNspinBoxChildType, XmNUMERIC); n++; 81 82 Widget parent = ui_container_prepare(ctn, &layout, xargs, &n); 83 84 char *name = args->name ? (char*)args->name : "button"; 85 Widget spinbox = XmCreateSimpleSpinBox(parent, name, xargs, n); 86 XtManageChild(spinbox); 87 ui_container_add(ctn, spinbox); 88 89 ui_set_widget_groups(obj->ctx, spinbox, args->states); 90 91 WidgetList children; 92 Cardinal num_children; 93 unsigned char type; 94 95 Widget textfield = NULL; 96 XtVaGetValues( 97 spinbox, 98 XmNchildren, &children, 99 XmNnumChildren, &num_children, 100 NULL); 101 102 for(int i = 0;i<num_children;i++) { 103 XtVaGetValues(children[i], XmNspinBoxChildType, &type, NULL); 104 Widget w = children[i]; 105 if(type == XmNUMERIC) { 106 textfield = children[i]; 107 } 108 } 109 110 UiSpinBox *data = malloc(sizeof(UiSpinBox)); 111 data->obj = obj; 112 data->textfield = textfield; 113 data->var = var; 114 data->vartype = vartype; 115 data->obs = NULL; 116 data->onchange = args->onchange; 117 data->onchangedata = args->onchangedata; 118 data->value = 0; 119 data->min = min; 120 data->max = max; 121 data->increment = args->step; 122 data->digits = args->digits; 123 124 UiObserver **obs = NULL; 125 if(var) { 126 double value = 0; 127 switch(vartype) { 128 default: break; 129 case UI_VAR_INTEGER: { 130 UiInteger *i = var->value; 131 i->get = ui_spinbutton_getint; 132 i->set = ui_spinbutton_setint; 133 i->obj = data; 134 value = (double)i->value; 135 obs = &i->observers; 136 break; 137 } 138 case UI_VAR_DOUBLE: { 139 UiDouble *d = var->value; 140 d->get = ui_spinbutton_getdouble; 141 d->set = ui_spinbutton_setdouble; 142 d->obj = data; 143 value = d->value; 144 obs = &d->observers; 145 break; 146 } 147 case UI_VAR_RANGE: { 148 UiRange *r = var->value; 149 r->get = ui_spinbutton_getrangeval; 150 r->set = ui_spinbutton_setrangeval; 151 r->setrange = ui_spinbutton_setrange; 152 r->setextent = ui_spinbutton_setextent; 153 r->obj = data; 154 value = r->value; 155 obs = &r->observers; 156 break; 157 } 158 } 159 ui_spinbox_set_value(data, value); 160 } 161 data->obs = obs; 162 163 XtAddCallback( 164 spinbox, 165 XmNvalueChangedCallback, 166 (XtCallbackProc)ui_spinbox_value_changed, 167 data); 168 169 XtAddCallback( 170 spinbox, 171 XmNdestroyCallback, 172 (XtCallbackProc)ui_destroy_data, 173 data); 174 175 XmTextFieldSetString(textfield, "0"); 176 177 178 return spinbox; 179 } 180 181 void ui_spinbox_set_value(UiSpinBox *spinbox, double value) { 182 if(value < spinbox->min) { 183 value = spinbox->min; 184 } 185 if(value > spinbox->max) { 186 value = spinbox->max; 187 } 188 189 char buf[32]; 190 snprintf(buf, 32, "%.*f", spinbox->digits, spinbox->value); 191 XmTextFieldSetString(spinbox->textfield, buf); 192 spinbox->value = value; 193 } 194 195 void ui_spinbox_value_changed(Widget widget, UiSpinBox *spinbox, XmSpinBoxCallbackStruct *cb) { 196 Boolean update_value = TRUE; 197 double value = spinbox->value; 198 switch(cb->reason) { 199 case XmCR_OK: { 200 update_value = FALSE; 201 break; 202 } 203 case XmCR_SPIN_NEXT: { 204 value += spinbox->increment; 205 break; 206 } 207 case XmCR_SPIN_PRIOR: { 208 value -= spinbox->increment; 209 break; 210 } 211 } 212 213 if(update_value) { 214 ui_spinbox_set_value(spinbox, value); 215 216 UiEvent event; 217 event.obj = spinbox->obj; 218 event.window = event.obj->window; 219 event.document = event.obj->ctx->document; 220 event.eventdata = NULL; 221 event.eventdatatype = 0; 222 event.intval = (int64_t)value; 223 event.set = ui_get_setop(); 224 225 if(spinbox->onchange) { 226 spinbox->onchange(&event, spinbox->onchangedata); 227 } 228 229 UiObserver *obs = *spinbox->obs; 230 ui_notify_evt(*spinbox->obs, &event); 231 } 232 } 233 234 int64_t ui_spinbutton_getint(UiInteger *i) { 235 UiSpinBox *spinbox = i->obj; 236 i->value = (int64_t)spinbox->value; 237 return i->value; 238 } 239 240 void ui_spinbutton_setint(UiInteger *i, int64_t val) { 241 UiSpinBox *spinbox = i->obj; 242 ui_spinbox_set_value(spinbox, (double)val); 243 i->value = spinbox->value; 244 } 245 246 double ui_spinbutton_getdouble(UiDouble *d) { 247 UiSpinBox *spinbox = d->obj; 248 d->value = spinbox->value; 249 return d->value; 250 } 251 252 void ui_spinbutton_setdouble(UiDouble *d, double val) { 253 UiSpinBox *spinbox = d->obj; 254 ui_spinbox_set_value(spinbox, val); 255 d->value = spinbox->value; 256 } 257 258 double ui_spinbutton_getrangeval(UiRange *r) { 259 UiSpinBox *spinbox = r->obj; 260 r->value = spinbox->value; 261 return r->value; 262 } 263 264 void ui_spinbutton_setrangeval(UiRange *r, double val) { 265 UiSpinBox *spinbox = r->obj; 266 ui_spinbox_set_value(spinbox, val); 267 r->value = spinbox->value; 268 } 269 void ui_spinbutton_setrange(UiRange *r, double min, double max) { 270 UiSpinBox *spinbox = r->obj; 271 spinbox->min = min; 272 spinbox->max = max; 273 r->min = min; 274 r->max = max; 275 } 276 277 void ui_spinbutton_setextent(UiRange *r, double extent) { 278 UiSpinBox *spinbox = r->obj; 279 spinbox->increment = extent; 280 r->extent = extent; 281 } 282