3 * Rob Zimmermann. All rights reserved.
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
13 static const char sccsid
[] = "$Id: m_menu.c,v 8.19 1996/12/11 20:58:23 bostic Exp $ (Berkeley) $Date: 1996/12/11 20:58:23 $";
16 #include <sys/queue.h>
18 #include <X11/Intrinsic.h>
19 #include <X11/StringDefs.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>
30 #include "../common/common.h"
32 #include "ipc_extern.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.
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
52 * implement file selection dialog boxes
53 * implement string prompt dialog boxes (e.g. for 'find')
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
68 * Change VI_STRING to VI_COMMAND so that menu actions cannot be confusing
69 * when in insert mode.
72 * THIS SHOULD GO AWAY -- WE SHOULDN'T SEND UNINTERPRETED STRINGS TO THE
75 * PUBLIC: void __vi_send_command_string __P((String));
78 __vi_send_command_string(str
)
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
);
93 strcat( buffer
, "\n" );
99 ipb
.len
= strlen(buffer
);
100 __vi_send("s", &ipb
);
104 /* Utility: beep for unimplemented command */
106 #if defined(__STDC__)
107 static void send_beep( Widget w
)
109 static void send_beep( w
)
113 XBell( XtDisplay(w
), 0 );
119 * Utility: make a dialog box go Modal
121 * PUBLIC: void __vi_cancel_cb __P((Widget, XtPointer, XtPointer));
123 static Bool have_answer
;
125 __vi_cancel_cb(w
, client_data
, call_data
)
127 XtPointer client_data
, call_data
;
132 void __vi_modal_dialog( db
)
137 /* post the dialog */
139 XtPopup( XtParent(db
), XtGrabExclusive
);
141 /* wait for a response */
142 ctx
= XtWidgetToApplicationContext(db
);
143 XtAddGrab( XtParent(db
), TRUE
, FALSE
);
144 for ( have_answer
= False
; ! have_answer
; )
145 XtAppProcessEvent( ctx
, XtIMAll
);
148 XtPopdown( XtParent(db
) );
149 XtRemoveGrab( XtParent(db
) );
153 /* Utility: Get a file (using standard File Selection Dialog Box) */
155 static String file_name
;
158 #if defined(__STDC__)
159 static void ok_file_name( Widget w
,
160 XtPointer client_data
,
164 static void ok_file_name( w
, client_data
, call_data
)
166 XtPointer client_data
;
170 XmFileSelectionBoxCallbackStruct
*cbs
;
172 cbs
= (XmFileSelectionBoxCallbackStruct
*) call_data
;
173 XmStringGetLtoR( cbs
->value
, XmSTRING_DEFAULT_CHARSET
, &file_name
);
179 #if defined(__STDC__)
180 static String
get_file( Widget w
, String prompt
)
182 static String
get_file( w
, prompt
)
187 /* make it static so we can reuse it */
190 /* our return parameter */
191 if ( file_name
!= NULL
) {
198 db
= XmCreateFileSelectionDialog( main_widget
, "file", NULL
, 0 );
199 XtAddCallback( db
, XmNokCallback
, ok_file_name
, NULL
);
200 XtAddCallback( db
, XmNcancelCallback
, __vi_cancel_cb
, NULL
);
203 /* use the title as a prompt */
204 XtVaSetValues( XtParent(db
), XmNtitle
, prompt
, 0 );
206 /* wait for a response */
207 __vi_modal_dialog( db
);
216 * Get a file name and send it with the command to the core.
219 file_command(w
, code
, prompt
)
227 if ((file
= get_file(w
, prompt
)) != NULL
) {
230 ipb
.len
= strlen(file
);
231 __vi_send("s", &ipb
);
237 * Menu action routines (one per menu entry)
239 * These are in the order in which they appear in the menu structure.
242 ma_edit_file(w
, call_data
, client_data
)
244 XtPointer call_data
, client_data
;
246 file_command(w
, VI_EDIT
, "Edit");
250 ma_split(w
, call_data
, client_data
)
252 XtPointer call_data
, client_data
;
254 file_command(w
, VI_EDITSPLIT
, "Edit");
258 ma_save(w
, call_data
, client_data
)
260 XtPointer call_data
, client_data
;
265 (void)__vi_send(NULL
, &ipb
);
269 ma_save_as(w
, call_data
, client_data
)
271 XtPointer call_data
, client_data
;
273 file_command(w
, VI_WRITEAS
, "Save As");
277 ma_wq(w
, call_data
, client_data
)
279 XtPointer call_data
, client_data
;
284 (void)__vi_send(NULL
, &ipb
);
288 ma_quit(w
, call_data
, client_data
)
290 XtPointer call_data
, client_data
;
295 (void)__vi_send(NULL
, &ipb
);
299 ma_undo(w
, call_data
, client_data
)
301 XtPointer call_data
, client_data
;
306 (void)__vi_send(NULL
, &ipb
);
309 #if defined(__STDC__)
310 static void ma_cut( Widget w
,
312 XtPointer client_data
315 static void ma_cut( w
, call_data
, client_data
)
318 XtPointer client_data
;
326 #if defined(__STDC__)
327 static void ma_copy( Widget w
,
329 XtPointer client_data
332 static void ma_copy( w
, call_data
, client_data
)
335 XtPointer client_data
;
343 #if defined(__STDC__)
344 static void ma_paste( Widget w
,
346 XtPointer client_data
349 static void ma_paste( w
, call_data
, client_data
)
352 XtPointer client_data
;
360 ma_find(w
, call_data
, client_data
)
362 XtPointer call_data
, client_data
;
364 __vi_show_search_dialog( main_widget
, "Find" );
368 ma_find_next(w
, call_data
, client_data
)
370 XtPointer call_data
, client_data
;
376 ma_tags(w
, call_data
, client_data
)
378 XtPointer call_data
, client_data
;
380 __vi_show_tags_dialog( main_widget
, "Tag Stack" );
384 ma_tagpop(w
, call_data
, client_data
)
386 XtPointer call_data
, client_data
;
388 __vi_send_command_string( "\024" );
392 ma_tagtop(w
, call_data
, client_data
)
394 XtPointer call_data
, client_data
;
396 __vi_send_command_string( ":tagtop" );
399 #if defined(__STDC__)
400 static void ma_preferences( Widget w
,
402 XtPointer client_data
405 static void ma_preferences( w
, call_data
, client_data
)
408 XtPointer client_data
;
411 __vi_show_options_dialog( main_widget
, "Preferences" );
415 /* Menu construction routines */
420 String accel
; /* for Motif */
421 String accel_text
; /* for the user */
430 static pull_down file_menu
[] = {
431 { "Edit File...", ma_edit_file
, "Alt<Key>e", "Alt+E" },
432 { "", NULL
, NULL
, NULL
},
433 { "Split Window...", ma_split
, NULL
, NULL
},
434 { "", NULL
, NULL
, NULL
},
435 { "Save ", ma_save
, "Alt<Key>s", "Alt+S" },
436 { "Save As...", ma_save_as
, "Shift Alt<Key>s", "Shift+Alt+S" },
437 { "", NULL
, NULL
, NULL
},
438 { "Write and Quit", ma_wq
, "Shift Alt<Key>q", "Shift+Alt+Q" },
439 { "Quit", ma_quit
, "Alt<Key>q", "Alt+Q" },
440 { NULL
, NULL
, NULL
, NULL
},
443 static pull_down edit_menu
[] = {
444 { "Undo", ma_undo
, NULL
, NULL
},
445 { "", NULL
, NULL
, NULL
},
446 { "Cut", ma_cut
, "Alt<Key>x", "Alt+X" },
447 { "Copy", ma_copy
, "Alt<Key>c", "Alt+C" },
448 { "Paste", ma_paste
, "Alt<Key>v", "Alt+V" },
449 { "", NULL
, NULL
, NULL
},
450 { "Find", ma_find
, "Alt<Key>f", "Alt+F" },
451 { "Find Next", ma_find_next
, "Alt<Key>g", "Alt+G" },
452 { NULL
, NULL
, NULL
, NULL
},
455 static pull_down options_menu
[] = {
456 { "Preferences", ma_preferences
, NULL
, NULL
},
457 { "Command Mode Maps", NULL
, NULL
, NULL
},
458 { "Insert Mode Maps", NULL
, NULL
, NULL
},
459 { NULL
, NULL
, NULL
, NULL
},
462 static pull_down tag_menu
[] = {
463 { "Show Tag Stack", ma_tags
, "Alt<Key>t", "Alt+T" },
464 { "", NULL
, NULL
, NULL
},
465 { "Pop Tag", ma_tagpop
, NULL
, NULL
},
466 { "Clear Stack", ma_tagtop
, NULL
, NULL
},
467 { NULL
, NULL
, NULL
, NULL
},
470 static pull_down help_menu
[] = {
471 { NULL
, NULL
, NULL
, NULL
},
474 static menu_bar main_menu
[] = {
475 { 'F', "File", file_menu
},
476 { 'E', "Edit", edit_menu
},
477 { 'O', "Options", options_menu
},
478 { 'T', "Tag", tag_menu
},
479 { 'H', "Help", help_menu
},
484 #if defined(__STDC__)
485 static void add_entries( Widget parent
, pull_down
*actions
)
487 static void add_entries( parent
, actions
)
495 for ( ; actions
->title
!= NULL
; actions
++ ) {
498 if ( *actions
->title
!= '\0' ) {
499 w
= XmCreatePushButton( parent
, actions
->title
, NULL
, 0 );
500 if ( actions
->action
== NULL
)
501 XtSetSensitive( w
, False
);
505 (XtCallbackProc
) actions
->action
,
508 if ( actions
->accel
!= NULL
) {
509 str
= XmStringCreateSimple( actions
->accel_text
);
511 XmNaccelerator
, actions
->accel
,
512 XmNacceleratorText
, str
,
519 w
= XmCreateSeparator( parent
, "separator", NULL
, 0 );
528 * vi_create_menubar --
530 * PUBLIC: Widget vi_create_menubar __P((Widget));
533 vi_create_menubar(parent
)
536 Widget menu
, pull
, button
;
539 /* save this for creation of children */
540 main_widget
= parent
;
542 menu
= XmCreateMenuBar( parent
, "Menu", NULL
, 0 );
544 for ( ptr
=main_menu
; ptr
->title
!= NULL
; ptr
++ ) {
546 pull
= XmCreatePulldownMenu( menu
, "pull", NULL
, 0 );
547 add_entries( pull
, ptr
->actions
);
548 button
= XmCreateCascadeButton( menu
, ptr
->title
, NULL
, 0 );
549 XtVaSetValues( button
, XmNsubMenuId
, pull
, 0 );
551 if ( strcmp( ptr
->title
, "Help" ) == 0 )
552 XtVaSetValues( menu
, XmNmenuHelpWidget
, button
, 0 );
555 /* These screw up accelerator processing. Punt for now */
557 XtVaSetValues( button
, XmNmnemonic
, ptr
->mnemonic
, 0 );
560 XtManageChild( button
);