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, entry->text_alloc);
43 GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
47 rec = g_new0(GUI_ENTRY_REC, 1);
51 rec->text_alloc = 1024;
52 rec->text = g_new(unichar, rec->text_alloc);
58 void gui_entry_destroy(GUI_ENTRY_REC *entry)
60 g_return_if_fail(entry != NULL);
62 if (active_entry == entry)
63 gui_entry_set_active(NULL);
66 g_free(entry->prompt);
70 /* Fixes the cursor position in screen */
71 static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
75 old_scrstart = entry->scrstart;
76 if (entry->pos - entry->scrstart < entry->width-2 - entry->promptlen &&
77 entry->pos - entry->scrstart > 0) {
78 entry->scrpos = entry->pos - entry->scrstart;
79 } else if (entry->pos < entry->width-1 - entry->promptlen) {
81 entry->scrpos = entry->pos;
83 entry->scrpos = (entry->width - entry->promptlen)*2/3;
84 entry->scrstart = entry->pos - entry->scrpos;
87 if (old_scrstart != entry->scrstart)
88 entry->redraw_needed_from = 0;
91 static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
96 xpos = entry->xpos + entry->promptlen + pos;
97 end_xpos = entry->xpos + entry->width;
101 term_set_color(root_window, ATTR_RESET);
102 term_move(root_window, xpos, entry->ypos);
104 p = entry->scrstart + pos < entry->text_len ?
105 entry->text + entry->scrstart + pos : empty_str;
106 for (; *p != '\0' && xpos < end_xpos; p++, xpos++) {
108 term_addch(root_window, ' ');
109 else if (*p >= 32 && (entry->utf8 || (*p & 127) >= 32))
110 term_add_unichar(root_window, *p);
112 term_set_color(root_window, ATTR_RESET|ATTR_REVERSE);
113 term_addch(root_window, *p+'A'-1);
114 term_set_color(root_window, ATTR_RESET);
118 /* clear the rest of the input line */
119 if (end_xpos == term_width)
120 term_clrtoeol(root_window);
122 while (xpos < end_xpos) {
123 term_addch(root_window, ' ');
129 static void gui_entry_draw(GUI_ENTRY_REC *entry)
131 if (entry->redraw_needed_from >= 0) {
132 gui_entry_draw_from(entry, entry->redraw_needed_from);
133 entry->redraw_needed_from = -1;
136 term_move_cursor(entry->xpos + entry->scrpos + entry->promptlen,
141 static void gui_entry_redraw_from(GUI_ENTRY_REC *entry, int pos)
143 pos -= entry->scrstart;
144 if (pos < 0) pos = 0;
146 if (entry->redraw_needed_from == -1 ||
147 entry->redraw_needed_from > pos)
148 entry->redraw_needed_from = pos;
151 void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width)
155 g_return_if_fail(entry != NULL);
157 if (entry->xpos != xpos || entry->ypos != ypos) {
158 /* position in screen changed - needs a full redraw */
161 entry->width = width;
162 gui_entry_redraw(entry);
166 if (entry->width == width)
167 return; /* no changes */
169 if (width > entry->width) {
170 /* input line grew - need to draw text at the end */
172 entry->width = width;
173 gui_entry_redraw_from(entry, old_width);
175 /* input line shrinked - make sure the cursor
176 is inside the input line */
177 entry->width = width;
178 if (entry->pos - entry->scrstart >
179 entry->width-2 - entry->promptlen) {
180 gui_entry_fix_cursor(entry);
184 gui_entry_draw(entry);
187 void gui_entry_set_active(GUI_ENTRY_REC *entry)
189 active_entry = entry;
192 term_move_cursor(entry->xpos + entry->scrpos +
193 entry->promptlen, entry->ypos);
198 void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str)
202 g_return_if_fail(entry != NULL);
204 oldlen = entry->promptlen;
206 g_free_not_null(entry->prompt);
207 entry->prompt = g_strdup(str);
208 entry->promptlen = format_get_length(str);
211 if (entry->prompt != NULL)
212 gui_printtext(entry->xpos, entry->ypos, entry->prompt);
214 if (entry->promptlen != oldlen) {
215 gui_entry_fix_cursor(entry);
216 gui_entry_draw(entry);
220 void gui_entry_set_hidden(GUI_ENTRY_REC *entry, int hidden)
222 g_return_if_fail(entry != NULL);
224 entry->hidden = hidden;
227 void gui_entry_set_utf8(GUI_ENTRY_REC *entry, int utf8)
229 g_return_if_fail(entry != NULL);
234 void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
236 g_return_if_fail(entry != NULL);
237 g_return_if_fail(str != NULL);
241 entry->text[0] = '\0';
243 gui_entry_insert_text(entry, str);
246 char *gui_entry_get_text(GUI_ENTRY_REC *entry)
251 g_return_val_if_fail(entry != NULL, NULL);
253 buf = g_malloc(entry->text_len*6 + 1);
255 utf16_to_utf8(entry->text, buf);
257 for (i = 0; i <= entry->text_len; i++)
258 buf[i] = entry->text[i];
263 void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
268 g_return_if_fail(entry != NULL);
269 g_return_if_fail(str != NULL);
271 gui_entry_redraw_from(entry, entry->pos);
273 len = !entry->utf8 ? strlen(str) : strlen_utf8(str);
274 entry_text_grow(entry, len);
276 /* make space for the string */
277 g_memmove(entry->text + entry->pos + len, entry->text + entry->pos,
278 (entry->text_len-entry->pos + 1) * sizeof(unichar));
281 for (i = 0; i < len; i++)
282 entry->text[entry->pos+i] = str[i];
284 chr = entry->text[entry->pos+len];
285 utf8_to_utf16(str, entry->text+entry->pos);
286 entry->text[entry->pos+len] = chr;
289 entry->text_len += len;
292 gui_entry_fix_cursor(entry);
293 gui_entry_draw(entry);
296 void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
298 g_return_if_fail(entry != NULL);
300 if (chr == 0 || chr == 13 || chr == 10)
301 return; /* never insert NUL, CR or LF characters */
303 gui_entry_redraw_from(entry, entry->pos);
305 entry_text_grow(entry, 1);
307 /* make space for the string */
308 g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
309 (entry->text_len-entry->pos + 1) * sizeof(unichar));
311 entry->text[entry->pos] = chr;
315 gui_entry_fix_cursor(entry);
316 gui_entry_draw(entry);
319 char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
324 g_return_val_if_fail(entry != NULL, NULL);
326 buf = g_malloc(entry->cutbuffer_len*6 + 1);
328 utf16_to_utf8(entry->cutbuffer, buf);
330 for (i = 0; i <= entry->cutbuffer_len; i++)
331 buf[i] = entry->cutbuffer[i];
336 void gui_entry_erase(GUI_ENTRY_REC *entry, int size)
338 g_return_if_fail(entry != NULL);
340 if (entry->pos < size)
343 /* put erased text to cutbuffer */
344 if (entry->cutbuffer == NULL || entry->cutbuffer_len < size) {
345 g_free(entry->cutbuffer);
346 entry->cutbuffer = g_new(unichar, size+1);
349 entry->cutbuffer_len = size;
350 entry->cutbuffer[size] = '\0';
351 memcpy(entry->cutbuffer, entry->text + entry->pos - size,
352 size * sizeof(unichar));
355 /* we just wanted to clear the cutbuffer */
359 g_memmove(entry->text + entry->pos - size, entry->text + entry->pos,
360 (entry->text_len-entry->pos+1) * sizeof(unichar));
363 entry->text_len -= size;
365 gui_entry_redraw_from(entry, entry->pos);
366 gui_entry_fix_cursor(entry);
367 gui_entry_draw(entry);
370 void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space)
374 g_return_if_fail(entry != NULL);
381 while (entry->text[to] == ' ' && to > 0)
383 while (entry->text[to] != ' ' && to > 0)
386 while (!i_isalnum(entry->text[to]) && to > 0)
388 while (i_isalnum(entry->text[to]) && to > 0)
393 gui_entry_erase(entry, entry->pos-to);
396 void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space)
400 g_return_if_fail(entry != NULL);
401 if (entry->pos == entry->text_len)
406 while (entry->text[to] == ' ' && to < entry->text_len)
408 while (entry->text[to] != ' ' && to < entry->text_len)
411 while (!i_isalnum(entry->text[to]) && to < entry->text_len)
413 while (i_isalnum(entry->text[to]) && to < entry->text_len)
417 size = to-entry->pos;
419 gui_entry_erase(entry, size);
422 void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
426 if (entry->pos == 0 || entry->text_len < 2)
429 if (entry->pos == entry->text_len)
433 chr = entry->text[entry->pos];
434 entry->text[entry->pos] = entry->text[entry->pos-1];
435 entry->text[entry->pos-1] = chr;
439 gui_entry_redraw_from(entry, entry->pos-2);
440 gui_entry_fix_cursor(entry);
441 gui_entry_draw(entry);
444 int gui_entry_get_pos(GUI_ENTRY_REC *entry)
446 g_return_val_if_fail(entry != NULL, 0);
451 void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos)
453 g_return_if_fail(entry != NULL);
455 if (pos >= 0 && pos <= entry->text_len)
458 gui_entry_fix_cursor(entry);
459 gui_entry_draw(entry);
462 void gui_entry_move_pos(GUI_ENTRY_REC *entry, int pos)
464 g_return_if_fail(entry != NULL);
466 if (entry->pos+pos >= 0 && entry->pos+pos <= entry->text_len)
469 gui_entry_fix_cursor(entry);
470 gui_entry_draw(entry);
473 static void gui_entry_move_words_left(GUI_ENTRY_REC *entry, int count, int to_space)
478 while (count > 0 && pos > 0) {
480 while (pos > 0 && entry->text[pos-1] == ' ')
482 while (pos > 0 && entry->text[pos-1] != ' ')
485 while (pos > 0 && !i_isalnum(entry->text[pos-1]))
487 while (pos > 0 && i_isalnum(entry->text[pos-1]))
496 static void gui_entry_move_words_right(GUI_ENTRY_REC *entry, int count, int to_space)
501 while (count > 0 && pos < entry->text_len) {
503 while (pos < entry->text_len && entry->text[pos] == ' ')
505 while (pos < entry->text_len && entry->text[pos] != ' ')
508 while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
510 while (pos < entry->text_len && i_isalnum(entry->text[pos]))
519 void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space)
521 g_return_if_fail(entry != NULL);
524 gui_entry_move_words_left(entry, -count, to_space);
526 gui_entry_move_words_right(entry, count, to_space);
528 gui_entry_fix_cursor(entry);
529 gui_entry_draw(entry);
532 void gui_entry_redraw(GUI_ENTRY_REC *entry)
534 g_return_if_fail(entry != NULL);
536 gui_entry_set_prompt(entry, NULL);
537 gui_entry_redraw_from(entry, 0);
538 gui_entry_fix_cursor(entry);
539 gui_entry_draw(entry);