📄 gntentry.c
字号:
#include <ctype.h>#include <string.h>#include "gntbox.h"#include "gntentry.h"#include "gntstyle.h"#include "gnttree.h"#include "gntutils.h"enum{ SIG_TEXT_CHANGED, SIGS,};static guint signals[SIGS] = { 0 };static GntWidgetClass *parent_class = NULL;static gboolean gnt_entry_key_pressed(GntWidget *widget, const char *text);static void gnt_entry_set_text_internal(GntEntry *entry, const char *text);static voiddestroy_suggest(GntEntry *entry){ if (entry->ddown) { gnt_widget_destroy(entry->ddown->parent); entry->ddown = NULL; }}static char *get_beginning_of_word(GntEntry *entry){ char *s = entry->cursor; while (s > entry->start) { char *t = g_utf8_find_prev_char(entry->start, s); if (isspace(*t)) break; s = t; } return s;}static gbooleancomplete_suggest(GntEntry *entry, const char *text){ gboolean changed = FALSE; if (entry->word) { char *s = get_beginning_of_word(entry); const char *iter = text; while (*iter && toupper(*s) == toupper(*iter)) { if (*s != *iter) changed = TRUE; *s++ = *iter++; } if (*iter) { gnt_entry_key_pressed(GNT_WIDGET(entry), iter); changed = TRUE; } } else { gnt_entry_set_text_internal(entry, text); changed = TRUE; } return changed;}static gbooleanshow_suggest_dropdown(GntEntry *entry){ char *suggest = NULL; int len; int offset = 0, x, y; int count = 0; GList *iter; const char *text = NULL; const char *sgst = NULL; if (entry->word) { char *s = get_beginning_of_word(entry); suggest = g_strndup(s, entry->cursor - s); if (entry->scroll < s) offset = gnt_util_onscreen_width(entry->scroll, s); } else suggest = g_strdup(entry->start); len = strlen(suggest); /* Don't need to use the utf8-function here */ if (entry->ddown == NULL) { GntWidget *box = gnt_vbox_new(FALSE); entry->ddown = gnt_tree_new(); gnt_tree_set_compare_func(GNT_TREE(entry->ddown), (GCompareFunc)g_utf8_collate); gnt_box_add_widget(GNT_BOX(box), entry->ddown); /* XXX: Connect to the "activate" signal for the dropdown tree */ GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); gnt_widget_get_position(GNT_WIDGET(entry), &x, &y); x += offset; y++; if (y + 10 >= getmaxy(stdscr)) y -= 11; gnt_widget_set_position(box, x, y); } else gnt_tree_remove_all(GNT_TREE(entry->ddown)); for (count = 0, iter = entry->suggests; iter; iter = iter->next) { text = iter->data; if (g_ascii_strncasecmp(suggest, text, len) == 0 && strlen(text) >= len) { gnt_tree_add_row_after(GNT_TREE(entry->ddown), (gpointer)text, gnt_tree_create_row(GNT_TREE(entry->ddown), text), NULL, NULL); count++; sgst = text; } } g_free(suggest); if (count == 0) { destroy_suggest(entry); return FALSE; } else if (count == 1) { destroy_suggest(entry); return complete_suggest(entry, sgst); } else { gnt_widget_draw(entry->ddown->parent); } return TRUE;}static voidgnt_entry_draw(GntWidget *widget){ GntEntry *entry = GNT_ENTRY(widget); int stop; gboolean focus; if ((focus = gnt_widget_has_focus(widget))) wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TEXT_NORMAL)); else wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); if (entry->masked) { mvwhline(widget->window, 0, 0, gnt_ascii_only() ? '*' : ACS_BULLET, g_utf8_pointer_to_offset(entry->scroll, entry->end)); } else mvwprintw(widget->window, 0, 0, "%s", entry->scroll); stop = gnt_util_onscreen_width(entry->scroll, entry->end); if (stop < widget->priv.width) whline(widget->window, ENTRY_CHAR, widget->priv.width - stop); if (focus) mvwchgat(widget->window, 0, gnt_util_onscreen_width(entry->scroll, entry->cursor), 1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL); GNTDEBUG;}static voidgnt_entry_size_request(GntWidget *widget){ if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) { widget->priv.height = 1; widget->priv.width = 20; }}static voidgnt_entry_map(GntWidget *widget){ if (widget->priv.width == 0 || widget->priv.height == 0) gnt_widget_size_request(widget); GNTDEBUG;}static voidentry_redraw(GntWidget *widget){ gnt_entry_draw(widget); gnt_widget_queue_update(widget);}static voidentry_text_changed(GntEntry *entry){ g_signal_emit(entry, signals[SIG_TEXT_CHANGED], 0);}static gbooleanmove_back(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); if (entry->cursor <= entry->start) return FALSE; entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor); if (entry->cursor < entry->scroll) entry->scroll = entry->cursor; entry_redraw(GNT_WIDGET(entry)); return TRUE;}static gbooleanmove_forward(GntBindable *bind, GList *list){ GntEntry *entry = GNT_ENTRY(bind); if (entry->cursor >= entry->end) return FALSE; entry->cursor = g_utf8_find_next_char(entry->cursor, NULL); while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); entry_redraw(GNT_WIDGET(entry)); return TRUE;}static gbooleanbackspace(GntBindable *bind, GList *null){ int len; GntEntry *entry = GNT_ENTRY(bind); if (entry->cursor <= entry->start) return TRUE; len = entry->cursor - g_utf8_find_prev_char(entry->start, entry->cursor); entry->cursor -= len; memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor); entry->end -= len; if (entry->scroll > entry->start) entry->scroll = g_utf8_find_prev_char(entry->start, entry->scroll); entry_redraw(GNT_WIDGET(entry)); if (entry->ddown) show_suggest_dropdown(entry); entry_text_changed(entry); return TRUE;}static gbooleandelkey(GntBindable *bind, GList *null){ int len; GntEntry *entry = GNT_ENTRY(bind); if (entry->cursor >= entry->end) return FALSE; len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor; memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1); entry->end -= len; entry_redraw(GNT_WIDGET(entry)); if (entry->ddown) show_suggest_dropdown(entry); entry_text_changed(entry); return TRUE;}static gbooleanmove_start(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); entry->scroll = entry->cursor = entry->start; entry_redraw(GNT_WIDGET(entry)); return TRUE;}static gbooleanmove_end(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); entry->cursor = entry->end; /* This should be better than this */ while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); entry_redraw(GNT_WIDGET(entry)); return TRUE;}static gbooleanhistory_prev(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); if (entry->histlength && entry->history->prev) { entry->history = entry->history->prev; gnt_entry_set_text_internal(entry, entry->history->data); destroy_suggest(entry); entry_text_changed(entry); return TRUE; } return FALSE;}static gbooleanhistory_next(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); if (entry->histlength && entry->history->next) { if (entry->history->prev == NULL) { /* Save the current contents */ char *text = g_strdup(gnt_entry_get_text(entry)); g_free(entry->history->data); entry->history->data = text; } entry->history = entry->history->next; gnt_entry_set_text_internal(entry, entry->history->data); destroy_suggest(entry); entry_text_changed(entry); return TRUE; } return FALSE;}static gbooleanclipboard_paste(GntBindable *bind, GList *n){ GntEntry *entry = GNT_ENTRY(bind); gchar *i, *text, *a, *all; text = i = gnt_get_clipboard_string(); while (*i != '\0') { i = g_utf8_next_char(i); if (*i == '\r' || *i == '\n') *i = ' '; } a = g_strndup(entry->start, entry->cursor - entry->start); all = g_strconcat(a, text, entry->cursor, NULL); gnt_entry_set_text_internal(entry, all); g_free(a); g_free(text); g_free(all); return TRUE;}static gbooleansuggest_show(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); if (entry->ddown) { gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down"); return TRUE; } return show_suggest_dropdown(entry);}static gbooleansuggest_next(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); if (entry->ddown) { gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down", NULL); return TRUE; } return FALSE;}static gbooleansuggest_prev(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); if (entry->ddown) { gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-up", NULL); return TRUE; } return FALSE;}static gbooleandel_to_home(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); if (entry->cursor <= entry->start) return TRUE; memmove(entry->start, entry->cursor, entry->end - entry->cursor); entry->end -= (entry->cursor - entry->start); entry->cursor = entry->scroll = entry->start; memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); entry_redraw(GNT_WIDGET(bind)); entry_text_changed(entry); return TRUE;}static gbooleandel_to_end(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); if (entry->end <= entry->cursor) return TRUE; entry->end = entry->cursor; memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); entry_redraw(GNT_WIDGET(bind)); entry_text_changed(entry); return TRUE;}#define SAME(a,b) ((g_unichar_isalpha(a) && g_unichar_isalpha(b)) || \ (g_unichar_isdigit(a) && g_unichar_isdigit(b)) || \ (g_unichar_isspace(a) && g_unichar_isspace(b)) || \ (g_unichar_iswide(a) && g_unichar_iswide(b)))static const char *begin_word(const char *text, const char *begin){ gunichar ch = 0; while (text > begin && (!*text || g_unichar_isspace(g_utf8_get_char(text)))) text = g_utf8_find_prev_char(begin, text); ch = g_utf8_get_char(text); while ((text = g_utf8_find_prev_char(begin, text)) >= begin) { gunichar cur = g_utf8_get_char(text); if (!SAME(ch, cur)) break; } return (text ? g_utf8_find_next_char(text, NULL) : begin);}static const char *next_begin_word(const char *text, const char *end){ gunichar ch = 0; ch = g_utf8_get_char(text); while ((text = g_utf8_find_next_char(text, end)) != NULL && text <= end) { gunichar cur = g_utf8_get_char(text); if (!SAME(ch, cur)) break; } while (text && text < end && g_unichar_isspace(g_utf8_get_char(text))) text = g_utf8_find_next_char(text, end); return (text ? text : end);}#undef SAMEstatic gbooleanmove_back_word(GntBindable *bind, GList *null){ GntEntry *entry = GNT_ENTRY(bind); const char *iter = g_utf8_find_prev_char(entry->start, entry->cursor); if (iter < entry->start) return TRUE; iter = begin_word(iter, entry->start); entry->cursor = (char*)iter; if (entry->cursor < entry->scroll) entry->scroll = entry->cursor; entry_redraw(GNT_WIDGET(bind)); return TRUE;}static gbooleandel_prev_word(GntBindable *bind, GList *null){ GntWidget *widget = GNT_WIDGET(bind); GntEntry *entry = GNT_ENTRY(bind); char *iter = g_utf8_find_prev_char(entry->start, entry->cursor); int count;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -