From dadeed21d2e80f9ce102bf9cce107a4e363bebee Mon Sep 17 00:00:00 2001 From: cohrs Date: Wed, 15 Oct 2003 06:02:27 +0000 Subject: [PATCH] debian bug #154629 - extended commands in gnome front end Not all of the extended commands worked in the gnome interface because '#' just caused the next character to be treated as a meta character (this was a hack I added a while back when none of the extended commands worked). Resolved by finally adding an extended command menu to the gnome interface. - updated some formatting so I could read the code - fixed startup player selection menus so accelerators work - added necessary calls to make sure selected menu item is visible - also removed some dead code --- doc/fixes34.3 | 1 + win/gnome/gnbind.c | 3 +- win/gnome/gnmenu.c | 243 ++++++++++++++++++++++++++++++------------- win/gnome/gnmenu.h | 2 +- win/gnome/gnopts.c | 8 +- win/gnome/gnplayer.c | 44 ++++---- win/gnome/gnsignal.c | 5 +- 7 files changed, 205 insertions(+), 101 deletions(-) diff --git a/doc/fixes34.3 b/doc/fixes34.3 index e0f32a445..b16b221b7 100644 --- a/doc/fixes34.3 +++ b/doc/fixes34.3 @@ -63,6 +63,7 @@ X11: avoid a possible crash when using window manger to close a player selection window Gnome: add Quiver menu item, fix outdated Quit menu item Gnome: key values on unsigned char platform could fail to compare correctly +Gnome: real extended command menu so all extended commands can be entered tty: avoid crash displaying quit inventory if inventory was already displayed diff --git a/win/gnome/gnbind.c b/win/gnome/gnbind.c index 51829bb51..cb9c29f2e 100644 --- a/win/gnome/gnbind.c +++ b/win/gnome/gnbind.c @@ -9,6 +9,7 @@ #include "gnbind.h" #include "gnmain.h" +#include "gnmenu.h" #include "gnaskstr.h" #include "gnyesno.h" @@ -1098,7 +1099,7 @@ int get_ext_cmd(void) */ int gnome_get_ext_cmd() { - return -1; + return ghack_menu_ext_cmd(); } diff --git a/win/gnome/gnmenu.c b/win/gnome/gnmenu.c index 4536401be..4462f40ed 100644 --- a/win/gnome/gnmenu.c +++ b/win/gnome/gnmenu.c @@ -8,6 +8,7 @@ #include "gnmenu.h" #include "gnmain.h" #include "gnbind.h" +#include "func_tab.h" typedef enum { MenuUnknown = 0, @@ -22,65 +23,60 @@ typedef struct { int selected; } menuItem; +typedef struct { + int curItem; + int numRows; + int charIdx; + guint32 lastTime; +} extMenu; static GdkColor color_blue = { 0, 0, 0, 0xffff }; -void ghack_menu_window_key_press(GtkWidget *menuWin, GdkEventKey *event, - gpointer data) +static void +ghack_menu_window_key(GtkWidget *menuWin, GdkEventKey *event, gpointer data) { - int i, numRows; - menuItem* item; - MenuWinType isMenu; - - /* Turn this on to debug key events */ -#if 0 - int ctl=GDK_CONTROL_MASK; - int alt=GDK_MOD1_MASK; - - g_message("I got a \"%s\" key (%d) %s%s", - gdk_keyval_name (event->keyval), event->keyval, - (event->state&ctl)? "+CONTROL":"", - (event->state&alt)? "+ALT":""); -#endif - - isMenu = (MenuWinType) GPOINTER_TO_INT - (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu")); - - if (isMenu == MenuMenu) { - GtkWidget *clist; - gint selection_mode; - - clist = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (menuWin), "clist")); - g_assert (clist != NULL); - numRows = GPOINTER_TO_INT( gtk_object_get_data( - GTK_OBJECT(clist), "numRows") ); - selection_mode = GPOINTER_TO_INT( gtk_object_get_data - (GTK_OBJECT (clist), "selection_mode")); - for( i=0; i<=numRows; i++) { - item = (menuItem*) gtk_clist_get_row_data( - GTK_CLIST (clist), i); - if (item == NULL) - continue; - if (!strcmp(item->accelerator, "")) { - continue; - } - if ( (!strcmp(item->accelerator, event->string)) || - ((selection_mode == GTK_SELECTION_MULTIPLE) && - (event->keyval == ','))) { - if (item->selected==TRUE) { - gtk_clist_unselect_row( GTK_CLIST (clist), - item->itemNumber, 0); - item->selected=FALSE; - } - else { - gtk_clist_select_row( GTK_CLIST (clist), - item->itemNumber, 0); - item->selected=TRUE; - } - } + int i, numRows; + menuItem* item; + MenuWinType isMenu; + + isMenu = (MenuWinType) GPOINTER_TO_INT + (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu")); + + if (isMenu == MenuMenu) { + GtkWidget *clist; + gint selection_mode; + + clist = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (menuWin), "clist")); + g_assert (clist != NULL); + numRows = GPOINTER_TO_INT + (gtk_object_get_data(GTK_OBJECT(clist), "numRows")); + selection_mode = GPOINTER_TO_INT + (gtk_object_get_data (GTK_OBJECT(clist), "selection_mode")); + for (i = 0; i <= numRows; ++i) { + item = (menuItem*) gtk_clist_get_row_data(GTK_CLIST(clist), i); + if (item == NULL) continue; + if (!strcmp(item->accelerator, "")) continue; + + if ((!strcmp(item->accelerator, event->string)) || + ((selection_mode == GTK_SELECTION_MULTIPLE) && + (event->keyval == ','))) { + if (item->selected) { + gtk_clist_unselect_row( GTK_CLIST (clist), + item->itemNumber, 0); + item->selected = FALSE; + } else { + gtk_clist_select_row(GTK_CLIST (clist), + item->itemNumber, 0); + if (gtk_clist_row_is_visible(GTK_CLIST(clist), + item->itemNumber) != GTK_VISIBILITY_FULL) + gtk_clist_moveto(GTK_CLIST(clist), + item->itemNumber, 0, 0.5, 0); + item->selected = TRUE; } + } } + } } @@ -240,22 +236,6 @@ ghack_menu_window_select_menu (GtkWidget *menuWin, GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE)); gtk_clist_set_selection_mode (GTK_CLIST (clist), (how == PICK_ANY)? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE); -#if 0 - /* Turn this on, and an "All" button will be appended to the - * menu dialog when it is in SELECTION_MULTIPLE mode. I commented - * this out because 1) it doesn't work very well, and 2) it is ugly. - * A better job of doing this is very welcome.... - * -Erik */ - if (how == PICK_ANY) { - static GdkEventKey event; - event.keyval='\''; - event.state=0; - gnome_dialog_append_button( GNOME_DIALOG(menuWin), "All"); - gnome_dialog_button_connect( GNOME_DIALOG(menuWin), 2, - GTK_SIGNAL_FUNC(ghack_menu_window_key_press), - &event); - } -#endif gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE); rc = gnome_dialog_run_and_close (GNOME_DIALOG (menuWin)); if ((rc == 1) || (GTK_CLIST (clist)->selection == NULL)) { @@ -368,9 +348,7 @@ ghack_menu_window_add_menu( GtkWidget *menuWin, gpointer menu_item, else if ( ('A'+numItems-26)<='Z') { g_snprintf(accelBuf, sizeof(accelBuf), "%c ", 'A'+numItems-26); gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf); - } - else { - g_warning( "I've run out of accelerator letters!"); + } else { accelBuf[0] = buf[0] = 0; } g_snprintf(buf, sizeof(buf), "%s", item->str); @@ -641,7 +619,7 @@ ghack_init_menu_window (void) NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "key_press_event", - GTK_SIGNAL_FUNC(ghack_menu_window_key_press), + GTK_SIGNAL_FUNC(ghack_menu_window_key), NULL); /* Center the dialog over parent */ @@ -654,3 +632,124 @@ ghack_init_menu_window (void) return menuWin; } +static void +ghack_ext_key_hit(GtkWidget *menuWin, GdkEventKey *event, gpointer data) +{ + GtkWidget* clist; + extMenu* info = (extMenu*) data; + int i; + char c = event->string[0]; + + clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); + g_assert(clist != NULL); + + /* if too long between keystrokes, reset to initial state */ + if (event->time - info->lastTime > 500) goto init_state; + + /* see if current item continue to match */ + if (info->charIdx > 0) { + if (extcmdlist[info->curItem].ef_txt[info->charIdx] == c) { + ++info->charIdx; + goto found; + } + } + + /* see if the prefix matches a later command in the list */ + if (info->curItem >= 0) { + for (i = info->curItem + 1; i < info->numRows; ++i) { + if (!strncmp(extcmdlist[info->curItem].ef_txt, + extcmdlist[i].ef_txt, info->charIdx-1)) { + if (extcmdlist[i].ef_txt[info->charIdx] == c) { + ++info->charIdx; + info->curItem = i; + goto found; + } + } + } + } + +init_state: + /* reset to initial state, look for matching 1st character */ + for (i = 0; i < info->numRows; ++i) { + if (extcmdlist[i].ef_txt[0] == c) { + info->charIdx = 1; + info->curItem = i; + goto found; + } + } + + /* no match: leave prior, if any selection in place */ + return; + +found: + info->lastTime = event->time; + gtk_clist_select_row(GTK_CLIST(clist), info->curItem, 0); + if (gtk_clist_row_is_visible(GTK_CLIST(clist), + info->curItem) != GTK_VISIBILITY_FULL) + gtk_clist_moveto(GTK_CLIST(clist), info->curItem, 0, 0.5, 0); +} + +int +ghack_menu_ext_cmd(void) +{ + int n; + GtkWidget* dialog; + GtkWidget* swin; + GtkWidget* frame1; + GtkWidget* clist; + extMenu info; + + dialog = gnome_dialog_new("Extended Commands", + GNOME_STOCK_BUTTON_OK, + GNOME_STOCK_BUTTON_CANCEL, + NULL); + gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE); + gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", + GTK_SIGNAL_FUNC(ghack_ext_key_hit), &info); + + frame1 = gtk_frame_new("Make your selection"); + gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1); + gtk_widget_show(frame1); + gtk_container_border_width(GTK_CONTAINER(frame1), 3); + + swin = gtk_scrolled_window_new(NULL, NULL); + clist = gtk_clist_new(2); + gtk_object_set_data(GTK_OBJECT(dialog), "clist", clist); + gtk_widget_set_usize(clist, 500, 400); + gtk_container_add(GTK_CONTAINER(swin), clist); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + gtk_signal_connect(GTK_OBJECT(clist), "select_row", + GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL); + + gtk_container_add(GTK_CONTAINER(frame1), swin); + gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1); + + /* Add the extended commands into the list here... */ + for (n = 0; extcmdlist[n].ef_txt; ++n) { + const char *text[3]={extcmdlist[n].ef_txt,extcmdlist[n].ef_desc,NULL}; + gtk_clist_insert(GTK_CLIST(clist), n, (char**) text); + } + + /* fill in starting info fields */ + info.curItem = -1; + info.numRows = n; + info.charIdx = 0; + info.lastTime = 0; + + gtk_clist_columns_autosize(GTK_CLIST(clist)); + gtk_widget_show_all(swin); + + /* Center the dialog over over parent */ + gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gnome_dialog_set_parent(GNOME_DIALOG(dialog), + GTK_WINDOW(ghack_get_main_window())); + + /* Run the dialog -- returning whichever button was pressed */ + n = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); + + /* Quit on button 2 or error */ + return (n != 0) ? -1 : info.curItem; +} diff --git a/win/gnome/gnmenu.h b/win/gnome/gnmenu.h index 2864cc709..7055aa4a9 100644 --- a/win/gnome/gnmenu.h +++ b/win/gnome/gnmenu.h @@ -27,6 +27,6 @@ typedef struct _GHackMenuItem GHackMenuItem; int ghack_menu_window_select_menu (GtkWidget *menuWin, MENU_ITEM_P **_selected, gint how); - +int ghack_menu_ext_cmd(void); #endif /* GnomeHackMenuWindow_h */ diff --git a/win/gnome/gnopts.c b/win/gnome/gnopts.c index b4845b965..04d0073be 100644 --- a/win/gnome/gnopts.c +++ b/win/gnome/gnopts.c @@ -15,7 +15,7 @@ static GtkWidget* clist; const char* tilesets[] = { "Traditional (16x16)", "Big (32x32)", 0 }; static void -player_sel_key_hit (GtkWidget *widget, GdkEventKey *event, gpointer data) +opt_sel_key_hit(GtkWidget *widget, GdkEventKey *event, gpointer data) { int i; for (i = 0; tilesets[i] != 0; ++i) { @@ -27,7 +27,7 @@ player_sel_key_hit (GtkWidget *widget, GdkEventKey *event, gpointer data) } static void -player_sel_row_selected (GtkCList *cList, int row, int col, GdkEvent *event) +opt_sel_row_selected(GtkCList *cList, int row, int col, GdkEvent *event) { tileset = row; } @@ -46,7 +46,7 @@ ghack_settings_dialog() NULL); gnome_dialog_close_hides (GNOME_DIALOG (dialog), FALSE); gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event", - GTK_SIGNAL_FUNC (player_sel_key_hit), tilesets ); + GTK_SIGNAL_FUNC (opt_sel_key_hit), tilesets ); frame1 = gtk_frame_new (_("Choose one of the following tilesets:")); gtk_object_set_data (GTK_OBJECT (dialog), "frame1", frame1); @@ -62,7 +62,7 @@ ghack_settings_dialog() GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect (GTK_OBJECT (clist), "select_row", - GTK_SIGNAL_FUNC (player_sel_row_selected), NULL ); + GTK_SIGNAL_FUNC (opt_sel_row_selected), NULL ); gtk_container_add (GTK_CONTAINER (frame1), swin); gtk_box_pack_start_defaults (GTK_BOX (GNOME_DIALOG (dialog)->vbox), frame1); diff --git a/win/gnome/gnplayer.c b/win/gnome/gnplayer.c index f34fa506a..f10fcd2ad 100644 --- a/win/gnome/gnplayer.c +++ b/win/gnome/gnplayer.c @@ -8,21 +8,24 @@ #include "gnmain.h" #include "hack.h" -static gint role_number; -static GtkWidget* clist; - -static void -player_sel_key_hit (GtkWidget *widget, GdkEventKey *event, gpointer data) +static gint role_number; +static GtkWidget* clist; + +static void +player_sel_key_hit (GtkWidget *widget, GdkEventKey *event, gpointer data) { - const char** roles = data; - int i; - for (i = 0; roles[i] != 0; ++i) { - if (roles[i][0] == toupper(event->keyval)) { - role_number = i; - gtk_clist_select_row( GTK_CLIST (clist), i, 0); - } - } -} + const char** roles = data; + int i; + for (i = 0; roles[i] != 0; ++i) { + if (tolower(roles[i][0]) == tolower(event->keyval)) { + role_number = i; + gtk_clist_select_row( GTK_CLIST (clist), i, 0); + if (gtk_clist_row_is_visible(GTK_CLIST(clist), + i) != GTK_VISIBILITY_FULL) + gtk_clist_moveto(GTK_CLIST(clist), i, 0, 0.5, 0); + } + } +} static void player_sel_row_selected (GtkCList *clist, int row, int col, GdkEvent *event) @@ -46,8 +49,8 @@ ghack_player_sel_dialog(const char** choices, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_close_hides (GNOME_DIALOG (dialog), FALSE); - gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event", - GTK_SIGNAL_FUNC (player_sel_key_hit), choices ); + gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event", + GTK_SIGNAL_FUNC (player_sel_key_hit), choices ); frame1 = gtk_frame_new(prompt); gtk_object_set_data (GTK_OBJECT (dialog), "frame1", frame1); @@ -67,7 +70,7 @@ ghack_player_sel_dialog(const char** choices, gtk_container_add (GTK_CONTAINER (frame1), swin); gtk_box_pack_start_defaults (GTK_BOX (GNOME_DIALOG (dialog)->vbox), frame1); - + /* Add the roles into the list here... */ for (i=0; choices[i]; i++) { gchar accelBuf[BUFSZ]; @@ -75,19 +78,18 @@ ghack_player_sel_dialog(const char** choices, sprintf( accelBuf, "%c ", tolower(choices[i][0])); gtk_clist_insert (GTK_CLIST (clist), i, (char**)text); } - + gtk_clist_columns_autosize (GTK_CLIST (clist)); gtk_widget_show_all (swin); /* Center the dialog over over parent */ gnome_dialog_set_default( GNOME_DIALOG(dialog), 0); gtk_window_set_modal( GTK_WINDOW(dialog), TRUE); - gnome_dialog_set_parent (GNOME_DIALOG (dialog), + gnome_dialog_set_parent (GNOME_DIALOG (dialog), GTK_WINDOW (ghack_get_main_window ()) ); /* Run the dialog -- returning whichever button was pressed */ - i = gnome_dialog_run (GNOME_DIALOG (dialog)); - gnome_dialog_close (GNOME_DIALOG (dialog)); + i = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); /* Quit on button 2 or error */ if (i < 0 || i > 1) { diff --git a/win/gnome/gnsignal.c b/win/gnome/gnsignal.c index 038797584..2e5b62167 100644 --- a/win/gnome/gnsignal.c +++ b/win/gnome/gnsignal.c @@ -369,8 +369,8 @@ ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) /* can't just ignore "#", it's a core feature */ case GDK_numbersign: - was_pound = 1; - return; + key='#'; + break; /* We will probably want to do something with these later... */ case GDK_KP_Begin: @@ -416,6 +416,7 @@ ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) default: key = event->keyval; + break; } if ((event->state & alt) || was_pound) { -- 2.40.0