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