Mercurial > pidgin
diff console/libgnt/gnttree.c @ 13850:0e1e59770cb0
[gaim-migrate @ 16308]
This is my first commit here. So don't yell at me if things get borked.
Also, I haven't looked at the auto-thingies yet. So don't puke at the
Makefiles.
Files in console/libgnt/ are for the 'Gaim/GObjectified Ncurses Toolkit'
library. Files in console/ uses libgaim and libgnt. Currently, only the
buddylist-ui is 'functional', ie. the buddy-list updates when someone
logs on or logs off. It still needs a lot of work.
committer: Tailor Script <tailor@pidgin.im>
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Thu, 22 Jun 2006 08:33:54 +0000 |
parents | |
children | 41753203a94d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/console/libgnt/gnttree.c Thu Jun 22 08:33:54 2006 +0000 @@ -0,0 +1,346 @@ +#include "gnttree.h" + +enum +{ + SIGS = 1, +}; + +/* XXX: Make this one into a GObject? + * ... Probably not */ +struct _GnTreeRow +{ + void *key; + char *text; + void *data; /* XXX: unused */ + + GntTreeRow *parent; + GntTreeRow *child; + GntTreeRow *next; +}; + +static GntWidgetClass *parent_class = NULL; +static guint signals[SIGS] = { 0 }; + +/* XXX: This is ugly, but what can you do ... */ +static void +gnt_tree_refresh(GntTree *tree) +{ + GntWidget *widget = GNT_WIDGET(tree); + int pos; + + if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + pos = 0; + else + pos = 1; + + copywin(tree->scroll, widget->window, tree->top, 0, + pos, pos, widget->priv.height - pos - 1, widget->priv.width - pos - 1, FALSE); + wrefresh(widget->window); +} + +static void +redraw_tree(GntTree *tree) +{ + int start; + GntWidget *widget = GNT_WIDGET(tree); + GList *iter; + + wbkgd(tree->scroll, COLOR_PAIR(GNT_COLOR_NORMAL)); + + /* XXX: Add the rows */ + for (start = tree->top, iter = g_list_nth(tree->list, tree->top); + iter && start < tree->bottom; start++, iter = iter->next) + { + char str[2096]; /* XXX: This should be safe for any terminal */ + GntTreeRow *row = g_hash_table_lookup(tree->hash, iter->data); + + snprintf(str, widget->priv.width - 2, "%s\n", row->text); + + if (start == tree->current) + { + wbkgdset(tree->scroll, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); + mvwprintw(tree->scroll, start, 0, str); + wbkgdset(tree->scroll, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); + } + else + mvwprintw(tree->scroll, start, 0, str); + } + + while (start < tree->bottom) + { + wmove(tree->scroll, start, 0); + wclrtoeol(tree->scroll); + start++; + } + + gnt_tree_refresh(tree); +} + +static void +gnt_tree_draw(GntWidget *widget) +{ + GntTree *tree = GNT_TREE(widget); + + /* For the Tree (or anything that scrolls), we will create a 'hidden' window + * of 'large enough' size. We never wrefresh that hidden-window, instead we + * just 'scroll' it, and wrefresh the subwindow */ + + if (tree->scroll == NULL) + { + tree->scroll = newwin(SCROLL_HEIGHT, widget->priv.width, widget->priv.y, widget->priv.x); + scrollok(tree->scroll, TRUE); + wsetscrreg(tree->scroll, 0, SCROLL_HEIGHT - 1); + + tree->top = 0; + tree->bottom = widget->priv.height - + (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER) ? 0 : 2); + } + + redraw_tree(tree); + + DEBUG; +} + +static void +gnt_tree_size_request(GntWidget *widget) +{ + if (widget->priv.height == 0) + widget->priv.height = 10; /* XXX: Why?! */ + if (widget->priv.width == 0) + widget->priv.width = 20; /* YYY: 'cuz ... */ +} + +static void +gnt_tree_map(GntWidget *widget) +{ + if (widget->priv.width == 0 || widget->priv.height == 0) + gnt_widget_size_request(widget); + DEBUG; +} + +static gboolean +gnt_tree_key_pressed(GntWidget *widget, const char *text) +{ + GntTree *tree = GNT_TREE(widget); + if (text[0] == 27) + { + if (strcmp(text+1, GNT_KEY_DOWN) == 0 && tree->current < g_list_length(tree->list) - 1) + { + tree->current++; + if (tree->current >= tree->bottom) + gnt_tree_scroll(tree, 1 + tree->current - tree->bottom); + redraw_tree(tree); + } + else if (strcmp(text+1, GNT_KEY_UP) == 0 && tree->current > 0) + { + tree->current--; + if (tree->current < tree->top) + gnt_tree_scroll(tree, tree->current - tree->top); + redraw_tree(tree); + } + } + else if (text[0] == '\r') + { + gnt_widget_activate(widget); + } + + return FALSE; +} + +static void +gnt_tree_destroy(GntWidget *widget) +{ + GntTree *tree = GNT_TREE(widget); + + g_hash_table_destroy(tree->hash); + g_list_free(tree->list); +} + +static void +gnt_tree_class_init(GntWidgetClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + + parent_class = GNT_WIDGET_CLASS(klass); + parent_class->destroy = gnt_tree_destroy; + parent_class->draw = gnt_tree_draw; + parent_class->map = gnt_tree_map; + parent_class->size_request = gnt_tree_size_request; + parent_class->key_pressed = gnt_tree_key_pressed; + + DEBUG; +} + +static void +gnt_tree_init(GTypeInstance *instance, gpointer class) +{ + DEBUG; +} + +/****************************************************************************** + * GntTree API + *****************************************************************************/ +GType +gnt_tree_get_gtype(void) +{ + static GType type = 0; + + if(type == 0) + { + static const GTypeInfo info = { + sizeof(GntTreeClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gnt_tree_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GntTree), + 0, /* n_preallocs */ + gnt_tree_init, /* instance_init */ + }; + + type = g_type_register_static(GNT_TYPE_WIDGET, + "GntTree", + &info, 0); + } + + return type; +} + +GntWidget *gnt_tree_new() +{ + GntWidget *widget = g_object_new(GNT_TYPE_TREE, NULL); + GntTree *tree = GNT_TREE(widget); + + tree->hash = g_hash_table_new(g_direct_hash, g_direct_equal); + + return widget; +} + +void gnt_tree_set_visible_rows(GntTree *tree, int rows) +{ + GntWidget *widget = GNT_WIDGET(tree); + widget->priv.height = rows; + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + widget->priv.height += 2; +} + +int gnt_tree_get_visible_rows(GntTree *tree) +{ + GntWidget *widget = GNT_WIDGET(tree); + int ret = widget->priv.height; + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) + widget->priv.height -= 2; +} + +void gnt_tree_scroll(GntTree *tree, int count) +{ + if (tree->top == 0 && count < 0) + return; + + if (count > 0 && tree->bottom + count >= g_list_length(tree->list)) + count = g_list_length(tree->list) - tree->bottom; + else if (count < 0 && tree->top + count < 0) + count = -tree->top; + + tree->top += count; + tree->bottom += count; + + /*wscrl(tree->scroll, count);*/ + gnt_tree_refresh(tree); +} + +void gnt_tree_add_row_after(GntTree *tree, void *key, const char *text, void *parent, void *bigbro) +{ + GntTreeRow *row = g_new0(GntTreeRow, 1), *pr = NULL; + + row->key = key; + row->text = g_strdup(text); + row->data = NULL; + + g_hash_table_insert(tree->hash, key, row); + + if (tree->root == NULL) + { + tree->root = row; + tree->list = g_list_prepend(tree->list, key); + } + else + { + int position; + + if (bigbro) + { + pr = g_hash_table_lookup(tree->hash, bigbro); + if (pr) + { + row->next = pr->next; + pr->next = row; + row->parent = pr->parent; + + position = g_list_index(tree->list, bigbro); + } + } + + if (pr == NULL && parent) + { + pr = g_hash_table_lookup(tree->hash, parent); + if (pr) + { + row->next = pr->child; + pr->child = row; + row->parent = pr; + + position = g_list_index(tree->list, parent); + } + } + + if (pr == NULL) + { + row->next = tree->root; + tree->root = row; + + tree->list = g_list_prepend(tree->list, key); + } + else + { + tree->list = g_list_insert(tree->list, key, position + 1); + } + } + + if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED)) + redraw_tree(tree); +} + +gpointer gnt_tree_get_selection_data(GntTree *tree) +{ + return g_list_nth(tree->list, tree->current); +} + +int gnt_tree_get_selection_index(GntTree *tree) +{ + return tree->current; +} + +void gnt_tree_remove(GntTree *tree, gpointer key) +{ + GntTreeRow *row = g_hash_table_lookup(tree->hash, key); + if (row) + { + int len, pos; + + g_free(row->text); + g_free(row); + + pos = g_list_index(tree->list, key); + + g_hash_table_remove(tree->hash, key); + tree->list = g_list_remove(tree->list, key); + + if (pos >= tree->top && pos < tree->bottom) + { + redraw_tree(tree); + } + } +} +