📄 gnttextview.c
字号:
parent_class->draw = gnt_text_view_draw; parent_class->map = gnt_text_view_map; parent_class->size_request = gnt_text_view_size_request; parent_class->key_pressed = gnt_text_view_key_pressed; parent_class->clicked = gnt_text_view_clicked; parent_class->size_changed = gnt_text_view_size_changed; GNTDEBUG;}static voidgnt_text_view_init(GTypeInstance *instance, gpointer class){ GntWidget *widget = GNT_WIDGET(instance); GNT_WIDGET_SET_FLAGS(GNT_WIDGET(instance), GNT_WIDGET_GROW_Y | GNT_WIDGET_GROW_X); widget->priv.minw = 5; widget->priv.minh = 2; GNTDEBUG;}/****************************************************************************** * GntTextView API *****************************************************************************/GTypegnt_text_view_get_gtype(void){ static GType type = 0; if(type == 0) { static const GTypeInfo info = { sizeof(GntTextViewClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc)gnt_text_view_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof(GntTextView), 0, /* n_preallocs */ gnt_text_view_init, /* instance_init */ NULL /* value_table */ }; type = g_type_register_static(GNT_TYPE_WIDGET, "GntTextView", &info, 0); } return type;}GntWidget *gnt_text_view_new(){ GntWidget *widget = g_object_new(GNT_TYPE_TEXT_VIEW, NULL); GntTextView *view = GNT_TEXT_VIEW(widget); GntTextLine *line = g_new0(GntTextLine, 1); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); view->string = g_string_new(NULL); view->list = g_list_append(view->list, line); return widget;}void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags){ gnt_text_view_append_text_with_tag(view, text, flags, NULL);}void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text, GntTextFormatFlags flags, const char *tagname){ GntWidget *widget = GNT_WIDGET(view); int fl = 0; const char *start, *end; GList *list = view->list; GntTextLine *line; int len; if (text == NULL || *text == '\0') return; fl = gnt_text_format_flag_to_chtype(flags); len = view->string->len; view->string = g_string_append(view->string, text); if (tagname) { GntTextTag *tag = g_new0(GntTextTag, 1); tag->name = g_strdup(tagname); tag->start = len; tag->end = view->string->len; view->tags = g_list_append(view->tags, tag); } view->list = g_list_first(view->list); start = end = view->string->str + len; while (*start) { GntTextLine *oldl; GntTextSegment *seg = NULL; if (*end == '\n' || *end == '\r') { if (!strncmp(end, "\r\n", 2)) end++; end++; start = end; gnt_text_view_next_line(view); view->list = g_list_first(view->list); continue; } line = view->list->data; if (line->length == widget->priv.width - 1) { /* The last added line was exactly the same width as the widget */ line = g_new0(GntTextLine, 1); line->soft = TRUE; view->list = g_list_prepend(view->list, line); } if ((end = strchr(start, '\r')) != NULL || (end = strchr(start, '\n')) != NULL) { len = gnt_util_onscreen_width(start, end - 1); if (len >= widget->priv.width - line->length - 1) { end = NULL; } } if (end == NULL) end = gnt_util_onscreen_width_to_pointer(start, widget->priv.width - line->length - 1, &len); /* Try to append to the previous segment if possible */ if (line->segments) { seg = g_list_last(line->segments)->data; if (seg->flags != fl) seg = NULL; } if (seg == NULL) { seg = g_new0(GntTextSegment, 1); seg->start = start - view->string->str; seg->tvflag = flags; seg->flags = fl; line->segments = g_list_append(line->segments, seg); } oldl = line; if (*end && *end != '\n' && *end != '\r') { const char *tmp = end; while (end && *end != '\n' && *end != '\r' && !g_ascii_isspace(*end)) { end = g_utf8_find_prev_char(seg->start + view->string->str, end); } if (!end || !g_ascii_isspace(*end)) end = tmp; else end++; /* Remove the space */ line = g_new0(GntTextLine, 1); line->soft = TRUE; view->list = g_list_prepend(view->list, line); } seg->end = end - view->string->str; oldl->length += len; start = end; } view->list = list; gnt_widget_draw(widget);}void gnt_text_view_scroll(GntTextView *view, int scroll){ if (scroll == 0) { view->list = g_list_first(view->list); } else if (scroll > 0) { GList *list = g_list_nth_prev(view->list, scroll); if (list == NULL) list = g_list_first(view->list); view->list = list; } else if (scroll < 0) { GList *list = g_list_nth(view->list, -scroll); if (list == NULL) list = g_list_last(view->list); view->list = list; } gnt_widget_draw(GNT_WIDGET(view));}void gnt_text_view_next_line(GntTextView *view){ GntTextLine *line = g_new0(GntTextLine, 1); GList *list = view->list; view->list = g_list_prepend(g_list_first(view->list), line); view->list = list; gnt_widget_draw(GNT_WIDGET(view));}chtype gnt_text_format_flag_to_chtype(GntTextFormatFlags flags){ chtype fl = 0; if (flags & GNT_TEXT_FLAG_BOLD) fl |= A_BOLD; if (flags & GNT_TEXT_FLAG_UNDERLINE) fl |= A_UNDERLINE; if (flags & GNT_TEXT_FLAG_BLINK) fl |= A_BLINK; if (flags & GNT_TEXT_FLAG_DIM) fl |= (A_DIM | COLOR_PAIR(GNT_COLOR_DISABLED)); else if (flags & GNT_TEXT_FLAG_HIGHLIGHT) fl |= (A_DIM | COLOR_PAIR(GNT_COLOR_HIGHLIGHT)); else fl |= COLOR_PAIR(GNT_COLOR_NORMAL); return fl;}void gnt_text_view_clear(GntTextView *view){ GntTextLine *line; g_list_foreach(view->list, free_text_line, NULL); g_list_free(view->list); view->list = NULL; line = g_new0(GntTextLine, 1); view->list = g_list_append(view->list, line); if (view->string) g_string_free(view->string, TRUE); view->string = g_string_new(NULL); if (GNT_WIDGET(view)->window) gnt_widget_draw(GNT_WIDGET(view));}int gnt_text_view_get_lines_below(GntTextView *view){ int below = 0; GList *list = view->list; while ((list = list->prev)) ++below; return below;}int gnt_text_view_get_lines_above(GntTextView *view){ int above = 0; GList *list = view->list; list = g_list_nth(view->list, GNT_WIDGET(view)->priv.height); if (!list) return 0; while ((list = list->next)) ++above; return above;}/** * XXX: There are quite possibly more than a few bugs here. */int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all){ GList *alllines = g_list_first(view->list); GList *list, *next, *iter, *inext; const int text_length = text ? strlen(text) : 0; int count = 0; for (list = view->tags; list; list = next) { GntTextTag *tag = list->data; next = list->next; if (strcmp(tag->name, name) == 0) { int change; char *before, *after; count++; before = g_strndup(view->string->str, tag->start); after = g_strdup(view->string->str + tag->end); change = (tag->end - tag->start) - text_length; g_string_printf(view->string, "%s%s%s", before, text ? text : "", after); g_free(before); g_free(after); /* Update the offsets of the next tags */ for (iter = next; iter; iter = iter->next) { GntTextTag *t = iter->data; t->start -= change; t->end -= change; } /* Update the offsets of the segments */ for (iter = alllines; iter; iter = inext) { GList *segs, *snext; GntTextLine *line = iter->data; inext = iter->next; for (segs = line->segments; segs; segs = snext) { GntTextSegment *seg = segs->data; snext = segs->next; if (seg->start >= tag->end) { /* The segment is somewhere after the tag */ seg->start -= change; seg->end -= change; } else if (seg->end <= tag->start) { /* This segment is somewhere in front of the tag */ } else if (seg->start >= tag->start) { /* This segment starts in the middle of the tag */ if (text == NULL) { free_text_segment(seg, NULL); line->segments = g_list_delete_link(line->segments, segs); if (line->segments == NULL) { free_text_line(line, NULL); if (view->list == iter) { if (inext) view->list = inext; else view->list = iter->prev; } alllines = g_list_delete_link(alllines, iter); } } else { /* XXX: (null) */ seg->start = tag->start; seg->end = tag->end - change; } line->length -= change; /* XXX: Make things work if the tagged text spans over several lines. */ } else { /* XXX: handle the rest of the conditions */ g_printerr("WTF! This needs to be handled properly!!\n"); } } } if (text == NULL) { /* Remove the tag */ view->tags = g_list_delete_link(view->tags, list); free_tag(tag, NULL); } else { tag->end -= change; } if (!all) break; } } return count;}static gbooleanscroll_tv(GntWidget *wid, const char *key, GntTextView *tv){ if (strcmp(key, GNT_KEY_PGUP) == 0) { gnt_text_view_scroll(tv, -(GNT_WIDGET(tv)->priv.height - 2)); } else if (strcmp(key, GNT_KEY_PGDOWN) == 0) { gnt_text_view_scroll(tv, GNT_WIDGET(tv)->priv.height - 2); } else if (strcmp(key, GNT_KEY_DOWN) == 0) { gnt_text_view_scroll(tv, 1); } else if (strcmp(key, GNT_KEY_UP) == 0) { gnt_text_view_scroll(tv, -1); } else { return FALSE; } return TRUE;}void gnt_text_view_attach_scroll_widget(GntTextView *view, GntWidget *widget){ g_signal_connect(G_OBJECT(widget), "key_pressed", G_CALLBACK(scroll_tv), view);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -