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'; p++) {
108 xpos += utf8_width(*p);
113 term_addch(root_window, ' ');
114 else if (*p >= 32 && (entry->utf8 || (*p & 127) >= 32))
115 term_add_unichar(root_window, *p);
117 term_set_color(root_window, ATTR_RESET|ATTR_REVERSE);
118 term_addch(root_window, *p+'A'-1);
119 term_set_color(root_window, ATTR_RESET);
123 /* clear the rest of the input line */
124 if (end_xpos == term_width)
125 term_clrtoeol(root_window);
127 while (xpos < end_xpos) {
128 term_addch(root_window, ' ');
134 static void gui_entry_draw(GUI_ENTRY_REC *entry)
136 if (entry->redraw_needed_from >= 0) {
137 gui_entry_draw_from(entry, entry->redraw_needed_from);
138 entry->redraw_needed_from = -1;
141 term_move_cursor(entry->xpos + entry->scrpos + entry->promptlen,
146 static void gui_entry_redraw_from(GUI_ENTRY_REC *entry, int pos)
148 pos -= entry->scrstart;
149 if (pos < 0) pos = 0;
151 if (entry->redraw_needed_from == -1 ||
152 entry->redraw_needed_from > pos)
153 entry->redraw_needed_from = pos;
156 void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width)
160 g_return_if_fail(entry != NULL);
162 if (entry->xpos != xpos || entry->ypos != ypos) {
163 /* position in screen changed - needs a full redraw */
166 entry->width = width;
167 gui_entry_redraw(entry);
171 if (entry->width == width)
172 return; /* no changes */
174 if (width > entry->width) {
175 /* input line grew - need to draw text at the end */
177 entry->width = width;
178 gui_entry_redraw_from(entry, old_width);
180 /* input line shrinked - make sure the cursor
181 is inside the input line */
182 entry->width = width;
183 if (entry->pos - entry->scrstart >
184 entry->width-2 - entry->promptlen) {
185 gui_entry_fix_cursor(entry);
189 gui_entry_draw(entry);
192 void gui_entry_set_active(GUI_ENTRY_REC *entry)
194 active_entry = entry;
197 term_move_cursor(entry->xpos + entry->scrpos +
198 entry->promptlen, entry->ypos);
203 void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str)
207 g_return_if_fail(entry != NULL);
209 oldlen = entry->promptlen;
211 g_free_not_null(entry->prompt);
212 entry->prompt = g_strdup(str);
213 entry->promptlen = format_get_length(str);
216 if (entry->prompt != NULL)
217 gui_printtext(entry->xpos, entry->ypos, entry->prompt);
219 if (entry->promptlen != oldlen) {
220 gui_entry_fix_cursor(entry);
221 gui_entry_draw(entry);
225 void gui_entry_set_hidden(GUI_ENTRY_REC *entry, int hidden)
227 g_return_if_fail(entry != NULL);
229 entry->hidden = hidden;
232 void gui_entry_set_utf8(GUI_ENTRY_REC *entry, int utf8)
234 g_return_if_fail(entry != NULL);
239 void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
241 g_return_if_fail(entry != NULL);
242 g_return_if_fail(str != NULL);
246 entry->text[0] = '\0';
248 gui_entry_insert_text(entry, str);
251 char *gui_entry_get_text(GUI_ENTRY_REC *entry)
256 g_return_val_if_fail(entry != NULL, NULL);
258 buf = g_malloc(entry->text_len*6 + 1);
260 utf16_to_utf8(entry->text, buf);
262 for (i = 0; i <= entry->text_len; i++)
263 buf[i] = entry->text[i];
268 void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
273 g_return_if_fail(entry != NULL);
274 g_return_if_fail(str != NULL);
276 gui_entry_redraw_from(entry, entry->pos);
278 len = !entry->utf8 ? strlen(str) : strlen_utf8(str);
279 entry_text_grow(entry, len);
281 /* make space for the string */
282 g_memmove(entry->text + entry->pos + len, entry->text + entry->pos,
283 (entry->text_len-entry->pos + 1) * sizeof(unichar));
286 for (i = 0; i < len; i++)
287 entry->text[entry->pos+i] = str[i];
289 chr = entry->text[entry->pos+len];
290 utf8_to_utf16(str, entry->text+entry->pos);
291 entry->text[entry->pos+len] = chr;
294 entry->text_len += len;
297 gui_entry_fix_cursor(entry);
298 gui_entry_draw(entry);
301 void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
303 g_return_if_fail(entry != NULL);
305 if (chr == 0 || chr == 13 || chr == 10)
306 return; /* never insert NUL, CR or LF characters */
308 gui_entry_redraw_from(entry, entry->pos);
310 entry_text_grow(entry, 1);
312 /* make space for the string */
313 g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
314 (entry->text_len-entry->pos + 1) * sizeof(unichar));
316 entry->text[entry->pos] = chr;
320 gui_entry_fix_cursor(entry);
321 gui_entry_draw(entry);
324 char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
329 g_return_val_if_fail(entry != NULL, NULL);
331 if (entry->cutbuffer == NULL)
334 buf = g_malloc(entry->cutbuffer_len*6 + 1);
336 utf16_to_utf8(entry->cutbuffer, buf);
338 for (i = 0; i <= entry->cutbuffer_len; i++)
339 buf[i] = entry->cutbuffer[i];
344 void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer)
346 g_return_if_fail(entry != NULL);
348 if (entry->pos < size)
351 if (update_cutbuffer) {
352 /* put erased text to cutbuffer */
353 if (entry->cutbuffer == NULL || entry->cutbuffer_len < size) {
354 g_free(entry->cutbuffer);
355 entry->cutbuffer = g_new(unichar, size+1);
358 entry->cutbuffer_len = size;
359 entry->cutbuffer[size] = '\0';
360 memcpy(entry->cutbuffer, entry->text + entry->pos - size,
361 size * sizeof(unichar));
365 /* we just wanted to clear the cutbuffer */
369 g_memmove(entry->text + entry->pos - size, entry->text + entry->pos,
370 (entry->text_len-entry->pos+1) * sizeof(unichar));
373 entry->text_len -= size;
375 gui_entry_redraw_from(entry, entry->pos);
376 gui_entry_fix_cursor(entry);
377 gui_entry_draw(entry);
380 void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space)
384 g_return_if_fail(entry != NULL);
391 while (entry->text[to] == ' ' && to > 0)
393 while (entry->text[to] != ' ' && to > 0)
396 while (!i_isalnum(entry->text[to]) && to > 0)
398 while (i_isalnum(entry->text[to]) && to > 0)
403 gui_entry_erase(entry, entry->pos-to, TRUE);
406 void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space)
410 g_return_if_fail(entry != NULL);
411 if (entry->pos == entry->text_len)
416 while (entry->text[to] == ' ' && to < entry->text_len)
418 while (entry->text[to] != ' ' && to < entry->text_len)
421 while (!i_isalnum(entry->text[to]) && to < entry->text_len)
423 while (i_isalnum(entry->text[to]) && to < entry->text_len)
427 size = to-entry->pos;
429 gui_entry_erase(entry, size, TRUE);
432 void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
436 if (entry->pos == 0 || entry->text_len < 2)
439 if (entry->pos == entry->text_len)
443 chr = entry->text[entry->pos];
444 entry->text[entry->pos] = entry->text[entry->pos-1];
445 entry->text[entry->pos-1] = chr;
449 gui_entry_redraw_from(entry, entry->pos-2);
450 gui_entry_fix_cursor(entry);
451 gui_entry_draw(entry);
454 int gui_entry_get_pos(GUI_ENTRY_REC *entry)
456 g_return_val_if_fail(entry != NULL, 0);
461 void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos)
463 g_return_if_fail(entry != NULL);
465 if (pos >= 0 && pos <= entry->text_len)
468 gui_entry_fix_cursor(entry);
469 gui_entry_draw(entry);
472 void gui_entry_move_pos(GUI_ENTRY_REC *entry, int pos)
474 g_return_if_fail(entry != NULL);
476 if (entry->pos+pos >= 0 && entry->pos+pos <= entry->text_len)
479 gui_entry_fix_cursor(entry);
480 gui_entry_draw(entry);
483 static void gui_entry_move_words_left(GUI_ENTRY_REC *entry, int count, int to_space)
488 while (count > 0 && pos > 0) {
490 while (pos > 0 && entry->text[pos-1] == ' ')
492 while (pos > 0 && entry->text[pos-1] != ' ')
495 while (pos > 0 && !i_isalnum(entry->text[pos-1]))
497 while (pos > 0 && i_isalnum(entry->text[pos-1]))
506 static void gui_entry_move_words_right(GUI_ENTRY_REC *entry, int count, int to_space)
511 while (count > 0 && pos < entry->text_len) {
513 while (pos < entry->text_len && entry->text[pos] == ' ')
515 while (pos < entry->text_len && entry->text[pos] != ' ')
518 while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
520 while (pos < entry->text_len && i_isalnum(entry->text[pos]))
529 void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space)
531 g_return_if_fail(entry != NULL);
534 gui_entry_move_words_left(entry, -count, to_space);
536 gui_entry_move_words_right(entry, count, to_space);
538 gui_entry_fix_cursor(entry);
539 gui_entry_draw(entry);
542 void gui_entry_redraw(GUI_ENTRY_REC *entry)
544 g_return_if_fail(entry != NULL);
546 gui_entry_set_prompt(entry, NULL);
547 gui_entry_redraw_from(entry, 0);
548 gui_entry_fix_cursor(entry);
549 gui_entry_draw(entry);