Final part of yesterday's split input fixes.
[nvi.git] / motif_l / m_search.c
blob2a5c57f31edb9ec9c572c4c0eac0b7a63c0e0ef6
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_search.c,v 8.12 2000/06/28 20:20:40 skimo Exp $ (Berkeley) $Date: 2000/06/28 20:20:40 $";
14 #endif /* not lint */
16 #include <sys/queue.h>
18 /* context */
19 #include <X11/X.h>
20 #include <X11/Intrinsic.h>
21 #include <Xm/DialogS.h>
22 #include <Xm/Form.h>
23 #include <Xm/Label.h>
24 #include <Xm/PushBG.h>
25 #include <Xm/TextF.h>
26 #include <Xm/ToggleB.h>
27 #include <Xm/RowColumn.h>
29 #include <bitstring.h>
30 #include <stdio.h>
31 #include <stdlib.h>
33 #include "../common/common.h"
34 #include "../ipc/ip.h"
35 #include "m_motif.h"
37 extern int vi_ofd;
40 /* types */
42 typedef struct sds {
43 struct sds *next;
44 Widget shell;
45 } save_dialog;
47 static save_dialog *dialogs = NULL;
49 typedef struct {
50 String name;
51 void (*cb)();
52 } ButtonData;
55 /* globals and constants */
57 static String PatternWidget = "text";
58 static String pattern = NULL;
60 static optData search_toggles[] = {
61 { optToggle, "extended", NULL, VI_SEARCH_EXT },
62 { optToggle, "iclower", NULL, VI_SEARCH_ICL },
63 { optToggle, "ignorecase", NULL, VI_SEARCH_IC },
64 { optToggle, "literal", NULL, VI_SEARCH_LIT },
65 { optToggle, "searchincr", NULL, VI_SEARCH_INCR },
66 { optToggle, "wrapscan", NULL, VI_SEARCH_WR },
67 { optTerminator, },
70 static void done_func __P((Widget));
71 static void next_func __P((Widget));
72 static void prev_func __P((Widget));
73 static void search __P((Widget, int));
75 static ButtonData button_data[] = {
76 { "Next", next_func },
77 { "Previous", prev_func },
78 { "Cancel", done_func } /* always last */
82 /* Xt utilities */
84 #if defined(__STDC__)
85 static Widget get_child_widget( Widget parent, String name )
86 #else
87 static Widget get_child_widget( parent, name )
88 Widget parent;
89 String name;
90 #endif
92 char buffer[1024];
94 strcpy( buffer, "*" );
95 strcat( buffer, name );
96 return XtNameToWidget( parent, buffer );
100 /* sync the global state */
102 #if defined(__STDC__)
103 static void get_state( Widget w )
104 #else
105 static void get_state( w )
106 Widget w;
107 #endif
109 #if defined(SelfTest)
110 int i;
111 #endif
112 Widget shell = w;
114 /* get all the data from the root of the widget tree */
115 while ( ! XtIsShell(shell) ) shell = XtParent(shell);
117 #if defined(SelfTest)
118 /* which flags? */
119 for (i=0; i<XtNumber(toggle_data); i++) {
120 if (( w = get_child_widget( shell, toggle_data[i].name )) != NULL ) {
121 XtVaGetValues( w, XmNset, &toggle_data[i].value, 0 );
124 #endif
126 /* what's the pattern? */
127 if (( w = get_child_widget( shell, PatternWidget )) != NULL ) {
128 if ( pattern != NULL ) XtFree( pattern );
129 pattern = XmTextFieldGetString( w );
134 /* Translate the user's actions into nvi commands */
136 * next_func --
137 * Action for next button.
139 static void
140 next_func(w)
141 Widget w;
143 search(w, 0);
147 * prev_func --
148 * Action for previous button.
150 static void
151 prev_func(w)
152 Widget w;
154 search(w, VI_SEARCH_REV);
158 * search --
159 * Perform the search.
161 static void
162 search(w, flags)
163 Widget w;
164 int flags;
166 IP_BUF ipb;
167 optData *opt;
168 Widget shell;
170 shell = w;
171 while ( ! XtIsShell(shell) ) shell = XtParent(shell);
173 /* Get current data from the root of the widget tree?
174 * Do it if we are a child of a dialog shell (assume we
175 * are a 'Find' dialog). Otherwise don't (we are the child
176 * of a menu and being invoked via accelerator)
178 if (XmIsDialogShell(shell))
179 get_state(w);
181 /* no pattern? probably, we haven't posted a search dialog yet.
182 * there ought to be a better thing to do here.
184 if ( pattern == NULL ) {
185 vi_info_message( w, "No previous string specified" );
186 return;
189 ipb.str1 = pattern;
190 ipb.len1 = strlen(pattern);
192 /* Initialize the search flags based on the buttons. */
193 ipb.val1 = flags;
194 for (opt = search_toggles; opt->kind != optTerminator; ++opt)
195 if (opt->value != NULL)
196 ipb.val1 |= opt->flags;
198 ipb.code = VI_C_SEARCH;
199 vi_send(vi_ofd, "a1", &ipb);
202 #if defined(__STDC__)
203 static void done_func( Widget w )
204 #else
205 static void done_func( w )
206 Widget w;
207 #endif
209 save_dialog *ptr;
211 #if defined(SelfTest)
212 puts( XtName(w) );
213 #endif
215 while ( ! XtIsShell(w) ) w = XtParent(w);
216 XtPopdown( w );
218 /* save it for later */
219 ptr = (save_dialog *) malloc( sizeof(save_dialog) );
220 ptr->next = dialogs;
221 ptr->shell = w;
222 dialogs = ptr;
226 /* create a set of push buttons */
228 #define SpacingRatio 4 /* 3:1 button to spaces */
230 #if defined(__STDC__)
231 static Widget create_push_buttons( Widget parent,
232 ButtonData *data,
233 int count
235 #else
236 static Widget create_push_buttons( parent, data, count )
237 Widget parent;
238 ButtonData *data;
239 int count;
240 #endif
242 Widget w, form;
243 int pos = 1, base;
245 base = SpacingRatio*count + 1;
246 form = XtVaCreateManagedWidget( "buttons",
247 xmFormWidgetClass,
248 parent,
249 XmNleftAttachment, XmATTACH_FORM,
250 XmNrightAttachment, XmATTACH_FORM,
251 XmNfractionBase, base,
252 XmNshadowType, XmSHADOW_ETCHED_IN,
253 XmNshadowThickness, 2,
254 XmNverticalSpacing, 4,
258 while ( count-- > 0 ) {
259 w = XtVaCreateManagedWidget(data->name,
260 xmPushButtonGadgetClass,
261 form,
262 XmNtopAttachment, XmATTACH_FORM,
263 XmNbottomAttachment,XmATTACH_FORM,
264 XmNleftAttachment, XmATTACH_POSITION,
265 XmNleftPosition, pos,
266 XmNshowAsDefault, False,
267 XmNrightAttachment, XmATTACH_POSITION,
268 XmNrightPosition, pos+SpacingRatio-1,
271 XtAddCallback( w, XmNactivateCallback, data->cb, 0 );
272 pos += SpacingRatio;
273 data++;
276 /* last button is 'cancel' */
277 XtVaSetValues( XtParent(form), XmNcancelButton, w, 0 );
279 return form;
283 /* create a set of check boxes */
285 #if defined(SelfTest)
287 #if defined(__STDC__)
288 static Widget create_check_boxes( Widget parent,
289 ToggleData *toggles,
290 int count
292 #else
293 static Widget create_check_boxes( parent, toggles, count )
294 Widget parent;
295 ToggleData *toggles;
296 int count;
297 #endif
299 Widget form;
300 int pos = 1, base;
302 base = SpacingRatio*count +1;
303 form = XtVaCreateManagedWidget( "toggles",
304 xmFormWidgetClass,
305 parent,
306 XmNleftAttachment, XmATTACH_FORM,
307 XmNrightAttachment, XmATTACH_FORM,
308 XmNfractionBase, base,
309 XmNverticalSpacing, 4,
313 while ( count-- > 0 ) {
314 XtVaCreateManagedWidget(toggles->name,
315 xmToggleButtonWidgetClass,
316 form,
317 XmNtopAttachment, XmATTACH_FORM,
318 XmNbottomAttachment, XmATTACH_FORM,
319 XmNleftAttachment, XmATTACH_POSITION,
320 XmNleftPosition, pos,
321 XmNrightAttachment, XmATTACH_POSITION,
322 XmNrightPosition, pos+SpacingRatio-1,
325 pos += SpacingRatio;
326 ++toggles;
329 return form;
332 #endif
335 /* Routines to handle the text field widget */
337 /* when the user hits 'CR' in a text widget, fire the default pushbutton */
338 #if defined(__STDC__)
339 static void text_cr( Widget w, void *ptr, void *ptr2 )
340 #else
341 static void text_cr( w, ptr, ptr2 )
342 Widget w;
343 void *ptr;
344 void *ptr2;
345 #endif
347 next_func( w );
351 #ifdef notdef
353 * when the user hits any other character, if we are doing incremental
354 * search, send the updated string to nvi
356 * XXX
357 * I don't currently see any way to make this work -- incremental search
358 * is going to be really nasty. What makes it worse is that the dialog
359 * box almost certainly obscured a chunk of the text file, so there's no
360 * way to use it even if it works.
362 #if defined(__STDC__)
363 static void value_changed( Widget w, void *ptr, void *ptr2 )
364 #else
365 static void value_changed( w, ptr, ptr2 )
366 Widget w;
367 void *ptr;
368 void *ptr2;
369 #endif
371 /* get all the data from the root of the widget tree */
372 get_state( w );
374 /* send it along? */
375 #if defined(SelfTest)
376 if ( incremental_search ) send_command( w );
377 #else
378 if ( __vi_incremental_search() ) send_command( w );
379 #endif
381 #endif /* notdef */
384 /* Draw and display a dialog the describes nvi search capability */
386 #if defined(__STDC__)
387 static Widget create_search_dialog( Widget parent, String title )
388 #else
389 static Widget create_search_dialog( parent, title )
390 Widget parent;
391 String title;
392 #endif
394 Widget box, form, label, text, checks, buttons, form2;
395 save_dialog *ptr;
397 /* use an existing one? */
398 if ( dialogs != NULL ) {
399 box = dialogs->shell;
400 ptr = dialogs->next;
401 free( dialogs );
402 dialogs = ptr;
403 return box;
406 box = XtVaCreatePopupShell( title,
407 xmDialogShellWidgetClass,
408 parent,
409 XmNtitle, title,
410 XmNallowShellResize, False,
414 form = XtVaCreateWidget( "form",
415 xmFormWidgetClass,
416 box,
417 XmNverticalSpacing, 4,
418 XmNhorizontalSpacing, 4,
422 form2 = XtVaCreateManagedWidget( "form",
423 xmFormWidgetClass,
424 form,
425 XmNtopAttachment, XmATTACH_FORM,
426 XmNleftAttachment, XmATTACH_FORM,
427 XmNrightAttachment, XmATTACH_FORM,
431 label = XtVaCreateManagedWidget( "Pattern:",
432 xmLabelWidgetClass,
433 form2,
434 XmNtopAttachment, XmATTACH_FORM,
435 XmNbottomAttachment,XmATTACH_FORM,
436 XmNleftAttachment, XmATTACH_FORM,
440 text = XtVaCreateManagedWidget( PatternWidget,
441 xmTextFieldWidgetClass,
442 form2,
443 XmNtopAttachment, XmATTACH_FORM,
444 XmNbottomAttachment,XmATTACH_FORM,
445 XmNleftAttachment, XmATTACH_WIDGET,
446 XmNleftWidget, label,
447 XmNrightAttachment, XmATTACH_FORM,
450 #ifdef notdef
451 XtAddCallback( text, XmNvalueChangedCallback, value_changed, 0 );
452 #endif
453 XtAddCallback( text, XmNactivateCallback, text_cr, 0 );
455 buttons = create_push_buttons( form, button_data, XtNumber(button_data) );
456 XtVaSetValues( buttons,
457 XmNbottomAttachment, XmATTACH_FORM,
461 #if defined(SelfTest)
462 checks = create_check_boxes( form, toggle_data, XtNumber(toggle_data) );
463 #else
464 checks = (Widget) __vi_create_search_toggles( form, search_toggles );
465 #endif
466 XtVaSetValues( checks,
467 XmNtopAttachment, XmATTACH_WIDGET,
468 XmNtopWidget, form2,
469 XmNbottomAttachment, XmATTACH_WIDGET,
470 XmNbottomWidget, buttons,
474 XtManageChild( form );
475 return box;
479 /* Module interface to the outside world
481 * xip_show_search_dialog( parent, title )
482 * pops up a search dialog
484 * xip_next_search()
485 * simulates a 'next' assuming that a search has been done
488 #if defined(__STDC__)
489 void __vi_show_search_dialog( Widget parent, String title )
490 #else
491 void __vi_show_search_dialog( parent, data, cbs )
492 Widget parent;
493 String title;
494 #endif
496 Widget db = create_search_dialog( parent, title );
497 Dimension height;
499 /* we can handle getting taller and wider or narrower, but not shorter */
500 XtVaGetValues( db, XmNheight, &height, 0 );
501 XtVaSetValues( db, XmNmaxHeight, height, XmNminHeight, height, 0 );
503 /* post the dialog */
504 XtPopup( db, XtGrabNone );
506 /* request initial focus to the text widget */
507 XmProcessTraversal( get_child_widget( db, PatternWidget ),
508 XmTRAVERSE_CURRENT
514 * __vi_search --
516 * PUBLIC: void __vi_search __P((Widget));
518 void
519 __vi_search( w )
520 Widget w;
522 next_func( w );
526 #if defined(SelfTest)
528 #if defined(__STDC__)
529 static void show_search( Widget w, XtPointer data, XtPointer cbs )
530 #else
531 static void show_search( w, data, cbs )
532 Widget w;
533 XtPointer data;
534 XtPointer cbs;
535 #endif
537 __vi_show_search_dialog( data, "Search" );
540 main( int argc, char *argv[] )
542 XtAppContext ctx;
543 Widget top_level, rc, button;
544 extern exit();
546 /* create a top-level shell for the window manager */
547 top_level = XtVaAppInitialize( &ctx,
548 argv[0],
549 NULL, 0, /* options */
550 (ArgcType) &argc,
551 argv, /* might get modified */
552 NULL,
553 NULL
556 rc = XtVaCreateManagedWidget( "rc",
557 xmRowColumnWidgetClass,
558 top_level,
562 button = XtVaCreateManagedWidget( "Pop up search dialog",
563 xmPushButtonGadgetClass,
567 XtAddCallback( button, XmNactivateCallback, show_search, rc );
569 button = XtVaCreateManagedWidget( "Quit",
570 xmPushButtonGadgetClass,
574 XtAddCallback( button, XmNactivateCallback, exit, 0 );
576 XtRealizeWidget(top_level);
577 XtAppMainLoop(ctx);
579 #endif