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);
72
#define big5_width(ch) ((ch)>0xff ? 2:1)
74
void unichars_to_big5(const unichar *str, char *out)
76
for (; *str != '\0'; str++) {
78
*out++ = (*str >> 8) & 0xff;
84
int strlen_big5(const unsigned char *str)
88
if (term_type != TERM_TYPE_BIG5)
91
while (*str != '\0') {
92
if (is_big5(str[0], str[1]))
100
void big5_to_unichars(const char *str, unichar *out)
102
const unsigned char *p = (const unsigned char *) str;
105
if (is_big5(p[0], p[1])) {
106
*out++ = p[0] << 8 | p[1];
115
/* ----------------------------- */
117
static int pos2scrpos(GUI_ENTRY_REC *entry, int pos)
122
for (p = entry->text; p - entry->text < pos; p++) {
123
if (term_type == TERM_TYPE_BIG5)
124
xpos += big5_width(*p);
125
else if (entry->utf8)
126
xpos += utf8_width(*p);
133
static int scrpos2pos(GUI_ENTRY_REC *entry, int pos)
137
for (i = 0, xpos = 0; entry->text[i]; i++) {
138
unichar *p = entry->text+i;
140
if (term_type == TERM_TYPE_BIG5)
141
width = big5_width(*p);
142
else if (entry->utf8)
143
width = utf8_width(*p);
147
if (xpos + width > pos)
158
/* Fixes the cursor position in screen */
159
static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
163
/* assume prompt len == prompt scrlen */
164
int start = pos2scrpos(entry, entry->scrstart);
165
int now = pos2scrpos(entry, entry->pos);
167
old_scrstart = entry->scrstart;
168
if (now-start < entry->width - 2 - entry->promptlen && now-start > 0)
169
entry->scrpos = now-start;
170
else if (now < entry->width - 1 - entry->promptlen) {
174
entry->scrstart = scrpos2pos(entry, now-(entry->width -
175
entry->promptlen)*2/3);
176
start = pos2scrpos(entry, entry->scrstart);
177
entry->scrpos = now - start;
180
if (old_scrstart != entry->scrstart)
181
entry->redraw_needed_from = 0;
184
static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
189
xpos = entry->xpos + entry->promptlen +
190
pos2scrpos(entry, pos + entry->scrstart) -
191
pos2scrpos(entry, entry->scrstart);
192
end_xpos = entry->xpos + entry->width;
197
term_set_color(root_window, ATTR_RESET);
198
term_move(root_window, xpos, entry->ypos);
200
p = entry->scrstart + pos < entry->text_len ?
201
entry->text + entry->scrstart + pos : empty_str;
202
for (; *p != '\0'; p++) {
205
else if (term_type == TERM_TYPE_BIG5)
206
xpos += big5_width(*p);
207
else if (entry->utf8)
208
xpos += utf8_width(*p);
216
term_addch(root_window, ' ');
217
else if (*p >= 32 && (entry->utf8 || (*p & 127) >= 32))
218
term_add_unichar(root_window, *p);
220
term_set_color(root_window, ATTR_RESET|ATTR_REVERSE);
221
term_addch(root_window, *p+'A'-1);
222
term_set_color(root_window, ATTR_RESET);
226
/* clear the rest of the input line */
227
if (end_xpos == term_width)
228
term_clrtoeol(root_window);
230
while (xpos < end_xpos) {
231
term_addch(root_window, ' ');
237
static void gui_entry_draw(GUI_ENTRY_REC *entry)
239
if (entry->redraw_needed_from >= 0) {
240
gui_entry_draw_from(entry, entry->redraw_needed_from);
241
entry->redraw_needed_from = -1;
244
term_move_cursor(entry->xpos + entry->scrpos + entry->promptlen,
249
static void gui_entry_redraw_from(GUI_ENTRY_REC *entry, int pos)
251
pos -= entry->scrstart;
252
if (pos < 0) pos = 0;
254
if (entry->redraw_needed_from == -1 ||
255
entry->redraw_needed_from > pos)
256
entry->redraw_needed_from = pos;
259
void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width)
263
g_return_if_fail(entry != NULL);
265
if (entry->xpos != xpos || entry->ypos != ypos) {
266
/* position in screen changed - needs a full redraw */
269
entry->width = width;
270
gui_entry_redraw(entry);
274
if (entry->width == width)
275
return; /* no changes */
277
if (width > entry->width) {
278
/* input line grew - need to draw text at the end */
280
entry->width = width;
281
gui_entry_redraw_from(entry, old_width);
283
/* input line shrinked - make sure the cursor
284
is inside the input line */
285
entry->width = width;
286
if (entry->pos - entry->scrstart >
287
entry->width-2 - entry->promptlen) {
288
gui_entry_fix_cursor(entry);
292
gui_entry_draw(entry);
295
void gui_entry_set_active(GUI_ENTRY_REC *entry)
297
active_entry = entry;
300
term_move_cursor(entry->xpos + entry->scrpos +
301
entry->promptlen, entry->ypos);
306
void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str)
310
g_return_if_fail(entry != NULL);
312
oldlen = entry->promptlen;
314
g_free_not_null(entry->prompt);
315
entry->prompt = g_strdup(str);
316
entry->promptlen = format_get_length(str);
319
if (entry->prompt != NULL)
320
gui_printtext(entry->xpos, entry->ypos, entry->prompt);
322
if (entry->promptlen != oldlen) {
323
gui_entry_fix_cursor(entry);
324
gui_entry_draw(entry);
328
void gui_entry_set_hidden(GUI_ENTRY_REC *entry, int hidden)
330
g_return_if_fail(entry != NULL);
332
entry->hidden = hidden;
335
void gui_entry_set_utf8(GUI_ENTRY_REC *entry, int utf8)
337
g_return_if_fail(entry != NULL);
342
void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
344
g_return_if_fail(entry != NULL);
345
g_return_if_fail(str != NULL);
349
entry->text[0] = '\0';
351
gui_entry_insert_text(entry, str);
354
char *gui_entry_get_text(GUI_ENTRY_REC *entry)
359
g_return_val_if_fail(entry != NULL, NULL);
361
buf = g_malloc(entry->text_len*6 + 1);
363
utf16_to_utf8(entry->text, buf);
365
if (term_type == TERM_TYPE_BIG5)
366
unichars_to_big5(entry->text, buf);
368
for (i = 0; i <= entry->text_len; i++)
369
buf[i] = entry->text[i];
374
void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
379
g_return_if_fail(entry != NULL);
380
g_return_if_fail(str != NULL);
382
gui_entry_redraw_from(entry, entry->pos);
384
len = !entry->utf8 ? strlen_big5(str) : strlen_utf8(str);
385
entry_text_grow(entry, len);
387
/* make space for the string */
388
g_memmove(entry->text + entry->pos + len, entry->text + entry->pos,
389
(entry->text_len-entry->pos + 1) * sizeof(unichar));
392
if (term_type == TERM_TYPE_BIG5) {
393
chr = entry->text[entry->pos + len];
394
big5_to_unichars(str, entry->text + entry->pos);
395
entry->text[entry->pos + len] = chr;
397
for (i = 0; i < len; i++)
398
entry->text[entry->pos + i] = str[i];
401
chr = entry->text[entry->pos+len];
402
utf8_to_utf16(str, entry->text+entry->pos);
403
entry->text[entry->pos+len] = chr;
406
entry->text_len += len;
409
gui_entry_fix_cursor(entry);
410
gui_entry_draw(entry);
413
void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
415
g_return_if_fail(entry != NULL);
417
if (chr == 0 || chr == 13 || chr == 10)
418
return; /* never insert NUL, CR or LF characters */
420
gui_entry_redraw_from(entry, entry->pos);
422
entry_text_grow(entry, 1);
424
/* make space for the string */
425
g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
426
(entry->text_len-entry->pos + 1) * sizeof(unichar));
428
entry->text[entry->pos] = chr;
432
gui_entry_fix_cursor(entry);
433
gui_entry_draw(entry);
436
char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
441
g_return_val_if_fail(entry != NULL, NULL);
443
if (entry->cutbuffer == NULL)
446
buf = g_malloc(entry->cutbuffer_len*6 + 1);
448
utf16_to_utf8(entry->cutbuffer, buf);
449
else if (term_type == TERM_TYPE_BIG5) {
450
unichars_to_big5(entry->cutbuffer, buf);
452
for (i = 0; i <= entry->cutbuffer_len; i++)
453
buf[i] = entry->cutbuffer[i];
458
void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer)
460
int newpos, size = 0;
462
g_return_if_fail(entry != NULL);
464
for (newpos = gui_entry_get_pos(entry); newpos > pos; size++)
466
gui_entry_erase(entry, size, update_cutbuffer);
469
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer)
471
g_return_if_fail(entry != NULL);
473
if (entry->pos < size)
476
if (update_cutbuffer) {
477
/* put erased text to cutbuffer */
478
if (entry->cutbuffer == NULL || entry->cutbuffer_len < size) {
479
g_free(entry->cutbuffer);
480
entry->cutbuffer = g_new(unichar, size+1);
483
entry->cutbuffer_len = size;
484
entry->cutbuffer[size] = '\0';
485
memcpy(entry->cutbuffer, entry->text + entry->pos - size,
486
size * sizeof(unichar));
490
/* we just wanted to clear the cutbuffer */
494
g_memmove(entry->text + entry->pos - size, entry->text + entry->pos,
495
(entry->text_len-entry->pos+1) * sizeof(unichar));
498
entry->text_len -= size;
500
gui_entry_redraw_from(entry, entry->pos);
501
gui_entry_fix_cursor(entry);
502
gui_entry_draw(entry);
505
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space)
509
g_return_if_fail(entry != NULL);
516
while (entry->text[to] == ' ' && to > 0)
518
while (entry->text[to] != ' ' && to > 0)
521
while (!i_isalnum(entry->text[to]) && to > 0)
523
while (i_isalnum(entry->text[to]) && to > 0)
528
gui_entry_erase(entry, entry->pos-to, TRUE);
531
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space)
535
g_return_if_fail(entry != NULL);
536
if (entry->pos == entry->text_len)
541
while (entry->text[to] == ' ' && to < entry->text_len)
543
while (entry->text[to] != ' ' && to < entry->text_len)
546
while (!i_isalnum(entry->text[to]) && to < entry->text_len)
548
while (i_isalnum(entry->text[to]) && to < entry->text_len)
552
size = to-entry->pos;
554
gui_entry_erase(entry, size, TRUE);
557
void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
561
if (entry->pos == 0 || entry->text_len < 2)
564
if (entry->pos == entry->text_len)
568
chr = entry->text[entry->pos];
569
entry->text[entry->pos] = entry->text[entry->pos-1];
570
entry->text[entry->pos-1] = chr;
574
gui_entry_redraw_from(entry, entry->pos-2);
575
gui_entry_fix_cursor(entry);
576
gui_entry_draw(entry);
579
void gui_entry_transpose_words(GUI_ENTRY_REC *entry)
581
int spos1, epos1, spos2, epos2;
583
/* find last position */
585
while (epos2 < entry->text_len && !i_isalnum(entry->text[epos2]))
587
while (epos2 < entry->text_len && i_isalnum(entry->text[epos2]))
590
/* find other position */
592
while (spos2 > 0 && !i_isalnum(entry->text[spos2-1]))
594
while (spos2 > 0 && i_isalnum(entry->text[spos2-1]))
598
while (epos1 > 0 && !i_isalnum(entry->text[epos1-1]))
602
while (spos1 > 0 && i_isalnum(entry->text[spos1-1]))
605
/* do wordswap if any found */
606
if (spos1 < epos1 && epos1 < spos2 && spos2 < epos2) {
607
unichar *first, *sep, *second;
610
first = (unichar *) g_malloc( (epos1 - spos1) * sizeof(unichar) );
611
sep = (unichar *) g_malloc( (spos2 - epos1) * sizeof(unichar) );
612
second = (unichar *) g_malloc( (epos2 - spos2) * sizeof(unichar) );
614
for (i = spos1; i < epos1; i++)
615
first[i-spos1] = entry->text[i];
616
for (i = epos1; i < spos2; i++)
617
sep[i-epos1] = entry->text[i];
618
for (i = spos2; i < epos2; i++)
619
second[i-spos2] = entry->text[i];
622
for (i = 0; i < epos2-spos2; i++)
623
entry->text[entry->pos++] = second[i];
624
for (i = 0; i < spos2-epos1; i++)
625
entry->text[entry->pos++] = sep[i];
626
for (i = 0; i < epos1-spos1; i++)
627
entry->text[entry->pos++] = first[i];
635
gui_entry_redraw_from(entry, spos1);
636
gui_entry_fix_cursor(entry);
637
gui_entry_draw(entry);
640
void gui_entry_capitalize_word(GUI_ENTRY_REC *entry)
642
int pos = entry->pos;
643
while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
646
if (pos < entry->text_len) {
647
entry->text[pos] = i_toupper(entry->text[pos]);
651
while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
652
entry->text[pos] = i_tolower(entry->text[pos]);
656
gui_entry_redraw_from(entry, entry->pos);
658
gui_entry_fix_cursor(entry);
659
gui_entry_draw(entry);
662
void gui_entry_downcase_word(GUI_ENTRY_REC *entry)
664
int pos = entry->pos;
665
while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
668
while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
669
entry->text[pos] = i_tolower(entry->text[pos]);
673
gui_entry_redraw_from(entry, entry->pos);
675
gui_entry_fix_cursor(entry);
676
gui_entry_draw(entry);
679
void gui_entry_upcase_word(GUI_ENTRY_REC *entry)
681
int pos = entry->pos;
682
while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
685
while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
686
entry->text[pos] = i_toupper(entry->text[pos]);
690
gui_entry_redraw_from(entry, entry->pos);
692
gui_entry_fix_cursor(entry);
693
gui_entry_draw(entry);
696
int gui_entry_get_pos(GUI_ENTRY_REC *entry)
698
g_return_val_if_fail(entry != NULL, 0);
703
void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos)
705
g_return_if_fail(entry != NULL);
707
if (pos >= 0 && pos <= entry->text_len)
710
gui_entry_fix_cursor(entry);
711
gui_entry_draw(entry);
714
void gui_entry_move_pos(GUI_ENTRY_REC *entry, int pos)
716
g_return_if_fail(entry != NULL);
718
if (entry->pos + pos >= 0 && entry->pos + pos <= entry->text_len)
721
gui_entry_fix_cursor(entry);
722
gui_entry_draw(entry);
725
static void gui_entry_move_words_left(GUI_ENTRY_REC *entry, int count, int to_space)
730
while (count > 0 && pos > 0) {
732
while (pos > 0 && entry->text[pos-1] == ' ')
734
while (pos > 0 && entry->text[pos-1] != ' ')
737
while (pos > 0 && !i_isalnum(entry->text[pos-1]))
739
while (pos > 0 && i_isalnum(entry->text[pos-1]))
748
static void gui_entry_move_words_right(GUI_ENTRY_REC *entry, int count, int to_space)
753
while (count > 0 && pos < entry->text_len) {
755
while (pos < entry->text_len && entry->text[pos] == ' ')
757
while (pos < entry->text_len && entry->text[pos] != ' ')
760
while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
762
while (pos < entry->text_len && i_isalnum(entry->text[pos]))
771
void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space)
773
g_return_if_fail(entry != NULL);
776
gui_entry_move_words_left(entry, -count, to_space);
778
gui_entry_move_words_right(entry, count, to_space);
780
gui_entry_fix_cursor(entry);
781
gui_entry_draw(entry);
784
void gui_entry_redraw(GUI_ENTRY_REC *entry)
786
g_return_if_fail(entry != NULL);
788
gui_entry_set_prompt(entry, NULL);
789
gui_entry_redraw_from(entry, 0);
790
gui_entry_fix_cursor(entry);
791
gui_entry_draw(entry);