# HG changeset patch # User Sadrul Habib Chowdhury # Date 1159082066 0 # Node ID 62bb53609a366aa6b8a5cd7e8d3d9fa31fcbb678 # Parent 1f46715c08d9c231cf0c4b2d9390fb392f698f17 [gaim-migrate @ 17341] Menus and windows. I have added a test-app test/menu.c to show how to use it. Pressing Ctrl+o brings up the menu for the window (if it has one). It should now be possible to add menus for account-actions and all that stuff. Patches are very welcome. committer: Tailor Script diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/Makefile.am --- a/console/libgnt/Makefile.am Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/Makefile.am Sun Sep 24 07:14:26 2006 +0000 @@ -16,10 +16,13 @@ gntlabel.c \ gntline.c \ gntmarshal.c \ + gntmenu.c \ + gntmenuitem.c \ gntstyle.c \ gnttextview.c \ gnttree.c \ gntutils.c \ + gntwindow.c \ gntmain.c libgnt_la_headers = \ @@ -34,10 +37,13 @@ gntlabel.h \ gntline.h \ gntmarshal.h \ + gntmenu.h \ + gntmenuitem.h \ gntstyle.h \ gnttextview.h \ gnttree.h \ gntutils.h \ + gntwindow.h \ gntwm.h \ gnt.h diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gnt.h --- a/console/libgnt/gnt.h Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/gnt.h Sun Sep 24 07:14:26 2006 +0000 @@ -29,5 +29,7 @@ void gnt_register_action(const char *label, void (*callback)()); +gboolean gnt_screen_menu_show(gpointer menu); + void gnt_quit(); diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntbox.c --- a/console/libgnt/gntbox.c Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/gntbox.c Sun Sep 24 07:14:26 2006 +0000 @@ -504,9 +504,15 @@ static void gnt_box_init(GTypeInstance *instance, gpointer class) { + GntWidget *widget = GNT_WIDGET(instance); + GntBox *box = GNT_BOX(widget); /* Initially make both the height and width resizable. * Update the flags as necessary when widgets are added to it. */ - GNT_WIDGET_SET_FLAGS(GNT_WIDGET(instance), GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + box->pad = 1; + box->fill = TRUE; GNTDEBUG; } @@ -547,14 +553,7 @@ box->homogeneous = homo; box->vertical = vert; - box->pad = 1; - box->fill = TRUE; - gnt_widget_set_take_focus(widget, TRUE); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - if (vert) - box->alignment = GNT_ALIGN_LEFT; - else - box->alignment = GNT_ALIGN_MID; + box->alignment = vert ? GNT_ALIGN_LEFT : GNT_ALIGN_MID; return widget; } diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntmain.c --- a/console/libgnt/gntmain.c Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/gntmain.c Sun Sep 24 07:14:26 2006 +0000 @@ -8,6 +8,7 @@ #include "gntbox.h" #include "gntcolors.h" #include "gntkeys.h" +#include "gntmenu.h" #include "gntstyle.h" #include "gnttree.h" #include "gntutils.h" @@ -34,6 +35,14 @@ * Need to wattrset for colors to use with PDCurses. */ +/** + * There can be at most one menu at a time on the screen. + * If there is a menu being displayed, then all the keystrokes will be sent to + * the menu until it is closed, either when the user activates a menuitem, or + * presses Escape to cancel the menu. + */ +static GntMenu *menu; + static int lock_focus_list; static GList *focus_list; static GList *ordered; @@ -120,6 +129,15 @@ static gboolean update_screen(gpointer null) { + if (menu) { + GntMenu *top = menu; + while (top) { + GntNode *node = g_hash_table_lookup(nodes, top); + if (node) + top_panel(node->panel); + top = top->submenu; + } + } update_panels(); doupdate(); return TRUE; @@ -685,7 +703,7 @@ static int reverse_char(WINDOW *d, int y, int x, gboolean set) { -#define DECIDE(ch) (set ? ((ch) | WA_REVERSE) : ((ch) & ~WA_REVERSE)) +#define DECIDE(ch) (set ? ((ch) | A_REVERSE) : ((ch) & ~A_REVERSE)) #ifdef NO_WIDECHAR chtype ch; @@ -777,8 +795,9 @@ if (mode == GNT_KP_MODE_NORMAL) { - if (ordered) - { + if (menu) { + ret = gnt_widget_key_pressed(GNT_WIDGET(menu), buffer); + } else if (ordered) { ret = gnt_widget_key_pressed(ordered->data, buffer); } @@ -1209,8 +1228,8 @@ while (widget->parent) widget = widget->parent; - - gnt_box_sync_children(GNT_BOX(widget)); + if (!GNT_IS_MENU(widget)) + gnt_box_sync_children(GNT_BOX(widget)); node = g_hash_table_lookup(nodes, widget); if (node && !node->panel) { @@ -1244,6 +1263,9 @@ GntWidget *w; if (!widget) return FALSE; + + if (GNT_IS_MENU(widget)) + return TRUE; w = widget; @@ -1416,3 +1438,25 @@ lock_focus_list = 0; } +static void +reset_menu(GntWidget *widget, gpointer null) +{ + menu = NULL; +} + +gboolean gnt_screen_menu_show(gpointer newmenu) +{ + if (menu) { + /* For now, if a menu is being displayed, then another menu + * can NOT take over. */ + return FALSE; + } + + menu = newmenu; + gnt_widget_draw(GNT_WIDGET(menu)); + + g_signal_connect(G_OBJECT(menu), "hide", G_CALLBACK(reset_menu), NULL); + + return TRUE; +} + diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntmenu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/console/libgnt/gntmenu.c Sun Sep 24 07:14:26 2006 +0000 @@ -0,0 +1,290 @@ +#include "gntmenu.h" + +#include + +enum +{ + SIGS = 1, +}; + +static GntTreeClass *parent_class = NULL; +static guint signals[SIGS] = { 0 }; + +void (*org_draw)(GntWidget *wid); +void (*org_destroy)(GntWidget *wid); +void (*org_map)(GntWidget *wid); +gboolean (*org_key_pressed)(GntWidget *w, const char *t); + +static void +gnt_menu_draw(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + GList *iter; + chtype type; + int i; + + if (menu->type == GNT_MENU_TOPLEVEL) { + wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); + werase(widget->window); + + for (i = 0, iter = menu->list; iter; iter = iter->next, i++) { + GntMenuItem *item = GNT_MENUITEM(iter->data); + type = ' ' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT); + if (i == menu->selected) + type |= A_REVERSE; + item->priv.x = getcurx(widget->window) + widget->priv.x; + item->priv.y = getcury(widget->window) + widget->priv.y + 1; + wbkgdset(widget->window, type); + wprintw(widget->window, " %s ", item->text); + } + } else { + org_draw(widget); + } + + GNTDEBUG; +} + +static void +gnt_menu_size_request(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + + if (menu->type == GNT_MENU_TOPLEVEL) { + widget->priv.height = 1; + widget->priv.width = getmaxx(stdscr); + } else { + widget->priv.height = g_list_length(menu->list) + 2; + widget->priv.width = 25; /* XXX: */ + } +} + +static void +menu_tree_add(GntMenu *menu, GntMenuItem *item, GntMenuItem *parent) +{ + gnt_tree_add_row_last(GNT_TREE(menu), item, + gnt_tree_create_row(GNT_TREE(menu), item->text, item->submenu ? ">" : " "), parent); + if (0 && item->submenu) { + GntMenu *sub = GNT_MENU(item->submenu); + GList *iter; + for (iter = sub->list; iter; iter = iter->next) { + GntMenuItem *it = GNT_MENUITEM(iter->data); + menu_tree_add(menu, it, item); + } + } +} + +static void +gnt_menu_map(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + + if (menu->type == GNT_MENU_TOPLEVEL) { + gnt_widget_size_request(widget); + } else { + /* Populate the tree */ + GList *iter; + gnt_tree_remove_all(GNT_TREE(widget)); + for (iter = menu->list; iter; iter = iter->next) { + GntMenuItem *item = GNT_MENUITEM(iter->data); + menu_tree_add(menu, item, NULL); + } + org_map(widget); + } + GNTDEBUG; +} + +static void +menuitem_activate(GntMenu *menu, GntMenuItem *item) +{ + if (item) { + if (item->submenu) { + GntMenu *sub = GNT_MENU(item->submenu); + menu->submenu = sub; + sub->type = GNT_MENU_POPUP; /* Submenus are *never* toplevel */ + sub->parentmenu = menu; + if (menu->type != GNT_MENU_TOPLEVEL) { + GntWidget *widget = GNT_WIDGET(menu); + item->priv.x = widget->priv.x + widget->priv.width - 1; + item->priv.y = widget->priv.y + gnt_tree_get_selection_visible_line(GNT_TREE(menu)); + } + gnt_widget_set_position(GNT_WIDGET(sub), item->priv.x, item->priv.y); + gnt_widget_draw(GNT_WIDGET(sub)); + } else if (item->callback) { + item->callback(item, item->callbackdata); + while (menu) { + gnt_widget_hide(GNT_WIDGET(menu)); + menu = menu->parentmenu; + } + } + } +} + +static gboolean +gnt_menu_key_pressed(GntWidget *widget, const char *text) +{ + GntMenu *menu = GNT_MENU(widget); + int current = menu->selected; + + if (menu->submenu) { + /*if (gnt_widget_key_pressed(GNT_WIDGET(menu->submenu), text))*/ + /*return TRUE;*/ + return (gnt_widget_key_pressed(GNT_WIDGET(menu->submenu), text)); + } + + if (text[0] == 27 && text[1] == 0) { + /* Escape closes menu */ + GntMenu *par = menu->parentmenu; + if (par != NULL) { + par->submenu = NULL; + gnt_widget_hide(widget); + } else + gnt_widget_hide(widget); + return TRUE; + } + + if (menu->type == GNT_MENU_TOPLEVEL) { + if (text[0] == 27) { + if (strcmp(text + 1, GNT_KEY_LEFT) == 0) { + menu->selected--; + if (menu->selected < 0) + menu->selected = g_list_length(menu->list) - 1; + } else if (strcmp(text + 1, GNT_KEY_RIGHT) == 0) { + menu->selected++; + if (menu->selected >= g_list_length(menu->list)) + menu->selected = 0; + } + } else if (text[0] == '\r' && text[1] == 0) { + gnt_widget_activate(widget); + } + + if (current != menu->selected) { + gnt_widget_draw(widget); + return TRUE; + } + } else { + return org_key_pressed(widget, text); + } + + return FALSE; +} + +static void +gnt_menu_destroy(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + g_list_foreach(menu->list, (GFunc)g_object_run_dispose, NULL); + g_list_free(menu->list); + org_destroy(widget); +} + +static void +gnt_menu_activate(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + GntMenuItem *item; + + if (menu->type == GNT_MENU_TOPLEVEL) { + item = g_list_nth_data(menu->list, menu->selected); + } else { + item = gnt_tree_get_selection_data(GNT_TREE(menu)); + } + + if (item) + menuitem_activate(menu, item); +} + +static void +gnt_menu_hide(GntWidget *widget) +{ + GntMenu *menu = GNT_MENU(widget); + if (menu->parentmenu) + menu->parentmenu->submenu = NULL; +} + +static void +gnt_menu_class_init(GntMenuClass *klass) +{ + GntWidgetClass *wid_class = GNT_WIDGET_CLASS(klass); + parent_class = GNT_TREE_CLASS(klass); + + org_destroy = wid_class->destroy; + org_map = wid_class->map; + org_draw = wid_class->draw; + org_key_pressed = wid_class->key_pressed; + + wid_class->destroy = gnt_menu_destroy; + wid_class->draw = gnt_menu_draw; + wid_class->map = gnt_menu_map; + wid_class->size_request = gnt_menu_size_request; + wid_class->key_pressed = gnt_menu_key_pressed; + wid_class->activate = gnt_menu_activate; + wid_class->hide = gnt_menu_hide; + + GNTDEBUG; +} + +static void +gnt_menu_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER | + GNT_WIDGET_CAN_TAKE_FOCUS); + GNTDEBUG; +} + +/****************************************************************************** + * GntMenu API + *****************************************************************************/ +GType +gnt_menu_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntMenuClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_menu_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntMenu), + 0, /* n_preallocs */ + gnt_menu_init, /* instance_init */ + }; + + type = g_type_register_static(GNT_TYPE_TREE, + "GntMenu", + &info, 0); + } + + return type; +} + +GntWidget *gnt_menu_new(GntMenuType type) +{ + GntWidget *widget = g_object_new(GNT_TYPE_MENU, NULL); + GntMenu *menu = GNT_MENU(widget); + menu->list = NULL; + menu->selected = -1; + menu->type = type; + + if (type == GNT_MENU_TOPLEVEL) { + widget->priv.x = 0; + widget->priv.y = 0; + } else { + GNT_TREE(widget)->show_separator = FALSE; + _gnt_tree_init_internals(GNT_TREE(widget), 2); + gnt_tree_set_col_width(GNT_TREE(widget), 1, 1); /* The second column is to indicate that it has a submenu */ + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER); + } + + return widget; +} + +void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item) +{ + menu->list = g_list_append(menu->list, item); +} + diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntmenu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/console/libgnt/gntmenu.h Sun Sep 24 07:14:26 2006 +0000 @@ -0,0 +1,70 @@ +#ifndef GNT_MENU_H +#define GNT_MENU_H + +#include "gnttree.h" +#include "gntcolors.h" +#include "gntkeys.h" + +#define GNT_TYPE_MENU (gnt_menu_get_gtype()) +#define GNT_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_MENU, GntMenu)) +#define GNT_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_MENU, GntMenuClass)) +#define GNT_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_MENU)) +#define GNT_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_MENU)) +#define GNT_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_MENU, GntMenuClass)) + +#define GNT_MENU_FLAGS(obj) (GNT_MENU(obj)->priv.flags) +#define GNT_MENU_SET_FLAGS(obj, flags) (GNT_MENU_FLAGS(obj) |= flags) +#define GNT_MENU_UNSET_FLAGS(obj, flags) (GNT_MENU_FLAGS(obj) &= ~(flags)) + +typedef struct _GnMenu GntMenu; +typedef struct _GnMenuPriv GntMenuPriv; +typedef struct _GnMenuClass GntMenuClass; + +#include "gntmenuitem.h" + +/** + * A toplevel-menu is displayed at the top of the screen, and it spans accross + * the entire width of the screen. + * A popup-menu could be displayed, for example, as a context menu for widgets. + */ +typedef enum +{ + GNT_MENU_TOPLEVEL = 1, /* Menu for a toplevel window */ + GNT_MENU_POPUP, /* A popup menu */ +} GntMenuType; + +struct _GnMenu +{ + GntTree parent; + GntMenuType type; + + GList *list; + int selected; + + /* This will keep track of its immediate submenu which is visible so that + * keystrokes can be passed to it. */ + GntMenu *submenu; + GntMenu *parentmenu; +}; + +struct _GnMenuClass +{ + GntTreeClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_menu_get_gtype(void); + +GntWidget *gnt_menu_new(GntMenuType type); + +void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item); + +G_END_DECLS + +#endif /* GNT_MENU_H */ diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntmenuitem.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/console/libgnt/gntmenuitem.c Sun Sep 24 07:14:26 2006 +0000 @@ -0,0 +1,79 @@ +#include "gntmenu.h" +#include "gntmenuitem.h" + +static GObjectClass *parent_class = NULL; + +static void +gnt_menuitem_destroy(GObject *obj) +{ + GntMenuItem *item = GNT_MENUITEM(obj); + g_free(item->text); + item->text = NULL; + if (item->submenu) + gnt_widget_destroy(GNT_WIDGET(item->submenu)); +} + +static void +gnt_menuitem_class_init(GntMenuItemClass *klass) +{ + parent_class = G_OBJECT_CLASS(klass); + + parent_class->dispose = gnt_menuitem_destroy; +} + +static void +gnt_menuitem_init(GTypeInstance *instance, gpointer class) +{ +} + +/****************************************************************************** + * GntMenuItem API + *****************************************************************************/ +GType +gnt_menuitem_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntMenuItemClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_menuitem_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntMenuItem), + 0, /* n_preallocs */ + gnt_menuitem_init, /* instance_init */ + }; + + type = g_type_register_static(G_TYPE_OBJECT, + "GntMenuItem", + &info, 0); + } + + return type; +} + +GObject *gnt_menuitem_new(const char *text) +{ + GObject *item = g_object_new(GNT_TYPE_MENUITEM, NULL); + GntMenuItem *menuitem = GNT_MENUITEM(item); + + menuitem->text = g_strdup(text); + + return item; +} + +void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data) +{ + item->callback = callback; + item->callbackdata = data; +} + +void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu) +{ + item->submenu = menu; +} + diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntmenuitem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/console/libgnt/gntmenuitem.h Sun Sep 24 07:14:26 2006 +0000 @@ -0,0 +1,69 @@ +#ifndef GNT_MENUITEM_H +#define GNT_MENUITEM_H + +#include +#include + +#define GNT_TYPE_MENUITEM (gnt_menuitem_get_gtype()) +#define GNT_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_MENUITEM, GntMenuItem)) +#define GNT_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_MENUITEM, GntMenuItemClass)) +#define GNT_IS_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_MENUITEM)) +#define GNT_IS_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_MENUITEM)) +#define GNT_MENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_MENUITEM, GntMenuItemClass)) + +#define GNT_MENUITEM_FLAGS(obj) (GNT_MENUITEM(obj)->priv.flags) +#define GNT_MENUITEM_SET_FLAGS(obj, flags) (GNT_MENUITEM_FLAGS(obj) |= flags) +#define GNT_MENUITEM_UNSET_FLAGS(obj, flags) (GNT_MENUITEM_FLAGS(obj) &= ~(flags)) + +typedef struct _GnMenuItem GntMenuItem; +typedef struct _GnMenuItemPriv GntMenuItemPriv; +typedef struct _GnMenuItemClass GntMenuItemClass; + +struct _GnMenuItemPriv +{ + /* These will be used to determine the position of the submenu */ + int x; + int y; +}; + +typedef void (*GntMenuItemCallback)(GntMenuItem *item, gpointer data); + +struct _GnMenuItem +{ + GObject parent; + GntMenuItemPriv priv; + + char *text; + + /* A GntMenuItem can have a callback associated with it. + * The callback will be activated whenever the suer selects it and presses enter (or clicks). + * However, if the GntMenuItem has some child, then the callback and callbackdata will be ignored. */ + gpointer callbackdata; + GntMenuItemCallback callback; + + GntMenu *submenu; +}; + +struct _GnMenuItemClass +{ + GObjectClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_menuitem_get_gtype(void); + +GObject *gnt_menuitem_new(const char *text); + +void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data); + +void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu); + +G_END_DECLS + +#endif /* GNT_MENUITEM_H */ diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gnttree.c --- a/console/libgnt/gnttree.c Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/gnttree.c Sun Sep 24 07:14:26 2006 +0000 @@ -288,8 +288,10 @@ tree_mark_columns(tree, pos, widget->priv.height - pos, ACS_BTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); } - tree_mark_columns(tree, pos, pos + 1, ACS_PLUS | COLOR_PAIR(GNT_COLOR_NORMAL)); - tree_mark_columns(tree, pos, pos, ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL)); + tree_mark_columns(tree, pos, pos + 1, + (tree->show_separator ? ACS_PLUS : ACS_HLINE) | COLOR_PAIR(GNT_COLOR_NORMAL)); + tree_mark_columns(tree, pos, pos, + (tree->show_separator ? ACS_VLINE : ' ') | COLOR_PAIR(GNT_COLOR_NORMAL)); start = 2; } @@ -356,7 +358,8 @@ whline(widget->window, ' ', widget->priv.width - pos * 2 - g_utf8_strlen(str, -1) - 1); tree->bottom = row; g_free(str); - tree_mark_columns(tree, pos, i, ACS_VLINE | attr); + tree_mark_columns(tree, pos, i, + (tree->show_separator ? ACS_VLINE : ' ') | attr); } wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); @@ -364,7 +367,8 @@ { mvwhline(widget->window, i, pos, ' ', widget->priv.width - pos * 2 - 1); - tree_mark_columns(tree, pos, i, ACS_VLINE); + tree_mark_columns(tree, pos, i, + (tree->show_separator ? ACS_VLINE : ' ')); i++; } @@ -696,6 +700,8 @@ gnt_tree_init(GTypeInstance *instance, gpointer class) { GntWidget *widget = GNT_WIDGET(instance); + GntTree *tree = GNT_TREE(widget); + tree->show_separator = TRUE; GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y); widget->priv.minw = 4; widget->priv.minh = 4; @@ -1125,19 +1131,24 @@ redraw_tree(tree); } -GntWidget *gnt_tree_new_with_columns(int col) +void _gnt_tree_init_internals(GntTree *tree, int col) { - GntWidget *widget = g_object_new(GNT_TYPE_TREE, NULL); - GntTree *tree = GNT_TREE(widget); - + tree->ncol = col; tree->hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_tree_row); - tree->ncol = col; tree->columns = g_new0(struct _GntTreeColInfo, col); while (col--) { tree->columns[col].width = 15; } tree->show_title = FALSE; +} + +GntWidget *gnt_tree_new_with_columns(int col) +{ + GntWidget *widget = g_object_new(GNT_TYPE_TREE, NULL); + GntTree *tree = GNT_TREE(widget); + + _gnt_tree_init_internals(tree, col); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW); gnt_widget_set_take_focus(widget, TRUE); @@ -1224,3 +1235,9 @@ gnt_widget_draw(GNT_WIDGET(tree)); } } + +void gnt_tree_set_show_separator(GntTree *tree, gboolean set) +{ + tree->show_separator = set; +} + diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gnttree.h --- a/console/libgnt/gnttree.h Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/gnttree.h Sun Sep 24 07:14:26 2006 +0000 @@ -46,6 +46,7 @@ char *title; } *columns; /* Would a GList be better? */ gboolean show_title; + gboolean show_separator; /* Whether to show column separators */ GCompareFunc compare; }; @@ -54,7 +55,7 @@ { GntWidgetClass parent; - void (*selection_changed)(int old, int current); + void (*selection_changed)(GntTreeRow *old, GntTreeRow * current); void (*gnt_reserved1)(void); void (*gnt_reserved2)(void); @@ -120,6 +121,13 @@ void gnt_tree_set_expanded(GntTree *tree, void *key, gboolean expanded); +void gnt_tree_set_show_separator(GntTree *tree, gboolean set); + G_END_DECLS +/* The following functions should NOT be used by applications. */ + +/* This should be called by the subclasses of GntTree's in their _new function */ +void _gnt_tree_init_internals(GntTree *tree, int col); + #endif /* GNT_TREE_H */ diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntwidget.c --- a/console/libgnt/gntwidget.c Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/gntwidget.c Sun Sep 24 07:14:26 2006 +0000 @@ -9,6 +9,7 @@ { SIG_DESTROY, SIG_DRAW, + SIG_HIDE, SIG_GIVE_FOCUS, SIG_LOST_FOCUS, SIG_KEY_PRESSED, @@ -167,6 +168,14 @@ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + signals[SIG_HIDE] = + g_signal_new("hide", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntWidgetClass, hide), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); signals[SIG_EXPOSE] = g_signal_new("expose", G_TYPE_FROM_CLASS(klass), @@ -403,6 +412,7 @@ void gnt_widget_hide(GntWidget *widget) { + g_signal_emit(widget, signals[SIG_HIDE], 0); wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); #if 0 /* XXX: I have no clue why, but this seemed to be necessary. */ diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntwidget.h --- a/console/libgnt/gntwidget.h Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/gntwidget.h Sun Sep 24 07:14:26 2006 +0000 @@ -93,6 +93,7 @@ void (*show)(GntWidget *obj); /* This will call draw() and take focus (if it can take focus) */ void (*destroy)(GntWidget *obj); void (*draw)(GntWidget *obj); /* This will draw the widget */ + void (*hide)(GntWidget *obj); void (*expose)(GntWidget *widget, int x, int y, int width, int height); void (*gained_focus)(GntWidget *widget); void (*lost_focus)(GntWidget *widget); diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntwindow.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/console/libgnt/gntwindow.c Sun Sep 24 07:14:26 2006 +0000 @@ -0,0 +1,113 @@ +#include "gntwindow.h" + +#include + +enum +{ + SIGS = 1, +}; + +static GntBoxClass *parent_class = NULL; +static guint signals[SIGS] = { 0 }; + +gboolean (*org_keypress)(GntWidget *widget, const char *text); +void (*org_destroy)(GntWidget *widget); + +static gboolean +gnt_window_key_pressed(GntWidget *widget, const char *text) +{ + if (strcmp(text, GNT_KEY_CTRL_O) == 0 && GNT_WINDOW(widget)->menu) { + gnt_screen_menu_show(GNT_WINDOW(widget)->menu); + return TRUE; + } else + return org_keypress(widget, text); + +} + +static void +gnt_window_destroy(GntWidget *widget) +{ + GntWindow *window = GNT_WINDOW(widget); + if (window->menu) + gnt_widget_destroy(GNT_WIDGET(window->menu)); + org_destroy(widget); +} + +static void +gnt_window_class_init(GntWindowClass *klass) +{ + GntWidgetClass *wid_class = GNT_WIDGET_CLASS(klass); + parent_class = GNT_BOX_CLASS(klass); + + org_keypress = wid_class->key_pressed; + wid_class->key_pressed = gnt_window_key_pressed; + + org_destroy = wid_class->destroy; + wid_class->destroy = gnt_window_destroy; + + GNTDEBUG; +} + +static void +gnt_window_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); + GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + GNTDEBUG; +} + +/****************************************************************************** + * GntWindow API + *****************************************************************************/ +GType +gnt_window_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntWindowClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_window_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntWindow), + 0, /* n_preallocs */ + gnt_window_init, /* instance_init */ + }; + + type = g_type_register_static(GNT_TYPE_BOX, + "GntWindow", + &info, 0); + } + + return type; +} + +GntWidget *gnt_window_new() +{ + GntWidget *widget = g_object_new(GNT_TYPE_WINDOW, NULL); + + return widget; +} + +GntWidget *gnt_window_box_new(gboolean homo, gboolean vert) +{ + GntWidget *wid = gnt_window_new(); + GntBox *box = GNT_BOX(wid); + + box->homogeneous = homo; + box->vertical = vert; + box->alignment = vert ? GNT_ALIGN_LEFT : GNT_ALIGN_MID; + + return wid; +} + +void gnt_window_set_menu(GntWindow *window, GntMenu *menu) +{ + window->menu = menu; +} + diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/gntwindow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/console/libgnt/gntwindow.h Sun Sep 24 07:14:26 2006 +0000 @@ -0,0 +1,56 @@ +#ifndef GNT_WINDOW_H +#define GNT_WINDOW_H + +#include "gnt.h" +#include "gntbox.h" +#include "gntcolors.h" +#include "gntkeys.h" +#include "gntmenu.h" + +#define GNT_TYPE_WINDOW (gnt_window_get_gtype()) +#define GNT_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_WINDOW, GntWindow)) +#define GNT_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_WINDOW, GntWindowClass)) +#define GNT_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_WINDOW)) +#define GNT_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WINDOW)) +#define GNT_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WINDOW, GntWindowClass)) + +#define GNT_WINDOW_FLAGS(obj) (GNT_WINDOW(obj)->priv.flags) +#define GNT_WINDOW_SET_FLAGS(obj, flags) (GNT_WINDOW_FLAGS(obj) |= flags) +#define GNT_WINDOW_UNSET_FLAGS(obj, flags) (GNT_WINDOW_FLAGS(obj) &= ~(flags)) + +typedef struct _GnWindow GntWindow; +typedef struct _GnWindowPriv GntWindowPriv; +typedef struct _GnWindowClass GntWindowClass; + +struct _GnWindow +{ + GntBox parent; + GntMenu *menu; +}; + +struct _GnWindowClass +{ + GntBoxClass parent; + + void (*gnt_reserved1)(void); + void (*gnt_reserved2)(void); + void (*gnt_reserved3)(void); + void (*gnt_reserved4)(void); +}; + +G_BEGIN_DECLS + +GType gnt_window_get_gtype(void); + +#define gnt_vwindow_new(homo) gnt_window_box_new(homo, TRUE) +#define gnt_hwindow_new(homo) gnt_window_box_new(homo, FALSE) + +GntWidget *gnt_window_new(); + +GntWidget *gnt_window_box_new(gboolean homo, gboolean vert); + +void gnt_window_set_menu(GntWindow *window, GntMenu *menu); + +G_END_DECLS + +#endif /* GNT_WINDOW_H */ diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/test/Makefile --- a/console/libgnt/test/Makefile Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/test/Makefile Sun Sep 24 07:14:26 2006 +0000 @@ -2,7 +2,7 @@ CFLAGS=`pkg-config --cflags gobject-2.0 gmodule-2.0` -g -I../ -DSTANDALONE LDFLAGS=`pkg-config --libs gobject-2.0 gmodule-2.0 gnt` -pg -EXAMPLES=combo focus tv multiwin keys +EXAMPLES=combo focus tv multiwin keys menu all: make examples diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/test/focus.c --- a/console/libgnt/test/focus.c Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/test/focus.c Sun Sep 24 07:14:26 2006 +0000 @@ -61,7 +61,7 @@ gnt_tree_add_choice(GNT_TREE(tree), "b", gnt_tree_create_row(GNT_TREE(tree), "b"), "d", NULL); GNT_WIDGET_UNSET_FLAGS(hbox, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); - gnt_box_set_title(GNT_BOX(hbox), "\u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 …"); + gnt_box_set_title(GNT_BOX(hbox), "\u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 \u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 ……\u4e0a\u6d77\u6700\u4f4e\u6708\u5de5 …"); g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(toggled), NULL); diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/test/menu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/console/libgnt/test/menu.c Sun Sep 24 07:14:26 2006 +0000 @@ -0,0 +1,65 @@ +#include "gnt.h" +#include "gntbox.h" +#include "gntlabel.h" +#include "gntmenu.h" +#include "gntmenuitem.h" +#include "gntwindow.h" + +void dothis(GntMenuItem *item, gpointer null) +{ + GntWidget *w = gnt_vbox_new(FALSE); + gnt_box_set_toplevel(GNT_BOX(w), TRUE); + gnt_box_add_widget(GNT_BOX(w), + gnt_label_new("Callback to a menuitem")); + gnt_widget_show(w); +} + +int main() +{ + freopen(".error", "w", stderr); + gnt_init(); + + GntWidget *menu = gnt_menu_new(GNT_MENU_TOPLEVEL); + GObject *item = gnt_menuitem_new("File"); + + gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); + + item = gnt_menuitem_new("Edit"); + gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); + + item = gnt_menuitem_new("Help"); + gnt_menu_add_item(GNT_MENU(menu), GNT_MENUITEM(item)); + + GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(GNT_MENUITEM(item), GNT_MENU(sub)); + + item = gnt_menuitem_new("Online Help"); + gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); + + item = gnt_menuitem_new("About"); + gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); + + sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(GNT_MENUITEM(item), GNT_MENU(sub)); + + item = gnt_menuitem_new("Online Help"); + gnt_menu_add_item(GNT_MENU(sub), GNT_MENUITEM(item)); + gnt_menuitem_set_callback(GNT_MENUITEM(item), dothis, NULL); + + gnt_screen_menu_show(menu); + + + GntWidget *win = gnt_window_new(); + gnt_box_add_widget(GNT_BOX(win), + gnt_label_new("...")); + gnt_box_set_title(GNT_BOX(win), "Title"); + gnt_window_set_menu(GNT_WINDOW(win), GNT_MENU(menu)); + gnt_widget_show(win); + + gnt_main(); + + gnt_quit(); + + return 0; +} + diff -r 1f46715c08d9 -r 62bb53609a36 console/libgnt/wms/s.c --- a/console/libgnt/wms/s.c Sat Sep 23 19:04:03 2006 +0000 +++ b/console/libgnt/wms/s.c Sun Sep 24 07:14:26 2006 +0000 @@ -1,4 +1,6 @@ +#include "gnt.h" #include "gntbox.h" +#include "gntmenu.h" #include "gntwm.h" #include "gntblist.h" @@ -52,6 +54,8 @@ int maxx, maxy; const char *name; + if (GNT_IS_MENU(win)) + return new_panel(win->window); getmaxyx(stdscr, maxy, maxx); gnt_widget_get_position(win, &x, &y);