*** empty log message ***
[nvi.git] / motif_l / m_options.c
blob470f5be4e0df6d22812abf1943b22ab6b6ac6da6
1 /*-
2 * Copyright (c) 1996
3 * Rob Zimmermann. All rights reserved.
4 * Copyright (c) 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: m_options.c,v 8.18 1997/08/02 16:50:10 bostic Exp $ (Berkeley) $Date: 1997/08/02 16:50:10 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #include <X11/X.h>
20 #include <X11/Intrinsic.h>
21 #include <Xm/DialogS.h>
22 #include <Xm/Form.h>
23 #include <Xm/Frame.h>
24 #include <Xm/LabelG.h>
25 #include <Xm/PushBG.h>
26 #include <Xm/TextF.h>
27 #include <Xm/ToggleBG.h>
28 #include <Xm/RowColumn.h>
30 #include <bitstring.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include "../common/common.h"
36 #include "../ipc/ip.h"
37 #include "m_motif.h"
39 static void set_opt __P((Widget, XtPointer, XtPointer));
42 /* constants */
44 #if defined(SelfTest)
46 /* in production, get these from the resource list */
48 #define toggleColumns 6
50 #endif
54 * global data
57 static Widget preferences = NULL;
59 static optData display[] = {
60 { optToggle, "comment", },
61 { optToggle, "flash", },
62 { optToggle, "leftright", },
63 { optToggle, "list", },
64 { optToggle, "number", },
65 { optToggle, "octal", },
66 { optToggle, "ruler", },
67 { optToggle, "showmode", },
68 { optToggle, "slowopen", },
69 { optToggle, "verbose", },
70 { optToggle, "windowname", },
71 { optTerminator, },
72 }, display_int[] = {
73 { optInteger, "report", },
74 { optInteger, "scroll", },
75 { optInteger, "shiftwidth", },
76 { optInteger, "sidescroll", },
77 { optInteger, "tabstop", },
78 { optInteger, "window", },
79 { optTerminator, },
80 }, display_str[] = {
81 { optString, "noprint", },
82 { optString, "print", },
83 { optTerminator, },
84 }, files[] = {
85 { optToggle, "autowrite", },
86 { optToggle, "lock", },
87 { optToggle, "readonly", },
88 { optToggle, "writeany", },
89 { optTerminator, },
90 }, files_str[] = {
91 { optString, "backup", },
92 { optString, "path", },
93 { optTerminator, },
94 }, general[] = {
95 { optToggle, "exrc", },
96 { optToggle, "lisp", },
97 { optToggle, "modeline", },
98 { optToggle, "sourceany", },
99 { optToggle, "tildeop", },
100 { optTerminator, },
101 }, general_int[] = {
102 { optInteger, "taglength", },
103 { optTerminator, },
104 }, general_str[] = {
105 { optString, "cdpath", },
106 { optString, "directory", },
107 { optString, "msgcat", },
108 { optString, "recdir", },
109 { optString, "shell", },
110 { optString, "shellmeta", },
111 { optString, "tags", },
112 { optTerminator, },
113 }, input[] = {
114 { optToggle, "altwerase", },
115 { optToggle, "autoindent", },
116 { optToggle, "remap", },
117 { optToggle, "showmatch", },
118 { optToggle, "ttywerase", },
119 { optTerminator, },
120 }, input_int[] = {
121 { optInteger, "escapetime", },
122 { optInteger, "keytime", },
123 { optInteger, "matchtime", },
124 { optInteger, "timeout", },
125 { optInteger, "wraplen", },
126 { optInteger, "wrapmargin", },
127 { optTerminator, },
128 }, input_str[] = {
129 { optString, "cedit", },
130 { optString, "filec", },
131 { optTerminator, },
132 }, search[] = {
133 { optToggle, "extended", },
134 { optToggle, "iclower", },
135 { optToggle, "ignorecase", },
136 { optToggle, "magic", },
137 { optToggle, "searchincr", },
138 { optToggle, "wrapscan", },
139 { optTerminator, },
140 }, search_str[] = {
141 { optString, "paragraphs", },
142 { optString, "sections", },
143 { optTerminator, },
146 /* ********* NOTE ***********
147 * Sheet 0 will always be shown first. It does not matter to the Xt code
148 * which sheet that is, so it ought to be the one users interact with most.
149 * Best guess is that's general editor options, but it might be Search/re.
150 * ********* NOTE ***********
152 static optSheet sheets[] = {
153 { "Display",
154 "These options control how text is displayed on the screen",
155 NULL,
156 display,
157 display_int,
158 display_str,
160 { "Files",
161 "These options control how the editor handles files",
162 NULL,
163 files,
164 NULL,
165 files_str,
167 { "Input",
168 "These options control text input behavior",
169 NULL,
170 input,
171 input_int,
172 input_str,
174 { "Search/RE",
175 "These options control searching and Regular Expression behavior",
176 NULL,
177 search,
178 NULL,
179 search_str,
181 { "Editor",
182 "These options control general editor configuration",
183 NULL,
184 general,
185 general_int,
186 general_str,
191 /* callbacks */
193 #if defined(SelfTest)
194 void __vi_cancel_cb()
196 puts( "cancelled" );
198 #endif
201 static void destroyed()
203 int i;
205 puts( "destroyed" );
207 /* some window managers destroy us upon popdown */
208 for (i=0; i<XtNumber(sheets); i++) {
209 sheets[i].holder = NULL;
211 preferences = NULL;
215 static void window_unmapped( w, ptr, ev, cont )
216 Widget w;
217 XtPointer ptr;
218 XEvent *ev;
219 Boolean *cont;
221 if ( ev->type == UnmapNotify ) {
222 #if defined(SelfTest)
223 puts( "unmapped" );
224 #endif
225 XtPopdown( XtParent( preferences ) );
230 * __vi_editopt --
231 * Set an edit option based on a core message.
233 * PUBLIC: int __vi_editopt __P((IP_BUF *));
236 __vi_editopt(ipbp)
237 IP_BUF *ipbp;
239 optData *opt;
241 #undef NSEARCH
242 #define NSEARCH(list) { \
243 for (opt = list; opt->kind != optTerminator; ++opt) \
244 if (!strcmp(opt->name, ipbp->str1)) \
245 goto found; \
248 NSEARCH(display);
249 NSEARCH(display_int);
250 NSEARCH(display_str);
251 NSEARCH(files);
252 NSEARCH(files_str);
253 NSEARCH(general);
254 NSEARCH(general_int);
255 NSEARCH(general_str);
256 NSEARCH(input);
257 NSEARCH(input_int);
258 NSEARCH(input_str);
259 NSEARCH(search);
260 NSEARCH(search_str);
262 return (0);
264 found: switch (opt->kind) {
265 case optToggle:
266 opt->value = (void *)ipbp->val1;
267 break;
268 case optInteger:
269 if (opt->value != NULL)
270 free(opt->value);
271 if ((opt->value = malloc(8)) != NULL)
272 (void)snprintf(opt->value,
273 8, "%lu", (u_long)ipbp->val1);
274 break;
275 case optString:
276 case optFile:
277 if (opt->value != NULL)
278 free(opt->value);
279 if ((opt->value = malloc(ipbp->len2)) != NULL)
280 memcpy(opt->value, ipbp->str2, ipbp->len2);
281 break;
282 case optTerminator:
283 abort();
285 return (0);
289 * set_opt --
290 * Send a set-edit-option message to core.
292 static void
293 set_opt(w, closure, call_data)
294 Widget w;
295 XtPointer closure, call_data;
297 optData *opt;
298 Boolean set;
299 IP_BUF ipb;
300 String str;
302 opt = closure;
304 ipb.code = VI_EDITOPT;
305 ipb.str1 = opt->name;
306 ipb.len1 = strlen(opt->name);
308 switch (opt->kind) {
309 case optToggle:
310 XtVaGetValues(w, XmNset, &set, 0);
311 ipb.val1 = set;
312 ipb.len2 = 0;
314 vi_wsend("ab1", &ipb);
315 if (ipb.val1) {
316 opt->value = (void *)!set;
318 * RAZ:
319 * How do we turn off the button? We don't want to
320 * go recursive where we set it and it calls set_opt
321 * to tell the core. Is that possible?
323 XtVaSetValues(w, XmNset, &set, 0);
324 break;
327 if (strcmp(opt->name, "ruler") == 0)
328 if (set)
329 __vi_show_text_ruler_dialog(
330 __vi_screen->area, "Ruler");
331 else
332 __vi_clear_text_ruler_dialog();
333 break;
334 case optInteger:
335 str = XmTextFieldGetString(w);
336 ipb.val1 = atoi(str);
337 ipb.len2 = 0;
338 vi_send("ab1", &ipb);
339 break;
340 case optFile:
341 case optString:
342 ipb.str2 = XmTextFieldGetString(w);
343 ipb.len2 = strlen(ipb.str2);
344 vi_send("ab1", &ipb);
345 break;
346 case optTerminator:
347 abort();
352 /* add toggles to the property sheet */
354 #if defined(__STDC__)
355 static void add_toggle( Widget parent, optData *option )
356 #else
357 static void add_toggle( parent, option )
358 Widget parent;
359 optData *option;
360 #endif
362 Widget w;
364 w = XtVaCreateManagedWidget( option->name,
365 xmToggleButtonGadgetClass,
366 parent,
367 XmNset, (Boolean) option->value,
370 XtAddCallback( w, XmNvalueChangedCallback, set_opt, option );
374 static Widget create_toggles( outer, toggles )
375 Widget outer;
376 optData *toggles;
378 Widget inner;
379 int i;
381 inner = XtVaCreateWidget( "toggleOptions",
382 xmRowColumnWidgetClass,
383 outer,
384 XmNpacking, XmPACK_COLUMN,
385 XmNnumColumns, 4,
386 XmNtopAttachment, XmATTACH_FORM,
387 XmNrightAttachment, XmATTACH_FORM,
388 XmNleftAttachment, XmATTACH_FORM,
392 /* first the booleans */
393 for (i=0; toggles[i].kind != optTerminator; i++) {
394 add_toggle( inner, &toggles[i] );
396 XtManageChild( inner );
398 return inner;
402 /* draw text fields and their labels */
404 #if defined(__STDC__)
405 static void add_string_options( Widget parent,
406 optData *options
408 #else
409 static void add_string_options( parent, options )
410 Widget parent;
411 optData *options;
412 #endif
414 int i;
415 Widget f, w;
417 for ( i=0; options[i].kind != optTerminator; i++ ) {
419 f = XtVaCreateWidget( "form",
420 xmFormWidgetClass,
421 parent,
425 XtVaCreateManagedWidget( options[i].name,
426 xmLabelGadgetClass,
428 XmNtopAttachment, XmATTACH_FORM,
429 XmNbottomAttachment, XmATTACH_FORM,
430 XmNleftAttachment, XmATTACH_FORM,
431 XmNrightAttachment, XmATTACH_POSITION,
432 XmNrightPosition, 20,
433 XmNalignment, XmALIGNMENT_END,
437 w = XtVaCreateManagedWidget( "text",
438 xmTextFieldWidgetClass,
440 XmNtopAttachment, XmATTACH_FORM,
441 XmNbottomAttachment, XmATTACH_FORM,
442 XmNrightAttachment, XmATTACH_FORM,
443 XmNleftAttachment, XmATTACH_POSITION,
444 XmNleftPosition, 20,
448 XmTextFieldSetString( w, (char *) options[i].value );
449 XtAddCallback( w, XmNactivateCallback, set_opt, &options[i] );
450 XtManageChild( f );
455 /* draw and display a single page of properties */
457 #if defined(__STDC__)
458 static Widget create_sheet( Widget parent, optSheet *sheet )
459 #else
460 static Widget create_sheet( parent, sheet )
461 Widget parent;
462 optSheet *sheet;
463 #endif
465 Widget outer, inner, frame;
466 Dimension height;
467 XmString str;
469 outer = XtVaCreateWidget( sheet->name,
470 xmFormWidgetClass,
471 parent,
472 XmNtopAttachment, XmATTACH_FORM,
473 XmNrightAttachment, XmATTACH_FORM,
474 XmNbottomAttachment, XmATTACH_FORM,
475 XmNleftAttachment, XmATTACH_FORM,
476 XmNshadowType, XmSHADOW_ETCHED_IN,
477 XmNshadowThickness, 2,
478 XmNverticalSpacing, 4,
479 XmNhorizontalSpacing, 4,
483 /* add descriptive text */
484 frame = XtVaCreateManagedWidget( "frame",
485 xmFrameWidgetClass,
486 outer,
487 XmNtopAttachment, XmATTACH_FORM,
488 XmNrightAttachment, XmATTACH_FORM,
489 XmNleftAttachment, XmATTACH_FORM,
492 str = XmStringCreateLtoR( sheet->description, XmSTRING_DEFAULT_CHARSET );
493 XtVaCreateManagedWidget( "description",
494 xmLabelGadgetClass,
495 frame,
496 XmNlabelString, str,
499 XmStringFree( str );
501 /* Add the toggles. */
502 inner = create_toggles( outer, sheet->toggles );
503 XtVaSetValues( inner,
504 XmNtopAttachment, XmATTACH_WIDGET,
505 XmNtopWidget, frame,
509 /* the string options go here */
510 inner = XtVaCreateWidget( "otherOptions",
511 xmRowColumnWidgetClass,
512 outer,
513 XmNpacking, XmPACK_COLUMN,
514 XmNtopAttachment, XmATTACH_WIDGET,
515 XmNtopWidget, inner,
516 XmNrightAttachment, XmATTACH_FORM,
517 XmNbottomAttachment, XmATTACH_FORM,
518 XmNleftAttachment, XmATTACH_FORM,
522 /* Optionally, the ints. */
523 if ( sheet->ints != NULL )
524 add_string_options( inner, sheet->ints );
526 /* Optionally, the rest. */
527 if ( sheet->others != NULL )
528 add_string_options( inner, sheet->others );
530 XtManageChild( inner );
532 /* finally, force resize of the parent */
533 XtVaGetValues( outer, XmNheight, &height, 0 );
534 XtVaSetValues( parent, XmNheight, height, 0 );
536 return outer;
540 /* change preferences to another sheet */
542 static void change_sheet( parent, current )
543 Widget parent;
544 int current;
546 static int current_sheet = -1;
548 /* create a new one? */
549 if ( sheets[current].holder == NULL )
550 sheets[current].holder = create_sheet( parent, &sheets[current] );
552 /* done with the old one? */
553 if ( current_sheet != -1 && sheets[current_sheet].holder != NULL )
554 XtUnmanageChild( sheets[current_sheet].holder );
556 current_sheet = current;
557 XtManageChild( sheets[current].holder );
558 XtManageChild( parent );
562 /* Draw and display a dialog the describes vi options */
564 #if defined(__STDC__)
565 static Widget create_options_dialog( Widget parent, String title )
566 #else
567 static Widget create_options_dialog( parent, title )
568 Widget parent;
569 String title;
570 #endif
572 Widget box, form, inner;
573 int i;
574 char buffer[1024];
576 /* already built? */
577 if ( preferences != NULL ) return preferences;
579 box = XtVaCreatePopupShell( title,
580 xmDialogShellWidgetClass,
581 parent,
582 XmNtitle, title,
583 XmNallowShellResize, False,
586 XtAddCallback( box, XmNpopdownCallback, __vi_cancel_cb, 0 );
587 XtAddCallback( box, XmNdestroyCallback, destroyed, 0 );
588 XtAddEventHandler( box,
589 SubstructureNotifyMask,
590 False,
591 window_unmapped,
592 NULL
595 form = XtVaCreateWidget( "options",
596 xmFormWidgetClass,
597 box,
601 /* copy the pointers to the sheet names */
602 *buffer = '\0';
603 for (i=0; i<XtNumber(sheets); i++) {
604 strcat( buffer, "|" );
605 strcat( buffer, sheets[i].name );
608 inner = __vi_CreateTabbedFolder( "tabs",
609 form,
610 buffer,
611 XtNumber(sheets),
612 change_sheet
615 /* build the property sheets early */
616 for ( i=0; i<XtNumber(sheets); i++ )
617 change_sheet( inner, i );
619 /* manage all of the sheets right now */
620 for ( i=0; i<XtNumber(sheets); i++ )
621 XtManageChild( sheets[i].holder );
622 XtManageChild( form );
624 /* remove all but the first one */
625 for ( i=0; i<XtNumber(sheets); i++ )
626 XtUnmanageChild( sheets[i].holder );
627 change_sheet( inner, 0 ); /* show first sheet first */
629 /* keep this global, we might destroy it later */
630 preferences = form;
632 /* done */
633 return form;
639 * module entry point
641 * __vi_show_options_dialog --
644 * PUBLIC: void __vi_show_options_dialog __P((Widget, String));
646 void
647 __vi_show_options_dialog(parent, title)
648 Widget parent;
649 String title;
651 Widget db = create_options_dialog( parent, title );
652 #if defined(SelfTest)
653 Widget shell = XtParent( db );
654 #endif
656 XtManageChild( db );
658 #if defined(SelfTest)
659 /* wait until it goes away */
660 XtPopup( shell, XtGrabNone );
661 #else
662 /* wait until it goes away */
663 __vi_modal_dialog( db );
664 #endif
669 /* module entry point
670 * Utilities for the search dialog
672 * __vi_toggle --
673 * Returns the current value of a toggle.
675 * PUBLIC: int __vi_toggle __P((char *));
678 __vi_toggle(name)
679 char *name;
681 optData *opt;
683 #undef NSEARCH
684 #define NSEARCH(list) { \
685 for (opt = list; opt->kind != optTerminator; ++opt) \
686 if (!strcmp(opt->name, name)) \
687 return ((int)opt->value); \
689 NSEARCH(display);
690 NSEARCH(files);
691 NSEARCH(general);
692 NSEARCH(input);
693 NSEARCH(search);
695 return (0);
699 * __vi_create_search_toggles --
700 * Creates the search toggles. This is so the options and search widgets
701 * share their appearance.
703 * PUBLIC: Widget __vi_create_search_toggles __P((Widget, optData[]));
705 Widget
706 __vi_create_search_toggles(parent, list)
707 Widget parent;
708 optData list[];
710 optData *opt;
713 * Copy current options information into the search table.
715 * XXX
716 * This is an O(M*N) loop, but I don't think it matters.
718 for (opt = list; opt->kind != optTerminator; ++opt)
719 opt->value = (void *)__vi_toggle(opt->name);
721 return (create_toggles(parent, list));
725 #if defined(SelfTest)
727 #if defined(__STDC__)
728 static void show_options( Widget w, XtPointer data, XtPointer cbs )
729 #else
730 static void show_options( w, data, cbs )
731 Widget w;
732 XtPointer data;
733 XtPointer cbs;
734 #endif
736 __vi_show_options_dialog( data, "Preferences" );
739 main( int argc, char *argv[] )
741 XtAppContext ctx;
742 Widget top_level, rc, button;
743 extern exit();
745 /* create a top-level shell for the window manager */
746 top_level = XtVaAppInitialize( &ctx,
747 argv[0],
748 NULL, 0, /* options */
749 (ArgcType) &argc,
750 argv, /* might get modified */
751 NULL,
752 NULL
755 rc = XtVaCreateManagedWidget( "rc",
756 xmRowColumnWidgetClass,
757 top_level,
761 button = XtVaCreateManagedWidget( "Pop up options dialog",
762 xmPushButtonGadgetClass,
766 XtAddCallback( button, XmNactivateCallback, show_options, rc );
768 button = XtVaCreateManagedWidget( "Quit",
769 xmPushButtonGadgetClass,
773 XtAddCallback( button, XmNactivateCallback, exit, 0 );
775 XtRealizeWidget(top_level);
776 XtAppMainLoop(ctx);
778 #endif