2 * GNT - The GLib Ncurses Toolkit
4 * GNT is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
28 #include "gntmarshal.h"
42 ENTRY_JAIL
= -1, /* Suspend the kill ring. */
43 ENTRY_DEL_BWD_WORD
= 1,
51 struct _GntEntryKillRing
57 static guint signals
[SIGS
] = { 0 };
59 static GntWidgetClass
*parent_class
= NULL
;
61 static gboolean
gnt_entry_key_pressed(GntWidget
*widget
, const char *text
);
62 static void gnt_entry_set_text_internal(GntEntry
*entry
, const char *text
);
65 update_kill_ring(GntEntry
*entry
, GntEntryAction action
, const char *text
, int len
)
68 entry
->killring
->last
= action
;
79 if (action
!= entry
->killring
->last
) {
84 {ENTRY_DEL_BWD_WORD
, ENTRY_DEL_FWD_WORD
},
85 {ENTRY_DEL_BWD_CHAR
, ENTRY_DEL_FWD_CHAR
},
86 {ENTRY_DEL_BOL
, ENTRY_DEL_EOL
},
87 {ENTRY_JAIL
, ENTRY_JAIL
},
91 for (i
= 0; merges
[i
].one
!= ENTRY_JAIL
; i
++) {
92 if (merges
[i
].one
== entry
->killring
->last
&&
93 merges
[i
].two
== action
) {
94 g_string_append_len(entry
->killring
->buffer
, text
, len
);
96 } else if (merges
[i
].one
== action
&&
97 merges
[i
].two
== entry
->killring
->last
) {
98 g_string_prepend_len(entry
->killring
->buffer
, text
, len
);
102 if (merges
[i
].one
== ENTRY_JAIL
) {
103 g_string_assign(entry
->killring
->buffer
, text
);
104 g_string_truncate(entry
->killring
->buffer
, len
);
106 entry
->killring
->last
= action
;
108 if (action
== ENTRY_DEL_BWD_CHAR
|| action
== ENTRY_DEL_BWD_WORD
)
109 g_string_prepend_len(entry
->killring
->buffer
, text
, len
);
111 g_string_append_len(entry
->killring
->buffer
, text
, len
);
117 destroy_suggest(GntEntry
*entry
)
121 gnt_widget_destroy(entry
->ddown
->parent
);
127 get_beginning_of_word(GntEntry
*entry
)
129 char *s
= entry
->cursor
;
130 while (s
> entry
->start
)
132 char *t
= g_utf8_find_prev_char(entry
->start
, s
);
141 complete_suggest(GntEntry
*entry
, const char *text
)
143 int offstart
= 0, offend
= 0;
146 char *s
= get_beginning_of_word(entry
);
147 const char *iter
= text
;
148 offstart
= g_utf8_pointer_to_offset(entry
->start
, s
);
149 while (*iter
&& toupper(*s
) == toupper(*iter
)) {
153 gnt_entry_key_pressed(GNT_WIDGET(entry
), iter
);
155 offend
= g_utf8_pointer_to_offset(entry
->start
, entry
->cursor
);
158 gnt_entry_set_text_internal(entry
, text
);
159 offend
= g_utf8_strlen(text
, -1);
162 g_signal_emit(G_OBJECT(entry
), signals
[SIG_COMPLETION
], 0,
163 entry
->start
+ offstart
, entry
->start
+ offend
);
164 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
169 max_common_prefix(const char *s
, const char *t
)
172 while (*f
&& *t
&& *f
== *t
++)
178 show_suggest_dropdown(GntEntry
*entry
)
180 char *suggest
= NULL
;
182 int offset
= 0, x
, y
;
185 const char *text
= NULL
;
186 const char *sgst
= NULL
;
191 char *s
= get_beginning_of_word(entry
);
192 suggest
= g_strndup(s
, entry
->cursor
- s
);
193 if (entry
->scroll
< s
)
194 offset
= gnt_util_onscreen_width(entry
->scroll
, s
);
197 suggest
= g_strdup(entry
->start
);
198 len
= strlen(suggest
); /* Don't need to use the utf8-function here */
200 if (entry
->ddown
== NULL
)
202 GntWidget
*box
= gnt_vbox_new(FALSE
);
203 entry
->ddown
= gnt_tree_new();
204 gnt_tree_set_compare_func(GNT_TREE(entry
->ddown
), (GCompareFunc
)g_utf8_collate
);
205 gnt_box_add_widget(GNT_BOX(box
), entry
->ddown
);
207 GNT_WIDGET_SET_FLAGS(box
, GNT_WIDGET_TRANSIENT
);
209 gnt_widget_get_position(GNT_WIDGET(entry
), &x
, &y
);
212 if (y
+ 10 >= getmaxy(stdscr
))
214 gnt_widget_set_position(box
, x
, y
);
217 gnt_tree_remove_all(GNT_TREE(entry
->ddown
));
219 for (count
= 0, iter
= entry
->suggests
; iter
; iter
= iter
->next
)
222 if (g_ascii_strncasecmp(suggest
, text
, len
) == 0 && strlen(text
) >= len
)
224 gnt_tree_add_row_after(GNT_TREE(entry
->ddown
), (gpointer
)text
,
225 gnt_tree_create_row(GNT_TREE(entry
->ddown
), text
),
229 max
= strlen(text
) - len
;
231 max
= MIN(max
, max_common_prefix(sgst
+ len
, text
+ len
));
238 destroy_suggest(entry
);
240 } else if (count
== 1) {
241 destroy_suggest(entry
);
242 return complete_suggest(entry
, sgst
);
245 GntWidget
*ddown
= entry
->ddown
;
246 char *match
= g_strndup(sgst
+ len
, max
);
248 gnt_entry_key_pressed(GNT_WIDGET(entry
), match
);
251 gnt_widget_destroy(ddown
);
253 entry
->ddown
= ddown
;
255 gnt_widget_draw(entry
->ddown
->parent
);
262 gnt_entry_draw(GntWidget
*widget
)
264 GntEntry
*entry
= GNT_ENTRY(widget
);
268 if ((focus
= gnt_widget_has_focus(widget
)))
269 wbkgdset(widget
->window
, '\0' | gnt_color_pair(GNT_COLOR_TEXT_NORMAL
));
271 wbkgdset(widget
->window
, '\0' | gnt_color_pair(GNT_COLOR_HIGHLIGHT_D
));
275 mvwhline(widget
->window
, 0, 0, gnt_ascii_only() ? '*' : ACS_BULLET
,
276 g_utf8_pointer_to_offset(entry
->scroll
, entry
->end
));
279 mvwprintw(widget
->window
, 0, 0, "%s", entry
->scroll
);
281 stop
= gnt_util_onscreen_width(entry
->scroll
, entry
->end
);
282 if (stop
< widget
->priv
.width
)
283 mvwhline(widget
->window
, 0, stop
, ENTRY_CHAR
, widget
->priv
.width
- stop
);
286 mvwchgat(widget
->window
, 0, gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
),
287 1, A_REVERSE
, GNT_COLOR_TEXT_NORMAL
, NULL
);
293 gnt_entry_size_request(GntWidget
*widget
)
295 if (!GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_MAPPED
))
297 widget
->priv
.height
= 1;
298 widget
->priv
.width
= 20;
303 gnt_entry_map(GntWidget
*widget
)
305 if (widget
->priv
.width
== 0 || widget
->priv
.height
== 0)
306 gnt_widget_size_request(widget
);
311 entry_redraw(GntWidget
*widget
)
313 gnt_entry_draw(widget
);
314 gnt_widget_queue_update(widget
);
318 entry_text_changed(GntEntry
*entry
)
320 g_signal_emit(entry
, signals
[SIG_TEXT_CHANGED
], 0);
324 move_back(GntBindable
*bind
, GList
*null
)
326 GntEntry
*entry
= GNT_ENTRY(bind
);
327 if (entry
->cursor
<= entry
->start
)
329 entry
->cursor
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
330 if (entry
->cursor
< entry
->scroll
)
331 entry
->scroll
= entry
->cursor
;
332 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
333 entry_redraw(GNT_WIDGET(entry
));
338 move_forward(GntBindable
*bind
, GList
*list
)
340 GntEntry
*entry
= GNT_ENTRY(bind
);
341 if (entry
->cursor
>= entry
->end
)
343 entry
->cursor
= g_utf8_find_next_char(entry
->cursor
, NULL
);
344 while (gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
) >= GNT_WIDGET(entry
)->priv
.width
)
345 entry
->scroll
= g_utf8_find_next_char(entry
->scroll
, NULL
);
346 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
347 entry_redraw(GNT_WIDGET(entry
));
352 backspace(GntBindable
*bind
, GList
*null
)
355 GntEntry
*entry
= GNT_ENTRY(bind
);
357 if (entry
->cursor
<= entry
->start
)
360 len
= entry
->cursor
- g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
361 update_kill_ring(entry
, ENTRY_DEL_BWD_CHAR
, entry
->cursor
, -len
);
362 entry
->cursor
-= len
;
364 memmove(entry
->cursor
, entry
->cursor
+ len
, entry
->end
- entry
->cursor
);
367 if (entry
->scroll
> entry
->start
)
368 entry
->scroll
= g_utf8_find_prev_char(entry
->start
, entry
->scroll
);
370 entry_redraw(GNT_WIDGET(entry
));
372 show_suggest_dropdown(entry
);
373 entry_text_changed(entry
);
378 delkey(GntBindable
*bind
, GList
*null
)
381 GntEntry
*entry
= GNT_ENTRY(bind
);
383 if (entry
->cursor
>= entry
->end
)
386 len
= g_utf8_find_next_char(entry
->cursor
, NULL
) - entry
->cursor
;
387 update_kill_ring(entry
, ENTRY_DEL_FWD_CHAR
, entry
->cursor
, len
);
388 memmove(entry
->cursor
, entry
->cursor
+ len
, entry
->end
- entry
->cursor
- len
+ 1);
390 entry_redraw(GNT_WIDGET(entry
));
393 show_suggest_dropdown(entry
);
394 entry_text_changed(entry
);
399 move_start(GntBindable
*bind
, GList
*null
)
401 GntEntry
*entry
= GNT_ENTRY(bind
);
402 entry
->scroll
= entry
->cursor
= entry
->start
;
403 entry_redraw(GNT_WIDGET(entry
));
404 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
409 move_end(GntBindable
*bind
, GList
*null
)
411 GntEntry
*entry
= GNT_ENTRY(bind
);
412 entry
->cursor
= entry
->end
;
413 /* This should be better than this */
414 while (gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
) >= GNT_WIDGET(entry
)->priv
.width
)
415 entry
->scroll
= g_utf8_find_next_char(entry
->scroll
, NULL
);
416 entry_redraw(GNT_WIDGET(entry
));
417 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
422 history_prev(GntBindable
*bind
, GList
*null
)
424 GntEntry
*entry
= GNT_ENTRY(bind
);
425 if (entry
->histlength
&& entry
->history
->prev
)
427 entry
->history
= entry
->history
->prev
;
428 gnt_entry_set_text_internal(entry
, entry
->history
->data
);
429 destroy_suggest(entry
);
430 entry_text_changed(entry
);
432 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
439 history_next(GntBindable
*bind
, GList
*null
)
441 GntEntry
*entry
= GNT_ENTRY(bind
);
442 if (entry
->histlength
&& entry
->history
->next
)
444 if (entry
->history
->prev
== NULL
)
446 /* Save the current contents */
447 char *text
= g_strdup(gnt_entry_get_text(entry
));
448 g_free(entry
->history
->data
);
449 entry
->history
->data
= text
;
452 entry
->history
= entry
->history
->next
;
453 gnt_entry_set_text_internal(entry
, entry
->history
->data
);
454 destroy_suggest(entry
);
455 entry_text_changed(entry
);
457 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
464 clipboard_paste(GntBindable
*bind
, GList
*n
)
466 GntEntry
*entry
= GNT_ENTRY(bind
);
467 gchar
*i
, *text
, *a
, *all
;
468 text
= i
= gnt_get_clipboard_string();
470 i
= g_utf8_next_char(i
);
471 if (*i
== '\r' || *i
== '\n')
474 a
= g_strndup(entry
->start
, entry
->cursor
- entry
->start
);
475 all
= g_strconcat(a
, text
, entry
->cursor
, NULL
);
476 gnt_entry_set_text_internal(entry
, all
);
477 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
485 suggest_show(GntBindable
*bind
, GList
*null
)
487 GntEntry
*entry
= GNT_ENTRY(bind
);
489 gnt_bindable_perform_action_named(GNT_BINDABLE(entry
->ddown
), "move-down");
492 return show_suggest_dropdown(entry
);
496 suggest_next(GntBindable
*bind
, GList
*null
)
498 GntEntry
*entry
= GNT_ENTRY(bind
);
500 gnt_bindable_perform_action_named(GNT_BINDABLE(entry
->ddown
), "move-down", NULL
);
507 suggest_prev(GntBindable
*bind
, GList
*null
)
509 GntEntry
*entry
= GNT_ENTRY(bind
);
511 gnt_bindable_perform_action_named(GNT_BINDABLE(entry
->ddown
), "move-up", NULL
);
518 del_to_home(GntBindable
*bind
, GList
*null
)
520 GntEntry
*entry
= GNT_ENTRY(bind
);
521 if (entry
->cursor
<= entry
->start
)
523 update_kill_ring(entry
, ENTRY_DEL_BOL
, entry
->start
, entry
->cursor
- entry
->start
);
524 memmove(entry
->start
, entry
->cursor
, entry
->end
- entry
->cursor
);
525 entry
->end
-= (entry
->cursor
- entry
->start
);
526 entry
->cursor
= entry
->scroll
= entry
->start
;
527 memset(entry
->end
, '\0', entry
->buffer
- (entry
->end
- entry
->start
));
528 entry_redraw(GNT_WIDGET(bind
));
529 entry_text_changed(entry
);
534 del_to_end(GntBindable
*bind
, GList
*null
)
536 GntEntry
*entry
= GNT_ENTRY(bind
);
537 if (entry
->end
<= entry
->cursor
)
539 update_kill_ring(entry
, ENTRY_DEL_EOL
, entry
->cursor
, entry
->end
- entry
->cursor
);
540 entry
->end
= entry
->cursor
;
541 memset(entry
->end
, '\0', entry
->buffer
- (entry
->end
- entry
->start
));
542 entry_redraw(GNT_WIDGET(bind
));
543 entry_text_changed(entry
);
547 #define SAME(a,b) ((g_unichar_isalpha(a) && g_unichar_isalpha(b)) || \
548 (g_unichar_isdigit(a) && g_unichar_isdigit(b)) || \
549 (g_unichar_isspace(a) && g_unichar_isspace(b)) || \
550 (g_unichar_iswide(a) && g_unichar_iswide(b)))
553 begin_word(const char *text
, const char *begin
)
556 while (text
> begin
&& (!*text
|| g_unichar_isspace(g_utf8_get_char(text
))))
557 text
= g_utf8_find_prev_char(begin
, text
);
558 ch
= g_utf8_get_char(text
);
559 while ((text
= g_utf8_find_prev_char(begin
, text
)) >= begin
) {
560 gunichar cur
= g_utf8_get_char(text
);
565 return (text
? g_utf8_find_next_char(text
, NULL
) : begin
);
569 next_begin_word(const char *text
, const char *end
)
573 while (text
&& text
< end
&& g_unichar_isspace(g_utf8_get_char(text
)))
574 text
= g_utf8_find_next_char(text
, end
);
576 ch
= g_utf8_get_char(text
);
577 while ((text
= g_utf8_find_next_char(text
, end
)) != NULL
&& text
<= end
) {
578 gunichar cur
= g_utf8_get_char(text
);
582 return (text
? text
: end
);
587 move_back_word(GntBindable
*bind
, GList
*null
)
589 GntEntry
*entry
= GNT_ENTRY(bind
);
590 const char *iter
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
592 if (iter
< entry
->start
)
594 iter
= begin_word(iter
, entry
->start
);
595 entry
->cursor
= (char*)iter
;
596 if (entry
->cursor
< entry
->scroll
)
597 entry
->scroll
= entry
->cursor
;
598 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
599 entry_redraw(GNT_WIDGET(bind
));
604 del_prev_word(GntBindable
*bind
, GList
*null
)
606 GntWidget
*widget
= GNT_WIDGET(bind
);
607 GntEntry
*entry
= GNT_ENTRY(bind
);
608 char *iter
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
611 if (iter
< entry
->start
)
613 iter
= (char*)begin_word(iter
, entry
->start
);
614 count
= entry
->cursor
- iter
;
615 update_kill_ring(entry
, ENTRY_DEL_BWD_WORD
, iter
, count
);
616 memmove(iter
, entry
->cursor
, entry
->end
- entry
->cursor
);
618 entry
->cursor
= iter
;
619 if (entry
->cursor
<= entry
->scroll
) {
620 entry
->scroll
= entry
->cursor
- widget
->priv
.width
+ 2;
621 if (entry
->scroll
< entry
->start
)
622 entry
->scroll
= entry
->start
;
624 memset(entry
->end
, '\0', entry
->buffer
- (entry
->end
- entry
->start
));
625 entry_redraw(widget
);
626 entry_text_changed(entry
);
632 move_forward_word(GntBindable
*bind
, GList
*list
)
634 GntEntry
*entry
= GNT_ENTRY(bind
);
635 GntWidget
*widget
= GNT_WIDGET(bind
);
636 entry
->cursor
= (char *)next_begin_word(entry
->cursor
, entry
->end
);
637 while (gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
) >= widget
->priv
.width
) {
638 entry
->scroll
= g_utf8_find_next_char(entry
->scroll
, NULL
);
640 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
641 entry_redraw(widget
);
646 delete_forward_word(GntBindable
*bind
, GList
*list
)
648 GntEntry
*entry
= GNT_ENTRY(bind
);
649 GntWidget
*widget
= GNT_WIDGET(bind
);
650 char *iter
= (char *)next_begin_word(entry
->cursor
, entry
->end
);
651 int len
= entry
->end
- iter
+ 1;
654 update_kill_ring(entry
, ENTRY_DEL_FWD_WORD
, entry
->cursor
, iter
- entry
->cursor
);
655 memmove(entry
->cursor
, iter
, len
);
656 len
= iter
- entry
->cursor
;
658 memset(entry
->end
, '\0', len
);
659 entry_redraw(widget
);
660 entry_text_changed(entry
);
665 transpose_chars(GntBindable
*bind
, GList
*null
)
667 GntEntry
*entry
= GNT_ENTRY(bind
);
668 char *current
, *prev
;
669 char hold
[8]; /* that's right */
671 if (entry
->cursor
<= entry
->start
)
675 entry
->cursor
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
677 current
= entry
->cursor
;
678 prev
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
679 move_forward(bind
, null
);
681 /* Let's do this dance! */
682 memcpy(hold
, prev
, current
- prev
);
683 memmove(prev
, current
, entry
->cursor
- current
);
684 memcpy(prev
+ (entry
->cursor
- current
), hold
, current
- prev
);
686 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
687 entry_redraw(GNT_WIDGET(entry
));
688 entry_text_changed(entry
);
693 entry_yank(GntBindable
*bind
, GList
*null
)
695 GntEntry
*entry
= GNT_ENTRY(bind
);
696 gnt_entry_key_pressed(GNT_WIDGET(entry
), entry
->killring
->buffer
->str
);
701 gnt_entry_key_pressed(GntWidget
*widget
, const char *text
)
703 GntEntry
*entry
= GNT_ENTRY(widget
);
709 destroy_suggest(entry
);
716 if ((text
[0] == '\r' || text
[0] == ' ' || text
[0] == '\n') && entry
->ddown
)
718 char *text
= g_strdup(gnt_tree_get_selection_data(GNT_TREE(entry
->ddown
)));
719 destroy_suggest(entry
);
720 complete_suggest(entry
, text
);
722 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
723 entry_text_changed(entry
);
727 if (!iscntrl(text
[0]))
729 const char *str
, *next
;
731 for (str
= text
; *str
; str
= next
)
734 next
= g_utf8_find_next_char(str
, NULL
);
738 /* XXX: Is it necessary to use _unichar_ variants here? */
739 if (ispunct(*str
) && (entry
->flag
& GNT_ENTRY_FLAG_NO_PUNCT
))
741 if (isspace(*str
) && (entry
->flag
& GNT_ENTRY_FLAG_NO_SPACE
))
743 if (isalpha(*str
) && !(entry
->flag
& GNT_ENTRY_FLAG_ALPHA
))
745 if (isdigit(*str
) && !(entry
->flag
& GNT_ENTRY_FLAG_INT
))
748 /* Reached the max? */
749 if (entry
->max
&& g_utf8_pointer_to_offset(entry
->start
, entry
->end
) >= entry
->max
)
752 if (entry
->end
+ len
- entry
->start
>= entry
->buffer
)
754 /* This will cause the buffer to grow */
755 char *tmp
= g_strdup(entry
->start
);
756 gnt_entry_set_text_internal(entry
, tmp
);
760 memmove(entry
->cursor
+ len
, entry
->cursor
, entry
->end
- entry
->cursor
+ 1);
765 if (*str
== '\r' || *str
== '\n')
766 *entry
->cursor
= ' ';
768 *entry
->cursor
= *str
;
773 while (gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
) >= widget
->priv
.width
)
774 entry
->scroll
= g_utf8_find_next_char(entry
->scroll
, NULL
);
777 show_suggest_dropdown(entry
);
779 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
780 entry_redraw(widget
);
781 entry_text_changed(entry
);
785 if (text
[0] == '\r' || text
[0] == '\n') {
786 gnt_widget_activate(widget
);
794 jail_killring(GntEntryKillRing
*kr
)
796 g_string_free(kr
->buffer
, TRUE
);
801 gnt_entry_destroy(GntWidget
*widget
)
803 GntEntry
*entry
= GNT_ENTRY(widget
);
804 g_free(entry
->start
);
808 entry
->history
= g_list_first(entry
->history
);
809 g_list_foreach(entry
->history
, (GFunc
)g_free
, NULL
);
810 g_list_free(entry
->history
);
815 g_list_foreach(entry
->suggests
, (GFunc
)g_free
, NULL
);
816 g_list_free(entry
->suggests
);
821 gnt_widget_destroy(entry
->ddown
->parent
);
824 jail_killring(entry
->killring
);
828 gnt_entry_lost_focus(GntWidget
*widget
)
830 GntEntry
*entry
= GNT_ENTRY(widget
);
831 destroy_suggest(entry
);
832 entry_redraw(widget
);
836 gnt_entry_class_init(GntEntryClass
*klass
)
838 GntBindableClass
*bindable
= GNT_BINDABLE_CLASS(klass
);
839 char s
[2] = {erasechar(), 0};
841 parent_class
= GNT_WIDGET_CLASS(klass
);
842 parent_class
->destroy
= gnt_entry_destroy
;
843 parent_class
->draw
= gnt_entry_draw
;
844 parent_class
->map
= gnt_entry_map
;
845 parent_class
->size_request
= gnt_entry_size_request
;
846 parent_class
->key_pressed
= gnt_entry_key_pressed
;
847 parent_class
->lost_focus
= gnt_entry_lost_focus
;
849 signals
[SIG_TEXT_CHANGED
] =
850 g_signal_new("text_changed",
851 G_TYPE_FROM_CLASS(klass
),
853 G_STRUCT_OFFSET(GntEntryClass
, text_changed
),
855 g_cclosure_marshal_VOID__VOID
,
858 signals
[SIG_COMPLETION
] =
859 g_signal_new("completion",
860 G_TYPE_FROM_CLASS(klass
),
863 gnt_closure_marshal_VOID__POINTER_POINTER
,
864 G_TYPE_NONE
, 2, G_TYPE_POINTER
, G_TYPE_POINTER
);
866 gnt_bindable_class_register_action(bindable
, "cursor-home", move_start
,
867 GNT_KEY_CTRL_A
, NULL
);
868 gnt_bindable_register_binding(bindable
, "cursor-home", GNT_KEY_HOME
, NULL
);
869 gnt_bindable_class_register_action(bindable
, "cursor-end", move_end
,
870 GNT_KEY_CTRL_E
, NULL
);
871 gnt_bindable_register_binding(bindable
, "cursor-end", GNT_KEY_END
, NULL
);
872 gnt_bindable_class_register_action(bindable
, "delete-prev", backspace
,
873 GNT_KEY_BACKSPACE
, NULL
);
874 gnt_bindable_register_binding(bindable
, "delete-prev", s
, NULL
);
875 gnt_bindable_register_binding(bindable
, "delete-prev", GNT_KEY_CTRL_H
, NULL
);
876 gnt_bindable_class_register_action(bindable
, "delete-next", delkey
,
878 gnt_bindable_register_binding(bindable
, "delete-next", GNT_KEY_CTRL_D
, NULL
);
879 gnt_bindable_class_register_action(bindable
, "delete-start", del_to_home
,
880 GNT_KEY_CTRL_U
, NULL
);
881 gnt_bindable_class_register_action(bindable
, "delete-end", del_to_end
,
882 GNT_KEY_CTRL_K
, NULL
);
883 gnt_bindable_class_register_action(bindable
, "delete-prev-word", del_prev_word
,
884 GNT_KEY_CTRL_W
, NULL
);
885 gnt_bindable_class_register_action(bindable
, "cursor-prev-word", move_back_word
,
887 gnt_bindable_class_register_action(bindable
, "cursor-prev", move_back
,
889 gnt_bindable_register_binding(bindable
, "cursor-prev", GNT_KEY_CTRL_B
, NULL
);
890 gnt_bindable_class_register_action(bindable
, "cursor-next", move_forward
,
891 GNT_KEY_RIGHT
, NULL
);
892 gnt_bindable_register_binding(bindable
, "cursor-next", GNT_KEY_CTRL_F
, NULL
);
893 gnt_bindable_class_register_action(bindable
, "cursor-next-word", move_forward_word
,
895 gnt_bindable_class_register_action(bindable
, "delete-next-word", delete_forward_word
,
897 gnt_bindable_class_register_action(bindable
, "transpose-chars", transpose_chars
,
898 GNT_KEY_CTRL_T
, NULL
);
899 gnt_bindable_class_register_action(bindable
, "yank", entry_yank
,
900 GNT_KEY_CTRL_Y
, NULL
);
901 gnt_bindable_class_register_action(bindable
, "suggest-show", suggest_show
,
903 gnt_bindable_class_register_action(bindable
, "suggest-next", suggest_next
,
905 gnt_bindable_class_register_action(bindable
, "suggest-prev", suggest_prev
,
907 gnt_bindable_class_register_action(bindable
, "history-prev", history_prev
,
908 GNT_KEY_CTRL_DOWN
, NULL
);
909 gnt_bindable_class_register_action(bindable
, "history-next", history_next
,
910 GNT_KEY_CTRL_UP
, NULL
);
911 gnt_bindable_class_register_action(bindable
, "clipboard-paste", clipboard_paste
,
912 GNT_KEY_CTRL_V
, NULL
);
914 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass
), GNT_BINDABLE_CLASS(klass
));
918 static GntEntryKillRing
*
921 GntEntryKillRing
*kr
= g_new0(GntEntryKillRing
, 1);
922 kr
->buffer
= g_string_new(NULL
);
927 gnt_entry_init(GTypeInstance
*instance
, gpointer
class)
929 GntWidget
*widget
= GNT_WIDGET(instance
);
930 GntEntry
*entry
= GNT_ENTRY(instance
);
932 entry
->flag
= GNT_ENTRY_FLAG_ALL
;
935 entry
->histlength
= 0;
936 entry
->history
= NULL
;
939 entry
->always
= FALSE
;
940 entry
->suggests
= NULL
;
941 entry
->killring
= new_killring();
943 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry
),
944 GNT_WIDGET_NO_BORDER
| GNT_WIDGET_NO_SHADOW
| GNT_WIDGET_CAN_TAKE_FOCUS
);
945 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry
), GNT_WIDGET_GROW_X
);
947 widget
->priv
.minw
= 3;
948 widget
->priv
.minh
= 1;
953 /******************************************************************************
955 *****************************************************************************/
957 gnt_entry_get_gtype(void)
959 static GType type
= 0;
963 static const GTypeInfo info
= {
964 sizeof(GntEntryClass
),
965 NULL
, /* base_init */
966 NULL
, /* base_finalize */
967 (GClassInitFunc
)gnt_entry_class_init
,
968 NULL
, /* class_finalize */
969 NULL
, /* class_data */
972 gnt_entry_init
, /* instance_init */
973 NULL
/* value_table */
976 type
= g_type_register_static(GNT_TYPE_WIDGET
,
984 GntWidget
*gnt_entry_new(const char *text
)
986 GntWidget
*widget
= g_object_new(GNT_TYPE_ENTRY
, NULL
);
987 GntEntry
*entry
= GNT_ENTRY(widget
);
989 gnt_entry_set_text_internal(entry
, text
);
995 gnt_entry_set_text_internal(GntEntry
*entry
, const char *text
)
1000 g_free(entry
->start
);
1002 if (text
&& text
[0])
1011 entry
->buffer
= len
+ 128;
1013 scroll
= entry
->scroll
- entry
->start
;
1014 cursor
= entry
->end
- entry
->cursor
;
1016 entry
->start
= g_new0(char, entry
->buffer
);
1018 snprintf(entry
->start
, len
+ 1, "%s", text
);
1019 entry
->end
= entry
->start
+ len
;
1021 entry
->scroll
= entry
->start
+ scroll
;
1022 entry
->cursor
= entry
->end
- cursor
;
1024 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry
), GNT_WIDGET_MAPPED
))
1025 entry_redraw(GNT_WIDGET(entry
));
1028 void gnt_entry_set_text(GntEntry
*entry
, const char *text
)
1030 gboolean changed
= TRUE
;
1031 if (text
== NULL
&& entry
->start
== NULL
)
1033 if (text
&& entry
->start
&& g_utf8_collate(text
, entry
->start
) == 0)
1035 gnt_entry_set_text_internal(entry
, text
);
1037 entry_text_changed(entry
);
1040 void gnt_entry_set_max(GntEntry
*entry
, int max
)
1045 void gnt_entry_set_flag(GntEntry
*entry
, GntEntryFlag flag
)
1048 /* XXX: Check the existing string to make sure the flags are respected? */
1051 const char *gnt_entry_get_text(GntEntry
*entry
)
1053 return entry
->start
;
1056 void gnt_entry_clear(GntEntry
*entry
)
1058 gnt_entry_set_text_internal(entry
, NULL
);
1059 entry
->scroll
= entry
->cursor
= entry
->end
= entry
->start
;
1060 entry_redraw(GNT_WIDGET(entry
));
1061 destroy_suggest(entry
);
1062 entry_text_changed(entry
);
1065 void gnt_entry_set_masked(GntEntry
*entry
, gboolean set
)
1067 entry
->masked
= set
;
1070 void gnt_entry_add_to_history(GntEntry
*entry
, const char *text
)
1072 g_return_if_fail(entry
->history
!= NULL
); /* Need to set_history_length first */
1074 if (g_list_length(entry
->history
) >= entry
->histlength
)
1077 entry
->history
= g_list_first(entry
->history
);
1078 g_free(entry
->history
->data
);
1079 entry
->history
->data
= g_strdup(text
);
1080 entry
->history
= g_list_prepend(entry
->history
, NULL
);
1083 void gnt_entry_set_history_length(GntEntry
*entry
, int num
)
1087 entry
->histlength
= num
;
1090 entry
->history
= g_list_first(entry
->history
);
1091 g_list_foreach(entry
->history
, (GFunc
)g_free
, NULL
);
1092 g_list_free(entry
->history
);
1093 entry
->history
= NULL
;
1098 if (entry
->histlength
== 0)
1100 entry
->histlength
= num
;
1101 entry
->history
= g_list_append(NULL
, NULL
);
1105 if (num
> 0 && num
< entry
->histlength
)
1107 GList
*first
, *iter
;
1109 for (first
= entry
->history
, index
= 0; first
->prev
; first
= first
->prev
, index
++);
1110 while ((iter
= g_list_nth(first
, num
)) != NULL
)
1113 first
= g_list_delete_link(first
, iter
);
1115 entry
->histlength
= num
;
1117 entry
->history
= g_list_last(first
);
1121 entry
->histlength
= num
;
1124 void gnt_entry_set_word_suggest(GntEntry
*entry
, gboolean word
)
1129 void gnt_entry_set_always_suggest(GntEntry
*entry
, gboolean always
)
1131 entry
->always
= always
;
1134 void gnt_entry_add_suggest(GntEntry
*entry
, const char *text
)
1138 if (!text
|| !*text
)
1141 find
= g_list_find_custom(entry
->suggests
, text
, (GCompareFunc
)g_utf8_collate
);
1144 entry
->suggests
= g_list_append(entry
->suggests
, g_strdup(text
));
1147 void gnt_entry_remove_suggest(GntEntry
*entry
, const char *text
)
1149 GList
*find
= g_list_find_custom(entry
->suggests
, text
, (GCompareFunc
)g_utf8_collate
);
1153 entry
->suggests
= g_list_delete_link(entry
->suggests
, find
);