4 Copyright (C) 1999 Timo Sirainen
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "gui-entry.h"
27 #include "gui-printtext.h"
30 const unichar empty_str[] = { 0 };
32 GUI_ENTRY_REC *active_entry;
34 static void entry_text_grow(GUI_ENTRY_REC *entry, int grow_size)
36 if (entry->text_len+grow_size < entry->text_alloc)
39 entry->text_alloc = nearest_power(entry->text_alloc+grow_size);
40 entry->text = g_realloc(entry->text,
41 sizeof(unichar) * entry->text_alloc);
44 GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
48 rec = g_new0(GUI_ENTRY_REC, 1);
52 rec->text_alloc = 1024;
53 rec->text = g_new(unichar, rec->text_alloc);
59 void gui_entry_destroy(GUI_ENTRY_REC *entry)
61 g_return_if_fail(entry != NULL);
63 if (active_entry == entry)
64 gui_entry_set_active(NULL);
67 g_free(entry->prompt);
71 /* Fixes the cursor position in screen */
72 static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
76 old_scrstart = entry->scrstart;
77 if (entry->pos - entry->scrstart < entry->width-2 - entry->promptlen &&
78 entry->pos - entry->scrstart > 0) {
79 entry->scrpos = entry->pos - entry->scrstart;
80 } else if (entry->pos < entry->width-1 - entry->promptlen) {
82 entry->scrpos = entry->pos;
84 entry->scrpos = (entry->width - entry->promptlen)*2/3;
85 entry->scrstart = entry->pos - entry->scrpos;
88 if (old_scrstart != entry->scrstart)
89 entry->redraw_needed_from = 0;
92 static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
97 xpos = entry->xpos + entry->promptlen + pos;
98 end_xpos = entry->xpos + entry->width;
102 term_set_color(root_window, ATTR_RESET);
103 term_move(root_window, xpos, entry->ypos);
105 p = entry->scrstart + pos < entry->text_len ?
106 entry->text + entry->scrstart + pos : empty_str;
107 for (; *p != '\0' && xpos < end_xpos; p++, xpos++) {
109 term_addch(root_window, ' ');
110 else if (*p >= 32 && (entry->utf8 || (*p & 127) >= 32))
111 term_add_unichar(root_window, *p);
113 term_set_color(root_window, ATTR_RESET|ATTR_REVERSE);
114 term_addch(root_window, *p+'A'-1);
115 term_set_color(root_window, ATTR_RESET);
119 /* clear the rest of the input line */
120 if (end_xpos == term_width)
121 term_clrtoeol(root_window);
123 while (xpos < end_xpos) {
124 term_addch(root_window, ' ');
130 static void gui_entry_draw(GUI_ENTRY_REC *entry)
132 if (entry->redraw_needed_from >= 0) {
133 gui_entry_draw_from(entry, entry->redraw_needed_from);
134 entry->redraw_needed_from = -1;
137 term_move_cursor(entry->xpos + entry->scrpos + entry->promptlen,
142 static void gui_entry_redraw_from(GUI_ENTRY_REC *entry, int pos)
144 pos -= entry->scrstart;
145 if (pos < 0) pos = 0;
147 if (entry->redraw_needed_from == -1 ||
148 entry->redraw_needed_from > pos)
149 entry->redraw_needed_from = pos;
152 void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width)
156 g_return_if_fail(entry != NULL);
158 if (entry->xpos != xpos || entry->ypos != ypos) {
159 /* position in screen changed - needs a full redraw */
162 entry->width = width;
163 gui_entry_redraw(entry);
167 if (entry->width == width)
168 return; /* no changes */
170 if (width > entry->width) {
171 /* input line grew - need to draw text at the end */
173 entry->width = width;
174 gui_entry_redraw_from(entry, old_width);
176 /* input line shrinked - make sure the cursor
177 is inside the input line */
178 entry->width = width;
179 if (entry->pos - entry->scrstart >
180 entry->width-2 - entry->promptlen) {
181 gui_entry_fix_cursor(entry);
185 gui_entry_draw(entry);
188 void gui_entry_set_active(GUI_ENTRY_REC *entry)
190 active_entry = entry;
193 term_move_cursor(entry->xpos + entry->scrpos +
194 entry->promptlen, entry->ypos);
199 void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str)
203 g_return_if_fail(entry != NULL);
205 oldlen = entry->promptlen;
207 g_free_not_null(entry->prompt);
208 entry->prompt = g_strdup(str);
209 entry->promptlen = format_get_length(str);
212 if (entry->prompt != NULL)
213 gui_printtext(entry->xpos, entry->ypos, entry->prompt);
215 if (entry->promptlen != oldlen) {
216 gui_entry_fix_cursor(entry);
217 gui_entry_draw(entry);
221 void gui_entry_set_hidden(GUI_ENTRY_REC *entry, int hidden)
223 g_return_if_fail(entry != NULL);
225 entry->hidden = hidden;
228 void gui_entry_set_utf8(GUI_ENTRY_REC *entry, int utf8)
230 g_return_if_fail(entry != NULL);
235 void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
237 g_return_if_fail(entry != NULL);
238 g_return_if_fail(str != NULL);
242 entry->text[0] = '\0';
244 gui_entry_insert_text(entry, str);
247 char *gui_entry_get_text(GUI_ENTRY_REC *entry)
252 g_return_val_if_fail(entry != NULL, NULL);
254 buf = g_malloc(entry->text_len*6 + 1);
256 utf16_to_utf8(entry->text, buf);
258 for (i = 0; i <= entry->text_len; i++)
259 buf[i] = entry->text[i];
264 void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
269 g_return_if_fail(entry != NULL);
270 g_return_if_fail(str != NULL);
272 gui_entry_redraw_from(entry, entry->pos);
274 len = !entry->utf8 ? strlen(str) : strlen_utf8(str);
275 entry_text_grow(entry, len);
277 /* make space for the string */
278 g_memmove(entry->text + entry->pos + len, entry->text + entry->pos,
279 (entry->text_len-entry->pos + 1) * sizeof(unichar));
282 for (i = 0; i < len; i++)
283 entry->text[entry->pos+i] = str[i];
285 chr = entry->text[entry->pos+len];
286 utf8_to_utf16(str, entry->text+entry->pos);
287 entry->text[entry->pos+len] = chr;
290 entry->text_len += len;
293 gui_entry_fix_cursor(entry);
294 gui_entry_draw(entry);
297 void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
299 g_return_if_fail(entry != NULL);
301 if (chr == 0 || chr == 13 || chr == 10)
302 return; /* never insert NUL, CR or LF characters */
304 gui_entry_redraw_from(entry, entry->pos);
306 entry_text_grow(entry, 1);
308 /* make space for the string */
309 g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
310 (entry->text_len-entry->pos + 1) * sizeof(unichar));
312 entry->text[entry->pos] = chr;
316 gui_entry_fix_cursor(entry);
317 gui_entry_draw(entry);
320 char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
325 g_return_val_if_fail(entry != NULL, NULL);
327 if (entry->cutbuffer == NULL)
330 buf = g_malloc(entry->cutbuffer_len*6 + 1);
332 utf16_to_utf8(entry->cutbuffer, buf);
334 for (i = 0; i <= entry->cutbuffer_len; i++)
335 buf[i] = entry->cutbuffer[i];
340 void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer)
342 g_return_if_fail(entry != NULL);
344 if (entry->pos < size)
347 if (update_cutbuffer) {
348 /* put erased text to cutbuffer */
349 if (entry->cutbuffer == NULL || entry->cutbuffer_len < size) {
350 g_free(entry->cutbuffer);
351 entry->cutbuffer = g_new(unichar, size+1);
354 entry->cutbuffer_len = size;
355 entry->cutbuffer[size] = '\0';
356 memcpy(entry->cutbuffer, entry->text + entry->pos - size,
357 size * sizeof(unichar));
361 /* we just wanted to clear the cutbuffer */
365 g_memmove(entry->text + entry->pos - size, entry->text + entry->pos,
366 (entry->text_len-entry->pos+1) * sizeof(unichar));
369 entry->text_len -= size;
371 gui_entry_redraw_from(entry, entry->pos);
372 gui_entry_fix_cursor(entry);
373 gui_entry_draw(entry);
376 void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space)
380 g_return_if_fail(entry != NULL);
387 while (entry->text[to] == ' ' && to > 0)
389 while (entry->text[to] != ' ' && to > 0)
392 while (!i_isalnum(entry->text[to]) && to > 0)
394 while (i_isalnum(entry->text[to]) && to > 0)
399 gui_entry_erase(entry, entry->pos-to, TRUE);
402 void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space)
406 g_return_if_fail(entry != NULL);
407 if (entry->pos == entry->text_len)
412 while (entry->text[to] == ' ' && to < entry->text_len)
414 while (entry->text[to] != ' ' && to < entry->text_len)
417 while (!i_isalnum(entry->text[to]) && to < entry->text_len)
419 while (i_isalnum(entry->text[to]) && to < entry->text_len)
423 size = to-entry->pos;
425 gui_entry_erase(entry, size, TRUE);
428 void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
432 if (entry->pos == 0 || entry->text_len < 2)
435 if (entry->pos == entry->text_len)
439 chr = entry->text[entry->pos];
440 entry->text[entry->pos] = entry->text[entry->pos-1];
441 entry->text[entry->pos-1] = chr;
445 gui_entry_redraw_from(entry, entry->pos-2);
446 gui_entry_fix_cursor(entry);
447 gui_entry_draw(entry);
450 int gui_entry_get_pos(GUI_ENTRY_REC *entry)
452 g_return_val_if_fail(entry != NULL, 0);
457 void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos)
459 g_return_if_fail(entry != NULL);
461 if (pos >= 0 && pos <= entry->text_len)
464 gui_entry_fix_cursor(entry);
465 gui_entry_draw(entry);
468 void gui_entry_move_pos(GUI_ENTRY_REC *entry, int pos)
470 g_return_if_fail(entry != NULL);
472 if (entry->pos+pos >= 0 && entry->pos+pos <= entry->text_len)
475 gui_entry_fix_cursor(entry);
476 gui_entry_draw(entry);
479 static void gui_entry_move_words_left(GUI_ENTRY_REC *entry, int count, int to_space)
484 while (count > 0 && pos > 0) {
486 while (pos > 0 && entry->text[pos-1] == ' ')
488 while (pos > 0 && entry->text[pos-1] != ' ')
491 while (pos > 0 && !i_isalnum(entry->text[pos-1]))
493 while (pos > 0 && i_isalnum(entry->text[pos-1]))
502 static void gui_entry_move_words_right(GUI_ENTRY_REC *entry, int count, int to_space)
507 while (count > 0 && pos < entry->text_len) {
509 while (pos < entry->text_len && entry->text[pos] == ' ')
511 while (pos < entry->text_len && entry->text[pos] != ' ')
514 while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
516 while (pos < entry->text_len && i_isalnum(entry->text[pos]))
525 void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space)
527 g_return_if_fail(entry != NULL);
530 gui_entry_move_words_left(entry, -count, to_space);
532 gui_entry_move_words_right(entry, count, to_space);
534 gui_entry_fix_cursor(entry);
535 gui_entry_draw(entry);
538 void gui_entry_redraw(GUI_ENTRY_REC *entry)
540 g_return_if_fail(entry != NULL);
542 gui_entry_set_prompt(entry, NULL);
543 gui_entry_redraw_from(entry, 0);
544 gui_entry_fix_cursor(entry);
545 gui_entry_draw(entry);