Added CreateTimer
[grace.git] / src / motif.c
blobca7ed7e9a4093593a428b98938d224d9245bd7fc
1 /*
2 * Grace - GRaphing, Advanced Computation and Exploration of data
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
6 * Copyright (c) 2012 Grace Development Team
8 * Maintained by Evgeny Stambulchik
11 * All Rights Reserved
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 /* Motif widgets */
30 #include "widgets.h"
32 #include "events.h"
33 #include "utils.h"
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <Xm/Xm.h>
38 #include <Xm/ArrowBG.h>
39 #include <Xm/CascadeBG.h>
40 #include <Xm/DialogS.h>
41 #include <Xm/FileSB.h>
42 #include <Xm/Form.h>
43 #include <Xm/Frame.h>
44 #include <Xm/Label.h>
45 #include <Xm/LabelG.h>
47 #if XmVersion >= 2000
48 # define USE_PANEDW 1
49 # include <Xm/PanedW.h>
50 #else
51 # define USE_PANEDW 0
52 #endif
54 #include <Xm/PushB.h>
55 #include <Xm/RowColumn.h>
56 #include <Xm/Separator.h>
57 #include <Xm/Scale.h>
58 #include <Xm/ScrolledW.h>
59 #include <Xm/Text.h>
60 #include <Xm/ToggleB.h>
61 #include "Tab.h"
62 #include "ListTree.h"
64 #include "globals.h"
66 /* Widgets */
67 void WidgetManage(Widget w)
69 XtManageChild(w);
72 void WidgetUnmanage(Widget w)
74 XtUnmanageChild(w);
77 int WidgetIsManaged(Widget w)
79 return (XtIsManaged(w) == True) ? TRUE:FALSE;
82 void *WidgetGetUserData(Widget w)
84 void *udata = NULL;
85 XtVaGetValues(w, XmNuserData, &udata, NULL);
87 return udata;
90 void WidgetSetUserData(Widget w, void *udata)
92 XtVaSetValues(w, XmNuserData, udata, NULL);
95 void WidgetSetSensitive(Widget w, int onoff)
97 XtSetSensitive(w, onoff ? True : False);
100 void WidgetSetFocus(Widget w)
102 XmProcessTraversal(w, XmTRAVERSE_CURRENT);
105 void WidgetSetWidth(Widget w, unsigned int width)
107 XtVaSetValues(w, XmNwidth, (Dimension) width, NULL);
110 void WidgetSetHeight(Widget w, unsigned int height)
112 XtVaSetValues(w, XmNheight, (Dimension) height, NULL);
115 void WidgetSetSize(Widget w, unsigned int width, unsigned int height)
117 XtVaSetValues(w,
118 XmNwidth, (Dimension) width,
119 XmNheight, (Dimension) height,
120 NULL);
123 void WidgetGetSize(Widget w, unsigned int *width, unsigned int *height)
125 Dimension ww, wh;
127 XtVaGetValues(w,
128 XmNwidth, &ww,
129 XmNheight, &wh,
130 NULL);
132 *width = (unsigned int) ww;
133 *height = (unsigned int) wh;
136 static int toolkit_modifiers_to_grace_modifiers(void *event)
138 XEvent *e = (XEvent *) event;
139 unsigned int state;
140 int modifiers = NO_MODIFIER;
142 switch (e->type) {
143 case ButtonPress:
144 case ButtonRelease:
145 state = e->xbutton.state;
146 break;
147 case KeyPress:
148 case KeyRelease:
149 state = e->xkey.state;
150 break;
151 default:
152 return modifiers;
155 if (state & ControlMask) {
156 modifiers = modifiers ^ CONTROL_MODIFIER;
159 if (state & ShiftMask) {
160 modifiers = modifiers ^ SHIFT_MODIFIER;
163 return modifiers;
166 static int toolkit_key_to_grace_key(void *event)
168 XKeyEvent *xke = (XKeyEvent *) event;
169 KeySym keybuf;
171 keybuf = XLookupKeysym(xke, 0);
173 switch (keybuf) {
174 case XK_e: /* e */
175 return KEY_E;
176 case XK_Up: /* Up */
177 return KEY_UP;
178 case XK_Down: /* Down */
179 return KEY_DOWN;
180 default:
181 return KEY_NONE;
185 static int toolkit_button_to_grace_button(void *event)
187 XButtonEvent *xbe = (XButtonEvent *) event;
189 switch (xbe->button) {
190 case Button4:
191 return WHEEL_UP_BUTTON;
192 case Button5:
193 return WHEEL_DOWN_BUTTON;
194 default:
195 return NO_BUTTON;
199 static int toolkit_to_grace(void *event)
201 XEvent *e = (XEvent *) event;
203 switch (e->type) {
204 case ButtonPress:
205 case ButtonRelease:
206 return toolkit_button_to_grace_button(event);
207 case KeyPress:
208 case KeyRelease:
209 return toolkit_key_to_grace_key(event);
210 default:
211 return KEY_NONE;
215 static void action(Widget w, XEvent *event, String *par, Cardinal *npar)
219 static void keyHook(Widget w, XtPointer client_data, String action_name,
220 XEvent *event, String *params, Cardinal *num_params)
222 Key_CBData *cbdata = (Key_CBData *) client_data;
224 if (strcmp(action_name, "action")) return;
226 /* In case if we have the same widget */
227 if (cbdata->key != toolkit_to_grace(event)) return;
228 if (cbdata->modifiers != toolkit_modifiers_to_grace_modifiers(event)) return;
230 if (w != cbdata->w) return;
232 cbdata->cbproc(cbdata->anydata);
235 extern XtAppContext app_con;
237 void AddWidgetKeyPressCB(Widget w, int key, Key_CBProc cbproc, void *anydata)
239 AddWidgetKeyPressCB2(w, NO_MODIFIER, key, cbproc, anydata);
242 void AddWidgetKeyPressCB2(Widget w, int modifiers, int key, Key_CBProc cbproc, void *anydata)
244 char *table = NULL;
245 XtActionsRec actions[1];
246 Key_CBData *cbdata;
248 cbdata = (Key_CBData *) xmalloc(sizeof(Key_CBData));
249 cbdata->w = w;
250 cbdata->modifiers = modifiers;
251 cbdata->key = key;
252 cbdata->cbproc = cbproc;
253 cbdata->anydata = anydata;
255 modifiers = modifiers ^ NO_MODIFIER;
257 if (modifiers & CONTROL_MODIFIER) {
258 table = copy_string(table, "Ctrl");
261 switch (key) {
262 case KEY_E:
263 table = concat_strings(table, "<Key>E: action()");
264 break;
265 case KEY_UP:
266 table = concat_strings(table, "<Key>osfUp: action()");
267 break;
268 case KEY_DOWN:
269 table = concat_strings(table, "<Key>osfDown: action()");
270 break;
271 default:
272 return;
275 actions[0].string = "action";
276 actions[0].proc = action;
278 XtOverrideTranslations(w, XtParseTranslationTable(table));
279 XtAppAddActions(app_con, actions, XtNumber(actions));
280 XtAppAddActionHook(app_con, keyHook, cbdata);
282 xfree(table);
285 void AddWidgetButtonPressCB(Widget w, int button, Key_CBProc cbproc, void *anydata)
287 char *table = NULL;
288 XtActionsRec actions[1];
289 Key_CBData *cbdata;
291 cbdata = (Key_CBData *) xmalloc(sizeof(Key_CBData));
292 cbdata->w = w;
293 cbdata->modifiers = NO_MODIFIER;
294 cbdata->key = button;
295 cbdata->cbproc = cbproc;
296 cbdata->anydata = anydata;
298 switch (button) {
299 case WHEEL_UP_BUTTON:
300 table = concat_strings(table, "<Btn4Down>: action()");
301 break;
302 case WHEEL_DOWN_BUTTON:
303 table = concat_strings(table, "<Btn5Down>: action()");
304 break;
305 default:
306 return;
309 actions[0].string = "action";
310 actions[0].proc = action;
312 XtOverrideTranslations(w, XtParseTranslationTable(table));
313 XtAppAddActions(app_con, actions, XtNumber(actions));
314 XtAppAddActionHook(app_con, keyHook, cbdata);
316 xfree(table);
319 static void widgetCB(Widget w, XtPointer client_data, XtPointer call_data)
321 Widget_CBData *cbdata = (Widget_CBData *) client_data;
323 cbdata->calldata = call_data;
325 cbdata->cbproc(cbdata);
328 void AddWidgetCB(Widget w, const char *callback, Widget_CBProc cbproc, void *anydata)
330 char *cb;
331 Widget_CBData *cbdata;
333 cbdata = (Widget_CBData *) xmalloc(sizeof(Widget_CBData));
334 cbdata->w = w;
335 cbdata->cbproc = cbproc;
336 cbdata->anydata = anydata;
338 cb = copy_string(NULL, callback);
339 cb = concat_strings(cb, "Callback");
341 XtAddCallback(w, cb, widgetCB, (XtPointer) cbdata);
343 xfree(cb);
346 static char *label_to_resname(const char *s, const char *suffix)
348 char *retval, *rs;
349 int capitalize = FALSE;
351 retval = copy_string(NULL, s);
352 rs = retval;
353 while (*s) {
354 if (isalnum(*s)) {
355 if (capitalize == TRUE) {
356 *rs = toupper(*s);
357 capitalize = FALSE;
358 } else {
359 *rs = tolower(*s);
361 rs++;
362 } else {
363 capitalize = TRUE;
365 s++;
367 *rs = '\0';
368 if (suffix != NULL) {
369 retval = concat_strings(retval, suffix);
371 return retval;
374 /* Dialog Window */
375 static void close_dialogCB(Widget_CBData *wcbdata)
377 WidgetUnmanage(wcbdata->anydata);
380 Widget CreateDialogWindow(Widget parent, const char *s)
382 Widget dialog;
383 char *bufp;
385 bufp = label_to_resname(s, "Dialog");
386 dialog = XmCreateDialogShell(parent, bufp, NULL, 0);
387 xfree(bufp);
389 AddWindowCloseCB(dialog, close_dialogCB, dialog);
391 bufp = copy_string(NULL, "Grace: ");
392 bufp = concat_strings(bufp, s);
393 XtVaSetValues(dialog, XmNtitle, bufp, NULL);
394 xfree(bufp);
396 return dialog;
399 /* Dialog */
400 Widget CreateDialog(Widget parent, const char *s)
402 Widget w;
404 w = CreateDialogWindow(parent, s);
405 w = CreateForm(w);
407 return w;
410 void DialogRaise(Widget form)
412 Widget w = XtParent(form);
414 WidgetManage(w);
415 XMapRaised(XtDisplay(w), XtWindow(w));
418 void DialogClose(Widget form)
420 WidgetUnmanage(XtParent(form));
423 void DialogSetResizable(Widget form, int onoff)
425 XtVaSetValues(form,
426 XmNresizePolicy, onoff ? XmRESIZE_ANY:XmRESIZE_NONE,
427 NULL);
428 XtVaSetValues(XtParent(form),
429 XmNallowShellResize, onoff ? True:False,
430 NULL);
433 /* File selection box */
434 Widget CreateFileSelectionBox(Widget parent)
436 Widget w;
438 w = XmCreateFileSelectionBox(parent, "FSB", NULL, 0);
440 AddMouseWheelSupport(XmFileSelectionBoxGetChild(w, XmDIALOG_LIST));
441 AddMouseWheelSupport(XmFileSelectionBoxGetChild(w, XmDIALOG_DIR_LIST));
443 return w;
446 /* File selection filter */
447 #if XmVersion >= 2000
448 static void show_hidden_cb(Widget but, int onoff, void *data)
450 Widget fsb = (Widget) data;
451 XtVaSetValues(fsb, XmNfileFilterStyle,
452 onoff ? XmFILTER_NONE:XmFILTER_HIDDEN_FILES, NULL);
454 #endif
456 void CreateFileSelectionFilter(Widget parent, Widget fsb)
458 #if XmVersion >= 2000
459 Widget button;
461 button = CreateToggleButton(parent, "Show hidden files");
462 AddToggleButtonCB(button, show_hidden_cb, fsb);
463 XtVaSetValues(fsb, XmNfileFilterStyle, XmFILTER_HIDDEN_FILES, NULL);
464 #endif
467 /* File selection dialog */
468 static XmStringCharSet charset = XmFONTLIST_DEFAULT_TAG;
470 static char *GetStringSimple(XmString xms)
472 char *s;
474 if (XmStringGetLtoR(xms, charset, &s)) {
475 return s;
476 } else {
477 return NULL;
481 static void fsb_setcwd_cb(Widget but, void *data)
483 char *bufp;
484 XmString directory;
485 Widget fsb = (Widget) data;
487 XtVaGetValues(fsb, XmNdirectory, &directory, NULL);
488 bufp = GetStringSimple(directory);
489 XmStringFree(directory);
490 if (bufp != NULL) {
491 set_workingdir(gapp, bufp);
492 XtFree(bufp);
496 #define FSB_CWD 0
497 #define FSB_HOME 1
498 #define FSB_ROOT 2
499 #define FSB_CYGDRV 3
501 static void fsb_cd_cb(OptionStructure *opt, int value, void *data)
503 char *dir;
504 FSBStructure *fsb = (FSBStructure *) data;
506 switch (value) {
507 case FSB_CWD:
508 dir = get_workingdir(gapp);
509 break;
510 case FSB_HOME:
511 dir = grace_get_userhome(gapp->grace);
512 break;
513 case FSB_ROOT:
514 dir = "/";
515 break;
516 case FSB_CYGDRV:
517 dir = "/cygdrive/";
518 break;
519 default:
520 return;
523 FSBDialogSetDirectory(fsb, dir);
526 static OptionItem fsb_items[] = {
527 {FSB_CWD, "Cwd"},
528 {FSB_HOME, "Home"},
529 {FSB_ROOT, "/"}
530 #ifdef __CYGWIN__
531 ,{FSB_CYGDRV, "My Computer"}
532 #endif
535 #define FSB_ITEMS_NUM sizeof(fsb_items)/sizeof(OptionItem)
537 FSBStructure *CreateFSBDialog(Widget parent, char *s)
539 FSBStructure *retval;
540 OptionStructure *opt;
541 Widget dialog, fr, form, button;
543 retval = xmalloc(sizeof(FSBStructure));
545 dialog = CreateDialogWindow(parent, s);
546 retval->FSB = CreateFileSelectionBox(dialog);
548 FSBDialogSetDirectory(retval, get_workingdir(gapp));
549 AddWidgetCB(retval->FSB, "cancel", close_dialogCB, dialog);
550 AddHelpCB(retval->FSB, "doc/UsersGuide.html#FS-dialog");
552 retval->rc = CreateVContainer(retval->FSB);
554 CreateFileSelectionFilter(retval->rc, retval->FSB);
556 fr = CreateFrame(retval->rc, NULL);
558 form = CreateForm(fr);
560 opt = CreateOptionChoice(form, "Chdir to:", 1, FSB_ITEMS_NUM, fsb_items);
561 AddOptionChoiceCB(opt, fsb_cd_cb, retval);
562 FormAddHChild(form, opt->menu);
564 button = CreateButton(form, "Set as cwd");
565 AddButtonCB(button, fsb_setcwd_cb, retval->FSB);
566 FormAddHChild(form, button);
567 FormFixateHChild(button);
569 WidgetManage(form);
571 return retval;
574 typedef struct {
575 FSBStructure *fsb;
576 FSB_CBProc cbproc;
577 void *anydata;
578 } FSB_CBdata;
580 static void fsb_int_cb_proc(Widget_CBData *wcbdata)
582 char *s;
583 int ok;
585 FSB_CBdata *cbdata = (FSB_CBdata *) wcbdata->anydata;
586 XmFileSelectionBoxCallbackStruct *cbs =
587 (XmFileSelectionBoxCallbackStruct *) wcbdata->calldata;
589 s = GetStringSimple(cbs->value);
590 if (s == NULL) {
591 errmsg("Error converting XmString to char string");
592 return;
595 set_wait_cursor();
597 ok = cbdata->cbproc(cbdata->fsb, s, cbdata->anydata);
598 XtFree(s);
599 if (ok) {
600 DialogClose(cbdata->fsb->FSB);
602 unset_wait_cursor();
605 void AddFSBDialogCB(FSBStructure *fsb, FSB_CBProc cbproc, void *anydata)
607 FSB_CBdata *cbdata;
609 cbdata = xmalloc(sizeof(FSB_CBdata));
610 cbdata->fsb = fsb;
611 cbdata->cbproc = (FSB_CBProc) cbproc;
612 cbdata->anydata = anydata;
614 AddWidgetCB(fsb->FSB, "ok", fsb_int_cb_proc, cbdata);
617 void FSBDialogSetPattern(FSBStructure *fsb, char *pattern)
619 XmString xmstr;
621 if (pattern != NULL) {
622 xmstr = XmStringCreateLocalized(pattern);
623 XtVaSetValues(fsb->FSB, XmNpattern, xmstr, NULL);
624 XmStringFree(xmstr);
628 void FSBDialogSetDirectory(FSBStructure *fsb, char *directory)
630 XmString xmstr;
632 if (directory != NULL) {
633 xmstr = XmStringCreateLocalized(directory);
634 XtVaSetValues(fsb->FSB, XmNdirectory, xmstr, NULL);
635 XmStringFree(xmstr);
639 /* Containers */
640 Widget CreateVContainer(Widget parent)
642 Widget rc;
644 rc = XmCreateRowColumn(parent, "VContainer", NULL, 0);
645 WidgetManage(rc);
647 return rc;
650 Widget CreateHContainer(Widget parent)
652 Widget rc;
654 rc = XmCreateRowColumn(parent, "HContainer", NULL, 0);
655 XtVaSetValues(rc, XmNorientation, XmHORIZONTAL, NULL);
656 WidgetManage(rc);
658 return rc;
661 /* Form */
662 Widget CreateForm(Widget parent)
664 Widget w;
666 w = XmCreateForm(parent, "form", NULL, 0);
668 return w;
671 void FormAddHChild(Widget form, Widget child)
673 Widget last_widget;
675 last_widget = WidgetGetUserData(form);
676 if (last_widget) {
677 XtVaSetValues(child,
678 XmNleftAttachment, XmATTACH_WIDGET,
679 XmNleftWidget, last_widget,
680 NULL);
681 XtVaSetValues(last_widget,
682 XmNrightAttachment, XmATTACH_NONE,
683 NULL);
684 } else {
685 XtVaSetValues(child,
686 XmNleftAttachment, XmATTACH_FORM,
687 NULL);
689 XtVaSetValues(child,
690 XmNtopAttachment, XmATTACH_FORM,
691 XmNbottomAttachment, XmATTACH_FORM,
692 XmNrightAttachment, XmATTACH_FORM,
693 NULL);
694 WidgetSetUserData(form, child);
697 void FormAddVChild(Widget form, Widget child)
699 Widget last_widget;
701 if (XtIsSubclass(child, listtreeWidgetClass) ||
702 (XmIsText(child) && XmIsScrolledWindow(XtParent(child)))) {
703 child = XtParent(child);
706 last_widget = WidgetGetUserData(form);
707 if (last_widget) {
708 XtVaSetValues(child,
709 XmNtopAttachment, XmATTACH_WIDGET,
710 XmNtopWidget, last_widget,
711 NULL);
712 XtVaSetValues(last_widget,
713 XmNbottomAttachment, XmATTACH_NONE,
714 NULL);
715 } else {
716 XtVaSetValues(child,
717 XmNtopAttachment, XmATTACH_FORM,
718 NULL);
720 XtVaSetValues(child,
721 XmNleftAttachment, XmATTACH_FORM,
722 XmNrightAttachment, XmATTACH_FORM,
723 XmNbottomAttachment, XmATTACH_FORM,
724 NULL);
725 WidgetSetUserData(form, child);
728 void FormFixateHChild(Widget w)
730 Widget prev;
731 XtVaGetValues(w, XmNleftWidget, &prev, NULL);
732 XtVaSetValues(w, XmNleftAttachment, XmATTACH_NONE, NULL);
733 XtVaSetValues(prev, XmNrightAttachment, XmATTACH_WIDGET,
734 XmNrightWidget, w,
735 NULL);
738 void FormFixateVChild(Widget w)
740 Widget prev;
741 XtVaGetValues(w, XmNtopWidget, &prev, NULL);
742 XtVaSetValues(w, XmNtopAttachment, XmATTACH_NONE, NULL);
743 XtVaSetValues(prev, XmNbottomAttachment, XmATTACH_WIDGET,
744 XmNbottomWidget, w,
745 NULL);
748 /* Grid */
749 typedef struct {
750 int ncols;
751 int nrows;
752 } GridData;
754 Widget CreateGrid(Widget parent, int ncols, int nrows)
756 Widget w;
757 int nfractions;
758 GridData *gd;
760 if (ncols <= 0 || nrows <= 0) {
761 errmsg("Wrong call to CreateGrid()");
762 ncols = 1;
763 nrows = 1;
766 nfractions = 0;
767 do {
768 nfractions++;
769 } while (nfractions % ncols || nfractions % nrows);
771 gd = xmalloc(sizeof(GridData));
772 gd->ncols = ncols;
773 gd->nrows = nrows;
775 w = CreateForm(parent);
777 XtVaSetValues(w,
778 XmNfractionBase, nfractions,
779 XmNuserData, gd,
780 NULL);
782 WidgetManage(w);
784 return w;
787 void PlaceGridChild(Widget grid, Widget w, int col, int row)
789 int nfractions, w1, h1;
790 GridData *gd;
792 XtVaGetValues(grid,
793 XmNfractionBase, &nfractions,
794 XmNuserData, &gd,
795 NULL);
797 if (gd == NULL) {
798 /* errmsg("PlaceGridChild() called with a non-grid widget"); */
799 return;
801 if (col < 0 || col >= gd->ncols) {
802 errmsg("PlaceGridChild() called with wrong `col' argument");
803 return;
805 if (row < 0 || row >= gd->nrows) {
806 errmsg("PlaceGridChild() called with wrong `row' argument");
807 return;
810 w1 = nfractions/gd->ncols;
811 h1 = nfractions/gd->nrows;
813 XtVaSetValues(w,
814 XmNleftAttachment , XmATTACH_POSITION,
815 XmNleftPosition , col*w1 ,
816 XmNrightAttachment , XmATTACH_POSITION,
817 XmNrightPosition , (col + 1)*w1 ,
818 XmNtopAttachment , XmATTACH_POSITION,
819 XmNtopPosition , row*h1 ,
820 XmNbottomAttachment, XmATTACH_POSITION,
821 XmNbottomPosition , (row + 1)*h1 ,
822 NULL);
825 /* Frame */
826 Widget CreateFrame(Widget parent, char *s)
828 Widget fr;
830 fr = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, parent, NULL);
831 if (s != NULL) {
832 XtVaCreateManagedWidget(s, xmLabelGadgetClass, fr,
833 XmNchildType, XmFRAME_TITLE_CHILD,
834 NULL);
837 return fr;
840 /* Scrolled window */
841 Widget CreateScrolledWindow(Widget parent)
843 return XtVaCreateManagedWidget("scrolledWindow",
844 xmScrolledWindowWidgetClass, parent,
845 XmNscrollingPolicy, XmAUTOMATIC,
846 NULL);
849 /* Paned window */
850 Widget CreatePanedWindow(Widget parent)
852 #if USE_PANEDW
853 return XtVaCreateManagedWidget("panedWindow",
854 xmPanedWindowWidgetClass, parent,
855 XmNorientation, XmHORIZONTAL,
856 NULL);
857 #else
858 return CreateGrid(parent, 2, 1);
859 #endif
862 void PanedWindowSetMinWidth(Widget w, unsigned int width)
864 XtVaSetValues(w, XmNpaneMinimum, (Dimension) width, NULL);
867 /* Tab */
868 Widget CreateTab(Widget parent)
870 Widget tab;
872 tab = XtVaCreateManagedWidget("tab", xmTabWidgetClass, parent, NULL);
874 return tab;
877 Widget CreateTabPage(Widget parent, char *s)
879 Widget w;
880 XmString str;
882 w = CreateVContainer(parent);
883 str = XmStringCreateLocalized(s);
884 XtVaSetValues(w, XmNtabLabel, str, NULL);
885 XmStringFree(str);
887 return w;
890 void SelectTabPage(Widget tab, Widget w)
892 XmTabSetTabWidget(tab, w, True);
895 /* Separator */
896 Widget CreateSeparator(Widget parent)
898 Widget sep;
900 sep = XmCreateSeparator(parent, "sep", NULL, 0);
901 WidgetManage(sep);
903 return sep;
906 /* Label */
907 Widget CreateLabel(Widget parent, char *s)
909 Widget label;
911 label = XtVaCreateManagedWidget("label",
912 xmLabelWidgetClass, parent,
913 XmNalignment, XmALIGNMENT_BEGINNING,
914 XmNrecomputeSize, True,
915 NULL);
917 LabelSetString(label, s);
919 return label;
922 void LabelSetString(Widget w, char *s)
924 XmString str;
926 if (s == NULL) return;
928 str = XmStringCreateLocalized(s);
929 XtVaSetValues(w, XmNlabelString, str, NULL);
930 XmStringFree(str);
934 void LabelSetPixmap(Widget w, int width, int height, const unsigned char *bits)
936 Pixmap pm;
938 X11Stuff *xstuff = gapp->gui->xstuff;
939 Pixel fg, bg;
941 XtVaGetValues(w,
942 XmNforeground, &fg,
943 XmNbackground, &bg,
944 NULL);
946 pm = XCreatePixmapFromBitmapData(xstuff->disp,
947 xstuff->root, (char *) bits, width, height, fg, bg, xstuff->depth);
949 XtVaSetValues(w,
950 XmNlabelType, XmPIXMAP,
951 XmNlabelPixmap, pm,
952 NULL);
955 /* Text edit */
956 Widget CreateLineTextEdit(Widget parent, int len)
958 Widget w;
960 w = XtVaCreateManagedWidget("text", xmTextWidgetClass, parent,
961 XmNtraversalOn, True,
962 NULL);
963 if (len > 0) {
964 XtVaSetValues(w, XmNcolumns, len, NULL);
967 return w;
970 Widget CreateMultiLineTextEdit(Widget parent, int nrows)
972 Widget w;
973 Arg args[3];
974 int ac;
976 ac = 0;
977 if (nrows > 0) {
978 XtSetArg(args[ac], XmNrows, nrows); ac++;
980 XtSetArg(args[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
981 XtSetArg(args[ac], XmNvisualPolicy, XmVARIABLE); ac++;
983 w = XmCreateScrolledText(parent, "text", args, ac);
984 WidgetManage(w);
986 return w;
989 char *TextEditGetString(Widget w)
991 char *s, *buf;
993 s = XmTextGetString(w);
994 buf = copy_string(NULL, s);
995 XtFree(s);
997 return buf;
1000 void TextEditSetString(Widget w, char *s)
1002 XmTextSetString(w, s ? s : "");
1005 /* Text */
1006 void TextSetLength(TextStructure *cst, int len)
1008 XtVaSetValues(cst->text, XmNcolumns, len, NULL);
1011 char *TextGetString(TextStructure *cst)
1013 return TextEditGetString(cst->text);
1016 void TextSetString(TextStructure *cst, char *s)
1018 cst->locked = TRUE;
1019 TextEditSetString(cst->text, s);
1020 XmTextSetInsertionPosition(cst->text, s ? strlen(s):0);
1021 cst->locked = FALSE;
1024 typedef struct {
1025 TextStructure *cst;
1026 TextValidate_CBProc cbproc;
1027 void *anydata;
1028 } TextValidate_CBData;
1030 static void text_int_validate_cb_proc(Widget_CBData *wcbdata)
1032 XmTextBlock text;
1033 TextValidate_CBData *cbdata = (TextValidate_CBData *) wcbdata->anydata;
1034 XmTextVerifyCallbackStruct *tcbs =
1035 (XmTextVerifyCallbackStruct *) wcbdata->calldata;
1037 if (cbdata->cst->locked) return;
1039 text = tcbs->text;
1041 if (!cbdata->cbproc(&text->ptr, &text->length, cbdata->anydata)) {
1042 tcbs->doit = False;
1046 void AddTextValidateCB(TextStructure *cst, TextValidate_CBProc cbproc, void *anydata)
1048 TextValidate_CBData *cbdata;
1050 cbdata = (TextValidate_CBData *) xmalloc(sizeof(TextValidate_CBData));
1051 cbdata->cst = cst;
1052 cbdata->cbproc = cbproc;
1053 cbdata->anydata = anydata;
1054 cst->locked = FALSE;
1056 AddWidgetCB(cst->text, "modifyVerify", text_int_validate_cb_proc, cbdata);
1059 int TextGetCursorPos(TextStructure *cst)
1061 return XmTextGetInsertionPosition(cst->text);
1064 void TextSetCursorPos(TextStructure *cst, int pos)
1066 XmTextSetInsertionPosition(cst->text, pos);
1069 int TextGetLastPosition(TextStructure *cst)
1071 return XmTextGetLastPosition(cst->text);
1074 void TextInsert(TextStructure *cst, int pos, char *s)
1076 XmTextInsert(cst->text, pos, s);
1079 void TextSetEditable(TextStructure *cst, int onoff)
1081 XtVaSetValues(cst->text, XmNeditable, onoff? True:False, NULL);
1084 /* Button */
1085 Widget CreateButton(Widget parent, char *label)
1087 Widget button;
1089 button = XtVaCreateManagedWidget(label,
1090 xmPushButtonWidgetClass, parent,
1091 NULL);
1093 XtVaSetValues(button,
1094 XmNalignment, XmALIGNMENT_CENTER,
1095 NULL);
1097 return button;
1100 Widget CreateBitmapButton(Widget parent,
1101 int width, int height, const unsigned char *bits)
1103 Widget button;
1105 button = XtVaCreateWidget("button",
1106 xmPushButtonWidgetClass, parent,
1107 NULL);
1108 LabelSetPixmap(button, width, height, bits);
1109 WidgetManage(button);
1111 return button;
1114 Widget CreateArrowButton(Widget parent, int arrow_type)
1116 Widget w;
1118 w = XtVaCreateManagedWidget("arrow", xmArrowButtonGadgetClass, parent,
1119 XmNarrowDirection, (arrow_type == ARROW_UP) ? XmARROW_UP : XmARROW_DOWN,
1120 NULL);
1122 return w;
1125 /* ToggleButton */
1126 Widget CreateToggleButton(Widget parent, char *s)
1128 return (XtVaCreateManagedWidget(s, xmToggleButtonWidgetClass, parent, NULL));
1131 int GetToggleButtonState(Widget w)
1133 if (!w) {
1134 errmsg("Internal error: GetToggleButtonState() called with NULL widget");
1135 return 0;
1136 } else {
1137 return XmToggleButtonGetState(w);
1141 void SetToggleButtonState(Widget w, int value)
1143 if (w == NULL) {
1144 return;
1146 XmToggleButtonSetState(w, value ? True:False, False);
1148 return;
1151 /* Scale */
1152 Widget CreateScale(Widget parent, char *s, int min, int max, int delta)
1154 Widget w;
1155 XmString str;
1157 str = XmStringCreateLocalized(s);
1159 w = XtVaCreateManagedWidget("scroll",
1160 xmScaleWidgetClass, parent,
1161 XmNtitleString, str,
1162 XmNminimum, min,
1163 XmNmaximum, max,
1164 XmNscaleMultiple, delta,
1165 XmNvalue, 0,
1166 XmNshowValue, True,
1167 XmNprocessingDirection, XmMAX_ON_RIGHT,
1168 XmNorientation, XmHORIZONTAL,
1169 #if XmVersion >= 2000
1170 XmNsliderMark, XmROUND_MARK,
1171 #endif
1172 NULL);
1174 XmStringFree(str);
1176 return w;
1179 void SetScaleValue(Widget w, int value)
1181 XtVaSetValues(w, XmNvalue, value, NULL);
1184 int GetScaleValue(Widget w)
1186 int value;
1187 XtVaGetValues(w, XmNvalue, &value, NULL);
1188 return value;
1191 /* SpinChoice */
1192 typedef void (*Timer_CBProc)(void *anydata);
1193 typedef struct {
1194 unsigned long timer_id;
1195 Timer_CBProc cbproc;
1196 void *anydata;
1197 } Timer_CBdata;
1199 typedef struct {
1200 SpinStructure *spin;
1201 Spin_CBProc cbproc;
1202 void *anydata;
1203 Timer_CBdata *tcbdata;
1204 } Spin_CBdata;
1206 static void sp_double_cb_proc(Widget_CBData *wcbdata)
1208 Spin_CBdata *cbdata = (Spin_CBdata *) wcbdata->anydata;
1210 cbdata->cbproc(cbdata->spin, GetSpinChoice(cbdata->spin), cbdata->anydata);
1213 static void sp_timer_proc(void *anydata)
1215 Spin_CBdata *cbdata = (Spin_CBdata *) anydata;
1217 cbdata->cbproc(cbdata->spin, GetSpinChoice(cbdata->spin), cbdata->anydata);
1220 static void timer_proc(XtPointer client_data, XtIntervalId *id)
1222 Timer_CBdata *cbdata = (Timer_CBdata *) client_data;
1224 cbdata->cbproc(cbdata->anydata);
1225 cbdata->timer_id = 0;
1228 void TimerStart(unsigned long interval, Timer_CBdata *cbdata)
1230 /* we count elapsed time since the last event, so first remove
1231 an existing timeout, if there is one */
1232 if (cbdata->timer_id) {
1233 XtRemoveTimeOut(cbdata->timer_id);
1236 cbdata->timer_id = XtAppAddTimeOut(app_con, interval, timer_proc, cbdata);
1239 static void sp_ev_proc(void *anydata)
1241 Spin_CBdata *cbdata = (Spin_CBdata *) anydata;
1243 TimerStart(250 /* 0.25 second */, cbdata->tcbdata);
1246 Timer_CBdata *CreateTimer(Timer_CBProc cbproc, void *anydata)
1248 Timer_CBdata *cbdata;
1250 cbdata = xmalloc(sizeof(Timer_CBdata));
1252 cbdata->cbproc = cbproc;
1253 cbdata->anydata = anydata;
1254 cbdata->timer_id = 0;
1256 return cbdata;
1259 void AddSpinChoiceCB(SpinStructure *spinp, Spin_CBProc cbproc, void *anydata)
1261 Spin_CBdata *cbdata;
1263 cbdata = xmalloc(sizeof(Spin_CBdata));
1265 cbdata->spin = spinp;
1266 cbdata->cbproc = cbproc;
1267 cbdata->anydata = anydata;
1268 cbdata->tcbdata = CreateTimer(sp_timer_proc, cbdata);
1270 AddWidgetCB(spinp->text, "activate", sp_double_cb_proc, cbdata);
1271 AddWidgetCB(spinp->arrow_up, "activate", sp_double_cb_proc, cbdata);
1272 AddWidgetCB(spinp->arrow_down, "activate", sp_double_cb_proc, cbdata);
1274 AddWidgetButtonPressCB(spinp->text, WHEEL_UP_BUTTON, sp_ev_proc, cbdata);
1275 AddWidgetButtonPressCB(spinp->text, WHEEL_DOWN_BUTTON, sp_ev_proc, cbdata);
1278 static void spin_arrow_cb(Widget_CBData *wcbdata)
1280 SpinStructure *spinp;
1281 double value, incr;
1283 spinp = (SpinStructure *) wcbdata->anydata;
1284 value = GetSpinChoice(spinp);
1285 incr = spinp->incr;
1287 if (wcbdata->w == spinp->arrow_up) {
1288 incr = spinp->incr;
1289 } else if (wcbdata->w == spinp->arrow_down) {
1290 incr = -spinp->incr;
1291 } else {
1292 errmsg("Wrong call to spin_arrow_cb()");
1293 return;
1295 value += incr;
1296 SetSpinChoice(spinp, value);
1297 WidgetSetFocus(spinp->text);
1300 static void spin_up(void *anydata)
1302 SpinStructure *spinp = (SpinStructure *) anydata;
1303 double value;
1305 value = GetSpinChoice(spinp) + spinp->incr;
1306 SetSpinChoice(spinp, value);
1309 static void spin_down(void *anydata)
1311 SpinStructure *spinp = (SpinStructure *) anydata;
1312 double value;
1314 value = GetSpinChoice(spinp) - spinp->incr;
1315 SetSpinChoice(spinp, value);
1318 SpinStructure *CreateSpinChoice(Widget parent, char *s, int len,
1319 int type, double min, double max, double incr)
1321 SpinStructure *retval;
1322 Widget fr, form;
1324 if (min >= max) {
1325 errmsg("min >= max in CreateSpinChoice()!");
1326 return NULL;
1329 retval = xmalloc(sizeof(SpinStructure));
1331 retval->type = type;
1332 retval->min = min;
1333 retval->max = max;
1334 retval->incr = incr;
1336 retval->rc = CreateHContainer(parent);
1338 CreateLabel(retval->rc, s);
1339 fr = CreateFrame(retval->rc, NULL);
1341 form = CreateForm(fr);
1343 retval->text = CreateLineTextEdit(form, len);
1344 FormAddHChild(form, retval->text);
1346 AddWidgetButtonPressCB(retval->text, WHEEL_UP_BUTTON, spin_up, retval);
1347 AddWidgetButtonPressCB(retval->text, WHEEL_DOWN_BUTTON, spin_down, retval);
1349 retval->arrow_down = CreateArrowButton(form, ARROW_DOWN);
1350 AddWidgetCB(retval->arrow_down, "activate", spin_arrow_cb, retval);
1351 FormAddHChild(form, retval->arrow_down);
1353 retval->arrow_up = CreateArrowButton(form, ARROW_UP);
1354 AddWidgetCB(retval->arrow_up, "activate", spin_arrow_cb, retval);
1355 FormAddHChild(form, retval->arrow_up);
1357 WidgetManage(form);
1359 return retval;
1362 void SetSpinChoice(SpinStructure *spinp, double value)
1364 X11Stuff *xstuff = gapp->gui->xstuff;
1365 char buf[64];
1367 if (value < spinp->min) {
1368 XBell(xstuff->disp, 50);
1369 value = spinp->min;
1370 } else if (value > spinp->max) {
1371 XBell(xstuff->disp, 50);
1372 value = spinp->max;
1375 if (spinp->type == SPIN_TYPE_FLOAT) {
1376 sprintf(buf, "%g", value);
1377 } else {
1378 sprintf(buf, "%d", (int) rint(value));
1380 TextEditSetString(spinp->text, buf);
1383 double GetSpinChoice(SpinStructure *spinp)
1385 double retval;
1386 char *s;
1388 s = TextEditGetString(spinp->text);
1390 graal_eval_expr(grace_get_graal(gapp->grace),
1391 s, &retval,
1392 gproject_get_top(gapp->gp));
1394 xfree(s);
1396 if (retval < spinp->min) {
1397 errmsg("Input value below min limit in GetSpinChoice()");
1398 retval = spinp->min;
1399 SetSpinChoice(spinp, retval);
1400 } else if (retval > spinp->max) {
1401 errmsg("Input value above max limit in GetSpinChoice()");
1402 retval = spinp->max;
1403 SetSpinChoice(spinp, retval);
1406 if (spinp->type == SPIN_TYPE_INT) {
1407 return rint(retval);
1408 } else {
1409 return retval;
1413 /* OptionChoice */
1414 #define MAX_PULLDOWN_LENGTH 30
1416 OptionStructure *CreateOptionChoice(Widget parent, char *labelstr,
1417 int ncols, int nchoices, OptionItem *items)
1419 Arg args[2];
1420 XmString str;
1421 OptionStructure *retval;
1423 retval = xcalloc(1, sizeof(OptionStructure));
1424 if (!retval) {
1425 return NULL;
1428 XtSetArg(args[0], XmNpacking, XmPACK_COLUMN);
1429 retval->pulldown = XmCreatePulldownMenu(parent, "pulldownMenu", args, 1);
1431 retval->ncols = ncols;
1433 UpdateOptionChoice(retval, nchoices, items);
1435 str = XmStringCreateLocalized(labelstr);
1436 XtSetArg(args[0], XmNlabelString, str);
1437 XtSetArg(args[1], XmNsubMenuId, retval->pulldown);
1439 retval->menu = XmCreateOptionMenu(parent, "optionMenu", args, 2);
1441 XmStringFree(str);
1443 WidgetManage(retval->menu);
1445 return retval;
1448 OptionStructure *CreateOptionChoiceVA(Widget parent, char *labelstr, ...)
1450 OptionStructure *retval;
1451 int nchoices = 0;
1452 OptionItem *oi = NULL;
1453 va_list var;
1454 char *s;
1455 int value;
1457 va_start(var, labelstr);
1458 while ((s = va_arg(var, char *)) != NULL) {
1459 value = va_arg(var, int);
1460 nchoices++;
1461 oi = xrealloc(oi, nchoices*sizeof(OptionItem));
1462 oi[nchoices - 1].value = value;
1463 oi[nchoices - 1].label = copy_string(NULL, s);
1465 va_end(var);
1467 retval = CreateOptionChoice(parent, labelstr, 1, nchoices, oi);
1469 while (nchoices) {
1470 nchoices--;
1471 xfree(oi[nchoices].label);
1473 xfree(oi);
1475 return retval;
1478 static void oc_int_cb_proc(Widget_CBData *wcbdata)
1480 int value;
1482 OC_CBdata *cbdata = (OC_CBdata *) wcbdata->anydata;
1484 value = GetOptionChoice(cbdata->opt);
1485 cbdata->cbproc(cbdata->opt, value, cbdata->anydata);
1488 void AddOptionChoiceCB(OptionStructure *opt, OC_CBProc cbproc, void *anydata)
1490 OC_CBdata *cbdata;
1491 unsigned int i;
1493 cbdata = xmalloc(sizeof(OC_CBdata));
1495 cbdata->opt = opt;
1496 cbdata->cbproc = cbproc;
1497 cbdata->anydata = anydata;
1499 opt->cblist = xrealloc(opt->cblist, (opt->cbnum + 1)*sizeof(OC_CBdata *));
1500 opt->cblist[opt->cbnum] = cbdata;
1501 opt->cbnum++;
1503 for (i = 0; i < opt->nchoices; i++) {
1504 AddWidgetCB(opt->options[i].widget, "activate", oc_int_cb_proc, cbdata);
1508 void UpdateOptionChoice(OptionStructure *optp, int nchoices, OptionItem *items)
1510 int i, nold, ncols, nw;
1511 Widget *wlist;
1513 nold = optp->nchoices;
1515 if (optp->ncols == 0) {
1516 ncols = 1;
1517 } else {
1518 ncols = optp->ncols;
1521 /* Don't create too tall pulldowns */
1522 if (nchoices > MAX_PULLDOWN_LENGTH*ncols) {
1523 ncols = (nchoices + MAX_PULLDOWN_LENGTH - 1)/MAX_PULLDOWN_LENGTH;
1526 XtVaSetValues(optp->pulldown, XmNnumColumns, ncols, NULL);
1528 nw = nold - nchoices;
1529 if (nw > 0) {
1530 /* Unmanage extra items before destroying to speed the things up */
1531 wlist = xmalloc(nw*sizeof(Widget));
1532 for (i = nchoices; i < nold; i++) {
1533 wlist[i - nchoices] = optp->options[i].widget;
1535 XtUnmanageChildren(wlist, nw);
1536 xfree(wlist);
1538 for (i = nchoices; i < nold; i++) {
1539 XtDestroyWidget(optp->options[i].widget);
1543 optp->options = xrealloc(optp->options, nchoices*sizeof(OptionWidgetItem));
1544 optp->nchoices = nchoices;
1546 for (i = nold; i < nchoices; i++) {
1547 unsigned int j;
1548 optp->options[i].widget = CreateButton(optp->pulldown, "");
1549 for (j = 0; j < optp->cbnum; j++) {
1550 OC_CBdata *cbdata = optp->cblist[j];
1551 AddWidgetCB(optp->options[i].widget, "activate", oc_int_cb_proc, cbdata);
1555 for (i = 0; i < nchoices; i++) {
1556 optp->options[i].value = items[i].value;
1557 if (items[i].label != NULL) {
1558 XmString str, ostr;
1559 XtVaGetValues(optp->options[i].widget, XmNlabelString, &ostr, NULL);
1560 str = XmStringCreateLocalized(items[i].label);
1561 if (XmStringCompare(str, ostr) != True) {
1562 XtVaSetValues(optp->options[i].widget, XmNlabelString, str, NULL);
1564 XmStringFree(str);
1568 nw = nchoices - nold;
1569 if (nw > 0) {
1570 wlist = xmalloc(nw*sizeof(Widget));
1571 for (i = nold; i < nchoices; i++) {
1572 wlist[i - nold] = optp->options[i].widget;
1574 XtManageChildren(wlist, nw);
1575 xfree(wlist);
1579 /* Menu */
1580 Widget CreatePopupMenu(Widget parent)
1582 return XmCreatePopupMenu(parent, "popupMenu", NULL, 0);
1585 void PopupMenuShow(Widget w, void *data)
1587 XmMenuPosition(w, (XButtonEvent *) data);
1588 WidgetManage(w);
1591 Widget CreateMenuBar(Widget parent)
1593 Widget menubar;
1595 menubar = XmCreateMenuBar(parent, "menuBar", NULL, 0);
1596 return menubar;
1599 Widget CreateMenu(Widget parent, char *label, char mnemonic, int help)
1601 Widget menupane, cascade;
1602 char ms[2];
1604 menupane = XmCreatePulldownMenu(parent, "menu", NULL, 0);
1606 ms[0] = mnemonic;
1607 ms[1] = '\0';
1609 cascade = XtVaCreateManagedWidget("cascade",
1610 xmCascadeButtonGadgetClass, parent,
1611 XmNsubMenuId, menupane,
1612 XmNmnemonic, XStringToKeysym(ms),
1613 NULL);
1615 LabelSetString(cascade, label);
1617 if (help) {
1618 XtVaSetValues(parent, XmNmenuHelpWidget, cascade, NULL);
1619 CreateMenuButton(menupane, "On context", 'x',
1620 ContextHelpCB, NULL);
1621 CreateSeparator(menupane);
1624 return menupane;
1627 Widget CreateMenuButton(Widget parent, char *label, char mnemonic,
1628 Button_CBProc cb, void *data)
1630 return CreateMenuButtonA(parent, label, mnemonic, NULL, NULL, cb, data);
1633 Widget CreateMenuButtonA(Widget parent, char *label, char mnemonic,
1634 char *accelerator, char* acceleratorText, Button_CBProc cb, void *data)
1636 Widget button;
1637 XmString str;
1638 char *name, ms[2];
1640 ms[0] = mnemonic;
1641 ms[1] = '\0';
1643 name = label_to_resname(label, "Button");
1645 button = CreateButton(parent, name);
1646 xfree(name);
1648 XtVaSetValues(button,
1649 XmNmnemonic, XStringToKeysym(ms),
1650 XmNalignment, XmALIGNMENT_BEGINNING,
1651 NULL);
1653 if (accelerator && acceleratorText) {
1654 str = XmStringCreateLocalized(acceleratorText);
1655 XtVaSetValues(button,
1656 XmNaccelerator, accelerator,
1657 XmNacceleratorText, str,
1658 NULL);
1659 XmStringFree(str);
1662 LabelSetString(button, label);
1664 AddButtonCB(button, cb, data);
1666 return button;
1669 Widget CreateMenuHelpButton(Widget parent, char *label, char mnemonic,
1670 Widget form, char *ha)
1672 Widget wbut;
1674 wbut = CreateMenuButton(parent, label, mnemonic, HelpCB, ha);
1675 AddHelpCB(form, ha);
1677 return wbut;
1680 Widget CreateMenuToggle(Widget parent, char *label, char mnemonic,
1681 TB_CBProc cb, void *data)
1683 Widget button;
1684 char *name, ms[2];
1686 ms[0] = mnemonic;
1687 ms[1] = '\0';
1689 name = label_to_resname(label, NULL);
1690 button = CreateToggleButton(parent, name);
1691 xfree(name);
1693 XtVaSetValues(button,
1694 XmNmnemonic, XStringToKeysym(ms),
1695 XmNvisibleWhenOff, True,
1696 XmNindicatorOn, True,
1697 NULL);
1699 LabelSetString(button, label);
1701 if (cb) {
1702 AddToggleButtonCB(button, cb, data);
1705 return button;
1708 Widget CreateMenuSeparator(Widget parent)
1710 return CreateSeparator(parent);