1 /*
2 gui-entry.c : irssi
3
4 Copyright (C) 1999 Timo Sirainen
5
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.
10
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.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "module.h"
22 #include "misc.h"
23 #include "utf8.h"
24 #include "formats.h"
25
26 #include "gui-entry.h"
27 #include "gui-printtext.h"
28 #include "term.h"
29 #include "recode.h"
30
31 #undef i_toupper
32 #undef i_tolower
33 #undef i_isalnum
34
35 #define KILL_RING_MAX 10
36
i_toupper(unichar c)37 static unichar i_toupper(unichar c)
38 {
39 if (term_type == TERM_TYPE_UTF8)
40 return g_unichar_toupper(c);
41 return c <= 255 ? toupper(c) : c;
42 }
43
i_tolower(unichar c)44 static unichar i_tolower(unichar c)
45 {
46 if (term_type == TERM_TYPE_UTF8)
47 return g_unichar_tolower(c);
48 return c <= 255 ? tolower(c) : c;
49 }
50
i_isalnum(unichar c)51 static int i_isalnum(unichar c)
52 {
53 if (term_type == TERM_TYPE_UTF8)
54 return (g_unichar_isalnum(c) || i_wcwidth(c) == 0);
55 return c <= 255 ? isalnum(c) : 0;
56 }
57
58 GUI_ENTRY_REC *active_entry;
59
entry_text_grow(GUI_ENTRY_REC * entry,int grow_size)60 static void entry_text_grow(GUI_ENTRY_REC *entry, int grow_size)
61 {
62 if (entry->text_len+grow_size < entry->text_alloc)
63 return;
64
65 entry->text_alloc = nearest_power(entry->text_alloc+grow_size);
66 entry->text = g_realloc(entry->text,
67 sizeof(unichar) * entry->text_alloc);
68
69 if (entry->uses_extents)
70 entry->extents = g_realloc(entry->extents,
71 sizeof(char *) * entry->text_alloc);
72 }
73
gui_entry_create(int xpos,int ypos,int width,int utf8)74 GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
75 {
76 GUI_ENTRY_REC *rec;
77
78 rec = g_new0(GUI_ENTRY_REC, 1);
79 rec->xpos = xpos;
80 rec->ypos = ypos;
81 rec->width = width;
82 rec->text_alloc = 1024;
83 rec->text = g_new(unichar, rec->text_alloc);
84 rec->extents = NULL;
85 rec->text[0] = '\0';
86 rec->utf8 = utf8;
87 return rec;
88 }
89
destroy_extents(GUI_ENTRY_REC * entry)90 static void destroy_extents(GUI_ENTRY_REC *entry)
91 {
92 if (entry->uses_extents) {
93 int i;
94 for (i = 0; i < entry->text_alloc; i++) {
95 if (entry->extents[i] != NULL) {
96 g_free(entry->extents[i]);
97 }
98 }
99 }
100 g_free(entry->extents);
101 entry->extents = NULL;
102 entry->uses_extents = FALSE;
103 }
104
gui_entry_destroy(GUI_ENTRY_REC * entry)105 void gui_entry_destroy(GUI_ENTRY_REC *entry)
106 {
107 GSList *tmp;
108
109 g_return_if_fail(entry != NULL);
110
111 if (active_entry == entry)
112 gui_entry_set_active(NULL);
113
114 for (tmp = entry->kill_ring; tmp != NULL; tmp = tmp->next) {
115 GUI_ENTRY_CUTBUFFER_REC *rec = tmp->data;
116 if (rec != NULL) {
117 g_free(rec->cutbuffer);
118 g_free(rec);
119 }
120 }
121 g_slist_free(entry->kill_ring);
122
123 destroy_extents(entry);
124 g_free(entry->text);
125 g_free(entry->prompt);
126 g_free(entry);
127 }
128
129 /* big5 functions */
130 #define big5_width(ch) ((ch)>0xff ? 2:1)
131
unichars_to_big5(const unichar * str,char * out)132 void unichars_to_big5(const unichar *str, char *out)
133 {
134 for (; *str != '\0'; str++) {
135 if (*str > 0xff)
136 *out++ = (*str >> 8) & 0xff;
137 *out++ = *str & 0xff;
138 }
139 *out = '\0';
140 }
141
strlen_big5(const unsigned char * str)142 int strlen_big5(const unsigned char *str)
143 {
144 int len=0;
145
146 while (*str != '\0') {
147 if (is_big5(str[0], str[1]))
148 str++;
149 len++;
150 str++;
151 }
152 return len;
153 }
154
unichars_to_big5_with_pos(const unichar * str,int spos,char * out,int * opos)155 void unichars_to_big5_with_pos(const unichar *str, int spos, char *out, int *opos)
156 {
157 const unichar *sstart = str;
158 char *ostart = out;
159
160 *opos = 0;
161 while(*str != '\0')
162 {
163 if(*str > 0xff)
164 *out ++ = (*str >> 8) & 0xff;
165 *out ++ = *str & 0xff;
166 str ++;
167 if(str - sstart == spos)
168 *opos = out - ostart;
169 }
170 *out = '\0';
171 }
172
big5_to_unichars(const char * str,unichar * out)173 void big5_to_unichars(const char *str, unichar *out)
174 {
175 const unsigned char *p = (const unsigned char *) str;
176
177 while (*p != '\0') {
178 if (is_big5(p[0], p[1])) {
179 *out++ = p[0] << 8 | p[1];
180 p += 2;
181 } else {
182 *out++ = *p++;
183 }
184 }
185 *out = '\0';
186 }
187
188 /* Return screen length of plain string */
scrlen_str(const char * str,int utf8)189 static int scrlen_str(const char *str, int utf8)
190 {
191 int len = 0;
192 char *stripped;
193 g_return_val_if_fail(str != NULL, 0);
194
195 stripped = strip_codes(str);
196 len = string_width(stripped, utf8 ? TREAT_STRING_AS_UTF8 : TREAT_STRING_AS_BYTES);
197 g_free(stripped);
198 return len;
199 }
200
201 /* ----------------------------- */
202
pos2scrpos(GUI_ENTRY_REC * entry,int pos,int cursor)203 static int pos2scrpos(GUI_ENTRY_REC *entry, int pos, int cursor)
204 {
205 int i;
206 int xpos = 0;
207
208 if (!cursor && pos <= 0)
209 return 0;
210
211 if (entry->uses_extents && entry->extents[0] != NULL) {
212 xpos += scrlen_str(entry->extents[0], entry->utf8);
213 }
214
215 for (i = 0; i < entry->text_len && i < pos; i++) {
216 unichar c = entry->text[i];
217 const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
218
219 if (term_type == TERM_TYPE_BIG5)
220 xpos += big5_width(c);
221 else if (entry->utf8)
222 xpos += unichar_isprint(c) ? i_wcwidth(c) : 1;
223 else
224 xpos++;
225
226 if (extent != NULL) {
227 xpos += scrlen_str(extent, entry->utf8);
228 }
229 }
230 return xpos + pos - i;
231 }
232
scrpos2pos(GUI_ENTRY_REC * entry,int pos)233 static int scrpos2pos(GUI_ENTRY_REC *entry, int pos)
234 {
235 int i, width, xpos = 0;
236
237 if (entry->uses_extents && entry->extents[0] != NULL) {
238 xpos += scrlen_str(entry->extents[0], entry->utf8);
239 }
240
241 for (i = 0; i < entry->text_len && xpos < pos; i++) {
242 unichar c = entry->text[i];
243 const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
244
245 if (term_type == TERM_TYPE_BIG5)
246 width = big5_width(c);
247 else if (entry->utf8)
248 width = unichar_isprint(c) ? i_wcwidth(c) : 1;
249 else
250 width = 1;
251
252 xpos += width;
253
254 if (extent != NULL) {
255 xpos += scrlen_str(extent, entry->utf8);
256 }
257 }
258 return i;
259 }
260
261 /* Fixes the cursor position in screen */
gui_entry_fix_cursor(GUI_ENTRY_REC * entry)262 static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
263 {
264 int old_scrstart;
265
266 /* assume prompt len == prompt scrlen */
267 int start = pos2scrpos(entry, entry->scrstart, FALSE);
268 int now = pos2scrpos(entry, entry->pos, TRUE);
269
270 old_scrstart = entry->scrstart;
271 if (now-start < entry->width - 2 - entry->promptlen && now-start > 0) {
272 entry->scrpos = now-start;
273 } else if (now < entry->width - 1 - entry->promptlen) {
274 entry->scrstart = 0;
275 entry->scrpos = now;
276 } else {
277 entry->scrstart = scrpos2pos(entry, now-(entry->width -
278 entry->promptlen)*2/3);
279 start = pos2scrpos(entry, entry->scrstart, FALSE);
280 entry->scrpos = now - start;
281 }
282
283 if (old_scrstart != entry->scrstart)
284 entry->redraw_needed_from = 0;
285 }
286
text_effects_only(const char * p)287 static char *text_effects_only(const char *p)
288 {
289 GString *str;
290
291 str = g_string_sized_new(strlen(p));
292 for (; *p != '\0'; p++) {
293 if (*p == 4 && p[1] != '\0') {
294 if (p[1] >= FORMAT_STYLE_SPECIAL) {
295 g_string_append_len(str, p, 2);
296 p++;
297 continue;
298 }
299
300 /* irssi color */
301 if (p[2] != '\0') {
302 #ifdef TERM_TRUECOLOR
303 if (p[1] == FORMAT_COLOR_24) {
304 if (p[3] == '\0') p += 2;
305 else if (p[4] == '\0') p += 3;
306 else if (p[5] == '\0') p += 4;
307 else {
308 g_string_append_len(str, p, 6);
309 p += 5;
310 }
311 } else {
312 #endif /* TERM_TRUECOLOR */
313 g_string_append_len(str, p, 3);
314 p += 2;
315 #ifdef TERM_TRUECOLOR
316 }
317 #endif /* TERM_TRUECOLOR */
318 continue;
319 }
320 }
321 }
322
323 return g_string_free(str, FALSE);
324 }
325
gui_entry_draw_from(GUI_ENTRY_REC * entry,int pos)326 static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
327 {
328 int i, start;
329 int start_xpos, xpos, new_xpos, end_xpos;
330 char *tmp;
331 GString *str;
332
333 start = entry->scrstart + pos;
334
335 start_xpos = xpos = entry->xpos + entry->promptlen +
336 pos2scrpos(entry, start, FALSE) -
337 pos2scrpos(entry, entry->scrstart, FALSE);
338 end_xpos = entry->xpos + entry->width;
339
340 if (xpos > end_xpos)
341 return;
342
343 str = g_string_sized_new(entry->text_alloc);
344
345 term_set_color(root_window, ATTR_RESET);
346 /* term_move(root_window, xpos, entry->ypos); */
347
348 if (entry->uses_extents && entry->extents[0] != NULL) {
349 g_string_append(str, entry->extents[0]);
350 }
351 for (i = 0; i < start && i < entry->text_len; i++) {
352 const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
353 if (extent != NULL) {
354 g_string_append(str, extent);
355 }
356 }
357 if (i == 0) {
358 xpos += scrlen_str(str->str, entry->utf8);
359 } else {
360 tmp = text_effects_only(str->str);
361 g_string_assign(str, tmp);
362 g_free(tmp);
363 }
364
365 for (; i < entry->text_len; i++) {
366 unichar c = entry->text[i];
367 const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
368 new_xpos = xpos;
369
370 if (entry->hidden)
371 new_xpos++;
372 else if (term_type == TERM_TYPE_BIG5)
373 new_xpos += big5_width(c);
374 else if (entry->utf8)
375 new_xpos += unichar_isprint(c) ? i_wcwidth(c) : 1;
376 else
377 new_xpos++;
378
379 if (new_xpos > end_xpos)
380 break;
381
382 if (entry->hidden) {
383 g_string_append_c(str, ' ');
384 } else if (unichar_isprint(c)) {
385 if (entry->utf8) {
386 g_string_append_unichar(str, c);
387 } else if (term_type == TERM_TYPE_BIG5) {
388 if(c > 0xff)
389 g_string_append_c(str, (c >> 8) & 0xff);
390 g_string_append_c(str, c & 0xff);
391 } else {
392 g_string_append_c(str, c);
393 }
394 } else {
395 g_string_append_c(str, 4);
396 g_string_append_c(str, FORMAT_STYLE_REVERSE);
397 g_string_append_c(str, (c & 127)+'A'-1);
398 g_string_append_c(str, 4);
399 g_string_append_c(str, FORMAT_STYLE_REVERSE);
400 }
401 xpos = new_xpos;
402
403 if (extent != NULL) {
404 new_xpos += scrlen_str(extent, entry->utf8);
405
406 if (new_xpos > end_xpos)
407 break;
408
409 g_string_append(str, extent);
410 xpos = new_xpos;
411 }
412 }
413
414 /* clear the rest of the input line */
415 if (xpos < end_xpos) {
416 if (end_xpos == term_width) {
417 g_string_append_c(str, 4);
418 g_string_append_c(str, FORMAT_STYLE_CLRTOEOL);
419 } else {
420 while (xpos < end_xpos) {
421 g_string_append_c(str, ' ');
422 xpos++;
423 }
424 }
425 }
426
427 gui_printtext_internal(start_xpos, entry->ypos, str->str);
428 g_string_free(str, TRUE);
429 }
430
gui_entry_draw(GUI_ENTRY_REC * entry)431 static void gui_entry_draw(GUI_ENTRY_REC *entry)
432 {
433 if (entry->redraw_needed_from >= 0) {
434 gui_entry_draw_from(entry, entry->redraw_needed_from);
435 entry->redraw_needed_from = -1;
436 }
437
438 term_move_cursor(entry->xpos + entry->scrpos + entry->promptlen,
439 entry->ypos);
440 term_refresh(NULL);
441 }
442
gui_entry_redraw_from(GUI_ENTRY_REC * entry,int pos)443 static void gui_entry_redraw_from(GUI_ENTRY_REC *entry, int pos)
444 {
445 pos -= entry->scrstart;
446 if (pos < 0) pos = 0;
447
448 if (entry->redraw_needed_from == -1 ||
449 entry->redraw_needed_from > pos)
450 entry->redraw_needed_from = pos;
451 }
452
gui_entry_move(GUI_ENTRY_REC * entry,int xpos,int ypos,int width)453 void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width)
454 {
455 int old_width;
456
457 g_return_if_fail(entry != NULL);
458
459 if (entry->xpos != xpos || entry->ypos != ypos) {
460 /* position in screen changed - needs a full redraw */
461 entry->xpos = xpos;
462 entry->ypos = ypos;
463 entry->width = width;
464 gui_entry_redraw(entry);
465 return;
466 }
467
468 if (entry->width == width)
469 return; /* no changes */
470
471 if (width > entry->width) {
472 /* input line grew - need to draw text at the end */
473 old_width = width;
474 entry->width = width;
475 gui_entry_redraw_from(entry, old_width);
476 } else {
477 /* input line shrinked - make sure the cursor
478 is inside the input line */
479 entry->width = width;
480 if (entry->pos - entry->scrstart >
481 entry->width-2 - entry->promptlen) {
482 gui_entry_fix_cursor(entry);
483 }
484 }
485
486 gui_entry_draw(entry);
487 }
488
gui_entry_set_active(GUI_ENTRY_REC * entry)489 void gui_entry_set_active(GUI_ENTRY_REC *entry)
490 {
491 active_entry = entry;
492
493 if (entry != NULL) {
494 term_move_cursor(entry->xpos + entry->scrpos +
495 entry->promptlen, entry->ypos);
496 term_refresh(NULL);
497 }
498 }
499
gui_entry_set_prompt(GUI_ENTRY_REC * entry,const char * str)500 void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str)
501 {
502 int oldlen;
503
504 g_return_if_fail(entry != NULL);
505
506 oldlen = entry->promptlen;
507 if (str != NULL) {
508 g_free_not_null(entry->prompt);
509 entry->prompt = g_strdup(str);
510 entry->promptlen = scrlen_str(str, entry->utf8);
511 }
512
513 if (entry->prompt != NULL)
514 gui_printtext_internal(entry->xpos, entry->ypos, entry->prompt);
515
516 if (entry->promptlen != oldlen) {
517 gui_entry_fix_cursor(entry);
518 gui_entry_draw(entry);
519 }
520 }
521
gui_entry_set_hidden(GUI_ENTRY_REC * entry,int hidden)522 void gui_entry_set_hidden(GUI_ENTRY_REC *entry, int hidden)
523 {
524 g_return_if_fail(entry != NULL);
525
526 entry->hidden = hidden;
527 }
528
gui_entry_set_utf8(GUI_ENTRY_REC * entry,int utf8)529 void gui_entry_set_utf8(GUI_ENTRY_REC *entry, int utf8)
530 {
531 g_return_if_fail(entry != NULL);
532
533 entry->utf8 = utf8;
534 }
535
gui_entry_set_text(GUI_ENTRY_REC * entry,const char * str)536 void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
537 {
538 g_return_if_fail(entry != NULL);
539 g_return_if_fail(str != NULL);
540
541 entry->text_len = 0;
542 entry->pos = 0;
543 entry->text[0] = '\0';
544 destroy_extents(entry);
545
546 gui_entry_insert_text(entry, str);
547 }
548
gui_entry_get_text(GUI_ENTRY_REC * entry)549 char *gui_entry_get_text(GUI_ENTRY_REC *entry)
550 {
551 char *buf;
552 int i;
553
554 g_return_val_if_fail(entry != NULL, NULL);
555
556 if (entry->utf8)
557 buf = g_ucs4_to_utf8(entry->text, -1, NULL, NULL, NULL);
558 else {
559 buf = g_malloc(entry->text_len*6 + 1);
560 if (term_type == TERM_TYPE_BIG5)
561 unichars_to_big5(entry->text, buf);
562 else
563 for (i = 0; i <= entry->text_len; i++)
564 buf[i] = entry->text[i];
565 }
566 return buf;
567 }
568
gui_entry_get_text_and_pos(GUI_ENTRY_REC * entry,int * pos)569 char *gui_entry_get_text_and_pos(GUI_ENTRY_REC *entry, int *pos)
570 {
571 char *buf;
572 int i;
573
574 g_return_val_if_fail(entry != NULL, NULL);
575
576 if (entry->utf8) {
577 buf = g_ucs4_to_utf8(entry->text, -1, NULL, NULL, NULL);
578 *pos = g_utf8_offset_to_pointer(buf, entry->pos) - buf;
579 } else {
580 buf = g_malloc(entry->text_len*6 + 1);
581 if(term_type==TERM_TYPE_BIG5)
582 unichars_to_big5_with_pos(entry->text, entry->pos, buf, pos);
583 else
584 {
585 for (i = 0; i <= entry->text_len; i++)
586 buf[i] = entry->text[i];
587 *pos = entry->pos;
588 }
589 }
590 return buf;
591 }
592
gui_entry_insert_text(GUI_ENTRY_REC * entry,const char * str)593 void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
594 {
595 unichar chr;
596 int i, len;
597 const char *ptr;
598
599 g_return_if_fail(entry != NULL);
600 g_return_if_fail(str != NULL);
601
602 gui_entry_redraw_from(entry, entry->pos);
603
604 if (entry->utf8) {
605 g_utf8_validate(str, -1, &ptr);
606 len = g_utf8_pointer_to_offset(str, ptr);
607 } else if (term_type == TERM_TYPE_BIG5)
608 len = strlen_big5((const unsigned char *)str);
609 else
610 len = strlen(str);
611 entry_text_grow(entry, len);
612
613 /* make space for the string */
614 g_memmove(entry->text + entry->pos + len, entry->text + entry->pos,
615 (entry->text_len-entry->pos + 1) * sizeof(unichar));
616
617 /* make space for the color */
618 if (entry->uses_extents) {
619 g_memmove(entry->extents + entry->pos + len + 1, entry->extents + entry->pos + 1,
620 (entry->text_len-entry->pos) * sizeof(char *));
621 for (i = 0; i < len; i++) {
622 entry->extents[entry->pos + i + 1] = NULL;
623 }
624 }
625
626 if (!entry->utf8) {
627 if (term_type == TERM_TYPE_BIG5) {
628 chr = entry->text[entry->pos + len];
629 big5_to_unichars(str, entry->text + entry->pos);
630 entry->text[entry->pos + len] = chr;
631 } else {
632 for (i = 0; i < len; i++)
633 entry->text[entry->pos + i] = str[i];
634 }
635 } else {
636 ptr = str;
637 for (i = 0; i < len; i++) {
638 entry->text[entry->pos + i] = g_utf8_get_char(ptr);
639 ptr = g_utf8_next_char(ptr);
640 }
641 }
642
643 entry->text_len += len;
644 entry->pos += len;
645
646 gui_entry_fix_cursor(entry);
647 gui_entry_draw(entry);
648 }
649
gui_entry_insert_char(GUI_ENTRY_REC * entry,unichar chr)650 void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
651 {
652 g_return_if_fail(entry != NULL);
653
654 if (chr == 0 || chr == 13 || chr == 10)
655 return; /* never insert NUL, CR or LF characters */
656
657 if (entry->utf8 && entry->pos == 0 && unichar_isprint(chr) && i_wcwidth(chr) == 0)
658 return;
659
660 gui_entry_redraw_from(entry, entry->pos);
661
662 entry_text_grow(entry, 1);
663
664 /* make space for the string */
665 g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
666 (entry->text_len-entry->pos + 1) * sizeof(unichar));
667
668 if (entry->uses_extents) {
669 g_memmove(entry->extents + entry->pos + 1 + 1, entry->extents + entry->pos + 1,
670 (entry->text_len-entry->pos) * sizeof(char *));
671 entry->extents[entry->pos + 1] = NULL;
672 }
673
674 entry->text[entry->pos] = chr;
675 entry->text_len++;
676 entry->pos++;
677
678 gui_entry_fix_cursor(entry);
679 gui_entry_draw(entry);
680 }
681
gui_entry_get_cutbuffer(GUI_ENTRY_REC * entry)682 char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
683 {
684 GUI_ENTRY_CUTBUFFER_REC *tmp;
685 char *buf;
686 int i;
687
688 g_return_val_if_fail(entry != NULL, NULL);
689
690 if (entry->kill_ring == NULL || entry->kill_ring->data == NULL)
691 return NULL;
692
693 tmp = entry->kill_ring->data;
694
695 if (tmp->cutbuffer == NULL)
696 return NULL;
697
698 if (entry->utf8)
699 buf = g_ucs4_to_utf8(tmp->cutbuffer, -1, NULL, NULL, NULL);
700 else {
701 buf = g_malloc(tmp->cutbuffer_len*6 + 1);
702 if (term_type == TERM_TYPE_BIG5)
703 unichars_to_big5(tmp->cutbuffer, buf);
704 else
705 for (i = 0; i <= tmp->cutbuffer_len; i++)
706 buf[i] = tmp->cutbuffer[i];
707 }
708 return buf;
709 }
710
gui_entry_get_next_cutbuffer(GUI_ENTRY_REC * entry)711 char *gui_entry_get_next_cutbuffer(GUI_ENTRY_REC *entry)
712 {
713 GUI_ENTRY_CUTBUFFER_REC *tmp;
714
715 g_return_val_if_fail(entry != NULL, NULL);
716
717 if (entry->kill_ring == NULL)
718 return NULL;
719
720 tmp = entry->kill_ring->data;
721
722 entry->kill_ring = g_slist_remove(entry->kill_ring, tmp);
723 entry->kill_ring = g_slist_append(entry->kill_ring, tmp);
724
725 return gui_entry_get_cutbuffer(entry);
726 }
727
gui_entry_erase_to(GUI_ENTRY_REC * entry,int pos,CUTBUFFER_UPDATE_OP update_cutbuffer)728 void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, CUTBUFFER_UPDATE_OP update_cutbuffer)
729 {
730 int newpos, size = 0;
731
732 g_return_if_fail(entry != NULL);
733
734 for (newpos = gui_entry_get_pos(entry); newpos > pos; size++)
735 newpos = newpos - 1;
736 gui_entry_erase(entry, size, update_cutbuffer);
737 }
738
get_cutbuffer_rec(GUI_ENTRY_REC * entry,CUTBUFFER_UPDATE_OP update_cutbuffer)739 static GUI_ENTRY_CUTBUFFER_REC *get_cutbuffer_rec(GUI_ENTRY_REC *entry, CUTBUFFER_UPDATE_OP update_cutbuffer)
740 {
741 GUI_ENTRY_CUTBUFFER_REC *tmp;
742
743 g_return_val_if_fail(entry != NULL, NULL);
744
745 if (entry->kill_ring == NULL) {
746 /* no kill ring exists */
747 entry->kill_ring = g_slist_prepend(entry->kill_ring, (void *)NULL);
748 } else {
749 tmp = entry->kill_ring->data;
750
751 if (tmp != NULL && tmp->cutbuffer_len > 0
752 && (!entry->previous_append_next_kill
753 || update_cutbuffer == CUTBUFFER_UPDATE_REPLACE)) {
754 /* a cutbuffer exists and should be replaced */
755 entry->kill_ring = g_slist_prepend(entry->kill_ring, (void *)NULL);
756 }
757 }
758
759 if (g_slist_length(entry->kill_ring) > KILL_RING_MAX) {
760 GUI_ENTRY_CUTBUFFER_REC *rec = g_slist_last(entry->kill_ring)->data;
761 entry->kill_ring = g_slist_remove(entry->kill_ring, rec);
762 if (rec != NULL) g_free(rec->cutbuffer);
763 g_free(rec);
764 }
765
766 if (entry->kill_ring->data == NULL) {
767 entry->kill_ring->data = g_new0(GUI_ENTRY_CUTBUFFER_REC, 1);
768 }
769
770 return entry->kill_ring->data;
771 }
772
gui_entry_erase(GUI_ENTRY_REC * entry,int size,CUTBUFFER_UPDATE_OP update_cutbuffer)773 void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer)
774 {
775 size_t i, w = 0;
776
777 g_return_if_fail(entry != NULL);
778
779 if (size == 0 || entry->pos < size)
780 return;
781
782 if (update_cutbuffer != CUTBUFFER_UPDATE_NOOP) {
783 int cutbuffer_new_size;
784 unichar *tmpcutbuffer;
785 GUI_ENTRY_CUTBUFFER_REC *tmp = get_cutbuffer_rec(entry, update_cutbuffer);
786
787 if (tmp->cutbuffer_len == 0) {
788 update_cutbuffer = CUTBUFFER_UPDATE_REPLACE;
789 }
790
791 cutbuffer_new_size = tmp->cutbuffer_len + size;
792 tmpcutbuffer = tmp->cutbuffer;
793 entry->append_next_kill = TRUE;
794 switch (update_cutbuffer) {
795 case CUTBUFFER_UPDATE_APPEND:
796 tmp->cutbuffer = g_new(unichar, cutbuffer_new_size+1);
797 memcpy(tmp->cutbuffer, tmpcutbuffer,
798 tmp->cutbuffer_len * sizeof(unichar));
799 memcpy(tmp->cutbuffer + tmp->cutbuffer_len,
800 entry->text + entry->pos - size, size * sizeof(unichar));
801
802 tmp->cutbuffer_len = cutbuffer_new_size;
803 tmp->cutbuffer[cutbuffer_new_size] = '\0';
804 g_free(tmpcutbuffer);
805 break;
806
807 case CUTBUFFER_UPDATE_PREPEND:
808 tmp->cutbuffer = g_new(unichar, cutbuffer_new_size+1);
809 memcpy(tmp->cutbuffer, entry->text + entry->pos - size,
810 size * sizeof(unichar));
811 memcpy(tmp->cutbuffer + size, tmpcutbuffer,
812 tmp->cutbuffer_len * sizeof(unichar));
813
814 tmp->cutbuffer_len = cutbuffer_new_size;
815 tmp->cutbuffer[cutbuffer_new_size] = '\0';
816 g_free(tmpcutbuffer);
817 break;
818
819 case CUTBUFFER_UPDATE_REPLACE:
820 /* put erased text to cutbuffer */
821 if (tmp->cutbuffer_len < size) {
822 g_free(tmp->cutbuffer);
823 tmp->cutbuffer = g_new(unichar, size+1);
824 }
825
826 tmp->cutbuffer_len = size;
827 tmp->cutbuffer[size] = '\0';
828 memcpy(tmp->cutbuffer, entry->text + entry->pos - size, size * sizeof(unichar));
829 break;
830
831 case CUTBUFFER_UPDATE_NOOP:
832 /* cannot happen, handled in "if" */
833 break;
834 }
835 }
836
837 if (entry->utf8)
838 while (entry->pos > size + w && i_wcwidth(entry->text[entry->pos - size - w]) == 0)
839 w++;
840
841 g_memmove(entry->text + entry->pos - size, entry->text + entry->pos,
842 (entry->text_len-entry->pos+1) * sizeof(unichar));
843
844 if (entry->uses_extents) {
845 for (i = entry->pos - size; i < entry->pos; i++) {
846 if (entry->extents[i+1] != NULL) {
847 g_free(entry->extents[i+1]);
848 }
849 }
850 g_memmove(entry->extents + entry->pos - size + 1, entry->extents + entry->pos + 1,
851 (entry->text_len - entry->pos) * sizeof(void *)); /* no null terminator here */
852 for (i = 0; i < size; i++) {
853 entry->extents[entry->text_len - i] = NULL;
854 }
855 if (entry->text_len == size && entry->extents[0] != NULL) {
856 g_free(entry->extents[0]);
857 entry->extents[0] = NULL;
858 }
859 }
860
861 entry->pos -= size;
862 entry->text_len -= size;
863
864 gui_entry_redraw_from(entry, entry->pos-w);
865 gui_entry_fix_cursor(entry);
866 gui_entry_draw(entry);
867 }
868
gui_entry_erase_cell(GUI_ENTRY_REC * entry)869 void gui_entry_erase_cell(GUI_ENTRY_REC *entry)
870 {
871 int size = 1;
872
873 g_return_if_fail(entry != NULL);
874
875 if (entry->utf8)
876 while (entry->pos+size < entry->text_len &&
877 i_wcwidth(entry->text[entry->pos+size]) == 0) size++;
878
879 g_memmove(entry->text + entry->pos, entry->text + entry->pos + size,
880 (entry->text_len-entry->pos-size+1) * sizeof(unichar));
881
882 if (entry->uses_extents) {
883 int i;
884 for (i = 0; i < size; i++) {
885 g_free(entry->extents[entry->pos + i + 1]);
886 }
887 g_memmove(entry->extents + entry->pos + 1, entry->extents + entry->pos + size + 1,
888 (entry->text_len-entry->pos-size) * sizeof(char *));
889 for (i = 0; i < size; i++) {
890 entry->extents[entry->text_len - i] = NULL;
891 }
892 if (entry->text_len == size && entry->extents[0] != NULL) {
893 g_free(entry->extents[0]);
894 entry->extents[0] = NULL;
895 }
896 }
897
898 entry->text_len -= size;
899
900 gui_entry_redraw_from(entry, entry->pos);
901 gui_entry_fix_cursor(entry);
902 gui_entry_draw(entry);
903 }
904
gui_entry_erase_word(GUI_ENTRY_REC * entry,int to_space,CUTBUFFER_UPDATE_OP cutbuffer_op)905 void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op)
906 {
907 int to;
908
909 g_return_if_fail(entry != NULL);
910 if (entry->pos == 0)
911 return;
912
913 to = entry->pos - 1;
914
915 if (to_space) {
916 while (entry->text[to] == ' ' && to > 0)
917 to--;
918 while (entry->text[to] != ' ' && to > 0)
919 to--;
920 } else {
921 while (!i_isalnum(entry->text[to]) && to > 0)
922 to--;
923 while (i_isalnum(entry->text[to]) && to > 0)
924 to--;
925 }
926 if (to > 0) to++;
927
928 gui_entry_erase(entry, entry->pos-to, cutbuffer_op);
929 }
930
gui_entry_erase_next_word(GUI_ENTRY_REC * entry,int to_space,CUTBUFFER_UPDATE_OP cutbuffer_op)931 void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op)
932 {
933 int to, size;
934
935 g_return_if_fail(entry != NULL);
936 if (entry->pos == entry->text_len)
937 return;
938
939 to = entry->pos;
940 if (to_space) {
941 while (entry->text[to] == ' ' && to < entry->text_len)
942 to++;
943 while (entry->text[to] != ' ' && to < entry->text_len)
944 to++;
945 } else {
946 while (!i_isalnum(entry->text[to]) && to < entry->text_len)
947 to++;
948 while (i_isalnum(entry->text[to]) && to < entry->text_len)
949 to++;
950 }
951
952 size = to-entry->pos;
953 entry->pos = to;
954 gui_entry_erase(entry, size, cutbuffer_op);
955 }
956
gui_entry_transpose_chars(GUI_ENTRY_REC * entry)957 void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
958 {
959 unichar chr;
960 char *extent;
961
962 if (entry->pos == 0 || entry->text_len < 2)
963 return;
964
965 if (entry->pos == entry->text_len)
966 entry->pos--;
967
968 /* swap chars */
969 chr = entry->text[entry->pos];
970 entry->text[entry->pos] = entry->text[entry->pos-1];
971 entry->text[entry->pos-1] = chr;
972
973 if (entry->uses_extents) {
974 extent = entry->extents[entry->pos+1];
975 entry->extents[entry->pos+1] = entry->extents[entry->pos];
976 entry->extents[entry->pos] = extent;
977 }
978
979 entry->pos++;
980
981 gui_entry_redraw_from(entry, entry->pos-2);
982 gui_entry_fix_cursor(entry);
983 gui_entry_draw(entry);
984 }
985
gui_entry_transpose_words(GUI_ENTRY_REC * entry)986 void gui_entry_transpose_words(GUI_ENTRY_REC *entry)
987 {
988 int spos1, epos1, spos2, epos2;
989
990 /* find last position */
991 epos2 = entry->pos;
992 while (epos2 < entry->text_len && !i_isalnum(entry->text[epos2]))
993 epos2++;
994 while (epos2 < entry->text_len && i_isalnum(entry->text[epos2]))
995 epos2++;
996
997 /* find other position */
998 spos2 = epos2;
999 while (spos2 > 0 && !i_isalnum(entry->text[spos2-1]))
1000 spos2--;
1001 while (spos2 > 0 && i_isalnum(entry->text[spos2-1]))
1002 spos2--;
1003
1004 epos1 = spos2;
1005 while (epos1 > 0 && !i_isalnum(entry->text[epos1-1]))
1006 epos1--;
1007
1008 spos1 = epos1;
1009 while (spos1 > 0 && i_isalnum(entry->text[spos1-1]))
1010 spos1--;
1011
1012 /* do wordswap if any found */
1013 if (spos1 < epos1 && epos1 < spos2 && spos2 < epos2) {
1014 unichar *first, *sep, *second;
1015 char **first_extent, **sep_extent, **second_extent;
1016 int i;
1017
1018 first = (unichar *) g_malloc( (epos1 - spos1) * sizeof(unichar) );
1019 sep = (unichar *) g_malloc( (spos2 - epos1) * sizeof(unichar) );
1020 second = (unichar *) g_malloc( (epos2 - spos2) * sizeof(unichar) );
1021
1022 first_extent = (char **) g_malloc( (epos1 - spos1) * sizeof(char *) );
1023 sep_extent = (char **) g_malloc( (spos2 - epos1) * sizeof(char *) );
1024 second_extent = (char **) g_malloc( (epos2 - spos2) * sizeof(char *) );
1025
1026 for (i = spos1; i < epos1; i++) {
1027 first[i-spos1] = entry->text[i];
1028 if (entry->uses_extents)
1029 first_extent[i-spos1] = entry->extents[i+1];
1030 }
1031 for (i = epos1; i < spos2; i++) {
1032 sep[i-epos1] = entry->text[i];
1033 if (entry->uses_extents)
1034 sep_extent[i-epos1] = entry->extents[i+1];
1035 }
1036 for (i = spos2; i < epos2; i++) {
1037 second[i-spos2] = entry->text[i];
1038 if (entry->uses_extents)
1039 second_extent[i-spos2] = entry->extents[i+1];
1040 }
1041
1042 entry->pos = spos1;
1043 for (i = 0; i < epos2-spos2; i++) {
1044 entry->text[entry->pos] = second[i];
1045 if (entry->uses_extents)
1046 entry->extents[entry->pos+1] = second_extent[i];
1047 entry->pos++;
1048 }
1049 for (i = 0; i < spos2-epos1; i++) {
1050 entry->text[entry->pos] = sep[i];
1051 if (entry->uses_extents)
1052 entry->extents[entry->pos+1] = sep_extent[i];
1053 entry->pos++;
1054 }
1055 for (i = 0; i < epos1-spos1; i++) {
1056 entry->text[entry->pos] = first[i];
1057 if (entry->uses_extents)
1058 entry->extents[entry->pos+1] = first_extent[i];
1059 entry->pos++;
1060 }
1061
1062 g_free(first);
1063 g_free(sep);
1064 g_free(second);
1065
1066 g_free(first_extent);
1067 g_free(sep_extent);
1068 g_free(second_extent);
1069 }
1070
1071 gui_entry_redraw_from(entry, spos1);
1072 gui_entry_fix_cursor(entry);
1073 gui_entry_draw(entry);
1074 }
1075
gui_entry_capitalize_word(GUI_ENTRY_REC * entry)1076 void gui_entry_capitalize_word(GUI_ENTRY_REC *entry)
1077 {
1078 int pos = entry->pos;
1079 while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
1080 pos++;
1081
1082 if (pos < entry->text_len) {
1083 entry->text[pos] = i_toupper(entry->text[pos]);
1084 pos++;
1085 }
1086
1087 while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
1088 entry->text[pos] = i_tolower(entry->text[pos]);
1089 pos++;
1090 }
1091
1092 gui_entry_redraw_from(entry, entry->pos);
1093 entry->pos = pos;
1094 gui_entry_fix_cursor(entry);
1095 gui_entry_draw(entry);
1096 }
1097
gui_entry_downcase_word(GUI_ENTRY_REC * entry)1098 void gui_entry_downcase_word(GUI_ENTRY_REC *entry)
1099 {
1100 int pos = entry->pos;
1101 while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
1102 pos++;
1103
1104 while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
1105 entry->text[pos] = i_tolower(entry->text[pos]);
1106 pos++;
1107 }
1108
1109 gui_entry_redraw_from(entry, entry->pos);
1110 entry->pos = pos;
1111 gui_entry_fix_cursor(entry);
1112 gui_entry_draw(entry);
1113 }
1114
gui_entry_upcase_word(GUI_ENTRY_REC * entry)1115 void gui_entry_upcase_word(GUI_ENTRY_REC *entry)
1116 {
1117 int pos = entry->pos;
1118 while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
1119 pos++;
1120
1121 while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
1122 entry->text[pos] = i_toupper(entry->text[pos]);
1123 pos++;
1124 }
1125
1126 gui_entry_redraw_from(entry, entry->pos);
1127 entry->pos = pos;
1128 gui_entry_fix_cursor(entry);
1129 gui_entry_draw(entry);
1130 }
1131
gui_entry_get_pos(GUI_ENTRY_REC * entry)1132 int gui_entry_get_pos(GUI_ENTRY_REC *entry)
1133 {
1134 g_return_val_if_fail(entry != NULL, 0);
1135
1136 return entry->pos;
1137 }
1138
gui_entry_set_pos(GUI_ENTRY_REC * entry,int pos)1139 void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos)
1140 {
1141 g_return_if_fail(entry != NULL);
1142
1143 if (pos >= 0 && pos <= entry->text_len)
1144 entry->pos = pos;
1145
1146 gui_entry_fix_cursor(entry);
1147 gui_entry_draw(entry);
1148 }
1149
gui_entry_set_text_and_pos_bytes(GUI_ENTRY_REC * entry,const char * str,int pos_bytes)1150 void gui_entry_set_text_and_pos_bytes(GUI_ENTRY_REC *entry, const char *str, int pos_bytes)
1151 {
1152 int pos, extents_alloc;
1153 char **extents;
1154 const char *ptr;
1155
1156 g_return_if_fail(entry != NULL);
1157
1158 extents = entry->extents;
1159 extents_alloc = entry->text_alloc;
1160 entry->extents = NULL;
1161 entry->uses_extents = FALSE;
1162
1163 gui_entry_set_text(entry, str);
1164
1165 if (entry->utf8) {
1166 g_utf8_validate(str, pos_bytes, &ptr);
1167 pos = g_utf8_pointer_to_offset(str, ptr);
1168 } else if (term_type == TERM_TYPE_BIG5)
1169 pos = strlen_big5((const unsigned char *)str) - strlen_big5((const unsigned char *)(str + pos_bytes));
1170 else
1171 pos = pos_bytes;
1172
1173 if (extents != NULL) {
1174 entry->uses_extents = TRUE;
1175 entry->extents = extents;
1176 if (extents_alloc < entry->text_alloc) {
1177 int i;
1178 entry->extents = g_realloc(entry->extents,
1179 sizeof(char *) * entry->text_alloc);
1180 for (i = extents_alloc; i < entry->text_alloc; i++) {
1181 entry->extents[i] = NULL;
1182 }
1183 }
1184 }
1185 gui_entry_redraw_from(entry, 0);
1186 gui_entry_set_pos(entry, pos);
1187 }
1188
gui_entry_move_pos(GUI_ENTRY_REC * entry,int pos)1189 void gui_entry_move_pos(GUI_ENTRY_REC *entry, int pos)
1190 {
1191 g_return_if_fail(entry != NULL);
1192
1193 if (entry->pos + pos >= 0 && entry->pos + pos <= entry->text_len)
1194 entry->pos += pos;
1195
1196 if (entry->utf8) {
1197 int step = pos < 0 ? -1 : 1;
1198 while(i_wcwidth(entry->text[entry->pos]) == 0 &&
1199 entry->pos + step >= 0 && entry->pos + step <= entry->text_len)
1200 entry->pos += step;
1201 }
1202
1203 gui_entry_fix_cursor(entry);
1204 gui_entry_draw(entry);
1205 }
1206
gui_entry_move_words_left(GUI_ENTRY_REC * entry,int count,int to_space)1207 static void gui_entry_move_words_left(GUI_ENTRY_REC *entry, int count, int to_space)
1208 {
1209 int pos;
1210
1211 pos = entry->pos;
1212 while (count > 0 && pos > 0) {
1213 if (to_space) {
1214 while (pos > 0 && entry->text[pos-1] == ' ')
1215 pos--;
1216 while (pos > 0 && entry->text[pos-1] != ' ')
1217 pos--;
1218 } else {
1219 while (pos > 0 && !i_isalnum(entry->text[pos-1]))
1220 pos--;
1221 while (pos > 0 && i_isalnum(entry->text[pos-1]))
1222 pos--;
1223 }
1224 count--;
1225 }
1226
1227 entry->pos = pos;
1228 }
1229
gui_entry_move_words_right(GUI_ENTRY_REC * entry,int count,int to_space)1230 static void gui_entry_move_words_right(GUI_ENTRY_REC *entry, int count, int to_space)
1231 {
1232 int pos;
1233
1234 pos = entry->pos;
1235 while (count > 0 && pos < entry->text_len) {
1236 if (to_space) {
1237 while (pos < entry->text_len && entry->text[pos] == ' ')
1238 pos++;
1239 while (pos < entry->text_len && entry->text[pos] != ' ')
1240 pos++;
1241 } else {
1242 while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
1243 pos++;
1244 while (pos < entry->text_len && i_isalnum(entry->text[pos]))
1245 pos++;
1246 }
1247 count--;
1248 }
1249
1250 entry->pos = pos;
1251 }
1252
gui_entry_move_words(GUI_ENTRY_REC * entry,int count,int to_space)1253 void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space)
1254 {
1255 g_return_if_fail(entry != NULL);
1256
1257 if (count < 0)
1258 gui_entry_move_words_left(entry, -count, to_space);
1259 else if (count > 0)
1260 gui_entry_move_words_right(entry, count, to_space);
1261
1262 gui_entry_fix_cursor(entry);
1263 gui_entry_draw(entry);
1264 }
1265
gui_entry_redraw(GUI_ENTRY_REC * entry)1266 void gui_entry_redraw(GUI_ENTRY_REC *entry)
1267 {
1268 g_return_if_fail(entry != NULL);
1269
1270 gui_entry_set_prompt(entry, NULL);
1271 gui_entry_redraw_from(entry, 0);
1272 gui_entry_fix_cursor(entry);
1273 gui_entry_draw(entry);
1274 }
1275
gui_entry_alloc_extents(GUI_ENTRY_REC * entry)1276 static void gui_entry_alloc_extents(GUI_ENTRY_REC *entry)
1277 {
1278 entry->uses_extents = TRUE;
1279 entry->extents = g_new0(char *, entry->text_alloc);
1280 }
1281
gui_entry_set_extent(GUI_ENTRY_REC * entry,int pos,const char * text)1282 void gui_entry_set_extent(GUI_ENTRY_REC *entry, int pos, const char *text)
1283 {
1284 int update = FALSE;
1285
1286 g_return_if_fail(entry != NULL);
1287
1288 if (pos < 0 || pos > entry->text_len)
1289 return;
1290
1291 if (text == NULL)
1292 return;
1293
1294 if (!entry->uses_extents) {
1295 gui_entry_alloc_extents(entry);
1296 }
1297
1298 if (g_strcmp0(entry->extents[pos], text) != 0) {
1299 g_free(entry->extents[pos]);
1300 if (*text == '\0') {
1301 entry->extents[pos] = NULL;
1302 } else {
1303 entry->extents[pos] = g_strdup(text);
1304 }
1305 update = TRUE;
1306 }
1307
1308 if (update) {
1309 gui_entry_redraw_from(entry, pos - 1);
1310 gui_entry_fix_cursor(entry);
1311 gui_entry_draw(entry);
1312 }
1313 }
1314
gui_entry_set_extents(GUI_ENTRY_REC * entry,int pos,int len,const char * left,const char * right)1315 void gui_entry_set_extents(GUI_ENTRY_REC *entry, int pos, int len, const char *left, const char *right)
1316 {
1317 int end, update = FALSE;
1318
1319 g_return_if_fail(entry != NULL);
1320
1321 if (pos < 0 || len < 0 || pos > entry->text_len)
1322 return;
1323
1324 end = pos + len;
1325
1326 if (end > entry->text_len)
1327 end = entry->text_len;
1328
1329 if (!entry->uses_extents) {
1330 gui_entry_alloc_extents(entry);
1331 }
1332
1333 if (g_strcmp0(entry->extents[pos], left) != 0) {
1334 g_free(entry->extents[pos]);
1335 if (*left == '\0') {
1336 entry->extents[pos] = NULL;
1337 } else {
1338 entry->extents[pos] = g_strdup(left);
1339 }
1340 update = TRUE;
1341 }
1342
1343 if (pos != end && g_strcmp0(entry->extents[end], right) != 0) {
1344 g_free(entry->extents[end]);
1345 if (*right == '\0') {
1346 entry->extents[end] = NULL;
1347 } else {
1348 entry->extents[end] = g_strdup(right);
1349 }
1350 update = TRUE;
1351 }
1352
1353 if (update) {
1354 gui_entry_redraw_from(entry, pos - 1);
1355 gui_entry_fix_cursor(entry);
1356 gui_entry_draw(entry);
1357 }
1358 }
1359
gui_entry_clear_extents(GUI_ENTRY_REC * entry,int pos,int len)1360 void gui_entry_clear_extents(GUI_ENTRY_REC *entry, int pos, int len)
1361 {
1362 int i, end, update = FALSE;
1363
1364 g_return_if_fail(entry != NULL);
1365
1366 if (pos < 0 || len < 0 || pos > entry->text_len)
1367 return;
1368
1369 end = pos + len;
1370
1371 if (end > entry->text_len)
1372 end = entry->text_len;
1373
1374 if (!entry->uses_extents) {
1375 return;
1376 }
1377
1378 for (i = pos; i <= end; i++) {
1379 if (entry->extents[i] != NULL) {
1380 g_free(entry->extents[i]);
1381 entry->extents[i] = NULL;
1382 update = TRUE;
1383 }
1384 }
1385
1386 if (update) {
1387 gui_entry_redraw_from(entry, pos);
1388 gui_entry_fix_cursor(entry);
1389 gui_entry_draw(entry);
1390 }
1391 }
1392
gui_entry_get_extent(GUI_ENTRY_REC * entry,int pos)1393 char *gui_entry_get_extent(GUI_ENTRY_REC *entry, int pos)
1394 {
1395 g_return_val_if_fail(entry != NULL, NULL);
1396
1397 if (!entry->uses_extents)
1398 return NULL;
1399
1400 if (pos < 0 || pos >= entry->text_len)
1401 return NULL;
1402
1403 return entry->extents[pos];
1404 }
1405
1406 #define POS_FLAG "%|"
gui_entry_get_text_and_extents(GUI_ENTRY_REC * entry)1407 GSList *gui_entry_get_text_and_extents(GUI_ENTRY_REC *entry)
1408 {
1409 GSList *list = NULL;
1410 GString *str;
1411 int i;
1412
1413 g_return_val_if_fail(entry != NULL, NULL);
1414
1415 if (entry->uses_extents && entry->extents[0] != NULL) {
1416 if (entry->pos == 0) {
1417 list = g_slist_prepend(list, g_strconcat(entry->extents[0], POS_FLAG, NULL));
1418 } else {
1419 list = g_slist_prepend(list, g_strdup(entry->extents[0]));
1420 }
1421 } else {
1422 if (entry->pos == 0) {
1423 list = g_slist_prepend(list, g_strdup(POS_FLAG));
1424 } else {
1425 list = g_slist_prepend(list, NULL);
1426 }
1427 }
1428
1429 str = g_string_sized_new(entry->text_alloc);
1430 for (i = 0; i < entry->text_len; i++) {
1431 if (entry->utf8) {
1432 g_string_append_unichar(str, entry->text[i]);
1433 } else if (term_type == TERM_TYPE_BIG5) {
1434 if(entry->text[i] > 0xff)
1435 g_string_append_c(str, (entry->text[i] >> 8) & 0xff);
1436 g_string_append_c(str, entry->text[i] & 0xff);
1437 } else {
1438 g_string_append_c(str, entry->text[i]);
1439 }
1440 if (entry->pos == i+1 || (entry->uses_extents && entry->extents[i+1] != NULL)) {
1441 list = g_slist_prepend(list, g_strdup(str->str));
1442 g_string_truncate(str, 0);
1443 if (entry->uses_extents && entry->extents[i+1] != NULL) {
1444 if (entry->pos == i+1) {
1445 list = g_slist_prepend(list, g_strconcat(entry->extents[i+1], POS_FLAG, NULL));
1446 } else {
1447 list = g_slist_prepend(list, g_strdup(entry->extents[i+1]));
1448 }
1449 } else if (entry->pos == i+1) {
1450 list = g_slist_prepend(list, g_strdup(POS_FLAG));
1451 }
1452 }
1453 }
1454 if (str->len > 0) {
1455 list = g_slist_prepend(list, g_strdup(str->str));
1456 }
1457 list = g_slist_reverse(list);
1458 g_string_free(str, TRUE);
1459
1460 return list;
1461 }
1462
gui_entry_set_text_and_extents(GUI_ENTRY_REC * entry,GSList * list)1463 void gui_entry_set_text_and_extents(GUI_ENTRY_REC *entry, GSList *list)
1464 {
1465 GSList *tmp;
1466 int pos = -1;
1467 int is_extent = 1;
1468
1469 gui_entry_set_text(entry, "");
1470 for (tmp = list, is_extent = TRUE; tmp != NULL; tmp = tmp->next, is_extent ^= 1) {
1471 if (is_extent) {
1472 char *extent;
1473 int len;
1474
1475 if (tmp->data == NULL)
1476 continue;
1477
1478 extent = g_strdup(tmp->data);
1479 len = strlen(extent);
1480 if (len >= strlen(POS_FLAG) && g_strcmp0(&extent[len-strlen(POS_FLAG)], POS_FLAG) == 0) {
1481 char *tmp;
1482 tmp = extent;
1483 extent = g_strndup(tmp, len - strlen(POS_FLAG));
1484 g_free(tmp);
1485 pos = entry->pos;
1486 }
1487
1488 if (strlen(extent) > 0) {
1489 gui_entry_set_extent(entry, entry->pos, extent);
1490 }
1491 g_free(extent);
1492 } else {
1493 gui_entry_insert_text(entry, tmp->data);
1494 }
1495 }
1496 gui_entry_set_pos(entry, pos);
1497 }
1498
gui_entry_init(void)1499 void gui_entry_init(void)
1500 {
1501 }
1502
gui_entry_deinit(void)1503 void gui_entry_deinit(void)
1504 {
1505 }
1506