forked from PsychoticNinja/ailin-nemui-irssi
Most of these have been deprecated since forever (2.2), but they didn't raise warnings. Now they do, and the warnings are not the most verbose warnings you could ask for, but, they point in the right direction. This doesn't handle the GTimeVal deprecation warnings. Those seem trickier since they cover API, will look into those right after this.
1506 lines
35 KiB
C
1506 lines
35 KiB
C
/*
|
|
gui-entry.c : irssi
|
|
|
|
Copyright (C) 1999 Timo Sirainen
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "module.h"
|
|
#include <irssi/src/core/misc.h>
|
|
#include <irssi/src/core/utf8.h>
|
|
#include <irssi/src/fe-common/core/formats.h>
|
|
|
|
#include <irssi/src/fe-text/gui-entry.h>
|
|
#include <irssi/src/fe-text/gui-printtext.h>
|
|
#include <irssi/src/fe-text/term.h>
|
|
#include <irssi/src/core/recode.h>
|
|
|
|
#undef i_toupper
|
|
#undef i_tolower
|
|
#undef i_isalnum
|
|
|
|
#define KILL_RING_MAX 10
|
|
|
|
static unichar i_toupper(unichar c)
|
|
{
|
|
if (term_type == TERM_TYPE_UTF8)
|
|
return g_unichar_toupper(c);
|
|
return c <= 255 ? toupper(c) : c;
|
|
}
|
|
|
|
static unichar i_tolower(unichar c)
|
|
{
|
|
if (term_type == TERM_TYPE_UTF8)
|
|
return g_unichar_tolower(c);
|
|
return c <= 255 ? tolower(c) : c;
|
|
}
|
|
|
|
static int i_isalnum(unichar c)
|
|
{
|
|
if (term_type == TERM_TYPE_UTF8)
|
|
return (g_unichar_isalnum(c) || i_wcwidth(c) == 0);
|
|
return c <= 255 ? isalnum(c) : 0;
|
|
}
|
|
|
|
GUI_ENTRY_REC *active_entry;
|
|
|
|
static void entry_text_grow(GUI_ENTRY_REC *entry, int grow_size)
|
|
{
|
|
if (entry->text_len+grow_size < entry->text_alloc)
|
|
return;
|
|
|
|
entry->text_alloc = nearest_power(entry->text_alloc+grow_size);
|
|
entry->text = g_realloc(entry->text,
|
|
sizeof(unichar) * entry->text_alloc);
|
|
|
|
if (entry->uses_extents)
|
|
entry->extents = g_realloc(entry->extents,
|
|
sizeof(char *) * entry->text_alloc);
|
|
}
|
|
|
|
GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
|
|
{
|
|
GUI_ENTRY_REC *rec;
|
|
|
|
rec = g_new0(GUI_ENTRY_REC, 1);
|
|
rec->xpos = xpos;
|
|
rec->ypos = ypos;
|
|
rec->width = width;
|
|
rec->text_alloc = 1024;
|
|
rec->text = g_new(unichar, rec->text_alloc);
|
|
rec->extents = NULL;
|
|
rec->text[0] = '\0';
|
|
rec->utf8 = utf8;
|
|
return rec;
|
|
}
|
|
|
|
static void destroy_extents(GUI_ENTRY_REC *entry)
|
|
{
|
|
if (entry->uses_extents) {
|
|
int i;
|
|
for (i = 0; i < entry->text_alloc; i++) {
|
|
if (entry->extents[i] != NULL) {
|
|
g_free(entry->extents[i]);
|
|
}
|
|
}
|
|
}
|
|
g_free(entry->extents);
|
|
entry->extents = NULL;
|
|
entry->uses_extents = FALSE;
|
|
}
|
|
|
|
void gui_entry_destroy(GUI_ENTRY_REC *entry)
|
|
{
|
|
GSList *tmp;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (active_entry == entry)
|
|
gui_entry_set_active(NULL);
|
|
|
|
for (tmp = entry->kill_ring; tmp != NULL; tmp = tmp->next) {
|
|
GUI_ENTRY_CUTBUFFER_REC *rec = tmp->data;
|
|
if (rec != NULL) {
|
|
g_free(rec->cutbuffer);
|
|
g_free(rec);
|
|
}
|
|
}
|
|
g_slist_free(entry->kill_ring);
|
|
|
|
destroy_extents(entry);
|
|
g_free(entry->text);
|
|
g_free(entry->prompt);
|
|
g_free(entry);
|
|
}
|
|
|
|
/* big5 functions */
|
|
#define big5_width(ch) ((ch)>0xff ? 2:1)
|
|
|
|
void unichars_to_big5(const unichar *str, char *out)
|
|
{
|
|
for (; *str != '\0'; str++) {
|
|
if (*str > 0xff)
|
|
*out++ = (*str >> 8) & 0xff;
|
|
*out++ = *str & 0xff;
|
|
}
|
|
*out = '\0';
|
|
}
|
|
|
|
int strlen_big5(const unsigned char *str)
|
|
{
|
|
int len=0;
|
|
|
|
while (*str != '\0') {
|
|
if (is_big5(str[0], str[1]))
|
|
str++;
|
|
len++;
|
|
str++;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
void unichars_to_big5_with_pos(const unichar *str, int spos, char *out, int *opos)
|
|
{
|
|
const unichar *sstart = str;
|
|
char *ostart = out;
|
|
|
|
*opos = 0;
|
|
while(*str != '\0')
|
|
{
|
|
if(*str > 0xff)
|
|
*out ++ = (*str >> 8) & 0xff;
|
|
*out ++ = *str & 0xff;
|
|
str ++;
|
|
if(str - sstart == spos)
|
|
*opos = out - ostart;
|
|
}
|
|
*out = '\0';
|
|
}
|
|
|
|
void big5_to_unichars(const char *str, unichar *out)
|
|
{
|
|
const unsigned char *p = (const unsigned char *) str;
|
|
|
|
while (*p != '\0') {
|
|
if (is_big5(p[0], p[1])) {
|
|
*out++ = p[0] << 8 | p[1];
|
|
p += 2;
|
|
} else {
|
|
*out++ = *p++;
|
|
}
|
|
}
|
|
*out = '\0';
|
|
}
|
|
|
|
/* Return screen length of plain string */
|
|
static int scrlen_str(const char *str, int utf8)
|
|
{
|
|
int len = 0;
|
|
char *stripped;
|
|
g_return_val_if_fail(str != NULL, 0);
|
|
|
|
stripped = strip_codes(str);
|
|
len = string_width(stripped, utf8 ? TREAT_STRING_AS_UTF8 : TREAT_STRING_AS_BYTES);
|
|
g_free(stripped);
|
|
return len;
|
|
}
|
|
|
|
/* ----------------------------- */
|
|
|
|
static int pos2scrpos(GUI_ENTRY_REC *entry, int pos, int cursor)
|
|
{
|
|
int i;
|
|
int xpos = 0;
|
|
|
|
if (!cursor && pos <= 0)
|
|
return 0;
|
|
|
|
if (entry->uses_extents && entry->extents[0] != NULL) {
|
|
xpos += scrlen_str(entry->extents[0], entry->utf8);
|
|
}
|
|
|
|
for (i = 0; i < entry->text_len && i < pos; i++) {
|
|
unichar c = entry->text[i];
|
|
const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
|
|
|
|
if (term_type == TERM_TYPE_BIG5)
|
|
xpos += big5_width(c);
|
|
else if (entry->utf8)
|
|
xpos += unichar_isprint(c) ? i_wcwidth(c) : 1;
|
|
else
|
|
xpos++;
|
|
|
|
if (extent != NULL) {
|
|
xpos += scrlen_str(extent, entry->utf8);
|
|
}
|
|
}
|
|
return xpos + pos - i;
|
|
}
|
|
|
|
static int scrpos2pos(GUI_ENTRY_REC *entry, int pos)
|
|
{
|
|
int i, width, xpos = 0;
|
|
|
|
if (entry->uses_extents && entry->extents[0] != NULL) {
|
|
xpos += scrlen_str(entry->extents[0], entry->utf8);
|
|
}
|
|
|
|
for (i = 0; i < entry->text_len && xpos < pos; i++) {
|
|
unichar c = entry->text[i];
|
|
const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
|
|
|
|
if (term_type == TERM_TYPE_BIG5)
|
|
width = big5_width(c);
|
|
else if (entry->utf8)
|
|
width = unichar_isprint(c) ? i_wcwidth(c) : 1;
|
|
else
|
|
width = 1;
|
|
|
|
xpos += width;
|
|
|
|
if (extent != NULL) {
|
|
xpos += scrlen_str(extent, entry->utf8);
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/* Fixes the cursor position in screen */
|
|
static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
|
|
{
|
|
int old_scrstart;
|
|
|
|
/* assume prompt len == prompt scrlen */
|
|
int start = pos2scrpos(entry, entry->scrstart, FALSE);
|
|
int now = pos2scrpos(entry, entry->pos, TRUE);
|
|
|
|
old_scrstart = entry->scrstart;
|
|
if (now-start < entry->width - 2 - entry->promptlen && now-start > 0) {
|
|
entry->scrpos = now-start;
|
|
} else if (now < entry->width - 1 - entry->promptlen) {
|
|
entry->scrstart = 0;
|
|
entry->scrpos = now;
|
|
} else {
|
|
entry->scrstart = scrpos2pos(entry, now-(entry->width -
|
|
entry->promptlen)*2/3);
|
|
start = pos2scrpos(entry, entry->scrstart, FALSE);
|
|
entry->scrpos = now - start;
|
|
}
|
|
|
|
if (old_scrstart != entry->scrstart)
|
|
entry->redraw_needed_from = 0;
|
|
}
|
|
|
|
static char *text_effects_only(const char *p)
|
|
{
|
|
GString *str;
|
|
|
|
str = g_string_sized_new(strlen(p));
|
|
for (; *p != '\0'; p++) {
|
|
if (*p == 4 && p[1] != '\0') {
|
|
if (p[1] >= FORMAT_STYLE_SPECIAL) {
|
|
g_string_append_len(str, p, 2);
|
|
p++;
|
|
continue;
|
|
}
|
|
|
|
/* irssi color */
|
|
if (p[2] != '\0') {
|
|
#ifdef TERM_TRUECOLOR
|
|
if (p[1] == FORMAT_COLOR_24) {
|
|
if (p[3] == '\0') p += 2;
|
|
else if (p[4] == '\0') p += 3;
|
|
else if (p[5] == '\0') p += 4;
|
|
else {
|
|
g_string_append_len(str, p, 6);
|
|
p += 5;
|
|
}
|
|
} else {
|
|
#endif /* TERM_TRUECOLOR */
|
|
g_string_append_len(str, p, 3);
|
|
p += 2;
|
|
#ifdef TERM_TRUECOLOR
|
|
}
|
|
#endif /* TERM_TRUECOLOR */
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return g_string_free(str, FALSE);
|
|
}
|
|
|
|
static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
|
|
{
|
|
int i, start;
|
|
int start_xpos, xpos, new_xpos, end_xpos;
|
|
char *tmp;
|
|
GString *str;
|
|
|
|
start = entry->scrstart + pos;
|
|
|
|
start_xpos = xpos = entry->xpos + entry->promptlen +
|
|
pos2scrpos(entry, start, FALSE) -
|
|
pos2scrpos(entry, entry->scrstart, FALSE);
|
|
end_xpos = entry->xpos + entry->width;
|
|
|
|
if (xpos > end_xpos)
|
|
return;
|
|
|
|
str = g_string_sized_new(entry->text_alloc);
|
|
|
|
term_set_color(root_window, ATTR_RESET);
|
|
/* term_move(root_window, xpos, entry->ypos); */
|
|
|
|
if (entry->uses_extents && entry->extents[0] != NULL) {
|
|
g_string_append(str, entry->extents[0]);
|
|
}
|
|
for (i = 0; i < start && i < entry->text_len; i++) {
|
|
const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
|
|
if (extent != NULL) {
|
|
g_string_append(str, extent);
|
|
}
|
|
}
|
|
if (i == 0) {
|
|
xpos += scrlen_str(str->str, entry->utf8);
|
|
} else {
|
|
tmp = text_effects_only(str->str);
|
|
g_string_assign(str, tmp);
|
|
g_free(tmp);
|
|
}
|
|
|
|
for (; i < entry->text_len; i++) {
|
|
unichar c = entry->text[i];
|
|
const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL;
|
|
new_xpos = xpos;
|
|
|
|
if (entry->hidden)
|
|
new_xpos++;
|
|
else if (term_type == TERM_TYPE_BIG5)
|
|
new_xpos += big5_width(c);
|
|
else if (entry->utf8)
|
|
new_xpos += unichar_isprint(c) ? i_wcwidth(c) : 1;
|
|
else
|
|
new_xpos++;
|
|
|
|
if (new_xpos > end_xpos)
|
|
break;
|
|
|
|
if (entry->hidden) {
|
|
g_string_append_c(str, ' ');
|
|
} else if (unichar_isprint(c)) {
|
|
if (entry->utf8) {
|
|
g_string_append_unichar(str, c);
|
|
} else if (term_type == TERM_TYPE_BIG5) {
|
|
if(c > 0xff)
|
|
g_string_append_c(str, (c >> 8) & 0xff);
|
|
g_string_append_c(str, c & 0xff);
|
|
} else {
|
|
g_string_append_c(str, c);
|
|
}
|
|
} else {
|
|
g_string_append_c(str, 4);
|
|
g_string_append_c(str, FORMAT_STYLE_REVERSE);
|
|
g_string_append_c(str, (c & 127)+'A'-1);
|
|
g_string_append_c(str, 4);
|
|
g_string_append_c(str, FORMAT_STYLE_REVERSE);
|
|
}
|
|
xpos = new_xpos;
|
|
|
|
if (extent != NULL) {
|
|
new_xpos += scrlen_str(extent, entry->utf8);
|
|
|
|
if (new_xpos > end_xpos)
|
|
break;
|
|
|
|
g_string_append(str, extent);
|
|
xpos = new_xpos;
|
|
}
|
|
}
|
|
|
|
/* clear the rest of the input line */
|
|
if (xpos < end_xpos) {
|
|
if (end_xpos == term_width) {
|
|
g_string_append_c(str, 4);
|
|
g_string_append_c(str, FORMAT_STYLE_CLRTOEOL);
|
|
} else {
|
|
while (xpos < end_xpos) {
|
|
g_string_append_c(str, ' ');
|
|
xpos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
gui_printtext_internal(start_xpos, entry->ypos, str->str);
|
|
g_string_free(str, TRUE);
|
|
}
|
|
|
|
static void gui_entry_draw(GUI_ENTRY_REC *entry)
|
|
{
|
|
if (entry->redraw_needed_from >= 0) {
|
|
gui_entry_draw_from(entry, entry->redraw_needed_from);
|
|
entry->redraw_needed_from = -1;
|
|
}
|
|
|
|
term_move_cursor(entry->xpos + entry->scrpos + entry->promptlen,
|
|
entry->ypos);
|
|
term_refresh(NULL);
|
|
}
|
|
|
|
static void gui_entry_redraw_from(GUI_ENTRY_REC *entry, int pos)
|
|
{
|
|
pos -= entry->scrstart;
|
|
if (pos < 0) pos = 0;
|
|
|
|
if (entry->redraw_needed_from == -1 ||
|
|
entry->redraw_needed_from > pos)
|
|
entry->redraw_needed_from = pos;
|
|
}
|
|
|
|
void gui_entry_move(GUI_ENTRY_REC *entry, int xpos, int ypos, int width)
|
|
{
|
|
int old_width;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (entry->xpos != xpos || entry->ypos != ypos) {
|
|
/* position in screen changed - needs a full redraw */
|
|
entry->xpos = xpos;
|
|
entry->ypos = ypos;
|
|
entry->width = width;
|
|
gui_entry_redraw(entry);
|
|
return;
|
|
}
|
|
|
|
if (entry->width == width)
|
|
return; /* no changes */
|
|
|
|
if (width > entry->width) {
|
|
/* input line grew - need to draw text at the end */
|
|
old_width = width;
|
|
entry->width = width;
|
|
gui_entry_redraw_from(entry, old_width);
|
|
} else {
|
|
/* input line shrinked - make sure the cursor
|
|
is inside the input line */
|
|
entry->width = width;
|
|
if (entry->pos - entry->scrstart >
|
|
entry->width-2 - entry->promptlen) {
|
|
gui_entry_fix_cursor(entry);
|
|
}
|
|
}
|
|
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_set_active(GUI_ENTRY_REC *entry)
|
|
{
|
|
active_entry = entry;
|
|
|
|
if (entry != NULL) {
|
|
term_move_cursor(entry->xpos + entry->scrpos +
|
|
entry->promptlen, entry->ypos);
|
|
term_refresh(NULL);
|
|
}
|
|
}
|
|
|
|
void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str)
|
|
{
|
|
int oldlen;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
oldlen = entry->promptlen;
|
|
if (str != NULL) {
|
|
g_free_not_null(entry->prompt);
|
|
entry->prompt = g_strdup(str);
|
|
entry->promptlen = scrlen_str(str, entry->utf8);
|
|
}
|
|
|
|
if (entry->prompt != NULL)
|
|
gui_printtext_internal(entry->xpos, entry->ypos, entry->prompt);
|
|
|
|
if (entry->promptlen != oldlen) {
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
}
|
|
|
|
void gui_entry_set_hidden(GUI_ENTRY_REC *entry, int hidden)
|
|
{
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
entry->hidden = hidden;
|
|
}
|
|
|
|
void gui_entry_set_utf8(GUI_ENTRY_REC *entry, int utf8)
|
|
{
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
entry->utf8 = utf8;
|
|
}
|
|
|
|
void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
|
|
{
|
|
g_return_if_fail(entry != NULL);
|
|
g_return_if_fail(str != NULL);
|
|
|
|
entry->text_len = 0;
|
|
entry->pos = 0;
|
|
entry->text[0] = '\0';
|
|
destroy_extents(entry);
|
|
|
|
gui_entry_insert_text(entry, str);
|
|
}
|
|
|
|
char *gui_entry_get_text(GUI_ENTRY_REC *entry)
|
|
{
|
|
char *buf;
|
|
int i;
|
|
|
|
g_return_val_if_fail(entry != NULL, NULL);
|
|
|
|
if (entry->utf8)
|
|
buf = g_ucs4_to_utf8(entry->text, -1, NULL, NULL, NULL);
|
|
else {
|
|
buf = g_malloc(entry->text_len*6 + 1);
|
|
if (term_type == TERM_TYPE_BIG5)
|
|
unichars_to_big5(entry->text, buf);
|
|
else
|
|
for (i = 0; i <= entry->text_len; i++)
|
|
buf[i] = entry->text[i];
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
char *gui_entry_get_text_and_pos(GUI_ENTRY_REC *entry, int *pos)
|
|
{
|
|
char *buf;
|
|
int i;
|
|
|
|
g_return_val_if_fail(entry != NULL, NULL);
|
|
|
|
if (entry->utf8) {
|
|
buf = g_ucs4_to_utf8(entry->text, -1, NULL, NULL, NULL);
|
|
*pos = g_utf8_offset_to_pointer(buf, entry->pos) - buf;
|
|
} else {
|
|
buf = g_malloc(entry->text_len*6 + 1);
|
|
if(term_type==TERM_TYPE_BIG5)
|
|
unichars_to_big5_with_pos(entry->text, entry->pos, buf, pos);
|
|
else
|
|
{
|
|
for (i = 0; i <= entry->text_len; i++)
|
|
buf[i] = entry->text[i];
|
|
*pos = entry->pos;
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
|
|
{
|
|
unichar chr;
|
|
int i, len;
|
|
const char *ptr;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
g_return_if_fail(str != NULL);
|
|
|
|
gui_entry_redraw_from(entry, entry->pos);
|
|
|
|
if (entry->utf8) {
|
|
g_utf8_validate(str, -1, &ptr);
|
|
len = g_utf8_pointer_to_offset(str, ptr);
|
|
} else if (term_type == TERM_TYPE_BIG5)
|
|
len = strlen_big5((const unsigned char *)str);
|
|
else
|
|
len = strlen(str);
|
|
entry_text_grow(entry, len);
|
|
|
|
/* make space for the string */
|
|
memmove(entry->text + entry->pos + len, entry->text + entry->pos,
|
|
(entry->text_len-entry->pos + 1) * sizeof(unichar));
|
|
|
|
/* make space for the color */
|
|
if (entry->uses_extents) {
|
|
memmove(entry->extents + entry->pos + len + 1, entry->extents + entry->pos + 1,
|
|
(entry->text_len-entry->pos) * sizeof(char *));
|
|
for (i = 0; i < len; i++) {
|
|
entry->extents[entry->pos + i + 1] = NULL;
|
|
}
|
|
}
|
|
|
|
if (!entry->utf8) {
|
|
if (term_type == TERM_TYPE_BIG5) {
|
|
chr = entry->text[entry->pos + len];
|
|
big5_to_unichars(str, entry->text + entry->pos);
|
|
entry->text[entry->pos + len] = chr;
|
|
} else {
|
|
for (i = 0; i < len; i++)
|
|
entry->text[entry->pos + i] = str[i];
|
|
}
|
|
} else {
|
|
ptr = str;
|
|
for (i = 0; i < len; i++) {
|
|
entry->text[entry->pos + i] = g_utf8_get_char(ptr);
|
|
ptr = g_utf8_next_char(ptr);
|
|
}
|
|
}
|
|
|
|
entry->text_len += len;
|
|
entry->pos += len;
|
|
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
|
|
{
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (chr == 0 || chr == 13 || chr == 10)
|
|
return; /* never insert NUL, CR or LF characters */
|
|
|
|
if (entry->utf8 && entry->pos == 0 && i_wcwidth(chr) == 0)
|
|
return;
|
|
|
|
gui_entry_redraw_from(entry, entry->pos);
|
|
|
|
entry_text_grow(entry, 1);
|
|
|
|
/* make space for the string */
|
|
memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
|
|
(entry->text_len-entry->pos + 1) * sizeof(unichar));
|
|
|
|
if (entry->uses_extents) {
|
|
memmove(entry->extents + entry->pos + 1 + 1, entry->extents + entry->pos + 1,
|
|
(entry->text_len-entry->pos) * sizeof(char *));
|
|
entry->extents[entry->pos + 1] = NULL;
|
|
}
|
|
|
|
entry->text[entry->pos] = chr;
|
|
entry->text_len++;
|
|
entry->pos++;
|
|
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
|
|
{
|
|
GUI_ENTRY_CUTBUFFER_REC *tmp;
|
|
char *buf;
|
|
int i;
|
|
|
|
g_return_val_if_fail(entry != NULL, NULL);
|
|
|
|
if (entry->kill_ring == NULL || entry->kill_ring->data == NULL)
|
|
return NULL;
|
|
|
|
tmp = entry->kill_ring->data;
|
|
|
|
if (tmp->cutbuffer == NULL)
|
|
return NULL;
|
|
|
|
if (entry->utf8)
|
|
buf = g_ucs4_to_utf8(tmp->cutbuffer, -1, NULL, NULL, NULL);
|
|
else {
|
|
buf = g_malloc(tmp->cutbuffer_len*6 + 1);
|
|
if (term_type == TERM_TYPE_BIG5)
|
|
unichars_to_big5(tmp->cutbuffer, buf);
|
|
else
|
|
for (i = 0; i <= tmp->cutbuffer_len; i++)
|
|
buf[i] = tmp->cutbuffer[i];
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
char *gui_entry_get_next_cutbuffer(GUI_ENTRY_REC *entry)
|
|
{
|
|
GUI_ENTRY_CUTBUFFER_REC *tmp;
|
|
|
|
g_return_val_if_fail(entry != NULL, NULL);
|
|
|
|
if (entry->kill_ring == NULL)
|
|
return NULL;
|
|
|
|
tmp = entry->kill_ring->data;
|
|
|
|
entry->kill_ring = g_slist_remove(entry->kill_ring, tmp);
|
|
entry->kill_ring = g_slist_append(entry->kill_ring, tmp);
|
|
|
|
return gui_entry_get_cutbuffer(entry);
|
|
}
|
|
|
|
void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, CUTBUFFER_UPDATE_OP update_cutbuffer)
|
|
{
|
|
int newpos, size = 0;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
for (newpos = gui_entry_get_pos(entry); newpos > pos; size++)
|
|
newpos = newpos - 1;
|
|
gui_entry_erase(entry, size, update_cutbuffer);
|
|
}
|
|
|
|
static GUI_ENTRY_CUTBUFFER_REC *get_cutbuffer_rec(GUI_ENTRY_REC *entry, CUTBUFFER_UPDATE_OP update_cutbuffer)
|
|
{
|
|
GUI_ENTRY_CUTBUFFER_REC *tmp;
|
|
|
|
g_return_val_if_fail(entry != NULL, NULL);
|
|
|
|
if (entry->kill_ring == NULL) {
|
|
/* no kill ring exists */
|
|
entry->kill_ring = g_slist_prepend(entry->kill_ring, (void *)NULL);
|
|
} else {
|
|
tmp = entry->kill_ring->data;
|
|
|
|
if (tmp != NULL && tmp->cutbuffer_len > 0
|
|
&& (!entry->previous_append_next_kill
|
|
|| update_cutbuffer == CUTBUFFER_UPDATE_REPLACE)) {
|
|
/* a cutbuffer exists and should be replaced */
|
|
entry->kill_ring = g_slist_prepend(entry->kill_ring, (void *)NULL);
|
|
}
|
|
}
|
|
|
|
if (g_slist_length(entry->kill_ring) > KILL_RING_MAX) {
|
|
GUI_ENTRY_CUTBUFFER_REC *rec = g_slist_last(entry->kill_ring)->data;
|
|
entry->kill_ring = g_slist_remove(entry->kill_ring, rec);
|
|
if (rec != NULL) g_free(rec->cutbuffer);
|
|
g_free(rec);
|
|
}
|
|
|
|
if (entry->kill_ring->data == NULL) {
|
|
entry->kill_ring->data = g_new0(GUI_ENTRY_CUTBUFFER_REC, 1);
|
|
}
|
|
|
|
return entry->kill_ring->data;
|
|
}
|
|
|
|
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer)
|
|
{
|
|
size_t i, w = 0;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (size == 0 || entry->pos < size)
|
|
return;
|
|
|
|
if (update_cutbuffer != CUTBUFFER_UPDATE_NOOP) {
|
|
int cutbuffer_new_size;
|
|
unichar *tmpcutbuffer;
|
|
GUI_ENTRY_CUTBUFFER_REC *tmp = get_cutbuffer_rec(entry, update_cutbuffer);
|
|
|
|
if (tmp->cutbuffer_len == 0) {
|
|
update_cutbuffer = CUTBUFFER_UPDATE_REPLACE;
|
|
}
|
|
|
|
cutbuffer_new_size = tmp->cutbuffer_len + size;
|
|
tmpcutbuffer = tmp->cutbuffer;
|
|
entry->append_next_kill = TRUE;
|
|
switch (update_cutbuffer) {
|
|
case CUTBUFFER_UPDATE_APPEND:
|
|
tmp->cutbuffer = g_new(unichar, cutbuffer_new_size+1);
|
|
memcpy(tmp->cutbuffer, tmpcutbuffer,
|
|
tmp->cutbuffer_len * sizeof(unichar));
|
|
memcpy(tmp->cutbuffer + tmp->cutbuffer_len,
|
|
entry->text + entry->pos - size, size * sizeof(unichar));
|
|
|
|
tmp->cutbuffer_len = cutbuffer_new_size;
|
|
tmp->cutbuffer[cutbuffer_new_size] = '\0';
|
|
g_free(tmpcutbuffer);
|
|
break;
|
|
|
|
case CUTBUFFER_UPDATE_PREPEND:
|
|
tmp->cutbuffer = g_new(unichar, cutbuffer_new_size+1);
|
|
memcpy(tmp->cutbuffer, entry->text + entry->pos - size,
|
|
size * sizeof(unichar));
|
|
memcpy(tmp->cutbuffer + size, tmpcutbuffer,
|
|
tmp->cutbuffer_len * sizeof(unichar));
|
|
|
|
tmp->cutbuffer_len = cutbuffer_new_size;
|
|
tmp->cutbuffer[cutbuffer_new_size] = '\0';
|
|
g_free(tmpcutbuffer);
|
|
break;
|
|
|
|
case CUTBUFFER_UPDATE_REPLACE:
|
|
/* put erased text to cutbuffer */
|
|
if (tmp->cutbuffer_len < size) {
|
|
g_free(tmp->cutbuffer);
|
|
tmp->cutbuffer = g_new(unichar, size+1);
|
|
}
|
|
|
|
tmp->cutbuffer_len = size;
|
|
tmp->cutbuffer[size] = '\0';
|
|
memcpy(tmp->cutbuffer, entry->text + entry->pos - size, size * sizeof(unichar));
|
|
break;
|
|
|
|
case CUTBUFFER_UPDATE_NOOP:
|
|
/* cannot happen, handled in "if" */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (entry->utf8)
|
|
while (entry->pos-size-w > 0 &&
|
|
i_wcwidth(entry->text[entry->pos-size-w]) == 0) w++;
|
|
|
|
memmove(entry->text + entry->pos - size, entry->text + entry->pos,
|
|
(entry->text_len-entry->pos+1) * sizeof(unichar));
|
|
|
|
if (entry->uses_extents) {
|
|
for (i = entry->pos - size; i < entry->pos; i++) {
|
|
if (entry->extents[i+1] != NULL) {
|
|
g_free(entry->extents[i+1]);
|
|
}
|
|
}
|
|
memmove(entry->extents + entry->pos - size + 1, entry->extents + entry->pos + 1,
|
|
(entry->text_len - entry->pos) * sizeof(void *)); /* no null terminator here */
|
|
for (i = 0; i < size; i++) {
|
|
entry->extents[entry->text_len - i] = NULL;
|
|
}
|
|
if (entry->text_len == size && entry->extents[0] != NULL) {
|
|
g_free(entry->extents[0]);
|
|
entry->extents[0] = NULL;
|
|
}
|
|
}
|
|
|
|
entry->pos -= size;
|
|
entry->text_len -= size;
|
|
|
|
gui_entry_redraw_from(entry, entry->pos-w);
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_erase_cell(GUI_ENTRY_REC *entry)
|
|
{
|
|
int size = 1;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (entry->utf8)
|
|
while (entry->pos+size < entry->text_len &&
|
|
i_wcwidth(entry->text[entry->pos+size]) == 0) size++;
|
|
|
|
memmove(entry->text + entry->pos, entry->text + entry->pos + size,
|
|
(entry->text_len-entry->pos-size+1) * sizeof(unichar));
|
|
|
|
if (entry->uses_extents) {
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
g_free(entry->extents[entry->pos + i + 1]);
|
|
}
|
|
memmove(entry->extents + entry->pos + 1, entry->extents + entry->pos + size + 1,
|
|
(entry->text_len-entry->pos-size) * sizeof(char *));
|
|
for (i = 0; i < size; i++) {
|
|
entry->extents[entry->text_len - i] = NULL;
|
|
}
|
|
if (entry->text_len == size && entry->extents[0] != NULL) {
|
|
g_free(entry->extents[0]);
|
|
entry->extents[0] = NULL;
|
|
}
|
|
}
|
|
|
|
entry->text_len -= size;
|
|
|
|
gui_entry_redraw_from(entry, entry->pos);
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op)
|
|
{
|
|
int to;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
if (entry->pos == 0)
|
|
return;
|
|
|
|
to = entry->pos - 1;
|
|
|
|
if (to_space) {
|
|
while (entry->text[to] == ' ' && to > 0)
|
|
to--;
|
|
while (entry->text[to] != ' ' && to > 0)
|
|
to--;
|
|
} else {
|
|
while (!i_isalnum(entry->text[to]) && to > 0)
|
|
to--;
|
|
while (i_isalnum(entry->text[to]) && to > 0)
|
|
to--;
|
|
}
|
|
if (to > 0) to++;
|
|
|
|
gui_entry_erase(entry, entry->pos-to, cutbuffer_op);
|
|
}
|
|
|
|
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op)
|
|
{
|
|
int to, size;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
if (entry->pos == entry->text_len)
|
|
return;
|
|
|
|
to = entry->pos;
|
|
if (to_space) {
|
|
while (entry->text[to] == ' ' && to < entry->text_len)
|
|
to++;
|
|
while (entry->text[to] != ' ' && to < entry->text_len)
|
|
to++;
|
|
} else {
|
|
while (!i_isalnum(entry->text[to]) && to < entry->text_len)
|
|
to++;
|
|
while (i_isalnum(entry->text[to]) && to < entry->text_len)
|
|
to++;
|
|
}
|
|
|
|
size = to-entry->pos;
|
|
entry->pos = to;
|
|
gui_entry_erase(entry, size, cutbuffer_op);
|
|
}
|
|
|
|
void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
|
|
{
|
|
unichar chr;
|
|
char *extent;
|
|
|
|
if (entry->pos == 0 || entry->text_len < 2)
|
|
return;
|
|
|
|
if (entry->pos == entry->text_len)
|
|
entry->pos--;
|
|
|
|
/* swap chars */
|
|
chr = entry->text[entry->pos];
|
|
entry->text[entry->pos] = entry->text[entry->pos-1];
|
|
entry->text[entry->pos-1] = chr;
|
|
|
|
if (entry->uses_extents) {
|
|
extent = entry->extents[entry->pos+1];
|
|
entry->extents[entry->pos+1] = entry->extents[entry->pos];
|
|
entry->extents[entry->pos] = extent;
|
|
}
|
|
|
|
entry->pos++;
|
|
|
|
gui_entry_redraw_from(entry, entry->pos-2);
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_transpose_words(GUI_ENTRY_REC *entry)
|
|
{
|
|
int spos1, epos1, spos2, epos2;
|
|
|
|
/* find last position */
|
|
epos2 = entry->pos;
|
|
while (epos2 < entry->text_len && !i_isalnum(entry->text[epos2]))
|
|
epos2++;
|
|
while (epos2 < entry->text_len && i_isalnum(entry->text[epos2]))
|
|
epos2++;
|
|
|
|
/* find other position */
|
|
spos2 = epos2;
|
|
while (spos2 > 0 && !i_isalnum(entry->text[spos2-1]))
|
|
spos2--;
|
|
while (spos2 > 0 && i_isalnum(entry->text[spos2-1]))
|
|
spos2--;
|
|
|
|
epos1 = spos2;
|
|
while (epos1 > 0 && !i_isalnum(entry->text[epos1-1]))
|
|
epos1--;
|
|
|
|
spos1 = epos1;
|
|
while (spos1 > 0 && i_isalnum(entry->text[spos1-1]))
|
|
spos1--;
|
|
|
|
/* do wordswap if any found */
|
|
if (spos1 < epos1 && epos1 < spos2 && spos2 < epos2) {
|
|
unichar *first, *sep, *second;
|
|
char **first_extent, **sep_extent, **second_extent;
|
|
int i;
|
|
|
|
first = (unichar *) g_malloc( (epos1 - spos1) * sizeof(unichar) );
|
|
sep = (unichar *) g_malloc( (spos2 - epos1) * sizeof(unichar) );
|
|
second = (unichar *) g_malloc( (epos2 - spos2) * sizeof(unichar) );
|
|
|
|
first_extent = (char **) g_malloc( (epos1 - spos1) * sizeof(char *) );
|
|
sep_extent = (char **) g_malloc( (spos2 - epos1) * sizeof(char *) );
|
|
second_extent = (char **) g_malloc( (epos2 - spos2) * sizeof(char *) );
|
|
|
|
for (i = spos1; i < epos1; i++) {
|
|
first[i-spos1] = entry->text[i];
|
|
if (entry->uses_extents)
|
|
first_extent[i-spos1] = entry->extents[i+1];
|
|
}
|
|
for (i = epos1; i < spos2; i++) {
|
|
sep[i-epos1] = entry->text[i];
|
|
if (entry->uses_extents)
|
|
sep_extent[i-epos1] = entry->extents[i+1];
|
|
}
|
|
for (i = spos2; i < epos2; i++) {
|
|
second[i-spos2] = entry->text[i];
|
|
if (entry->uses_extents)
|
|
second_extent[i-spos2] = entry->extents[i+1];
|
|
}
|
|
|
|
entry->pos = spos1;
|
|
for (i = 0; i < epos2-spos2; i++) {
|
|
entry->text[entry->pos] = second[i];
|
|
if (entry->uses_extents)
|
|
entry->extents[entry->pos+1] = second_extent[i];
|
|
entry->pos++;
|
|
}
|
|
for (i = 0; i < spos2-epos1; i++) {
|
|
entry->text[entry->pos] = sep[i];
|
|
if (entry->uses_extents)
|
|
entry->extents[entry->pos+1] = sep_extent[i];
|
|
entry->pos++;
|
|
}
|
|
for (i = 0; i < epos1-spos1; i++) {
|
|
entry->text[entry->pos] = first[i];
|
|
if (entry->uses_extents)
|
|
entry->extents[entry->pos+1] = first_extent[i];
|
|
entry->pos++;
|
|
}
|
|
|
|
g_free(first);
|
|
g_free(sep);
|
|
g_free(second);
|
|
|
|
g_free(first_extent);
|
|
g_free(sep_extent);
|
|
g_free(second_extent);
|
|
}
|
|
|
|
gui_entry_redraw_from(entry, spos1);
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_capitalize_word(GUI_ENTRY_REC *entry)
|
|
{
|
|
int pos = entry->pos;
|
|
while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
|
|
pos++;
|
|
|
|
if (pos < entry->text_len) {
|
|
entry->text[pos] = i_toupper(entry->text[pos]);
|
|
pos++;
|
|
}
|
|
|
|
while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
|
|
entry->text[pos] = i_tolower(entry->text[pos]);
|
|
pos++;
|
|
}
|
|
|
|
gui_entry_redraw_from(entry, entry->pos);
|
|
entry->pos = pos;
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_downcase_word(GUI_ENTRY_REC *entry)
|
|
{
|
|
int pos = entry->pos;
|
|
while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
|
|
pos++;
|
|
|
|
while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
|
|
entry->text[pos] = i_tolower(entry->text[pos]);
|
|
pos++;
|
|
}
|
|
|
|
gui_entry_redraw_from(entry, entry->pos);
|
|
entry->pos = pos;
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_upcase_word(GUI_ENTRY_REC *entry)
|
|
{
|
|
int pos = entry->pos;
|
|
while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
|
|
pos++;
|
|
|
|
while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
|
|
entry->text[pos] = i_toupper(entry->text[pos]);
|
|
pos++;
|
|
}
|
|
|
|
gui_entry_redraw_from(entry, entry->pos);
|
|
entry->pos = pos;
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
int gui_entry_get_pos(GUI_ENTRY_REC *entry)
|
|
{
|
|
g_return_val_if_fail(entry != NULL, 0);
|
|
|
|
return entry->pos;
|
|
}
|
|
|
|
void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos)
|
|
{
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (pos >= 0 && pos <= entry->text_len)
|
|
entry->pos = pos;
|
|
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_set_text_and_pos_bytes(GUI_ENTRY_REC *entry, const char *str, int pos_bytes)
|
|
{
|
|
int pos, extents_alloc;
|
|
char **extents;
|
|
const char *ptr;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
extents = entry->extents;
|
|
extents_alloc = entry->text_alloc;
|
|
entry->extents = NULL;
|
|
entry->uses_extents = FALSE;
|
|
|
|
gui_entry_set_text(entry, str);
|
|
|
|
if (entry->utf8) {
|
|
g_utf8_validate(str, pos_bytes, &ptr);
|
|
pos = g_utf8_pointer_to_offset(str, ptr);
|
|
} else if (term_type == TERM_TYPE_BIG5)
|
|
pos = strlen_big5((const unsigned char *)str) - strlen_big5((const unsigned char *)(str + pos_bytes));
|
|
else
|
|
pos = pos_bytes;
|
|
|
|
if (extents != NULL) {
|
|
entry->uses_extents = TRUE;
|
|
entry->extents = extents;
|
|
if (extents_alloc < entry->text_alloc) {
|
|
int i;
|
|
entry->extents = g_realloc(entry->extents,
|
|
sizeof(char *) * entry->text_alloc);
|
|
for (i = extents_alloc; i < entry->text_alloc; i++) {
|
|
entry->extents[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
gui_entry_redraw_from(entry, 0);
|
|
gui_entry_set_pos(entry, pos);
|
|
}
|
|
|
|
void gui_entry_move_pos(GUI_ENTRY_REC *entry, int pos)
|
|
{
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (entry->pos + pos >= 0 && entry->pos + pos <= entry->text_len)
|
|
entry->pos += pos;
|
|
|
|
if (entry->utf8) {
|
|
int step = pos < 0 ? -1 : 1;
|
|
while(i_wcwidth(entry->text[entry->pos]) == 0 &&
|
|
entry->pos + step >= 0 && entry->pos + step <= entry->text_len)
|
|
entry->pos += step;
|
|
}
|
|
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
static void gui_entry_move_words_left(GUI_ENTRY_REC *entry, int count, int to_space)
|
|
{
|
|
int pos;
|
|
|
|
pos = entry->pos;
|
|
while (count > 0 && pos > 0) {
|
|
if (to_space) {
|
|
while (pos > 0 && entry->text[pos-1] == ' ')
|
|
pos--;
|
|
while (pos > 0 && entry->text[pos-1] != ' ')
|
|
pos--;
|
|
} else {
|
|
while (pos > 0 && !i_isalnum(entry->text[pos-1]))
|
|
pos--;
|
|
while (pos > 0 && i_isalnum(entry->text[pos-1]))
|
|
pos--;
|
|
}
|
|
count--;
|
|
}
|
|
|
|
entry->pos = pos;
|
|
}
|
|
|
|
static void gui_entry_move_words_right(GUI_ENTRY_REC *entry, int count, int to_space)
|
|
{
|
|
int pos;
|
|
|
|
pos = entry->pos;
|
|
while (count > 0 && pos < entry->text_len) {
|
|
if (to_space) {
|
|
while (pos < entry->text_len && entry->text[pos] == ' ')
|
|
pos++;
|
|
while (pos < entry->text_len && entry->text[pos] != ' ')
|
|
pos++;
|
|
} else {
|
|
while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
|
|
pos++;
|
|
while (pos < entry->text_len && i_isalnum(entry->text[pos]))
|
|
pos++;
|
|
}
|
|
count--;
|
|
}
|
|
|
|
entry->pos = pos;
|
|
}
|
|
|
|
void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space)
|
|
{
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (count < 0)
|
|
gui_entry_move_words_left(entry, -count, to_space);
|
|
else if (count > 0)
|
|
gui_entry_move_words_right(entry, count, to_space);
|
|
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
void gui_entry_redraw(GUI_ENTRY_REC *entry)
|
|
{
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
gui_entry_set_prompt(entry, NULL);
|
|
gui_entry_redraw_from(entry, 0);
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
|
|
static void gui_entry_alloc_extents(GUI_ENTRY_REC *entry)
|
|
{
|
|
entry->uses_extents = TRUE;
|
|
entry->extents = g_new0(char *, entry->text_alloc);
|
|
}
|
|
|
|
void gui_entry_set_extent(GUI_ENTRY_REC *entry, int pos, const char *text)
|
|
{
|
|
int update = FALSE;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (pos < 0 || pos > entry->text_len)
|
|
return;
|
|
|
|
if (text == NULL)
|
|
return;
|
|
|
|
if (!entry->uses_extents) {
|
|
gui_entry_alloc_extents(entry);
|
|
}
|
|
|
|
if (g_strcmp0(entry->extents[pos], text) != 0) {
|
|
g_free(entry->extents[pos]);
|
|
if (*text == '\0') {
|
|
entry->extents[pos] = NULL;
|
|
} else {
|
|
entry->extents[pos] = g_strdup(text);
|
|
}
|
|
update = TRUE;
|
|
}
|
|
|
|
if (update) {
|
|
gui_entry_redraw_from(entry, pos - 1);
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
}
|
|
|
|
void gui_entry_set_extents(GUI_ENTRY_REC *entry, int pos, int len, const char *left, const char *right)
|
|
{
|
|
int end, update = FALSE;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (pos < 0 || len < 0 || pos > entry->text_len)
|
|
return;
|
|
|
|
end = pos + len;
|
|
|
|
if (end > entry->text_len)
|
|
end = entry->text_len;
|
|
|
|
if (!entry->uses_extents) {
|
|
gui_entry_alloc_extents(entry);
|
|
}
|
|
|
|
if (g_strcmp0(entry->extents[pos], left) != 0) {
|
|
g_free(entry->extents[pos]);
|
|
if (*left == '\0') {
|
|
entry->extents[pos] = NULL;
|
|
} else {
|
|
entry->extents[pos] = g_strdup(left);
|
|
}
|
|
update = TRUE;
|
|
}
|
|
|
|
if (pos != end && g_strcmp0(entry->extents[end], right) != 0) {
|
|
g_free(entry->extents[end]);
|
|
if (*right == '\0') {
|
|
entry->extents[end] = NULL;
|
|
} else {
|
|
entry->extents[end] = g_strdup(right);
|
|
}
|
|
update = TRUE;
|
|
}
|
|
|
|
if (update) {
|
|
gui_entry_redraw_from(entry, pos - 1);
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
}
|
|
|
|
void gui_entry_clear_extents(GUI_ENTRY_REC *entry, int pos, int len)
|
|
{
|
|
int i, end, update = FALSE;
|
|
|
|
g_return_if_fail(entry != NULL);
|
|
|
|
if (pos < 0 || len < 0 || pos > entry->text_len)
|
|
return;
|
|
|
|
end = pos + len;
|
|
|
|
if (end > entry->text_len)
|
|
end = entry->text_len;
|
|
|
|
if (!entry->uses_extents) {
|
|
return;
|
|
}
|
|
|
|
for (i = pos; i <= end; i++) {
|
|
if (entry->extents[i] != NULL) {
|
|
g_free(entry->extents[i]);
|
|
entry->extents[i] = NULL;
|
|
update = TRUE;
|
|
}
|
|
}
|
|
|
|
if (update) {
|
|
gui_entry_redraw_from(entry, pos);
|
|
gui_entry_fix_cursor(entry);
|
|
gui_entry_draw(entry);
|
|
}
|
|
}
|
|
|
|
char *gui_entry_get_extent(GUI_ENTRY_REC *entry, int pos)
|
|
{
|
|
g_return_val_if_fail(entry != NULL, NULL);
|
|
|
|
if (!entry->uses_extents)
|
|
return NULL;
|
|
|
|
if (pos < 0 || pos >= entry->text_len)
|
|
return NULL;
|
|
|
|
return entry->extents[pos];
|
|
}
|
|
|
|
#define POS_FLAG "%|"
|
|
GSList *gui_entry_get_text_and_extents(GUI_ENTRY_REC *entry)
|
|
{
|
|
GSList *list = NULL;
|
|
GString *str;
|
|
int i;
|
|
|
|
g_return_val_if_fail(entry != NULL, NULL);
|
|
|
|
if (entry->uses_extents && entry->extents[0] != NULL) {
|
|
if (entry->pos == 0) {
|
|
list = g_slist_prepend(list, g_strconcat(entry->extents[0], POS_FLAG, NULL));
|
|
} else {
|
|
list = g_slist_prepend(list, g_strdup(entry->extents[0]));
|
|
}
|
|
} else {
|
|
if (entry->pos == 0) {
|
|
list = g_slist_prepend(list, g_strdup(POS_FLAG));
|
|
} else {
|
|
list = g_slist_prepend(list, NULL);
|
|
}
|
|
}
|
|
|
|
str = g_string_sized_new(entry->text_alloc);
|
|
for (i = 0; i < entry->text_len; i++) {
|
|
if (entry->utf8) {
|
|
g_string_append_unichar(str, entry->text[i]);
|
|
} else if (term_type == TERM_TYPE_BIG5) {
|
|
if(entry->text[i] > 0xff)
|
|
g_string_append_c(str, (entry->text[i] >> 8) & 0xff);
|
|
g_string_append_c(str, entry->text[i] & 0xff);
|
|
} else {
|
|
g_string_append_c(str, entry->text[i]);
|
|
}
|
|
if (entry->pos == i+1 || (entry->uses_extents && entry->extents[i+1] != NULL)) {
|
|
list = g_slist_prepend(list, g_strdup(str->str));
|
|
g_string_truncate(str, 0);
|
|
if (entry->uses_extents && entry->extents[i+1] != NULL) {
|
|
if (entry->pos == i+1) {
|
|
list = g_slist_prepend(list, g_strconcat(entry->extents[i+1], POS_FLAG, NULL));
|
|
} else {
|
|
list = g_slist_prepend(list, g_strdup(entry->extents[i+1]));
|
|
}
|
|
} else if (entry->pos == i+1) {
|
|
list = g_slist_prepend(list, g_strdup(POS_FLAG));
|
|
}
|
|
}
|
|
}
|
|
if (str->len > 0) {
|
|
list = g_slist_prepend(list, g_strdup(str->str));
|
|
}
|
|
list = g_slist_reverse(list);
|
|
g_string_free(str, TRUE);
|
|
|
|
return list;
|
|
}
|
|
|
|
void gui_entry_set_text_and_extents(GUI_ENTRY_REC *entry, GSList *list)
|
|
{
|
|
GSList *tmp;
|
|
int pos = -1;
|
|
int is_extent = 1;
|
|
|
|
gui_entry_set_text(entry, "");
|
|
for (tmp = list, is_extent = TRUE; tmp != NULL; tmp = tmp->next, is_extent ^= 1) {
|
|
if (is_extent) {
|
|
char *extent;
|
|
int len;
|
|
|
|
if (tmp->data == NULL)
|
|
continue;
|
|
|
|
extent = g_strdup(tmp->data);
|
|
len = strlen(extent);
|
|
if (len >= strlen(POS_FLAG) && g_strcmp0(&extent[len-strlen(POS_FLAG)], POS_FLAG) == 0) {
|
|
char *tmp;
|
|
tmp = extent;
|
|
extent = g_strndup(tmp, len - strlen(POS_FLAG));
|
|
g_free(tmp);
|
|
pos = entry->pos;
|
|
}
|
|
|
|
if (strlen(extent) > 0) {
|
|
gui_entry_set_extent(entry, entry->pos, extent);
|
|
}
|
|
g_free(extent);
|
|
} else {
|
|
gui_entry_insert_text(entry, tmp->data);
|
|
}
|
|
}
|
|
gui_entry_set_pos(entry, pos);
|
|
}
|
|
|
|
void gui_entry_init(void)
|
|
{
|
|
}
|
|
|
|
void gui_entry_deinit(void)
|
|
{
|
|
}
|