NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / win / gnome / gnmenu.c
blob74c2d946525dac1484095acb533e2fb023e23ee0
1 /* aNetHack 0.0.1 gnmenu.c $ANH-Date: 1432512805 2015/05/25 00:13:25 $ $ANH-Branch: master $:$ANH-Revision: 1.10 $ */
2 /* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
3 /* aNetHack may be freely redistributed. See license for details. */
5 #include <string.h>
6 #include <gtk/gtk.h>
7 #include <gnome.h>
8 #include "gnmenu.h"
9 #include "gnmain.h"
10 #include "gnbind.h"
11 #include "func_tab.h"
13 typedef enum { MenuUnknown = 0, MenuText, MenuMenu } MenuWinType;
15 typedef struct {
16 ANY_P identifier;
17 gchar accelerator[BUFSZ];
18 int itemNumber;
19 int selected;
20 } menuItem;
22 typedef struct {
23 int curItem;
24 int numRows;
25 int charIdx;
26 guint32 lastTime;
27 } extMenu;
29 static GdkColor color_blue = { 0, 0, 0, 0xffff };
31 static void
32 ghack_menu_window_key(GtkWidget *menuWin, GdkEventKey *event, gpointer data)
34 int i, numRows;
35 menuItem *item;
36 MenuWinType isMenu;
38 isMenu = (MenuWinType) GPOINTER_TO_INT(
39 gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu"));
41 if (isMenu == MenuMenu) {
42 GtkWidget *clist;
43 gint selection_mode;
45 clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist"));
46 g_assert(clist != NULL);
47 numRows = GPOINTER_TO_INT(
48 gtk_object_get_data(GTK_OBJECT(clist), "numRows"));
49 selection_mode = GPOINTER_TO_INT(
50 gtk_object_get_data(GTK_OBJECT(clist), "selection_mode"));
51 for (i = 0; i <= numRows; ++i) {
52 item = (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i);
53 if (item == NULL)
54 continue;
55 if (!strcmp(item->accelerator, ""))
56 continue;
58 if ((!strcmp(item->accelerator, event->string))
59 || ((selection_mode == GTK_SELECTION_MULTIPLE)
60 && (event->keyval == ','))) {
61 if (item->selected) {
62 gtk_clist_unselect_row(GTK_CLIST(clist), item->itemNumber,
63 0);
64 item->selected = FALSE;
65 } else {
66 gtk_clist_select_row(GTK_CLIST(clist), item->itemNumber,
67 0);
68 if (gtk_clist_row_is_visible(GTK_CLIST(clist),
69 item->itemNumber)
70 != GTK_VISIBILITY_FULL)
71 gtk_clist_moveto(GTK_CLIST(clist), item->itemNumber,
72 0, 0.5, 0);
73 item->selected = TRUE;
80 static void
81 ghack_menu_row_selected(GtkCList *clist, int row, int col, GdkEvent *event)
83 /* FIXME: Do something */
86 void
87 ghack_menu_window_clear(GtkWidget *menuWin, gpointer data)
89 MenuWinType isMenu;
90 int i, numRows;
91 menuItem *item;
93 isMenu = (MenuWinType) GPOINTER_TO_INT(
94 gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu"));
96 if (isMenu == MenuMenu) {
97 GtkWidget *clist;
99 clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist"));
100 g_assert(clist != NULL);
102 /* destroy existing menu data, if any */
103 if (clist) {
104 /* destroy all the row_data we stored in the clist */
105 numRows = GPOINTER_TO_INT(
106 gtk_object_get_data(GTK_OBJECT(clist), "numRows"));
107 for (i = 0; i < numRows; i++) {
108 item =
109 (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i);
110 if (item != NULL) {
111 g_free(item);
112 gtk_clist_set_row_data(GTK_CLIST(clist), i,
113 (gpointer) NULL);
116 gtk_object_set_data(GTK_OBJECT(clist), "numItems",
117 GINT_TO_POINTER(-1));
118 gtk_clist_clear(GTK_CLIST(clist));
122 else if (isMenu == MenuText) {
123 GnomeLess *gless;
125 gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless"));
126 g_assert(gless != NULL);
128 gtk_editable_delete_text(GTK_EDITABLE(gless->text), 0, 0);
132 void
133 ghack_menu_window_display(GtkWidget *menuWin, gboolean blocking,
134 gpointer data)
136 // if(blocking) {
137 gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE);
138 gnome_dialog_set_close(GNOME_DIALOG(menuWin), TRUE);
139 gnome_dialog_run_and_close(GNOME_DIALOG(menuWin));
141 // else {
142 // gtk_widget_show(menuWin);
146 gint
147 ghack_menu_hide(GtkWidget *menuWin, GdkEvent *event, gpointer data)
149 gtk_widget_hide(menuWin);
150 return FALSE; /* FIXME: what is correct result here? */
153 void
154 ghack_menu_window_start_menu(GtkWidget *menuWin, gpointer data)
156 GtkWidget *frame1, *swin, *clist;
157 MenuWinType isMenu;
159 g_assert(menuWin != NULL);
160 g_assert(data == NULL);
162 /* destroy existing menu data, if any */
163 frame1 = gtk_object_get_data(GTK_OBJECT(menuWin), "frame1");
164 if (frame1)
165 gtk_widget_destroy(frame1);
167 isMenu = MenuMenu;
168 gtk_object_set_data(GTK_OBJECT(menuWin), "isMenu",
169 GINT_TO_POINTER(isMenu));
171 gtk_widget_set_usize(GTK_WIDGET(menuWin), 500, 400);
172 gtk_window_set_policy(GTK_WINDOW(menuWin), TRUE, TRUE, FALSE);
174 frame1 = gtk_frame_new("Make your selection");
175 g_assert(frame1 != NULL);
176 gtk_object_set_data(GTK_OBJECT(menuWin), "frame1", frame1);
177 gtk_widget_show(GTK_WIDGET(frame1));
178 gtk_container_set_border_width(GTK_CONTAINER(frame1), 5);
179 gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(menuWin)->vbox), frame1, TRUE,
180 TRUE, 0);
182 swin = gtk_scrolled_window_new(NULL, NULL);
183 g_assert(swin != NULL);
184 gtk_object_set_data(GTK_OBJECT(menuWin), "swin", swin);
185 gtk_widget_show(GTK_WIDGET(swin));
186 gtk_container_add(GTK_CONTAINER(frame1), swin);
188 clist = gtk_clist_new(4);
189 g_assert(clist != NULL);
190 gtk_object_set_data(GTK_OBJECT(menuWin), "clist", clist);
191 gtk_widget_show(GTK_WIDGET(clist));
192 gtk_container_add(GTK_CONTAINER(swin), clist);
194 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
195 GTK_POLICY_AUTOMATIC,
196 GTK_POLICY_AUTOMATIC);
198 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
199 GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL);
200 gtk_object_set_data(GTK_OBJECT(clist), "numItems", GINT_TO_POINTER(-1));
204 ghack_menu_window_select_menu(GtkWidget *menuWin, MENU_ITEM_P **_selected,
205 gint how)
207 gint rc;
208 guint num_sel, i, idx;
209 GtkWidget *clist;
210 GList *cur;
211 MENU_ITEM_P *selected = NULL;
212 menuItem *item;
214 g_assert(_selected != NULL);
215 *_selected = NULL;
217 if (how == PICK_NONE) {
218 gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE);
219 rc = gnome_dialog_run_and_close(GNOME_DIALOG(menuWin));
220 return (rc == 1 ? -1 : 0);
223 clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist"));
224 g_assert(clist != NULL);
226 gtk_object_set_data(GTK_OBJECT(clist), "selection_mode",
227 GINT_TO_POINTER((how == PICK_ANY)
228 ? GTK_SELECTION_MULTIPLE
229 : GTK_SELECTION_SINGLE));
230 gtk_clist_set_selection_mode(GTK_CLIST(clist),
231 (how == PICK_ANY) ? GTK_SELECTION_MULTIPLE
232 : GTK_SELECTION_SINGLE);
233 gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE);
234 rc = gnome_dialog_run_and_close(GNOME_DIALOG(menuWin));
235 if ((rc == 1) || (GTK_CLIST(clist)->selection == NULL)) {
236 return (-1);
239 num_sel = g_list_length(GTK_CLIST(clist)->selection);
240 if (num_sel < 1) {
241 return (-1);
244 /* fill in array with selections from clist */
245 selected = g_new0(MENU_ITEM_P, num_sel);
246 g_assert(selected != NULL);
247 cur = GTK_CLIST(clist)->selection;
248 i = 0;
249 while (cur) {
250 g_assert(i < num_sel);
252 /* grab row number from clist selection list */
253 idx = GPOINTER_TO_INT(cur->data);
255 item = (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), idx);
256 selected[i].item = item->identifier;
257 selected[i].count = -1;
258 cur = g_list_next(cur);
259 i++;
262 *_selected = selected;
264 return ((int) num_sel);
267 void
268 ghack_menu_window_add_menu(GtkWidget *menuWin, gpointer menu_item,
269 gpointer data)
271 GHackMenuItem *item;
272 GtkWidget *clist;
273 gchar buf[BUFSZ] = "", accelBuf[BUFSZ] = "";
274 gchar *pbuf;
275 char *text[4] = { buf, NULL, NULL, NULL };
276 gint nCurrentRow = -1, numItems = -1;
277 MenuWinType isMenu;
278 GtkStyle *bigStyle = NULL;
279 gboolean item_selectable;
280 GdkImlibImage *image;
281 static gboolean special;
283 g_assert(menu_item != NULL);
284 item = (GHackMenuItem *) menu_item;
285 item_selectable = (item->identifier->a_int == 0) ? FALSE : TRUE;
286 isMenu = (MenuWinType) GPOINTER_TO_INT(
287 gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu"));
289 clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist"));
290 g_assert(clist != NULL);
291 /* This is a special kludge to make the special hidden help menu item work
292 * as designed */
293 if (special == TRUE) {
294 special = FALSE;
295 item_selectable = TRUE;
297 if (!strcmp(item->str, "The aNetHack license.")) {
298 special = TRUE;
301 if (item->str) {
302 /* First, make a new blank entry in the clist */
303 nCurrentRow = gtk_clist_append(GTK_CLIST(clist), text);
305 if (item->glyph != NO_GLYPH) {
306 image = ghack_image_from_glyph(item->glyph, FALSE);
307 if (image == NULL || image->pixmap == NULL) {
308 g_warning("Bummer -- having to force rendering for glyph %d!",
309 item->glyph);
310 /* wierd -- pixmap is NULL so retry rendering it */
311 image = ghack_image_from_glyph(item->glyph, TRUE);
313 if (image == NULL || image->pixmap == NULL) {
314 g_error("Aiiee! glyph is still NULL for item\n\"%s\"",
315 item->str);
316 } else
317 gtk_clist_set_pixmap(GTK_CLIST(clist), nCurrentRow, 1,
318 gdk_imlib_move_image(image),
319 gdk_imlib_move_mask(image));
321 if (item->accelerator) {
322 /* FIXME: handle accelerator, */
323 g_snprintf(accelBuf, sizeof(accelBuf), "%c ", item->accelerator);
324 gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf);
325 g_snprintf(buf, sizeof(buf), "%s", item->str);
326 gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf);
327 } else {
328 if (item->group_accel) {
329 /* FIXME: maybe some day I should try to handle
330 * group accelerators... */
332 if (((item->attr == 0) && (item->identifier->a_int != 0))
333 || (special == TRUE)) {
334 numItems = GPOINTER_TO_INT(gtk_object_get_data(
335 GTK_OBJECT(clist), "numItems")) + 1;
337 /* Ok, now invent a unique accelerator */
338 if (('a' + numItems) <= 'z') {
339 g_snprintf(accelBuf, sizeof(accelBuf), "%c ",
340 'a' + numItems);
341 gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0,
342 accelBuf);
343 } else if (('A' + numItems - 26) <= 'Z') {
344 g_snprintf(accelBuf, sizeof(accelBuf), "%c ",
345 'A' + numItems - 26);
346 gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0,
347 accelBuf);
348 } else {
349 accelBuf[0] = buf[0] = 0;
351 g_snprintf(buf, sizeof(buf), "%s", item->str);
352 gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf);
353 gtk_object_set_data(GTK_OBJECT(clist), "numItems",
354 GINT_TO_POINTER(numItems));
356 /* This junk is to specially handle the options menu */
357 pbuf = strstr(buf, " [");
358 if (pbuf == NULL) {
359 pbuf = strstr(buf, "\t[");
361 if (pbuf != NULL) {
362 *pbuf = 0;
363 pbuf++;
364 gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 3,
365 pbuf);
368 /* FIXME: handle more than 26*2 accelerators (but how?
369 * since I only have so many keys to work with???)
370 else
372 foo();
375 else {
376 g_snprintf(buf, sizeof(buf), "%s", item->str);
377 pbuf = strstr(buf, " [");
378 if (pbuf == NULL) {
379 pbuf = strstr(buf, "\t[");
381 if (pbuf != NULL) {
382 *pbuf = 0;
383 pbuf++;
384 gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 3,
385 pbuf);
387 gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf);
391 if (item->attr) {
392 switch (item->attr) {
393 case ATR_ULINE:
394 case ATR_BOLD:
395 case ATR_BLINK:
396 case ATR_INVERSE:
397 bigStyle = gtk_style_copy(GTK_WIDGET(clist)->style);
398 g_assert(bigStyle != NULL);
399 gdk_font_unref(bigStyle->font);
400 bigStyle->font =
401 gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*");
402 bigStyle->fg[GTK_STATE_NORMAL] = color_blue;
403 gtk_clist_set_cell_style(GTK_CLIST(clist), nCurrentRow, 2,
404 bigStyle);
405 item_selectable = FALSE;
409 g_assert(nCurrentRow >= 0);
410 gtk_clist_set_selectable(GTK_CLIST(clist), nCurrentRow,
411 item_selectable);
413 if (item_selectable == TRUE && item->presel == TRUE) {
414 /* pre-select this item */
415 gtk_clist_select_row(GTK_CLIST(clist), nCurrentRow, 0);
418 gtk_object_set_data(GTK_OBJECT(clist), "numRows",
419 GINT_TO_POINTER(nCurrentRow));
421 /* We have to allocate memory here, since the menu_item currently
422 * lives on the stack, and will otherwise go to the great bit bucket
423 * in the sky as soon as this function exits, which would leave a
424 * pointer to crap in the row_data. Use g_memdup to make a private,
425 * persistant copy of the item identifier.
427 * We need to arrange to blow away this memory somewhere (like
428 * ghack_menu_destroy and ghack_menu_window_clear for example).
430 * -Erik
433 menuItem newItem;
434 menuItem *pNewItem;
436 newItem.identifier = *item->identifier;
437 newItem.itemNumber = nCurrentRow;
438 newItem.selected = FALSE;
439 newItem.accelerator[0] = 0;
440 /* only copy 1 char, since accel keys are by definition 1 char */
441 if (accelBuf[0]) {
442 strncpy(newItem.accelerator, accelBuf, 1);
444 newItem.accelerator[1] = 0;
446 pNewItem = g_memdup(&newItem, sizeof(menuItem));
447 gtk_clist_set_row_data(GTK_CLIST(clist), nCurrentRow,
448 (gpointer) pNewItem);
451 /* Now adjust the column widths to match the contents */
452 gtk_clist_columns_autosize(GTK_CLIST(clist));
455 void
456 ghack_menu_window_end_menu(GtkWidget *menuWin, gpointer data)
458 const char *p = (const char *) data;
460 if ((p) && (*p)) {
461 GtkWidget *frame1 =
462 gtk_object_get_data(GTK_OBJECT(menuWin), "frame1");
463 g_assert(frame1 != NULL);
465 gtk_frame_set_label(GTK_FRAME(frame1), p);
469 void
470 ghack_menu_window_put_string(GtkWidget *menuWin, int attr, const char *text,
471 gpointer data)
473 GnomeLess *gless;
474 MenuWinType isMenu;
476 if (text == NULL)
477 return;
479 isMenu = (MenuWinType) GPOINTER_TO_INT(
480 gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu"));
482 if (isMenu == MenuText) {
483 gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless"));
484 g_assert(gless != NULL);
485 g_assert(gless->text != NULL);
486 g_assert(GTK_IS_TEXT(gless->text));
488 /* Don't bother with attributes yet */
489 gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, text, -1);
490 gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, "\n", -1);
494 else if (isMenu == MenuUnknown) {
495 isMenu = MenuText;
496 gtk_object_set_data(GTK_OBJECT(menuWin), "isMenu",
497 GINT_TO_POINTER(isMenu));
499 gtk_widget_set_usize(GTK_WIDGET(menuWin), 500, 400);
500 gtk_window_set_policy(GTK_WINDOW(menuWin), TRUE, TRUE, FALSE);
502 gless = GNOME_LESS(gnome_less_new());
503 g_assert(gless != NULL);
504 gtk_object_set_data(GTK_OBJECT(menuWin), "gless", gless);
505 gtk_widget_show(GTK_WIDGET(gless));
507 gnome_less_show_string(gless, text);
508 gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, "\n", -1);
510 gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(menuWin)->vbox),
511 GTK_WIDGET(gless), TRUE, TRUE, 0);
515 void
516 ghack_menu_destroy(GtkWidget *menuWin, gpointer data)
518 MenuWinType isMenu;
520 isMenu = (MenuWinType) GPOINTER_TO_INT(
521 gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu"));
523 if (isMenu == MenuText) {
524 GnomeLess *gless;
526 gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless"));
527 g_assert(gless != NULL);
528 g_assert(gless->text != NULL);
529 g_assert(GTK_IS_TEXT(gless->text));
530 gtk_widget_destroy(GTK_WIDGET(gless));
533 else if (isMenu == MenuMenu) {
534 GtkWidget *frame1, *swin, *clist;
536 /* destroy existing menu data, if any */
537 clist = gtk_object_get_data(GTK_OBJECT(menuWin), "clist");
538 if (clist) {
539 /* destroy all the row_data we stored in the clist */
540 int i, numRows;
541 menuItem *item;
542 numRows = GPOINTER_TO_INT(
543 gtk_object_get_data(GTK_OBJECT(clist), "numRows"));
544 for (i = 0; i < numRows; i++) {
545 item =
546 (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i);
547 if (item != NULL) {
548 g_free(item);
549 gtk_clist_set_row_data(GTK_CLIST(clist), i,
550 (gpointer) NULL);
554 gtk_object_set_data(GTK_OBJECT(clist), "numItems",
555 GINT_TO_POINTER(-1));
556 gtk_widget_destroy(clist);
558 swin = gtk_object_get_data(GTK_OBJECT(menuWin), "swin");
559 if (swin) {
560 gtk_widget_destroy(swin);
562 frame1 = gtk_object_get_data(GTK_OBJECT(menuWin), "frame1");
563 if (frame1) {
564 gtk_widget_destroy(frame1);
567 gnome_delete_nhwindow_by_reference(menuWin);
570 GtkWidget *
571 ghack_init_menu_window(void)
573 GtkWidget *menuWin = NULL;
574 GtkWidget *parent = ghack_get_main_window();
576 menuWin = gnome_dialog_new("GnomeHack", GNOME_STOCK_BUTTON_OK,
577 GNOME_STOCK_BUTTON_CANCEL, NULL);
579 gnome_dialog_set_default(GNOME_DIALOG(menuWin), 0);
580 gtk_signal_connect(GTK_OBJECT(menuWin), "destroy",
581 GTK_SIGNAL_FUNC(ghack_menu_destroy), NULL);
583 gtk_signal_connect(GTK_OBJECT(menuWin), "delete_event",
584 GTK_SIGNAL_FUNC(ghack_menu_hide), NULL);
586 gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_clear",
587 GTK_SIGNAL_FUNC(ghack_menu_window_clear), NULL);
589 gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_display",
590 GTK_SIGNAL_FUNC(ghack_menu_window_display), NULL);
592 gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_start_menu",
593 GTK_SIGNAL_FUNC(ghack_menu_window_start_menu), NULL);
595 gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_add_menu",
596 GTK_SIGNAL_FUNC(ghack_menu_window_add_menu), NULL);
598 gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_end_menu",
599 GTK_SIGNAL_FUNC(ghack_menu_window_end_menu), NULL);
601 gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_select_menu",
602 GTK_SIGNAL_FUNC(ghack_menu_window_select_menu), NULL);
604 gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_putstr",
605 GTK_SIGNAL_FUNC(ghack_menu_window_put_string), NULL);
607 gtk_signal_connect(GTK_OBJECT(menuWin), "key_press_event",
608 GTK_SIGNAL_FUNC(ghack_menu_window_key), NULL);
610 /* Center the dialog over parent */
611 g_assert(parent != NULL);
612 g_assert(menuWin != NULL);
613 g_assert(GTK_IS_WINDOW(parent));
614 g_assert(GNOME_IS_DIALOG(menuWin));
615 gnome_dialog_set_parent(GNOME_DIALOG(menuWin), GTK_WINDOW(parent));
617 return menuWin;
620 static void
621 ghack_ext_key_hit(GtkWidget *menuWin, GdkEventKey *event, gpointer data)
623 GtkWidget *clist;
624 extMenu *info = (extMenu *) data;
625 int i;
626 char c = event->string[0];
628 clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist"));
629 g_assert(clist != NULL);
631 /* if too long between keystrokes, reset to initial state */
632 if (event->time - info->lastTime > 500)
633 goto init_state;
635 /* see if current item continue to match */
636 if (info->charIdx > 0) {
637 if (extcmdlist[info->curItem].ef_txt[info->charIdx] == c) {
638 ++info->charIdx;
639 goto found;
643 /* see if the prefix matches a later command in the list */
644 if (info->curItem >= 0) {
645 for (i = info->curItem + 1; i < info->numRows; ++i) {
646 if (!strncmp(extcmdlist[info->curItem].ef_txt,
647 extcmdlist[i].ef_txt, info->charIdx)) {
648 if (extcmdlist[i].ef_txt[info->charIdx] == c) {
649 ++info->charIdx;
650 info->curItem = i;
651 goto found;
657 init_state:
658 /* reset to initial state, look for matching 1st character */
659 for (i = 0; i < info->numRows; ++i) {
660 if (extcmdlist[i].ef_txt[0] == c) {
661 info->charIdx = 1;
662 info->curItem = i;
663 goto found;
667 /* no match: leave prior, if any selection in place */
668 return;
670 found:
671 info->lastTime = event->time;
672 gtk_clist_select_row(GTK_CLIST(clist), info->curItem, 0);
673 if (gtk_clist_row_is_visible(GTK_CLIST(clist), info->curItem)
674 != GTK_VISIBILITY_FULL)
675 gtk_clist_moveto(GTK_CLIST(clist), info->curItem, 0, 0.5, 0);
679 ghack_menu_ext_cmd(void)
681 int n;
682 GtkWidget *dialog;
683 GtkWidget *swin;
684 GtkWidget *frame1;
685 GtkWidget *clist;
686 extMenu info;
688 dialog = gnome_dialog_new("Extended Commands", GNOME_STOCK_BUTTON_OK,
689 GNOME_STOCK_BUTTON_CANCEL, NULL);
690 gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE);
691 gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event",
692 GTK_SIGNAL_FUNC(ghack_ext_key_hit), &info);
694 frame1 = gtk_frame_new("Make your selection");
695 gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1);
696 gtk_widget_show(frame1);
697 gtk_container_border_width(GTK_CONTAINER(frame1), 3);
699 swin = gtk_scrolled_window_new(NULL, NULL);
700 clist = gtk_clist_new(2);
701 gtk_object_set_data(GTK_OBJECT(dialog), "clist", clist);
702 gtk_widget_set_usize(clist, 500, 400);
703 gtk_container_add(GTK_CONTAINER(swin), clist);
704 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
705 GTK_POLICY_AUTOMATIC,
706 GTK_POLICY_AUTOMATIC);
708 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
709 GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL);
711 gtk_container_add(GTK_CONTAINER(frame1), swin);
712 gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1);
714 /* Add the extended commands into the list here... */
715 for (n = 0; extcmdlist[n].ef_txt; ++n) {
716 const char *text[3] = { extcmdlist[n].ef_txt, extcmdlist[n].ef_desc,
717 NULL };
718 gtk_clist_insert(GTK_CLIST(clist), n, (char **) text);
721 /* fill in starting info fields */
722 info.curItem = -1;
723 info.numRows = n;
724 info.charIdx = 0;
725 info.lastTime = 0;
727 gtk_clist_columns_autosize(GTK_CLIST(clist));
728 gtk_widget_show_all(swin);
730 /* Center the dialog over over parent */
731 gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
732 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
733 gnome_dialog_set_parent(GNOME_DIALOG(dialog),
734 GTK_WINDOW(ghack_get_main_window()));
736 /* Run the dialog -- returning whichever button was pressed */
737 n = gnome_dialog_run_and_close(GNOME_DIALOG(dialog));
739 /* Quit on button 2 or error */
740 return (n != 0) ? -1 : info.curItem;