2 * xoptions.c -- Move list window, part of X front end for XBoard
4 * Copyright 2000, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
5 * ------------------------------------------------------------------------
7 * GNU XBoard is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or (at
10 * your option) any later version.
12 * GNU XBoard is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see http://www.gnu.org/licenses/. *
20 *------------------------------------------------------------------------
21 ** See the file ChangeLog for a revision history. */
23 // [HGM] this file is the counterpart of woptions.c, containing xboard popup menus
24 // similar to those of WinBoard, to set the most common options interactively.
31 #include <sys/types.h>
36 #else /* not STDC_HEADERS */
37 extern char *getenv();
40 # else /* not HAVE_STRING_H */
42 # endif /* not HAVE_STRING_H */
43 #endif /* not STDC_HEADERS */
50 #include <X11/Intrinsic.h>
51 #include <X11/StringDefs.h>
52 #include <X11/Shell.h>
53 #include <X11/Xatom.h>
54 #include <X11/Xaw/Dialog.h>
55 #include <X11/Xaw/Form.h>
56 #include <X11/Xaw/List.h>
57 #include <X11/Xaw/Label.h>
58 #include <X11/Xaw/SimpleMenu.h>
59 #include <X11/Xaw/SmeBSB.h>
60 #include <X11/Xaw/SmeLine.h>
61 #include <X11/Xaw/Box.h>
62 #include <X11/Xaw/Paned.h>
63 #include <X11/Xaw/MenuButton.h>
64 #include <X11/cursorfont.h>
65 #include <X11/Xaw/Text.h>
66 #include <X11/Xaw/AsciiText.h>
67 #include <X11/Xaw/Viewport.h>
68 #include <X11/Xaw/Toggle.h>
77 # define _(s) gettext (s)
78 # define N_(s) gettext_noop (s)
84 // [HGM] the following code for makng menu popups was cloned from the FileNamePopUp routines
86 static Widget previous = NULL;
87 static Option *currentOption;
90 SetFocus (Widget w, XtPointer data, XEvent *event, Boolean *b)
97 XtSetArg(args[0], XtNdisplayCaret, False);
98 XtSetValues(previous, args, 1);
100 XtSetArg(args[0], XtNstring, &s);
101 XtGetValues(w, args, 1);
103 XtSetArg(args[0], XtNdisplayCaret, True);
104 if(!strchr(s, '\n') && strlen(s) < 80) XtSetArg(args[1], XtNinsertPosition, strlen(s)), j++;
105 XtSetValues(w, args, j);
106 XtSetKeyboardFocus((Widget) data, w);
110 //--------------------------- Engine-specific options menu ----------------------------------
113 static Boolean browserUp;
116 GetWidgetText (Option *opt, char **buf)
119 XtSetArg(arg, XtNstring, buf);
120 XtGetValues(opt->handle, &arg, 1);
124 SetWidgetText (Option *opt, char *buf, int n)
127 XtSetArg(arg, XtNstring, buf);
128 XtSetValues(opt->handle, &arg, 1);
129 if(n >= 0) SetFocus(opt->handle, shells[n], NULL, False);
133 GetWidgetState (Option *opt, int *state)
136 XtSetArg(arg, XtNstate, state);
137 XtGetValues(opt->handle, &arg, 1);
141 SetWidgetState (Option *opt, int state)
144 XtSetArg(arg, XtNstate, state);
145 XtSetValues(opt->handle, &arg, 1);
149 SetDialogTitle (DialogClass dlg, char *title)
152 XtSetArg(args[0], XtNtitle, title);
153 XtSetValues(shells[dlg], args, 1);
157 CheckCallback (Widget ww, XtPointer data, XEvent *event, Boolean *b)
159 Widget w = currentOption[(int)(intptr_t)data].handle;
163 XtSetArg(args[0], XtNstate, &s);
164 XtGetValues(w, args, 1);
165 SetWidgetState(¤tOption[(int)(intptr_t)data], !s);
169 SpinCallback (Widget w, XtPointer client_data, XtPointer call_data)
173 char buf[MSG_SIZ], *p;
174 int j = 0; // Initialiasation is necessary because the text value may be non-numeric causing the scanf conversion to fail
175 int data = (intptr_t) client_data;
177 XtSetArg(args[0], XtNlabel, &name);
178 XtGetValues(w, args, 1);
180 GetWidgetText(¤tOption[data], &val);
181 sscanf(val, "%d", &j);
182 if (strcmp(name, _("browse")) == 0) {
184 for(r = ""; *q; q++) if(*q == '.') r = q; else if(*q == '/') r = ""; // last dot after last slash
185 if(!strcmp(r, "") && !currentCps && currentOption[data].type == FileName && currentOption[data].textValue)
186 r = currentOption[data].textValue;
188 if(XsraSelFile(shells[TransientDlg], currentOption[data].name, NULL, NULL, "", "", r,
189 currentOption[data].type == PathName ? "p" : "f", NULL, &p)) {
191 if(len && p[len-1] == '/') p[len-1] = NULLCHAR;
192 XtSetArg(args[0], XtNstring, p);
193 XtSetValues(currentOption[data].handle, args, 1);
196 SetFocus(currentOption[data].handle, shells[TransientDlg], (XEvent*) NULL, False);
199 if (strcmp(name, "+") == 0) {
200 if(++j > currentOption[data].max) return;
202 if (strcmp(name, "-") == 0) {
203 if(--j < currentOption[data].min) return;
205 snprintf(buf, MSG_SIZ, "%d", j);
206 SetWidgetText(¤tOption[data], buf, TransientDlg);
210 ComboSelect (Widget w, caddr_t addr, caddr_t index) // callback for all combo items
213 int i = ((intptr_t)addr)>>8;
214 int j = 255 & (intptr_t) addr;
216 values[i] = j; // store in temporary, for transfer at OK
218 if(currentOption[i].min & NO_GETTEXT)
219 XtSetArg(args[0], XtNlabel, ((char**)currentOption[i].textValue)[j]);
221 XtSetArg(args[0], XtNlabel, _(((char**)currentOption[i].textValue)[j]));
223 XtSetValues(currentOption[i].handle, args, 1);
225 if(currentOption[i].min & COMBO_CALLBACK && !currentCps && comboCallback) (comboCallback)(i);
229 CreateComboPopup (Widget parent, Option *option, int n)
234 char **mb = (char **) option->textValue;
236 if(mb[0] == NULL) return; // avoid empty menus, as they cause crash
237 menu = XtCreatePopupShell(option->name, simpleMenuWidgetClass,
240 XtSetArg(args[j], XtNwidth, 100); j++;
241 while (mb[i] != NULL)
243 if (option->min & NO_GETTEXT)
244 XtSetArg(args[j], XtNlabel, mb[i]);
246 XtSetArg(args[j], XtNlabel, _(mb[i]));
247 entry = XtCreateManagedWidget((String) mb[i], smeBSBObjectClass,
249 XtAddCallback(entry, XtNcallback,
250 (XtCallbackProc) ComboSelect,
251 (caddr_t)(intptr_t) (256*n+i));
256 char moveTypeInTranslations[] =
257 "<Key>Return: TypeInProc(1) \n"
258 "<Key>Escape: TypeInProc(0) \n";
261 char *translationTable[] = {
262 historyTranslations, commentTranslations, moveTypeInTranslations, ICSInputTranslations,
266 AddHandler (Option *opt, int nr)
268 XtOverrideTranslations(opt->handle, XtParseTranslationTable(translationTable[nr]));
271 //----------------------------Generic dialog --------------------------------------------
273 // cloned from Engine Settings dialog (and later merged with it)
275 Widget shells[NrOfDialogs];
276 WindowPlacement *wp[NrOfDialogs] = { NULL, &wpComment, &wpTags, NULL, NULL, NULL, NULL, &wpMoveHistory };
277 static Option *dialogOptions[NrOfDialogs];
280 DialogExists (DialogClass n)
282 return shells[n] != NULL;
286 PopDown (DialogClass n)
290 Dimension windowH, windowW; Position windowX, windowY;
291 if (!shellUp[n]) return 0;
292 if(n && wp[n]) { // remember position
294 XtSetArg(args[j], XtNx, &windowX); j++;
295 XtSetArg(args[j], XtNy, &windowY); j++;
296 XtSetArg(args[j], XtNheight, &windowH); j++;
297 XtSetArg(args[j], XtNwidth, &windowW); j++;
298 XtGetValues(shells[n], args, j);
301 wp[n]->width = windowW;
302 wp[n]->height = windowH;
305 XtPopdown(shells[n]);
306 if(n == 0) XtDestroyWidget(shells[n]);
309 MarkMenuItem(marked[n], False);
312 if(!n) currentCps = NULL; // if an Engine Settings dialog was up, we must be popping it down now
317 GenericPopDown (Widget w, XEvent *event, String *prms, Cardinal *nprms)
319 if(browserUp || dialogError) return; // prevent closing dialog when it has an open file-browse daughter
320 PopDown(prms[0][0] - '0');
324 AppendText (Option *opt, char *s)
329 GetWidgetText(opt, &v);
331 t.ptr = s; t.firstPos = 0; t.length = strlen(s); t.format = XawFmt8Bit;
332 XawTextReplace(opt->handle, len, len, &t);
337 SetColor (char *colorName, Option *box)
342 if (!appData.monoMode) {
343 vFrom.addr = (caddr_t) colorName;
344 vFrom.size = strlen(colorName);
345 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
346 if (vTo.addr == NULL) {
347 buttonColor = (Pixel) -1;
349 buttonColor = *(Pixel *) vTo.addr;
351 } else buttonColor = timerBackgroundPixel;
352 XtSetArg(args[0], XtNbackground, buttonColor);;
353 XtSetValues(box->handle, args, 1);
357 ColorChanged (Widget w, XtPointer data, XEvent *event, Boolean *b)
360 if ( (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) && *buf == '\r' )
361 RefreshColor((int)(intptr_t) data, 0);
365 GenericCallback (Widget w, XtPointer client_data, XtPointer call_data)
370 int data = (intptr_t) client_data;
372 currentOption = dialogOptions[data>>16]; data &= 0xFFFF;
374 XtSetArg(args[0], XtNlabel, &name);
375 XtGetValues(w, args, 1);
377 if (strcmp(name, _("cancel")) == 0) {
381 if (strcmp(name, _("OK")) == 0) { // save buttons imply OK
382 if(GenericReadout(currentOption, -1)) PopDown(data);
386 if(currentOption[data].type == SaveButton) GenericReadout(currentOption, -1);
387 snprintf(buf, MSG_SIZ, "option %s\n", name);
388 SendToProgram(buf, currentCps);
389 } else ((ButtonCallback*) currentOption[data].target)(data);
392 static char *oneLiner = "<Key>Return: redraw-display()\n";
395 GenericPopUp (Option *option, char *title, DialogClass dlgNr)
398 Widget popup, layout, dialog=NULL, edit=NULL, form, last, b_ok, b_cancel, leftMargin = NULL, textField = NULL;
400 int x, y, i, j, height=999, width=1, h, c, w, shrink=FALSE;
401 int win_x, win_y, maxWidth, maxTextWidth;
403 char def[MSG_SIZ], *msg;
404 static char pane[6] = "paneX";
405 Widget texts[100], forelast = NULL, anchor, widest, lastrow = NULL, browse = NULL;
406 Dimension bWidth = 50;
408 if(shellUp[dlgNr]) return 0; // already up
409 if(dlgNr && shells[dlgNr]) {
410 XtPopup(shells[dlgNr], XtGrabNone);
411 shellUp[dlgNr] = True;
415 dialogOptions[dlgNr] = option; // make available to callback
416 // post currentOption globally, so Spin and Combo callbacks can already use it
417 // WARNING: this kludge does not work for persistent dialogs, so that these cannot have spin or combo controls!
418 currentOption = option;
420 if(currentCps) { // Settings popup for engine: format through heuristic
421 int n = currentCps->nrOptions;
422 if(!n) { DisplayNote(_("Engine has no options")); currentCps = NULL; return 0; }
423 if(n > 50) width = 4; else if(n>24) width = 2; else width = 1;
424 height = n / width + 1;
425 if(n && (currentOption[n-1].type == Button || currentOption[n-1].type == SaveButton)) currentOption[n].min = SAME_ROW; // OK on same line
426 currentOption[n].type = EndMark; currentOption[n].target = NULL; // delimit list by callback-less end mark
429 XtSetArg(args[i], XtNresizable, True); i++;
430 popup = shells[dlgNr] =
431 XtCreatePopupShell(title, transientShellWidgetClass,
432 shellWidget, args, i);
435 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
436 layoutArgs, XtNumber(layoutArgs));
437 for(c=0; c<width; c++) {
440 XtCreateManagedWidget(pane, formWidgetClass, layout,
441 formArgs, XtNumber(formArgs));
443 XtSetArg(args[j], XtNfromHoriz, leftMargin); j++;
444 XtSetValues(form, args, j);
447 last = widest = NULL; anchor = lastrow;
448 for(h=0; h<height; h++) {
450 if(option[i].type == EndMark) break;
453 switch(option[i].type) {
455 snprintf(def, MSG_SIZ, "%.2f", *(float*)option[i].target);
456 option[i].value = *(float*)option[i].target;
459 if(!currentCps) option[i].value = *(int*)option[i].target;
460 snprintf(def, MSG_SIZ, "%d", option[i].value);
465 if(option[i].name[0]) {
467 XtSetArg(args[j], XtNfromVert, last); j++;
468 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
469 XtSetArg(args[j], XtNright, XtChainLeft); j++;
470 XtSetArg(args[j], XtNheight, textHeight), j++;
471 XtSetArg(args[j], XtNborderWidth, 0); j++;
472 XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++;
473 XtSetArg(args[j], XtNlabel, _(option[i].name)); j++;
475 dialog = XtCreateManagedWidget(option[i].name, labelWidgetClass, form, args, j);
476 } else texts[h] = dialog = NULL;
477 w = option[i].type == Spin || option[i].type == Fractional ? 70 : option[i].max ? option[i].max : 205;
478 if(option[i].type == FileName || option[i].type == PathName) w -= 55;
480 XtSetArg(args[j], XtNfromVert, last); j++;
481 XtSetArg(args[j], XtNfromHoriz, dialog); j++;
482 XtSetArg(args[j], XtNborderWidth, 1); j++;
483 XtSetArg(args[j], XtNwidth, w); j++;
484 if(option[i].type == TextBox && option[i].min) {
485 XtSetArg(args[j], XtNheight, option[i].min); j++;
486 if(option[i].value & 1) { XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++; }
487 if(option[i].value & 2) { XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollAlways); j++; }
488 if(option[i].value & 4) { XtSetArg(args[j], XtNautoFill, True); j++; }
489 if(option[i].value & 8) { XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++; }
490 } else shrink = TRUE;
491 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
492 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
493 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
494 XtSetArg(args[j], XtNdisplayCaret, False); j++;
495 XtSetArg(args[j], XtNright, XtChainRight); j++;
496 XtSetArg(args[j], XtNresizable, True); j++;
497 XtSetArg(args[j], XtNinsertPosition, 9999); j++;
498 XtSetArg(args[j], XtNstring, option[i].type==Spin || option[i].type==Fractional ? def :
499 currentCps ? option[i].textValue : *(char**)option[i].target); j++;
501 option[i].handle = (void*)
502 (textField = last = XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j));
503 XtAddEventHandler(last, ButtonPressMask, False, SetFocus, (XtPointer) popup);
504 if(option[i].min == 0 || option[i].type != TextBox)
505 XtOverrideTranslations(last, XtParseTranslationTable(oneLiner));
507 if(option[i].type == TextBox || option[i].type == Fractional) break;
509 // add increment and decrement controls for spin
511 XtSetArg(args[j], XtNfromVert, edit); j++;
512 XtSetArg(args[j], XtNfromHoriz, last); j++;
513 XtSetArg(args[j], XtNleft, XtChainRight); j++;
514 XtSetArg(args[j], XtNright, XtChainRight); j++;
515 if(option[i].type == FileName || option[i].type == PathName) {
516 msg = _("browse"); w = 0;
517 /* automatically scale to width of text */
518 XtSetArg(args[j], XtNwidth, (XtArgVal) NULL ); j++;
519 if(textHeight) XtSetArg(args[j], XtNheight, textHeight), j++;
522 XtSetArg(args[j], XtNheight, textHeight/2); j++;
523 XtSetArg(args[j], XtNwidth, w); j++;
525 edit = XtCreateManagedWidget(msg, commandWidgetClass, form, args, j);
526 XtAddCallback(edit, XtNcallback, SpinCallback, (XtPointer)(intptr_t) i);
527 if(w == 0) browse = edit;
529 if(option[i].type != Spin) break;
532 XtSetArg(args[j], XtNfromVert, edit); j++;
533 XtSetArg(args[j], XtNfromHoriz, last); j++;
534 XtSetArg(args[j], XtNvertDistance, -1); j++;
535 XtSetArg(args[j], XtNheight, textHeight/2); j++;
536 XtSetArg(args[j], XtNwidth, 20); j++;
537 XtSetArg(args[j], XtNleft, XtChainRight); j++;
538 XtSetArg(args[j], XtNright, XtChainRight); j++;
539 last = XtCreateManagedWidget("-", commandWidgetClass, form, args, j);
540 XtAddCallback(last, XtNcallback, SpinCallback, (XtPointer)(intptr_t) i);
543 if(!currentCps) option[i].value = *(Boolean*)option[i].target;
545 XtSetArg(args[j], XtNfromVert, last); j++;
546 XtSetArg(args[j], XtNvertDistance, (textHeight+2)/4 + 3); j++;
547 XtSetArg(args[j], XtNwidth, textHeight/2); j++;
548 XtSetArg(args[j], XtNheight, textHeight/2); j++;
549 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
550 XtSetArg(args[j], XtNright, XtChainLeft); j++;
551 XtSetArg(args[j], XtNstate, option[i].value); j++;
552 option[i].handle = (void*)
553 (dialog = XtCreateManagedWidget(" ", toggleWidgetClass, form, args, j));
555 msg = option[i].name;
556 if(*msg == NULLCHAR) msg = option[i].textValue;
559 XtSetArg(args[j], XtNfromVert, last); j++;
560 XtSetArg(args[j], XtNfromHoriz, option[i].type != Label ? dialog : NULL); j++;
561 if(option[i].type != Label) XtSetArg(args[j], XtNheight, textHeight), j++, shrink = TRUE;
562 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
563 XtSetArg(args[j], XtNborderWidth, 0); j++;
564 XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++;
565 XtSetArg(args[j], XtNlabel, _(msg)); j++;
566 last = XtCreateManagedWidget(msg, labelWidgetClass, form, args, j);
567 if(option[i].type == CheckBox)
568 XtAddEventHandler(last, ButtonPressMask, False, CheckCallback, (XtPointer)(intptr_t) i);
573 if(option[i].min & SAME_ROW) {
574 XtSetArg(args[j], XtNfromVert, lastrow); j++;
575 XtSetArg(args[j], XtNfromHoriz, last); j++;
576 XtSetArg(args[j], XtNleft, XtChainRight); j++;
577 XtSetArg(args[j], XtNright, XtChainRight); j++;
578 if(shrink) XtSetArg(args[j], XtNheight, textHeight), j++;
580 XtSetArg(args[j], XtNfromVert, last); j++;
581 XtSetArg(args[j], XtNfromHoriz, NULL); j++; lastrow = forelast;
584 XtSetArg(args[j], XtNlabel, _(option[i].name)); j++;
585 if(option[i].max) { XtSetArg(args[j], XtNwidth, option[i].max); j++; }
586 if(option[i].textValue) { // special for buttons of New Variant dialog
587 XtSetArg(args[j], XtNsensitive, appData.noChessProgram || option[i].value < 0
588 || strstr(first.variants, VariantName(option[i].value))); j++;
589 XtSetArg(args[j], XtNborderWidth, (gameInfo.variant == option[i].value)+1); j++;
591 option[i].handle = (void*)
592 (dialog = last = XtCreateManagedWidget(option[i].name, commandWidgetClass, form, args, j));
593 if(option[i].choice && ((char*)option[i].choice)[0] == '#' && !currentCps) {
594 SetColor( *(char**) option[i-1].target, &option[i]);
595 XtAddEventHandler(option[i-1].handle, KeyReleaseMask, False, ColorChanged, (XtPointer)(intptr_t) i-1);
597 XtAddCallback(last, XtNcallback, GenericCallback,
598 (XtPointer)(intptr_t) i + (dlgNr<<16));
599 if(option[i].textValue) SetColor( option[i].textValue, &option[i]);
600 forelast = lastrow; // next button can go on same row
604 XtSetArg(args[j], XtNfromVert, last); j++;
605 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
606 XtSetArg(args[j], XtNright, XtChainLeft); j++;
607 XtSetArg(args[j], XtNheight, textHeight), j++;
608 XtSetArg(args[j], XtNborderWidth, 0); j++;
609 XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++;
610 XtSetArg(args[j], XtNlabel, _(option[i].name)); j++;
611 texts[h] = dialog = XtCreateManagedWidget(option[i].name, labelWidgetClass, form, args, j);
613 if(currentCps) option[i].choice = (char**) option[i].textValue; else {
614 for(j=0; option[i].choice[j]; j++)
615 if(*(char**)option[i].target && !strcmp(*(char**)option[i].target, option[i].choice[j])) break;
616 option[i].value = j + (option[i].choice[j] == NULL);
620 XtSetArg(args[j], XtNfromVert, last); j++;
621 XtSetArg(args[j], XtNfromHoriz, dialog); j++;
622 XtSetArg(args[j], XtNwidth, option[i].max && !currentCps ? option[i].max : 100); j++;
623 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
624 XtSetArg(args[j], XtNmenuName, XtNewString(option[i].name)); j++;
625 XtSetArg(args[j], XtNlabel, _(((char**)option[i].textValue)[option[i].value])); j++;
626 XtSetArg(args[j], XtNheight, textHeight), j++;
628 option[i].handle = (void*)
629 (last = XtCreateManagedWidget(" ", menuButtonWidgetClass, form, args, j));
630 CreateComboPopup(last, option + i, i);
631 values[i] = option[i].value;
638 printf("GenericPopUp: unexpected case in switch.\n");
643 // make an attempt to align all spins and textbox controls
644 maxWidth = maxTextWidth = 0;
647 XtSetArg(args[j], XtNwidth, &bWidth); j++;
648 XtGetValues(browse, args, j);
650 for(h=0; h<height; h++) {
652 if(option[i].type == EndMark) break;
653 if(option[i].type == Spin || option[i].type == TextBox || option[i].type == ComboBox
654 || option[i].type == PathName || option[i].type == FileName) {
656 if(!texts[h]) continue;
658 XtSetArg(args[j], XtNwidth, &w); j++;
659 XtGetValues(texts[h], args, j);
660 if(option[i].type == Spin) {
661 if(w > maxWidth) maxWidth = w;
664 if(w > maxTextWidth) maxTextWidth = w;
665 if(!widest) widest = texts[h];
669 if(maxTextWidth + 110 < maxWidth)
670 maxTextWidth = maxWidth - 110;
671 else maxWidth = maxTextWidth + 110;
672 for(h=0; h<height; h++) {
674 if(option[i].type == EndMark) break;
675 if(!texts[h]) continue; // Note: texts[h] can be undefined (giving errors in valgrind), but then both if's below will be false.
677 if(option[i].type == Spin) {
678 XtSetArg(args[j], XtNwidth, maxWidth); j++;
679 XtSetValues(texts[h], args, j);
681 if(option[i].type == TextBox || option[i].type == ComboBox || option[i].type == PathName || option[i].type == FileName) {
682 XtSetArg(args[j], XtNwidth, maxTextWidth); j++;
683 XtSetValues(texts[h], args, j);
684 if(bWidth != 50 && (option[i].type == FileName || option[i].type == PathName)) {
685 int tWidth = (option[i].max ? option[i].max : 205) - 5 - bWidth;
687 XtSetArg(args[j], XtNwidth, tWidth); j++;
688 XtSetValues(option[i].handle, args, j);
694 if(!(option[i].min & NO_OK)) {
696 if(option[i].min & SAME_ROW) {
697 for(j=i-1; option[j+1].min & SAME_ROW && option[j].type == Button; j--) {
698 XtSetArg(args[0], XtNtop, XtChainBottom);
699 XtSetArg(args[1], XtNbottom, XtChainBottom);
700 XtSetValues(option[j].handle, args, 2);
702 if(option[j].type == TextBox && option[j].name[0] == NULLCHAR) {
703 XtSetArg(args[0], XtNbottom, XtChainBottom);
704 XtSetValues(option[j].handle, args, 1);
707 XtSetArg(args[j], XtNfromHoriz, last); last = forelast;
708 } else shrink = FALSE,
709 XtSetArg(args[j], XtNfromHoriz, widest ? widest : dialog); j++;
710 XtSetArg(args[j], XtNfromVert, anchor ? anchor : last); j++;
711 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
712 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
713 XtSetArg(args[j], XtNleft, XtChainRight); j++;
714 XtSetArg(args[j], XtNright, XtChainRight); j++;
715 if(shrink) XtSetArg(args[j], XtNheight, textHeight), j++;
716 b_ok = XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j);
717 XtAddCallback(b_ok, XtNcallback, GenericCallback, (XtPointer)(intptr_t) dlgNr + (dlgNr<<16));
719 XtSetArg(args[0], XtNfromHoriz, b_ok);
720 b_cancel = XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
721 XtAddCallback(b_cancel, XtNcallback, GenericCallback, (XtPointer)(intptr_t) dlgNr);
724 XtRealizeWidget(popup);
725 XSetWMProtocols(xDisplay, XtWindow(popup), &wm_delete_window, 1);
726 snprintf(def, MSG_SIZ, "<Message>WM_PROTOCOLS: GenericPopDown(\"%d\") \n", dlgNr);
727 XtAugmentTranslations(popup, XtParseTranslationTable(def));
728 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
729 &x, &y, &win_x, &win_y, &mask);
731 XtSetArg(args[0], XtNx, x - 10);
732 XtSetArg(args[1], XtNy, y - 30);
733 XtSetValues(popup, args, 2);
735 XtPopup(popup, dlgNr ? XtGrabNone : XtGrabExclusive);
736 shellUp[dlgNr] = True;
738 if(textField)SetFocus(textField, popup, (XEvent*) NULL, False);
739 if(dlgNr && wp[dlgNr] && wp[dlgNr]->width > 0) { // if persistent window-info available, reposition
741 XtSetArg(args[j], XtNheight, (Dimension) (wp[dlgNr]->height)); j++;
742 XtSetArg(args[j], XtNwidth, (Dimension) (wp[dlgNr]->width)); j++;
743 XtSetArg(args[j], XtNx, (Position) (wp[dlgNr]->x)); j++;
744 XtSetArg(args[j], XtNy, (Position) (wp[dlgNr]->y)); j++;
745 XtSetValues(popup, args, j);
751 /* function called when the data to Paste is ready */
753 SendTextCB (Widget w, XtPointer client_data, Atom *selection,
754 Atom *type, XtPointer value, unsigned long *len, int *format)
756 char buf[MSG_SIZ], *p = (char*) textOptions[(int)(intptr_t) client_data].choice, *name = (char*) value, *q;
757 if (value==NULL || *len==0) return; /* nothing selected, abort */
759 strncpy(buf, p, MSG_SIZ);
760 q = strstr(p, "$name");
761 snprintf(buf + (q-p), MSG_SIZ -(q-p), "%s%s", name, q+5);
769 char *p = (char*) textOptions[n].choice;
770 if(strstr(p, "$name")) {
771 XtGetSelectionValue(menuBarWidget,
772 XA_PRIMARY, XA_STRING,
773 /* (XtSelectionCallbackProc) */ SendTextCB,
774 (XtPointer) (intptr_t) n, /* client_data passed to PastePositionCB */
777 } else SendString(p);
781 SetInsertPos (Option *opt, int pos)
784 XtSetArg(args[0], XtNinsertPosition, pos);
785 XtSetValues(opt->handle, args, 1);
786 // SetFocus(opt->handle, shells[InputBoxDlg], NULL, False); // No idea why this does not work, and the following is needed:
787 XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime);
791 TypeInProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
795 if(prms[0][0] == '1') {
796 GetWidgetText(&boxOptions[0], &val);
797 TypeInDoneEvent(val);
799 PopDown(TransientDlg);
803 HardSetFocus (Option *opt)
805 XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime);