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 gboolean changed
= FALSE
;
144 int offstart
= 0, offend
= 0;
147 char *s
= get_beginning_of_word(entry
);
148 const char *iter
= text
;
149 offstart
= g_utf8_pointer_to_offset(entry
->start
, s
);
150 while (*iter
&& toupper(*s
) == toupper(*iter
)) {
156 gnt_entry_key_pressed(GNT_WIDGET(entry
), iter
);
159 offend
= g_utf8_pointer_to_offset(entry
->start
, entry
->cursor
);
162 gnt_entry_set_text_internal(entry
, text
);
164 offend
= g_utf8_strlen(text
, -1);
168 g_signal_emit(G_OBJECT(entry
), signals
[SIG_COMPLETION
], 0,
169 entry
->start
+ offstart
, entry
->start
+ offend
);
170 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
175 max_common_prefix(const char *s
, const char *t
)
178 while (*f
&& *t
&& *f
== *t
++)
184 show_suggest_dropdown(GntEntry
*entry
)
186 char *suggest
= NULL
;
188 int offset
= 0, x
, y
;
191 const char *text
= NULL
;
192 const char *sgst
= NULL
;
197 char *s
= get_beginning_of_word(entry
);
198 suggest
= g_strndup(s
, entry
->cursor
- s
);
199 if (entry
->scroll
< s
)
200 offset
= gnt_util_onscreen_width(entry
->scroll
, s
);
203 suggest
= g_strdup(entry
->start
);
204 len
= strlen(suggest
); /* Don't need to use the utf8-function here */
206 if (entry
->ddown
== NULL
)
208 GntWidget
*box
= gnt_vbox_new(FALSE
);
209 entry
->ddown
= gnt_tree_new();
210 gnt_tree_set_compare_func(GNT_TREE(entry
->ddown
), (GCompareFunc
)g_utf8_collate
);
211 gnt_box_add_widget(GNT_BOX(box
), entry
->ddown
);
213 GNT_WIDGET_SET_FLAGS(box
, GNT_WIDGET_TRANSIENT
);
215 gnt_widget_get_position(GNT_WIDGET(entry
), &x
, &y
);
218 if (y
+ 10 >= getmaxy(stdscr
))
220 gnt_widget_set_position(box
, x
, y
);
223 gnt_tree_remove_all(GNT_TREE(entry
->ddown
));
225 for (count
= 0, iter
= entry
->suggests
; iter
; iter
= iter
->next
)
228 if (g_ascii_strncasecmp(suggest
, text
, len
) == 0 && strlen(text
) >= len
)
230 gnt_tree_add_row_after(GNT_TREE(entry
->ddown
), (gpointer
)text
,
231 gnt_tree_create_row(GNT_TREE(entry
->ddown
), text
),
235 max
= strlen(text
) - len
;
237 max
= MIN(max
, max_common_prefix(sgst
+ len
, text
+ len
));
244 destroy_suggest(entry
);
246 } else if (count
== 1) {
247 destroy_suggest(entry
);
248 return complete_suggest(entry
, sgst
);
251 GntWidget
*ddown
= entry
->ddown
;
252 char *match
= g_strndup(sgst
+ len
, max
);
254 gnt_entry_key_pressed(GNT_WIDGET(entry
), match
);
257 gnt_widget_destroy(ddown
);
259 entry
->ddown
= ddown
;
261 gnt_widget_draw(entry
->ddown
->parent
);
268 gnt_entry_draw(GntWidget
*widget
)
270 GntEntry
*entry
= GNT_ENTRY(widget
);
274 if ((focus
= gnt_widget_has_focus(widget
)))
275 wbkgdset(widget
->window
, '\0' | gnt_color_pair(GNT_COLOR_TEXT_NORMAL
));
277 wbkgdset(widget
->window
, '\0' | gnt_color_pair(GNT_COLOR_HIGHLIGHT_D
));
281 mvwhline(widget
->window
, 0, 0, gnt_ascii_only() ? '*' : ACS_BULLET
,
282 g_utf8_pointer_to_offset(entry
->scroll
, entry
->end
));
285 mvwprintw(widget
->window
, 0, 0, "%s", entry
->scroll
);
287 stop
= gnt_util_onscreen_width(entry
->scroll
, entry
->end
);
288 if (stop
< widget
->priv
.width
)
289 mvwhline(widget
->window
, 0, stop
, ENTRY_CHAR
, widget
->priv
.width
- stop
);
292 mvwchgat(widget
->window
, 0, gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
),
293 1, A_REVERSE
, GNT_COLOR_TEXT_NORMAL
, NULL
);
299 gnt_entry_size_request(GntWidget
*widget
)
301 if (!GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_MAPPED
))
303 widget
->priv
.height
= 1;
304 widget
->priv
.width
= 20;
309 gnt_entry_map(GntWidget
*widget
)
311 if (widget
->priv
.width
== 0 || widget
->priv
.height
== 0)
312 gnt_widget_size_request(widget
);
317 entry_redraw(GntWidget
*widget
)
319 gnt_entry_draw(widget
);
320 gnt_widget_queue_update(widget
);
324 entry_text_changed(GntEntry
*entry
)
326 g_signal_emit(entry
, signals
[SIG_TEXT_CHANGED
], 0);
330 move_back(GntBindable
*bind
, GList
*null
)
332 GntEntry
*entry
= GNT_ENTRY(bind
);
333 if (entry
->cursor
<= entry
->start
)
335 entry
->cursor
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
336 if (entry
->cursor
< entry
->scroll
)
337 entry
->scroll
= entry
->cursor
;
338 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
339 entry_redraw(GNT_WIDGET(entry
));
344 move_forward(GntBindable
*bind
, GList
*list
)
346 GntEntry
*entry
= GNT_ENTRY(bind
);
347 if (entry
->cursor
>= entry
->end
)
349 entry
->cursor
= g_utf8_find_next_char(entry
->cursor
, NULL
);
350 while (gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
) >= GNT_WIDGET(entry
)->priv
.width
)
351 entry
->scroll
= g_utf8_find_next_char(entry
->scroll
, NULL
);
352 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
353 entry_redraw(GNT_WIDGET(entry
));
358 backspace(GntBindable
*bind
, GList
*null
)
361 GntEntry
*entry
= GNT_ENTRY(bind
);
363 if (entry
->cursor
<= entry
->start
)
366 len
= entry
->cursor
- g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
367 update_kill_ring(entry
, ENTRY_DEL_BWD_CHAR
, entry
->cursor
, -len
);
368 entry
->cursor
-= len
;
370 memmove(entry
->cursor
, entry
->cursor
+ len
, entry
->end
- entry
->cursor
);
373 if (entry
->scroll
> entry
->start
)
374 entry
->scroll
= g_utf8_find_prev_char(entry
->start
, entry
->scroll
);
376 entry_redraw(GNT_WIDGET(entry
));
378 show_suggest_dropdown(entry
);
379 entry_text_changed(entry
);
384 delkey(GntBindable
*bind
, GList
*null
)
387 GntEntry
*entry
= GNT_ENTRY(bind
);
389 if (entry
->cursor
>= entry
->end
)
392 len
= g_utf8_find_next_char(entry
->cursor
, NULL
) - entry
->cursor
;
393 update_kill_ring(entry
, ENTRY_DEL_FWD_CHAR
, entry
->cursor
, len
);
394 memmove(entry
->cursor
, entry
->cursor
+ len
, entry
->end
- entry
->cursor
- len
+ 1);
396 entry_redraw(GNT_WIDGET(entry
));
399 show_suggest_dropdown(entry
);
400 entry_text_changed(entry
);
405 move_start(GntBindable
*bind
, GList
*null
)
407 GntEntry
*entry
= GNT_ENTRY(bind
);
408 entry
->scroll
= entry
->cursor
= entry
->start
;
409 entry_redraw(GNT_WIDGET(entry
));
410 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
415 move_end(GntBindable
*bind
, GList
*null
)
417 GntEntry
*entry
= GNT_ENTRY(bind
);
418 entry
->cursor
= entry
->end
;
419 /* This should be better than this */
420 while (gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
) >= GNT_WIDGET(entry
)->priv
.width
)
421 entry
->scroll
= g_utf8_find_next_char(entry
->scroll
, NULL
);
422 entry_redraw(GNT_WIDGET(entry
));
423 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
428 history_prev(GntBindable
*bind
, GList
*null
)
430 GntEntry
*entry
= GNT_ENTRY(bind
);
431 if (entry
->histlength
&& entry
->history
->prev
)
433 entry
->history
= entry
->history
->prev
;
434 gnt_entry_set_text_internal(entry
, entry
->history
->data
);
435 destroy_suggest(entry
);
436 entry_text_changed(entry
);
438 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
445 history_next(GntBindable
*bind
, GList
*null
)
447 GntEntry
*entry
= GNT_ENTRY(bind
);
448 if (entry
->histlength
&& entry
->history
->next
)
450 if (entry
->history
->prev
== NULL
)
452 /* Save the current contents */
453 char *text
= g_strdup(gnt_entry_get_text(entry
));
454 g_free(entry
->history
->data
);
455 entry
->history
->data
= text
;
458 entry
->history
= entry
->history
->next
;
459 gnt_entry_set_text_internal(entry
, entry
->history
->data
);
460 destroy_suggest(entry
);
461 entry_text_changed(entry
);
463 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
470 clipboard_paste(GntBindable
*bind
, GList
*n
)
472 GntEntry
*entry
= GNT_ENTRY(bind
);
473 gchar
*i
, *text
, *a
, *all
;
474 text
= i
= gnt_get_clipboard_string();
476 i
= g_utf8_next_char(i
);
477 if (*i
== '\r' || *i
== '\n')
480 a
= g_strndup(entry
->start
, entry
->cursor
- entry
->start
);
481 all
= g_strconcat(a
, text
, entry
->cursor
, NULL
);
482 gnt_entry_set_text_internal(entry
, all
);
483 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
491 suggest_show(GntBindable
*bind
, GList
*null
)
493 GntEntry
*entry
= GNT_ENTRY(bind
);
495 gnt_bindable_perform_action_named(GNT_BINDABLE(entry
->ddown
), "move-down");
498 return show_suggest_dropdown(entry
);
502 suggest_next(GntBindable
*bind
, GList
*null
)
504 GntEntry
*entry
= GNT_ENTRY(bind
);
506 gnt_bindable_perform_action_named(GNT_BINDABLE(entry
->ddown
), "move-down", NULL
);
513 suggest_prev(GntBindable
*bind
, GList
*null
)
515 GntEntry
*entry
= GNT_ENTRY(bind
);
517 gnt_bindable_perform_action_named(GNT_BINDABLE(entry
->ddown
), "move-up", NULL
);
524 del_to_home(GntBindable
*bind
, GList
*null
)
526 GntEntry
*entry
= GNT_ENTRY(bind
);
527 if (entry
->cursor
<= entry
->start
)
529 update_kill_ring(entry
, ENTRY_DEL_BOL
, entry
->start
, entry
->cursor
- entry
->start
);
530 memmove(entry
->start
, entry
->cursor
, entry
->end
- entry
->cursor
);
531 entry
->end
-= (entry
->cursor
- entry
->start
);
532 entry
->cursor
= entry
->scroll
= entry
->start
;
533 memset(entry
->end
, '\0', entry
->buffer
- (entry
->end
- entry
->start
));
534 entry_redraw(GNT_WIDGET(bind
));
535 entry_text_changed(entry
);
540 del_to_end(GntBindable
*bind
, GList
*null
)
542 GntEntry
*entry
= GNT_ENTRY(bind
);
543 if (entry
->end
<= entry
->cursor
)
545 update_kill_ring(entry
, ENTRY_DEL_EOL
, entry
->cursor
, entry
->end
- entry
->cursor
);
546 entry
->end
= entry
->cursor
;
547 memset(entry
->end
, '\0', entry
->buffer
- (entry
->end
- entry
->start
));
548 entry_redraw(GNT_WIDGET(bind
));
549 entry_text_changed(entry
);
553 #define SAME(a,b) ((g_unichar_isalpha(a) && g_unichar_isalpha(b)) || \
554 (g_unichar_isdigit(a) && g_unichar_isdigit(b)) || \
555 (g_unichar_isspace(a) && g_unichar_isspace(b)) || \
556 (g_unichar_iswide(a) && g_unichar_iswide(b)))
559 begin_word(const char *text
, const char *begin
)
562 while (text
> begin
&& (!*text
|| g_unichar_isspace(g_utf8_get_char(text
))))
563 text
= g_utf8_find_prev_char(begin
, text
);
564 ch
= g_utf8_get_char(text
);
565 while ((text
= g_utf8_find_prev_char(begin
, text
)) >= begin
) {
566 gunichar cur
= g_utf8_get_char(text
);
571 return (text
? g_utf8_find_next_char(text
, NULL
) : begin
);
575 next_begin_word(const char *text
, const char *end
)
578 ch
= g_utf8_get_char(text
);
579 while ((text
= g_utf8_find_next_char(text
, end
)) != NULL
&& text
<= end
) {
580 gunichar cur
= g_utf8_get_char(text
);
585 while (text
&& text
< end
&& g_unichar_isspace(g_utf8_get_char(text
)))
586 text
= g_utf8_find_next_char(text
, end
);
587 return (text
? text
: end
);
592 move_back_word(GntBindable
*bind
, GList
*null
)
594 GntEntry
*entry
= GNT_ENTRY(bind
);
595 const char *iter
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
597 if (iter
< entry
->start
)
599 iter
= begin_word(iter
, entry
->start
);
600 entry
->cursor
= (char*)iter
;
601 if (entry
->cursor
< entry
->scroll
)
602 entry
->scroll
= entry
->cursor
;
603 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
604 entry_redraw(GNT_WIDGET(bind
));
609 del_prev_word(GntBindable
*bind
, GList
*null
)
611 GntWidget
*widget
= GNT_WIDGET(bind
);
612 GntEntry
*entry
= GNT_ENTRY(bind
);
613 char *iter
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
616 if (iter
< entry
->start
)
618 iter
= (char*)begin_word(iter
, entry
->start
);
619 count
= entry
->cursor
- iter
;
620 update_kill_ring(entry
, ENTRY_DEL_BWD_WORD
, iter
, count
);
621 memmove(iter
, entry
->cursor
, entry
->end
- entry
->cursor
);
623 entry
->cursor
= iter
;
624 if (entry
->cursor
<= entry
->scroll
) {
625 entry
->scroll
= entry
->cursor
- widget
->priv
.width
+ 2;
626 if (entry
->scroll
< entry
->start
)
627 entry
->scroll
= entry
->start
;
629 memset(entry
->end
, '\0', entry
->buffer
- (entry
->end
- entry
->start
));
630 entry_redraw(widget
);
631 entry_text_changed(entry
);
637 move_forward_word(GntBindable
*bind
, GList
*list
)
639 GntEntry
*entry
= GNT_ENTRY(bind
);
640 GntWidget
*widget
= GNT_WIDGET(bind
);
641 entry
->cursor
= (char *)next_begin_word(entry
->cursor
, entry
->end
);
642 while (gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
) >= widget
->priv
.width
) {
643 entry
->scroll
= g_utf8_find_next_char(entry
->scroll
, NULL
);
645 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
646 entry_redraw(widget
);
651 delete_forward_word(GntBindable
*bind
, GList
*list
)
653 GntEntry
*entry
= GNT_ENTRY(bind
);
654 GntWidget
*widget
= GNT_WIDGET(bind
);
655 char *iter
= (char *)next_begin_word(entry
->cursor
, entry
->end
);
656 int len
= entry
->end
- iter
+ 1;
659 update_kill_ring(entry
, ENTRY_DEL_FWD_WORD
, entry
->cursor
, iter
- entry
->cursor
);
660 memmove(entry
->cursor
, iter
, len
);
661 len
= iter
- entry
->cursor
;
663 memset(entry
->end
, '\0', len
);
664 entry_redraw(widget
);
665 entry_text_changed(entry
);
670 transpose_chars(GntBindable
*bind
, GList
*null
)
672 GntEntry
*entry
= GNT_ENTRY(bind
);
673 char *current
, *prev
;
674 char hold
[8]; /* that's right */
676 if (entry
->cursor
<= entry
->start
)
680 entry
->cursor
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
682 current
= entry
->cursor
;
683 prev
= g_utf8_find_prev_char(entry
->start
, entry
->cursor
);
684 move_forward(bind
, null
);
686 /* Let's do this dance! */
687 memcpy(hold
, prev
, current
- prev
);
688 memmove(prev
, current
, entry
->cursor
- current
);
689 memcpy(prev
+ (entry
->cursor
- current
), hold
, current
- prev
);
691 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
692 entry_redraw(GNT_WIDGET(entry
));
693 entry_text_changed(entry
);
698 entry_yank(GntBindable
*bind
, GList
*null
)
700 GntEntry
*entry
= GNT_ENTRY(bind
);
701 gnt_entry_key_pressed(GNT_WIDGET(entry
), entry
->killring
->buffer
->str
);
706 gnt_entry_key_pressed(GntWidget
*widget
, const char *text
)
708 GntEntry
*entry
= GNT_ENTRY(widget
);
714 destroy_suggest(entry
);
722 if ((text
[0] == '\r' || text
[0] == ' ') && entry
->ddown
)
724 char *text
= g_strdup(gnt_tree_get_selection_data(GNT_TREE(entry
->ddown
)));
725 destroy_suggest(entry
);
726 complete_suggest(entry
, text
);
728 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
729 entry_text_changed(entry
);
733 if (!iscntrl(text
[0]))
735 const char *str
, *next
;
737 for (str
= text
; *str
; str
= next
)
740 next
= g_utf8_find_next_char(str
, NULL
);
744 /* XXX: Is it necessary to use _unichar_ variants here? */
745 if (ispunct(*str
) && (entry
->flag
& GNT_ENTRY_FLAG_NO_PUNCT
))
747 if (isspace(*str
) && (entry
->flag
& GNT_ENTRY_FLAG_NO_SPACE
))
749 if (isalpha(*str
) && !(entry
->flag
& GNT_ENTRY_FLAG_ALPHA
))
751 if (isdigit(*str
) && !(entry
->flag
& GNT_ENTRY_FLAG_INT
))
754 /* Reached the max? */
755 if (entry
->max
&& g_utf8_pointer_to_offset(entry
->start
, entry
->end
) >= entry
->max
)
758 if (entry
->end
+ len
- entry
->start
>= entry
->buffer
)
760 /* This will cause the buffer to grow */
761 char *tmp
= g_strdup(entry
->start
);
762 gnt_entry_set_text_internal(entry
, tmp
);
766 memmove(entry
->cursor
+ len
, entry
->cursor
, entry
->end
- entry
->cursor
+ 1);
771 if (*str
== '\r' || *str
== '\n')
772 *entry
->cursor
= ' ';
774 *entry
->cursor
= *str
;
779 while (gnt_util_onscreen_width(entry
->scroll
, entry
->cursor
) >= widget
->priv
.width
)
780 entry
->scroll
= g_utf8_find_next_char(entry
->scroll
, NULL
);
783 show_suggest_dropdown(entry
);
785 update_kill_ring(entry
, ENTRY_JAIL
, NULL
, 0);
786 entry_redraw(widget
);
787 entry_text_changed(entry
);
796 jail_killring(GntEntryKillRing
*kr
)
798 g_string_free(kr
->buffer
, TRUE
);
803 gnt_entry_destroy(GntWidget
*widget
)
805 GntEntry
*entry
= GNT_ENTRY(widget
);
806 g_free(entry
->start
);
810 entry
->history
= g_list_first(entry
->history
);
811 g_list_foreach(entry
->history
, (GFunc
)g_free
, NULL
);
812 g_list_free(entry
->history
);
817 g_list_foreach(entry
->suggests
, (GFunc
)g_free
, NULL
);
818 g_list_free(entry
->suggests
);
823 gnt_widget_destroy(entry
->ddown
->parent
);
826 jail_killring(entry
->killring
);
830 gnt_entry_lost_focus(GntWidget
*widget
)
832 GntEntry
*entry
= GNT_ENTRY(widget
);
833 destroy_suggest(entry
);
834 entry_redraw(widget
);
838 gnt_entry_class_init(GntEntryClass
*klass
)
840 GntBindableClass
*bindable
= GNT_BINDABLE_CLASS(klass
);
841 char s
[2] = {erasechar(), 0};
843 parent_class
= GNT_WIDGET_CLASS(klass
);
844 parent_class
->destroy
= gnt_entry_destroy
;
845 parent_class
->draw
= gnt_entry_draw
;
846 parent_class
->map
= gnt_entry_map
;
847 parent_class
->size_request
= gnt_entry_size_request
;
848 parent_class
->key_pressed
= gnt_entry_key_pressed
;
849 parent_class
->lost_focus
= gnt_entry_lost_focus
;
851 signals
[SIG_TEXT_CHANGED
] =
852 g_signal_new("text_changed",
853 G_TYPE_FROM_CLASS(klass
),
855 G_STRUCT_OFFSET(GntEntryClass
, text_changed
),
857 g_cclosure_marshal_VOID__VOID
,
860 signals
[SIG_COMPLETION
] =
861 g_signal_new("completion",
862 G_TYPE_FROM_CLASS(klass
),
865 gnt_closure_marshal_VOID__POINTER_POINTER
,
866 G_TYPE_NONE
, 2, G_TYPE_POINTER
, G_TYPE_POINTER
);
868 gnt_bindable_class_register_action(bindable
, "cursor-home", move_start
,
869 GNT_KEY_CTRL_A
, NULL
);
870 gnt_bindable_register_binding(bindable
, "cursor-home", GNT_KEY_HOME
, NULL
);
871 gnt_bindable_class_register_action(bindable
, "cursor-end", move_end
,
872 GNT_KEY_CTRL_E
, NULL
);
873 gnt_bindable_register_binding(bindable
, "cursor-end", GNT_KEY_END
, NULL
);
874 gnt_bindable_class_register_action(bindable
, "delete-prev", backspace
,
875 GNT_KEY_BACKSPACE
, NULL
);
876 gnt_bindable_register_binding(bindable
, "delete-prev", s
, NULL
);
877 gnt_bindable_register_binding(bindable
, "delete-prev", GNT_KEY_CTRL_H
, NULL
);
878 gnt_bindable_class_register_action(bindable
, "delete-next", delkey
,
880 gnt_bindable_register_binding(bindable
, "delete-next", GNT_KEY_CTRL_D
, NULL
);
881 gnt_bindable_class_register_action(bindable
, "delete-start", del_to_home
,
882 GNT_KEY_CTRL_U
, NULL
);
883 gnt_bindable_class_register_action(bindable
, "delete-end", del_to_end
,
884 GNT_KEY_CTRL_K
, NULL
);
885 gnt_bindable_class_register_action(bindable
, "delete-prev-word", del_prev_word
,
886 GNT_KEY_CTRL_W
, NULL
);
887 gnt_bindable_class_register_action(bindable
, "cursor-prev-word", move_back_word
,
889 gnt_bindable_class_register_action(bindable
, "cursor-prev", move_back
,
891 gnt_bindable_register_binding(bindable
, "cursor-prev", GNT_KEY_CTRL_B
, NULL
);
892 gnt_bindable_class_register_action(bindable
, "cursor-next", move_forward
,
893 GNT_KEY_RIGHT
, NULL
);
894 gnt_bindable_register_binding(bindable
, "cursor-next", GNT_KEY_CTRL_F
, NULL
);
895 gnt_bindable_class_register_action(bindable
, "cursor-next-word", move_forward_word
,
897 gnt_bindable_class_register_action(bindable
, "delete-next-word", delete_forward_word
,
899 gnt_bindable_class_register_action(bindable
, "transpose-chars", transpose_chars
,
900 GNT_KEY_CTRL_T
, NULL
);
901 gnt_bindable_class_register_action(bindable
, "yank", entry_yank
,
902 GNT_KEY_CTRL_Y
, NULL
);
903 gnt_bindable_class_register_action(bindable
, "suggest-show", suggest_show
,
905 gnt_bindable_class_register_action(bindable
, "suggest-next", suggest_next
,
907 gnt_bindable_class_register_action(bindable
, "suggest-prev", suggest_prev
,
909 gnt_bindable_class_register_action(bindable
, "history-prev", history_prev
,
910 GNT_KEY_CTRL_DOWN
, NULL
);
911 gnt_bindable_class_register_action(bindable
, "history-next", history_next
,
912 GNT_KEY_CTRL_UP
, NULL
);
913 gnt_bindable_class_register_action(bindable
, "clipboard-paste", clipboard_paste
,
914 GNT_KEY_CTRL_V
, NULL
);
916 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass
), GNT_BINDABLE_CLASS(klass
));
920 static GntEntryKillRing
*
923 GntEntryKillRing
*kr
= g_new0(GntEntryKillRing
, 1);
924 kr
->buffer
= g_string_new(NULL
);
929 gnt_entry_init(GTypeInstance
*instance
, gpointer
class)
931 GntWidget
*widget
= GNT_WIDGET(instance
);
932 GntEntry
*entry
= GNT_ENTRY(instance
);
934 entry
->flag
= GNT_ENTRY_FLAG_ALL
;
937 entry
->histlength
= 0;
938 entry
->history
= NULL
;
941 entry
->always
= FALSE
;
942 entry
->suggests
= NULL
;
943 entry
->killring
= new_killring();
945 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry
),
946 GNT_WIDGET_NO_BORDER
| GNT_WIDGET_NO_SHADOW
| GNT_WIDGET_CAN_TAKE_FOCUS
);
947 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry
), GNT_WIDGET_GROW_X
);
949 widget
->priv
.minw
= 3;
950 widget
->priv
.minh
= 1;
955 /******************************************************************************
957 *****************************************************************************/
959 gnt_entry_get_gtype(void)
961 static GType type
= 0;
965 static const GTypeInfo info
= {
966 sizeof(GntEntryClass
),
967 NULL
, /* base_init */
968 NULL
, /* base_finalize */
969 (GClassInitFunc
)gnt_entry_class_init
,
970 NULL
, /* class_finalize */
971 NULL
, /* class_data */
974 gnt_entry_init
, /* instance_init */
975 NULL
/* value_table */
978 type
= g_type_register_static(GNT_TYPE_WIDGET
,
986 GntWidget
*gnt_entry_new(const char *text
)
988 GntWidget
*widget
= g_object_new(GNT_TYPE_ENTRY
, NULL
);
989 GntEntry
*entry
= GNT_ENTRY(widget
);
991 gnt_entry_set_text_internal(entry
, text
);
997 gnt_entry_set_text_internal(GntEntry
*entry
, const char *text
)
1002 g_free(entry
->start
);
1004 if (text
&& text
[0])
1013 entry
->buffer
= len
+ 128;
1015 scroll
= entry
->scroll
- entry
->start
;
1016 cursor
= entry
->end
- entry
->cursor
;
1018 entry
->start
= g_new0(char, entry
->buffer
);
1020 snprintf(entry
->start
, len
+ 1, "%s", text
);
1021 entry
->end
= entry
->start
+ len
;
1023 entry
->scroll
= entry
->start
+ scroll
;
1024 entry
->cursor
= entry
->end
- cursor
;
1026 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry
), GNT_WIDGET_MAPPED
))
1027 entry_redraw(GNT_WIDGET(entry
));
1030 void gnt_entry_set_text(GntEntry
*entry
, const char *text
)
1032 gboolean changed
= TRUE
;
1033 if (text
== NULL
&& entry
->start
== NULL
)
1035 if (text
&& entry
->start
&& g_utf8_collate(text
, entry
->start
) == 0)
1037 gnt_entry_set_text_internal(entry
, text
);
1039 entry_text_changed(entry
);
1042 void gnt_entry_set_max(GntEntry
*entry
, int max
)
1047 void gnt_entry_set_flag(GntEntry
*entry
, GntEntryFlag flag
)
1050 /* XXX: Check the existing string to make sure the flags are respected? */
1053 const char *gnt_entry_get_text(GntEntry
*entry
)
1055 return entry
->start
;
1058 void gnt_entry_clear(GntEntry
*entry
)
1060 gnt_entry_set_text_internal(entry
, NULL
);
1061 entry
->scroll
= entry
->cursor
= entry
->end
= entry
->start
;
1062 entry_redraw(GNT_WIDGET(entry
));
1063 destroy_suggest(entry
);
1064 entry_text_changed(entry
);
1067 void gnt_entry_set_masked(GntEntry
*entry
, gboolean set
)
1069 entry
->masked
= set
;
1072 void gnt_entry_add_to_history(GntEntry
*entry
, const char *text
)
1074 g_return_if_fail(entry
->history
!= NULL
); /* Need to set_history_length first */
1076 if (g_list_length(entry
->history
) >= entry
->histlength
)
1079 entry
->history
= g_list_first(entry
->history
);
1080 g_free(entry
->history
->data
);
1081 entry
->history
->data
= g_strdup(text
);
1082 entry
->history
= g_list_prepend(entry
->history
, NULL
);
1085 void gnt_entry_set_history_length(GntEntry
*entry
, int num
)
1089 entry
->histlength
= num
;
1092 entry
->history
= g_list_first(entry
->history
);
1093 g_list_foreach(entry
->history
, (GFunc
)g_free
, NULL
);
1094 g_list_free(entry
->history
);
1095 entry
->history
= NULL
;
1100 if (entry
->histlength
== 0)
1102 entry
->histlength
= num
;
1103 entry
->history
= g_list_append(NULL
, NULL
);
1107 if (num
> 0 && num
< entry
->histlength
)
1109 GList
*first
, *iter
;
1111 for (first
= entry
->history
, index
= 0; first
->prev
; first
= first
->prev
, index
++);
1112 while ((iter
= g_list_nth(first
, num
)) != NULL
)
1115 first
= g_list_delete_link(first
, iter
);
1117 entry
->histlength
= num
;
1119 entry
->history
= g_list_last(first
);
1123 entry
->histlength
= num
;
1126 void gnt_entry_set_word_suggest(GntEntry
*entry
, gboolean word
)
1131 void gnt_entry_set_always_suggest(GntEntry
*entry
, gboolean always
)
1133 entry
->always
= always
;
1136 void gnt_entry_add_suggest(GntEntry
*entry
, const char *text
)
1140 if (!text
|| !*text
)
1143 find
= g_list_find_custom(entry
->suggests
, text
, (GCompareFunc
)g_utf8_collate
);
1146 entry
->suggests
= g_list_append(entry
->suggests
, g_strdup(text
));
1149 void gnt_entry_remove_suggest(GntEntry
*entry
, const char *text
)
1151 GList
*find
= g_list_find_custom(entry
->suggests
, text
, (GCompareFunc
)g_utf8_collate
);
1155 entry
->suggests
= g_list_delete_link(entry
->suggests
, find
);