add comment for later
[nvi.git] / motif_l / m_options.c
blob9e3838977f4cb5410afc919123d693ba3b15015d
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.21 2001/06/25 15:19:27 skimo Exp $ (Berkeley) $Date: 2001/06/25 15:19:27 $";
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 extern int vi_ofd;
41 static void set_opt __P((Widget, XtPointer, XtPointer));
44 /* constants */
46 #if defined(SelfTest)
48 /* in production, get these from the resource list */
50 #define toggleColumns 6
52 #endif
56 * global data
59 static Widget preferences = NULL;
61 static optData display[] = {
62 { optToggle, "comment", },
63 { optToggle, "flash", },
64 { optToggle, "leftright", },
65 { optToggle, "list", },
66 { optToggle, "number", },
67 { optToggle, "octal", },
68 { optToggle, "ruler", },
69 { optToggle, "showmode", },
70 { optToggle, "slowopen", },
71 { optToggle, "verbose", },
72 { optToggle, "windowname", },
73 { optTerminator, },
74 }, display_int[] = {
75 { optInteger, "report", },
76 { optInteger, "scroll", },
77 { optInteger, "shiftwidth", },
78 { optInteger, "sidescroll", },
79 { optInteger, "tabstop", },
80 { optInteger, "window", },
81 { optTerminator, },
82 }, display_str[] = {
83 { optString, "noprint", },
84 { optString, "print", },
85 { optTerminator, },
86 }, files[] = {
87 { optToggle, "autowrite", },
88 { optToggle, "lock", },
89 { optToggle, "readonly", },
90 { optToggle, "writeany", },
91 { optTerminator, },
92 }, files_str[] = {
93 { optString, "backup", },
94 { optString, "path", },
95 { optTerminator, },
96 }, general[] = {
97 { optToggle, "exrc", },
98 { optToggle, "lisp", },
99 { optToggle, "modeline", },
100 { optToggle, "sourceany", },
101 { optToggle, "tildeop", },
102 { optTerminator, },
103 }, general_int[] = {
104 { optInteger, "taglength", },
105 { optTerminator, },
106 }, general_str[] = {
107 { optString, "cdpath", },
108 { optString, "directory", },
109 { optString, "msgcat", },
110 { optString, "recdir", },
111 { optString, "shell", },
112 { optString, "shellmeta", },
113 { optString, "tags", },
114 { optTerminator, },
115 }, input[] = {
116 { optToggle, "altwerase", },
117 { optToggle, "autoindent", },
118 { optToggle, "remap", },
119 { optToggle, "showmatch", },
120 { optToggle, "ttywerase", },
121 { optTerminator, },
122 }, input_int[] = {
123 { optInteger, "escapetime", },
124 { optInteger, "keytime", },
125 { optInteger, "matchtime", },
126 { optInteger, "timeout", },
127 { optInteger, "wraplen", },
128 { optInteger, "wrapmargin", },
129 { optTerminator, },
130 }, input_str[] = {
131 { optString, "cedit", },
132 { optString, "filec", },
133 { optTerminator, },
134 }, search[] = {
135 { optToggle, "extended", },
136 { optToggle, "iclower", },
137 { optToggle, "ignorecase", },
138 { optToggle, "magic", },
139 { optToggle, "searchincr", },
140 { optToggle, "wrapscan", },
141 { optTerminator, },
142 }, search_str[] = {
143 { optString, "paragraphs", },
144 { optString, "sections", },
145 { optTerminator, },
148 /* ********* NOTE ***********
149 * Sheet 0 will always be shown first. It does not matter to the Xt code
150 * which sheet that is, so it ought to be the one users interact with most.
151 * Best guess is that's general editor options, but it might be Search/re.
152 * ********* NOTE ***********
154 static optSheet sheets[] = {
155 { "Display",
156 "These options control how text is displayed on the screen",
157 NULL,
158 display,
159 display_int,
160 display_str,
162 { "Files",
163 "These options control how the editor handles files",
164 NULL,
165 files,
166 NULL,
167 files_str,
169 { "Input",
170 "These options control text input behavior",
171 NULL,
172 input,
173 input_int,
174 input_str,
176 { "Search/RE",
177 "These options control searching and Regular Expression behavior",
178 NULL,
179 search,
180 NULL,
181 search_str,
183 { "Editor",
184 "These options control general editor configuration",
185 NULL,
186 general,
187 general_int,
188 general_str,
193 /* callbacks */
195 #if defined(SelfTest)
196 void __vi_cancel_cb()
198 puts( "cancelled" );
200 #endif
203 static void destroyed(void)
205 int i;
207 puts( "destroyed" );
209 /* some window managers destroy us upon popdown */
210 for (i=0; i<XtNumber(sheets); i++) {
211 sheets[i].holder = NULL;
213 preferences = NULL;
217 static void window_unmapped(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont)
219 if ( ev->type == UnmapNotify ) {
220 #if defined(SelfTest)
221 puts( "unmapped" );
222 #endif
223 XtPopdown( XtParent( preferences ) );
228 * __vi_editopt --
229 * Set an edit option based on a core message.
231 * PUBLIC: int __vi_editopt __P((IPVI *, const char *, u_int32_t, const char *, u_int32_t, u_int32_t));
234 __vi_editopt(IPVI *ipvi, const char *str1, u_int32_t len1, const char *str2, u_int32_t len2, u_int32_t val1)
236 optData *opt;
238 #undef NSEARCH
239 #define NSEARCH(list) { \
240 for (opt = list; opt->kind != optTerminator; ++opt) \
241 if (!strcmp(opt->name, str1)) \
242 goto found; \
245 NSEARCH(display);
246 NSEARCH(display_int);
247 NSEARCH(display_str);
248 NSEARCH(files);
249 NSEARCH(files_str);
250 NSEARCH(general);
251 NSEARCH(general_int);
252 NSEARCH(general_str);
253 NSEARCH(input);
254 NSEARCH(input_int);
255 NSEARCH(input_str);
256 NSEARCH(search);
257 NSEARCH(search_str);
259 return (0);
261 found: switch (opt->kind) {
262 case optToggle:
263 opt->value = (void *)val1;
264 break;
265 case optInteger:
266 if (opt->value != NULL)
267 free(opt->value);
268 if ((opt->value = malloc(8)) != NULL)
269 (void)snprintf(opt->value,
270 8, "%lu", (u_long)val1);
271 break;
272 case optString:
273 case optFile:
274 if (opt->value != NULL)
275 free(opt->value);
276 if ((opt->value = malloc(len2)) != NULL)
277 memcpy(opt->value, str2, len2);
278 break;
279 case optTerminator:
280 abort();
282 return (0);
286 * set_opt --
287 * Send a set-edit-option message to core.
289 static void
290 set_opt(Widget w, XtPointer closure, XtPointer call_data)
292 optData *opt;
293 Boolean set;
294 IP_BUF ipb;
295 String str;
296 extern IPVI ipvi_motif;
298 opt = closure;
300 ipb.code = VI_EDITOPT;
301 ipb.str1 = opt->name;
302 ipb.len1 = strlen(opt->name);
304 switch (opt->kind) {
305 case optToggle:
306 XtVaGetValues(w, XmNset, &set, 0);
307 ipb.val1 = set;
308 ipb.len2 = 0;
310 vi_wsend(&ipvi_motif, "ab1", &ipb);
311 if (ipb.val1) {
312 opt->value = (void *)!set;
314 * RAZ:
315 * How do we turn off the button? We don't want to
316 * go recursive where we set it and it calls set_opt
317 * to tell the core. Is that possible?
319 XtVaSetValues(w, XmNset, &set, 0);
320 break;
323 if (strcmp(opt->name, "ruler") == 0)
324 if (set)
325 __vi_show_text_ruler_dialog(
326 __vi_screen->area, "Ruler");
327 else
328 __vi_clear_text_ruler_dialog();
329 break;
330 case optInteger:
331 str = XmTextFieldGetString(w);
332 ipb.val1 = atoi(str);
333 ipb.len2 = 0;
334 vi_send(vi_ofd, "ab1", &ipb);
335 break;
336 case optFile:
337 case optString:
338 ipb.str2 = XmTextFieldGetString(w);
339 ipb.len2 = strlen(ipb.str2);
340 vi_send(vi_ofd, "ab1", &ipb);
341 break;
342 case optTerminator:
343 abort();
348 /* add toggles to the property sheet */
350 #if defined(__STDC__)
351 static void add_toggle( Widget parent, optData *option )
352 #else
353 static void add_toggle( parent, option )
354 Widget parent;
355 optData *option;
356 #endif
358 Widget w;
360 w = XtVaCreateManagedWidget( option->name,
361 xmToggleButtonGadgetClass,
362 parent,
363 XmNset, (Boolean) option->value,
366 XtAddCallback( w, XmNvalueChangedCallback, set_opt, option );
370 static Widget create_toggles(Widget outer, optData *toggles)
372 Widget inner;
373 int i;
375 inner = XtVaCreateWidget( "toggleOptions",
376 xmRowColumnWidgetClass,
377 outer,
378 XmNpacking, XmPACK_COLUMN,
379 XmNnumColumns, 4,
380 XmNtopAttachment, XmATTACH_FORM,
381 XmNrightAttachment, XmATTACH_FORM,
382 XmNleftAttachment, XmATTACH_FORM,
386 /* first the booleans */
387 for (i=0; toggles[i].kind != optTerminator; i++) {
388 add_toggle( inner, &toggles[i] );
390 XtManageChild( inner );
392 return inner;
396 /* draw text fields and their labels */
398 #if defined(__STDC__)
399 static void add_string_options( Widget parent,
400 optData *options
402 #else
403 static void add_string_options( parent, options )
404 Widget parent;
405 optData *options;
406 #endif
408 int i;
409 Widget f, w;
411 for ( i=0; options[i].kind != optTerminator; i++ ) {
413 f = XtVaCreateWidget( "form",
414 xmFormWidgetClass,
415 parent,
419 XtVaCreateManagedWidget( options[i].name,
420 xmLabelGadgetClass,
422 XmNtopAttachment, XmATTACH_FORM,
423 XmNbottomAttachment, XmATTACH_FORM,
424 XmNleftAttachment, XmATTACH_FORM,
425 XmNrightAttachment, XmATTACH_POSITION,
426 XmNrightPosition, 20,
427 XmNalignment, XmALIGNMENT_END,
431 w = XtVaCreateManagedWidget( "text",
432 xmTextFieldWidgetClass,
434 XmNtopAttachment, XmATTACH_FORM,
435 XmNbottomAttachment, XmATTACH_FORM,
436 XmNrightAttachment, XmATTACH_FORM,
437 XmNleftAttachment, XmATTACH_POSITION,
438 XmNleftPosition, 20,
442 XmTextFieldSetString( w, (char *) options[i].value );
443 XtAddCallback( w, XmNactivateCallback, set_opt, &options[i] );
444 XtManageChild( f );
449 /* draw and display a single page of properties */
451 #if defined(__STDC__)
452 static Widget create_sheet( Widget parent, optSheet *sheet )
453 #else
454 static Widget create_sheet( parent, sheet )
455 Widget parent;
456 optSheet *sheet;
457 #endif
459 Widget outer, inner, frame;
460 Dimension height;
461 XmString str;
463 outer = XtVaCreateWidget( sheet->name,
464 xmFormWidgetClass,
465 parent,
466 XmNtopAttachment, XmATTACH_FORM,
467 XmNrightAttachment, XmATTACH_FORM,
468 XmNbottomAttachment, XmATTACH_FORM,
469 XmNleftAttachment, XmATTACH_FORM,
470 XmNshadowType, XmSHADOW_ETCHED_IN,
471 XmNshadowThickness, 2,
472 XmNverticalSpacing, 4,
473 XmNhorizontalSpacing, 4,
477 /* add descriptive text */
478 frame = XtVaCreateManagedWidget( "frame",
479 xmFrameWidgetClass,
480 outer,
481 XmNtopAttachment, XmATTACH_FORM,
482 XmNrightAttachment, XmATTACH_FORM,
483 XmNleftAttachment, XmATTACH_FORM,
486 str = XmStringCreateLtoR( sheet->description, XmSTRING_DEFAULT_CHARSET );
487 XtVaCreateManagedWidget( "description",
488 xmLabelGadgetClass,
489 frame,
490 XmNlabelString, str,
493 XmStringFree( str );
495 /* Add the toggles. */
496 inner = create_toggles( outer, sheet->toggles );
497 XtVaSetValues( inner,
498 XmNtopAttachment, XmATTACH_WIDGET,
499 XmNtopWidget, frame,
503 /* the string options go here */
504 inner = XtVaCreateWidget( "otherOptions",
505 xmRowColumnWidgetClass,
506 outer,
507 XmNpacking, XmPACK_COLUMN,
508 XmNtopAttachment, XmATTACH_WIDGET,
509 XmNtopWidget, inner,
510 XmNrightAttachment, XmATTACH_FORM,
511 XmNbottomAttachment, XmATTACH_FORM,
512 XmNleftAttachment, XmATTACH_FORM,
516 /* Optionally, the ints. */
517 if ( sheet->ints != NULL )
518 add_string_options( inner, sheet->ints );
520 /* Optionally, the rest. */
521 if ( sheet->others != NULL )
522 add_string_options( inner, sheet->others );
524 XtManageChild( inner );
526 /* finally, force resize of the parent */
527 XtVaGetValues( outer, XmNheight, &height, 0 );
528 XtVaSetValues( parent, XmNheight, height, 0 );
530 return outer;
534 /* change preferences to another sheet */
536 static void change_sheet(Widget parent, int current)
538 static int current_sheet = -1;
540 /* create a new one? */
541 if ( sheets[current].holder == NULL )
542 sheets[current].holder = create_sheet( parent, &sheets[current] );
544 /* done with the old one? */
545 if ( current_sheet != -1 && sheets[current_sheet].holder != NULL )
546 XtUnmanageChild( sheets[current_sheet].holder );
548 current_sheet = current;
549 XtManageChild( sheets[current].holder );
550 XtManageChild( parent );
554 /* Draw and display a dialog the describes vi options */
556 #if defined(__STDC__)
557 static Widget create_options_dialog( Widget parent, String title )
558 #else
559 static Widget create_options_dialog( parent, title )
560 Widget parent;
561 String title;
562 #endif
564 Widget box, form, inner;
565 int i;
566 char buffer[1024];
568 /* already built? */
569 if ( preferences != NULL ) return preferences;
571 box = XtVaCreatePopupShell( title,
572 xmDialogShellWidgetClass,
573 parent,
574 XmNtitle, title,
575 XmNallowShellResize, False,
578 XtAddCallback( box, XmNpopdownCallback, __vi_cancel_cb, 0 );
579 XtAddCallback( box, XmNdestroyCallback, destroyed, 0 );
580 XtAddEventHandler( box,
581 SubstructureNotifyMask,
582 False,
583 window_unmapped,
584 NULL
587 form = XtVaCreateWidget( "options",
588 xmFormWidgetClass,
589 box,
593 /* copy the pointers to the sheet names */
594 *buffer = '\0';
595 for (i=0; i<XtNumber(sheets); i++) {
596 strcat( buffer, "|" );
597 strcat( buffer, sheets[i].name );
600 inner = __vi_CreateTabbedFolder( "tabs",
601 form,
602 buffer,
603 XtNumber(sheets),
604 change_sheet
607 /* build the property sheets early */
608 for ( i=0; i<XtNumber(sheets); i++ )
609 change_sheet( inner, i );
611 /* manage all of the sheets right now */
612 for ( i=0; i<XtNumber(sheets); i++ )
613 XtManageChild( sheets[i].holder );
614 XtManageChild( form );
616 /* remove all but the first one */
617 for ( i=0; i<XtNumber(sheets); i++ )
618 XtUnmanageChild( sheets[i].holder );
619 change_sheet( inner, 0 ); /* show first sheet first */
621 /* keep this global, we might destroy it later */
622 preferences = form;
624 /* done */
625 return form;
631 * module entry point
633 * __vi_show_options_dialog --
636 * PUBLIC: void __vi_show_options_dialog __P((Widget, String));
638 void
639 __vi_show_options_dialog(Widget parent, String title)
641 Widget db = create_options_dialog( parent, title );
642 #if defined(SelfTest)
643 Widget shell = XtParent( db );
644 #endif
646 XtManageChild( db );
648 #if defined(SelfTest)
649 /* wait until it goes away */
650 XtPopup( shell, XtGrabNone );
651 #else
652 /* wait until it goes away */
653 __vi_modal_dialog( db );
654 #endif
659 /* module entry point
660 * Utilities for the search dialog
662 * __vi_toggle --
663 * Returns the current value of a toggle.
665 * PUBLIC: int __vi_toggle __P((char *));
668 __vi_toggle(char *name)
670 optData *opt;
672 #undef NSEARCH
673 #define NSEARCH(list) { \
674 for (opt = list; opt->kind != optTerminator; ++opt) \
675 if (!strcmp(opt->name, name)) \
676 return ((int)opt->value); \
678 NSEARCH(display);
679 NSEARCH(files);
680 NSEARCH(general);
681 NSEARCH(input);
682 NSEARCH(search);
684 return (0);
688 * __vi_create_search_toggles --
689 * Creates the search toggles. This is so the options and search widgets
690 * share their appearance.
692 * PUBLIC: Widget __vi_create_search_toggles __P((Widget, optData[]));
694 Widget
695 __vi_create_search_toggles(Widget parent, optData *list)
697 optData *opt;
700 * Copy current options information into the search table.
702 * XXX
703 * This is an O(M*N) loop, but I don't think it matters.
705 for (opt = list; opt->kind != optTerminator; ++opt)
706 opt->value = (void *)__vi_toggle(opt->name);
708 return (create_toggles(parent, list));
712 #if defined(SelfTest)
714 #if defined(__STDC__)
715 static void show_options( Widget w, XtPointer data, XtPointer cbs )
716 #else
717 static void show_options( w, data, cbs )
718 Widget w;
719 XtPointer data;
720 XtPointer cbs;
721 #endif
723 __vi_show_options_dialog( data, "Preferences" );
726 main( int argc, char *argv[] )
728 XtAppContext ctx;
729 Widget top_level, rc, button;
730 extern exit();
732 /* create a top-level shell for the window manager */
733 top_level = XtVaAppInitialize( &ctx,
734 argv[0],
735 NULL, 0, /* options */
736 (ArgcType) &argc,
737 argv, /* might get modified */
738 NULL,
739 NULL
742 rc = XtVaCreateManagedWidget( "rc",
743 xmRowColumnWidgetClass,
744 top_level,
748 button = XtVaCreateManagedWidget( "Pop up options dialog",
749 xmPushButtonGadgetClass,
753 XtAddCallback( button, XmNactivateCallback, show_options, rc );
755 button = XtVaCreateManagedWidget( "Quit",
756 xmPushButtonGadgetClass,
760 XtAddCallback( button, XmNactivateCallback, exit, 0 );
762 XtRealizeWidget(top_level);
763 XtAppMainLoop(ctx);
765 #endif