changeset 13855:5b288502a382

[gaim-migrate @ 16314] New widget GntEntry. It's mostly functional. Some minor improvements to the box-packing code. Minor improvements to the skeleton code for gnt, and completely change the name from my initial choice of GN (Glib and Ncurses) to GNT (Gaim Ncurses Toolkit). committer: Tailor Script <tailor@pidgin.im>
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Fri, 23 Jun 2006 06:24:25 +0000
parents a4c30c1d9de8
children 3cdd05b9830a
files console/libgnt/Makefile console/libgnt/gnt-skel.c console/libgnt/gnt-skel.h console/libgnt/gntbox.c console/libgnt/gntcolors.c console/libgnt/gntentry.c console/libgnt/gntentry.h console/libgnt/gntkeys.h console/libgnt/gnttree.c console/libgnt/gntwidget.c console/libgnt/test.c
diffstat 11 files changed, 404 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/console/libgnt/Makefile	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/Makefile	Fri Jun 23 06:24:25 2006 +0000
@@ -6,6 +6,7 @@
 	gntbox.h \
 	gntbutton.h \
 	gntcolors.h \
+	gntentry.h \
 	gntlabel.h \
 	gnttree.h \
 	gntutils.h \
@@ -16,6 +17,7 @@
 	gntbox.c \
 	gntbutton.c \
 	gntcolors.c \
+	gntentry.c \
 	gntlabel.c \
 	gnttree.c \
 	gntutils.c \
@@ -26,6 +28,7 @@
 	gntbox.o \
 	gntbutton.o \
 	gntcolors.o \
+	gntentry.o \
 	gntlabel.o \
 	gnttree.o \
 	gntutils.o \
@@ -34,11 +37,13 @@
 all: libgnt
 
 test: $(OBJECTS)
+key: $(OBJECTS)
 
 gntwidget.o: gntwidget.c $(HEADERS)
 gntbox.o: gntbox.c $(HEADERS)
 gntbutton.o: gntbutton.c $(HEADERS)
 gntcolors.o: gntcolors.c $(HEADERS)
+gntentry.o: gntentry.c $(HEADERS)
 gntlabel.o: gntlabel.c $(HEADERS)
 gnttree.o: gnttree.c $(HEADERS)
 gntutils.o: gntutils.c $(HEADERS)
--- a/console/libgnt/gnt-skel.c	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/gnt-skel.c	Fri Jun 23 06:24:25 2006 +0000
@@ -1,4 +1,4 @@
-#include "gn-skel.h"
+#include "gnt-skel.h"
 
 enum
 {
@@ -34,11 +34,17 @@
 }
 
 static void
+gnt_skel_destroy(GntWidget *widget)
+{
+}
+
+static void
 gnt_skel_class_init(GntWidgetClass *klass)
 {
 	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
 
 	parent_class = GNT_WIDGET_CLASS(klass);
+	parent_class->destroy = gnt_skel_destroy;
 	parent_class->draw = gnt_skel_draw;
 	parent_class->map = gnt_skel_map;
 	parent_class->size_request = gnt_skel_size_request;
--- a/console/libgnt/gnt-skel.h	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/gnt-skel.h	Fri Jun 23 06:24:25 2006 +0000
@@ -1,10 +1,10 @@
 #ifndef GNT_SKEL_H
 #define GNT_SKEL_H
 
-#include "gnwidget.h"
-#include "gn.h"
-#include "gncolors.h"
-#include "gnkeys.h"
+#include "gntwidget.h"
+#include "gnt.h"
+#include "gntcolors.h"
+#include "gntkeys.h"
 
 #define GNT_TYPE_SKEL				(gnt_skel_get_gtype())
 #define GNT_SKEL(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_SKEL, GntSkel))
--- a/console/libgnt/gntbox.c	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/gntbox.c	Fri Jun 23 06:24:25 2006 +0000
@@ -53,15 +53,13 @@
 
 	w = h = 0;
 	max = -1;
-	curx = widget->priv.x + 1;
-	cury = widget->priv.y + 1;
+	curx = widget->priv.x;
+	cury = widget->priv.y;
 	if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER))
 	{
 		has_border = TRUE;
-		curx += box->pad;
-		cury += box->pad;
-		if (!box->vertical)
-			curx++;
+		curx += 1;
+		cury += 1;
 	}
 
 	for (iter = box->list; iter; iter = iter->next)
@@ -84,7 +82,7 @@
 
 	if (has_border)
 	{
-		curx += 2;
+		curx += 1;
 		cury += 1;
 		max += 2;
 	}
@@ -146,16 +144,44 @@
 	DEBUG;
 }
 
+/* Ensures that the current widget can take focus */
+static void
+ensure_active(GntBox *box)
+{
+	int investigated = 0;
+	int total;
+
+	if (box->active == NULL)
+		box->active = box->list;
+
+	total = g_list_length(box->list);
+
+	while (box->active && !GNT_WIDGET_IS_FLAG_SET(box->active->data, GNT_WIDGET_CAN_TAKE_FOCUS))
+	{
+		box->active = box->active->next;
+		investigated++;
+	}
+
+	/* Rotate if necessary */
+	if (!box->active && investigated < total)
+	{
+		box->active = box->list;
+		while (investigated < total &&  !GNT_WIDGET_IS_FLAG_SET(box->active->data, GNT_WIDGET_CAN_TAKE_FOCUS))
+		{
+			box->active = box->active->next;
+			investigated++;
+		}
+	}
+}
+
 static gboolean
 gnt_box_key_pressed(GntWidget *widget, const char *text)
 {
 	GntBox *box = GNT_BOX(widget);
 
-	/*if (box->list == NULL)*/
-		/*return FALSE;*/
-
+	ensure_active(box);
 	if (box->active == NULL)
-		box->active = box->list;
+		return FALSE;
 
 	if (gnt_widget_key_pressed(box->active->data, text))
 		return TRUE;
--- a/console/libgnt/gntcolors.c	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/gntcolors.c	Fri Jun 23 06:24:25 2006 +0000
@@ -19,6 +19,7 @@
 		init_pair(GNT_COLOR_HIGHLIGHT, GNT_COLOR_BLUE, GNT_COLOR_GRAY);
 		init_pair(GNT_COLOR_SHADOW, GNT_COLOR_BLACK, GNT_COLOR_DARK_GRAY);
 		init_pair(GNT_COLOR_TITLE, GNT_COLOR_WHITE, GNT_COLOR_DARK_GRAY);
+		init_pair(GNT_COLOR_TEXT_NORMAL, GNT_COLOR_BLACK, GNT_COLOR_GRAY);
 	}
 	else
 	{
@@ -26,6 +27,7 @@
 		init_pair(GNT_COLOR_HIGHLIGHT, COLOR_CYAN, COLOR_BLACK);
 		init_pair(GNT_COLOR_SHADOW, COLOR_BLACK, COLOR_BLACK);
 		init_pair(GNT_COLOR_TITLE, COLOR_WHITE, COLOR_BLACK);
+		init_pair(GNT_COLOR_TEXT_NORMAL, COLOR_BLACK, COLOR_WHITE);
 	}
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/console/libgnt/gntentry.c	Fri Jun 23 06:24:25 2006 +0000
@@ -0,0 +1,251 @@
+#include <string.h>
+#include "gntentry.h"
+
+enum
+{
+	SIGS = 1,
+};
+
+static GntWidgetClass *parent_class = NULL;
+static guint signals[SIGS] = { 0 };
+
+static void
+gnt_entry_draw(GntWidget *widget)
+{
+	GntEntry *entry = GNT_ENTRY(widget);
+	int stop;
+
+	wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TEXT_NORMAL));
+	mvwprintw(widget->window, 0, 0, entry->scroll);
+
+	stop = entry->end - entry->scroll;
+	if (stop < widget->priv.width)
+		mvwhline(widget->window, 0, stop, ENTRY_CHAR, widget->priv.width - stop);
+
+	wrefresh(widget->window);
+
+	DEBUG;
+}
+
+static void
+gnt_entry_size_request(GntWidget *widget)
+{
+	GntEntry *entry = GNT_ENTRY(widget);
+	widget->priv.height = 1;
+	widget->priv.width = 20;
+}
+
+static void
+gnt_entry_map(GntWidget *widget)
+{
+	if (widget->priv.width == 0 || widget->priv.height == 0)
+		gnt_widget_size_request(widget);
+	DEBUG;
+}
+
+static gboolean
+gnt_entry_key_pressed(GntWidget *widget, const char *text)
+{
+	GntEntry *entry = GNT_ENTRY(widget);
+
+	if (text[0] == 27)
+	{
+		if (strcmp(text + 1, GNT_KEY_DEL) == 0 && entry->cursor < entry->end)
+		{
+			memmove(entry->cursor, entry->cursor + 1, entry->end - entry->cursor + 1);
+			entry->end--;
+			gnt_entry_draw(widget);
+		}
+		else if (strcmp(text + 1, GNT_KEY_LEFT) == 0 && entry->cursor > entry->start)
+		{
+			entry->cursor--;
+			if (entry->cursor < entry->scroll)
+				entry->scroll--;
+			gnt_entry_draw(widget);
+		}
+		else if (strcmp(text + 1, GNT_KEY_RIGHT) == 0 && entry->cursor < entry->end)
+		{
+			entry->cursor++;
+			if (entry->cursor - entry->scroll > widget->priv.width)
+				entry->scroll++;
+			gnt_entry_draw(widget);
+		}
+		/* XXX: handle other keys, like home/end, and ctrl+ goodness */
+	}
+	else
+	{
+		if (!iscntrl(text[0]))
+		{
+			int i;
+
+			for (i = 0; text[i]; i++)
+			{
+				/* Valid input? */
+				if (ispunct(text[i]) && (entry->flag & GNT_ENTRY_FLAG_NO_PUNCT))
+					continue;
+				if (isspace(text[i]) && (entry->flag & GNT_ENTRY_FLAG_NO_SPACE))
+					continue;
+				if (isalpha(text[i]) && !(entry->flag & GNT_ENTRY_FLAG_ALPHA))
+					continue;
+				if (isdigit(text[i]) && !(entry->flag & GNT_ENTRY_FLAG_INT))
+					continue;
+
+				/* Reached the max? */
+				if (entry->max && entry->end - entry->start >= entry->max)
+					continue;
+
+				if (entry->end - entry->start >= entry->buffer)
+				{
+					char *tmp = g_strdup_printf(entry->start);
+					gnt_entry_set_text(entry, tmp);
+					g_free(tmp);
+				}
+
+				*(entry->cursor) = text[i];
+				entry->cursor++;
+
+				entry->end++;
+				if (entry->cursor - entry->scroll > widget->priv.width)
+					entry->scroll++;
+			}
+			gnt_entry_draw(widget);
+		}
+		else
+		{
+			/* Backspace is here */
+			if (strcmp(text, GNT_KEY_BACKSPACE) == 0 && entry->cursor > entry->start)
+			{
+				entry->cursor--;
+				memmove(entry->cursor, entry->cursor + 1, entry->end - entry->cursor);
+				entry->end--;
+
+				if (entry->scroll > entry->start)
+					entry->scroll--;
+
+				gnt_entry_draw(widget);
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+static void
+gnt_entry_destroy(GntWidget *widget)
+{
+	GntEntry *entry = GNT_ENTRY(widget);
+	g_free(entry->start);
+}
+
+static void
+gnt_entry_class_init(GntWidgetClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	parent_class = GNT_WIDGET_CLASS(klass);
+	parent_class->destroy = gnt_entry_destroy;
+	parent_class->draw = gnt_entry_draw;
+	parent_class->map = gnt_entry_map;
+	parent_class->size_request = gnt_entry_size_request;
+	parent_class->key_pressed = gnt_entry_key_pressed;
+
+	DEBUG;
+}
+
+static void
+gnt_entry_init(GTypeInstance *instance, gpointer class)
+{
+	GntEntry *entry = GNT_ENTRY(instance);
+
+	entry->flag = GNT_ENTRY_FLAG_ALL;
+	entry->max = 0;
+
+	GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry),
+			GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS);
+	
+	DEBUG;
+}
+
+/******************************************************************************
+ * GntEntry API
+ *****************************************************************************/
+GType
+gnt_entry_get_gtype(void)
+{
+	static GType type = 0;
+
+	if(type == 0)
+	{
+		static const GTypeInfo info = {
+			sizeof(GntEntryClass),
+			NULL,					/* base_init		*/
+			NULL,					/* base_finalize	*/
+			(GClassInitFunc)gnt_entry_class_init,
+			NULL,					/* class_finalize	*/
+			NULL,					/* class_data		*/
+			sizeof(GntEntry),
+			0,						/* n_preallocs		*/
+			gnt_entry_init,			/* instance_init	*/
+		};
+
+		type = g_type_register_static(GNT_TYPE_WIDGET,
+									  "GntEntry",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+GntWidget *gnt_entry_new(const char *text)
+{
+	GntWidget *widget = g_object_new(GNT_TYPE_ENTRY, NULL);
+	GntEntry *entry = GNT_ENTRY(widget);
+
+	gnt_entry_set_text(entry, text);
+
+	return widget;
+}
+
+void gnt_entry_set_text(GntEntry *entry, const char *text)
+{
+	int len;
+	int scroll, cursor;
+
+	g_free(entry->start);
+
+	if (text && text[0])
+	{
+		len = g_utf8_strlen(text, -1);
+		entry->buffer = len * 2;
+	}
+	else
+	{
+		entry->buffer = 128;
+		len = 0;
+	}
+
+	scroll = entry->scroll - entry->start;
+	cursor = entry->end - entry->cursor;
+
+	entry->start = g_new0(char, entry->buffer);
+	if (text)
+		snprintf(entry->start, len + 1, "%s", text);
+	entry->end = entry->start + len;
+
+	entry->scroll = entry->start + scroll;
+	entry->cursor = entry->end - cursor;
+
+	/* XXX: redraw if necessary? */
+}
+
+void gnt_entry_set_max(GntEntry *entry, int max)
+{
+	entry->max = max;
+}
+
+void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag)
+{
+	entry->flag = flag;
+	/* XXX: Check the existing string to make sure the flags are respected? */
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/console/libgnt/gntentry.h	Fri Jun 23 06:24:25 2006 +0000
@@ -0,0 +1,78 @@
+#ifndef GNT_ENTRY_H
+#define GNT_ENTRY_H
+
+#include "gntwidget.h"
+#include "gnt.h"
+#include "gntcolors.h"
+#include "gntkeys.h"
+
+#define GNT_TYPE_ENTRY				(gnt_entry_get_gtype())
+#define GNT_ENTRY(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_ENTRY, GntEntry))
+#define GNT_ENTRY_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), GNT_TYPE_ENTRY, GntEntryClass))
+#define GNT_IS_ENTRY(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_ENTRY))
+#define GNT_IS_ENTRY_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_ENTRY))
+#define GNT_ENTRY_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_ENTRY, GntEntryClass))
+
+#define GNT_ENTRY_FLAGS(obj)				(GNT_ENTRY(obj)->priv.flags)
+#define GNT_ENTRY_SET_FLAGS(obj, flags)		(GNT_ENTRY_FLAGS(obj) |= flags)
+#define GNT_ENTRY_UNSET_FLAGS(obj, flags)	(GNT_ENTRY_FLAGS(obj) &= ~(flags))
+
+#define	ENTRY_CHAR		'_'			/* The character to use to fill in the blank places */
+
+typedef struct _GnEntry			GntEntry;
+typedef struct _GnEntryPriv		GntEntryPriv;
+typedef struct _GnEntryClass	GntEntryClass;
+
+typedef enum
+{
+	GNT_ENTRY_FLAG_ALPHA    = 1 << 0,  /* Only alpha */
+	GNT_ENTRY_FLAG_INT      = 1 << 1,  /* Only integer */
+	GNT_ENTRY_FLAG_NO_SPACE = 1 << 2,  /* No blank space is allowed */
+	GNT_ENTRY_FLAG_NO_PUNCT = 1 << 3,  /* No punctuations */
+	GNT_ENTRY_FLAG_MASK     = 1 << 4,  /* Mask the inputs */
+} GntEntryFlag;
+
+#define GNT_ENTRY_FLAG_ALL    (GNT_ENTRY_FLAG_ALPHA | GNT_ENTRY_FLAG_INT)
+
+struct _GnEntry
+{
+	GntWidget parent;
+
+	GntEntryFlag flag;
+
+	char *start;
+	char *end;
+	char *scroll;   /* Current scrolling position */
+	char *cursor;   /* Cursor location */
+	                /* 0 <= cursor - scroll < widget-width */
+	
+	size_t buffer;  /* Size of the buffer */
+	
+	int max;        /* 0 means infinite */
+};
+
+struct _GnEntryClass
+{
+	GntWidgetClass parent;
+
+	void (*gnt_reserved1)(void);
+	void (*gnt_reserved2)(void);
+	void (*gnt_reserved3)(void);
+	void (*gnt_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType gnt_entry_get_gtype(void);
+
+GntWidget *gnt_entry_new(const char *text);
+
+void gnt_entry_set_max(GntEntry *entry, int max);
+
+void gnt_entry_set_text(GntEntry *entry, const char *text);
+
+void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag);
+
+G_END_DECLS
+
+#endif /* GNT_ENTRY_H */
--- a/console/libgnt/gntkeys.h	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/gntkeys.h	Fri Jun 23 06:24:25 2006 +0000
@@ -1,14 +1,17 @@
 #ifndef GNT_KEYS_H
 #define GNT_KEYS_H
 
-#define	GNT_KEY_POPUP	"[29~"
+#define GNT_KEY_POPUP   "[29~"
 
 /* Arrow keys */
-#define	GNT_KEY_LEFT		"[D"
-#define	GNT_KEY_RIGHT	"[C"
-#define	GNT_KEY_UP		"[A"
-#define	GNT_KEY_DOWN		"[B"
+#define GNT_KEY_LEFT   "[D"
+#define GNT_KEY_RIGHT  "[C"
+#define GNT_KEY_UP     "[A"
+#define GNT_KEY_DOWN   "[B"
 
-#define	GNT_KEY_ENTER	"\r"
+#define GNT_KEY_ENTER  "\r"
+
+#define GNT_KEY_BACKSPACE "\177"
+#define GNT_KEY_DEL    "[3~"
 
 #endif
--- a/console/libgnt/gnttree.c	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/gnttree.c	Fri Jun 23 06:24:25 2006 +0000
@@ -46,11 +46,11 @@
 		if ((wr = snprintf(str, widget->priv.width, "%s", row->text)) >= widget->priv.width)
 		{
 			/* XXX: ellipsize */
-			str[widget->priv.width - 1] = 0;
+			str[widget->priv.width - 1 - pos] = 0;
 		}
 		else
 		{
-			while (wr < widget->priv.width - 1)
+			while (wr < widget->priv.width - 1 - pos)
 				str[wr++] = ' ';
 			str[wr] = 0;
 		}
@@ -67,8 +67,8 @@
 
 	while (start < tree->bottom)
 	{
-		wmove(widget->window, start - tree->top + pos, pos);
-		wclrtoeol(widget->window);
+		mvwhline(widget->window, start - tree->top + pos, pos, ' ',
+				widget->priv.width - pos * 2);
 		start++;
 	}
 
--- a/console/libgnt/gntwidget.c	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/gntwidget.c	Fri Jun 23 06:24:25 2006 +0000
@@ -286,6 +286,8 @@
 gnt_widget_key_pressed(GntWidget *widget, const char *keys)
 {
 	gboolean ret;
+	if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS))
+		return FALSE;
 	g_signal_emit(widget, signals[SIG_KEY_PRESSED], 0, keys, &ret);
 	return ret;
 }
--- a/console/libgnt/test.c	Fri Jun 23 00:57:30 2006 +0000
+++ b/console/libgnt/test.c	Fri Jun 23 06:24:25 2006 +0000
@@ -90,7 +90,9 @@
 	gnt_box_add_widget(GNT_BOX(vbox), widget2);
 
 	gnt_box_add_widget(GNT_BOX(hbox), label);
-	gnt_box_add_widget(GNT_BOX(hbox), vbox);
+	/*gnt_box_add_widget(GNT_BOX(hbox), vbox);*/
+
+	gnt_box_add_widget(GNT_BOX(hbox), gnt_entry_new("a"));
 
 	tree = gnt_tree_new();
 	gnt_box_add_widget(GNT_BOX(hbox), tree);
@@ -106,11 +108,11 @@
 
 	/*gnt_widget_set_take_focus(vbox, TRUE);*/
 	/*gnt_widget_set_take_focus(hbox, TRUE);*/
-	gnt_widget_set_position(hbox, 10, 10);
+	/*gnt_widget_set_position(hbox, 10, 10);*/
 
 	gnt_widget_show(hbox);
 
-	g_signal_connect(hbox, "key_pressed", G_CALLBACK(key_pressed), widget);
+	/*g_signal_connect(hbox, "key_pressed", G_CALLBACK(key_pressed), widget);*/
 	g_signal_connect(widget, "activate", G_CALLBACK(button1), hbox);
 	g_signal_connect(widget2, "activate", G_CALLBACK(button2), hbox);