1/*
2** xgc
3**
4** choice.c
5**
6** All the generic stuff for dealing with choice widgets.
7*/
8
9#include <stdio.h>
10#include <X11/Intrinsic.h>
11#include <X11/StringDefs.h>
12#include <X11/Xaw/Form.h>
13#include <X11/Xaw/Label.h>
14#include <X11/Xaw/Toggle.h>
15
16#include "xgc.h"
17
18static void print_text_to_buffer(Widget, caddr_t, caddr_t);
19
20/* create_choice(w,info)
21** ---------------------
22** What a choice widget is:  A collection of toggle buttons placed inside
23** a form widget.  Exactly one of these toggle buttons can be "on" at
24** any given time;  the rest are "off".  "On" toggle buttons have
25** the foreground and background colors reversed.
26** Also, specifically because it comes in handy in xgc, choosing one
27** of the buttons causes a string associated with it to be printed out
28** (and interpreted).  Half of the string is global to the whole form
29** and the other half is local to each button.
30**
31** For example, pressing the "xor" button in the "function" form would
32** cause xgc to interpret the string "function xor", thus changing the
33** function in the GC to xor.
34**
35** There's also a label widget to the left of that mess, with an
36** incredibly descriptive title.
37**
38** create_choice() makes one.
39**
40** w is the form widget (already created) into which we will place the
41** toggle buttons.  info contains lots of useful information, such
42** as the names of the buttons and their strings (see xgc.h).
43*/
44
45ChoiceDesc *
46create_choice(Widget w, XgcStuff *info)
47{
48  ChoiceDesc *choice;		/* What we will return.  Contains
49				** Widget ID's of the label and toggles. */
50  int i;			/* Counter */
51  char *text;			/* Text to be interpreted when the
52				** toggle widget is selected. */
53
54  /* ArgList for the label widget */
55  static Arg labelargs[] = {
56    {XtNborderWidth,  (XtArgVal) 0},
57    {XtNjustify,      (XtArgVal) XtJustifyRight},
58    {XtNvertDistance, (XtArgVal) 4}
59  };
60
61  /* ArgList for the toggle widgets */
62  static Arg toggleargs[] = {
63    {XtNfromHoriz,     (XtArgVal) NULL},
64    {XtNfromVert,      (XtArgVal) NULL},
65    {XtNhorizDistance, (XtArgVal) 4},
66    {XtNvertDistance,  (XtArgVal) 4},
67    {XtNradioGroup,    (XtArgVal) NULL},
68    {XtNcallback,      (XtArgVal) NULL}
69  };
70
71  /* Callback list for the toggle widgets */
72  static XtCallbackRec callbacklist[] = {
73    {(XtCallbackProc)  print_text_to_buffer, NULL},
74    {NULL,                                   NULL}
75  };
76
77  /* Allocate space for the widgets and initialize choice */
78  choice = (ChoiceDesc *) XtMalloc(sizeof(ChoiceDesc));
79  choice->widgets = (WidgetList) XtMalloc(sizeof(Widget) *
80					  info->choice.num_toggles);
81  choice->size = info->choice.num_toggles;
82  choice->label = XtCreateManagedWidget(info->choice.name,labelWidgetClass,w,
83					labelargs,XtNumber(labelargs));
84
85  /* set up the toggle widgets */
86  toggleargs[5].value = (XtArgVal) callbacklist;
87  for (i = 0; i < info->choice.num_toggles; ++i) {
88    if (i == 0) {
89      /* the upper left toggle; put it next to the label
90       and don't worry about radio groups */
91      toggleargs[0].value = (XtArgVal) choice->label;
92      toggleargs[1].value = (XtArgVal) NULL;
93      toggleargs[2].value = (XtArgVal) 10;
94      toggleargs[3].value = (XtArgVal) 4;
95      toggleargs[4].value = (XtArgVal) NULL;
96    }
97    else {
98      toggleargs[4].value = (XtArgVal) choice->widgets[0];
99				/* are we starting a new row? */
100      if (info->choice.columns > 0 &&
101	  i > 1 &&
102	  (i % (info->choice.columns) == 0)) {
103	toggleargs[0].value = (XtArgVal) choice->label;
104	/* under the appropriate toggle */
105	toggleargs[1].value = (XtArgVal) choice->widgets[i - info->choice.columns];
106	toggleargs[2].value = (XtArgVal) 10;
107	toggleargs[3].value = (XtArgVal) 4;
108      }
109      else {			/* we're in the middle of a row */
110	/* to the right of the previous toggle */
111	toggleargs[0].value = (XtArgVal) choice->widgets[i - 1];
112	toggleargs[1].value = (XtArgVal) NULL;
113	toggleargs[2].value = (XtArgVal) -1; /* overlapping slightly */
114	toggleargs[3].value = (XtArgVal) 4;
115      }
116
117      if (info->choice.columns > 0 &&
118	  i >= info->choice.columns) {
119	/* correct vertical spacing */
120	toggleargs[1].value = (XtArgVal) choice->widgets[i - info->choice.columns];
121	toggleargs[3].value = (XtArgVal) -1;
122      }
123    }
124
125    /* Put the correct stuff in the text field */
126    text = (char *) XtMalloc((unsigned) (strlen(info->choice.text) +
127					 strlen((info->data)[i].text) + 3));
128    strcpy(text, info->choice.text);
129    strcat(text, " ");
130    strcat(text, (info->data)[i].text);
131    strcat(text, "\n");
132    callbacklist[0].closure = (caddr_t) text;
133
134    /* Create it finally */
135    choice->widgets[i] = XtCreateManagedWidget((info->data[i]).name,
136					       toggleWidgetClass,
137					       w,
138					       toggleargs,
139					       XtNumber(toggleargs));
140  }
141
142  /* The toggle widgets have all been created;
143  ** now make the all the same width if that's
144  ** what we want to do.                    */
145
146  if (info->choice.columns > 0) {
147    Dimension maxwidth = 0;	/* maximum width we've found */
148    Dimension width;		/* width of the current widget */
149    static Arg args[] = {	/* for getting and setting the width */
150      {XtNwidth,    (XtArgVal) NULL}
151    };
152
153    args[0].value = (XtArgVal) &width;
154
155    /* Find the maximum width of any toggle widget */
156    for (i = 0; i < info->choice.num_toggles; ++i) {
157      XtGetValues(choice->widgets[i],args,1);
158      maxwidth = max(maxwidth,width);
159    }
160
161    /* Now set them all to that width */
162    args[0].value = (XtArgVal) maxwidth;
163    for (i = 0; i < info->choice.num_toggles; ++i)
164      XtSetValues(choice->widgets[i],args,1);
165  }
166
167  /* return the list of toggles that were just created */
168  return (choice);
169}
170
171
172
173/* select_button(choice,togglenum)
174** -------------------------------
175** "Selects" the togglenumth toggle widget in the choice layout
176** represented by choice.  It simply turns the widget on, as if the
177** user had selected it, without calling any callbacks.  It's used
178** to give feedback when reading from a script.
179*/
180
181void
182select_button(ChoiceDesc *choice, int togglenum)
183{
184  static Arg toggleargs[] = {
185    {XtNstate,   (XtArgVal) True}
186  };
187
188  XtSetValues(choice->widgets[togglenum],toggleargs,XtNumber(toggleargs));
189}
190
191/* line_up_labels(descs,numdescs)
192** ------------------------------
193** descs represents a bunch of choice layouts (numdescs is the size of
194** descs).  This function sets each label in descs to the same width,
195** thus making them line up nicely since they're all on the left margin.
196*/
197
198void
199line_up_labels(ChoiceDesc *descs[], int numdescs)
200{
201  int i;			/* counter */
202  Dimension width;		/* current width */
203  Dimension maxwidth = (Dimension) 0; /* max width found */
204
205  static Arg widthargs[] = {
206    {XtNwidth,     (XtArgVal) NULL }
207  };
208
209  widthargs[0].value = (XtArgVal) &width;
210
211  /* Find the maximum width */
212  for (i = 0; i < numdescs; ++i) {
213    XtGetValues(descs[i]->label, widthargs, XtNumber(widthargs));
214    maxwidth = max(maxwidth,width);
215  }
216
217  /* Set all labels to that width */
218  widthargs[0].value = (XtArgVal) maxwidth;
219  for (i = 0; i < numdescs; ++i) {
220    XtSetValues(descs[i]->label, widthargs, XtNumber(widthargs));
221  }
222}
223
224/* choose_defaults(descs,numdescs)
225** -------------------------------
226** descs represents a bunch of choice layouts (numdescs is the size of
227** descs).  This function goes through all of descs and selects the
228** appropriate toggle widget for each one.  This includes calling
229** the callbacks associated with that widget.
230**
231** This function ends up initializing both the screen and the GC, and
232** ensures that they are consistent.
233*/
234
235void
236choose_defaults(ChoiceDesc *descs[], int numdescs)
237{
238  int i;			/* which choice layout */
239  int j;			/* which toggle within it */
240
241  for (i = 0; i < numdescs; ++i) {
242    j = 0;
243    if (i == 0)
244      j = 3;
245    select_button(descs[i],j);
246    XtCallCallbacks(descs[i]->widgets[j], XtNcallback, (caddr_t) NULL);
247  }
248}
249
250
251/* print_text_to_buffer(w,closure,call_data)
252** -----------------------------------------
253** This is also in the list of callbacks for the toggle buttons in a
254** choice widget.  It sends the string contained in closure (which
255** was set way back in create_choice()) over to interpret(), which
256** decides what to do with it.
257*/
258
259/*ARGSUSED*/
260static void
261print_text_to_buffer(
262    Widget  w,
263    caddr_t closure,           /* contains the string */
264    caddr_t call_data)
265{
266  interpret((char *) closure);          /* Gee, that was easy */
267}
268