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

📄 gnttextview.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "gnttextview.h"#include "gntutils.h"#include <string.h>enum{	SIGS = 1,};typedef struct{	GntTextFormatFlags tvflag;	chtype flags;	int start;	int end;     /* This is the next byte of the last character of this segment */} GntTextSegment;typedef struct{	GList *segments;         /* A list of GntTextSegments */	int length;              /* The current length of the line so far (ie. onscreen width) */	gboolean soft;           /* TRUE if it's an overflow from prev. line */} GntTextLine;typedef struct{	char *name;	int start;	int end;} GntTextTag;static GntWidgetClass *parent_class = NULL;static gchar *select_start;static gchar *select_end;static gboolean double_click;static voidgnt_text_view_draw(GntWidget *widget){	GntTextView *view = GNT_TEXT_VIEW(widget);	int i = 0;	GList *lines;	int rows, scrcol;	wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL));	werase(widget->window);	for (i = 0, lines = view->list; i < widget->priv.height && lines; i++, lines = lines->next)	{		GList *iter;		GntTextLine *line = lines->data;		wmove(widget->window, widget->priv.height - 1 - i, 0);		for (iter = line->segments; iter; iter = iter->next)		{			GntTextSegment *seg = iter->data;			char *end = view->string->str + seg->end;			char back = *end;			chtype fl = seg->flags;			*end = '\0';			if (select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) {				fl |= A_REVERSE;				wattrset(widget->window, fl);				wprintw(widget->window, "%s", (view->string->str + seg->start));			} else if (select_start && select_end &&				((select_start >= view->string->str + seg->start && select_start <= view->string->str + seg->end) ||				(select_end <= view->string->str + seg->end && select_start <= view->string->str + seg->start))) {				char *cur = view->string->str + seg->start;				while (*cur != '\0') {					gchar *last = g_utf8_next_char(cur);					gchar *str;					if (cur >= select_start && cur <= select_end)						fl |= A_REVERSE;					else						fl = seg->flags;					str = g_strndup(cur, last - cur);					wattrset(widget->window, fl);					waddstr(widget->window, str);					g_free(str);					cur = g_utf8_next_char(cur);				}			} else {				wattrset(widget->window, fl);				wprintw(widget->window, "%s", (view->string->str + seg->start));			}			*end = back;		}		wattroff(widget->window, A_UNDERLINE | A_BLINK | A_REVERSE);		whline(widget->window, ' ', widget->priv.width - line->length - 1);	}	scrcol = widget->priv.width - 1;	rows = widget->priv.height - 2;	if (rows > 0)	{		int total = g_list_length(g_list_first(view->list));		int showing, position, up, down;		showing = rows * rows / total + 1;		showing = MIN(rows, showing);		total -= rows;		up = g_list_length(lines);		down = total - up;		position = (rows - showing) * up / MAX(1, up + down);		position = MAX((lines != NULL), position);		if (showing + position > rows)			position = rows - showing;				if (showing + position == rows && view->list && view->list->prev)			position = MAX(1, rows - 1 - showing);		else if (showing + position < rows && view->list && !view->list->prev)			position = rows - showing;		mvwvline(widget->window, position + 1, scrcol,				ACS_CKBOARD | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D), showing);	}	mvwaddch(widget->window, 0, scrcol,			(lines ? ACS_UARROW : ' ') | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));	mvwaddch(widget->window, widget->priv.height - 1, scrcol,			((view->list && view->list->prev) ? ACS_DARROW : ' ') |				COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));	GNTDEBUG;}static voidgnt_text_view_size_request(GntWidget *widget){	if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED))	{		gnt_widget_set_size(widget, 64, 20);	}}static voidgnt_text_view_map(GntWidget *widget){	if (widget->priv.width == 0 || widget->priv.height == 0)		gnt_widget_size_request(widget);	GNTDEBUG;}static gbooleangnt_text_view_key_pressed(GntWidget *widget, const char *text){	return FALSE;}static voidfree_text_segment(gpointer data, gpointer null){	GntTextSegment *seg = data;	g_free(seg);}static voidfree_text_line(gpointer data, gpointer null){	GntTextLine *line = data;	g_list_foreach(line->segments, free_text_segment, NULL);	g_list_free(line->segments);	g_free(line);}static voidfree_tag(gpointer data, gpointer null){	GntTextTag *tag = data;	g_free(tag->name);	g_free(tag);}static voidgnt_text_view_destroy(GntWidget *widget){	GntTextView *view = GNT_TEXT_VIEW(widget);	view->list = g_list_first(view->list);	g_list_foreach(view->list, free_text_line, NULL);	g_list_free(view->list);	g_list_foreach(view->tags, free_tag, NULL);	g_list_free(view->tags);	g_string_free(view->string, TRUE);}static char *gnt_text_view_get_p(GntTextView *view, int x, int y){	int i = 0;	GntWidget *wid = GNT_WIDGET(view);	GntTextLine *line;	GList *lines;	GList *segs;	GntTextSegment *seg;	gchar *pos;	y = wid->priv.height - y;	if (g_list_length(view->list) < y) {		x = 0;		y = g_list_length(view->list) - 1;	}	lines = g_list_nth(view->list, y - 1);	if (!lines)		return NULL;	do {		line = lines->data;		lines = lines->next;	} while (line && !line->segments && lines);	if (!line || !line->segments) /* no valid line */		return NULL;	segs = line->segments;	seg = (GntTextSegment *)segs->data;	pos = view->string->str + seg->start;	x = MIN(x, line->length);	while (++i <= x) {		gunichar *u;		pos = g_utf8_next_char(pos);		u = g_utf8_to_ucs4(pos, -1, NULL, NULL, NULL);		if (u && g_unichar_iswide(*u))			i++;		g_free(u);	}	return pos;}static GString *select_word_text(GntTextView *view, gchar *c){	gchar *start = c;	gchar *end = c;	gchar *t, *endsize;	while ((t = g_utf8_prev_char(start))) {		if (!g_ascii_isspace(*t)) {			if (start == view->string->str)				break;			start = t;		} else			break;	}	while ((t = g_utf8_next_char(end))) {		if (!g_ascii_isspace(*t))			end = t;		else			break;	}	select_start = start;	select_end = end;	endsize = g_utf8_next_char(select_end); /* End at the correct byte */	return g_string_new_len(start, endsize - start);}static gboolean too_slow(gpointer n){	double_click = FALSE;	return FALSE;}static gbooleangnt_text_view_clicked(GntWidget *widget, GntMouseEvent event, int x, int y){	if (event == GNT_MOUSE_SCROLL_UP) {		gnt_text_view_scroll(GNT_TEXT_VIEW(widget), -1);	} else if (event == GNT_MOUSE_SCROLL_DOWN) {		gnt_text_view_scroll(GNT_TEXT_VIEW(widget), 1);	} else if (event == GNT_LEFT_MOUSE_DOWN) {		select_start = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y);		g_timeout_add(500, too_slow, NULL);	} else if (event == GNT_MOUSE_UP) {		if (select_start) {			GString *clip;			select_end = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y);			if (select_end < select_start) {				gchar *t = select_start;				select_start = select_end;				select_end = t;			}			if (select_start == select_end) {				if (double_click) {					clip = select_word_text(GNT_TEXT_VIEW(widget), select_start);					double_click = FALSE;				} else {					double_click = TRUE;					select_start = 0;					select_end = 0;					gnt_widget_draw(widget);					return TRUE;				}			} else {				gchar *endsize = g_utf8_next_char(select_end); /* End at the correct byte */				clip = g_string_new_len(select_start, endsize - select_start);			}			gnt_widget_draw(widget);			gnt_set_clipboard_string(clip->str);			g_string_free(clip, TRUE);		}	} else		return FALSE;	return TRUE;}static voidgnt_text_view_reflow(GntTextView *view){	/* This is pretty ugly, and inefficient. Someone do something about it. */	GntTextLine *line;	GList *back, *iter, *list;	GString *string;	int pos = 0;    /* no. of 'real' lines */	list = view->list;	while (list->prev) {		line = list->data;		if (!line->soft)			pos++;		list = list->prev;	}	back = g_list_last(view->list);	view->list = NULL;	string = view->string;	view->string = NULL;	gnt_text_view_clear(view);	view->string = g_string_set_size(view->string, string->len);	view->string->len = 0;	GNT_WIDGET_SET_FLAGS(GNT_WIDGET(view), GNT_WIDGET_DRAWING);	for (; back; back = back->prev) {		line = back->data;		if (back->next && !line->soft) {			gnt_text_view_append_text_with_flags(view, "\n", GNT_TEXT_FLAG_NORMAL);		}		for (iter = line->segments; iter; iter = iter->next) {			GntTextSegment *seg = iter->data;			char *start = string->str + seg->start;			char *end = string->str + seg->end;			char back = *end;			*end = '\0';			gnt_text_view_append_text_with_flags(view, start, seg->tvflag);			*end = back;		}		free_text_line(line, NULL);	}	g_list_free(list);	list = view->list = g_list_first(view->list);	/* Go back to the line that was in view before resizing started */	while (pos--) {		while (((GntTextLine*)list->data)->soft)			list = list->next;		list = list->next;	}	view->list = list;	GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(view), GNT_WIDGET_DRAWING);	if (GNT_WIDGET(view)->window)		gnt_widget_draw(GNT_WIDGET(view));	g_string_free(string, TRUE);}static voidgnt_text_view_size_changed(GntWidget *widget, int w, int h){	if (w != widget->priv.width) {		gnt_text_view_reflow(GNT_TEXT_VIEW(widget));	}}static voidgnt_text_view_class_init(GntTextViewClass *klass){	parent_class = GNT_WIDGET_CLASS(klass);	parent_class->destroy = gnt_text_view_destroy;

⌨️ 快捷键说明

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