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