# HG changeset patch # User Olaf Wintermann # Date 1733333482 -3600 # Node ID 0ebf9d7b23e8304f75a6ec7cf5bd38393e41a224 # Parent a7f18dda6bafc0d33daa25a09ed8d4c75f67dd45 add first code of the new Motif implementation, implement buttons diff -r a7f18dda6baf -r 0ebf9d7b23e8 application/main.c --- a/application/main.c Wed Dec 04 08:57:35 2024 +0100 +++ b/application/main.c Wed Dec 04 18:31:22 2024 +0100 @@ -34,7 +34,7 @@ #include #include -#ifndef UI_COCOA +#if !defined(UI_COCOA) && !defined(UI_MOTIF) typedef struct { UiString *str1; @@ -455,10 +455,22 @@ #endif -#ifdef UI_COCOA +#if defined(UI_COCOA) || defined(UI_MOTIF) + +void action_button(UiEvent *event, void *data) { + printf("action_button\n"); +} void application_startup(UiEvent *event, void *data) { - + UiObject *obj = ui_window("Test", NULL); + ui_button(obj, .label = "Test Button", .onclick = action_button); + ui_togglebutton(obj, .label = "Togglebutton"); + ui_checkbox(obj, .label = "Checkbox", .enable_group = 123); + ui_checkbox(obj, .label = "Checkbox Disabled", .groups = UI_GROUPS(123)); + ui_radiobutton(obj, .label = "Radio 1", .varname = "radio"); + ui_radiobutton(obj, .label = "Radio 2", .varname = "radio"); + + ui_show(obj); } int main(int argc, char** argv) { diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/common/context.c --- a/ui/common/context.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/common/context.c Wed Dec 04 18:31:22 2024 +0100 @@ -187,6 +187,13 @@ } UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) { + if(ctx->vars_unbound) { + UiVar *unbound = cxMapGet(ctx->vars_unbound, name); + if(unbound) { + return unbound; + } + } + UiVar *var = uic_get_var(ctx, name); if(var) { if(var->type == type) { diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/common/object.c --- a/ui/common/object.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/common/object.c Wed Dec 04 18:31:22 2024 +0100 @@ -64,16 +64,17 @@ obj->ref++; } -void ui_object_unref(UiObject *obj) { +int ui_object_unref(UiObject *obj) { // it is possible to have 0 references, in case // a window was created but ui_show was never called if(obj->ref == 0 || --obj->ref == 0) { if(obj->destroy) { obj->destroy(obj); - } else { - uic_object_destroy(obj); } + uic_object_destroy(obj); + return 0; } + return 1; } void uic_object_destroy(UiObject *obj) { diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/Grid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/motif/Grid.c Wed Dec 04 18:31:22 2024 +0100 @@ -0,0 +1,487 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 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. + */ + +/* + * + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "Grid.h" + +#include + + + +static XtActionsRec actionslist[] = { + {"getfocus",grid_getfocus}, + {"loosefocus",grid_loosefocus}, + {"NULL",NULL} +}; + +//static char defaultTranslations[] = ": mousedown()\n"; +static char defaultTranslations[] = "\ +: getfocus()\n\ +: loosefocus()\n"; + + +///* +static XtResource constraints[] = +{ + { + gridColumn, + gridColumn, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.x), + XmRImmediate, + (XtPointer) 0 + }, + { + gridRow, + gridRow, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.y), + XmRImmediate, + (XtPointer) 0 + }, + { + gridColspan, + gridColspan, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.colspan), + XmRImmediate, + (XtPointer) 0 + }, + { + gridRowspan, + gridRowspan, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.rowspan), + XmRImmediate, + (XtPointer) 0 + }, + { + gridMarginLeft, + gridMarginLeft, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.margin_left), + XmRImmediate, + (XtPointer) 0 + }, + { + gridMarginRight, + gridMarginRight, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.margin_right), + XmRImmediate, + (XtPointer) 0 + }, + { + gridMarginTop, + gridMarginTop, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.margin_top), + XmRImmediate, + (XtPointer) 0 + }, + { + gridMarginBottom, + gridMarginBottom, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.margin_bottom), + XmRImmediate, + (XtPointer) 0 + }, + { + gridHExpand, + gridHExpand, + XmRBoolean, + sizeof (Boolean), + XtOffsetOf( GridConstraintRec, + grid.hexpand), + XmRImmediate, + (XtPointer) 0 + }, + { + gridVExpand, + gridVExpand, + XmRBoolean, + sizeof (Boolean), + XtOffsetOf( GridConstraintRec, + grid.vexpand), + XmRImmediate, + (XtPointer) 0 + }, + { + gridHFill, + gridHFill, + XmRBoolean, + sizeof (Boolean), + XtOffsetOf( GridConstraintRec, + grid.hfill), + XmRImmediate, + (XtPointer) 0 + }, + { + gridVFill, + gridVFill, + XmRBoolean, + sizeof (Boolean), + XtOffsetOf( GridConstraintRec, + grid.vfill), + XmRImmediate, + (XtPointer) 0 + } + +}; +//*/ +//static XtResource constraints[] = {}; + +GridClassRec gridClassRec = { + // Core Class + { + //(WidgetClass)&constraintClassRec, // superclass + (WidgetClass)&xmManagerClassRec, + "Grid", // class_name + sizeof(GridRec), // widget_size + grid_class_initialize, // class_initialize + NULL, // class_part_initialize + FALSE, // class_inited + (XtInitProc)grid_initialize, // initialize + NULL, // initialize_hook + grid_realize, // realize + actionslist, // actions + XtNumber(actionslist), // num_actions + NULL, // resources + 0, // num_resources + NULLQUARK, // xrm_class + True, // compress_motion + True, // compress_exposure + True, // compress_enterleave + False, // visible_interest + (XtWidgetProc)grid_destroy, // destroy + (XtWidgetProc)grid_resize, // resize + (XtExposeProc)grid_expose, // expose + grid_set_values, // set_values + NULL, // set_values_hook + XtInheritSetValuesAlmost, // set_values_almost + NULL, // get_values_hook + (XtAcceptFocusProc)grid_acceptfocus, // accept_focus + XtVersion, // version + NULL, // callback_offsets + //NULL, // tm_table + defaultTranslations, + XtInheritQueryGeometry, // query_geometry + NULL, // display_accelerator + NULL, // extension + }, + // Composite Class + { + GridGeometryManager, /* geometry_manager */ + GridChangeManaged, /* change_managed */ + XtInheritInsertChild, /* insert_child */ + XtInheritDeleteChild, /* delete_child */ + NULL, /* extension */ + }, + // Constraint Class + { + constraints, /* resources */ + XtNumber(constraints), /* num_resources */ + sizeof(GridConstraintRec), /* constraint_size */ + grid_constraint_init, /* initialize */ + NULL, /* destroy */ + ConstraintSetValues, /* set_values */ + NULL, /* extension */ + }, + // XmManager Class + ///* + { + NULL, + NULL, + 0, + NULL, + 0, + NULL, + NULL + }, + //*/ + // MyWidget Class + { + 0 + } +}; + +WidgetClass gridClass = (WidgetClass)&gridClassRec; + + +void grid_class_initialize(Widget request, Widget new, ArgList args, Cardinal *num_args) { + +} +void grid_initialize(Widget request, Widget new, ArgList args, Cardinal num_args) { + MyWidget mn = (MyWidget)new; + + mn->mywidget.max_col = 0; + mn->mywidget.max_row = 0; + +} +void grid_realize(MyWidget w,XtValueMask *valueMask,XSetWindowAttributes *attributes) { + XtMakeResizeRequest((Widget)w, 400, 400, NULL, NULL); + (coreClassRec.core_class.realize)((Widget)w, valueMask, attributes); + grid_place_children(w); +} + + +void grid_destroy(MyWidget widget) { + +} +void grid_resize(MyWidget widget) { + grid_place_children(widget); +} + +void grid_expose(MyWidget widget, XEvent *event, Region region) { + +} + + +Boolean grid_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) { + return False; +} + +Boolean grid_acceptfocus(Widget w, Time *t) { + +} + +void grid_getfocus(MyWidget myw, XEvent *event, String *params, Cardinal *nparam) { + +} + +void grid_loosefocus(MyWidget myw, XEvent *event, String *params, Cardinal *nparam) { + +} + + + +XtGeometryResult GridGeometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply) { + GridRec *grid = (GridRec*)XtParent(widget); + GridConstraintRec *constraints = widget->core.constraints; + //XtVaSetValues(widget, XmNwidth, request->width, XmNheight, request->height, NULL); + if((request->request_mode & CWWidth) == CWWidth) { + widget->core.width = request->width; + constraints->grid.pref_width = request->width; + } + if((request->request_mode & CWHeight) == CWHeight) { + widget->core.height = request->height; + constraints->grid.pref_height = request->height; + } + grid_place_children((MyWidget)XtParent(widget)); + return XtGeometryYes; +} + +void GridChangeManaged(Widget widget) { + +} + +Boolean ConstraintSetValues(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) { + GridConstraintRec *constraints = neww->core.constraints; + MyWidget grid = (MyWidget)XtParent(neww); + if(constraints->grid.x > grid->mywidget.max_col) { + grid->mywidget.max_col = constraints->grid.x; + } + if(constraints->grid.y > grid->mywidget.max_row) { + grid->mywidget.max_row = constraints->grid.y; + } +} + + +void grid_constraint_init( + Widget request, + Widget neww, + ArgList args, + Cardinal* num_args +) +{ + GridConstraintRec *constraints = neww->core.constraints; + + MyWidget grid = (MyWidget)XtParent(neww); + if(constraints->grid.x > grid->mywidget.max_col) { + grid->mywidget.max_col = constraints->grid.x; + } + if(constraints->grid.y > grid->mywidget.max_row) { + grid->mywidget.max_row = constraints->grid.y; + } + constraints->grid.pref_width = neww->core.width; + constraints->grid.pref_height = neww->core.height; +} + +void grid_place_children(MyWidget w) { + int ncols = w->mywidget.max_col+1; + int nrows = w->mywidget.max_row+1; + GridDef *cols = calloc(ncols, sizeof(GridDef)); + GridDef *rows = calloc(nrows, sizeof(GridDef)); + int num_cols_expanding = 0; + int num_rows_expanding = 0; + int req_width = 0; + int req_height = 0; + + for(int i=0;icomposite.num_children;i++) { + Widget child = w->composite.children[i]; + GridConstraintRec *constraints = child->core.constraints; + if(constraints->grid.x < ncols) { + if(constraints->grid.hexpand) { + cols[constraints->grid.x].expand = TRUE; + } + if(constraints->grid.pref_width > cols[constraints->grid.x].size) { + cols[constraints->grid.x].size = constraints->grid.pref_width; + } + } else { + fprintf(stderr, "Error: x >= ncols\n"); + } + if(constraints->grid.y < nrows) { + if(constraints->grid.vexpand) { + rows[constraints->grid.y].expand = TRUE; + } + if(constraints->grid.pref_height > rows[constraints->grid.y].size) { + rows[constraints->grid.y].size = constraints->grid.pref_height; + } + } else { + fprintf(stderr, "Error: y >= nrows\n"); + } + } + + for(int i=0;icore.width - req_width; + int hexpand2 = 0; + if(width_diff > 0 && num_cols_expanding > 0) { + hexpand = width_diff / num_cols_expanding; + hexpand2 = width_diff-hexpand*num_cols_expanding; + } + int x = 0; + for(int i=0;icore.height - req_height; + int vexpand2 = 0; + if(height_diff > 0 && num_rows_expanding > 0) { + vexpand = height_diff / num_rows_expanding; + vexpand2 = height_diff-vexpand*num_rows_expanding; + } + int y = 0; + for(int i=0;icomposite.num_children;i++) { + Widget child = w->composite.children[i]; + GridConstraintRec *constraints = child->core.constraints; + GridDef c = cols[constraints->grid.x]; + GridDef r = rows[constraints->grid.y]; + int x = c.pos; + int y = r.pos; + int width = constraints->grid.pref_width; + int height = constraints->grid.pref_height; + if(constraints->grid.hfill) { + if(constraints->grid.colspan > 1) { + Dimension cwidth = 0; + for(int j=0;jgrid.colspan;j++) { + if(constraints->grid.x+j < ncols) { + cwidth += cols[constraints->grid.x+j].size; + } + } + width = cwidth; + } else { + width = c.size; + } + } + if(constraints->grid.vfill) { + if(constraints->grid.rowspan > 1) { + Dimension cheight = 0; + for(int j=0;jgrid.rowspan;j++) { + if(constraints->grid.y+j < nrows) { + cheight += rows[constraints->grid.y+j].size; + } + } + height = cheight; + } else { + height = r.size; + } + } + + XtConfigureWidget(child, x, y, width, height, child->core.border_width); + //printf("child %d %d - %d %d\n", (int)child->core.x, (int)child->core.y, (int)child->core.width, (int)child->core.height); + } + + free(cols); + free(rows); +} + diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/Grid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/motif/Grid.h Wed Dec 04 18:31:22 2024 +0100 @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 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 GRID_H +#define GRID_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define gridColumn "gridColumn" +#define gridRow "gridRow" +#define gridColspan "gridColspan" +#define gridRowspan "gridRowspan" +#define gridHExpand "gridHExpand" +#define gridVExpand "gridVExpand" +#define gridHFill "gridHFill" +#define gridVFill "gridVFill" +#define gridMarginLeft "gridMarginLeft" +#define gridMarginRight "gridMarginRight" +#define gridMarginTop "gridMarginTop" +#define gridMarginBottom "gridMarginBottom" + + +typedef struct GridDef { + Dimension size; + Dimension pos; + Boolean expand; +} GridDef; + +typedef struct GridClassPart { + int test; +} GridClassPart; + +typedef struct GridClassRec { + CoreClassPart core_class; + CompositeClassPart composite_class; + ConstraintClassPart constraint_class; + XmManagerClassPart manager_class; + GridClassPart mywidgetclass; +} GridClassRec; + + +typedef struct GridPart { + int margin_left; + int margin_right; + int margin_top; + int margin_bottom; + int max_col; + int max_row; +} GridPart; + +typedef struct GridRec { + CorePart core; + CompositePart composite; + ConstraintPart constraint; + XmManagerPart manager; + GridPart mywidget; +} GridRec; + +typedef struct GridContraintPart { + Dimension x; + Dimension y; + Dimension margin_left; + Dimension margin_right; + Dimension margin_top; + Dimension margin_bottom; + Boolean hexpand; + Boolean vexpand; + Boolean hfill; + Boolean vfill; + Dimension colspan; + Dimension rowspan; + Dimension pref_width; + Dimension pref_height; +} GridContraintPart; + +typedef struct GridConstraintRec { + XmManagerConstraintPart manager; + GridContraintPart grid; +} GridConstraintRec; + +typedef GridRec* MyWidget; + +extern WidgetClass gridClass; + +void grid_class_initialize(); +void grid_initialize(); +void grid_realize(); +void grid_destroy(); +void grid_resize(); +void grid_expose(); +Boolean grid_set_values(); +Boolean grid_acceptfocus(Widget , Time*); + +void grid_place_children(MyWidget w); + +void grid_getfocus(); +void grid_loosefocus(); + +void grid_constraint_init( + Widget request, + Widget neww, + ArgList args, + Cardinal* num_args +); + +XtGeometryResult GridGeometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply); +void GridChangeManaged(Widget widget); +Boolean ConstraintSetValues(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args); + + +#ifdef __cplusplus +} +#endif + +#endif /* GRID_H */ + diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/button.c --- a/ui/motif/button.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/button.c Wed Dec 04 18:31:22 2024 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -38,69 +38,54 @@ #include #include +#include -UIWIDGET ui_button(UiObject *obj, char *label, ui_callback f, void *data) { - UiContainer *ct = uic_get_current_container(obj); - XmString str = XmStringCreateLocalized(label); + +UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) { + Arg xargs[16]; + int n = 0; - int n = 0; - Arg args[16]; + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); - XtSetArg(args[n], XmNlabelString, str); - n++; + Widget parent = ctn->prepare(ctn, xargs, &n); - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget button = XmCreatePushButton(parent, "button", args, n); - ct->add(ct, button); + XmString label = NULL; + if(args.label) { + label = XmStringCreateLocalized((char*)args.label); + XtSetArg(xargs[n], XmNlabelString, label); n++; + } - if(f) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = data; - event->callback = f; - event->value = 0; + char *name = args.name ? (char*)args.name : "button"; + Widget button = XmCreatePushButton(parent, name, xargs, n); + XtManageChild(button); + ctn->add(ctn, button); + + ui_set_widget_groups(obj->ctx, button, args.groups); + + if(args.onclick) { + UiEventData *eventdata = malloc(sizeof(UiEventData)); + eventdata->callback = args.onclick; + eventdata->userdata = args.onclickdata; + eventdata->obj = obj; + eventdata->value = 0; XtAddCallback( button, XmNactivateCallback, (XtCallbackProc)ui_push_button_callback, - event); + eventdata); + XtAddCallback( + button, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + eventdata); } - XtManageChild(button); + XmStringFree(label); return button; } -// wrapper -int64_t ui_toggle_button_get(UiInteger *i) { - int state = 0; - XtVaGetValues(i->obj, XmNset, &state, NULL); - i->value = state; - return state; -} - -void ui_toggle_button_set(UiInteger *i, int64_t value) { - Arg arg; - XtSetArg(arg, XmNset, value); - XtSetValues(i->obj, &arg, 1); - i->value = value; -} - -void ui_toggle_button_callback( - Widget widget, - UiEventData *event, - XmToggleButtonCallbackStruct *tb) -{ - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - // TODO: e.document - e.intval = tb->set; - event->callback(&e, event->userdata); -} - void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d) { UiEvent e; e.obj = event->obj; @@ -110,105 +95,295 @@ event->callback(&e, event->userdata); } +UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) { + Arg xargs[16]; + int n = 0; + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + XtSetArg(xargs[n], XmNfillOnSelect, True); n++; + XtSetArg(xargs[n], XmNindicatorOn, False); n++; + + XmString label = NULL; + if(args.label) { + label = XmStringCreateLocalized((char*)args.label); + XtSetArg(xargs[n], XmNlabelString, label); n++; + } + + char *name = args.name ? (char*)args.name : "togglebutton"; + Widget button = XmCreateToggleButton(parent, name, xargs, n); + XtManageChild(button); + ctn->add(ctn, button); + + ui_set_widget_groups(obj->ctx, button, args.groups); + + ui_bind_togglebutton(obj, button, args.varname, args.value, args.onchange, args.onchangedata, args.enable_group); + + XmStringFree(label); + return button; +} -static void radio_callback( - Widget widget, - RadioEventData *event, - XmToggleButtonCallbackStruct *tb) -{ - if(tb->set) { - RadioButtonGroup *group = event->group; - if(group->current) { - Arg arg; - XtSetArg(arg, XmNset, FALSE); - XtSetValues(group->current, &arg, 1); +UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) { + Arg xargs[16]; + int n = 0; + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + + XmString label = NULL; + if(args.label) { + label = XmStringCreateLocalized((char*)args.label); + XtSetArg(xargs[n], XmNlabelString, label); n++; + } + + char *name = args.name ? (char*)args.name : "button"; + Widget button = XmCreateToggleButton(parent, name, xargs, n); + XtManageChild(button); + ctn->add(ctn, button); + + ui_set_widget_groups(obj->ctx, button, args.groups); + + ui_bind_togglebutton(obj, button, args.varname, args.value, args.onchange, args.onchangedata, args.enable_group); + + XmStringFree(label); + return button; +} + +UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) { + return ui_checkbox_create(obj, args); +} + +static void togglebutton_changed(Widget w, UiVarEventData *event, XmToggleButtonCallbackStruct *tb) { + if(event->value > 0) { + // button in configured to enable/disable states + if(tb->set) { + ui_set_group(event->obj->ctx, event->value); + } else { + ui_unset_group(event->obj->ctx, event->value); } - group->current = widget; + } + + UiEvent e; + e.obj = event->obj; + e.window = e.obj->window; + e.document = e.obj->ctx->document; + e.eventdata = NULL; + e.intval = XmToggleButtonGetState(w); + + if(event->callback) { + event->callback(&e, event->userdata); + } + + if(event->var && event->var->value) { + UiInteger *v = event->var->value; + v->value = e.intval; + ui_notify_evt(v->observers, &e); } } -UIWIDGET ui_radiobutton(UiObject *obj, char *label, UiInteger *rgroup) { - UiContainer *ct = uic_get_current_container(obj); - XmString str = XmStringCreateLocalized(label); - - int n = 0; - Arg args[16]; - - XtSetArg(args[n], XmNlabelString, str); - n++; - XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY_ROUND); - n++; - - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget button = XmCreateToggleButton(parent, "radiobutton", args, n); - ct->add(ct, button); - - if(rgroup) { - RadioButtonGroup *group; - if(rgroup->obj) { - group = rgroup->obj; - if(!group->buttons) { - group->buttons = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 8); - } - cxListAdd(group->buttons, button); - group->ref++; - } else { - group = malloc(sizeof(RadioButtonGroup)); - group->buttons = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 8); - cxListAdd(group->buttons, button); - group->current = button; - // this is the first button in the radiobutton group - // so we should enable it - Arg arg; - XtSetArg(arg, XmNset, TRUE); - XtSetValues(button, &arg, 1); - rgroup->obj = group; - - group->current = button; +void ui_bind_togglebutton( + UiObject *obj, + Widget widget, + const char *varname, + UiInteger *value, + ui_callback onchange, + void *onchangedata, + int enable_state) +{ + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER); + if(var) { + value = (UiInteger*)var->value; + value->obj = widget; + value->get = ui_togglebutton_get; + value->set = ui_togglebutton_set; + + if(value->value) { + XmToggleButtonSetState(widget, True, False); } - - RadioEventData *event = malloc(sizeof(RadioEventData)); - event->obj = obj; - event->callback = NULL; - event->userdata = NULL; - event->group = group; - XtAddCallback( - button, - XmNvalueChangedCallback, - (XtCallbackProc)radio_callback, - event); - - rgroup->get = ui_radiobutton_get; - rgroup->set = ui_radiobutton_set; } - XtManageChild(button); - return button; + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + event->obj = obj; + event->callback = onchange; + event->userdata = onchangedata; + event->var = var; + event->observers = NULL; + event->value = enable_state; + XtAddCallback( + widget, + XmNvalueChangedCallback, + (XtCallbackProc)togglebutton_changed, + event); + XtAddCallback( + widget, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + event); +} + +int64_t ui_togglebutton_get(UiInteger *i) { + Widget togglebutton = i->obj; + Boolean state = XmToggleButtonGetState(togglebutton); + i->value = state; + return state; +} + +void ui_togglebutton_set(UiInteger *i, int64_t value) { + Widget togglebutton = i->obj; + i->value = value; + XmToggleButtonSetState(togglebutton, (Boolean)value, False); +} + +static void destroy_list(Widget w, CxList *list, XtPointer d) { + cxListDestroy(list); } -int64_t ui_radiobutton_get(UiInteger *value) { - RadioButtonGroup *group = value->obj; +static void radiobutton_changed(Widget w, UiVarEventData *event, XmToggleButtonCallbackStruct *tb) { + if(event->value > 0) { + // button in configured to enable/disable states + if(tb->set) { + ui_set_group(event->obj->ctx, event->value); + } else { + ui_unset_group(event->obj->ctx, event->value); + } + } + + if(!tb->set) { + return; // only handle set-events + } - int i = cxListFind(group->buttons, group->current); - if (i >= 0) { - value->value = i; - return i; - } else { - return 0; + UiInteger *value = NULL; + int64_t v = 0; + if(event->var) { + value = event->var->value; + // find widget index and update all radiobuttons + // the UiInteger value must always be up-to-date + CxList *list = value->obj; + CxIterator i = cxListIterator(list); + cx_foreach(Widget, button, i) { + Boolean state = False; + if(button == w) { + value->value = i.index+1; // update value + state = True; + } + XmToggleButtonSetState(button, state, False); + } + v = value->value; + } + + UiEvent e; + e.obj = event->obj; + e.window = e.obj->window; + e.document = e.obj->ctx->document; + e.eventdata = value; + e.intval = v; + + if(event->callback) { + event->callback(&e, event->userdata); + } + + if(value) { + ui_notify_evt(value->observers, &e); } } -void ui_radiobutton_set(UiInteger *value, int64_t i) { - RadioButtonGroup *group = value->obj; - Arg arg; +UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs args) { + Arg xargs[16]; + int n = 0; + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + XtSetArg(xargs[n], XmNindicatorType, XmONE_OF_MANY_ROUND); n++; + XmString label = NULL; + if(args.label) { + label = XmStringCreateLocalized((char*)args.label); + XtSetArg(xargs[n], XmNlabelString, label); n++; + } + + char *name = args.name ? (char*)args.name : "button"; + Widget button = XmCreateToggleButton(parent, name, xargs, n); + XtManageChild(button); + ctn->add(ctn, button); + + ui_set_widget_groups(obj->ctx, button, args.groups); - XtSetArg(arg, XmNset, FALSE); - XtSetValues(group->current, &arg, 1); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER); + if(var) { + UiInteger *value = var->value; + CxList *rb = value->obj; + if(!rb) { + // first button in the radiobutton group + // create a list for all buttons and use the list as value obj + rb = cxArrayListCreateSimple(CX_STORE_POINTERS, 4); + value->obj = rb; + value->get = ui_radiobutton_get; + value->set = ui_radiobutton_set; + + // the first radio button is also responsible for cleanup + XtAddCallback( + button, + XmNdestroyCallback, + (XtCallbackProc)destroy_list, + rb); + } + cxListAdd(rb, button); + + // set the radiobutton state, if the value is already set + if(cxListSize(rb) == value->value) { + XmToggleButtonSetState(button, True, False); + } + } - Widget button = cxListAt(group->buttons, i); - if(button) { - XtSetArg(arg, XmNset, TRUE); - XtSetValues(button, &arg, 1); - group->current = button; + // the radio button needs to handle change events to update all + // other buttons in the radio button group + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + event->obj = obj; + event->callback = args.onchange; + event->userdata = args.onchangedata; + event->observers = NULL; + event->var = var; + event->value = args.enable_group; + XtAddCallback( + button, + XmNvalueChangedCallback, + (XtCallbackProc)radiobutton_changed, + event); + XtAddCallback( + button, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + event); + + XmStringFree(label); + return button; + + +} + +int64_t ui_radiobutton_get(UiInteger *i) { + // the UiInteger should be updated automatically by change events + return i->value; +} + +void ui_radiobutton_set(UiInteger *i, int64_t value) { + CxList *list = i->obj; + if(i->value > 0) { + Widget current = cxListAt(list, i->value-1); + if(current) { + XmToggleButtonSetState(current, False, False); + } + } + if(value > 0 && value <= cxListSize(list)) { + Widget button = cxListAt(list, value-1); + if(button) { + XmToggleButtonSetState(button, True, False); + i->value = value; + } } } diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/button.h --- a/ui/motif/button.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/button.h Wed Dec 04 18:31:22 2024 +0100 @@ -36,30 +36,22 @@ extern "C" { #endif -typedef struct { - CxList *buttons; - Widget current; - int ref; -} RadioButtonGroup; - -typedef struct { - UiObject *obj; - ui_callback callback; - void *userdata; - RadioButtonGroup *group; -} RadioEventData; - -// wrapper -int64_t ui_toggle_button_get(UiInteger *i); -void ui_toggle_button_set(UiInteger *i, int64_t value); -void ui_toggle_button_callback( - Widget widget, - UiEventData *data, - XmToggleButtonCallbackStruct *e); void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d); -int64_t ui_radiobutton_get(UiInteger *value); -void ui_radiobutton_set(UiInteger *value, int64_t i); +void ui_bind_togglebutton( + UiObject *obj, + Widget widget, + const char *varname, + UiInteger *value, + ui_callback onchange, + void *onchangedata, + int enable_state); + +int64_t ui_togglebutton_get(UiInteger *i); +void ui_togglebutton_set(UiInteger *i, int64_t value); + +int64_t ui_radiobutton_get(UiInteger *i); +void ui_radiobutton_set(UiInteger *i, int64_t value); #ifdef __cplusplus } diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/container.c --- a/ui/motif/container.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/container.c Wed Dec 04 18:31:22 2024 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -34,781 +34,51 @@ #include "../common/context.h" #include "../common/object.h" -#include -#include -#include - -#define UI_GRID_MAX_COLUMNS 512 - -static UiBool ui_lb2bool(UiLayoutBool b) { - return b == UI_LAYOUT_TRUE ? TRUE : FALSE; -} - -static UiLayoutBool ui_bool2lb(UiBool b) { - return b ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE; -} - - -UiContainer* ui_frame_container(UiObject *obj, Widget frame) { - UiContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiContainer)); - ct->widget = frame; - ct->prepare = ui_frame_container_prepare; - ct->add = ui_frame_container_add; - return ct; -} - -Widget ui_frame_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { - return ct->widget; -} - -void ui_frame_container_add(UiContainer *ct, Widget widget) { - ui_reset_layout(ct->layout); - ct->current = widget; -} - - -UiContainer* ui_box_container(UiObject *obj, Widget box, int margin, int spacing, UiBoxOrientation orientation) { - UiBoxContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiBoxContainer)); - ct->container.widget = box; - ct->container.prepare = ui_box_container_prepare; - ct->container.add = ui_box_container_add; - ct->orientation = orientation; - ct->margin = margin; - ct->spacing = spacing; - return (UiContainer*)ct; -} +#include "Grid.h" -Widget ui_box_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { - UiBoxContainer *bc = (UiBoxContainer*)ct; - if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { - fill = ui_lb2bool(ct->layout.fill); - } - - if(bc->has_fill && fill) { - fprintf(stderr, "UiError: container has 2 filled widgets"); - fill = FALSE; - } - if(fill) { - bc->has_fill = TRUE; - } - - int a = *n; - // determine fixed and dynamic attachments - void *f1; - void *f2; - void *d1; - void *d2; - void *w1; - void *w2; - if(bc->orientation == UI_BOX_VERTICAL) { - f1 = XmNleftAttachment; - f2 = XmNrightAttachment; - d1 = XmNtopAttachment; - d2 = XmNbottomAttachment; - w1 = XmNtopWidget; - w2 = XmNbottomWidget; - - // margin/spacing - XtSetArg(args[a], XmNleftOffset, bc->margin); a++; - XtSetArg(args[a], XmNrightOffset, bc->margin); a++; - - XtSetArg(args[a], XmNtopOffset, bc->prev_widget ? bc->spacing : bc->margin); a++; - } else { - f1 = XmNtopAttachment; - f2 = XmNbottomAttachment; - d1 = XmNleftAttachment; - d2 = XmNrightAttachment; - w1 = XmNleftWidget; - w2 = XmNrightWidget; - - // margin/spacing - XtSetArg(args[a], XmNtopOffset, bc->margin); a++; - XtSetArg(args[a], XmNbottomOffset, bc->margin); a++; - - XtSetArg(args[a], XmNleftOffset, bc->prev_widget ? bc->spacing : bc->margin); a++; - } - XtSetArg(args[a], f1, XmATTACH_FORM); a++; - XtSetArg(args[a], f2, XmATTACH_FORM); a++; - - if(fill) { - XtSetArg(args[a], d2, XmATTACH_FORM); a++; - } - if(bc->prev_widget) { - XtSetArg(args[a], d1, XmATTACH_WIDGET); a++; - XtSetArg(args[a], w1, bc->prev_widget); a++; - } else { - XtSetArg(args[a], d1, XmATTACH_FORM); a++; - } - - *n = a; - return ct->widget; -} - -void ui_box_container_add(UiContainer *ct, Widget widget) { - UiBoxContainer *bc = (UiBoxContainer*)ct; - // determine dynamic attachments - void *d1; - void *d2; - void *w1; - void *w2; - if(bc->orientation == UI_BOX_VERTICAL) { - d1 = XmNtopAttachment; - d2 = XmNbottomAttachment; - w1 = XmNtopWidget; - w2 = XmNbottomWidget; - - } else { - d1 = XmNleftAttachment; - d2 = XmNrightAttachment; - w1 = XmNleftWidget; - w2 = XmNrightWidget; - } - - if(bc->prev_widget) { - int v = 0; - XtVaGetValues(bc->prev_widget, d2, &v, NULL); - if(v == XmATTACH_FORM) { - XtVaSetValues( - bc->prev_widget, - d2, - XmATTACH_WIDGET, - w2, - widget, - NULL); - XtVaSetValues( - widget, - d1, - XmATTACH_NONE, - d2, - XmATTACH_FORM, - NULL); - } - } - bc->prev_widget = widget; - - ui_reset_layout(ct->layout); - ct->current = widget; -} - -UiContainer* ui_grid_container(UiObject *obj, Widget form, int columnspacing, int rowspacing) { - UiGridContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiGridContainer)); - ct->container.widget = form; - ct->container.prepare = ui_grid_container_prepare; - ct->container.add = ui_grid_container_add; - ct->columnspacing = columnspacing; - ct->rowspacing = rowspacing; - ct->lines = cxLinkedListCreateSimple(CX_STORE_POINTERS); - return (UiContainer*)ct; -} - -void ui_grid_newline(UiGridContainer *grid) { - if(grid->current) { - grid->current = NULL; - } - grid->container.layout.newline = FALSE; -} - -Widget ui_grid_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { - UiGridContainer *grid = (UiGridContainer*)ct; - if(ct->layout.newline) { - ui_grid_newline(grid); - } - return ct->widget; +UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation) { + UiBoxContainer *ctn = ui_malloc(obj->ctx, sizeof(UiBoxContainer)); + memset(ctn, 0, sizeof(UiBoxContainer)); + ctn->container.prepare = orientation == UI_BOX_VERTICAL ? ui_vbox_prepare : ui_hbox_prepare; + ctn->container.add = ui_box_container_add; + ctn->container.widget = grid; + ctn->n = 0; + return (UiContainerX*)ctn; } -void ui_grid_container_add(UiContainer *ct, Widget widget) { - UiGridContainer *grid = (UiGridContainer*)ct; - - if(grid->current) { - cxListAdd(grid->current, widget); - } else { - grid->current = cxLinkedListCreateSimple(CX_STORE_POINTERS); - cxListAdd(grid->current, widget); - cxListAdd(grid->lines, grid->current); - } - - ui_reset_layout(ct->layout); - ct->current = widget; -} - -static void ui_grid_resize(Widget widget, XtPointer udata, XtPointer cdata) { - UiGridContainer *grid = udata; - - CxList *rowdim = cxArrayListCreateSimple(sizeof(int), grid->lines->size); - int coldim[UI_GRID_MAX_COLUMNS]; - memset(coldim, 0, UI_GRID_MAX_COLUMNS*sizeof(int)); - int numcol = 0; - - // get the minimum size of the columns and rows - int sumw = 0; - int sumh = 0; - CxIterator lineIterator = cxListIterator(grid->lines); - cx_foreach(CxList *, row, lineIterator) { - int rheight = 0; - int i=0; - int sum_width = 0; - CxIterator colIterator = cxListIterator(row); - cx_foreach(Widget, w, colIterator) { - int widget_width = 0; - int widget_height = 0; - XtVaGetValues( - w, - XmNwidth, - &widget_width, - XmNheight, - &widget_height, - NULL); - - // get the maximum height in this row - if(widget_height > rheight) { - rheight = widget_height; - } - - // get the maximum width in this column - if(widget_width > coldim[i]) { - coldim[i] = widget_width; - } - sum_width += widget_width; - if(sum_width > sumw) { - sumw = sum_width; - } - - i++; - if(i > numcol) { - numcol = i; - } - } - cxListAdd(rowdim, &rheight); - sumh += rheight; - } - - // check container size - int gwidth = 0; - int gheight = 0; - XtVaGetValues(widget, XmNwidth, &gwidth, XmNheight, &gheight, NULL); - if(gwidth < sumw || gheight < sumh) { - XtVaSetValues(widget, XmNwidth, sumw, XmNheight, sumh, NULL); - cxListDestroy(rowdim); - return; - } - - - // adjust the positions of all children - int y = 0; - lineIterator = cxListIterator(grid->lines); - cx_foreach(CxList *, row, lineIterator) { - int x = 0; - int i=0; - int *rowheight = cxListAt(rowdim, lineIterator.index); - CxIterator colIterator = cxListIterator(row); - cx_foreach(Widget, w, colIterator) { - XtVaSetValues( - w, - XmNx, x, - XmNy, y, - XmNwidth, coldim[i], - XmNheight, *rowheight, - NULL); - - x += coldim[i]; - i++; - } - y += *rowheight; - } - - cxListDestroy(rowdim); -} - -UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow) { - UiContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiContainer)); - ct->widget = scrolledwindow; - ct->prepare = ui_scrolledwindow_container_prepare; - ct->add = ui_scrolledwindow_container_add; - return ct; -} - -Widget ui_scrolledwindow_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { - return ct->widget; -} - -void ui_scrolledwindow_container_add(UiContainer *ct, Widget widget) { - ui_reset_layout(ct->layout); - ct->current = widget; -} - - -UiContainer* ui_tabview_container(UiObject *obj, Widget frame) { - UiTabViewContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiTabViewContainer)); - ct->context = obj->ctx; - ct->container.widget = frame; - ct->container.prepare = ui_tabview_container_prepare; - ct->container.add = ui_tabview_container_add; - ct->tabs = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 16); - return (UiContainer*)ct; -} - -Widget ui_tabview_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { +static Widget ui_box_container_prepare(UiBoxContainer *box, Arg *args, int *n) { int a = *n; - XtSetArg(args[a], XmNleftAttachment, XmATTACH_FORM); a++; - XtSetArg(args[a], XmNrightAttachment, XmATTACH_FORM); a++; - XtSetArg(args[a], XmNtopAttachment, XmATTACH_FORM); a++; - XtSetArg(args[a], XmNbottomAttachment, XmATTACH_FORM); a++; - *n = a; - return ct->widget; -} - -void ui_tabview_container_add(UiContainer *ct, Widget widget) { - UiTabViewContainer *tabview = (UiTabViewContainer*)ct; - - if(tabview->current) { - XtUnmanageChild(tabview->current); - } - - tabview->current = widget; - cxListAdd(tabview->tabs, widget); - - ui_select_tab(ct->widget, 0); - ui_reset_layout(ct->layout); - ct->current = widget; -} - -UIWIDGET ui_box(UiObject *obj, int margin, int spacing, UiBoxOrientation orientation) { - UiContainer *ct = uic_get_current_container(obj); - - Arg args[16]; - int n = 0; - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget form = XmCreateForm(parent, "vbox", args, n); - ct->add(ct, form); - XtManageChild(form); - - UiObject *newobj = uic_object_new(obj, form); - newobj->container = ui_box_container(obj, form, margin, spacing, orientation); - uic_obj_add(obj, newobj); - - return form; -} - -UIWIDGET ui_vbox(UiObject *obj) { - return ui_box(obj, 0, 0, UI_BOX_VERTICAL); -} - -UIWIDGET ui_hbox(UiObject *obj) { - return ui_box(obj, 0, 0, UI_BOX_HORIZONTAL); -} - -UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) { - return ui_box(obj, margin, spacing, UI_BOX_VERTICAL); -} - -UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) { - return ui_box(obj, margin, spacing, UI_BOX_HORIZONTAL); + box->n++; + return box->container.widget; } -UIWIDGET ui_grid(UiObject *obj) { - return ui_grid_sp(obj, 0, 0, 0); -} - -UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) { - UiContainer *ct = uic_get_current_container(obj); - - Arg args[16]; - int n = 0; - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget grid = XmCreateDrawingArea(parent, "grid", args, n); - ct->add(ct, grid); - XtManageChild(grid); - - UiObject *newobj = uic_object_new(obj, grid); - newobj->container = ui_grid_container(obj, grid, columnspacing, rowspacing); - uic_obj_add(obj, newobj); - - XtAddCallback (grid, XmNresizeCallback , ui_grid_resize, newobj->container); - - return grid; -} - -UIWIDGET ui_scrolledwindow(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - - Arg args[16]; - int n = 0; - XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); // TODO: dosn't work, use XmAPPLICATION_DEFINED - n++; - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget scrolledwindow = XmCreateScrolledWindow(parent, "scrolledwindow", args, n); - ct->add(ct, scrolledwindow); - XtManageChild(scrolledwindow); - - UiObject *newobj = uic_object_new(obj, scrolledwindow); - newobj->container = ui_scrolledwindow_container(obj, scrolledwindow); - uic_obj_add(obj, newobj); - - return scrolledwindow; -} - -UIWIDGET ui_sidebar(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - - Arg args[16]; - int n = 0; - - XtSetArg(args[n], XmNorientation, XmHORIZONTAL); - n++; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget pane = XmCreatePanedWindow(parent, "pane", args, n); - ct->add(ct, pane); - XtManageChild(pane); - - // add sidebar widget - Widget sidebar = XmCreateForm(pane, "sidebar", args, 0); - XtManageChild(sidebar); - - UiObject *left = uic_object_new(obj, sidebar); - left->container = ui_box_container(left, sidebar, 0, 0, UI_BOX_VERTICAL); - - // add content widget - XtSetArg (args[0], XmNpaneMaximum, 8000); - Widget content = XmCreateForm(pane, "content_area", args, 1); - XtManageChild(content); - - UiObject *right = uic_object_new(obj, content); - right->container = ui_box_container(right, content, 0, 0, UI_BOX_VERTICAL); - - uic_obj_add(obj, right); - uic_obj_add(obj, left); - - return sidebar; -} - -UIWIDGET ui_tabview(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - - // create a simple frame as container widget - // when tabs are selected, the current child will be replaced by the - // the new tab widget - Arg args[16]; - int n = 0; - XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); - n++; - XtSetArg(args[n], XmNshadowThickness, 0); - n++; - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget form = XmCreateForm(parent, "tabview", args, n); - ct->add(ct, form); - XtManageChild(form); - - UiObject *tabviewobj = uic_object_new(obj, form); - tabviewobj->container = ui_tabview_container(obj, form); - uic_obj_add(obj, tabviewobj); - - XtVaSetValues(form, XmNuserData, tabviewobj->container, NULL); - - return form; -} - -void ui_tab(UiObject *obj, char *title) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.label = title; - - ui_vbox(obj); -} - -void ui_select_tab(UIWIDGET tabview, int tab) { - UiTabViewContainer *ct = NULL; - XtVaGetValues(tabview, XmNuserData, &ct, NULL); - if(ct) { - XtUnmanageChild(ct->current); - Widget w = cxListAt(ct->tabs, tab); - if(w) { - XtManageChild(w); - ct->current = w; - } else { - fprintf(stderr, "UiError: front tab index: %d\n", tab); - } - } else { - fprintf(stderr, "UiError: widget is not a tabview\n"); +Widget ui_vbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n) { + UiBoxContainer *box = (UiBoxContainer*)ctn; + int a = *n; + XtSetArg(args[a], gridRow, box->n); a++; + if(box->container.layout.fill == UI_ON) { + XtSetArg(args[a], gridVExpand, TRUE); a++; + XtSetArg(args[a], gridVFill, TRUE); a++; } -} - - -/* document tabview */ - -static void ui_tabbar_resize(Widget widget, XtPointer udata, XtPointer cdata) { - MotifTabbedPane *v = (MotifTabbedPane*)udata; - - int width = 0; - int height = 0; - XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL); - int button_width = width / 4; - int x = 0; - CxIterator tabIterator = cxListIterator(v->tabs); - cx_foreach(UiTab*, tab, tabIterator) { - XtVaSetValues( - tab->tab_button, - XmNx, x, - XmNy, 0, - XmNwidth, - button_width, - - NULL); - x += button_width; - } - - if(height <= v->height) { - XtVaSetValues(widget, XmNheight, v->height + 4, NULL); - } -} - -static void ui_tabbar_expose(Widget widget, XtPointer udata, XtPointer cdata) { - MotifTabbedPane *v = (MotifTabbedPane*)udata; - XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *)cdata; - XEvent *event = cbs->event; - Display *dpy = XtDisplay(widget); - - XGCValues gcvals; - GC gc; - Pixel fgpix; - - int tab_x; - int tab_width; - XtVaGetValues(v->current->tab_button, XmNx, &tab_x, XmNwidth, &tab_width, XmNhighlightColor, &fgpix, NULL); - - gcvals.foreground = v->bg1; - gc = XCreateGC( dpy, XtWindow(widget), (GCForeground), &gcvals); - - int width = 0; - int height = 0; - XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL); - XFillRectangle(dpy, XtWindow(widget), gc, 0, 0, width, height); - - gcvals.foreground = fgpix; - gc = XCreateGC( dpy, XtWindow(widget), (GCForeground), &gcvals); - - XFillRectangle(dpy, XtWindow(widget), gc, tab_x, 0, tab_width, height); - + XtSetArg(args[a], gridHExpand, TRUE); a++; + XtSetArg(args[a], gridHFill, TRUE); a++; + *n = a; + return ui_box_container_prepare(box, args, n); } -UiTabbedPane* ui_tabbed_document_view(UiObject *obj) { - int n = 0; - Arg args[16]; - - UiContainer *ct = uic_get_current_container(obj); - Widget parent = ct->prepare(ct, args, &n, TRUE); - - Widget tabview = XmCreateForm(parent, "tabview_form", args, n); - XtManageChild(tabview); - - XtSetArg(args[0], XmNorientation, XmHORIZONTAL); - XtSetArg(args[1], XmNpacking, XmPACK_TIGHT); - XtSetArg(args[2], XmNspacing, 1); - XtSetArg(args[3], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[4], XmNrightAttachment, XmATTACH_FORM); - XtSetArg(args[5], XmNtopAttachment, XmATTACH_FORM); - XtSetArg(args[6], XmNmarginWidth, 0); - XtSetArg(args[7], XmNmarginHeight, 0); - Widget tabbar = XmCreateDrawingArea(tabview, "tabbar", args, 8); - XtManageChild(tabbar); - - XtSetArg(args[0], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[1], XmNrightAttachment, XmATTACH_FORM); - XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET); - XtSetArg(args[3], XmNtopWidget, tabbar); - XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM); - XtSetArg(args[5], XmNshadowThickness, 0); - Widget tabct = XmCreateForm(tabview, "tabview", args, 6); - XtManageChild(tabct); - - MotifTabbedPane *tabbedpane = ui_malloc(obj->ctx, sizeof(MotifTabbedPane)); - tabbedpane->view.ctx = uic_current_obj(obj)->ctx; - tabbedpane->view.widget = tabct; - tabbedpane->view.document = NULL; - tabbedpane->tabbar = tabbar; - tabbedpane->tabs = cxArrayListCreate(obj->ctx->allocator, cx_cmp_uintptr, CX_STORE_POINTERS, 16); - tabbedpane->current = NULL; - tabbedpane->height = 0; - - XtAddCallback(tabbar, XmNresizeCallback , ui_tabbar_resize, tabbedpane); - XtAddCallback(tabbar, XmNexposeCallback, ui_tabbar_expose, tabbedpane); - - return &tabbedpane->view; +Widget ui_hbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n) { + UiBoxContainer *box = (UiBoxContainer*)ctn; + int a = *n; + XtSetArg(args[a], gridRow, box->n); a++; + if(box->container.layout.fill == UI_ON) { + XtSetArg(args[a], gridHExpand, TRUE); a++; + } + XtSetArg(args[a], gridVExpand, TRUE); a++; + *n = a; + return ui_box_container_prepare(box, args, n); } -UiObject* ui_document_tab(UiTabbedPane *view) { - MotifTabbedPane *v = (MotifTabbedPane*)view; - int n = 0; - Arg args[16]; - - // hide the current tab content - if(v->current) { - XtUnmanageChild(v->current->content->widget); - } - - UiTab *tab = ui_malloc(view->ctx, sizeof(UiTab)); - - // create the new tab content - XtSetArg(args[0], XmNshadowThickness, 0); - XtSetArg(args[1], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[2], XmNrightAttachment, XmATTACH_FORM); - XtSetArg(args[3], XmNtopAttachment, XmATTACH_FORM); - XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM); - XtSetArg(args[5], XmNuserData, tab); - Widget frame = XmCreateFrame(view->widget, "tab", args, 6); - XtManageChild(frame); - - UiObject *content = ui_malloc(view->ctx, sizeof(UiObject)); - content->widget = NULL; // initialization for uic_context() - content->ctx = uic_context(content, view->ctx->mp); - content->ctx->parent = view->ctx; - content->ctx->attach_document = uic_context_attach_document; - content->ctx->detach_document2 = uic_context_detach_document2; - content->widget = frame; - content->window = view->ctx->obj->window; - content->container = ui_frame_container(content, frame); - content->next = NULL; - - // add tab button - cxListAdd(v->tabs, tab); - - XmString label = XmStringCreateLocalized("tab"); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNshadowThickness, 0); - XtSetArg(args[2], XmNhighlightThickness, 0); - - Widget button = XmCreatePushButton(v->tabbar, "tab_button", args, 3); - tab->tabbedpane = v; - tab->content = content; - tab->tab_button = button; - XtManageChild(button); - XtAddCallback( - button, - XmNactivateCallback, - (XtCallbackProc)ui_tab_button_callback, - tab); - - if(v->height == 0) { - XtVaGetValues( - button, - XmNarmColor, - &v->bg1, - XmNbackground, - &v->bg2, - XmNheight, - &v->height, - NULL); - v->height += 2; // border - } - - ui_change_tab(v, tab); - ui_tabbar_resize(v->tabbar, v, NULL); - - return content; -} - -void ui_tab_button_callback(Widget widget, UiTab *tab, XtPointer d) { - MotifTabbedPane *t = tab->tabbedpane; - if(t->current) { - XtUnmanageChild(t->current->content->widget); - XtVaSetValues(t->current->tab_button, XmNset, 0, NULL); - } - XtManageChild(tab->content->widget); - - ui_change_tab(t, tab); +void ui_box_container_add(UiContainerPrivate *ctn, Widget widget) { + ui_reset_layout(ctn->layout); } - -void ui_change_tab(MotifTabbedPane *pane, UiTab *tab) { - UiContext *ctx = tab->content->ctx; - ctx->parent->detach_document2(ctx->parent, pane->current->content->ctx->document); - ctx->parent->attach_document(ctx->parent, ctx->document); - - if(pane->current) { - XtVaSetValues(pane->current->tab_button, XmNshadowThickness, 0, XmNbackground, pane->bg1, NULL); - } - XtVaSetValues(tab->tab_button, XmNshadowThickness, 1, XmNbackground, pane->bg2, NULL); - - pane->current = tab; - pane->index = cxListFind(pane->tabs, tab); - printf("index: %d\n", pane->index); - - // redraw tabbar - Display *dpy = XtDisplay(pane->tabbar); - Window window = XtWindow(pane->tabbar); - if(dpy && window) { - XClearArea(dpy, XtWindow(pane->tabbar), 0, 0, 0, 0, TRUE); - XFlush(dpy); - } -} - -void ui_tab_set_document(UiContext *ctx, void *document) { - if(ctx->parent->document) { - //ctx->parent->detach_document(ctx->parent, ctx->parent->document); - } - uic_context_attach_document(ctx, document); - //uic_context_set_document(ctx->parent, document); - //ctx->parent->document = document; - - UiTab *tab = NULL; - XtVaGetValues( - ctx->obj->widget, - XmNuserData, - &tab, - NULL); - if(tab) { - if(tab->tabbedpane->current == tab) { - ctx->parent->attach_document(ctx->parent, ctx->document); - } - } else { - fprintf(stderr, "UiError: ui_bar_set_document: Cannot set document"); - } -} - - - -/* - * -------------------- Layout Functions -------------------- - * - * functions for setting layout attributes for the current container - * - */ - -void ui_layout_fill(UiObject *obj, UiBool fill) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.fill = ui_bool2lb(fill); -} - -void ui_layout_hexpand(UiObject *obj, UiBool expand) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.hexpand = expand; -} - -void ui_layout_vexpand(UiObject *obj, UiBool expand) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.vexpand = expand; -} - -void ui_layout_gridwidth(UiObject *obj, int width) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.gridwidth = width; -} - -void ui_newline(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.newline = TRUE; -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/container.h --- a/ui/motif/container.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/container.h Wed Dec 04 18:31:22 2024 +0100 @@ -37,26 +37,37 @@ #ifdef __cplusplus extern "C" { #endif - -#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout)) -typedef struct MotifTabbedPane MotifTabbedPane; -typedef struct UiTab UiTab; -typedef struct UiBoxContainer UiBoxContainer; -typedef struct UiGridContainer UiGridContainer; -typedef struct UiTabViewContainer UiTabViewContainer; -typedef struct UiLayout UiLayout; +#define UI_APPLY_LAYOUT(layout, args) \ + layout.fill = args.fill; \ + layout.hexpand = args.hexpand; \ + layout.vexpand = args.vexpand; \ + layout.hfill = args.hfill; \ + layout.vfill = args.vfill; \ + layout.colspan = args.colspan; \ + layout.rowspan = args.rowspan + +typedef enum UiBoxOrientation UiBoxOrientation; + +#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout)) +#define ui_lb2bool(b) ((b) == UI_LAYOUT_TRUE ? TRUE : FALSE) +#define ui_bool2lb(b) ((b) ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE) -typedef Widget (*ui_container_add_f)(UiContainer*, Arg*, int*, UiBool); - -typedef enum UiLayoutBool UiLayoutBool; -typedef enum UiBoxOrientation UiBoxOrientation; +#define ui_obj_container(obj) (UiContainerPrivate*)obj->container_end + +typedef struct UiLayout UiLayout; - -enum UiLayoutBool { - UI_LAYOUT_UNDEFINED = 0, - UI_LAYOUT_TRUE, - UI_LAYOUT_FALSE, +struct UiLayout { + UiTri fill; + UiBool newline; + char *label; + UiBool hexpand; + UiBool vexpand; + UiBool hfill; + UiBool vfill; + int width; + int colspan; + int rowspan; }; enum UiBoxOrientation { @@ -64,93 +75,32 @@ UI_BOX_HORIZONTAL }; -struct UiLayout { - UiLayoutBool fill; - UiBool newline; - char *label; - UiBool hexpand; - UiBool vexpand; - int gridwidth; -}; +typedef struct UiContainerPrivate UiContainerPrivate; -struct UiContainer { - Widget widget; - Widget (*prepare)(UiContainer*, Arg *, int*, UiBool); - void (*add)(UiContainer*, Widget); - UiLayout layout; - Widget current; - Widget menu; -}; -struct UiBoxContainer { - UiContainer container; - Widget prev_widget; - UiBool has_fill; - UiBoxOrientation orientation; - int margin; - int spacing; -}; - -struct UiGridContainer { - UiContainer container; - CxList *lines; - CxList *current; - int columnspacing; - int rowspacing; -}; - -struct UiTabViewContainer { - UiContainer container; - UiContext *context; - Widget widget; - CxList *tabs; - Widget current; +struct UiContainerPrivate { + UiContainerX container; + Widget (*prepare)(UiContainerPrivate*, Arg *, int*); + void (*add)(UiContainerPrivate*, Widget); + Widget widget; + UiLayout layout; }; -struct MotifTabbedPane { - UiTabbedPane view; - Widget tabbar; - CxList *tabs; - UiTab *current; - int index; - Pixel bg1; - Pixel bg2; - int height; -}; - -struct UiTab { - MotifTabbedPane *tabbedpane; - UiObject *content; - Widget tab_button; -}; - - -UiContainer* ui_frame_container(UiObject *obj, Widget frame); -Widget ui_frame_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_frame_container_add(UiContainer *ct, Widget widget); +typedef struct UiBoxContainer { + UiContainerPrivate container; + Dimension n; +} UiBoxContainer; -UiContainer* ui_box_container(UiObject *obj, Widget box, int margin, int spacing, UiBoxOrientation orientation); -Widget ui_box_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_box_container_add(UiContainer *ct, Widget widget); - -UiContainer* ui_grid_container(UiObject *obj, Widget form, int columnspacing, int rowspacing); -Widget ui_grid_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_grid_container_add(UiContainer *ct, Widget widget); +typedef struct UiGridContainer { + UiContainerPrivate container; + int x; + int y; +} UiGridContainer; -UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow); -Widget ui_scrolledwindow_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_scrolledwindow_container_add(UiContainer *ct, Widget widget); - -UiContainer* ui_tabview_container(UiObject *obj, Widget rowcolumn); -Widget ui_tabview_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_tabview_container_add(UiContainer *ct, Widget widget); - -void ui_tab_button_callback(Widget widget, UiTab *tab, XtPointer d); -void ui_change_tab(MotifTabbedPane *pane, UiTab *tab); - -void ui_tab_set_document(UiContext *ctx, void *document); -void ui_tab_detach_document(UiContext *ctx); - +UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation); +Widget ui_vbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n); +Widget ui_hbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n); +void ui_box_container_add(UiContainerPrivate *ctn, Widget widget); #ifdef __cplusplus } diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/dnd.c --- a/ui/motif/dnd.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/dnd.c Wed Dec 04 18:31:22 2024 +0100 @@ -28,18 +28,3 @@ #include "dnd.h" -void ui_selection_settext(UiSelection *sel, char *str, int len) { - -} - -void ui_selection_seturis(UiSelection *sel, char **uris, int nelm) { - -} - -char* ui_selection_gettext(UiSelection *sel) { - return NULL; -} - -char** ui_selection_geturis(UiSelection *sel, size_t *nelm) { - return NULL; -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/graphics.c --- a/ui/motif/graphics.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/graphics.c Wed Dec 04 18:31:22 2024 +0100 @@ -34,250 +34,3 @@ #include "graphics.h" #include "container.h" - -static void ui_drawingarea_expose(Widget widget, XtPointer u, XtPointer c) { - UiDrawEvent *drawevent = u; - //XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *)c; - //XEvent *event = cbs->event; - Display *dpy = XtDisplay(widget); - - UiEvent ev; - ev.obj = drawevent->obj; - ev.window = drawevent->obj->window; - ev.document = drawevent->obj->ctx->document; - ev.eventdata = NULL; - ev.intval = 0; - - XtVaGetValues( - widget, - XmNwidth, - &drawevent->gr.g.width, - XmNheight, - &drawevent->gr.g.height, - NULL); - - XGCValues gcvals; - gcvals.foreground = BlackPixelOfScreen(XtScreen(widget)); - drawevent->gr.gc = XCreateGC(dpy, XtWindow(widget), (GCForeground), &gcvals); - - drawevent->callback(&ev, &drawevent->gr.g, drawevent->userdata); -} - -UIWIDGET ui_drawingarea(UiObject *obj, ui_drawfunc f, void *userdata) { - UiContainer *ct = uic_get_current_container(obj); - - int n = 0; - Arg args[16]; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget drawingarea = XmCreateDrawingArea(parent, "drawingarea", args, n); - - if(f) { - UiDrawEvent *event = malloc(sizeof(UiDrawEvent)); - event->obj = obj; - event->callback = f; - event->userdata = userdata; - - event->gr.display = XtDisplay(drawingarea); - event->gr.widget = drawingarea; - - Colormap colormap; - XtVaGetValues(drawingarea, XmNcolormap, &colormap, NULL); - event->gr.colormap = colormap; - - XtAddCallback( - drawingarea, - XmNexposeCallback, - ui_drawingarea_expose, - event); - - XtVaSetValues(drawingarea, XmNuserData, event, NULL); - } - - XtManageChild(drawingarea); - return drawingarea; -} - -static void ui_drawingarea_input(Widget widget, XtPointer u, XtPointer c) { - XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c; - XEvent *xevent = cbs->event; - UiMouseEventData *event = u; - - if (cbs->reason == XmCR_INPUT) { - if (xevent->xany.type == ButtonPress) { - UiMouseEvent me; - me.x = xevent->xbutton.x; - me.y = xevent->xbutton.y; - // TODO: configurable double click time - me.type = xevent->xbutton.time - event->last_event > 300 ? UI_PRESS : UI_PRESS2; - - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.eventdata = &me; - e.intval = 0; - event->callback(&e, event->userdata); - - - event->last_event = me.type == UI_PRESS2 ? 0 : xevent->xbutton.time; - } - } - -} - -void ui_drawingarea_mousehandler(UiObject *obj, UIWIDGET widget, ui_callback f, void *u) { - if(f) { - UiMouseEventData *event = malloc(sizeof(UiMouseEventData)); - event->obj = obj; - event->callback = f; - event->userdata = u; - event->last_event = 0; - - XtAddCallback(widget, XmNinputCallback, ui_drawingarea_input, event); - } -} - -void ui_drawingarea_getsize(UIWIDGET drawingarea, int *width, int *height) { - XtVaGetValues( - drawingarea, - XmNwidth, - width, - XmNheight, - height, - NULL); -} - -void ui_drawingarea_redraw(UIWIDGET drawingarea) { - //XClearArea(XtDisplay(drawingarea), drawingarea->core.window, 0, 0, drawingarea->core.width, drawingarea->core.height, True); - UiDrawEvent *event; - XtVaGetValues(drawingarea, XmNuserData, &event, NULL); - ui_drawingarea_expose(drawingarea, event, NULL); -} - - -/* -------------------- text layout functions -------------------- */ -UiTextLayout* ui_text(UiGraphics *g) { - UiTextLayout *text = malloc(sizeof(UiTextLayout)); - memset(text, 0, sizeof(UiTextLayout)); - text->text = NULL; - text->length = 0; - text->widget = ((UiXlibGraphics*)g)->widget; - text->fontset = NULL; - return text; -} - -static void create_default_fontset(UiTextLayout *layout) { - char **missing = NULL; - int num_missing = 0; - char *def = NULL; - Display *dpy = XtDisplay(layout->widget); - XFontSet fs = XCreateFontSet( - dpy, - "-dt-interface system-medium-r-normal-s*utf*:," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-1," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-10," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-15," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-2," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-3," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-4," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-5," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-9," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-e," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-r," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-ru," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-u," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-uni," - "-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208", - &missing, &num_missing, &def); - layout->fontset = fs; -} - -void ui_text_free(UiTextLayout *text) { - // TODO -} - -void ui_text_setstring(UiTextLayout *layout, char *str) { - ui_text_setstringl(layout, str, strlen(str)); -} - -void ui_text_setstringl(UiTextLayout *layout, char *str, int len) { - layout->text = str; - layout->length = len; - layout->changed = 1; -} - -void ui_text_setfont(UiTextLayout *layout, char *font, int size) { - create_default_fontset(layout);//TODO - layout->changed = 1; -} - -void ui_text_getsize(UiTextLayout *layout, int *width, int *height) { - if(layout->changed) { - XRectangle ext, lext; - XmbTextExtents(layout->fontset, layout->text, layout->length, &ext, &lext); - layout->width = ext.width; - layout->height = ext.height; - layout->changed = 0; - } - *width = layout->width; - *height = layout->height; -} - -void ui_text_setwidth(UiTextLayout *layout, int width) { - layout->maxwidth = width; -} - - -/* -------------------- drawing functions -------------------- */ - -void ui_graphics_color(UiGraphics *g, int red, int green, int blue) { - UiXlibGraphics *gr = (UiXlibGraphics*)g; - XColor color; - color.flags= DoRed | DoGreen | DoBlue; - color.red = red * 257; - color.green = green * 257; - color.blue = blue * 257; - XAllocColor(gr->display, gr->colormap, &color); - XSetForeground(gr->display, gr->gc, color.pixel); -} - -void ui_draw_line(UiGraphics *g, int x1, int y1, int x2, int y2) { - UiXlibGraphics *gr = (UiXlibGraphics*)g; - XDrawLine(gr->display, XtWindow(gr->widget), gr->gc, x1, y1, x2, y2); -} - -void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, int fill) { - UiXlibGraphics *gr = (UiXlibGraphics*)g; - if(fill) { - XFillRectangle(gr->display, XtWindow(gr->widget), gr->gc, x, y, w, h); - } else { - XDrawRectangle(gr->display, XtWindow(gr->widget), gr->gc, x, y, w, h); - } -} - -void ui_draw_text(UiGraphics *g, int x, int y, UiTextLayout *text) { - UiXlibGraphics *gr = (UiXlibGraphics*)g; - int width, height; - ui_text_getsize(text, &width, &height); - if(text->maxwidth > 0) { - XRectangle clip; - clip.x = x; - clip.y = y; - clip.width = text->maxwidth; - clip.height = height; - XSetClipRectangles(gr->display, gr->gc, 0, 0, &clip, 1, Unsorted); - } - - XmbDrawString( - gr->display, - XtWindow(gr->widget), - text->fontset, - gr->gc, - x, - y + height, - text->text, - text->length); - - XSetClipMask(gr->display, gr->gc, None); -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/graphics.h --- a/ui/motif/graphics.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/graphics.h Wed Dec 04 18:31:22 2024 +0100 @@ -36,38 +36,6 @@ extern "C" { #endif -typedef struct UiXlibGraphics { - UiGraphics g; - Display *display; - Widget widget; - Colormap colormap; - GC gc; -} UiXlibGraphics; - -typedef struct UiDrawEvent { - ui_drawfunc callback; - UiObject *obj; - void *userdata; - UiXlibGraphics gr; -} UiDrawEvent; - -typedef struct UiMouseEventData { - UiObject *obj; - ui_callback callback; - void *userdata; - Time last_event; -} UiMouseEventData; - -struct UiTextLayout { - char *text; - size_t length; - Widget widget; - XFontSet fontset; - int maxwidth; - int width; - int height; - int changed; -}; #ifdef __cplusplus diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/image.c --- a/ui/motif/image.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/image.c Wed Dec 04 18:31:22 2024 +0100 @@ -6,35 +6,3 @@ #include "image.h" -UiIcon* ui_icon(const char *name, int size) { - return NULL; -} - -UiIcon* ui_icon_unscaled(const char *name, int size) { - return NULL; -} - -void ui_free_icon(UiIcon *icon) { - -} - -UiImage* ui_icon_image(UiIcon *icon) { - return NULL; -} - -UiImage* ui_image(const char *filename) { - return NULL; -} - -UiImage* ui_named_image(const char *filename, const char *name) { - return NULL; -} - -UiImage* ui_load_image_from_path(const char *path, const char *name) { - return NULL; -} - -void ui_free_image(UiImage *img) { - -} - diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/label.c --- a/ui/motif/label.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/label.c Wed Dec 04 18:31:22 2024 +0100 @@ -34,36 +34,3 @@ #include "../common/context.h" #include "../common/object.h" -UIWIDGET ui_label(UiObject *obj, char *label) { - UiContainer *ct = uic_get_current_container(obj); - XmString str = XmStringCreateLocalized(label); - - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNlabelString, str); - n++; - - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget widget = XmCreateLabel(parent, "label", args, n); - ct->add(ct, widget); - XtManageChild(widget); - - return widget; -} - -UIWIDGET ui_space(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - XmString str = XmStringCreateLocalized(""); - - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNlabelString, str); - n++; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget widget = XmCreateLabel(parent, "space_label", args, n); - ct->add(ct, widget); - XtManageChild(widget); - - return widget; -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/list.c --- a/ui/motif/list.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/list.c Wed Dec 04 18:31:22 2024 +0100 @@ -34,175 +34,3 @@ #include "list.h" #include "../common/object.h" - -void* ui_strmodel_getvalue(void *elm, int column) { - return column == 0 ? elm : NULL; -} - - -UIWIDGET ui_listview_str(UiObject *obj, UiList *list, ui_callback f, void *udata) { - return ui_listview(obj, list, ui_strmodel_getvalue, f, udata); -} - -UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - int count; - XmStringTable items = ui_create_stringlist(var->value, getvalue, &count); - - Arg args[8]; - int n = 0; - XtSetArg(args[n], XmNitemCount, count); - n++; - XtSetArg(args[n], XmNitems, count == 0 ? NULL : items); - n++; - - UiContainer *ct = uic_get_current_container(obj); - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget widget = XmCreateScrolledList(parent, "listview", args, n); - ct->add(ct, XtParent(widget)); - XtManageChild(widget); - - UiListView *listview = cxMalloc(obj->ctx->allocator, sizeof(UiListView)); - listview->widget = widget; - listview->list = var; - listview->getvalue = getvalue; - - for (int i=0;ictx->allocator, - sizeof(UiListViewEventData)); - event->event.obj = obj; - event->event.userdata = udata; - event->event.callback = f; - event->event.value = 0; - event->var = var; - XtAddCallback( - widget, - XmNdefaultActionCallback, - (XtCallbackProc)ui_list_selection_callback, - event); - } - - return widget; -} - -UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - return ui_listview_var(obj, var, getvalue, f, udata); -} - -UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - UiListVar *value = var->value; - return ui_listview_var(obj, var, getvalue, f, udata); - } else { - // TODO: error - } - return NULL; -} - - -XmStringTable ui_create_stringlist(UiList *list, ui_getvaluefunc getvalue, int *count) { - int num = list->count(list); - XmStringTable items = (XmStringTable)XtMalloc(num * sizeof(XmString)); - void *data = list->first(list); - for(int i=0;inext(list); - } - - *count = num; - return items; -} - - -void ui_listview_update(UiEvent *event, UiListView *view) { - int count; - XmStringTable items = ui_create_stringlist( - view->list->value, - view->getvalue, - &count); - - XtVaSetValues( - view->widget, - XmNitems, count == 0 ? NULL : items, - XmNitemCount, - count, - NULL); - - for (int i=0;ievent.obj; - e.window = event->event.obj->window; - e.document = event->event.obj->ctx->document; - UiList *list = event->var->value; - e.eventdata = list->get(list, cbs->item_position - 1); - e.intval = cbs->item_position - 1; - event->event.callback(&e, event->event.userdata); -} - - -/* --------------------------- ComboBox --------------------------- */ - -UIWIDGET ui_combobox_str(UiObject *obj, UiList *list, ui_callback f, void *udata) { - return ui_combobox(obj, list, ui_strmodel_getvalue, f, udata); -} - -UIWIDGET ui_combobox(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - return ui_combobox_var(obj, var, getvalue, f, udata); -} - -UIWIDGET ui_combobox_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - UiListVar *value = var->value; - return ui_combobox_var(obj, var, getvalue, f, udata); - } else { - // TODO: error - } - return NULL; -} - -UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiListView *listview = cxMalloc( - obj->ctx->allocator, - sizeof(UiListView)); - - UiContainer *ct = uic_get_current_container(obj); - Arg args[16]; - int n = 0; - XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_NONE); - n++; - XtSetArg(args[n], XmNtraversalOn, FALSE); - n++; - XtSetArg(args[n], XmNwidth, 160); - n++; - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget combobox = XmCreateDropDownList(parent, "combobox", args, n); - XtManageChild(combobox); - listview->widget = combobox; - listview->list = var; - listview->getvalue = getvalue; - - ui_listview_update(NULL, listview); - - return parent; -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/list.h --- a/ui/motif/list.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/list.h Wed Dec 04 18:31:22 2024 +0100 @@ -37,24 +37,7 @@ extern "C" { #endif -typedef struct UiListView { - Widget widget; - UiVar *list; - ui_getvaluefunc getvalue; -} UiListView; - -typedef struct UiListViewEventData { - UiEventData event; - UiVar *var; -} UiListViewEventData; - -void* ui_strmodel_getvalue(void *elm, int column); - -XmStringTable ui_create_stringlist(UiList *list, ui_getvaluefunc getvalue, int *count); -void ui_listview_update(UiEvent *event, UiListView *view); -void ui_list_selection_callback (Widget widget, UiListViewEventData *event, XtPointer data); - -UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata); + #ifdef __cplusplus } diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/menu.c --- a/ui/motif/menu.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/menu.c Wed Dec 04 18:31:22 2024 +0100 @@ -41,444 +41,3 @@ #include #include -static ui_menu_add_f createMenuItem[] = { - /* UI_MENU */ add_menu_widget, - /* UI_MENU_SUBMENU */ add_menu_widget, - /* UI_MENU_ITEM */ add_menuitem_widget, - /* UI_MENU_STOCK_ITEM */ add_menuitem_st_widget, - /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, - /* UI_MENU_CHECK_ITEM_NV */ add_checkitemnv_widget, - /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, - /* UI_MENU_ITEM_LIST_NV */ NULL, // TODO - /* UI_MENU_SEPARATOR */ add_menuseparator_widget -}; - -// private menu functions -void ui_create_menubar(UiObject *obj) { - UiMenu *menus = uic_get_menu_list(); - if(!menus) { - return; - } - - Widget menubar = XmCreateMenuBar(obj->widget, "main_list", NULL, 0); - XtManageChild(menubar); - - UiMenu *menu = menus; - int menu_index = 0; - while(menu) { - menu_index += add_menu_widget(menubar, menu_index, &menu->item, obj); - - menu = (UiMenu*)menu->item.next; - } -} - -int add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { - UiMenu *menu = (UiMenu*)item; - - Widget menuItem = XtVaCreateManagedWidget( - menu->label, - xmCascadeButtonWidgetClass, - parent, - NULL); - Widget m = XmVaCreateSimplePulldownMenu(parent, menu->label, i, NULL, NULL); - - UiMenuItemI *mi = menu->items_begin; - int menu_index = 0; - while(mi) { - menu_index += createMenuItem[mi->type](m, menu_index, mi, obj); - mi = mi->next; - } - - return 1; -} - -int add_menuitem_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiMenuItem *mi = (UiMenuItem*)item; - - Arg args[1]; - XmString label = XmStringCreateLocalized(mi->label); - XtSetArg(args[0], XmNlabelString, label); - - Widget mitem = XtCreateManagedWidget( - "menubutton", - xmPushButtonWidgetClass, - parent, - args, - 1); - XmStringFree(label); - - if(mi->callback != NULL) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = mi->userdata; - event->callback = mi->callback; - event->value = 0; - XtAddCallback( - mitem, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - - if(mi->groups) { - uic_add_group_widget(obj->ctx, mitem, (ui_enablefunc)XtSetSensitive, mi->groups); - } - - return 1; -} - -int add_menuitem_st_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { - UiStMenuItem *mi = (UiStMenuItem*)item; - - UiStockItem *si = ui_get_stock_item(mi->stockid); - if(!si) { - fprintf(stderr, "UI Error: unknown stock id: %s\n", mi->stockid); - return 0; - } - - int n = 0; - Arg args[4]; - XmString label = XmStringCreateLocalized(si->label); - XmString at = NULL; - - XtSetArg(args[n], XmNlabelString, label); - n++; - if(si->accelerator) { - XtSetArg(args[n], XmNaccelerator, si->accelerator); - n++; - } - if(si->accelerator_label) { - at = XmStringCreateLocalized(si->accelerator_label); - XtSetArg(args[n], XmNacceleratorText, at); - n++; - } - - Widget mitem = XtCreateManagedWidget( - "menubutton", - xmPushButtonWidgetClass, - parent, - args, - n); - XmStringFree(label); - if(at) { - XmStringFree(at); - } - - if(mi->callback != NULL) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = mi->userdata; - event->callback = mi->callback; - event->value = 0; - XtAddCallback( - mitem, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - - if(mi->groups) { - uic_add_group_widget(obj->ctx, mitem, (ui_enablefunc)XtSetSensitive, mi->groups); - } - - return 1; -} - -int add_menuseparator_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - Widget s = XmCreateSeparatorGadget (parent, "menu_separator", NULL, 0); - XtManageChild(s); - return 1; -} - -int add_checkitem_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiCheckItem *ci = (UiCheckItem*)item; - - Arg args[3]; - XmString label = XmStringCreateLocalized(ci->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNvisibleWhenOff, 1); - Widget checkbox = XtCreateManagedWidget( - "menutogglebutton", - xmToggleButtonWidgetClass, - parent, - args, - 2); - XmStringFree(label); - - if(ci->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = ci->userdata; - event->callback = ci->callback; - XtAddCallback( - checkbox, - XmNvalueChangedCallback, - (XtCallbackProc)ui_toggle_button_callback, - event); - } - - return 1; -} - -int add_checkitemnv_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiCheckItemNV *ci = (UiCheckItemNV*)item; - - Arg args[3]; - XmString label = XmStringCreateLocalized(ci->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNvisibleWhenOff, 1); - Widget checkbox = XtCreateManagedWidget( - "menutogglebutton", - xmToggleButtonWidgetClass, - parent, - args, - 2); - XmStringFree(label); - - UiVar *var = uic_create_var(obj->ctx, ci->varname, UI_VAR_INTEGER); - if(var) { - UiInteger *value = var->value; - value->obj = checkbox; - value->get = ui_toggle_button_get; - value->set = ui_toggle_button_set; - value = 0; - } else { - // TODO: error - } - - return 1; -} - -int add_menuitem_list_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiMenuItemList *il = (UiMenuItemList*)item; - - UiActiveMenuItemList *ls = cxMalloc( - obj->ctx->allocator, - sizeof(UiActiveMenuItemList)); - - ls->object = obj; - ls->menu = parent; - ls->index = i; - ls->oldcount = 0; - ls->list = il->list; - ls->callback = il->callback; - ls->userdata = il->userdata; - - ls->list->observers = ui_add_observer( - ls->list->observers, - (ui_callback)ui_update_menuitem_list, - ls); - - ui_update_menuitem_list(NULL, ls); - - return 0; -} - -void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { - Arg args[4]; - - // remove old items - if(list->oldcount > 0) { - Widget *children; - int nc; - - XtVaGetValues( - list->menu, - XmNchildren, - &children, - XmNnumChildren, - &nc, - NULL); - - for(int i=0;ioldcount;i++) { - XtDestroyWidget(children[list->index + i]); - } - } - - char *str = ui_list_first(list->list); - if(str) { - // add separator - XtSetArg(args[0], XmNpositionIndex, list->index); - Widget s = XmCreateSeparatorGadget (list->menu, "menu_separator", args, 1); - XtManageChild(s); - } - int i = 1; - while(str) { - XmString label = XmStringCreateLocalized(str); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNpositionIndex, list->index + i); - - Widget mitem = XtCreateManagedWidget( - "menubutton", - xmPushButtonWidgetClass, - list->menu, - args, - 2); - XmStringFree(label); - - if(list->callback) { - // TODO: use mempool - UiEventData *event = malloc(sizeof(UiEventData)); - event->obj = list->object; - event->userdata = list->userdata; - event->callback = list->callback; - event->value = i - 1; - - XtAddCallback( - mitem, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - - str = ui_list_next(list->list); - i++; - } - - list->oldcount = i; -} - -void ui_menu_event_wrapper(Widget widget, XtPointer udata, XtPointer cdata) { - UiEventData *event = udata; - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.intval = 0; - event->callback(&e, event->userdata); -} - - -/* - * widget menu functions - */ - -static void ui_popup_handler(Widget widget, XtPointer data, XEvent *event, Boolean *c) { - Widget menu = data; - XmMenuPosition(menu, (XButtonPressedEvent *)event); - XtManageChild(menu); - - *c = FALSE; -} - -UIMENU ui_contextmenu(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - if(ct->current) { - return ui_contextmenu_w(obj, ct->current); - } else { - return NULL; // TODO: warn - } -} - -UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) { - UiContainer *ct = uic_get_current_container(obj); - - Widget menu = XmCreatePopupMenu(widget, "popup_menu", NULL, 0); - ct->menu = menu; - - XtAddEventHandler(widget, ButtonPressMask, FALSE, ui_popup_handler, menu); - - return menu; -} - -void ui_contextmenu_popup(UIMENU menu) { - -} - -void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata) { - ui_widget_menuitem_gr(obj, label, f, userdata, -1); -} - -void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; - } - - // add groups - CxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!groups) { - groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16); - } - cxListAdd(groups, &group); - } - va_end(ap); - - // create menuitem - Arg args[4]; - XmString labelstr = XmStringCreateLocalized(label); - XtSetArg(args[0], XmNlabelString, labelstr); - - Widget item = XmCreatePushButton(ct->menu, "menu_button", args, 1); - XtManageChild(item); - XmStringFree(labelstr); -} - -void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) { - ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1); -} - -void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; - } - - // add groups - CxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!groups) { - groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16); - } - cxListAdd(groups, &group); - } - va_end(ap); - - // create menuitem - UiStockItem *stockItem = ui_get_stock_item(stockid); - Arg args[4]; - XmString labelstr = XmStringCreateLocalized(stockItem->label); - XtSetArg(args[0], XmNlabelString, labelstr); - - Widget item = XmCreatePushButton(ct->menu, "menu_button", args, 1); - XtManageChild(item); - XmStringFree(labelstr); -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/menu.h --- a/ui/motif/menu.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/menu.h Wed Dec 04 18:31:22 2024 +0100 @@ -37,33 +37,6 @@ #endif -typedef struct UiActiveMenuItemList UiActiveMenuItemList; - -typedef int(*ui_menu_add_f)(Widget, int, UiMenuItemI*, UiObject*); - -struct UiActiveMenuItemList { - UiObject *object; - Widget menu; - int index; - int oldcount; - UiList *list; - ui_callback callback; - void *userdata; -}; - -void ui_create_menubar(UiObject *obj); - -int add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_menuitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_menuitem_st_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_menuseparator_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_checkitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_checkitemnv_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_menuitem_list_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); - -void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list); -void ui_menu_event_wrapper(Widget widget, XtPointer udata, XtPointer cdata); - #ifdef __cplusplus } diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/objs.mk --- a/ui/motif/objs.mk Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/objs.mk Wed Dec 04 18:31:22 2024 +0100 @@ -39,11 +39,11 @@ MOTIFOBJ += label.o MOTIFOBJ += text.o MOTIFOBJ += list.o -MOTIFOBJ += tree.o MOTIFOBJ += graphics.o MOTIFOBJ += range.o MOTIFOBJ += dnd.o MOTIFOBJ += image.o +MOTIFOBJ += Grid.o TOOLKITOBJS += $(MOTIFOBJ:%=$(MOTIF_OBJPRE)%) TOOLKITSOURCE += $(MOTIFOBJ:%.o=motif/%.c) diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/range.c --- a/ui/motif/range.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/range.c Wed Dec 04 18:31:22 2024 +0100 @@ -34,104 +34,3 @@ #include "../common/context.h" #include "../common/object.h" - -static UIWIDGET ui_scrollbar(UiObject *obj, UiOrientation orientation, UiRange *range, ui_callback f, void *userdata) { - UiContainer *ct = uic_get_current_container(obj); - - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNorientation, orientation == UI_HORIZONTAL ? XmHORIZONTAL : XmVERTICAL); - n++; - XtSetArg (args[n], XmNmaximum, 10); - n++; - XtSetArg (args[n], XmNsliderSize, 1); - n++; - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget scrollbar = XmCreateScrollBar(parent, "scrollbar", args, n); - XtManageChild(scrollbar); - ct->add(ct, scrollbar); - - if(range) { - range->get = ui_scrollbar_get; - range->set = ui_scrollbar_set; - range->setrange = ui_scrollbar_setrange; - range->setextent = ui_scrollbar_setextent; - range->obj = scrollbar; - } - - if(f) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = userdata; - event->callback = f; - event->value = 0; - XtAddCallback( - scrollbar, - XmNvalueChangedCallback, - (XtCallbackProc)ui_scrollbar_callback, - event); - } - - return scrollbar; -} - -UIWIDGET ui_hscrollbar(UiObject *obj, UiRange *range, ui_callback f, void *userdata) { - return ui_scrollbar(obj, UI_HORIZONTAL, range, f, userdata); -} - -UIWIDGET ui_vscrollbar(UiObject *obj, UiRange *range, ui_callback f, void *userdata) { - return ui_scrollbar(obj, UI_VERTICAL, range, f, userdata); -} - -void ui_scrollbar_callback(Widget scrollbar, UiEventData *event, XtPointer cdata) { - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.intval = event->value; - event->callback(&e, event->userdata); -} - -double ui_scrollbar_get(UiRange *range) { - int intval; - XtVaGetValues( - range->obj, - XmNvalue, - &intval, - NULL); - double value = (double)intval / 10; - range->value = value; - return value; -} - -void ui_scrollbar_set(UiRange *range, double value) { - XtVaSetValues( - range->obj, - XmNvalue, - (int)(value * 10), - NULL); - range->value = value; -} - -void ui_scrollbar_setrange(UiRange *range, double min, double max) { - XtVaSetValues( - range->obj, - XmNminimum, - (int)(min * 10), - XmNmaximum, - (int)(max * 10), - NULL); - range->min = min; - range->max = max; -} - -void ui_scrollbar_setextent(UiRange *range, double extent) { - XtVaSetValues( - range->obj, - XmNsliderSize, - (int)(extent * 10), - NULL); - range->extent = extent; -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/range.h --- a/ui/motif/range.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/range.h Wed Dec 04 18:31:22 2024 +0100 @@ -36,11 +36,6 @@ extern "C" { #endif -void ui_scrollbar_callback(Widget scrollbar, UiEventData *event, XtPointer cdata); -double ui_scrollbar_get(UiRange *range); -void ui_scrollbar_set(UiRange *range, double value); -void ui_scrollbar_setrange(UiRange *range, double min, double max); -void ui_scrollbar_setextent(UiRange *range, double extent); #ifdef __cplusplus diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/stock.c --- a/ui/motif/stock.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/stock.c Wed Dec 04 18:31:22 2024 +0100 @@ -33,44 +33,4 @@ #include "../ui/properties.h" #include -static CxMap *stock_items; -void ui_stock_init() { - stock_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 64); - - ui_add_stock_item(UI_STOCK_NEW, "New", "CtrlN", "Ctrl+N", NULL); - ui_add_stock_item(UI_STOCK_OPEN, "Open", "CtrlO", "Ctrl+O", NULL); - ui_add_stock_item(UI_STOCK_SAVE, "Save", "CtrlS", "Ctrl+S", NULL); - ui_add_stock_item(UI_STOCK_SAVE_AS, "Save as ...", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_REVERT_TO_SAVED, "Revert to saved", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_CLOSE, "Close", "CtrlW", "Ctrl+W", NULL); - ui_add_stock_item(UI_STOCK_UNDO, "Undo", "CtrlZ", "Ctrl+Z", NULL); - ui_add_stock_item(UI_STOCK_REDO, "Redo", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_GO_BACK, "Back", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_GO_FORWARD, "Forward", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_CUT, "Cut", "CtrlX", "Ctrl+X", NULL); - ui_add_stock_item(UI_STOCK_COPY, "Copy", "CtrlC", "Ctrl+C", NULL); - ui_add_stock_item(UI_STOCK_PASTE, "Paste", "CtrlV", "Ctrl+V", NULL); - ui_add_stock_item(UI_STOCK_DELETE, "Delete", NULL, NULL, NULL); -} - -void ui_add_stock_item(char *id, char *label, char *accelerator, char *accelerator_label, void *icon) { - UiStockItem *i = malloc(sizeof(UiStockItem)); - i->label = label; - i->accelerator = accelerator; - i->accelerator_label = accelerator_label; - // TODO: icon - - cxMapPut(stock_items, id, i); -} - -UiStockItem* ui_get_stock_item(char *id) { - UiStockItem *item = cxMapGet(stock_items, id); - if(item) { - char *label = uistr_n(id); - if(label) { - item->label = label; - } - } - return item; -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/stock.h --- a/ui/motif/stock.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/stock.h Wed Dec 04 18:31:22 2024 +0100 @@ -35,18 +35,7 @@ extern "C" { #endif -typedef struct UiStockItem { - char *label; - char *accelerator; - char *accelerator_label; - // TODO: icon -} UiStockItem; - -void ui_stock_init(); -void ui_add_stock_item(char *id, char *label, char *accelerator, char *accelerator_label, void *icon); - -UiStockItem* ui_get_stock_item(char *id); #ifdef __cplusplus } diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/text.c --- a/ui/motif/text.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/text.c Wed Dec 04 18:31:22 2024 +0100 @@ -32,476 +32,3 @@ #include "text.h" #include "container.h" - -UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var) { - UiContainer *ct = uic_get_current_container(obj); - int n = 0; - Arg args[16]; - - //XtSetArg(args[n], XmNeditable, TRUE); - //n++; - XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); - n++; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget text_area = XmCreateScrolledText(parent, "text_area", args, n); - ct->add(ct, XtParent(text_area)); - XtManageChild(text_area); - - UiTextArea *uitext = cxMalloc( - obj->ctx->allocator, - sizeof(UiTextArea)); - uitext->ctx = obj->ctx; - uitext->last_selection_state = 0; - XtAddCallback( - text_area, - XmNmotionVerifyCallback, - (XtCallbackProc)ui_text_selection_callback, - uitext); - - // bind value - if(var->value) { - UiText *value = var->value; - if(value->value.ptr) { - XmTextSetString(text_area, value->value.ptr); - value->value.free(value->value.ptr); - } - - value->set = ui_textarea_set; - value->get = ui_textarea_get; - value->getsubstr = ui_textarea_getsubstr; - value->insert = ui_textarea_insert; - value->setposition = ui_textarea_setposition; - value->position = ui_textarea_position; - value->selection = ui_textarea_selection; - value->length = ui_textarea_length; - value->value.ptr = NULL; - value->obj = text_area; - - if(!value->undomgr) { - value->undomgr = ui_create_undomgr(); - } - - XtAddCallback( - text_area, - XmNmodifyVerifyCallback, - (XtCallbackProc)ui_text_modify_callback, - var); - } - - return text_area; -} - -UIWIDGET ui_textarea(UiObject *obj, UiText *value) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = value; - var->type = UI_VAR_SPECIAL; - return ui_textarea_var(obj, var); -} - -UIWIDGET ui_textarea_nv(UiObject *obj, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_TEXT); - if(var) { - return ui_textarea_var(obj, var); - } else { - // TODO: error - } - return NULL; -} - -char* ui_textarea_get(UiText *text) { - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - char *str = XmTextGetString(text->obj); - text->value.ptr = str; - text->value.free = (ui_freefunc)XtFree; - return str; -} - -void ui_textarea_set(UiText *text, const char *str) { - XmTextSetString(text->obj, str); - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - text->value.ptr = NULL; -} - -char* ui_textarea_getsubstr(UiText *text, int begin, int end) { - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - int length = end - begin; - char *str = XtMalloc(length + 1); - XmTextGetSubstring(text->obj, begin, length, length + 1, str); - text->value.ptr = str; - text->value.free = (ui_freefunc)XtFree; - return str; -} - -void ui_textarea_insert(UiText *text, int pos, char *str) { - text->value.ptr = NULL; - XmTextInsert(text->obj, pos, str); - if(text->value.ptr) { - text->value.free(text->value.ptr); - } -} - -void ui_textarea_setposition(UiText *text, int pos) { - XmTextSetInsertionPosition(text->obj, pos); -} - -int ui_textarea_position(UiText *text) { - long begin; - long end; - XmTextGetSelectionPosition(text->obj, &begin, &end); - text->pos = begin; - return text->pos; -} - -void ui_textarea_selection(UiText *text, int *begin, int *end) { - XmTextGetSelectionPosition(text->obj, (long*)begin, (long*)end); -} - -int ui_textarea_length(UiText *text) { - return (int)XmTextGetLastPosition(text->obj); -} - - -void ui_text_set(UiText *text, char *str) { - if(text->set) { - text->set(text, str); - } else { - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - text->value.ptr = XtNewString(str); - text->value.free = (ui_freefunc)XtFree; - } -} - -char* ui_text_get(UiText *text) { - if(text->get) { - return text->get(text); - } else { - return text->value.ptr; - } -} - - -UiUndoMgr* ui_create_undomgr() { - UiUndoMgr *mgr = malloc(sizeof(UiUndoMgr)); - mgr->begin = NULL; - mgr->end = NULL; - mgr->cur = NULL; - mgr->length = 0; - mgr->event = 1; - return mgr; -} - -void ui_destroy_undomgr(UiUndoMgr *mgr) { - UiTextBufOp *op = mgr->begin; - while(op) { - UiTextBufOp *nextOp = op->next; - if(op->text) { - free(op->text); - } - free(op); - op = nextOp; - } - free(mgr); -} - -void ui_text_selection_callback( - Widget widget, - UiTextArea *textarea, - XtPointer data) -{ - long left = 0; - long right = 0; - XmTextGetSelectionPosition(widget, &left, &right); - int sel = left < right ? 1 : 0; - if(sel != textarea->last_selection_state) { - if(sel) { - ui_set_group(textarea->ctx, UI_GROUP_SELECTION); - } else { - ui_unset_group(textarea->ctx, UI_GROUP_SELECTION); - } - } - textarea->last_selection_state = sel; -} - -void ui_text_modify_callback(Widget widget, UiVar *var, XtPointer data) { - UiText *value = var->value; - if(!value->obj) { - // TODO: bug, fix - return; - } - if(!value->undomgr) { - value->undomgr = ui_create_undomgr(); - } - - XmTextVerifyCallbackStruct *txv = (XmTextVerifyCallbackStruct*)data; - int type = txv->text->length > 0 ? UI_TEXTBUF_INSERT : UI_TEXTBUF_DELETE; - UiUndoMgr *mgr = value->undomgr; - if(!mgr->event) { - return; - } - - char *text = txv->text->ptr; - int length = txv->text->length; - - if(mgr->cur) { - UiTextBufOp *elm = mgr->cur->next; - if(elm) { - mgr->cur->next = NULL; - mgr->end = mgr->cur; - while(elm) { - elm->prev = NULL; - UiTextBufOp *next = elm->next; - ui_free_textbuf_op(elm); - elm = next; - } - } - - UiTextBufOp *last_op = mgr->cur; - if( - last_op->type == UI_TEXTBUF_INSERT && - ui_check_insertstr(last_op->text, last_op->len, text, length) == 0) - { - // append text to last op - int ln = last_op->len; - char *newtext = malloc(ln + length + 1); - memcpy(newtext, last_op->text, ln); - memcpy(newtext+ln, text, length); - newtext[ln+length] = '\0'; - - last_op->text = newtext; - last_op->len = ln + length; - last_op->end += length; - - return; - } - } - - char *str; - if(type == UI_TEXTBUF_INSERT) { - str = malloc(length + 1); - memcpy(str, text, length); - str[length] = 0; - } else { - length = txv->endPos - txv->startPos; - str = malloc(length + 1); - XmTextGetSubstring(value->obj, txv->startPos, length, length+1, str); - } - - UiTextBufOp *op = malloc(sizeof(UiTextBufOp)); - op->prev = NULL; - op->next = NULL; - op->type = type; - op->start = txv->startPos; - op->end = txv->endPos + 1; - op->len = length; - op->text = str; - - cx_linked_list_add( - (void**)&mgr->begin, - (void**)&mgr->end, - offsetof(UiTextBufOp, prev), - offsetof(UiTextBufOp, next), - op); - - mgr->cur = op; -} - -int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen) { - // return 1 if oldstr + newstr are one word - - int has_space = 0; - for(int i=0;i 32) { - return 1; - } - } - - return 0; -} - -void ui_free_textbuf_op(UiTextBufOp *op) { - if(op->text) { - free(op->text); - } - free(op); -} - - -void ui_text_undo(UiText *value) { - UiUndoMgr *mgr = value->undomgr; - - if(mgr->cur) { - UiTextBufOp *op = mgr->cur; - mgr->event = 0; - switch(op->type) { - case UI_TEXTBUF_INSERT: { - XmTextReplace(value->obj, op->start, op->end, ""); - break; - } - case UI_TEXTBUF_DELETE: { - XmTextInsert(value->obj, op->start, op->text); - break; - } - } - mgr->event = 1; - mgr->cur = mgr->cur->prev; - } -} - -void ui_text_redo(UiText *value) { - UiUndoMgr *mgr = value->undomgr; - - UiTextBufOp *elm = NULL; - if(mgr->cur) { - if(mgr->cur->next) { - elm = mgr->cur->next; - } - } else if(mgr->begin) { - elm = mgr->begin; - } - - if(elm) { - UiTextBufOp *op = elm; - mgr->event = 0; - switch(op->type) { - case UI_TEXTBUF_INSERT: { - XmTextInsert(value->obj, op->start, op->text); - break; - } - case UI_TEXTBUF_DELETE: { - XmTextReplace(value->obj, op->start, op->end, ""); - break; - } - } - mgr->event = 1; - mgr->cur = elm; - } -} - - -/* ------------------------- textfield ------------------------- */ - -static UIWIDGET create_textfield(UiObject *obj, int width, UiBool frameless, UiBool password, UiString *value) { - UiContainer *ct = uic_get_current_container(obj); - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNeditMode, XmSINGLE_LINE_EDIT); - n++; - if(width > 0) { - XtSetArg(args[n], XmNcolumns, width / 2 + 1); - n++; - } - if(frameless) { - XtSetArg(args[n], XmNshadowThickness, 0); - n++; - } - if(password) { - // TODO - } - - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget textfield = XmCreateText(parent, "text_field", args, n); - ct->add(ct, textfield); - XtManageChild(textfield); - - // bind value - if(value) { - if(value->value.ptr) { - XmTextSetString(textfield, value->value.ptr); - value->value.free(value->value.ptr); - } - - value->set = ui_textfield_set; - value->get = ui_textfield_get; - value->value.ptr = NULL; - value->obj = textfield; - } - - return textfield; -} - -static UIWIDGET create_textfield_nv(UiObject *obj, int width, UiBool frameless, UiBool password, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_STRING); - if(var) { - UiString *value = var->value; - return ui_textfield(obj, value); - } else { - // TODO: error - } - return NULL; -} - -UIWIDGET ui_textfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, FALSE, FALSE, value); -} - -UIWIDGET ui_textfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, FALSE, FALSE, varname); -} - -UIWIDGET ui_textfield_w(UiObject *obj, int width, UiString *value) { - return create_textfield(obj, width, FALSE, FALSE, value); -} - -UIWIDGET ui_textfield_wnv(UiObject *obj, int width, char *varname) { - return create_textfield_nv(obj, width, FALSE, FALSE, varname); -} - -UIWIDGET ui_frameless_textfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, TRUE, FALSE, value); -} - -UIWIDGET ui_frameless_textfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, TRUE, FALSE, varname); -} - -UIWIDGET ui_passwordfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, FALSE, TRUE, value); -} - -UIWIDGET ui_passwordfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, FALSE, TRUE, varname); -} - -UIWIDGET ui_passwordfield_w(UiObject *obj, int width, UiString *value) { - return create_textfield(obj, width, FALSE, TRUE, value); -} - -UIWIDGET ui_passwordfield_wnv(UiObject *obj, int width, char *varname) { - return create_textfield_nv(obj, width, FALSE, TRUE, varname); -} - - -char* ui_textfield_get(UiString *str) { - if(str->value.ptr) { - str->value.free(str->value.ptr); - } - char *value = XmTextGetString(str->obj); - str->value.ptr = value; - str->value.free = (ui_freefunc)XtFree; - return value; -} - -void ui_textfield_set(UiString *str, char *value) { - XmTextSetString(str->obj, value); - if(str->value.ptr) { - str->value.free(str->value.ptr); - } - str->value.ptr = NULL; -} - diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/text.h --- a/ui/motif/text.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/text.h Wed Dec 04 18:31:22 2024 +0100 @@ -37,54 +37,6 @@ extern "C" { #endif -#define UI_TEXTBUF_INSERT 0 -#define UI_TEXTBUF_DELETE 1 -typedef struct UiTextBufOp UiTextBufOp; -struct UiTextBufOp { - UiTextBufOp *prev; - UiTextBufOp *next; - int type; // UI_TEXTBUF_INSERT, UI_TEXTBUF_DELETE - int start; - int end; - int len; - char *text; -}; - -typedef struct UiUndoMgr { - UiTextBufOp *begin; - UiTextBufOp *end; - UiTextBufOp *cur; - int length; - int event; -} UiUndoMgr; - -typedef struct UiTextArea { - UiContext *ctx; - int last_selection_state; -} UiTextArea; - -char* ui_textarea_get(UiText *text); -void ui_textarea_set(UiText *text, const char *str); -char* ui_textarea_getsubstr(UiText *text, int begin, int end); -void ui_textarea_insert(UiText *text, int pos, char *str); -void ui_textarea_setposition(UiText *text, int pos); -int ui_textarea_position(UiText *text); -void ui_textarea_selection(UiText *text, int *begin, int *end); -int ui_textarea_length(UiText *text); - -UiUndoMgr* ui_create_undomgr(); -void ui_destroy_undomgr(UiUndoMgr *mgr); -void ui_text_selection_callback( - Widget widget, - UiTextArea *textarea, - XtPointer data); -void ui_text_modify_callback(Widget widget, UiVar *var, XtPointer data); -int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen); -void ui_free_textbuf_op(UiTextBufOp *op); - -char* ui_textfield_get(UiString *str); -void ui_textfield_set(UiString *str, char *value); - #ifdef __cplusplus } #endif diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/toolbar.c --- a/ui/motif/toolbar.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/toolbar.c Wed Dec 04 18:31:22 2024 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -42,340 +42,3 @@ #include "../common/context.h" -static CxMap *toolbar_items; -static CxList *defaults; - -void ui_toolbar_init() { - toolbar_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - defaults = cxLinkedListCreateSimple(CX_STORE_POINTERS); -} - -void ui_toolitem(char *name, char *label, ui_callback f, void *userdata) { - UiToolItem *item = malloc(sizeof(UiToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_widget; - item->label = label; - item->image = NULL; - item->callback = f; - item->userdata = userdata; - item->groups = NULL; - item->isimportant = FALSE; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_st(char *name, char *stockid, ui_callback f, void *userdata) { - ui_toolitem_stgr(name, stockid, f, userdata, -1); -} - -void ui_toolitem_stgr(char *name, char *stockid, ui_callback f, void *userdata, ...) { - UiStToolItem *item = malloc(sizeof(UiStToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_st_widget; - item->stockid = stockid; - item->callback = f; - item->userdata = userdata; - item->groups = NULL; - item->isimportant = FALSE; - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!item->groups) { - item->groups = cxArrayListCreateSimple(sizeof(int), 16); - } - cxListAdd(item->groups, &group); - } - va_end(ap); - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_img(char *name, char *label, char *img, ui_callback f, void *udata) { - // TODO - - UiToolItem *item = malloc(sizeof(UiToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_widget; - item->label = label; - item->image = img; - item->callback = f; - item->userdata = udata; - item->groups = NULL; - item->isimportant = FALSE; - - cxMapPut(toolbar_items, name, item); -} - - -void ui_toolitem_toggle_stgr(char *name, char *stockid, ui_callback f, void *udata, ...) { - // TODO - - UiStToolItem *item = malloc(sizeof(UiStToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_st_toggle_widget; - item->stockid = stockid; - item->callback = f; - item->userdata = udata; - item->groups = NULL; - item->isimportant = FALSE; - - // add groups - va_list ap; - va_start(ap, udata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!item->groups) { - item->groups = cxArrayListCreateSimple(sizeof(int), 16); - } - cxListAdd(item->groups, &group); - } - va_end(ap); - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle_imggr(char *name, char *label, char *img, ui_callback f, void *udata, ...) { - // TODO - - UiToolItem *item = malloc(sizeof(UiToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = label; - item->image = img; - item->callback = f; - item->userdata = udata; - item->groups = NULL; - item->isimportant = FALSE; - - // add groups - va_list ap; - va_start(ap, udata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!item->groups) { - item->groups = cxArrayListCreateSimple(sizeof(int), 16); - } - cxListAdd(item->groups, &group); - } - va_end(ap); - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolbar_combobox( - char *name, - UiList *list, - ui_getvaluefunc getvalue, - ui_callback f, - void *udata) -{ - UiToolbarComboBox *cb = malloc(sizeof(UiToolbarComboBox)); - cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox; - cb->list = list; - cb->getvalue = getvalue; - cb->callback = f; - cb->userdata = udata; - - cxMapPut(toolbar_items, name, cb); -} - -void ui_toolbar_combobox_str( - char *name, - UiList *list, - ui_callback f, - void *udata) -{ - ui_toolbar_combobox(name, list, ui_strmodel_getvalue, f, udata); -} - -void ui_toolbar_combobox_nv( - char *name, - char *listname, - ui_getvaluefunc getvalue, - ui_callback f, - void *udata) -{ - UiToolbarComboBoxNV *cb = malloc(sizeof(UiToolbarComboBoxNV)); - cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox_nv; - cb->listname = listname; - cb->getvalue = getvalue; - cb->callback = f; - cb->userdata = udata; - - cxMapPut(toolbar_items, name, cb); -} - - -void ui_toolbar_add_default(char *name) { - char *s = strdup(name); - cxListAdd(defaults, s); -} - -Widget ui_create_toolbar(UiObject *obj, Widget parent) { - if(!defaults) { - return NULL; - } - - Arg args[8]; - XtSetArg(args[0], XmNshadowType, XmSHADOW_ETCHED_OUT); - XtSetArg(args[1], XmNshadowThickness, 1); - XtSetArg(args[2], XmNtopAttachment, XmATTACH_FORM); - XtSetArg(args[3], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[4], XmNrightAttachment, XmATTACH_FORM); - Widget frame = XmCreateFrame(parent, "toolbar_frame", args, 5); - - XtSetArg(args[0], XmNorientation, XmHORIZONTAL); - XtSetArg(args[1], XmNpacking, XmPACK_TIGHT); - XtSetArg(args[2], XmNspacing, 1); - Widget toolbar = XmCreateRowColumn (frame, "toolbar", args, 3); - - CxIterator i = cxListIterator(defaults); - cx_foreach(char *, def, i) { - UiToolItemI *item = cxMapGet(toolbar_items, def); - if(item) { - item->add_to(toolbar, item, obj); - } else if(!strcmp(def, "@separator")) { - // TODO - } else { - fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", def); - } - } - - XtManageChild(toolbar); - XtManageChild(frame); - - return frame; -} - -void add_toolitem_widget(Widget parent, UiToolItem *item, UiObject *obj) { - Arg args[4]; - - XmString label = XmStringCreateLocalized(item->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNshadowThickness, 1); - XtSetArg(args[2], XmNtraversalOn, FALSE); - Widget button = XmCreatePushButton(parent, "toolbar_button", args, 3); - - XmStringFree(label); - - if(item->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; - XtAddCallback( - button, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - - XtManageChild(button); - - if(item->groups) { - uic_add_group_widget(obj->ctx, button, (ui_enablefunc)XtSetSensitive, item->groups); - } -} - -void add_toolitem_st_widget(Widget parent, UiStToolItem *item, UiObject *obj) { - Arg args[8]; - - UiStockItem *stock_item = ui_get_stock_item(item->stockid); - - XmString label = XmStringCreateLocalized(stock_item->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNshadowThickness, 1); - XtSetArg(args[2], XmNtraversalOn, FALSE); - Widget button = XmCreatePushButton(parent, "toolbar_button", args, 3); - - XmStringFree(label); - - if(item->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; - XtAddCallback( - button, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - - XtManageChild(button); - - if(item->groups) { - uic_add_group_widget(obj->ctx, button, (ui_enablefunc)XtSetSensitive, item->groups); - } -} - -void add_toolitem_toggle_widget(Widget parent, UiToolItem *item, UiObject *obj) { - Arg args[8]; - - XmString label = XmStringCreateLocalized(item->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNshadowThickness, 1); - XtSetArg(args[2], XmNtraversalOn, FALSE); - XtSetArg(args[3], XmNindicatorOn, XmINDICATOR_NONE); - Widget button = XmCreateToggleButton(parent, "toolbar_toggle_button", args, 4); - - XmStringFree(label); - - if(item->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; - XtAddCallback( - button, - XmNvalueChangedCallback, - (XtCallbackProc)ui_toggle_button_callback, - event); - } - - XtManageChild(button); - - if(item->groups) { - uic_add_group_widget(obj->ctx, button, (ui_enablefunc)XtSetSensitive, item->groups); - } -} - -void add_toolitem_st_toggle_widget(Widget parent, UiStToolItem *item, UiObject *obj) { - -} - -void add_toolbar_combobox(Widget tb, UiToolbarComboBox *item, UiObject *obj) { - UiListView *listview = cxMalloc( - obj->ctx->allocator, - sizeof(UiListView)); - - UiVar *var = cxMalloc(obj->ctx->allocator, sizeof(UiVar)); - var->value = item->list; - var->type = UI_VAR_SPECIAL; - - Arg args[8]; - XtSetArg(args[0], XmNshadowThickness, 1); - XtSetArg(args[1], XmNindicatorOn, XmINDICATOR_NONE); - XtSetArg(args[2], XmNtraversalOn, FALSE); - XtSetArg(args[3], XmNwidth, 120); - Widget combobox = XmCreateDropDownList(tb, "toolbar_combobox", args, 4); - XtManageChild(combobox); - listview->widget = combobox; - listview->list = var; - listview->getvalue = item->getvalue; - - ui_listview_update(NULL, listview); - - if(item->callback) { - // TODO: - - } -} - -void add_toolbar_combobox_nv(Widget tb, UiToolbarComboBoxNV *item, UiObject *obj) { - -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/toolbar.h --- a/ui/motif/toolbar.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/toolbar.h Wed Dec 04 18:31:22 2024 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -37,66 +37,6 @@ extern "C" { #endif -typedef struct UiToolItemI UiToolItemI; -typedef struct UiToolItem UiToolItem; -typedef struct UiStToolItem UiStToolItem; - -typedef struct UiToolbarComboBox UiToolbarComboBox; -typedef struct UiToolbarComboBoxNV UiToolbarComboBoxNV; - -typedef void(*ui_toolbar_add_f)(Widget, UiToolItemI*, UiObject*); - -struct UiToolItemI { - ui_toolbar_add_f add_to; -}; - -struct UiToolItem { - UiToolItemI item; - char *label; - void *image; - ui_callback callback; - void *userdata; - CxList *groups; - Boolean isimportant; -}; - -struct UiStToolItem { - UiToolItemI item; - char *stockid; - ui_callback callback; - void *userdata; - CxList *groups; - Boolean isimportant; -}; - -struct UiToolbarComboBox { - UiToolItemI item; - UiList *list; - ui_getvaluefunc getvalue; - ui_callback callback; - void *userdata; -}; - -struct UiToolbarComboBoxNV { - UiToolItemI item; - char *listname; - ui_getvaluefunc getvalue; - ui_callback callback; - void *userdata; -}; - -void ui_toolbar_init(); - -Widget ui_create_toolbar(UiObject *obj, Widget parent); - -void add_toolitem_widget(Widget tb, UiToolItem *item, UiObject *obj); -void add_toolitem_st_widget(Widget tb, UiStToolItem *item, UiObject *obj); -void add_toolitem_toggle_widget(Widget tb, UiToolItem *item, UiObject *obj); -void add_toolitem_st_toggle_widget(Widget tb, UiStToolItem *item, UiObject *obj); - -void add_toolbar_combobox(Widget tb, UiToolbarComboBox *item, UiObject *obj); -void add_toolbar_combobox_nv(Widget tb, UiToolbarComboBoxNV *item, UiObject *obj); - #ifdef __cplusplus } #endif diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/toolkit.c --- a/ui/motif/toolkit.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/toolkit.c Wed Dec 04 18:31:22 2024 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -33,15 +33,21 @@ #include "toolkit.h" #include "toolbar.h" +#include "container.h" #include "stock.h" +#include "../common/menu.h" +#include "../common/toolbar.h" #include "../common/document.h" #include "../common/properties.h" #include +#include +#include + static XtAppContext app; static Display *display; static Widget active_window; -static char *application_name; +static const char *application_name; static ui_callback startup_func; static void *startup_data; @@ -68,6 +74,11 @@ "*rt*fontType: FONT_IS_XFT", "*rt*fontName: Sans", "*rt*fontSize: 11", + + "*window_frame.shadowType: SHADOW_ETCHED_OUT", + "*window_frame.shadowThickness: 1", + "*togglebutton.shadowThickness: 1", + "*togglebutton.highlightThickness: 2", NULL }; @@ -76,8 +87,9 @@ read(event_pipe[0], &ptr, sizeof(void*)); } -void ui_init(char *appname, int argc, char **argv) { +void ui_init(const char *appname, int argc, char **argv) { application_name = appname; + uic_init_global_context(); XtToolkitInitialize(); XtSetLanguageProc(NULL, NULL, NULL); @@ -85,15 +97,10 @@ XtAppSetFallbackResources(app, fallback); display = XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv); - char **missing = NULL; - int nm = 0; - char *def = NULL; - XCreateFontSet(display, "-dt-interface system-medium-r-normal-s*utf*", &missing, &nm, &def); uic_docmgr_init(); - ui_toolbar_init(); - ui_stock_init(); - + uic_menu_init(); + uic_toolbar_init(); uic_load_app_properties(); if(pipe(event_pipe)) { @@ -108,11 +115,11 @@ NULL); } -char* ui_appname() { +const char* ui_appname() { return application_name; } -Display* ui_get_display() { +Display* ui_motif_get_display() { return display; } @@ -157,11 +164,12 @@ void ui_show(UiObject *obj) { uic_check_group_widgets(obj->ctx); XtRealizeWidget(obj->widget); - ui_window_dark_theme(XtDisplay(obj->widget), XtWindow(obj->widget)); // TODO: if } -// implemented in window.c -//void ui_close(UiObject *obj) +void ui_close(UiObject *obj) { + +} + void ui_set_enabled(UIWIDGET widget, int enabled) { XtSetSensitive(widget, enabled); @@ -182,17 +190,16 @@ } static Boolean ui_job_finished(void *data) { - printf("WorkProc\n"); UiJob *job = data; - - UiEvent event; - event.obj = job->obj; - event.window = job->obj->window; - event.document = job->obj->ctx->document; - event.intval = 0; - event.eventdata = NULL; - - job->finish_callback(&event, job->finish_data); + if(job->finish_callback) { + UiEvent event; + event.obj = job->obj; + event.window = job->obj->window; + event.document = job->obj->ctx->document; + event.intval = 0; + event.eventdata = NULL; + job->finish_callback(&event, job->finish_data); + } free(job); return TRUE; } @@ -201,7 +208,6 @@ UiJob *job = data; int result = job->job_func(job->job_data); if(!result) { - printf("XtAppAddWorkProc\n"); write(event_pipe[1], &job, sizeof(void*)); // hack XtAppAddWorkProc(app, ui_job_finished, job); @@ -221,7 +227,6 @@ } void ui_clipboard_set(char *str) { - printf("copy: {%s}\n", str); int length = strlen(str) + 1; Display *dp = XtDisplayOfObject(active_window); @@ -287,6 +292,9 @@ return active_window; } +/* + * doesn't work with gnome anymore + */ void ui_window_dark_theme(Display *dp, Window window) { Atom atom = XInternAtom(dp, "_GTK_THEME_VARIANT", False); Atom type = XInternAtom(dp, "UTF8_STRING", False); @@ -300,3 +308,23 @@ (const unsigned char*)"dark", 4); } + +void ui_destroy_eventdata(Widget w, XtPointer *data, XtPointer d) { + free(data); +} + +void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) { + if(!groups) { + return; + } + size_t ngroups = uic_group_array_size(groups); + ui_set_widget_ngroups(ctx, widget, groups, ngroups); +} + +void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups) { + if(ngroups > 0) { + uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); + ui_set_enabled(widget, FALSE); + } +} + diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/toolkit.h --- a/ui/motif/toolkit.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/toolkit.h Wed Dec 04 18:31:22 2024 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -38,8 +38,6 @@ extern "C" { #endif -Display* ui_get_display(); - typedef struct UiEventData { UiObject *obj; ui_callback callback; @@ -47,6 +45,31 @@ int value; } UiEventData; +typedef struct UiEventDataExt { + UiObject *obj; + ui_callback callback; + void *userdata; + ui_callback callback2; + void *userdata2; + int value0; + int value1; + int value2; + int value3; + void *customdata0; + void *customdata1; + void *customdata2; + void *customdata3; +} UiEventDataExt; + +typedef struct UiVarEventData { + UiObject *obj; + UiVar *var; + UiObserver **observers; + ui_callback callback; + void *userdata; + int value; +} UiVarEventData; + typedef struct UiJob { UiObject *obj; ui_threadfunc job_func; @@ -60,12 +83,19 @@ void ui_exit_mainloop(); +Display* ui_motif_get_display(void); + void ui_set_active_window(Widget w); Widget ui_get_active_window(); 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_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); + #ifdef __cplusplus } #endif diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/tree.c --- a/ui/motif/tree.c Wed Dec 04 08:57:35 2024 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,328 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2014 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 -#include -#include -#include - -#include "tree.h" - -#include "container.h" -#include "../common/object.h" -#include "../common/context.h" -#include -#include -#include - -UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) { - // TODO: check if modelinfo is complete - - Arg args[32]; - int n = 0; - - // create scrolled window - UiContainer *ct = uic_get_current_container(obj); - Widget parent = ct->prepare(ct, args, &n, TRUE); - - XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); - n++; - XtSetArg(args[n], XmNshadowThickness, 0); - n++; - Widget scrollw = XmCreateScrolledWindow(parent, "scroll_win", args, n); - ct->add(ct, scrollw); - XtManageChild(scrollw); - - // create table headers - XmStringTable header = (XmStringTable)XtMalloc( - model->columns * sizeof(XmString)); - for(int i=0;icolumns;i++) { - header[i] = XmStringCreateLocalized(model->titles[i]); - } - n = 0; - XtSetArg(args[n], XmNdetailColumnHeading, header); - n++; - XtSetArg(args[n], XmNdetailColumnHeadingCount, model->columns); - n++; - - // set res - XtSetArg(args[n], XmNlayoutType, XmDETAIL); - n++; - XtSetArg(args[n], XmNentryViewType, XmSMALL_ICON); - n++; - XtSetArg(args[n], XmNselectionPolicy, XmSINGLE_SELECT); - n++; - XtSetArg(args[n], XmNwidth, 600); - n++; - - // create widget - //UiContainer *ct = uic_get_current_container(obj); - //Widget parent = ct->add(ct, args, &n); - - Widget container = XmCreateContainer(scrollw, "table", args, n); - XtManageChild(container); - - // add callbacks - UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); - event->obj = obj; - event->activate = cb.activate; - event->selection = cb.selection; - event->userdata = cb.userdata; - event->last_selection = NULL; - if(cb.selection) { - XtAddCallback( - container, - XmNselectionCallback, - (XtCallbackProc)ui_table_select_callback, - event); - } - if(cb.activate) { - XtAddCallback( - container, - XmNdefaultActionCallback, - (XtCallbackProc)ui_table_action_callback, - event); - } - - // add initial data - UiList *list = var->value; - void *data = list->first(list); - int width = 0; - while(data) { - int w = ui_add_icon_gadget(container, model, data); - if(w > width) { - width = w; - } - data = list->next(list); - } - - UiTableView *tableview = cxMalloc(obj->ctx->allocator, sizeof(UiTableView)); - tableview->widget = container; - tableview->var = var; - tableview->model = model; - - // set new XmContainer width - XtVaSetValues(container, XmNwidth, width, NULL); - - // cleanup - for(int i=0;icolumns;i++) { - XmStringFree(header[i]); - } - XtFree((char*)header); - - return scrollw; -} - -UIWIDGET ui_table(UiObject *obj, UiList *data, UiModel *model, UiListCallbacks cb) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = data; - var->type = UI_VAR_SPECIAL; - return ui_table_var(obj, var, model, cb); -} - -void ui_table_update(UiEvent *event, UiTableView *view) { - // clear container - Widget *children; - int nc; - - XtVaGetValues( - view->widget, - XmNchildren, - &children, - XmNnumChildren, - &nc, - NULL); - - for(int i=0;ivar->value; - - void *data = list->first(list); - int width = 0; - while(data) { - int w = ui_add_icon_gadget(view->widget, view->model, data); - if(w > width) { - width = w; - } - data = list->next(list); - } - -} - -#define UI_COL_CHAR_WIDTH 12 - -int ui_add_icon_gadget(Widget container, UiModel *model, void *data) { - int width = 50; - - if(model->columns == 0) { - return width; - } - - XmString label = NULL; - Arg args[8]; - Boolean f; - // first column - if(model->types[0] != 12345678) { // TODO: icon/label type - char *str = ui_type_to_string( - model->types[0], - model->getvalue(data, 0), - &f); - - // column width - width += strlen(str) * UI_COL_CHAR_WIDTH; - - - XmString label = XmStringCreateLocalized(str); - XtSetArg(args[0], XmNlabelString, label); - if(f) { - free(str); - } - } else { - // TODO - } - - // remaining columns are the icon gadget details - XmStringTable details = (XmStringTable)XtMalloc( - (model->columns - 1) * sizeof(XmString)); - for(int i=1;icolumns;i++) { - char *str = ui_type_to_string( - model->types[i], - model->getvalue(data, i), - &f); - - // column width - width += strlen(str) * UI_COL_CHAR_WIDTH; - - details[i - 1] = XmStringCreateLocalized(str); - if(f) { - free(str); - } - } - XtSetArg(args[1], XmNdetail, details); - XtSetArg(args[2], XmNdetailCount, model->columns - 1); - XtSetArg(args[3], XmNshadowThickness, 0); - // create widget - Widget item = XmCreateIconGadget(container, "table_item", args, 4); - XtManageChild(item); - - // cleanup - XmStringFree(label); - for(int i=0;icolumns-1;i++) { - XmStringFree(details[i]); - } - XtFree((char*)details); - - return width; -} - -char* ui_type_to_string(UiModelType type, void *data, Boolean *free) { - switch(type) { - case UI_STRING: *free = FALSE; return data; - case UI_INTEGER: { - *free = TRUE; - int *val = data; - cxmutstr str = cx_asprintf("%d", *val); - return str.ptr; - } - case UI_ICON: break; // TODO - case UI_ICON_TEXT: break; // TODO - } - *free = FALSE; - return NULL; -} - -void ui_table_action_callback( - Widget widget, - UiTreeEventData *event, - XmContainerSelectCallbackStruct *sel) -{ - UiListSelection *selection = ui_list_selection(sel); - - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.eventdata = selection; - e.intval = selection->count > 0 ? selection->rows[0] : -1; - event->activate(&e, event->userdata); - - free(event->last_selection->rows); - free(event->last_selection); - event->last_selection = selection; -} - -void ui_table_select_callback( - Widget widget, - UiTreeEventData *event, - XmContainerSelectCallbackStruct *sel) -{ - UiListSelection *selection = ui_list_selection(sel); - if(!ui_compare_list_selection(selection, event->last_selection)) { - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.eventdata = selection; - e.intval = selection->count > 0 ? selection->rows[0] : -1; - event->selection(&e, event->userdata); - } - if(event->last_selection) { - free(event->last_selection->rows); - free(event->last_selection); - } - event->last_selection = selection; -} - -UiListSelection* ui_list_selection(XmContainerSelectCallbackStruct *xs) { - UiListSelection *selection = malloc(sizeof(UiListSelection)); - selection->count = xs->selected_item_count; - selection->rows = calloc(selection->count, sizeof(int)); - for(int i=0;icount;i++) { - int index; - XtVaGetValues(xs->selected_items[i], XmNpositionIndex, &index, NULL); - selection->rows[i] = index; - } - return selection; -} - -Boolean ui_compare_list_selection(UiListSelection *s1, UiListSelection *s2) { - if(!s1 || !s2) { - return FALSE; - } - if(s1->count != s2->count) { - return FALSE; - } - for(int i=0;icount;i++) { - if(s1->rows[i] != s2->rows[i]) { - return FALSE; - } - } - return TRUE; -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/tree.h --- a/ui/motif/tree.h Wed Dec 04 08:57:35 2024 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2014 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 TREE_H -#define TREE_H - -#include "../ui/tree.h" -#include "../common/context.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct UiTreeEventData { - UiObject *obj; - ui_callback activate; - ui_callback selection; - void *userdata; - UiListSelection *last_selection; -} UiTreeEventData; - -typedef struct UiTableView { - Widget widget; - UiVar *var; - UiModel *model; -} UiTableView; - -void ui_table_update(UiEvent *event, UiTableView *view); -int ui_add_icon_gadget(Widget container, UiModel *model, void *data); -char* ui_type_to_string(UiModelType type, void *data, Boolean *free); - -void ui_table_action_callback( - Widget widget, - UiTreeEventData *event, - XmContainerSelectCallbackStruct *sel); -void ui_table_select_callback( - Widget widget, - UiTreeEventData *event, - XmContainerSelectCallbackStruct *sel); - -UiListSelection* ui_list_selection(XmContainerSelectCallbackStruct *xs); - -Boolean ui_compare_list_selection(UiListSelection *s1, UiListSelection *s2); - - -#ifdef __cplusplus -} -#endif - -#endif /* TREE_H */ - diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/window.c --- a/ui/motif/window.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/window.c Wed Dec 04 18:31:22 2024 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -36,6 +36,8 @@ #include "../ui/window.h" #include "../common/context.h" +#include "Grid.h" + #include static int nwindows = 0; @@ -45,17 +47,7 @@ static void window_close_handler(Widget window, void *udata, void *cdata) { UiObject *obj = udata; - UiEvent ev; - ev.window = obj->window; - ev.document = obj->ctx->document; - ev.obj = obj; - ev.eventdata = NULL; - ev.intval = 0; - - if(obj->ctx->close_callback) { - obj->ctx->close_callback(&ev, obj->ctx->close_data); - } - // TODO: free UiObject + uic_object_destroy(obj); nwindows--; if(nwindows == 0) { @@ -63,7 +55,8 @@ } } -static UiObject* create_window(char *title, void *window_data, UiBool simple) { + +static UiObject* create_window(const char *title, void *window_data, Boolean simple) { CxMempool *mp = cxBasicMempoolCreate(256); const CxAllocator *a = mp->allocator; UiObject *obj = cxCalloc(a, 1, sizeof(UiObject)); @@ -72,23 +65,20 @@ Arg args[16]; int n = 0; - - XtSetArg(args[0], XmNtitle, title); - //XtSetArg(args[1], XmNbaseWidth, window_default_width); - //XtSetArg(args[2], XmNbaseHeight, window_default_height); - XtSetArg(args[1], XmNminWidth, 100); - XtSetArg(args[2], XmNminHeight, 50); - XtSetArg(args[3], XmNwidth, window_default_width); - XtSetArg(args[4], XmNheight, window_default_height); + XtSetArg(args[n], XmNtitle, title); n++; + XtSetArg(args[n], XmNminWidth, 100); n++; + XtSetArg(args[n], XmNminHeight, 50); n++; + XtSetArg(args[n], XmNwidth, window_default_width); n++; + XtSetArg(args[n], XmNheight, window_default_height); n++; Widget toplevel = XtAppCreateShell( - "Test123", - "abc", + ui_appname(), + "mainwindow", //applicationShellWidgetClass, vendorShellWidgetClass, - ui_get_display(), + ui_motif_get_display(), args, - 5); + n); Atom wm_delete_window; wm_delete_window = XmInternAtom( @@ -101,111 +91,30 @@ window_close_handler, obj); - // TODO: use callback - ui_set_active_window(toplevel); - Widget window = XtVaCreateManagedWidget( title, xmMainWindowWidgetClass, toplevel, NULL); - obj->widget = window; - Widget form = XtVaCreateManagedWidget( - "window_form", - xmFormWidgetClass, - window, - NULL); - Widget toolbar = NULL; - if(!simple) { - ui_create_menubar(obj); - toolbar = ui_create_toolbar(obj, form); - } - - // window content - XtSetArg(args[0], XmNshadowType, XmSHADOW_ETCHED_OUT); - XtSetArg(args[1], XmNshadowThickness, 0); - XtSetArg(args[2], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[3], XmNrightAttachment, XmATTACH_FORM); - XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM); - if(toolbar) { - XtSetArg(args[5], XmNtopAttachment, XmATTACH_WIDGET); - XtSetArg(args[6], XmNtopWidget, toolbar); - n = 7; - } else { - XtSetArg(args[5], XmNtopAttachment, XmATTACH_FORM); - n = 6; - } - Widget frame = XmCreateFrame(form, "content_frame", args, n); + // content frame + n = 0; + Widget frame = XmCreateFrame(window, "window_frame", args, n); XtManageChild(frame); - Widget content_form = XmCreateForm(frame, "content_form", NULL, 0); - XtManageChild(content_form); - obj->container = ui_box_container(obj, content_form, 0, 0, UI_BOX_VERTICAL); + Widget vbox = XtCreateManagedWidget("window_vbox", gridClass, frame, NULL, 0); + UiContainerX *container = ui_box_container(obj, vbox, UI_BOX_VERTICAL); + uic_object_push_container(obj, container); - XtManageChild(form); - obj->widget = toplevel; nwindows++; return obj; -} +} -UiObject* ui_window(char *title, void *window_data) { +UiObject* ui_window(const char *title, void *window_data) { return create_window(title, window_data, FALSE); } -UiObject* ui_simplewindow(char *title, void *window_data) { +UiObject* ui_simple_window(const char *title, void *window_data) { return create_window(title, window_data, TRUE); } - -void ui_close(UiObject *obj) { - XtDestroyWidget(obj->widget); - window_close_handler(obj->widget, obj, NULL); -} - -typedef struct FileDialogData { - int running; - char *file; -} FileDialogData; - -static void filedialog_select( - Widget widget, - FileDialogData *data, - XmFileSelectionBoxCallbackStruct *selection) -{ - char *path = NULL; - XmStringGetLtoR(selection->value, XmSTRING_DEFAULT_CHARSET, &path); - data->running = 0; - data->file = strdup(path); - XtFree(path); - XtUnmanageChild(widget); -} - -static void filedialog_cancel( - Widget widget, - FileDialogData *data, - XmFileSelectionBoxCallbackStruct *selection) - -{ - data->running = 0; - XtUnmanageChild(widget); -} - -char* ui_openfiledialog(UiObject *obj) { - Widget dialog = XmCreateFileSelectionDialog(obj->widget, "openfiledialog", NULL, 0); - XtManageChild(dialog); - - FileDialogData data; - data.running = 1; - data.file = NULL; - - XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)filedialog_select, &data); - XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)filedialog_cancel, &data); - - ui_secondary_event_loop(&data.running); - return data.file; -} - -char* ui_savefiledialog(UiObject *obj) { - return ui_openfiledialog(obj); -} diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/motif/window.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/motif/window.h Wed Dec 04 18:31:22 2024 +0100 @@ -0,0 +1,44 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 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 WINDOW_H +#define WINDOW_H + +#ifdef __cplusplus +extern "C" { +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* WINDOW_H */ + diff -r a7f18dda6baf -r 0ebf9d7b23e8 ui/ui/toolkit.h --- a/ui/ui/toolkit.h Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/ui/toolkit.h Wed Dec 04 18:31:22 2024 +0100 @@ -441,7 +441,7 @@ UIEXPORT void ui_context_destroy(UiContext *ctx); UIEXPORT void ui_object_ref(UiObject *obj); -UIEXPORT void ui_object_unref(UiObject *obj); +UIEXPORT int ui_object_unref(UiObject *obj); UIEXPORT void ui_onstartup(ui_callback f, void *userdata); UIEXPORT void ui_onopen(ui_callback f, void *userdata);