add spinbox (Motif)

Fri, 14 Nov 2025 22:02:00 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 14 Nov 2025 22:02:00 +0100
changeset 897
0d488f04078d
parent 896
ae0ad20122cc
child 898
0484fc666c1d

add spinbox (Motif)

application/main.c file | annotate | diff | comparison | revisions
ui/motif/entry.c file | annotate | diff | comparison | revisions
ui/motif/entry.h file | annotate | diff | comparison | revisions
ui/motif/objs.mk file | annotate | diff | comparison | revisions
--- a/application/main.c	Thu Nov 13 21:29:00 2025 +0100
+++ b/application/main.c	Fri Nov 14 22:02:00 2025 +0100
@@ -995,7 +995,7 @@
     */
     
     ui_button(obj, .label = "Next Tab", .onclick = action_next_tab);
-    ui_tabview_w(obj, wdata->tabview, .tabview = UI_TABVIEW_INVISIBLE, .value = wdata->tab, .fill = UI_ON) {
+    ui_tabview_w(obj, wdata->tabview, .value = wdata->tab, .fill = UI_ON) {
         ui_tab(obj, "Tab 1") {
             ui_textarea(obj, .varname = "text", .fill = UI_ON);
         }
@@ -1009,6 +1009,12 @@
         ui_tab(obj, "Tab 3") {
             ui_button(obj, .label = "Test Tab 3", .onclick = action_remove_tab3);
         }
+        
+        ui_tab(obj, "Tab 4") {
+            ui_grid(obj, .margin = 10) {
+                ui_spinbox(obj, .varname = "num1");
+            }
+        }
     }
     
     
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/motif/entry.c	Fri Nov 14 22:02:00 2025 +0100
@@ -0,0 +1,151 @@
+/*
+ * 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->groups);
+    
+    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->onchange = args->onchange;
+    data->onchangedata = args->onchangedata;
+    data->last_value = 0;
+    data->min = min;
+    data->max = max;
+    data->increment = args->step;
+    data->digits = args->digits;
+    
+    XtAddCallback(
+            spinbox,
+            XmNvalueChangedCallback,
+            (XtCallbackProc)ui_spinbox_value_changed,
+            data);
+    
+    XmTextFieldSetString(textfield, "0");
+    
+    
+    return spinbox;
+}
+
+void ui_spinbox_value_changed(Widget widget, UiSpinBox *spinbox, XmSpinBoxCallbackStruct *cb) {
+    char buf[32];
+    switch(cb->reason) {
+        case 62: {
+            spinbox->last_value += spinbox->increment;
+            snprintf(buf, 32, "%.*f", spinbox->digits, spinbox->last_value);
+            XmTextFieldSetString(spinbox->textfield, buf);
+            break;
+        }
+        case 63: {
+            spinbox->last_value -= spinbox->increment;
+            snprintf(buf, 32, "%.*f", spinbox->digits, spinbox->last_value);
+            XmTextFieldSetString(spinbox->textfield, buf);
+            break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/motif/entry.h	Fri Nov 14 22:02:00 2025 +0100
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef ENTRY_H
+#define ENTRY_H
+
+#include "../ui/entry.h"
+#include "container.h"
+#include "toolkit.h"
+
+#include <Xm/SSpinB.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct UiSpinBox {
+    UiObject *obj;
+    Widget textfield;
+    UiVar *var;
+    UiVarType vartype;
+    ui_callback onchange;
+    void* onchangedata;
+    double last_value;
+    double min;
+    double max;
+    double increment;
+    int digits;
+} UiSpinBox;
+    
+void ui_spinbox_value_changed(Widget widget, UiSpinBox *spinbox, XmSpinBoxCallbackStruct *cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ENTRY_H */
+
--- a/ui/motif/objs.mk	Thu Nov 13 21:29:00 2025 +0100
+++ b/ui/motif/objs.mk	Fri Nov 14 22:02:00 2025 +0100
@@ -45,6 +45,7 @@
 MOTIFOBJ += dnd.o
 MOTIFOBJ += image.o
 MOTIFOBJ += Grid.o
+MOTIFOBJ += entry.o
 
 TOOLKITOBJS += $(MOTIFOBJ:%=$(MOTIF_OBJPRE)%)
 TOOLKITSOURCE += $(MOTIFOBJ:%.o=motif/%.c)

mercurial