⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gnttree.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#include "gntmarshal.h"#include "gntstyle.h"#include "gnttree.h"#include "gntutils.h"#include <string.h>#include <ctype.h>#define SEARCH_TIMEOUT 4000   /* 4 secs */#define SEARCHING(tree)  (tree->search && tree->search->len > 0)enum{	SIG_SELECTION_CHANGED,	SIG_SCROLLED,	SIG_TOGGLED,	SIG_COLLAPSED,	SIGS,};#define	TAB_SIZE 3/* XXX: Make this one into a GObject? * 		 ... Probably not */struct _GntTreeRow{	void *key;	void *data;		/* XXX: unused */	gboolean collapsed;	gboolean choice;            /* Is this a choice-box?	                               If choice is true, then child will be NULL */	gboolean isselected;	GntTextFormatFlags flags;	GntTreeRow *parent;	GntTreeRow *child;	GntTreeRow *next;	GntTreeRow *prev;	GList *columns;	GntTree *tree;};struct _GntTreeCol{	char *text;	int span;       /* How many columns does it span? */};static void tree_selection_changed(GntTree *, GntTreeRow *, GntTreeRow *);static GntWidgetClass *parent_class = NULL;static guint signals[SIGS] = { 0 };/* Move the item at position old to position new */static GList *g_list_reposition_child(GList *list, int old, int new){	gpointer item = g_list_nth_data(list, old);	list = g_list_remove(list, item);	if (old < new)		new--;   /* because the positions would have shifted after removing the item */	list = g_list_insert(list, item, new);	return list;}static GntTreeRow *_get_next(GntTreeRow *row, gboolean godeep){	if (row == NULL)		return NULL;	if (godeep && row->child)		return row->child;	if (row->next)		return row->next;	return _get_next(row->parent, FALSE);}static gbooleanrow_matches_search(GntTreeRow *row){	GntTree *t = row->tree;	if (t->search && t->search->len > 0) {		char *one = g_utf8_casefold(((GntTreeCol*)row->columns->data)->text, -1);		char *two = g_utf8_casefold(t->search->str, -1);		char *z = strstr(one, two);		g_free(one);		g_free(two);		if (z == NULL)			return FALSE;	}	return TRUE;}static GntTreeRow *get_next(GntTreeRow *row){	if (row == NULL)		return NULL;	while ((row = _get_next(row, !row->collapsed)) != NULL) {		if (row_matches_search(row))			break;	}	return row;}/* Returns the n-th next row. If it doesn't exist, returns NULL */static GntTreeRow *get_next_n(GntTreeRow *row, int n){	while (row && n--)		row = get_next(row);	return row;}/* Returns the n-th next row. If it doesn't exist, then the last non-NULL node */static GntTreeRow *get_next_n_opt(GntTreeRow *row, int n, int *pos){	GntTreeRow *next = row;	int r = 0;	if (row == NULL)		return NULL;	while (row && n--)	{		row = get_next(row);		if (row)		{			next = row;			r++;		}	}	if (pos)		*pos = r;	return next;}static GntTreeRow *get_last_child(GntTreeRow *row){	if (row == NULL)		return NULL;	if (!row->collapsed && row->child)		row = row->child;	else		return row;	while(row->next)		row = row->next;	return get_last_child(row);}static GntTreeRow *get_prev(GntTreeRow *row){	if (row == NULL)		return NULL;	while (row) {		if (row->prev)			row = get_last_child(row->prev);		else			row = row->parent;		if (!row || row_matches_search(row))			break;	}	return row;}static GntTreeRow *get_prev_n(GntTreeRow *row, int n){	while (row && n--)		row = get_prev(row);	return row;}/* Distance of row from the root *//* XXX: This is uber-inefficient */static intget_root_distance(GntTreeRow *row){	if (row == NULL)		return -1;	return get_root_distance(get_prev(row)) + 1;}/* Returns the distance between a and b.  * If a is 'above' b, then the distance is positive */static intget_distance(GntTreeRow *a, GntTreeRow *b){	/* First get the distance from a to the root.	 * Then the distance from b to the root.	 * Subtract.	 * It's not that good, but it works. */	int ha = get_root_distance(a);	int hb = get_root_distance(b);	return (hb - ha);}static intfind_depth(GntTreeRow *row){	int dep = -1;	while (row)	{		dep++;		row = row->parent;	}	return dep;}static char *update_row_text(GntTree *tree, GntTreeRow *row){	GString *string = g_string_new(NULL);	GList *iter;	int i;	gboolean notfirst = FALSE;	int lastvisible = tree->ncol;	while (lastvisible && tree->columns[lastvisible].invisible)		lastvisible--;	for (i = 0, iter = row->columns; i < tree->ncol && iter; i++, iter = iter->next)	{		GntTreeCol *col = iter->data;		const char *text;		int len = gnt_util_onscreen_width(col->text, NULL);		int fl = 0;		gboolean cut = FALSE;		int width;		if (tree->columns[i].invisible)			continue;		if (i == lastvisible)			width = GNT_WIDGET(tree)->priv.width - gnt_util_onscreen_width(string->str, NULL);		else			width = tree->columns[i].width;		if (i == 0)		{			if (row->choice)			{				g_string_append_printf(string, "[%c] ",						row->isselected ? 'X' : ' ');				fl = 4;			}			else if (row->parent == NULL && row->child)			{				if (row->collapsed)				{					string = g_string_append(string, "+ ");				}				else				{					string = g_string_append(string, "- ");				}				fl = 2;			}			else			{				fl = TAB_SIZE * find_depth(row);				g_string_append_printf(string, "%*s", fl, "");			}			len += fl;		}		else if (notfirst)			g_string_append_c(string, '|');		else			g_string_append_c(string, ' ');		notfirst = TRUE;		if (len > width) {			len = width - 1;			cut = TRUE;		}		text = gnt_util_onscreen_width_to_pointer(col->text, len - fl, NULL);		string = g_string_append_len(string, col->text, text - col->text);		if (cut) { /* ellipsis */			if (gnt_ascii_only())				g_string_append_c(string, '~');			else				string = g_string_append(string, "\342\200\246");			len++;		}		if (len < tree->columns[i].width && iter->next)			g_string_append_printf(string, "%*s", width - len, "");	}	return g_string_free(string, FALSE);}#define NEXT_X x += tree->columns[i].width + (i > 0 ? 1 : 0)static voidtree_mark_columns(GntTree *tree, int pos, int y, chtype type){	GntWidget *widget = GNT_WIDGET(tree);	int i;	int x = pos;	gboolean notfirst = FALSE;	for (i = 0; i < tree->ncol - 1; i++)	{		if (!tree->columns[i].invisible) {			notfirst = TRUE;			NEXT_X;		}		if (!tree->columns[i+1].invisible && notfirst)			mvwaddch(widget->window, y, x, type);	}}static voidredraw_tree(GntTree *tree){	int start, i;	GntWidget *widget = GNT_WIDGET(tree);	GntTreeRow *row;	int pos, up, down;	int rows, scrcol;	if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED))		return;	if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER))		pos = 0;	else		pos = 1;	if (tree->top == NULL)		tree->top = tree->root;	if (tree->current == NULL) {		tree->current = tree->root;		tree_selection_changed(tree, NULL, tree->current);	}	wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL));	start = 0;	if (tree->show_title)	{		int i;		int x = pos;		mvwhline(widget->window, pos + 1, pos, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL),				widget->priv.width - pos - 1);		mvwhline(widget->window, pos, pos, ' ' | COLOR_PAIR(GNT_COLOR_NORMAL),				widget->priv.width - pos - 1);		for (i = 0; i < tree->ncol; i++)		{			if (tree->columns[i].invisible) {				continue;			}			mvwaddstr(widget->window, pos, x + 1, tree->columns[i].title);			NEXT_X;		}		if (pos)		{			tree_mark_columns(tree, pos, 0, ACS_TTEE | COLOR_PAIR(GNT_COLOR_NORMAL));			tree_mark_columns(tree, pos, widget->priv.height - pos,					ACS_BTEE | 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;	}	rows = widget->priv.height - pos * 2 - start - 1;	tree->bottom = get_next_n_opt(tree->top, rows, &down);	if (down < rows)	{		tree->top = get_prev_n(tree->bottom, rows);		if (tree->top == NULL)			tree->top = tree->root;	}	up = get_distance(tree->top, tree->current);	if (up < 0)		tree->top = tree->current;	else if (up >= widget->priv.height - pos)		tree->top = get_prev_n(tree->current, rows);	if (tree->top && !row_matches_search(tree->top))		tree->top = get_next(tree->top);	row = tree->top;	scrcol = widget->priv.width - 1 - 2 * pos;  /* exclude the borders and the scrollbar */	for (i = start + pos; row && i < widget->priv.height - pos;				i++, row = get_next(row))	{		char *str;		int wr;		GntTextFormatFlags flags = row->flags;		int attr = 0;		if (!row_matches_search(row))			continue;		str = update_row_text(tree, row);		if ((wr = gnt_util_onscreen_width(str, NULL)) > scrcol)		{			char *s = (char*)gnt_util_onscreen_width_to_pointer(str, scrcol, &wr);			*s = '\0';		}		if (flags & GNT_TEXT_FLAG_BOLD)			attr |= A_BOLD;		if (flags & GNT_TEXT_FLAG_UNDERLINE)			attr |= A_UNDERLINE;		if (flags & GNT_TEXT_FLAG_BLINK)			attr |= A_BLINK;		if (row == tree->current)		{			if (gnt_widget_has_focus(widget))				attr |= COLOR_PAIR(GNT_COLOR_HIGHLIGHT);			else				attr |= COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D);		}		else		{			if (flags & GNT_TEXT_FLAG_DIM)				attr |= (A_DIM | COLOR_PAIR(GNT_COLOR_DISABLED));			else if (flags & GNT_TEXT_FLAG_HIGHLIGHT)				attr |= (A_DIM | COLOR_PAIR(GNT_COLOR_HIGHLIGHT));			else				attr |= COLOR_PAIR(GNT_COLOR_NORMAL);		}		wbkgdset(widget->window, '\0' | attr);		mvwaddstr(widget->window, i, pos, str);		whline(widget->window, ' ', scrcol - wr);		tree->bottom = row;		g_free(str);		tree_mark_columns(tree, pos, i,			(tree->show_separator ? ACS_VLINE : ' ') | attr);	}	wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));	while (i < widget->priv.height - pos)	{		mvwhline(widget->window, i, pos, ' ',				widget->priv.width - pos * 2 - 1);		tree_mark_columns(tree, pos, i,			(tree->show_separator ? ACS_VLINE : ' '));		i++;	}	scrcol = widget->priv.width - pos - 1;  /* position of the scrollbar */	rows--;	if (rows > 0)	{		int total;		int showing, position;		get_next_n_opt(tree->root, g_list_length(tree->list), &total);		showing = rows * rows / MAX(total, 1) + 1;		showing = MIN(rows, showing);		total -= rows;		up = get_distance(tree->root, tree->top);		down = total - up;		position = (rows - showing) * up / MAX(1, up + down);		position = MAX((tree->top != tree->root), position);		if (showing + position > rows)			position = rows - showing;		if (showing + position == rows  && row)			position = MAX(0, rows - 1 - showing);		else if (showing + position < rows && !row)			position = rows - showing;		position += pos + start + 1;		mvwvline(widget->window, pos + start + 1, scrcol,				' ' | COLOR_PAIR(GNT_COLOR_NORMAL), rows);		mvwvline(widget->window, position, scrcol,				ACS_CKBOARD | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D), showing);	}	mvwaddch(widget->window, start + pos, scrcol,			((tree->top != tree->root) ?  ACS_UARROW : ' ') |				COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));	mvwaddch(widget->window, widget->priv.height - pos - 1, scrcol,			(row ?  ACS_DARROW : ' ') | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));	/* If there's a search-text, show it in the bottom of the tree */	if (tree->search && tree->search->len > 0) {		const char *str = gnt_util_onscreen_width_to_pointer(tree->search->str, scrcol - 1, NULL);		wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));		mvwaddnstr(widget->window, widget->priv.height - pos - 1, pos,				tree->search->str, str - tree->search->str);	}	gnt_widget_queue_update(widget);}static voidgnt_tree_draw(GntWidget *widget){	GntTree *tree = GNT_TREE(widget);	redraw_tree(tree);		GNTDEBUG;}static voidgnt_tree_size_request(GntWidget *widget){	if (widget->priv.height == 0)		widget->priv.height = 10;	/* XXX: Why?! */	if (widget->priv.width == 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -