xenocara/app/xgc/choice.c
2010-10-31 19:41:34 +00:00

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 */
}