Horizontally-Drawn RowColumn Class for Motif Library (C)?

痴心易碎 提交于 2020-05-31 04:04:32

问题


I am using the Motif Library for my job. If anybody is not familiar with this library, you can find a list of files here https://packages.ubuntu.com/xenial/amd64/libmotif-dev/filelist, as well as another question here Motif 1.2 X11 on using RowColumn widget inside a ScrolledWindow.

My issue is that the xmRowColumnWidgetClass is drawn vertically, which means it draws it column by column (starts at top left moving to bottom left, then moves right to the next column, etc.)

Doing something like this:

Widget parentWidget, rowColumn;

XtAppContext app;

parentWidget = XtVaAppInitialize(&app, "rowColumn", NULL, 0,
&argc, argv, NULL, NULL);

and then like this:

rowColumn = XtVaCreateManagedWidget("rowcolumn",
            xmRowColumnWidgetClass,
            parentWidget,
            XmNnumColumns, 3,
            XmNpacking, XmPACK_COLUMN,
            XmNspacing, 6,
            NULL);

(void) XtVaCreateManagedWidget("button 1",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 2",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 3",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 4",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 5",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 6",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 7",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 8",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 9",
xmPushButtonWidgetClass, rowColumn, NULL);

So the above code would create the Widgets like this:

button 1    button 4    button 7

button 2    button 5    button 8

button 3    button 6    button 9

My problem is that I want certain ones to be side-by-side rather than above-below.

And suppose as a way around this I specify an order like this: button 1, button 4, button 7, button 2, button 5, button 8, button 3, button 6, button 9. That would look like this:

button 1    button 2    button 3

button 4    button 5    button 6

button 7    button 8    button 9

However, if I wanted to remove a button or add a new button, this messes everything up. Let's say I remove the "button 4" from the above example, so the order is like this: button 1, button 7, button 2, button 5, button 8, button 3, button 6, button 9. That would look like this:

button 1    button 5    button 6

button 7    button 8    button 9

button 2    button 3

As you can see, practically nothing that should be side-by-side next to each other is next to each other now.

This problem also happens when you add a new button: Let's say we want to add a button 10 to the end: button 1, button 4, button 7, button 2, button 5, button 8, button 3, button 6, button 9, button 10. This would look like this:

button 1    button 5    button 9

button 4    button 8    button 10

button 7    button 3

button 2    button 6

This by far looks the worst, since adding a new button increases the normal of rows to 4 instead of 3, which changes the entire layout.


To anybody familiar with this library:

How do I create a xmRowColumnWidgetClass instance that draws horizontally (row-by-row) instead of vertically? (column-by-column)

Or, how can I extend this library and possibly make a xmHorRowColumnWidgetClass that does what I want?


Another group of examples of this library:
https://github.com/spartrekus/Motif-C-Examples
https://github.com/spartrekus/Motif-C-Examples/blob/master/rowcol.c


回答1:


Use XmForm class, and play with the constrained resources attached to the children. You can generate XmATTACH_POSITION in the child, and set a grid in the form to make it (the grid) to stretch and compress with the parent resizing. For example you can attatch the four borders of the child to a 4x3 cell imaginary grid coveing the parent (XmForm) widget and attach the children to fixed positions in the parent, so if you delete one of them, the hole is not filled by the neighbour widgets. See the doc for XmForm, IMHO is the widget you should use.

keypad.c

Below there's and example of a simple keypad usint XmForm to illustrate how the resources have to be initialized. It shows the minimum hardwired resources to touch.

/* main.c -- main program to create a keypad with an XmForm
                         widget.
 * Author: Luis Colorado <luiscoloradourcola@gmail.com>
 * Date: Tue Apr 21 16:15:28 EEST 2020
 * Copyright: (C) 2020 Luis Colorado.  All rights reserved.
 * License: BSD.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PushBG.h>

#define F(_fmt) __FILE__":%d:%s: " _fmt, __LINE__, __func__

/* XmForm has a coordinate set based on a common denominator
 * that it applies to x and y coordinates, in order to subdivide
 * the grid (that has the same subdivisions along the x axis, as
 * it has along the y axis, so in order to make a 4x3 grid we
 * calculate the MCM(3, 4) = 12 to use as the denominator to
 * divide the x and y sides of it.  This makes the coordinates 
 * to go as the drawing marks.
 *      0   4   8  12
 *      +---+---+---+  0
 *      | 1 | 2 | 3 |
 *      +---+---+---+  3
 *      | 4 | 5 | 6 |
 *      *---+---+---+  6
 *      | 7 | 8 | 9 |
 *      +---+---+---+  9
 *      | * | 0 | # |
 *      +---+---+---+ 12
 */

struct but_desc {
        int left_x, top_y;
        int right_x, bot_y;
        char *name;
        char *out;
        void (*cb)(Widget, XtPointer, XtPointer);
};

void callback(Widget w, XtPointer data, XtPointer cd);

static struct but_desc
pos_tab[] = {
    { 4, 9,  8, 12, "b0",        "0", callback, },
        { 0, 0,  4,  3, "b1",        "1", callback, },
        { 4, 0,  8,  3, "b2",        "2", callback, },
        { 8, 0, 12,  3, "b3",        "3", callback, },
        { 0, 3,  4,  6, "b4",        "4", callback, },
        { 4, 3,  8,  6, "b5",        "5", callback, },
        { 8, 3, 12,  6, "b6",        "6", callback, },
        { 0, 6,  4,  9, "b7",        "7", callback, },
        { 4, 6,  8,  9, "b8",        "8", callback, },
        { 8, 6, 12,  9, "b9",        "9", callback, },
        { 8, 9, 12, 12, "bhash",     "#", callback, },
        { 0, 9,  4, 12, "basterisk", "*", callback, },
        { 0, 0,  0,  0, NULL, NULL, },
};

int
main(int argc, char **argv)
{
        XtAppContext app_ctx;
        char *class_name = "XKeypad";

        Widget topLevel = XtVaAppInitialize(
                &app_ctx,
                class_name,
                NULL, 0, /* XrmOptionDescRec array */
                &argc, argv, /* args to main */
                NULL, /* default resources */
                NULL); /* empty list of arguments */

        if (!topLevel) {
                fprintf(stderr,
                F("Couldnt create main widget"));
                exit(EXIT_FAILURE);
        }

        char *form_name = "form";
        Widget form = XtVaCreateManagedWidget(
        form_name,
                xmFormWidgetClass,
                topLevel,
                XmNfractionBase, 12,
                NULL);

        if (!form) {
                fprintf(stderr,
                        F("Couldn't create form '%s'\n"),
                        form_name);
                exit(EXIT_FAILURE);
        }

        struct but_desc *p;
        for (p = pos_tab; p->name; ++p) {
                printf(F("Creando botón '%s'@{(%d,%d),(%d,%d)}\n"),
                        p->name, p->left_x, p->top_y, p->right_x, p->bot_y);
                Widget button =
                        XtVaCreateManagedWidget(
                                        p->name,
                                        xmPushButtonGadgetClass,
                                        form,
                                        XmNleftAttachment, XmATTACH_POSITION,
                                        XmNrightAttachment, XmATTACH_POSITION,
                                        XmNtopAttachment, XmATTACH_POSITION,
                                        XmNbottomAttachment, XmATTACH_POSITION,
                                        XmNleftPosition, p->left_x,
                                        XmNrightPosition, p->right_x,
                                        XmNtopPosition, p->top_y,
                                        XmNbottomPosition, p->bot_y,
                                        NULL, NULL);
                if (!button) {
                        fprintf(stderr,
                                F("Couldnt create button '%s'\n"),
                                p->name);
                        exit(EXIT_FAILURE);
                }
                XtAddCallback(button, XmNactivateCallback, p->cb, p);
        }

        XtRealizeWidget(topLevel);
        XtAppMainLoop(app_ctx);

} /* main */

void callback(Widget w, XtPointer p, XtPointer cd)
{
        struct but_desc *data = p;
        write(1, data->out, strlen(data->out));
}

I have added this repository with the example code below. The repository includes a Makefile and a default resources file (XKeypad).




回答2:


To make the xmRowColumnWidgetClass instance draw horizontally, add XmNorientation, XmHORIZONTAL to the code:

rowColumn = XtVaCreateManagedWidget("rowcolumn",
            xmRowColumnWidgetClass,
            parentWidget,
            XmNnumColumns, 3,
            XmNorientation, XmHORIZONTAL,
            XmNpacking, XmPACK_COLUMN,
            XmNspacing, 6,
            NULL);

This makes it draw row-by-row rather than column-by-column.

XmNnumColumns now refers to the number of rows rather than columns for some reason, but this is a separate issue and so the above code does indeed answer my original question.



来源:https://stackoverflow.com/questions/61281340/horizontally-drawn-rowcolumn-class-for-motif-library-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!