add comment for later
[nvi.git] / motif_l / m_menu.c
blobb395c2328f7a42f2c3c8a1623f8d81c6a4e6714d
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.25 2001/06/25 15:19:27 skimo Exp $ (Berkeley) $Date: 2001/06/25 15:19:27 $";
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 extern int vi_ofd;
36 /* save this for creation of children */
37 static Widget main_widget = NULL;
39 /* This module defines the menu structure for vi. Each menu
40 * item has an action routine associated with it. For the most
41 * part, those actions will simply call vi_send with vi commands.
42 * others will pop up file selection dialogs and use them for
43 * vi commands, and other will have to have special actions.
45 * Future:
46 * vi core will have to let us know when to be sensitive
47 * change VI_STRING to VI_COMMAND so that menu actions cannot
48 * be confusing when in insert mode
49 * need VI_CUT, VI_COPY, and VI_PASTE to perform the appropriate
50 * operations on the visible text of yank buffer. VI_COPY
51 * is likely a NOP, but it will make users happy
52 * add mnemonics
53 * add accelerators
54 * implement file selection dialog boxes
55 * implement string prompt dialog boxes (e.g. for 'find')
57 * Interface:
58 * Widget create_menubar( Widget parent ) creates and returns the
59 * X menu structure. The caller can place this
60 * anywhere in the widget heirarchy.
63 #define BufferSize 1024
66 * __vi_send_command_string --
67 * Utility: Send a menu command to vi
69 * Future:
70 * Change VI_STRING to VI_COMMAND so that menu actions cannot be confusing
71 * when in insert mode.
73 * XXX
74 * THIS SHOULD GO AWAY -- WE SHOULDN'T SEND UNINTERPRETED STRINGS TO THE
75 * CORE.
77 * PUBLIC: void __vi_send_command_string __P((String));
79 void
80 __vi_send_command_string(String str)
82 IP_BUF ipb;
83 char buffer[BufferSize];
85 /* Future: Need VI_COMMAND so vi knows this is not text to insert
86 * At that point, appending a cr/lf will not be necessary. For now,
87 * append iff we are a colon or slash command. Of course, if we are in
88 * insert mode, all bets are off.
90 strcpy( buffer, str );
91 switch ( *str ) {
92 case ':':
93 case '/':
94 strcat( buffer, "\n" );
95 break;
98 ipb.code = VI_STRING;
99 ipb.str1 = buffer;
100 ipb.len1 = strlen(buffer);
101 vi_send(vi_ofd, "a", &ipb);
105 /* Utility: beep for unimplemented command */
107 #if defined(__STDC__)
108 static void send_beep( Widget w )
109 #else
110 static void send_beep( w )
111 Widget w;
112 #endif
114 XBell( XtDisplay(w), 0 );
119 * __vi_cancel_cb --
120 * Utility: make a dialog box go Modal
122 * PUBLIC: void __vi_cancel_cb __P((Widget, XtPointer, XtPointer));
124 static Bool have_answer;
125 void
126 __vi_cancel_cb(Widget w, XtPointer client_data, XtPointer call_data)
128 have_answer = True;
132 * PUBLIC: void __vi_modal_dialog __P((Widget));
134 void
135 __vi_modal_dialog(Widget db)
137 XtAppContext ctx;
139 /* post the dialog */
140 XtManageChild( db );
141 XtPopup( XtParent(db), XtGrabExclusive );
143 /* wait for a response */
144 ctx = XtWidgetToApplicationContext(db);
145 XtAddGrab( XtParent(db), TRUE, FALSE );
146 for ( have_answer = False; ! have_answer; )
147 XtAppProcessEvent( ctx, XtIMAll );
149 /* done with db */
150 XtPopdown( XtParent(db) );
151 XtRemoveGrab( XtParent(db) );
155 /* Utility: Get a file (using standard File Selection Dialog Box) */
157 static String file_name;
160 #if defined(__STDC__)
161 static void ok_file_name( Widget w,
162 XtPointer client_data,
163 XtPointer call_data
165 #else
166 static void ok_file_name( w, client_data, call_data )
167 Widget w;
168 XtPointer client_data;
169 XtPointer call_data;
170 #endif
172 XmFileSelectionBoxCallbackStruct *cbs;
174 cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
175 XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &file_name );
177 have_answer = True;
181 #if defined(__STDC__)
182 static String get_file( Widget w, String prompt )
183 #else
184 static String get_file( w, prompt )
185 Widget w;
186 String prompt;
187 #endif
189 /* make it static so we can reuse it */
190 static Widget db;
192 /* our return parameter */
193 if ( file_name != NULL ) {
194 XtFree( file_name );
195 file_name = NULL;
198 /* create one? */
199 if ( db == NULL ){
200 db = XmCreateFileSelectionDialog( main_widget, "file", NULL, 0 );
201 XtAddCallback( db, XmNokCallback, ok_file_name, NULL );
202 XtAddCallback( db, XmNcancelCallback, __vi_cancel_cb, NULL );
205 /* use the title as a prompt */
206 XtVaSetValues( XtParent(db), XmNtitle, prompt, 0 );
208 /* wait for a response */
209 __vi_modal_dialog( db );
211 /* done */
212 return file_name;
217 * file_command --
218 * Get a file name and send it with the command to the core.
220 static void
221 file_command(Widget w, int code, String prompt)
223 IP_BUF ipb;
224 char *file;
226 if ((file = get_file(w, prompt)) != NULL) {
227 ipb.code = code;
228 ipb.str1 = file;
229 ipb.len1 = strlen(file);
230 vi_send(vi_ofd, "a", &ipb);
236 * Menu action routines (one per menu entry)
238 * These are in the order in which they appear in the menu structure.
240 static void
241 ma_edit_file(Widget w, XtPointer call_data, XtPointer client_data)
243 file_command(w, VI_EDIT, "Edit");
246 static void
247 ma_split(Widget w, XtPointer call_data, XtPointer client_data)
249 file_command(w, VI_EDITSPLIT, "Edit");
252 static void
253 ma_save(Widget w, XtPointer call_data, XtPointer client_data)
255 IP_BUF ipb;
257 ipb.code = VI_WRITE;
258 (void)vi_send(vi_ofd, NULL, &ipb);
261 static void
262 ma_save_as(Widget w, XtPointer call_data, XtPointer client_data)
264 file_command(w, VI_WRITEAS, "Save As");
267 static void
268 ma_wq(Widget w, XtPointer call_data, XtPointer client_data)
270 IP_BUF ipb;
272 ipb.code = VI_WQ;
273 (void)vi_send(vi_ofd, NULL, &ipb);
276 static void
277 ma_quit(Widget w, XtPointer call_data, XtPointer client_data)
279 IP_BUF ipb;
281 ipb.code = VI_QUIT;
282 (void)vi_send(vi_ofd, NULL, &ipb);
285 static void
286 ma_undo(Widget w, XtPointer call_data, XtPointer client_data)
288 IP_BUF ipb;
290 ipb.code = VI_UNDO;
291 (void)vi_send(vi_ofd, NULL, &ipb);
294 #if defined(__STDC__)
295 static void ma_cut( Widget w,
296 XtPointer call_data,
297 XtPointer client_data
299 #else
300 static void ma_cut( w, call_data, client_data )
301 Widget w;
302 XtPointer call_data;
303 XtPointer client_data;
304 #endif
306 /* future */
307 send_beep( w );
311 #if defined(__STDC__)
312 static void ma_copy( Widget w,
313 XtPointer call_data,
314 XtPointer client_data
316 #else
317 static void ma_copy( w, call_data, client_data )
318 Widget w;
319 XtPointer call_data;
320 XtPointer client_data;
321 #endif
323 /* future */
324 send_beep( w );
328 #if defined(__STDC__)
329 static void ma_paste( Widget w,
330 XtPointer call_data,
331 XtPointer client_data
333 #else
334 static void ma_paste( w, call_data, client_data )
335 Widget w;
336 XtPointer call_data;
337 XtPointer client_data;
338 #endif
340 /* future */
341 send_beep( w );
344 static void
345 ma_find(Widget w, XtPointer call_data, XtPointer client_data)
347 __vi_show_search_dialog( main_widget, "Find" );
350 static void
351 ma_find_next(Widget w, XtPointer call_data, XtPointer client_data)
353 __vi_search( w );
356 static void
357 ma_tags(Widget w, XtPointer call_data, XtPointer client_data)
359 __vi_show_tags_dialog( main_widget, "Tag Stack" );
362 static void
363 ma_tagpop(Widget w, XtPointer call_data, XtPointer client_data)
365 __vi_send_command_string( "\024" );
368 static void
369 ma_tagtop(Widget w, XtPointer call_data, XtPointer client_data)
371 __vi_send_command_string( ":tagtop" );
374 #if defined(__STDC__)
375 static void ma_preferences( Widget w,
376 XtPointer call_data,
377 XtPointer client_data
379 #else
380 static void ma_preferences( w, call_data, client_data )
381 Widget w;
382 XtPointer call_data;
383 XtPointer client_data;
384 #endif
386 __vi_show_options_dialog( main_widget, "Preferences" );
390 /* Menu construction routines */
392 typedef struct {
393 String title;
394 void (*action)();
395 String accel; /* for Motif */
396 String accel_text; /* for the user */
397 } pull_down;
399 typedef struct {
400 char mnemonic;
401 String title;
402 pull_down *actions;
403 } menu_bar;
405 static pull_down file_menu[] = {
406 { "Edit File...", ma_edit_file, "Alt<Key>e", "Alt+E" },
407 { "", NULL, NULL, NULL },
408 { "Split Window...", ma_split, NULL, NULL },
409 { "", NULL, NULL, NULL },
410 { "Save ", ma_save, "Alt<Key>s", "Alt+S" },
411 { "Save As...", ma_save_as, "Shift Alt<Key>s", "Shift+Alt+S" },
412 { "", NULL, NULL, NULL },
413 { "Write and Quit", ma_wq, "Shift Alt<Key>q", "Shift+Alt+Q" },
414 { "Quit", ma_quit, "Alt<Key>q", "Alt+Q" },
415 { NULL, NULL, NULL, NULL },
418 static pull_down edit_menu[] = {
419 { "Undo", ma_undo, NULL, NULL },
420 { "", NULL, NULL, NULL },
421 { "Cut", ma_cut, "Alt<Key>x", "Alt+X" },
422 { "Copy", ma_copy, "Alt<Key>c", "Alt+C" },
423 { "Paste", ma_paste, "Alt<Key>v", "Alt+V" },
424 { "", NULL, NULL, NULL },
425 { "Find", ma_find, "Alt<Key>f", "Alt+F" },
426 { "Find Next", ma_find_next, "Alt<Key>g", "Alt+G" },
427 { NULL, NULL, NULL, NULL },
430 static pull_down options_menu[] = {
431 { "Preferences", ma_preferences, NULL, NULL },
432 { "Command Mode Maps", NULL, NULL, NULL },
433 { "Insert Mode Maps", NULL, NULL, NULL },
434 { NULL, NULL, NULL, NULL },
437 static pull_down tag_menu[] = {
438 { "Show Tag Stack", ma_tags, "Alt<Key>t", "Alt+T" },
439 { "", NULL, NULL, NULL },
440 { "Pop Tag", ma_tagpop, NULL, NULL },
441 { "Clear Stack", ma_tagtop, NULL, NULL },
442 { NULL, NULL, NULL, NULL },
445 static pull_down help_menu[] = {
446 { NULL, NULL, NULL, NULL },
449 static menu_bar main_menu[] = {
450 { 'F', "File", file_menu },
451 { 'E', "Edit", edit_menu },
452 { 'O', "Options", options_menu },
453 { 'T', "Tag", tag_menu },
454 { 'H', "Help", help_menu },
455 { 0, NULL, NULL },
459 #if defined(__STDC__)
460 static void add_entries( Widget parent, pull_down *actions )
461 #else
462 static void add_entries( parent, actions )
463 Widget parent;
464 pull_down *actions;
465 #endif
467 Widget w;
468 XmString str;
470 for ( ; actions->title != NULL; actions++ ) {
472 /* a separator? */
473 if ( *actions->title != '\0' ) {
474 w = XmCreatePushButton( parent, actions->title, NULL, 0 );
475 if ( actions->action == NULL )
476 XtSetSensitive( w, False );
477 else
478 XtAddCallback( w,
479 XmNactivateCallback,
480 (XtCallbackProc) actions->action,
481 actions
483 if ( actions->accel != NULL ) {
484 str = XmStringCreateSimple( actions->accel_text );
485 XtVaSetValues( w,
486 XmNaccelerator, actions->accel,
487 XmNacceleratorText, str,
490 XmStringFree( str );
493 else {
494 w = XmCreateSeparator( parent, "separator", NULL, 0 );
497 XtManageChild( w );
503 * vi_create_menubar --
505 * PUBLIC: Widget vi_create_menubar __P((Widget));
507 Widget
508 vi_create_menubar(Widget parent)
510 Widget menu, pull, button;
511 menu_bar *ptr;
513 /* save this for creation of children */
514 main_widget = parent;
516 menu = XmCreateMenuBar( parent, "Menu", NULL, 0 );
518 for ( ptr=main_menu; ptr->title != NULL; ptr++ ) {
520 pull = XmCreatePulldownMenu( menu, "pull", NULL, 0 );
521 add_entries( pull, ptr->actions );
522 button = XmCreateCascadeButton( menu, ptr->title, NULL, 0 );
523 XtVaSetValues( button, XmNsubMenuId, pull, 0 );
525 if ( strcmp( ptr->title, "Help" ) == 0 )
526 XtVaSetValues( menu, XmNmenuHelpWidget, button, 0 );
528 #if 0
529 /* These screw up accelerator processing. Punt for now */
530 if ( ptr->mnemonic )
531 XtVaSetValues( button, XmNmnemonic, ptr->mnemonic, 0 );
532 #endif
534 XtManageChild( button );
537 return menu;