268 lines
8.2 KiB
C
268 lines
8.2 KiB
C
|
/*
|
||
|
** xgc
|
||
|
**
|
||
|
** choice.c
|
||
|
**
|
||
|
** All the generic stuff for dealing with choice widgets.
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <X11/Intrinsic.h>
|
||
|
#include <X11/StringDefs.h>
|
||
|
#include <X11/Xaw/Form.h>
|
||
|
#include <X11/Xaw/Label.h>
|
||
|
#include <X11/Xaw/Toggle.h>
|
||
|
|
||
|
#include "xgc.h"
|
||
|
|
||
|
static void print_text_to_buffer(Widget, caddr_t, caddr_t);
|
||
|
|
||
|
/* create_choice(w,info)
|
||
|
** ---------------------
|
||
|
** What a choice widget is: A collection of toggle buttons placed inside
|
||
|
** a form widget. Exactly one of these toggle buttons can be "on" at
|
||
|
** any given time; the rest are "off". "On" toggle buttons have
|
||
|
** the foreground and background colors reversed.
|
||
|
** Also, specifically because it comes in handy in xgc, choosing one
|
||
|
** of the buttons causes a string associated with it to be printed out
|
||
|
** (and interpreted). Half of the string is global to the whole form
|
||
|
** and the other half is local to each button.
|
||
|
**
|
||
|
** For example, pressing the "xor" button in the "function" form would
|
||
|
** cause xgc to interpret the string "function xor", thus changing the
|
||
|
** function in the GC to xor.
|
||
|
**
|
||
|
** There's also a label widget to the left of that mess, with an
|
||
|
** incredibly descriptive title.
|
||
|
**
|
||
|
** create_choice() makes one.
|
||
|
**
|
||
|
** w is the form widget (already created) into which we will place the
|
||
|
** toggle buttons. info contains lots of useful information, such
|
||
|
** as the names of the buttons and their strings (see xgc.h).
|
||
|
*/
|
||
|
|
||
|
ChoiceDesc *
|
||
|
create_choice(Widget w, XgcStuff *info)
|
||
|
{
|
||
|
ChoiceDesc *choice; /* What we will return. Contains
|
||
|
** Widget ID's of the label and toggles. */
|
||
|
int i; /* Counter */
|
||
|
char *text; /* Text to be interpreted when the
|
||
|
** toggle widget is selected. */
|
||
|
|
||
|
/* ArgList for the label widget */
|
||
|
static Arg labelargs[] = {
|
||
|
{XtNborderWidth, (XtArgVal) 0},
|
||
|
{XtNjustify, (XtArgVal) XtJustifyRight},
|
||
|
{XtNvertDistance, (XtArgVal) 4}
|
||
|
};
|
||
|
|
||
|
/* ArgList for the toggle widgets */
|
||
|
static Arg toggleargs[] = {
|
||
|
{XtNfromHoriz, (XtArgVal) NULL},
|
||
|
{XtNfromVert, (XtArgVal) NULL},
|
||
|
{XtNhorizDistance, (XtArgVal) 4},
|
||
|
{XtNvertDistance, (XtArgVal) 4},
|
||
|
{XtNradioGroup, (XtArgVal) NULL},
|
||
|
{XtNcallback, (XtArgVal) NULL}
|
||
|
};
|
||
|
|
||
|
/* Callback list for the toggle widgets */
|
||
|
static XtCallbackRec callbacklist[] = {
|
||
|
{(XtCallbackProc) print_text_to_buffer, NULL},
|
||
|
{NULL, NULL}
|
||
|
};
|
||
|
|
||
|
/* Allocate space for the widgets and initialize choice */
|
||
|
choice = (ChoiceDesc *) XtMalloc(sizeof(ChoiceDesc));
|
||
|
choice->widgets = (WidgetList) XtMalloc(sizeof(Widget) *
|
||
|
info->choice.num_toggles);
|
||
|
choice->size = info->choice.num_toggles;
|
||
|
choice->label = XtCreateManagedWidget(info->choice.name,labelWidgetClass,w,
|
||
|
labelargs,XtNumber(labelargs));
|
||
|
|
||
|
/* set up the toggle widgets */
|
||
|
toggleargs[5].value = (XtArgVal) callbacklist;
|
||
|
for (i = 0; i < info->choice.num_toggles; ++i) {
|
||
|
if (i == 0) {
|
||
|
/* the upper left toggle; put it next to the label
|
||
|
and don't worry about radio groups */
|
||
|
toggleargs[0].value = (XtArgVal) choice->label;
|
||
|
toggleargs[1].value = (XtArgVal) NULL;
|
||
|
toggleargs[2].value = (XtArgVal) 10;
|
||
|
toggleargs[3].value = (XtArgVal) 4;
|
||
|
toggleargs[4].value = (XtArgVal) NULL;
|
||
|
}
|
||
|
else {
|
||
|
toggleargs[4].value = (XtArgVal) choice->widgets[0];
|
||
|
/* are we starting a new row? */
|
||
|
if (info->choice.columns > 0 &&
|
||
|
i > 1 &&
|
||
|
(i % (info->choice.columns) == 0)) {
|
||
|
toggleargs[0].value = (XtArgVal) choice->label;
|
||
|
/* under the appropriate toggle */
|
||
|
toggleargs[1].value = (XtArgVal) choice->widgets[i - info->choice.columns];
|
||
|
toggleargs[2].value = (XtArgVal) 10;
|
||
|
toggleargs[3].value = (XtArgVal) 4;
|
||
|
}
|
||
|
else { /* we're in the middle of a row */
|
||
|
/* to the right of the previous toggle */
|
||
|
toggleargs[0].value = (XtArgVal) choice->widgets[i - 1];
|
||
|
toggleargs[1].value = (XtArgVal) NULL;
|
||
|
toggleargs[2].value = (XtArgVal) -1; /* overlapping slightly */
|
||
|
toggleargs[3].value = (XtArgVal) 4;
|
||
|
}
|
||
|
|
||
|
if (info->choice.columns > 0 &&
|
||
|
i >= info->choice.columns) {
|
||
|
/* correct vertical spacing */
|
||
|
toggleargs[1].value = (XtArgVal) choice->widgets[i - info->choice.columns];
|
||
|
toggleargs[3].value = (XtArgVal) -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Put the correct stuff in the text field */
|
||
|
text = (char *) XtMalloc((unsigned) (strlen(info->choice.text) +
|
||
|
strlen((info->data)[i].text) + 3));
|
||
|
strcpy(text, info->choice.text);
|
||
|
strcat(text, " ");
|
||
|
strcat(text, (info->data)[i].text);
|
||
|
strcat(text, "\n");
|
||
|
callbacklist[0].closure = (caddr_t) text;
|
||
|
|
||
|
/* Create it finally */
|
||
|
choice->widgets[i] = XtCreateManagedWidget((info->data[i]).name,
|
||
|
toggleWidgetClass,
|
||
|
w,
|
||
|
toggleargs,
|
||
|
XtNumber(toggleargs));
|
||
|
}
|
||
|
|
||
|
/* The toggle widgets have all been created;
|
||
|
** now make the all the same width if that's
|
||
|
** what we want to do. */
|
||
|
|
||
|
if (info->choice.columns > 0) {
|
||
|
Dimension maxwidth = 0; /* maximum width we've found */
|
||
|
Dimension width; /* width of the current widget */
|
||
|
static Arg args[] = { /* for getting and setting the width */
|
||
|
{XtNwidth, (XtArgVal) NULL}
|
||
|
};
|
||
|
|
||
|
args[0].value = (XtArgVal) &width;
|
||
|
|
||
|
/* Find the maximum width of any toggle widget */
|
||
|
for (i = 0; i < info->choice.num_toggles; ++i) {
|
||
|
XtGetValues(choice->widgets[i],args,1);
|
||
|
maxwidth = max(maxwidth,width);
|
||
|
}
|
||
|
|
||
|
/* Now set them all to that width */
|
||
|
args[0].value = (XtArgVal) maxwidth;
|
||
|
for (i = 0; i < info->choice.num_toggles; ++i)
|
||
|
XtSetValues(choice->widgets[i],args,1);
|
||
|
}
|
||
|
|
||
|
/* return the list of toggles that were just created */
|
||
|
return (choice);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* select_button(choice,togglenum)
|
||
|
** -------------------------------
|
||
|
** "Selects" the togglenumth toggle widget in the choice layout
|
||
|
** represented by choice. It simply turns the widget on, as if the
|
||
|
** user had selected it, without calling any callbacks. It's used
|
||
|
** to give feedback when reading from a script.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
select_button(ChoiceDesc *choice, int togglenum)
|
||
|
{
|
||
|
static Arg toggleargs[] = {
|
||
|
{XtNstate, (XtArgVal) True}
|
||
|
};
|
||
|
|
||
|
XtSetValues(choice->widgets[togglenum],toggleargs,XtNumber(toggleargs));
|
||
|
}
|
||
|
|
||
|
/* line_up_labels(descs,numdescs)
|
||
|
** ------------------------------
|
||
|
** descs represents a bunch of choice layouts (numdescs is the size of
|
||
|
** descs). This function sets each label in descs to the same width,
|
||
|
** thus making them line up nicely since they're all on the left margin.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
line_up_labels(ChoiceDesc *descs[], int numdescs)
|
||
|
{
|
||
|
int i; /* counter */
|
||
|
Dimension width; /* current width */
|
||
|
Dimension maxwidth = (Dimension) 0; /* max width found */
|
||
|
|
||
|
static Arg widthargs[] = {
|
||
|
{XtNwidth, (XtArgVal) NULL }
|
||
|
};
|
||
|
|
||
|
widthargs[0].value = (XtArgVal) &width;
|
||
|
|
||
|
/* Find the maximum width */
|
||
|
for (i = 0; i < numdescs; ++i) {
|
||
|
XtGetValues(descs[i]->label, widthargs, XtNumber(widthargs));
|
||
|
maxwidth = max(maxwidth,width);
|
||
|
}
|
||
|
|
||
|
/* Set all labels to that width */
|
||
|
widthargs[0].value = (XtArgVal) maxwidth;
|
||
|
for (i = 0; i < numdescs; ++i) {
|
||
|
XtSetValues(descs[i]->label, widthargs, XtNumber(widthargs));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* choose_defaults(descs,numdescs)
|
||
|
** -------------------------------
|
||
|
** descs represents a bunch of choice layouts (numdescs is the size of
|
||
|
** descs). This function goes through all of descs and selects the
|
||
|
** appropriate toggle widget for each one. This includes calling
|
||
|
** the callbacks associated with that widget.
|
||
|
**
|
||
|
** This function ends up initializing both the screen and the GC, and
|
||
|
** ensures that they are consistent.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
choose_defaults(ChoiceDesc *descs[], int numdescs)
|
||
|
{
|
||
|
int i; /* which choice layout */
|
||
|
int j; /* which toggle within it */
|
||
|
|
||
|
for (i = 0; i < numdescs; ++i) {
|
||
|
j = 0;
|
||
|
if (i == 0)
|
||
|
j = 3;
|
||
|
select_button(descs[i],j);
|
||
|
XtCallCallbacks(descs[i]->widgets[j], XtNcallback, (caddr_t) NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* print_text_to_buffer(w,closure,call_data)
|
||
|
** -----------------------------------------
|
||
|
** This is also in the list of callbacks for the toggle buttons in a
|
||
|
** choice widget. It sends the string contained in closure (which
|
||
|
** was set way back in create_choice()) over to interpret(), which
|
||
|
** decides what to do with it.
|
||
|
*/
|
||
|
|
||
|
/*ARGSUSED*/
|
||
|
static void
|
||
|
print_text_to_buffer(
|
||
|
Widget w,
|
||
|
caddr_t closure, /* contains the string */
|
||
|
caddr_t call_data)
|
||
|
{
|
||
|
interpret((char *) closure); /* Gee, that was easy */
|
||
|
}
|