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