clean up naming, add select functions
[nvi.git] / motif_l / m_menu.c
blob250624f89dd57c9360d32169de208cf54ec11982
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_menu.c,v 8.23 1996/12/18 10:26:33 bostic Exp $ (Berkeley) $Date: 1996/12/18 10:26:33 $";
14 #endif /* not lint */
16 #include <sys/queue.h>
18 #include <X11/Intrinsic.h>
19 #include <X11/StringDefs.h>
20 #include <Xm/PushB.h>
21 #include <Xm/CascadeB.h>
22 #include <Xm/RowColumn.h>
23 #include <Xm/Separator.h>
24 #include <Xm/FileSB.h>
25 #include <Xm/SelectioB.h>
27 #include <bitstring.h>
28 #include <stdio.h>
30 #include "../common/common.h"
31 #include "../ipc/ip.h"
32 #include "m_motif.h"
34 /* save this for creation of children */
35 static Widget main_widget = NULL;
37 /* This module defines the menu structure for vi. Each menu
38 * item has an action routine associated with it. For the most
39 * part, those actions will simply call vi_send with vi commands.
40 * others will pop up file selection dialogs and use them for
41 * vi commands, and other will have to have special actions.
43 * Future:
44 * vi core will have to let us know when to be sensitive
45 * change VI_STRING to VI_COMMAND so that menu actions cannot
46 * be confusing when in insert mode
47 * need VI_CUT, VI_COPY, and VI_PASTE to perform the appropriate
48 * operations on the visible text of yank buffer. VI_COPY
49 * is likely a NOP, but it will make users happy
50 * add mnemonics
51 * add accelerators
52 * implement file selection dialog boxes
53 * implement string prompt dialog boxes (e.g. for 'find')
55 * Interface:
56 * Widget create_menubar( Widget parent ) creates and returns the
57 * X menu structure. The caller can place this
58 * anywhere in the widget heirarchy.
61 #define BufferSize 1024
64 * __vi_send_command_string --
65 * Utility: Send a menu command to vi
67 * Future:
68 * Change VI_STRING to VI_COMMAND so that menu actions cannot be confusing
69 * when in insert mode.
71 * XXX
72 * THIS SHOULD GO AWAY -- WE SHOULDN'T SEND UNINTERPRETED STRINGS TO THE
73 * CORE.
75 * PUBLIC: void __vi_send_command_string __P((String));
77 void
78 __vi_send_command_string(str)
79 String str;
81 IP_BUF ipb;
82 char buffer[BufferSize];
84 /* Future: Need VI_COMMAND so vi knows this is not text to insert
85 * At that point, appending a cr/lf will not be necessary. For now,
86 * append iff we are a colon or slash command. Of course, if we are in
87 * insert mode, all bets are off.
89 strcpy( buffer, str );
90 switch ( *str ) {
91 case ':':
92 case '/':
93 strcat( buffer, "\n" );
94 break;
97 ipb.code = VI_STRING;
98 ipb.str1 = buffer;
99 ipb.len1 = strlen(buffer);
100 vi_send("a", &ipb);
104 /* Utility: beep for unimplemented command */
106 #if defined(__STDC__)
107 static void send_beep( Widget w )
108 #else
109 static void send_beep( w )
110 Widget w;
111 #endif
113 XBell( XtDisplay(w), 0 );
118 * __vi_cancel_cb --
119 * Utility: make a dialog box go Modal
121 * PUBLIC: void __vi_cancel_cb __P((Widget, XtPointer, XtPointer));
123 static Bool have_answer;
124 void
125 __vi_cancel_cb(w, client_data, call_data)
126 Widget w;
127 XtPointer client_data, call_data;
129 have_answer = True;
133 * PUBLIC: void __vi_modal_dialog __P((Widget));
135 void
136 __vi_modal_dialog( db )
137 Widget db;
139 XtAppContext ctx;
141 /* post the dialog */
142 XtManageChild( db );
143 XtPopup( XtParent(db), XtGrabExclusive );
145 /* wait for a response */
146 ctx = XtWidgetToApplicationContext(db);
147 XtAddGrab( XtParent(db), TRUE, FALSE );
148 for ( have_answer = False; ! have_answer; )
149 XtAppProcessEvent( ctx, XtIMAll );
151 /* done with db */
152 XtPopdown( XtParent(db) );
153 XtRemoveGrab( XtParent(db) );
157 /* Utility: Get a file (using standard File Selection Dialog Box) */
159 static String file_name;
162 #if defined(__STDC__)
163 static void ok_file_name( Widget w,
164 XtPointer client_data,
165 XtPointer call_data
167 #else
168 static void ok_file_name( w, client_data, call_data )
169 Widget w;
170 XtPointer client_data;
171 XtPointer call_data;
172 #endif
174 XmFileSelectionBoxCallbackStruct *cbs;
176 cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
177 XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &file_name );
179 have_answer = True;
183 #if defined(__STDC__)
184 static String get_file( Widget w, String prompt )
185 #else
186 static String get_file( w, prompt )
187 Widget w;
188 String prompt;
189 #endif
191 /* make it static so we can reuse it */
192 static Widget db;
194 /* our return parameter */
195 if ( file_name != NULL ) {
196 XtFree( file_name );
197 file_name = NULL;
200 /* create one? */
201 if ( db == NULL ){
202 db = XmCreateFileSelectionDialog( main_widget, "file", NULL, 0 );
203 XtAddCallback( db, XmNokCallback, ok_file_name, NULL );
204 XtAddCallback( db, XmNcancelCallback, __vi_cancel_cb, NULL );
207 /* use the title as a prompt */
208 XtVaSetValues( XtParent(db), XmNtitle, prompt, 0 );
210 /* wait for a response */
211 __vi_modal_dialog( db );
213 /* done */
214 return file_name;
219 * file_command --
220 * Get a file name and send it with the command to the core.
222 static void
223 file_command(w, code, prompt)
224 Widget w;
225 int code;
226 String prompt;
228 IP_BUF ipb;
229 char *file;
231 if ((file = get_file(w, prompt)) != NULL) {
232 ipb.code = code;
233 ipb.str1 = file;
234 ipb.len1 = strlen(file);
235 vi_send("a", &ipb);
241 * Menu action routines (one per menu entry)
243 * These are in the order in which they appear in the menu structure.
245 static void
246 ma_edit_file(w, call_data, client_data)
247 Widget w;
248 XtPointer call_data, client_data;
250 file_command(w, VI_EDIT, "Edit");
253 static void
254 ma_split(w, call_data, client_data)
255 Widget w;
256 XtPointer call_data, client_data;
258 file_command(w, VI_EDITSPLIT, "Edit");
261 static void
262 ma_save(w, call_data, client_data)
263 Widget w;
264 XtPointer call_data, client_data;
266 IP_BUF ipb;
268 ipb.code = VI_WRITE;
269 (void)vi_send(NULL, &ipb);
272 static void
273 ma_save_as(w, call_data, client_data)
274 Widget w;
275 XtPointer call_data, client_data;
277 file_command(w, VI_WRITEAS, "Save As");
280 static void
281 ma_wq(w, call_data, client_data)
282 Widget w;
283 XtPointer call_data, client_data;
285 IP_BUF ipb;
287 ipb.code = VI_WQ;
288 (void)vi_send(NULL, &ipb);
291 static void
292 ma_quit(w, call_data, client_data)
293 Widget w;
294 XtPointer call_data, client_data;
296 IP_BUF ipb;
298 ipb.code = VI_QUIT;
299 (void)vi_send(NULL, &ipb);
302 static void
303 ma_undo(w, call_data, client_data)
304 Widget w;
305 XtPointer call_data, client_data;
307 IP_BUF ipb;
309 ipb.code = VI_UNDO;
310 (void)vi_send(NULL, &ipb);
313 #if defined(__STDC__)
314 static void ma_cut( Widget w,
315 XtPointer call_data,
316 XtPointer client_data
318 #else
319 static void ma_cut( w, call_data, client_data )
320 Widget w;
321 XtPointer call_data;
322 XtPointer client_data;
323 #endif
325 /* future */
326 send_beep( w );
330 #if defined(__STDC__)
331 static void ma_copy( Widget w,
332 XtPointer call_data,
333 XtPointer client_data
335 #else
336 static void ma_copy( w, call_data, client_data )
337 Widget w;
338 XtPointer call_data;
339 XtPointer client_data;
340 #endif
342 /* future */
343 send_beep( w );
347 #if defined(__STDC__)
348 static void ma_paste( Widget w,
349 XtPointer call_data,
350 XtPointer client_data
352 #else
353 static void ma_paste( w, call_data, client_data )
354 Widget w;
355 XtPointer call_data;
356 XtPointer client_data;
357 #endif
359 /* future */
360 send_beep( w );
363 static void
364 ma_find(w, call_data, client_data)
365 Widget w;
366 XtPointer call_data, client_data;
368 __vi_show_search_dialog( main_widget, "Find" );
371 static void
372 ma_find_next(w, call_data, client_data)
373 Widget w;
374 XtPointer call_data, client_data;
376 __vi_search( w );
379 static void
380 ma_tags(w, call_data, client_data)
381 Widget w;
382 XtPointer call_data, client_data;
384 __vi_show_tags_dialog( main_widget, "Tag Stack" );
387 static void
388 ma_tagpop(w, call_data, client_data)
389 Widget w;
390 XtPointer call_data, client_data;
392 __vi_send_command_string( "\024" );
395 static void
396 ma_tagtop(w, call_data, client_data)
397 Widget w;
398 XtPointer call_data, client_data;
400 __vi_send_command_string( ":tagtop" );
403 #if defined(__STDC__)
404 static void ma_preferences( Widget w,
405 XtPointer call_data,
406 XtPointer client_data
408 #else
409 static void ma_preferences( w, call_data, client_data )
410 Widget w;
411 XtPointer call_data;
412 XtPointer client_data;
413 #endif
415 __vi_show_options_dialog( main_widget, "Preferences" );
419 /* Menu construction routines */
421 typedef struct {
422 String title;
423 void (*action)();
424 String accel; /* for Motif */
425 String accel_text; /* for the user */
426 } pull_down;
428 typedef struct {
429 char mnemonic;
430 String title;
431 pull_down *actions;
432 } menu_bar;
434 static pull_down file_menu[] = {
435 { "Edit File...", ma_edit_file, "Alt<Key>e", "Alt+E" },
436 { "", NULL, NULL, NULL },
437 { "Split Window...", ma_split, NULL, NULL },
438 { "", NULL, NULL, NULL },
439 { "Save ", ma_save, "Alt<Key>s", "Alt+S" },
440 { "Save As...", ma_save_as, "Shift Alt<Key>s", "Shift+Alt+S" },
441 { "", NULL, NULL, NULL },
442 { "Write and Quit", ma_wq, "Shift Alt<Key>q", "Shift+Alt+Q" },
443 { "Quit", ma_quit, "Alt<Key>q", "Alt+Q" },
444 { NULL, NULL, NULL, NULL },
447 static pull_down edit_menu[] = {
448 { "Undo", ma_undo, NULL, NULL },
449 { "", NULL, NULL, NULL },
450 { "Cut", ma_cut, "Alt<Key>x", "Alt+X" },
451 { "Copy", ma_copy, "Alt<Key>c", "Alt+C" },
452 { "Paste", ma_paste, "Alt<Key>v", "Alt+V" },
453 { "", NULL, NULL, NULL },
454 { "Find", ma_find, "Alt<Key>f", "Alt+F" },
455 { "Find Next", ma_find_next, "Alt<Key>g", "Alt+G" },
456 { NULL, NULL, NULL, NULL },
459 static pull_down options_menu[] = {
460 { "Preferences", ma_preferences, NULL, NULL },
461 { "Command Mode Maps", NULL, NULL, NULL },
462 { "Insert Mode Maps", NULL, NULL, NULL },
463 { NULL, NULL, NULL, NULL },
466 static pull_down tag_menu[] = {
467 { "Show Tag Stack", ma_tags, "Alt<Key>t", "Alt+T" },
468 { "", NULL, NULL, NULL },
469 { "Pop Tag", ma_tagpop, NULL, NULL },
470 { "Clear Stack", ma_tagtop, NULL, NULL },
471 { NULL, NULL, NULL, NULL },
474 static pull_down help_menu[] = {
475 { NULL, NULL, NULL, NULL },
478 static menu_bar main_menu[] = {
479 { 'F', "File", file_menu },
480 { 'E', "Edit", edit_menu },
481 { 'O', "Options", options_menu },
482 { 'T', "Tag", tag_menu },
483 { 'H', "Help", help_menu },
484 { 0, NULL, NULL },
488 #if defined(__STDC__)
489 static void add_entries( Widget parent, pull_down *actions )
490 #else
491 static void add_entries( parent, actions )
492 Widget parent;
493 pull_down *actions;
494 #endif
496 Widget w;
497 XmString str;
499 for ( ; actions->title != NULL; actions++ ) {
501 /* a separator? */
502 if ( *actions->title != '\0' ) {
503 w = XmCreatePushButton( parent, actions->title, NULL, 0 );
504 if ( actions->action == NULL )
505 XtSetSensitive( w, False );
506 else
507 XtAddCallback( w,
508 XmNactivateCallback,
509 (XtCallbackProc) actions->action,
510 actions
512 if ( actions->accel != NULL ) {
513 str = XmStringCreateSimple( actions->accel_text );
514 XtVaSetValues( w,
515 XmNaccelerator, actions->accel,
516 XmNacceleratorText, str,
519 XmStringFree( str );
522 else {
523 w = XmCreateSeparator( parent, "separator", NULL, 0 );
526 XtManageChild( w );
532 * vi_create_menubar --
534 * PUBLIC: Widget vi_create_menubar __P((Widget));
536 Widget
537 vi_create_menubar(parent)
538 Widget parent;
540 Widget menu, pull, button;
541 menu_bar *ptr;
543 /* save this for creation of children */
544 main_widget = parent;
546 menu = XmCreateMenuBar( parent, "Menu", NULL, 0 );
548 for ( ptr=main_menu; ptr->title != NULL; ptr++ ) {
550 pull = XmCreatePulldownMenu( menu, "pull", NULL, 0 );
551 add_entries( pull, ptr->actions );
552 button = XmCreateCascadeButton( menu, ptr->title, NULL, 0 );
553 XtVaSetValues( button, XmNsubMenuId, pull, 0 );
555 if ( strcmp( ptr->title, "Help" ) == 0 )
556 XtVaSetValues( menu, XmNmenuHelpWidget, button, 0 );
558 #if 0
559 /* These screw up accelerator processing. Punt for now */
560 if ( ptr->mnemonic )
561 XtVaSetValues( button, XmNmnemonic, ptr->mnemonic, 0 );
562 #endif
564 XtManageChild( button );
567 return menu;