Mercurial > pidgin
annotate finch/libgnt/gntentry.c @ 21205:ebbe7b5df08e
Move 2.2.2 to the right place.
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Wed, 10 Oct 2007 04:01:22 +0000 |
parents | 470feb3084a4 |
children | 9187d331aebe |
rev | line source |
---|---|
17928
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
1 /** |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
2 * GNT - The GLib Ncurses Toolkit |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
3 * |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
4 * GNT is the legal property of its developers, whose names are too numerous |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
5 * to list here. Please refer to the COPYRIGHT file distributed with this |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
6 * source distribution. |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
7 * |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
8 * This library is free software; you can redistribute it and/or modify |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
9 * it under the terms of the GNU General Public License as published by |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
10 * the Free Software Foundation; either version 2 of the License, or |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
11 * (at your option) any later version. |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
12 * |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
13 * This program is distributed in the hope that it will be useful, |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
16 * GNU General Public License for more details. |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
17 * |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
18 * You should have received a copy of the GNU General Public License |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
19 * along with this program; if not, write to the Free Software |
19681
44b4e8bd759b
The FSF changed its address a while ago; our files were out of date.
John Bailey <rekkanoryo@rekkanoryo.org>
parents:
18873
diff
changeset
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
17928
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
21 */ |
8410511f4dbb
applied changes from 016401bd409e6229fae0ab1e80d9fef9365511b3
Eric Polino <aluink@pidgin.im>
parents:
16899
diff
changeset
|
22 |
15817 | 23 #include <ctype.h> |
24 #include <string.h> | |
25 | |
26 #include "gntbox.h" | |
27 #include "gntentry.h" | |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
28 #include "gntmarshal.h" |
15817 | 29 #include "gntstyle.h" |
30 #include "gnttree.h" | |
31 #include "gntutils.h" | |
32 | |
33 enum | |
34 { | |
35 SIG_TEXT_CHANGED, | |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
36 SIG_COMPLETION, |
15817 | 37 SIGS, |
38 }; | |
39 static guint signals[SIGS] = { 0 }; | |
40 | |
41 static GntWidgetClass *parent_class = NULL; | |
42 | |
15959
efbced3f38ac
Update the tab completion a little bit. The binding for suggest-show will perform suggest-next if the suggest-dropdown is already showing. If there's just one suggestion, then complete with that suggestion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15817
diff
changeset
|
43 static gboolean gnt_entry_key_pressed(GntWidget *widget, const char *text); |
15817 | 44 static void gnt_entry_set_text_internal(GntEntry *entry, const char *text); |
45 | |
46 static void | |
47 destroy_suggest(GntEntry *entry) | |
48 { | |
49 if (entry->ddown) | |
50 { | |
51 gnt_widget_destroy(entry->ddown->parent); | |
52 entry->ddown = NULL; | |
53 } | |
54 } | |
55 | |
56 static char * | |
57 get_beginning_of_word(GntEntry *entry) | |
58 { | |
59 char *s = entry->cursor; | |
60 while (s > entry->start) | |
61 { | |
62 char *t = g_utf8_find_prev_char(entry->start, s); | |
63 if (isspace(*t)) | |
64 break; | |
65 s = t; | |
66 } | |
67 return s; | |
68 } | |
69 | |
70 static gboolean | |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
71 complete_suggest(GntEntry *entry, const char *text) |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
72 { |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
73 gboolean changed = FALSE; |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
74 int offstart = 0, offend = 0; |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
75 |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
76 if (entry->word) { |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
77 char *s = get_beginning_of_word(entry); |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
78 const char *iter = text; |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
79 offstart = g_utf8_pointer_to_offset(entry->start, s); |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
80 while (*iter && toupper(*s) == toupper(*iter)) { |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
81 if (*s != *iter) |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
82 changed = TRUE; |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
83 *s++ = *iter++; |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
84 } |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
85 if (*iter) { |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
86 gnt_entry_key_pressed(GNT_WIDGET(entry), iter); |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
87 changed = TRUE; |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
88 } |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
89 offend = g_utf8_pointer_to_offset(entry->start, entry->cursor); |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
90 } else { |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
91 offstart = 0; |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
92 gnt_entry_set_text_internal(entry, text); |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
93 changed = TRUE; |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
94 offend = g_utf8_strlen(text, -1); |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
95 } |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
96 |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
97 if (changed) |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
98 g_signal_emit(G_OBJECT(entry), signals[SIG_COMPLETION], 0, |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
99 entry->start + offstart, entry->start + offend); |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
100 return changed; |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
101 } |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
102 |
20088
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
103 static int |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
104 max_common_prefix(const char *s, const char *t) |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
105 { |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
106 const char *f = s; |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
107 while (*f && *t && *f == *t++) |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
108 f++; |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
109 return f - s; |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
110 } |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
111 |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
112 static gboolean |
15817 | 113 show_suggest_dropdown(GntEntry *entry) |
114 { | |
115 char *suggest = NULL; | |
116 int len; | |
117 int offset = 0, x, y; | |
118 int count = 0; | |
119 GList *iter; | |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
120 const char *text = NULL; |
16899
6502a3846264
Fix tab-completion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
16889
diff
changeset
|
121 const char *sgst = NULL; |
20088
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
122 int max = -1; |
15817 | 123 |
124 if (entry->word) | |
125 { | |
126 char *s = get_beginning_of_word(entry); | |
127 suggest = g_strndup(s, entry->cursor - s); | |
128 if (entry->scroll < s) | |
129 offset = gnt_util_onscreen_width(entry->scroll, s); | |
130 } | |
131 else | |
132 suggest = g_strdup(entry->start); | |
133 len = strlen(suggest); /* Don't need to use the utf8-function here */ | |
20088
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
134 |
15817 | 135 if (entry->ddown == NULL) |
136 { | |
137 GntWidget *box = gnt_vbox_new(FALSE); | |
138 entry->ddown = gnt_tree_new(); | |
139 gnt_tree_set_compare_func(GNT_TREE(entry->ddown), (GCompareFunc)g_utf8_collate); | |
140 gnt_box_add_widget(GNT_BOX(box), entry->ddown); | |
141 | |
142 GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); | |
143 | |
144 gnt_widget_get_position(GNT_WIDGET(entry), &x, &y); | |
145 x += offset; | |
146 y++; | |
147 if (y + 10 >= getmaxy(stdscr)) | |
148 y -= 11; | |
149 gnt_widget_set_position(box, x, y); | |
150 } | |
151 else | |
152 gnt_tree_remove_all(GNT_TREE(entry->ddown)); | |
153 | |
154 for (count = 0, iter = entry->suggests; iter; iter = iter->next) | |
155 { | |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
156 text = iter->data; |
15817 | 157 if (g_ascii_strncasecmp(suggest, text, len) == 0 && strlen(text) >= len) |
158 { | |
159 gnt_tree_add_row_after(GNT_TREE(entry->ddown), (gpointer)text, | |
160 gnt_tree_create_row(GNT_TREE(entry->ddown), text), | |
161 NULL, NULL); | |
162 count++; | |
20088
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
163 if (max == -1) |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
164 max = strlen(text) - len; |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
165 else if (max) |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
166 max = MIN(max, max_common_prefix(sgst + len, text + len)); |
16899
6502a3846264
Fix tab-completion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
16889
diff
changeset
|
167 sgst = text; |
15817 | 168 } |
169 } | |
170 g_free(suggest); | |
171 | |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
172 if (count == 0) { |
15817 | 173 destroy_suggest(entry); |
174 return FALSE; | |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
175 } else if (count == 1) { |
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
176 destroy_suggest(entry); |
16899
6502a3846264
Fix tab-completion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
16889
diff
changeset
|
177 return complete_suggest(entry, sgst); |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
178 } else { |
20088
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
179 if (max > 0) { |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
180 GntWidget *ddown = entry->ddown; |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
181 char *match = g_strndup(sgst + len, max); |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
182 entry->ddown = NULL; |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
183 gnt_entry_key_pressed(GNT_WIDGET(entry), match); |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
184 g_free(match); |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
185 if (entry->ddown) |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
186 gnt_widget_destroy(ddown); |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
187 else |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
188 entry->ddown = ddown; |
470feb3084a4
Tab-complete as much as possible when there are multiple suggests.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
19681
diff
changeset
|
189 } |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
190 gnt_widget_draw(entry->ddown->parent); |
15817 | 191 } |
192 | |
193 return TRUE; | |
194 } | |
195 | |
196 static void | |
197 gnt_entry_draw(GntWidget *widget) | |
198 { | |
199 GntEntry *entry = GNT_ENTRY(widget); | |
200 int stop; | |
201 gboolean focus; | |
202 | |
203 if ((focus = gnt_widget_has_focus(widget))) | |
204 wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TEXT_NORMAL)); | |
205 else | |
206 wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D)); | |
207 | |
208 if (entry->masked) | |
209 { | |
210 mvwhline(widget->window, 0, 0, gnt_ascii_only() ? '*' : ACS_BULLET, | |
211 g_utf8_pointer_to_offset(entry->scroll, entry->end)); | |
212 } | |
213 else | |
214 mvwprintw(widget->window, 0, 0, "%s", entry->scroll); | |
215 | |
216 stop = gnt_util_onscreen_width(entry->scroll, entry->end); | |
217 if (stop < widget->priv.width) | |
18346
72a52cff76f3
Draw the password entries correctly.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
17928
diff
changeset
|
218 mvwhline(widget->window, 0, stop, ENTRY_CHAR, widget->priv.width - stop); |
15817 | 219 |
220 if (focus) | |
221 mvwchgat(widget->window, 0, gnt_util_onscreen_width(entry->scroll, entry->cursor), | |
222 1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL); | |
223 | |
224 GNTDEBUG; | |
225 } | |
226 | |
227 static void | |
228 gnt_entry_size_request(GntWidget *widget) | |
229 { | |
230 if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED)) | |
231 { | |
232 widget->priv.height = 1; | |
233 widget->priv.width = 20; | |
234 } | |
235 } | |
236 | |
237 static void | |
238 gnt_entry_map(GntWidget *widget) | |
239 { | |
240 if (widget->priv.width == 0 || widget->priv.height == 0) | |
241 gnt_widget_size_request(widget); | |
242 GNTDEBUG; | |
243 } | |
244 | |
245 static void | |
246 entry_redraw(GntWidget *widget) | |
247 { | |
248 gnt_entry_draw(widget); | |
249 gnt_widget_queue_update(widget); | |
250 } | |
251 | |
252 static void | |
253 entry_text_changed(GntEntry *entry) | |
254 { | |
255 g_signal_emit(entry, signals[SIG_TEXT_CHANGED], 0); | |
256 } | |
257 | |
258 static gboolean | |
259 move_back(GntBindable *bind, GList *null) | |
260 { | |
261 GntEntry *entry = GNT_ENTRY(bind); | |
262 if (entry->cursor <= entry->start) | |
263 return FALSE; | |
264 entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor); | |
265 if (entry->cursor < entry->scroll) | |
266 entry->scroll = entry->cursor; | |
267 entry_redraw(GNT_WIDGET(entry)); | |
268 return TRUE; | |
269 } | |
270 | |
271 static gboolean | |
272 move_forward(GntBindable *bind, GList *list) | |
273 { | |
274 GntEntry *entry = GNT_ENTRY(bind); | |
275 if (entry->cursor >= entry->end) | |
276 return FALSE; | |
277 entry->cursor = g_utf8_find_next_char(entry->cursor, NULL); | |
278 while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) | |
279 entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); | |
280 entry_redraw(GNT_WIDGET(entry)); | |
281 return TRUE; | |
282 } | |
283 | |
284 static gboolean | |
285 backspace(GntBindable *bind, GList *null) | |
286 { | |
287 int len; | |
288 GntEntry *entry = GNT_ENTRY(bind); | |
289 | |
290 if (entry->cursor <= entry->start) | |
291 return TRUE; | |
292 | |
293 len = entry->cursor - g_utf8_find_prev_char(entry->start, entry->cursor); | |
294 entry->cursor -= len; | |
295 memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor); | |
296 entry->end -= len; | |
297 | |
298 if (entry->scroll > entry->start) | |
299 entry->scroll = g_utf8_find_prev_char(entry->start, entry->scroll); | |
300 | |
301 entry_redraw(GNT_WIDGET(entry)); | |
302 if (entry->ddown) | |
303 show_suggest_dropdown(entry); | |
304 entry_text_changed(entry); | |
305 return TRUE; | |
306 } | |
307 | |
308 static gboolean | |
309 delkey(GntBindable *bind, GList *null) | |
310 { | |
311 int len; | |
312 GntEntry *entry = GNT_ENTRY(bind); | |
313 | |
314 if (entry->cursor >= entry->end) | |
315 return FALSE; | |
316 | |
317 len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor; | |
318 memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1); | |
319 entry->end -= len; | |
320 entry_redraw(GNT_WIDGET(entry)); | |
321 | |
322 if (entry->ddown) | |
323 show_suggest_dropdown(entry); | |
324 entry_text_changed(entry); | |
325 return TRUE; | |
326 } | |
327 | |
328 static gboolean | |
329 move_start(GntBindable *bind, GList *null) | |
330 { | |
331 GntEntry *entry = GNT_ENTRY(bind); | |
332 entry->scroll = entry->cursor = entry->start; | |
333 entry_redraw(GNT_WIDGET(entry)); | |
334 return TRUE; | |
335 } | |
336 | |
337 static gboolean | |
338 move_end(GntBindable *bind, GList *null) | |
339 { | |
340 GntEntry *entry = GNT_ENTRY(bind); | |
341 entry->cursor = entry->end; | |
342 /* This should be better than this */ | |
343 while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) | |
344 entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); | |
345 entry_redraw(GNT_WIDGET(entry)); | |
346 return TRUE; | |
347 } | |
348 | |
349 static gboolean | |
350 history_prev(GntBindable *bind, GList *null) | |
351 { | |
352 GntEntry *entry = GNT_ENTRY(bind); | |
353 if (entry->histlength && entry->history->prev) | |
354 { | |
355 entry->history = entry->history->prev; | |
356 gnt_entry_set_text_internal(entry, entry->history->data); | |
357 destroy_suggest(entry); | |
358 entry_text_changed(entry); | |
359 | |
360 return TRUE; | |
361 } | |
362 return FALSE; | |
363 } | |
364 | |
365 static gboolean | |
366 history_next(GntBindable *bind, GList *null) | |
367 { | |
368 GntEntry *entry = GNT_ENTRY(bind); | |
369 if (entry->histlength && entry->history->next) | |
370 { | |
371 if (entry->history->prev == NULL) | |
372 { | |
373 /* Save the current contents */ | |
374 char *text = g_strdup(gnt_entry_get_text(entry)); | |
375 g_free(entry->history->data); | |
376 entry->history->data = text; | |
377 } | |
378 | |
379 entry->history = entry->history->next; | |
380 gnt_entry_set_text_internal(entry, entry->history->data); | |
381 destroy_suggest(entry); | |
382 entry_text_changed(entry); | |
383 | |
384 return TRUE; | |
385 } | |
386 return FALSE; | |
387 } | |
388 | |
389 static gboolean | |
390 clipboard_paste(GntBindable *bind, GList *n) | |
391 { | |
392 GntEntry *entry = GNT_ENTRY(bind); | |
393 gchar *i, *text, *a, *all; | |
394 text = i = gnt_get_clipboard_string(); | |
395 while (*i != '\0') { | |
396 i = g_utf8_next_char(i); | |
397 if (*i == '\r' || *i == '\n') | |
398 *i = ' '; | |
399 } | |
400 a = g_strndup(entry->start, entry->cursor - entry->start); | |
401 all = g_strconcat(a, text, entry->cursor, NULL); | |
402 gnt_entry_set_text_internal(entry, all); | |
403 g_free(a); | |
404 g_free(text); | |
405 g_free(all); | |
406 return TRUE; | |
407 } | |
408 | |
409 static gboolean | |
410 suggest_show(GntBindable *bind, GList *null) | |
411 { | |
15959
efbced3f38ac
Update the tab completion a little bit. The binding for suggest-show will perform suggest-next if the suggest-dropdown is already showing. If there's just one suggestion, then complete with that suggestion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15817
diff
changeset
|
412 GntEntry *entry = GNT_ENTRY(bind); |
efbced3f38ac
Update the tab completion a little bit. The binding for suggest-show will perform suggest-next if the suggest-dropdown is already showing. If there's just one suggestion, then complete with that suggestion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15817
diff
changeset
|
413 if (entry->ddown) { |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
414 gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down"); |
15959
efbced3f38ac
Update the tab completion a little bit. The binding for suggest-show will perform suggest-next if the suggest-dropdown is already showing. If there's just one suggestion, then complete with that suggestion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15817
diff
changeset
|
415 return TRUE; |
efbced3f38ac
Update the tab completion a little bit. The binding for suggest-show will perform suggest-next if the suggest-dropdown is already showing. If there's just one suggestion, then complete with that suggestion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15817
diff
changeset
|
416 } |
efbced3f38ac
Update the tab completion a little bit. The binding for suggest-show will perform suggest-next if the suggest-dropdown is already showing. If there's just one suggestion, then complete with that suggestion.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15817
diff
changeset
|
417 return show_suggest_dropdown(entry); |
15817 | 418 } |
419 | |
420 static gboolean | |
421 suggest_next(GntBindable *bind, GList *null) | |
422 { | |
423 GntEntry *entry = GNT_ENTRY(bind); | |
424 if (entry->ddown) { | |
425 gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down", NULL); | |
426 return TRUE; | |
427 } | |
428 return FALSE; | |
429 } | |
430 | |
431 static gboolean | |
432 suggest_prev(GntBindable *bind, GList *null) | |
433 { | |
434 GntEntry *entry = GNT_ENTRY(bind); | |
435 if (entry->ddown) { | |
436 gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-up", NULL); | |
437 return TRUE; | |
438 } | |
439 return FALSE; | |
440 } | |
441 | |
442 static gboolean | |
443 del_to_home(GntBindable *bind, GList *null) | |
444 { | |
445 GntEntry *entry = GNT_ENTRY(bind); | |
446 if (entry->cursor <= entry->start) | |
447 return TRUE; | |
448 memmove(entry->start, entry->cursor, entry->end - entry->cursor); | |
449 entry->end -= (entry->cursor - entry->start); | |
450 entry->cursor = entry->scroll = entry->start; | |
451 memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); | |
452 entry_redraw(GNT_WIDGET(bind)); | |
453 entry_text_changed(entry); | |
454 return TRUE; | |
455 } | |
456 | |
457 static gboolean | |
458 del_to_end(GntBindable *bind, GList *null) | |
459 { | |
460 GntEntry *entry = GNT_ENTRY(bind); | |
461 if (entry->end <= entry->cursor) | |
462 return TRUE; | |
463 entry->end = entry->cursor; | |
464 memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); | |
465 entry_redraw(GNT_WIDGET(bind)); | |
466 entry_text_changed(entry); | |
467 return TRUE; | |
468 } | |
469 | |
470 #define SAME(a,b) ((g_unichar_isalpha(a) && g_unichar_isalpha(b)) || \ | |
471 (g_unichar_isdigit(a) && g_unichar_isdigit(b)) || \ | |
472 (g_unichar_isspace(a) && g_unichar_isspace(b)) || \ | |
473 (g_unichar_iswide(a) && g_unichar_iswide(b))) | |
474 | |
475 static const char * | |
476 begin_word(const char *text, const char *begin) | |
477 { | |
478 gunichar ch = 0; | |
479 while (text > begin && (!*text || g_unichar_isspace(g_utf8_get_char(text)))) | |
480 text = g_utf8_find_prev_char(begin, text); | |
481 ch = g_utf8_get_char(text); | |
482 while ((text = g_utf8_find_prev_char(begin, text)) >= begin) { | |
483 gunichar cur = g_utf8_get_char(text); | |
484 if (!SAME(ch, cur)) | |
485 break; | |
486 } | |
487 | |
488 return (text ? g_utf8_find_next_char(text, NULL) : begin); | |
489 } | |
490 | |
491 static const char * | |
492 next_begin_word(const char *text, const char *end) | |
493 { | |
494 gunichar ch = 0; | |
495 ch = g_utf8_get_char(text); | |
496 while ((text = g_utf8_find_next_char(text, end)) != NULL && text <= end) { | |
497 gunichar cur = g_utf8_get_char(text); | |
498 if (!SAME(ch, cur)) | |
499 break; | |
500 } | |
501 | |
502 while (text && text < end && g_unichar_isspace(g_utf8_get_char(text))) | |
503 text = g_utf8_find_next_char(text, end); | |
504 return (text ? text : end); | |
505 } | |
506 | |
507 #undef SAME | |
508 static gboolean | |
509 move_back_word(GntBindable *bind, GList *null) | |
510 { | |
511 GntEntry *entry = GNT_ENTRY(bind); | |
512 const char *iter = g_utf8_find_prev_char(entry->start, entry->cursor); | |
513 | |
514 if (iter < entry->start) | |
515 return TRUE; | |
516 iter = begin_word(iter, entry->start); | |
517 entry->cursor = (char*)iter; | |
518 if (entry->cursor < entry->scroll) | |
519 entry->scroll = entry->cursor; | |
520 entry_redraw(GNT_WIDGET(bind)); | |
521 return TRUE; | |
522 } | |
523 | |
524 static gboolean | |
525 del_prev_word(GntBindable *bind, GList *null) | |
526 { | |
527 GntWidget *widget = GNT_WIDGET(bind); | |
528 GntEntry *entry = GNT_ENTRY(bind); | |
529 char *iter = g_utf8_find_prev_char(entry->start, entry->cursor); | |
530 int count; | |
531 | |
532 if (iter < entry->start) | |
533 return TRUE; | |
534 iter = (char*)begin_word(iter, entry->start); | |
535 count = entry->cursor - iter; | |
536 memmove(iter, entry->cursor, entry->end - entry->cursor); | |
537 entry->end -= count; | |
538 entry->cursor = iter; | |
539 if (entry->cursor <= entry->scroll) { | |
540 entry->scroll = entry->cursor - widget->priv.width + 2; | |
541 if (entry->scroll < entry->start) | |
542 entry->scroll = entry->start; | |
543 } | |
544 memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); | |
545 entry_redraw(widget); | |
546 entry_text_changed(entry); | |
547 | |
548 return TRUE; | |
549 } | |
550 | |
551 static gboolean | |
552 move_forward_word(GntBindable *bind, GList *list) | |
553 { | |
554 GntEntry *entry = GNT_ENTRY(bind); | |
555 GntWidget *widget = GNT_WIDGET(bind); | |
556 entry->cursor = (char *)next_begin_word(entry->cursor, entry->end); | |
557 while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) { | |
558 entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); | |
559 } | |
560 entry_redraw(widget); | |
561 return TRUE; | |
562 } | |
563 | |
564 static gboolean | |
565 delete_forward_word(GntBindable *bind, GList *list) | |
566 { | |
567 GntEntry *entry = GNT_ENTRY(bind); | |
568 GntWidget *widget = GNT_WIDGET(bind); | |
569 char *iter = (char *)next_begin_word(entry->cursor, entry->end); | |
570 int len = entry->end - iter + 1; | |
571 if (len <= 0) | |
572 return TRUE; | |
573 memmove(entry->cursor, iter, len); | |
574 len = iter - entry->cursor; | |
575 entry->end -= len; | |
576 memset(entry->end, '\0', len); | |
577 entry_redraw(widget); | |
578 entry_text_changed(entry); | |
579 return TRUE; | |
580 } | |
581 | |
582 static gboolean | |
583 gnt_entry_key_pressed(GntWidget *widget, const char *text) | |
584 { | |
585 GntEntry *entry = GNT_ENTRY(widget); | |
586 | |
587 if (text[0] == 27) | |
588 { | |
589 if (text[1] == 0) | |
590 { | |
591 destroy_suggest(entry); | |
592 return TRUE; | |
593 } | |
594 | |
595 return FALSE; | |
596 } | |
597 else | |
598 { | |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
599 if ((text[0] == '\r' || text[0] == ' ') && entry->ddown) |
15817 | 600 { |
601 char *text = g_strdup(gnt_tree_get_selection_data(GNT_TREE(entry->ddown))); | |
602 destroy_suggest(entry); | |
16889
c31328dba5c2
Fix some ickyness in the tab-completion. Now, if there's only one suggest word, then the first tab will just complete the suggestion. If there's only one suggest word, and it's already completed, then tab will take focus to the next widget. If there is a dropdown, then you can select a suggest word by pressing tabs to move to it, then either space or enter to accept it.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15959
diff
changeset
|
603 complete_suggest(entry, text); |
15817 | 604 g_free(text); |
605 entry_text_changed(entry); | |
606 return TRUE; | |
607 } | |
608 | |
609 if (!iscntrl(text[0])) | |
610 { | |
611 const char *str, *next; | |
612 | |
613 for (str = text; *str; str = next) | |
614 { | |
615 int len; | |
616 next = g_utf8_find_next_char(str, NULL); | |
617 len = next - str; | |
618 | |
619 /* Valid input? */ | |
620 /* XXX: Is it necessary to use _unichar_ variants here? */ | |
621 if (ispunct(*str) && (entry->flag & GNT_ENTRY_FLAG_NO_PUNCT)) | |
622 continue; | |
623 if (isspace(*str) && (entry->flag & GNT_ENTRY_FLAG_NO_SPACE)) | |
624 continue; | |
625 if (isalpha(*str) && !(entry->flag & GNT_ENTRY_FLAG_ALPHA)) | |
626 continue; | |
627 if (isdigit(*str) && !(entry->flag & GNT_ENTRY_FLAG_INT)) | |
628 continue; | |
629 | |
630 /* Reached the max? */ | |
631 if (entry->max && g_utf8_pointer_to_offset(entry->start, entry->end) >= entry->max) | |
632 continue; | |
633 | |
634 if (entry->end + len - entry->start >= entry->buffer) | |
635 { | |
636 /* This will cause the buffer to grow */ | |
637 char *tmp = g_strdup(entry->start); | |
638 gnt_entry_set_text_internal(entry, tmp); | |
639 g_free(tmp); | |
640 } | |
641 | |
642 memmove(entry->cursor + len, entry->cursor, entry->end - entry->cursor + 1); | |
643 entry->end += len; | |
644 | |
645 while (str < next) | |
646 { | |
647 if (*str == '\r' || *str == '\n') | |
648 *entry->cursor = ' '; | |
649 else | |
650 *entry->cursor = *str; | |
651 entry->cursor++; | |
652 str++; | |
653 } | |
654 | |
655 while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) | |
656 entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); | |
657 | |
658 if (entry->ddown) | |
659 show_suggest_dropdown(entry); | |
660 } | |
661 entry_redraw(widget); | |
662 entry_text_changed(entry); | |
663 return TRUE; | |
664 } | |
665 } | |
666 | |
667 return FALSE; | |
668 } | |
669 | |
670 static void | |
671 gnt_entry_destroy(GntWidget *widget) | |
672 { | |
673 GntEntry *entry = GNT_ENTRY(widget); | |
674 g_free(entry->start); | |
675 | |
676 if (entry->history) | |
677 { | |
678 entry->history = g_list_first(entry->history); | |
679 g_list_foreach(entry->history, (GFunc)g_free, NULL); | |
680 g_list_free(entry->history); | |
681 } | |
682 | |
683 if (entry->suggests) | |
684 { | |
685 g_list_foreach(entry->suggests, (GFunc)g_free, NULL); | |
686 g_list_free(entry->suggests); | |
687 } | |
688 | |
689 if (entry->ddown) | |
690 { | |
691 gnt_widget_destroy(entry->ddown->parent); | |
692 } | |
693 } | |
694 | |
695 static void | |
696 gnt_entry_lost_focus(GntWidget *widget) | |
697 { | |
698 GntEntry *entry = GNT_ENTRY(widget); | |
699 destroy_suggest(entry); | |
700 entry_redraw(widget); | |
701 } | |
702 | |
703 static void | |
704 gnt_entry_class_init(GntEntryClass *klass) | |
705 { | |
706 GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); | |
707 char s[2] = {erasechar(), 0}; | |
708 | |
709 parent_class = GNT_WIDGET_CLASS(klass); | |
710 parent_class->destroy = gnt_entry_destroy; | |
711 parent_class->draw = gnt_entry_draw; | |
712 parent_class->map = gnt_entry_map; | |
713 parent_class->size_request = gnt_entry_size_request; | |
714 parent_class->key_pressed = gnt_entry_key_pressed; | |
715 parent_class->lost_focus = gnt_entry_lost_focus; | |
716 | |
717 signals[SIG_TEXT_CHANGED] = | |
718 g_signal_new("text_changed", | |
719 G_TYPE_FROM_CLASS(klass), | |
720 G_SIGNAL_RUN_LAST, | |
721 G_STRUCT_OFFSET(GntEntryClass, text_changed), | |
722 NULL, NULL, | |
723 g_cclosure_marshal_VOID__VOID, | |
724 G_TYPE_NONE, 0); | |
725 | |
18382
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
726 signals[SIG_COMPLETION] = |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
727 g_signal_new("completion", |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
728 G_TYPE_FROM_CLASS(klass), |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
729 G_SIGNAL_RUN_LAST, |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
730 0, NULL, NULL, |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
731 gnt_closure_marshal_VOID__POINTER_POINTER, |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
732 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); |
aa60f5a89286
A 'completion' signal to emit whenever user accepts a completion suggest.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
18346
diff
changeset
|
733 |
15817 | 734 gnt_bindable_class_register_action(bindable, "cursor-home", move_start, |
735 GNT_KEY_CTRL_A, NULL); | |
736 gnt_bindable_register_binding(bindable, "cursor-home", GNT_KEY_HOME, NULL); | |
737 gnt_bindable_class_register_action(bindable, "cursor-end", move_end, | |
738 GNT_KEY_CTRL_E, NULL); | |
739 gnt_bindable_register_binding(bindable, "cursor-end", GNT_KEY_END, NULL); | |
740 gnt_bindable_class_register_action(bindable, "delete-prev", backspace, | |
741 GNT_KEY_BACKSPACE, NULL); | |
742 gnt_bindable_register_binding(bindable, "delete-prev", s, NULL); | |
743 gnt_bindable_register_binding(bindable, "delete-prev", GNT_KEY_CTRL_H, NULL); | |
744 gnt_bindable_class_register_action(bindable, "delete-next", delkey, | |
745 GNT_KEY_DEL, NULL); | |
746 gnt_bindable_register_binding(bindable, "delete-next", GNT_KEY_CTRL_D, NULL); | |
747 gnt_bindable_class_register_action(bindable, "delete-start", del_to_home, | |
748 GNT_KEY_CTRL_U, NULL); | |
749 gnt_bindable_class_register_action(bindable, "delete-end", del_to_end, | |
750 GNT_KEY_CTRL_K, NULL); | |
751 gnt_bindable_class_register_action(bindable, "delete-prev-word", del_prev_word, | |
752 GNT_KEY_CTRL_W, NULL); | |
753 gnt_bindable_class_register_action(bindable, "cursor-prev-word", move_back_word, | |
754 "\033" "b", NULL); | |
755 gnt_bindable_class_register_action(bindable, "cursor-prev", move_back, | |
756 GNT_KEY_LEFT, NULL); | |
757 gnt_bindable_register_binding(bindable, "cursor-prev", GNT_KEY_CTRL_B, NULL); | |
758 gnt_bindable_class_register_action(bindable, "cursor-next", move_forward, | |
759 GNT_KEY_RIGHT, NULL); | |
760 gnt_bindable_register_binding(bindable, "cursor-next", GNT_KEY_CTRL_F, NULL); | |
761 gnt_bindable_class_register_action(bindable, "cursor-next-word", move_forward_word, | |
762 "\033" "f", NULL); | |
763 gnt_bindable_class_register_action(bindable, "delete-next-word", delete_forward_word, | |
764 "\033" "d", NULL); | |
765 gnt_bindable_class_register_action(bindable, "suggest-show", suggest_show, | |
766 "\t", NULL); | |
767 gnt_bindable_class_register_action(bindable, "suggest-next", suggest_next, | |
768 GNT_KEY_DOWN, NULL); | |
769 gnt_bindable_class_register_action(bindable, "suggest-prev", suggest_prev, | |
770 GNT_KEY_UP, NULL); | |
771 gnt_bindable_class_register_action(bindable, "history-prev", history_prev, | |
772 GNT_KEY_CTRL_DOWN, NULL); | |
773 gnt_bindable_class_register_action(bindable, "history-next", history_next, | |
774 GNT_KEY_CTRL_UP, NULL); | |
775 gnt_bindable_class_register_action(bindable, "clipboard-paste", clipboard_paste, | |
776 GNT_KEY_CTRL_V, NULL); | |
777 | |
778 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); | |
779 GNTDEBUG; | |
780 } | |
781 | |
782 static void | |
783 gnt_entry_init(GTypeInstance *instance, gpointer class) | |
784 { | |
785 GntWidget *widget = GNT_WIDGET(instance); | |
786 GntEntry *entry = GNT_ENTRY(instance); | |
787 | |
788 entry->flag = GNT_ENTRY_FLAG_ALL; | |
789 entry->max = 0; | |
790 | |
791 entry->histlength = 0; | |
792 entry->history = NULL; | |
793 | |
794 entry->word = TRUE; | |
795 entry->always = FALSE; | |
796 entry->suggests = NULL; | |
797 | |
798 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), | |
799 GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS); | |
800 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), GNT_WIDGET_GROW_X); | |
801 | |
802 widget->priv.minw = 3; | |
803 widget->priv.minh = 1; | |
804 | |
805 GNTDEBUG; | |
806 } | |
807 | |
808 /****************************************************************************** | |
809 * GntEntry API | |
810 *****************************************************************************/ | |
811 GType | |
812 gnt_entry_get_gtype(void) | |
813 { | |
814 static GType type = 0; | |
815 | |
816 if(type == 0) | |
817 { | |
818 static const GTypeInfo info = { | |
819 sizeof(GntEntryClass), | |
820 NULL, /* base_init */ | |
821 NULL, /* base_finalize */ | |
822 (GClassInitFunc)gnt_entry_class_init, | |
823 NULL, /* class_finalize */ | |
824 NULL, /* class_data */ | |
825 sizeof(GntEntry), | |
826 0, /* n_preallocs */ | |
827 gnt_entry_init, /* instance_init */ | |
828 NULL /* value_table */ | |
829 }; | |
830 | |
831 type = g_type_register_static(GNT_TYPE_WIDGET, | |
832 "GntEntry", | |
833 &info, 0); | |
834 } | |
835 | |
836 return type; | |
837 } | |
838 | |
839 GntWidget *gnt_entry_new(const char *text) | |
840 { | |
841 GntWidget *widget = g_object_new(GNT_TYPE_ENTRY, NULL); | |
842 GntEntry *entry = GNT_ENTRY(widget); | |
843 | |
844 gnt_entry_set_text_internal(entry, text); | |
845 | |
846 return widget; | |
847 } | |
848 | |
849 static void | |
850 gnt_entry_set_text_internal(GntEntry *entry, const char *text) | |
851 { | |
852 int len; | |
853 int scroll, cursor; | |
854 | |
855 g_free(entry->start); | |
856 | |
857 if (text && text[0]) | |
858 { | |
859 len = strlen(text); | |
860 } | |
861 else | |
862 { | |
863 len = 0; | |
864 } | |
865 | |
866 entry->buffer = len + 128; | |
867 | |
868 scroll = entry->scroll - entry->start; | |
869 cursor = entry->end - entry->cursor; | |
870 | |
871 entry->start = g_new0(char, entry->buffer); | |
872 if (text) | |
873 snprintf(entry->start, len + 1, "%s", text); | |
874 entry->end = entry->start + len; | |
875 | |
876 entry->scroll = entry->start + scroll; | |
877 entry->cursor = entry->end - cursor; | |
878 | |
879 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry), GNT_WIDGET_MAPPED)) | |
880 entry_redraw(GNT_WIDGET(entry)); | |
881 } | |
882 | |
883 void gnt_entry_set_text(GntEntry *entry, const char *text) | |
884 { | |
885 gboolean changed = TRUE; | |
886 if (text == NULL && entry->start == NULL) | |
887 changed = FALSE; | |
888 if (text && entry->start && g_utf8_collate(text, entry->start) == 0) | |
889 changed = FALSE; | |
890 gnt_entry_set_text_internal(entry, text); | |
891 if (changed) | |
892 entry_text_changed(entry); | |
893 } | |
894 | |
895 void gnt_entry_set_max(GntEntry *entry, int max) | |
896 { | |
897 entry->max = max; | |
898 } | |
899 | |
900 void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag) | |
901 { | |
902 entry->flag = flag; | |
903 /* XXX: Check the existing string to make sure the flags are respected? */ | |
904 } | |
905 | |
906 const char *gnt_entry_get_text(GntEntry *entry) | |
907 { | |
908 return entry->start; | |
909 } | |
910 | |
911 void gnt_entry_clear(GntEntry *entry) | |
912 { | |
913 gnt_entry_set_text_internal(entry, NULL); | |
914 entry->scroll = entry->cursor = entry->end = entry->start; | |
915 entry_redraw(GNT_WIDGET(entry)); | |
916 destroy_suggest(entry); | |
917 entry_text_changed(entry); | |
918 } | |
919 | |
920 void gnt_entry_set_masked(GntEntry *entry, gboolean set) | |
921 { | |
922 entry->masked = set; | |
923 } | |
924 | |
925 void gnt_entry_add_to_history(GntEntry *entry, const char *text) | |
926 { | |
927 g_return_if_fail(entry->history != NULL); /* Need to set_history_length first */ | |
928 | |
929 if (g_list_length(entry->history) >= entry->histlength) | |
930 return; | |
931 | |
932 entry->history = g_list_first(entry->history); | |
933 g_free(entry->history->data); | |
934 entry->history->data = g_strdup(text); | |
935 entry->history = g_list_prepend(entry->history, NULL); | |
936 } | |
937 | |
938 void gnt_entry_set_history_length(GntEntry *entry, int num) | |
939 { | |
940 if (num == 0) | |
941 { | |
942 entry->histlength = num; | |
943 if (entry->history) | |
944 { | |
945 entry->history = g_list_first(entry->history); | |
946 g_list_foreach(entry->history, (GFunc)g_free, NULL); | |
947 g_list_free(entry->history); | |
948 entry->history = NULL; | |
949 } | |
950 return; | |
951 } | |
952 | |
953 if (entry->histlength == 0) | |
954 { | |
955 entry->histlength = num; | |
956 entry->history = g_list_append(NULL, NULL); | |
957 return; | |
958 } | |
959 | |
960 if (num > 0 && num < entry->histlength) | |
961 { | |
962 GList *first, *iter; | |
963 int index = 0; | |
964 for (first = entry->history, index = 0; first->prev; first = first->prev, index++); | |
965 while ((iter = g_list_nth(first, num)) != NULL) | |
966 { | |
967 g_free(iter->data); | |
968 first = g_list_delete_link(first, iter); | |
969 } | |
970 entry->histlength = num; | |
971 if (index >= num) | |
972 entry->history = g_list_last(first); | |
973 return; | |
974 } | |
975 | |
976 entry->histlength = num; | |
977 } | |
978 | |
979 void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word) | |
980 { | |
981 entry->word = word; | |
982 } | |
983 | |
984 void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always) | |
985 { | |
986 entry->always = always; | |
987 } | |
988 | |
989 void gnt_entry_add_suggest(GntEntry *entry, const char *text) | |
990 { | |
991 GList *find; | |
992 | |
993 if (!text || !*text) | |
994 return; | |
995 | |
996 find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); | |
997 if (find) | |
998 return; | |
999 entry->suggests = g_list_append(entry->suggests, g_strdup(text)); | |
1000 } | |
1001 | |
1002 void gnt_entry_remove_suggest(GntEntry *entry, const char *text) | |
1003 { | |
1004 GList *find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); | |
1005 if (find) | |
1006 { | |
1007 g_free(find->data); | |
1008 entry->suggests = g_list_delete_link(entry->suggests, find); | |
1009 } | |
1010 } | |
1011 |