Mercurial > pidgin.yaz
diff finch/libgnt/gntentry.c @ 15818:0e3a8505ebbe
renamed gaim-text to finch
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sun, 18 Mar 2007 19:38:15 +0000 |
parents | |
children | efbced3f38ac |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/libgnt/gntentry.c Sun Mar 18 19:38:15 2007 +0000 @@ -0,0 +1,932 @@ +#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 void gnt_entry_set_text_internal(GntEntry *entry, const char *text); + +static void +destroy_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 gboolean +show_suggest_dropdown(GntEntry *entry) +{ + char *suggest = NULL; + int len; + int offset = 0, x, y; + int count = 0; + GList *iter; + + 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) + { + const char *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++; + } + } + g_free(suggest); + + if (count == 0) + { + destroy_suggest(entry); + return FALSE; + } + + gnt_widget_draw(entry->ddown->parent); + return TRUE; +} + +static void +gnt_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 void +gnt_entry_size_request(GntWidget *widget) +{ + if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) + { + 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); + GNTDEBUG; +} + +static void +entry_redraw(GntWidget *widget) +{ + gnt_entry_draw(widget); + gnt_widget_queue_update(widget); +} + +static void +entry_text_changed(GntEntry *entry) +{ + g_signal_emit(entry, signals[SIG_TEXT_CHANGED], 0); +} + +static gboolean +move_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 gboolean +move_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 gboolean +backspace(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 gboolean +delkey(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 gboolean +move_start(GntBindable *bind, GList *null) +{ + GntEntry *entry = GNT_ENTRY(bind); + entry->scroll = entry->cursor = entry->start; + entry_redraw(GNT_WIDGET(entry)); + return TRUE; +} + +static gboolean +move_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 gboolean +history_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 gboolean +history_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 gboolean +clipboard_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 gboolean +suggest_show(GntBindable *bind, GList *null) +{ + return show_suggest_dropdown(GNT_ENTRY(bind)); +} + +static gboolean +suggest_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 gboolean +suggest_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 gboolean +del_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 gboolean +del_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 SAME +static gboolean +move_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 gboolean +del_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; + + if (iter < entry->start) + return TRUE; + iter = (char*)begin_word(iter, entry->start); + count = entry->cursor - iter; + memmove(iter, entry->cursor, entry->end - entry->cursor); + entry->end -= count; + entry->cursor = iter; + if (entry->cursor <= entry->scroll) { + entry->scroll = entry->cursor - widget->priv.width + 2; + if (entry->scroll < entry->start) + entry->scroll = entry->start; + } + memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); + entry_redraw(widget); + entry_text_changed(entry); + + return TRUE; +} + +static gboolean +move_forward_word(GntBindable *bind, GList *list) +{ + GntEntry *entry = GNT_ENTRY(bind); + GntWidget *widget = GNT_WIDGET(bind); + entry->cursor = (char *)next_begin_word(entry->cursor, entry->end); + while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) { + entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); + } + entry_redraw(widget); + return TRUE; +} + +static gboolean +delete_forward_word(GntBindable *bind, GList *list) +{ + GntEntry *entry = GNT_ENTRY(bind); + GntWidget *widget = GNT_WIDGET(bind); + char *iter = (char *)next_begin_word(entry->cursor, entry->end); + int len = entry->end - iter + 1; + if (len <= 0) + return TRUE; + memmove(entry->cursor, iter, len); + len = iter - entry->cursor; + entry->end -= len; + memset(entry->end, '\0', len); + entry_redraw(widget); + entry_text_changed(entry); + return TRUE; +} + +static gboolean +gnt_entry_key_pressed(GntWidget *widget, const char *text) +{ + GntEntry *entry = GNT_ENTRY(widget); + + if (text[0] == 27) + { + if (text[1] == 0) + { + destroy_suggest(entry); + return TRUE; + } + + return FALSE; + } + else + { + if (text[0] == '\t') + { + if (entry->ddown) + destroy_suggest(entry); + else if (entry->suggests) + return show_suggest_dropdown(entry); + + return FALSE; + } + else if (text[0] == '\r' && entry->ddown) + { + char *text = g_strdup(gnt_tree_get_selection_data(GNT_TREE(entry->ddown))); + destroy_suggest(entry); + if (entry->word) + { + char *s = get_beginning_of_word(entry); + char *iter = text; + while (*iter && toupper(*s) == toupper(*iter)) + { + *s++ = *iter++; + } + gnt_entry_key_pressed(widget, iter); + } + else + { + gnt_entry_set_text_internal(entry, text); + } + g_free(text); + entry_text_changed(entry); + return TRUE; + } + + if (!iscntrl(text[0])) + { + const char *str, *next; + + for (str = text; *str; str = next) + { + int len; + next = g_utf8_find_next_char(str, NULL); + len = next - str; + + /* Valid input? */ + /* XXX: Is it necessary to use _unichar_ variants here? */ + if (ispunct(*str) && (entry->flag & GNT_ENTRY_FLAG_NO_PUNCT)) + continue; + if (isspace(*str) && (entry->flag & GNT_ENTRY_FLAG_NO_SPACE)) + continue; + if (isalpha(*str) && !(entry->flag & GNT_ENTRY_FLAG_ALPHA)) + continue; + if (isdigit(*str) && !(entry->flag & GNT_ENTRY_FLAG_INT)) + continue; + + /* Reached the max? */ + if (entry->max && g_utf8_pointer_to_offset(entry->start, entry->end) >= entry->max) + continue; + + if (entry->end + len - entry->start >= entry->buffer) + { + /* This will cause the buffer to grow */ + char *tmp = g_strdup(entry->start); + gnt_entry_set_text_internal(entry, tmp); + g_free(tmp); + } + + memmove(entry->cursor + len, entry->cursor, entry->end - entry->cursor + 1); + entry->end += len; + + while (str < next) + { + if (*str == '\r' || *str == '\n') + *entry->cursor = ' '; + else + *entry->cursor = *str; + entry->cursor++; + str++; + } + + while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) + entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); + + if (entry->ddown) + show_suggest_dropdown(entry); + } + entry_redraw(widget); + entry_text_changed(entry); + return TRUE; + } + } + + return FALSE; +} + +static void +gnt_entry_destroy(GntWidget *widget) +{ + GntEntry *entry = GNT_ENTRY(widget); + g_free(entry->start); + + if (entry->history) + { + entry->history = g_list_first(entry->history); + g_list_foreach(entry->history, (GFunc)g_free, NULL); + g_list_free(entry->history); + } + + if (entry->suggests) + { + g_list_foreach(entry->suggests, (GFunc)g_free, NULL); + g_list_free(entry->suggests); + } + + if (entry->ddown) + { + gnt_widget_destroy(entry->ddown->parent); + } +} + +static void +gnt_entry_lost_focus(GntWidget *widget) +{ + GntEntry *entry = GNT_ENTRY(widget); + destroy_suggest(entry); + entry_redraw(widget); +} + +static void +gnt_entry_class_init(GntEntryClass *klass) +{ + GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); + char s[2] = {erasechar(), 0}; + + 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; + parent_class->lost_focus = gnt_entry_lost_focus; + + signals[SIG_TEXT_CHANGED] = + g_signal_new("text_changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GntEntryClass, text_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + gnt_bindable_class_register_action(bindable, "cursor-home", move_start, + GNT_KEY_CTRL_A, NULL); + gnt_bindable_register_binding(bindable, "cursor-home", GNT_KEY_HOME, NULL); + gnt_bindable_class_register_action(bindable, "cursor-end", move_end, + GNT_KEY_CTRL_E, NULL); + gnt_bindable_register_binding(bindable, "cursor-end", GNT_KEY_END, NULL); + gnt_bindable_class_register_action(bindable, "delete-prev", backspace, + GNT_KEY_BACKSPACE, NULL); + gnt_bindable_register_binding(bindable, "delete-prev", s, NULL); + gnt_bindable_register_binding(bindable, "delete-prev", GNT_KEY_CTRL_H, NULL); + gnt_bindable_class_register_action(bindable, "delete-next", delkey, + GNT_KEY_DEL, NULL); + gnt_bindable_register_binding(bindable, "delete-next", GNT_KEY_CTRL_D, NULL); + gnt_bindable_class_register_action(bindable, "delete-start", del_to_home, + GNT_KEY_CTRL_U, NULL); + gnt_bindable_class_register_action(bindable, "delete-end", del_to_end, + GNT_KEY_CTRL_K, NULL); + gnt_bindable_class_register_action(bindable, "delete-prev-word", del_prev_word, + GNT_KEY_CTRL_W, NULL); + gnt_bindable_class_register_action(bindable, "cursor-prev-word", move_back_word, + "\033" "b", NULL); + gnt_bindable_class_register_action(bindable, "cursor-prev", move_back, + GNT_KEY_LEFT, NULL); + gnt_bindable_register_binding(bindable, "cursor-prev", GNT_KEY_CTRL_B, NULL); + gnt_bindable_class_register_action(bindable, "cursor-next", move_forward, + GNT_KEY_RIGHT, NULL); + gnt_bindable_register_binding(bindable, "cursor-next", GNT_KEY_CTRL_F, NULL); + gnt_bindable_class_register_action(bindable, "cursor-next-word", move_forward_word, + "\033" "f", NULL); + gnt_bindable_class_register_action(bindable, "delete-next-word", delete_forward_word, + "\033" "d", NULL); + gnt_bindable_class_register_action(bindable, "suggest-show", suggest_show, + "\t", NULL); + gnt_bindable_class_register_action(bindable, "suggest-next", suggest_next, + GNT_KEY_DOWN, NULL); + gnt_bindable_class_register_action(bindable, "suggest-prev", suggest_prev, + GNT_KEY_UP, NULL); + gnt_bindable_class_register_action(bindable, "history-prev", history_prev, + GNT_KEY_CTRL_DOWN, NULL); + gnt_bindable_class_register_action(bindable, "history-next", history_next, + GNT_KEY_CTRL_UP, NULL); + gnt_bindable_class_register_action(bindable, "clipboard-paste", clipboard_paste, + GNT_KEY_CTRL_V, NULL); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); + GNTDEBUG; +} + +static void +gnt_entry_init(GTypeInstance *instance, gpointer class) +{ + GntWidget *widget = GNT_WIDGET(instance); + GntEntry *entry = GNT_ENTRY(instance); + + entry->flag = GNT_ENTRY_FLAG_ALL; + entry->max = 0; + + entry->histlength = 0; + entry->history = NULL; + + entry->word = TRUE; + entry->always = FALSE; + entry->suggests = NULL; + + GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), + GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS); + GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), GNT_WIDGET_GROW_X); + + widget->priv.minw = 3; + widget->priv.minh = 1; + + GNTDEBUG; +} + +/****************************************************************************** + * 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 */ + NULL /* value_table */ + }; + + 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_internal(entry, text); + + return widget; +} + +static void +gnt_entry_set_text_internal(GntEntry *entry, const char *text) +{ + int len; + int scroll, cursor; + + g_free(entry->start); + + if (text && text[0]) + { + len = strlen(text); + } + else + { + len = 0; + } + + entry->buffer = len + 128; + + 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; + + if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry), GNT_WIDGET_MAPPED)) + entry_redraw(GNT_WIDGET(entry)); +} + +void gnt_entry_set_text(GntEntry *entry, const char *text) +{ + gboolean changed = TRUE; + if (text == NULL && entry->start == NULL) + changed = FALSE; + if (text && entry->start && g_utf8_collate(text, entry->start) == 0) + changed = FALSE; + gnt_entry_set_text_internal(entry, text); + if (changed) + entry_text_changed(entry); +} + +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? */ +} + +const char *gnt_entry_get_text(GntEntry *entry) +{ + return entry->start; +} + +void gnt_entry_clear(GntEntry *entry) +{ + gnt_entry_set_text_internal(entry, NULL); + entry->scroll = entry->cursor = entry->end = entry->start; + entry_redraw(GNT_WIDGET(entry)); + destroy_suggest(entry); + entry_text_changed(entry); +} + +void gnt_entry_set_masked(GntEntry *entry, gboolean set) +{ + entry->masked = set; +} + +void gnt_entry_add_to_history(GntEntry *entry, const char *text) +{ + g_return_if_fail(entry->history != NULL); /* Need to set_history_length first */ + + if (g_list_length(entry->history) >= entry->histlength) + return; + + entry->history = g_list_first(entry->history); + g_free(entry->history->data); + entry->history->data = g_strdup(text); + entry->history = g_list_prepend(entry->history, NULL); +} + +void gnt_entry_set_history_length(GntEntry *entry, int num) +{ + if (num == 0) + { + entry->histlength = num; + if (entry->history) + { + entry->history = g_list_first(entry->history); + g_list_foreach(entry->history, (GFunc)g_free, NULL); + g_list_free(entry->history); + entry->history = NULL; + } + return; + } + + if (entry->histlength == 0) + { + entry->histlength = num; + entry->history = g_list_append(NULL, NULL); + return; + } + + if (num > 0 && num < entry->histlength) + { + GList *first, *iter; + int index = 0; + for (first = entry->history, index = 0; first->prev; first = first->prev, index++); + while ((iter = g_list_nth(first, num)) != NULL) + { + g_free(iter->data); + first = g_list_delete_link(first, iter); + } + entry->histlength = num; + if (index >= num) + entry->history = g_list_last(first); + return; + } + + entry->histlength = num; +} + +void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word) +{ + entry->word = word; +} + +void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always) +{ + entry->always = always; +} + +void gnt_entry_add_suggest(GntEntry *entry, const char *text) +{ + GList *find; + + if (!text || !*text) + return; + + find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); + if (find) + return; + entry->suggests = g_list_append(entry->suggests, g_strdup(text)); +} + +void gnt_entry_remove_suggest(GntEntry *entry, const char *text) +{ + GList *find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); + if (find) + { + g_free(find->data); + entry->suggests = g_list_delete_link(entry->suggests, find); + } +} +