Mercurial > pidgin
comparison console/libgnt/gntentry.c @ 14091:ae4cbed1b309
[gaim-migrate @ 16715]
Add support for tab-completion and save-history in GntEntry.
Also, the keyboard-commands should now work for Xterms.
committer: Tailor Script <tailor@pidgin.im>
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Sat, 12 Aug 2006 10:27:29 +0000 |
parents | 27182f83b79b |
children | d0f3eba2717c |
comparison
equal
deleted
inserted
replaced
14090:983fbec46eb0 | 14091:ae4cbed1b309 |
---|---|
1 #include <ctype.h> | 1 #include <ctype.h> |
2 #include <string.h> | 2 #include <string.h> |
3 | 3 |
4 #include "gntbox.h" | |
4 #include "gntentry.h" | 5 #include "gntentry.h" |
6 #include "gnttree.h" | |
5 | 7 |
6 enum | 8 enum |
7 { | 9 { |
8 SIGS = 1, | 10 SIGS = 1, |
9 }; | 11 }; |
10 | 12 |
11 static GntWidgetClass *parent_class = NULL; | 13 static GntWidgetClass *parent_class = NULL; |
12 static guint signals[SIGS] = { 0 }; | 14 static guint signals[SIGS] = { 0 }; |
15 | |
16 static void | |
17 destroy_suggest(GntEntry *entry) | |
18 { | |
19 if (entry->ddown) | |
20 { | |
21 gnt_widget_destroy(entry->ddown->parent); | |
22 entry->ddown = NULL; | |
23 } | |
24 } | |
25 | |
26 static char * | |
27 get_beginning_of_word(GntEntry *entry) | |
28 { | |
29 char *s = entry->cursor; | |
30 while (s > entry->start) | |
31 { | |
32 char *t = g_utf8_find_prev_char(entry->start, s); | |
33 if ((*t < 'A' || *t > 'Z') && (*t < 'a' || *t > 'z')) | |
34 break; | |
35 s = t; | |
36 } | |
37 return s; | |
38 } | |
39 | |
40 static gboolean | |
41 show_suggest_dropdown(GntEntry *entry) | |
42 { | |
43 char *suggest = NULL; | |
44 int len; | |
45 int offset = 0, x, y; | |
46 int count = 0; | |
47 GList *iter; | |
48 | |
49 if (entry->word) | |
50 { | |
51 char *s = get_beginning_of_word(entry); | |
52 suggest = g_strndup(s, entry->cursor - s); | |
53 if (entry->scroll < s) | |
54 offset = g_utf8_pointer_to_offset(entry->scroll, s); | |
55 } | |
56 else | |
57 suggest = g_strdup(entry->start); | |
58 len = strlen(suggest); /* Don't need to use the utf8-function here */ | |
59 | |
60 if (entry->ddown == NULL) | |
61 { | |
62 GntWidget *box = gnt_vbox_new(FALSE); | |
63 entry->ddown = gnt_tree_new(); | |
64 gnt_box_add_widget(GNT_BOX(box), entry->ddown); | |
65 | |
66 GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); | |
67 | |
68 gnt_widget_get_position(GNT_WIDGET(entry), &x, &y); | |
69 x += offset; | |
70 y++; | |
71 if (y + 10 >= getmaxy(stdscr)) | |
72 y -= 11; | |
73 gnt_widget_set_position(box, x, y); | |
74 | |
75 gnt_widget_draw(box); | |
76 } | |
77 else | |
78 gnt_tree_remove_all(GNT_TREE(entry->ddown)); | |
79 | |
80 for (count = 0, iter = entry->suggests; iter; iter = iter->next) | |
81 { | |
82 const char *text = iter->data; | |
83 if (strncmp(suggest, text, len) == 0 && strlen(text) >= len) | |
84 { | |
85 gnt_tree_add_row_after(GNT_TREE(entry->ddown), (gpointer)text, | |
86 gnt_tree_create_row(GNT_TREE(entry->ddown), text), | |
87 NULL, NULL); | |
88 count++; | |
89 } | |
90 } | |
91 g_free(suggest); | |
92 | |
93 if (count == 0) | |
94 { | |
95 destroy_suggest(entry); | |
96 return FALSE; | |
97 } | |
98 | |
99 return TRUE; | |
100 } | |
13 | 101 |
14 static void | 102 static void |
15 gnt_entry_draw(GntWidget *widget) | 103 gnt_entry_draw(GntWidget *widget) |
16 { | 104 { |
17 GntEntry *entry = GNT_ENTRY(widget); | 105 GntEntry *entry = GNT_ENTRY(widget); |
78 { | 166 { |
79 int len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor; | 167 int len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor; |
80 memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1); | 168 memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1); |
81 entry->end -= len; | 169 entry->end -= len; |
82 entry_redraw(widget); | 170 entry_redraw(widget); |
171 | |
172 if (entry->ddown) | |
173 show_suggest_dropdown(entry); | |
174 | |
175 return TRUE; | |
83 } | 176 } |
84 else if (strcmp(text + 1, GNT_KEY_LEFT) == 0 && entry->cursor > entry->start) | 177 else if (strcmp(text + 1, GNT_KEY_LEFT) == 0 && entry->cursor > entry->start) |
85 { | 178 { |
86 entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor); | 179 entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor); |
87 if (entry->cursor < entry->scroll) | 180 if (entry->cursor < entry->scroll) |
88 entry->scroll = entry->cursor; | 181 entry->scroll = entry->cursor; |
89 entry_redraw(widget); | 182 entry_redraw(widget); |
183 | |
184 return TRUE; | |
90 } | 185 } |
91 else if (strcmp(text + 1, GNT_KEY_RIGHT) == 0 && entry->cursor < entry->end) | 186 else if (strcmp(text + 1, GNT_KEY_RIGHT) == 0 && entry->cursor < entry->end) |
92 { | 187 { |
93 entry->cursor = g_utf8_find_next_char(entry->cursor, NULL); | 188 entry->cursor = g_utf8_find_next_char(entry->cursor, NULL); |
94 if (g_utf8_pointer_to_offset(entry->scroll, entry->cursor) >= widget->priv.width) | 189 if (g_utf8_pointer_to_offset(entry->scroll, entry->cursor) >= widget->priv.width) |
95 entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); | 190 entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); |
96 entry_redraw(widget); | 191 entry_redraw(widget); |
192 | |
193 return TRUE; | |
194 } | |
195 else if (strcmp(text + 1, GNT_KEY_CTRL_DOWN) == 0 && entry->histlength) | |
196 { | |
197 if (entry->history->prev) | |
198 { | |
199 entry->history = entry->history->prev; | |
200 gnt_entry_set_text(entry, entry->history->data); | |
201 destroy_suggest(entry); | |
202 | |
203 return TRUE; | |
204 } | |
205 } | |
206 else if (strcmp(text + 1, GNT_KEY_UP) == 0 || | |
207 strcmp(text + 1, GNT_KEY_DOWN) == 0) | |
208 { | |
209 if (entry->ddown) | |
210 { | |
211 gnt_widget_key_pressed(entry->ddown, text); | |
212 return TRUE; | |
213 } | |
214 } | |
215 else if (strcmp(text + 1, GNT_KEY_CTRL_UP) == 0 && entry->histlength) | |
216 { | |
217 if (entry->history->next) | |
218 { | |
219 if (entry->history->prev == NULL) | |
220 { | |
221 /* Save the current contents */ | |
222 char *text = g_strdup(gnt_entry_get_text(entry)); | |
223 g_free(entry->history->data); | |
224 entry->history->data = text; | |
225 } | |
226 | |
227 entry->history = entry->history->next; | |
228 gnt_entry_set_text(entry, entry->history->data); | |
229 destroy_suggest(entry); | |
230 | |
231 return TRUE; | |
232 } | |
97 } | 233 } |
98 /* XXX: handle other keys, like home/end, and ctrl+ goodness */ | 234 /* XXX: handle other keys, like home/end, and ctrl+ goodness */ |
99 else | 235 else if (text[1] == 0) |
236 { | |
237 destroy_suggest(entry); | |
238 } | |
239 | |
240 return FALSE; | |
241 } | |
242 else | |
243 { | |
244 if (text[0] == '\t') | |
245 { | |
246 if (entry->ddown) | |
247 destroy_suggest(entry); | |
248 else if (entry->suggests) | |
249 return show_suggest_dropdown(entry); | |
250 | |
100 return FALSE; | 251 return FALSE; |
101 | 252 } |
102 return TRUE; | 253 else if (text[0] == '\r' && entry->ddown) |
103 } | 254 { |
104 else | 255 char *text = g_strdup(gnt_tree_get_selection_data(GNT_TREE(entry->ddown))); |
105 { | 256 destroy_suggest(entry); |
257 if (entry->word) | |
258 { | |
259 char *s = get_beginning_of_word(entry); | |
260 char *iter = text; | |
261 while (*s == *iter) | |
262 { | |
263 s++; | |
264 iter++; | |
265 } | |
266 gnt_entry_key_pressed(widget, iter); | |
267 } | |
268 else | |
269 { | |
270 gnt_entry_set_text(entry, text); | |
271 } | |
272 g_free(text); | |
273 return TRUE; | |
274 } | |
275 | |
106 if (!iscntrl(text[0])) | 276 if (!iscntrl(text[0])) |
107 { | 277 { |
108 const char *str, *next; | 278 const char *str, *next; |
109 | 279 |
110 for (str = text; *str;) | 280 for (str = text; *str;) |
141 while (str < next) | 311 while (str < next) |
142 *(entry->cursor++) = *str++; | 312 *(entry->cursor++) = *str++; |
143 | 313 |
144 while (g_utf8_pointer_to_offset(entry->scroll, entry->cursor) >= widget->priv.width) | 314 while (g_utf8_pointer_to_offset(entry->scroll, entry->cursor) >= widget->priv.width) |
145 entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); | 315 entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); |
316 | |
317 if (entry->ddown) | |
318 show_suggest_dropdown(entry); | |
146 } | 319 } |
147 entry_redraw(widget); | 320 entry_redraw(widget); |
148 return TRUE; | 321 return TRUE; |
149 } | 322 } |
150 else | 323 else |
159 | 332 |
160 if (entry->scroll > entry->start) | 333 if (entry->scroll > entry->start) |
161 entry->scroll = g_utf8_find_prev_char(entry->start, entry->scroll); | 334 entry->scroll = g_utf8_find_prev_char(entry->start, entry->scroll); |
162 | 335 |
163 entry_redraw(widget); | 336 entry_redraw(widget); |
337 if (entry->ddown) | |
338 show_suggest_dropdown(entry); | |
164 return TRUE; | 339 return TRUE; |
165 } | 340 } |
166 } | 341 } |
167 } | 342 } |
168 | 343 |
172 static void | 347 static void |
173 gnt_entry_destroy(GntWidget *widget) | 348 gnt_entry_destroy(GntWidget *widget) |
174 { | 349 { |
175 GntEntry *entry = GNT_ENTRY(widget); | 350 GntEntry *entry = GNT_ENTRY(widget); |
176 g_free(entry->start); | 351 g_free(entry->start); |
352 | |
353 if (entry->history) | |
354 { | |
355 entry->history = g_list_first(entry->history); | |
356 g_list_foreach(entry->history, (GFunc)g_free, NULL); | |
357 g_list_free(entry->history); | |
358 } | |
359 | |
360 if (entry->suggests) | |
361 { | |
362 g_list_foreach(entry->suggests, (GFunc)g_free, NULL); | |
363 g_list_free(entry->suggests); | |
364 } | |
365 | |
366 if (entry->ddown) | |
367 { | |
368 gnt_widget_destroy(entry->ddown->parent); | |
369 } | |
370 } | |
371 | |
372 static void | |
373 gnt_entry_lost_focus(GntWidget *widget) | |
374 { | |
375 GntEntry *entry = GNT_ENTRY(widget); | |
376 destroy_suggest(entry); | |
377 entry_redraw(widget); | |
177 } | 378 } |
178 | 379 |
179 static void | 380 static void |
180 gnt_entry_class_init(GntEntryClass *klass) | 381 gnt_entry_class_init(GntEntryClass *klass) |
181 { | 382 { |
183 parent_class->destroy = gnt_entry_destroy; | 384 parent_class->destroy = gnt_entry_destroy; |
184 parent_class->draw = gnt_entry_draw; | 385 parent_class->draw = gnt_entry_draw; |
185 parent_class->map = gnt_entry_map; | 386 parent_class->map = gnt_entry_map; |
186 parent_class->size_request = gnt_entry_size_request; | 387 parent_class->size_request = gnt_entry_size_request; |
187 parent_class->key_pressed = gnt_entry_key_pressed; | 388 parent_class->key_pressed = gnt_entry_key_pressed; |
389 parent_class->lost_focus = gnt_entry_lost_focus; | |
188 | 390 |
189 DEBUG; | 391 DEBUG; |
190 } | 392 } |
191 | 393 |
192 static void | 394 static void |
195 GntWidget *widget = GNT_WIDGET(instance); | 397 GntWidget *widget = GNT_WIDGET(instance); |
196 GntEntry *entry = GNT_ENTRY(instance); | 398 GntEntry *entry = GNT_ENTRY(instance); |
197 | 399 |
198 entry->flag = GNT_ENTRY_FLAG_ALL; | 400 entry->flag = GNT_ENTRY_FLAG_ALL; |
199 entry->max = 0; | 401 entry->max = 0; |
402 | |
403 entry->histlength = 0; | |
404 entry->history = NULL; | |
405 | |
406 entry->word = TRUE; | |
407 entry->always = FALSE; | |
408 entry->suggests = NULL; | |
200 | 409 |
201 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), | 410 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), |
202 GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS); | 411 GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS); |
203 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), GNT_WIDGET_GROW_X); | 412 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry), GNT_WIDGET_GROW_X); |
204 | 413 |
300 void gnt_entry_clear(GntEntry *entry) | 509 void gnt_entry_clear(GntEntry *entry) |
301 { | 510 { |
302 gnt_entry_set_text(entry, NULL); | 511 gnt_entry_set_text(entry, NULL); |
303 entry->scroll = entry->cursor = entry->end = entry->start; | 512 entry->scroll = entry->cursor = entry->end = entry->start; |
304 entry_redraw(GNT_WIDGET(entry)); | 513 entry_redraw(GNT_WIDGET(entry)); |
514 destroy_suggest(entry); | |
305 } | 515 } |
306 | 516 |
307 void gnt_entry_set_masked(GntEntry *entry, gboolean set) | 517 void gnt_entry_set_masked(GntEntry *entry, gboolean set) |
308 { | 518 { |
309 entry->masked = set; | 519 entry->masked = set; |
310 } | 520 } |
311 | 521 |
522 void gnt_entry_add_to_history(GntEntry *entry, const char *text) | |
523 { | |
524 g_return_if_fail(entry->history != NULL); /* Need to set_history_length first */ | |
525 | |
526 if (g_list_length(entry->history) >= entry->histlength) | |
527 return; | |
528 | |
529 entry->history = g_list_first(entry->history); | |
530 g_free(entry->history->data); | |
531 entry->history->data = g_strdup(text); | |
532 entry->history = g_list_prepend(entry->history, NULL); | |
533 } | |
534 | |
535 void gnt_entry_set_history_length(GntEntry *entry, int num) | |
536 { | |
537 if (num == 0) | |
538 { | |
539 entry->histlength = num; | |
540 if (entry->history) | |
541 { | |
542 entry->history = g_list_first(entry->history); | |
543 g_list_foreach(entry->history, (GFunc)g_free, NULL); | |
544 g_list_free(entry->history); | |
545 entry->history = NULL; | |
546 } | |
547 return; | |
548 } | |
549 | |
550 if (entry->histlength == 0) | |
551 { | |
552 entry->histlength = num; | |
553 entry->history = g_list_append(NULL, NULL); | |
554 return; | |
555 } | |
556 | |
557 if (num > 0 && num < entry->histlength) | |
558 { | |
559 GList *first, *iter; | |
560 int index = 0; | |
561 for (first = entry->history, index = 0; first->prev; first = first->prev, index++); | |
562 while ((iter = g_list_nth(first, num)) != NULL) | |
563 { | |
564 g_free(iter->data); | |
565 first = g_list_delete_link(first, iter); | |
566 } | |
567 entry->histlength = num; | |
568 if (index >= num) | |
569 entry->history = g_list_last(first); | |
570 return; | |
571 } | |
572 | |
573 entry->histlength = num; | |
574 } | |
575 | |
576 void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word) | |
577 { | |
578 entry->word = word; | |
579 } | |
580 | |
581 void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always) | |
582 { | |
583 entry->always = always; | |
584 } | |
585 | |
586 void gnt_entry_add_suggest(GntEntry *entry, const char *text) | |
587 { | |
588 GList *find; | |
589 | |
590 if (!text || !*text) | |
591 return; | |
592 | |
593 find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); | |
594 if (find) | |
595 return; | |
596 entry->suggests = g_list_append(entry->suggests, g_strdup(text)); | |
597 } | |
598 | |
599 void gnt_entry_remove_suggest(GntEntry *entry, const char *text) | |
600 { | |
601 GList *find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate); | |
602 if (find) | |
603 { | |
604 g_free(find->data); | |
605 entry->suggests = g_list_delete_link(entry->suggests, find); | |
606 } | |
607 } | |
608 |