ui/motif/list.c

Wed, 01 Jan 2025 11:39:42 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 01 Jan 2025 11:39:42 +0100
branch
newapi
changeset 427
7ead63398a50
parent 406
0ebf9d7b23e8
permissions
-rw-r--r--

implement listview (Motif)

/*
 * 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 <stdio.h>
#include <stdlib.h>

#include "container.h"

#include "list.h"
#include "../common/object.h"

UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args) {
    Arg xargs[16];
    int n = 0;
    
    UiContainerPrivate *ctn = ui_obj_container(obj);
    UI_APPLY_LAYOUT(ctn->layout, args);
    
    if(args.multiselection) {
        XtSetArg(xargs[n], XmNselectionPolicy, XmEXTENDED_SELECT); n++;
    } else {
        XtSetArg(xargs[n], XmNselectionPolicy, XmSINGLE_SELECT); n++;
    }
    
    char *name = args.name ? (char*)args.name : "listview";
    Widget parent = ctn->prepare(ctn, xargs, &n);
    Widget widget = XmCreateScrolledList(parent, name, xargs, n);
    XtManageChild(widget);
    
    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.list, args.varname, UI_VAR_LIST);
    
    UiListView *listview = malloc(sizeof(UiListView));
    memset(listview, 0, sizeof(UiListView));
    listview->obj = obj;
    listview->widget = widget;
    listview->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
    listview->var = var;
    listview->onactivate = args.onactivate;
    listview->onactivatedata = args.onactivatedata;
    listview->onselection = args.onselection;
    listview->onselectiondata = args.onselectiondata;
    
    if(var) {
        UiList *list = var->value;
        list->obj = listview;
        list->update = ui_listview_update;
        list->getselection = ui_listview_getselection;
        list->setselection = ui_listview_setselection;
        ui_listview_update(list, 0);
    }
    
    XtAddCallback(
                widget,
                XmNdestroyCallback,
                (XtCallbackProc)ui_listview_destroy,
                listview);
    
    XtAddCallback(
                widget,
                XmNdefaultActionCallback,
                (XtCallbackProc)ui_listview_activate,
                listview);
    XtAddCallback(
                widget,
                XmNextendedSelectionCallback,
                (XtCallbackProc)ui_listview_selection,
                listview);
    XtAddCallback(
                widget,
                XmNsingleSelectionCallback,
                (XtCallbackProc)ui_listview_selection,
                listview);
    
    return widget;
}

void ui_listview_destroy(Widget w, UiListView *listview, XtPointer d) {
    // TODO
}

static void list_callback(UiObject *obj, UiListSelection sel, ui_callback callback, void *userdata) {
    UiEvent event;
    event.obj = obj;
    event.window = obj->window;
    event.document = obj->ctx->document;
    event.eventdata = &sel;
    event.intval = sel.count > 0 ? sel.rows[0] : -1;
    callback(&event, userdata);
}

static void listview_save_selection(UiListView *listview, XmListCallbackStruct *cb) {
    UiListSelection sel = { cb->selected_item_count, NULL };
    if(sel.count > 0) {
        sel.rows = calloc(sel.count, sizeof(int));
        for(int i=0;i<sel.count;i++) {
            sel.rows[i] = cb->selected_item_positions[i]-1;
        }
    }
    free(listview->current_selection.rows);
    listview->current_selection = sel;
}

void ui_listview_activate(Widget w, UiListView *listview, XmListCallbackStruct *cb) {
    listview_save_selection(listview, cb);
    if(listview->onactivate) {
        list_callback(listview->obj, listview->current_selection, listview->onactivate, listview->onactivatedata);
    }
}

void ui_listview_selection(Widget w, UiListView *listview, XmListCallbackStruct *cb) {
    listview_save_selection(listview, cb);
    if(listview->onselection) {
        list_callback(listview->obj, listview->current_selection, listview->onselection, listview->onselectiondata);
    }
}

static XmStringTable 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;i<num;i++) {
        char *s = getvalue(data, 0);
        items[i] = XmStringCreateLocalized(s ? s : "");
        data = list->next(list);
    }
    
    *count = num;
    return items;
}

void ui_listview_update(UiList *list, int i) {
    UiListView *listview = list->obj;
    
    int count;
    XmStringTable items = create_stringlist(
            list,
            listview->getvalue,
            &count);
    
    XtVaSetValues(
            listview->widget,
            XmNitems, count == 0 ? NULL : items,
            XmNitemCount,
            count,
            NULL);
    
    for (int i=0;i<count;i++) {
        XmStringFree(items[i]);
    }
    XtFree((char *)items);
}

UiListSelection ui_listview_getselection(UiList *list) {
    UiListView *listview = list->obj;
    UiListSelection sel = { listview->current_selection.count, NULL };
    if(sel.count > 0) {
        sel.rows = calloc(sel.count, sizeof(int));
        memcpy(sel.rows, listview->current_selection.rows, sel.count*sizeof(int));
    }
    return sel;
}

void ui_listview_setselection(UiList *list, UiListSelection selection) {
    UiListView *listview = list->obj;
    XmListDeselectAllItems(listview->widget);
    for(int i=0;i<selection.count;i++) {
        XmListSelectPos(listview->widget, selection.rows[i]+1, False);
    }
}

void* ui_strmodel_getvalue(void *elm, int column) {
    return column == 0 ? elm : NULL;
}

mercurial