758 lines
22 KiB
C
758 lines
22 KiB
C
/* NetHack 3.5 gnmenu.c $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */
|
|
/* NetHack 3.5 gnmenu.c $Date: 2009/05/06 10:57:36 $ $Revision: 1.6 $ */
|
|
/* SCCS Id: @(#)gnmenu.c 3.5 2000/07/16 */
|
|
/* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include <string.h>
|
|
#include <gtk/gtk.h>
|
|
#include <gnome.h>
|
|
#include "gnmenu.h"
|
|
#include "gnmain.h"
|
|
#include "gnbind.h"
|
|
#include "func_tab.h"
|
|
|
|
typedef enum {
|
|
MenuUnknown = 0,
|
|
MenuText,
|
|
MenuMenu
|
|
} MenuWinType;
|
|
|
|
typedef struct {
|
|
ANY_P identifier;
|
|
gchar accelerator[BUFSZ];
|
|
int itemNumber;
|
|
int selected;
|
|
} menuItem;
|
|
|
|
typedef struct {
|
|
int curItem;
|
|
int numRows;
|
|
int charIdx;
|
|
guint32 lastTime;
|
|
} extMenu;
|
|
|
|
static GdkColor color_blue = { 0, 0, 0, 0xffff };
|
|
|
|
|
|
static void
|
|
ghack_menu_window_key(GtkWidget *menuWin, GdkEventKey *event, gpointer data)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
ghack_menu_row_selected (GtkCList *clist, int row, int col, GdkEvent *event)
|
|
{
|
|
/* FIXME: Do something */
|
|
}
|
|
|
|
|
|
void
|
|
ghack_menu_window_clear(GtkWidget *menuWin, gpointer data)
|
|
{
|
|
MenuWinType isMenu;
|
|
int i, numRows;
|
|
menuItem* item;
|
|
|
|
isMenu = (MenuWinType) GPOINTER_TO_INT
|
|
(gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
|
|
|
|
if (isMenu == MenuMenu) {
|
|
GtkWidget *clist;
|
|
|
|
clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist"));
|
|
g_assert (clist != NULL);
|
|
|
|
/* destroy existing menu data, if any */
|
|
if (clist) {
|
|
/* destroy all the row_data we stored in the clist */
|
|
numRows = GPOINTER_TO_INT( gtk_object_get_data(
|
|
GTK_OBJECT(clist), "numRows") );
|
|
for( i=0; i<numRows; i++) {
|
|
item = (menuItem*) gtk_clist_get_row_data(
|
|
GTK_CLIST (clist), i);
|
|
if (item != NULL) {
|
|
g_free( item);
|
|
gtk_clist_set_row_data (GTK_CLIST (clist), i,
|
|
(gpointer) NULL);
|
|
}
|
|
}
|
|
gtk_object_set_data (GTK_OBJECT (clist), "numItems",
|
|
GINT_TO_POINTER (-1));
|
|
gtk_clist_clear (GTK_CLIST (clist));
|
|
}
|
|
}
|
|
|
|
else if (isMenu == MenuText) {
|
|
GnomeLess *gless;
|
|
|
|
gless = GNOME_LESS (gtk_object_get_data (GTK_OBJECT (menuWin), "gless"));
|
|
g_assert (gless != NULL);
|
|
|
|
gtk_editable_delete_text (GTK_EDITABLE (gless->text), 0, 0);
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
ghack_menu_window_display(GtkWidget *menuWin, gboolean blocking,
|
|
gpointer data)
|
|
{
|
|
//if(blocking) {
|
|
gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE);
|
|
gnome_dialog_set_close (GNOME_DIALOG (menuWin), TRUE);
|
|
gnome_dialog_run_and_close(GNOME_DIALOG (menuWin));
|
|
//}
|
|
//else {
|
|
//gtk_widget_show(menuWin);
|
|
//}
|
|
}
|
|
|
|
gint
|
|
ghack_menu_hide( GtkWidget *menuWin, GdkEvent *event, gpointer data )
|
|
{
|
|
gtk_widget_hide (menuWin);
|
|
return FALSE; /* FIXME: what is correct result here? */
|
|
}
|
|
|
|
|
|
void
|
|
ghack_menu_window_start_menu (GtkWidget *menuWin, gpointer data)
|
|
{
|
|
GtkWidget *frame1, *swin, *clist;
|
|
MenuWinType isMenu;
|
|
|
|
g_assert (menuWin != NULL);
|
|
g_assert (data == NULL);
|
|
|
|
/* destroy existing menu data, if any */
|
|
frame1 = gtk_object_get_data (GTK_OBJECT (menuWin), "frame1");
|
|
if (frame1)
|
|
gtk_widget_destroy (frame1);
|
|
|
|
isMenu = MenuMenu;
|
|
gtk_object_set_data (GTK_OBJECT (menuWin), "isMenu",
|
|
GINT_TO_POINTER (isMenu));
|
|
|
|
gtk_widget_set_usize (GTK_WIDGET (menuWin), 500, 400);
|
|
gtk_window_set_policy (GTK_WINDOW (menuWin), TRUE, TRUE, FALSE);
|
|
|
|
frame1 = gtk_frame_new ("Make your selection");
|
|
g_assert (frame1 != NULL);
|
|
gtk_object_set_data (GTK_OBJECT(menuWin), "frame1", frame1);
|
|
gtk_widget_show (GTK_WIDGET (frame1));
|
|
gtk_container_set_border_width (GTK_CONTAINER (frame1), 5);
|
|
gtk_box_pack_start (GTK_BOX (GNOME_DIALOG(menuWin)->vbox), frame1,
|
|
TRUE, TRUE, 0);
|
|
|
|
swin = gtk_scrolled_window_new (NULL, NULL);
|
|
g_assert (swin != NULL);
|
|
gtk_object_set_data (GTK_OBJECT(menuWin), "swin", swin);
|
|
gtk_widget_show (GTK_WIDGET (swin));
|
|
gtk_container_add (GTK_CONTAINER (frame1), swin);
|
|
|
|
clist = gtk_clist_new (4);
|
|
g_assert (clist != NULL);
|
|
gtk_object_set_data (GTK_OBJECT(menuWin), "clist", clist);
|
|
gtk_widget_show (GTK_WIDGET (clist));
|
|
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_object_set_data (GTK_OBJECT (clist), "numItems",
|
|
GINT_TO_POINTER (-1));
|
|
}
|
|
|
|
|
|
int
|
|
ghack_menu_window_select_menu (GtkWidget *menuWin,
|
|
MENU_ITEM_P **_selected, gint how)
|
|
{
|
|
gint rc;
|
|
guint num_sel, i, idx;
|
|
GtkWidget *clist;
|
|
GList *cur;
|
|
MENU_ITEM_P *selected = NULL;
|
|
menuItem* item;
|
|
|
|
g_assert (_selected != NULL);
|
|
*_selected = NULL;
|
|
|
|
|
|
if (how == PICK_NONE) {
|
|
gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE);
|
|
rc = gnome_dialog_run_and_close (GNOME_DIALOG (menuWin));
|
|
return( rc == 1 ? -1 : 0);
|
|
}
|
|
|
|
clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist"));
|
|
g_assert (clist != NULL);
|
|
|
|
gtk_object_set_data (GTK_OBJECT (clist), "selection_mode",
|
|
GINT_TO_POINTER ((how == PICK_ANY)?
|
|
GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE));
|
|
gtk_clist_set_selection_mode (GTK_CLIST (clist),
|
|
(how == PICK_ANY)? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
|
|
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)) {
|
|
return(-1);
|
|
}
|
|
|
|
num_sel = g_list_length (GTK_CLIST (clist)->selection);
|
|
if (num_sel < 1) {
|
|
return(-1);
|
|
}
|
|
|
|
/* fill in array with selections from clist */
|
|
selected = g_new0( MENU_ITEM_P, num_sel);
|
|
g_assert (selected != NULL);
|
|
cur = GTK_CLIST (clist)->selection;
|
|
i = 0;
|
|
while (cur) {
|
|
g_assert (i < num_sel);
|
|
|
|
/* grab row number from clist selection list */
|
|
idx = GPOINTER_TO_INT (cur->data);
|
|
|
|
item = (menuItem*) gtk_clist_get_row_data( GTK_CLIST (clist), idx);
|
|
selected[i].item = item->identifier;
|
|
selected[i].count = -1;
|
|
cur = g_list_next(cur);
|
|
i++;
|
|
}
|
|
|
|
*_selected = selected;
|
|
|
|
return( (int) num_sel);
|
|
}
|
|
|
|
void
|
|
ghack_menu_window_add_menu( GtkWidget *menuWin, gpointer menu_item,
|
|
gpointer data)
|
|
{
|
|
GHackMenuItem* item;
|
|
GtkWidget *clist;
|
|
gchar buf[BUFSZ]="", accelBuf[BUFSZ]="";
|
|
gchar *pbuf;
|
|
char *text[4] = { buf, NULL, NULL, NULL };
|
|
gint nCurrentRow = -1, numItems = -1;
|
|
MenuWinType isMenu;
|
|
GtkStyle *bigStyle = NULL;
|
|
gboolean item_selectable;
|
|
GdkImlibImage* image;
|
|
static gboolean special;
|
|
|
|
g_assert (menu_item != NULL);
|
|
item = (GHackMenuItem*) menu_item;
|
|
item_selectable = ( item->identifier->a_int == 0)? FALSE : TRUE;
|
|
isMenu = (MenuWinType) GPOINTER_TO_INT
|
|
(gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
|
|
|
|
clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist"));
|
|
g_assert (clist != NULL);
|
|
/* This is a special kludge to make the special hidden help menu item work as designed */
|
|
if ( special==TRUE ) {
|
|
special=FALSE;
|
|
item_selectable=TRUE;
|
|
}
|
|
if ( ! strcmp( item->str, "The NetHack license.")) {
|
|
special=TRUE;
|
|
}
|
|
|
|
if (item->str) {
|
|
|
|
/* First, make a new blank entry in the clist */
|
|
nCurrentRow = gtk_clist_append (GTK_CLIST (clist), text);
|
|
|
|
if (item->glyph != NO_GLYPH) {
|
|
image = ghack_image_from_glyph( item->glyph, FALSE);
|
|
if (image==NULL || image->pixmap==NULL) {
|
|
g_warning("Bummer -- having to force rendering for glyph %d!", item->glyph);
|
|
/* wierd -- pixmap is NULL so retry rendering it */
|
|
image = ghack_image_from_glyph( item->glyph, TRUE);
|
|
}
|
|
if (image==NULL || image->pixmap==NULL) {
|
|
g_error("Aiiee! glyph is still NULL for item\n\"%s\"",
|
|
item->str);
|
|
}
|
|
else
|
|
gtk_clist_set_pixmap (GTK_CLIST (clist),
|
|
nCurrentRow, 1,
|
|
gdk_imlib_move_image( image),
|
|
gdk_imlib_move_mask( image));
|
|
}
|
|
if (item->accelerator) {
|
|
/* FIXME: handle accelerator, */
|
|
g_snprintf(accelBuf, sizeof(accelBuf), "%c ", item->accelerator);
|
|
gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 0, accelBuf);
|
|
g_snprintf(buf, sizeof(buf), "%s", item->str);
|
|
gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf);
|
|
} else {
|
|
if (item->group_accel) {
|
|
/* FIXME: maybe some day I should try to handle
|
|
* group accelerators... */
|
|
}
|
|
if (( (item->attr == 0) && (item->identifier->a_int != 0)) || (special ==TRUE) ) {
|
|
numItems = GPOINTER_TO_INT( gtk_object_get_data(
|
|
GTK_OBJECT(clist), "numItems") )+1;
|
|
|
|
/* Ok, now invent a unique accelerator */
|
|
if ( ('a'+numItems) <= 'z' ) {
|
|
g_snprintf(accelBuf, sizeof(accelBuf), "%c ", 'a'+numItems);
|
|
gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf);
|
|
}
|
|
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 {
|
|
accelBuf[0] = buf[0] = 0;
|
|
}
|
|
g_snprintf(buf, sizeof(buf), "%s", item->str);
|
|
gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf);
|
|
gtk_object_set_data (GTK_OBJECT (clist), "numItems",
|
|
GINT_TO_POINTER (numItems));
|
|
|
|
/* This junk is to specially handle the options menu */
|
|
pbuf = strstr( buf, " [");
|
|
if (pbuf == NULL) {
|
|
pbuf = strstr( buf, "\t[");
|
|
}
|
|
if (pbuf != NULL) {
|
|
*pbuf=0;
|
|
pbuf++;
|
|
gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 3, pbuf);
|
|
}
|
|
}
|
|
/* FIXME: handle more than 26*2 accelerators (but how?
|
|
* since I only have so many keys to work with???)
|
|
else
|
|
{
|
|
foo();
|
|
}
|
|
*/
|
|
else {
|
|
g_snprintf(buf, sizeof(buf), "%s", item->str);
|
|
pbuf = strstr( buf, " [");
|
|
if (pbuf == NULL) {
|
|
pbuf = strstr( buf, "\t[");
|
|
}
|
|
if (pbuf != NULL) {
|
|
*pbuf=0;
|
|
pbuf++;
|
|
gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 3, pbuf);
|
|
}
|
|
gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf);
|
|
|
|
}
|
|
}
|
|
|
|
if (item->attr) {
|
|
switch(item->attr) {
|
|
case ATR_ULINE:
|
|
case ATR_BOLD:
|
|
case ATR_BLINK:
|
|
case ATR_INVERSE:
|
|
bigStyle = gtk_style_copy (GTK_WIDGET (clist)->style);
|
|
g_assert (bigStyle != NULL);
|
|
gdk_font_unref (bigStyle->font);
|
|
bigStyle->font = gdk_font_load (
|
|
"-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*");
|
|
bigStyle->fg[GTK_STATE_NORMAL] = color_blue;
|
|
gtk_clist_set_cell_style (GTK_CLIST (clist),
|
|
nCurrentRow, 2, bigStyle);
|
|
item_selectable = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
g_assert (nCurrentRow >= 0);
|
|
gtk_clist_set_selectable (GTK_CLIST (clist), nCurrentRow,
|
|
item_selectable);
|
|
|
|
if ( item_selectable==TRUE && item->presel== TRUE) {
|
|
/* pre-select this item */
|
|
gtk_clist_select_row( GTK_CLIST (clist), nCurrentRow, 0);
|
|
}
|
|
|
|
gtk_object_set_data (GTK_OBJECT (clist), "numRows",
|
|
GINT_TO_POINTER (nCurrentRow));
|
|
|
|
/* We have to allocate memory here, since the menu_item currently
|
|
* lives on the stack, and will otherwise go to the great bit bucket
|
|
* in the sky as soon as this function exits, which would leave a
|
|
* pointer to crap in the row_data. Use g_memdup to make a private,
|
|
* persistant copy of the item identifier.
|
|
*
|
|
* We need to arrange to blow away this memory somewhere (like
|
|
* ghack_menu_destroy and ghack_menu_window_clear for example).
|
|
*
|
|
* -Erik
|
|
*/
|
|
{
|
|
menuItem newItem;
|
|
menuItem *pNewItem;
|
|
|
|
newItem.identifier = *item->identifier;
|
|
newItem.itemNumber=nCurrentRow;
|
|
newItem.selected=FALSE;
|
|
newItem.accelerator[0]=0;
|
|
/* only copy 1 char, since accel keys are by definition 1 char */
|
|
if (accelBuf[0]) {
|
|
strncpy(newItem.accelerator, accelBuf, 1);
|
|
}
|
|
newItem.accelerator[1]=0;
|
|
|
|
pNewItem = g_memdup(&newItem, sizeof( menuItem));
|
|
gtk_clist_set_row_data (GTK_CLIST (clist), nCurrentRow,
|
|
(gpointer) pNewItem);
|
|
}
|
|
}
|
|
/* Now adjust the column widths to match the contents */
|
|
gtk_clist_columns_autosize (GTK_CLIST (clist));
|
|
}
|
|
|
|
void
|
|
ghack_menu_window_end_menu (GtkWidget *menuWin, gpointer data)
|
|
{
|
|
const char* p = (const char*) data;
|
|
|
|
if ((p) && (*p)) {
|
|
GtkWidget *frame1 = gtk_object_get_data (GTK_OBJECT (menuWin), "frame1");
|
|
g_assert (frame1 != NULL);
|
|
|
|
gtk_frame_set_label (GTK_FRAME(frame1), p);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void ghack_menu_window_put_string(GtkWidget *menuWin, int attr,
|
|
const char* text, gpointer data)
|
|
{
|
|
GnomeLess *gless;
|
|
MenuWinType isMenu;
|
|
|
|
if (text == NULL)
|
|
return;
|
|
|
|
isMenu = (MenuWinType) GPOINTER_TO_INT
|
|
(gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
|
|
|
|
if (isMenu == MenuText) {
|
|
gless = GNOME_LESS (gtk_object_get_data (GTK_OBJECT (menuWin), "gless"));
|
|
g_assert (gless != NULL);
|
|
g_assert (gless->text != NULL);
|
|
g_assert (GTK_IS_TEXT (gless->text));
|
|
|
|
/* Don't bother with attributes yet */
|
|
gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, text, -1);
|
|
gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, "\n", -1);
|
|
|
|
}
|
|
|
|
else if (isMenu == MenuUnknown) {
|
|
isMenu = MenuText;
|
|
gtk_object_set_data (GTK_OBJECT (menuWin), "isMenu",
|
|
GINT_TO_POINTER (isMenu));
|
|
|
|
gtk_widget_set_usize (GTK_WIDGET (menuWin), 500, 400);
|
|
gtk_window_set_policy (GTK_WINDOW (menuWin), TRUE, TRUE, FALSE);
|
|
|
|
gless = GNOME_LESS (gnome_less_new ());
|
|
g_assert (gless != NULL);
|
|
gtk_object_set_data (GTK_OBJECT (menuWin), "gless", gless);
|
|
gtk_widget_show (GTK_WIDGET (gless));
|
|
|
|
gnome_less_show_string (gless, text);
|
|
gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, "\n", -1);
|
|
|
|
gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (menuWin)->vbox),
|
|
GTK_WIDGET (gless), TRUE, TRUE, 0);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ghack_menu_destroy (GtkWidget *menuWin, gpointer data)
|
|
{
|
|
MenuWinType isMenu;
|
|
|
|
isMenu = (MenuWinType) GPOINTER_TO_INT
|
|
(gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu"));
|
|
|
|
if (isMenu == MenuText) {
|
|
GnomeLess *gless;
|
|
|
|
gless = GNOME_LESS (gtk_object_get_data (GTK_OBJECT (menuWin), "gless"));
|
|
g_assert (gless != NULL);
|
|
g_assert (gless->text != NULL);
|
|
g_assert (GTK_IS_TEXT (gless->text));
|
|
gtk_widget_destroy(GTK_WIDGET(gless));
|
|
}
|
|
|
|
else if (isMenu == MenuMenu) {
|
|
GtkWidget *frame1, *swin, *clist;
|
|
|
|
/* destroy existing menu data, if any */
|
|
clist = gtk_object_get_data (GTK_OBJECT (menuWin), "clist");
|
|
if (clist) {
|
|
/* destroy all the row_data we stored in the clist */
|
|
int i, numRows;
|
|
menuItem* item;
|
|
numRows = GPOINTER_TO_INT( gtk_object_get_data(
|
|
GTK_OBJECT(clist), "numRows") );
|
|
for( i=0; i<numRows; i++) {
|
|
item = (menuItem*) gtk_clist_get_row_data(
|
|
GTK_CLIST (clist), i);
|
|
if (item != NULL) {
|
|
g_free( item);
|
|
gtk_clist_set_row_data (GTK_CLIST (clist), i,
|
|
(gpointer) NULL);
|
|
}
|
|
}
|
|
|
|
gtk_object_set_data (GTK_OBJECT (clist), "numItems",
|
|
GINT_TO_POINTER (-1));
|
|
gtk_widget_destroy (clist);
|
|
}
|
|
swin = gtk_object_get_data (GTK_OBJECT (menuWin), "swin");
|
|
if (swin) {
|
|
gtk_widget_destroy (swin);
|
|
}
|
|
frame1 = gtk_object_get_data (GTK_OBJECT (menuWin), "frame1");
|
|
if (frame1) {
|
|
gtk_widget_destroy (frame1);
|
|
}
|
|
}
|
|
gnome_delete_nhwindow_by_reference (menuWin);
|
|
}
|
|
|
|
|
|
GtkWidget*
|
|
ghack_init_menu_window (void)
|
|
{
|
|
GtkWidget *menuWin = NULL;
|
|
GtkWidget *parent = ghack_get_main_window ();
|
|
|
|
menuWin = gnome_dialog_new("GnomeHack", GNOME_STOCK_BUTTON_OK,
|
|
GNOME_STOCK_BUTTON_CANCEL, NULL);
|
|
|
|
gnome_dialog_set_default( GNOME_DIALOG(menuWin), 0);
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "destroy",
|
|
GTK_SIGNAL_FUNC(ghack_menu_destroy),
|
|
NULL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (menuWin), "delete_event",
|
|
GTK_SIGNAL_FUNC (ghack_menu_hide),
|
|
NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_clear",
|
|
GTK_SIGNAL_FUNC(ghack_menu_window_clear),
|
|
NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_display",
|
|
GTK_SIGNAL_FUNC(ghack_menu_window_display),
|
|
NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_start_menu",
|
|
GTK_SIGNAL_FUNC(ghack_menu_window_start_menu),
|
|
NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_add_menu",
|
|
GTK_SIGNAL_FUNC(ghack_menu_window_add_menu),
|
|
NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_end_menu",
|
|
GTK_SIGNAL_FUNC(ghack_menu_window_end_menu),
|
|
NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_select_menu",
|
|
GTK_SIGNAL_FUNC(ghack_menu_window_select_menu),
|
|
NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_putstr",
|
|
GTK_SIGNAL_FUNC(ghack_menu_window_put_string),
|
|
NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(menuWin), "key_press_event",
|
|
GTK_SIGNAL_FUNC(ghack_menu_window_key),
|
|
NULL);
|
|
|
|
/* Center the dialog over parent */
|
|
g_assert (parent != NULL);
|
|
g_assert (menuWin != NULL);
|
|
g_assert (GTK_IS_WINDOW (parent));
|
|
g_assert (GNOME_IS_DIALOG (menuWin));
|
|
gnome_dialog_set_parent (GNOME_DIALOG (menuWin), GTK_WINDOW (parent));
|
|
|
|
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)) {
|
|
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;
|
|
}
|