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);
+		}
+	}
+}
+