mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-25 13:55:34 -05:00
Make textbox use character position instead of byte index for cursor.
This commit is contained in:
parent
acdd8ddb5a
commit
26d1e64b22
3 changed files with 38 additions and 34 deletions
|
@ -201,7 +201,7 @@ void textbox_text ( textbox *tb, const char *text )
|
||||||
textbox_moveresize ( tb, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h );
|
textbox_moveresize ( tb, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h );
|
||||||
}
|
}
|
||||||
|
|
||||||
tb->cursor = MAX ( 0, MIN ( ( int ) strlen ( text ), tb->cursor ) );
|
tb->cursor = MAX ( 0, MIN ( ( int ) g_utf8_strlen ( tb->text, -1 ), tb->cursor ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// within the parent handled auto width/height modes
|
// within the parent handled auto width/height modes
|
||||||
|
@ -284,8 +284,6 @@ static void texbox_update ( textbox *tb )
|
||||||
cairo_set_operator ( tb->main_draw, CAIRO_OPERATOR_SOURCE );
|
cairo_set_operator ( tb->main_draw, CAIRO_OPERATOR_SOURCE );
|
||||||
|
|
||||||
pango_cairo_update_layout ( tb->main_draw, tb->layout );
|
pango_cairo_update_layout ( tb->main_draw, tb->layout );
|
||||||
char *text = tb->text ? tb->text : "";
|
|
||||||
int text_len = strlen ( text );
|
|
||||||
int font_height = textbox_get_font_height ( tb );
|
int font_height = textbox_get_font_height ( tb );
|
||||||
|
|
||||||
int cursor_x = 0;
|
int cursor_x = 0;
|
||||||
|
@ -296,14 +294,14 @@ static void texbox_update ( textbox *tb )
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( tb->flags & TB_EDITABLE ) {
|
if ( tb->flags & TB_EDITABLE ) {
|
||||||
|
// We want to place the cursor based on the text shown.
|
||||||
|
const char *text = pango_layout_get_text ( tb->layout );
|
||||||
|
// Clamp the position, should not be needed, but we are paranoid.
|
||||||
|
int cursor_offset = MIN ( tb->cursor, g_utf8_strlen ( text, -1 ) );
|
||||||
PangoRectangle pos;
|
PangoRectangle pos;
|
||||||
int cursor_offset = 0;
|
// convert to byte location.
|
||||||
cursor_offset = MIN ( tb->cursor, text_len );
|
char *offset = g_utf8_offset_to_pointer ( text, cursor_offset );
|
||||||
if ( (tb->flags&TB_PASSWORD) == TB_PASSWORD ){
|
pango_layout_get_cursor_pos ( tb->layout, offset - text, &pos, NULL );
|
||||||
cursor_offset = g_utf8_pointer_to_offset ( tb->text, tb->text+cursor_offset );
|
|
||||||
}
|
|
||||||
pango_layout_get_cursor_pos ( tb->layout, cursor_offset, &pos, NULL );
|
|
||||||
// Add a small 4px offset between cursor and last glyph.
|
|
||||||
cursor_x = pos.x / PANGO_SCALE;
|
cursor_x = pos.x / PANGO_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +372,7 @@ void textbox_draw ( textbox *tb, cairo_t *draw )
|
||||||
// cursor handling for edit mode
|
// cursor handling for edit mode
|
||||||
void textbox_cursor ( textbox *tb, int pos )
|
void textbox_cursor ( textbox *tb, int pos )
|
||||||
{
|
{
|
||||||
int length = ( tb->text == NULL ) ? 0 : strlen ( tb->text );
|
int length = ( tb->text == NULL ) ? 0 : g_utf8_strlen ( tb->text, -1 );
|
||||||
tb->cursor = MAX ( 0, MIN ( length, pos ) );
|
tb->cursor = MAX ( 0, MIN ( length, pos ) );
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -382,15 +380,13 @@ void textbox_cursor ( textbox *tb, int pos )
|
||||||
// move right
|
// move right
|
||||||
void textbox_cursor_inc ( textbox *tb )
|
void textbox_cursor_inc ( textbox *tb )
|
||||||
{
|
{
|
||||||
int index = g_utf8_next_char ( &( tb->text[tb->cursor] ) ) - tb->text;
|
textbox_cursor ( tb, tb->cursor + 1 );
|
||||||
textbox_cursor ( tb, index );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// move left
|
// move left
|
||||||
void textbox_cursor_dec ( textbox *tb )
|
void textbox_cursor_dec ( textbox *tb )
|
||||||
{
|
{
|
||||||
int index = g_utf8_prev_char ( &( tb->text[tb->cursor] ) ) - tb->text;
|
textbox_cursor ( tb, tb->cursor - 1 );
|
||||||
textbox_cursor ( tb, index );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move word right
|
// Move word right
|
||||||
|
@ -400,7 +396,7 @@ static void textbox_cursor_inc_word ( textbox *tb )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Find word boundaries, with pango_Break?
|
// Find word boundaries, with pango_Break?
|
||||||
gchar *c = &( tb->text[tb->cursor] );
|
gchar *c = g_utf8_offset_to_pointer ( tb->text, tb->cursor );
|
||||||
while ( ( c = g_utf8_next_char ( c ) ) ) {
|
while ( ( c = g_utf8_next_char ( c ) ) ) {
|
||||||
gunichar uc = g_utf8_get_char ( c );
|
gunichar uc = g_utf8_get_char ( c );
|
||||||
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
||||||
|
@ -420,7 +416,7 @@ static void textbox_cursor_inc_word ( textbox *tb )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int index = c - tb->text;
|
int index = g_utf8_pointer_to_offset ( tb->text, c );
|
||||||
textbox_cursor ( tb, index );
|
textbox_cursor ( tb, index );
|
||||||
}
|
}
|
||||||
// move word left
|
// move word left
|
||||||
|
@ -428,7 +424,7 @@ static void textbox_cursor_dec_word ( textbox *tb )
|
||||||
{
|
{
|
||||||
// Find word boundaries, with pango_Break?
|
// Find word boundaries, with pango_Break?
|
||||||
gchar *n;
|
gchar *n;
|
||||||
gchar *c = &( tb->text[tb->cursor] );
|
gchar *c = g_utf8_offset_to_pointer ( tb->text, tb->cursor );
|
||||||
while ( ( c = g_utf8_prev_char ( c ) ) && c != tb->text ) {
|
while ( ( c = g_utf8_prev_char ( c ) ) && c != tb->text ) {
|
||||||
gunichar uc = g_utf8_get_char ( c );
|
gunichar uc = g_utf8_get_char ( c );
|
||||||
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
||||||
|
@ -451,7 +447,7 @@ static void textbox_cursor_dec_word ( textbox *tb )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int index = c - tb->text;
|
int index = g_utf8_pointer_to_offset ( tb->text, c );
|
||||||
textbox_cursor ( tb, index );
|
textbox_cursor ( tb, index );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,13 +459,15 @@ void textbox_cursor_end ( textbox *tb )
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tb->cursor = ( int ) strlen ( tb->text );
|
tb->cursor = ( int ) g_utf8_strlen ( tb->text, -1 );
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert text
|
// insert text
|
||||||
void textbox_insert ( textbox *tb, int pos, char *str, int slen )
|
void textbox_insert ( textbox *tb, int char_pos, char *str, int slen )
|
||||||
{
|
{
|
||||||
|
char *c = g_utf8_offset_to_pointer ( tb->text, char_pos );
|
||||||
|
int pos = c - tb->text;
|
||||||
int len = ( int ) strlen ( tb->text );
|
int len = ( int ) strlen ( tb->text );
|
||||||
pos = MAX ( 0, MIN ( len, pos ) );
|
pos = MAX ( 0, MIN ( len, pos ) );
|
||||||
// expand buffer
|
// expand buffer
|
||||||
|
@ -488,12 +486,19 @@ void textbox_insert ( textbox *tb, int pos, char *str, int slen )
|
||||||
// remove text
|
// remove text
|
||||||
void textbox_delete ( textbox *tb, int pos, int dlen )
|
void textbox_delete ( textbox *tb, int pos, int dlen )
|
||||||
{
|
{
|
||||||
int len = strlen ( tb->text );
|
int len = g_utf8_strlen ( tb->text, -1 );
|
||||||
|
if ( len == pos ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
pos = MAX ( 0, MIN ( len, pos ) );
|
pos = MAX ( 0, MIN ( len, pos ) );
|
||||||
|
if ( ( pos + dlen ) > len ) {
|
||||||
|
dlen = len - dlen;
|
||||||
|
}
|
||||||
// move everything after pos+dlen down
|
// move everything after pos+dlen down
|
||||||
char *at = tb->text + pos;
|
char *start = g_utf8_offset_to_pointer ( tb->text, pos );
|
||||||
|
char *end = g_utf8_offset_to_pointer ( tb->text, pos + dlen );
|
||||||
// Move remainder + closing \0
|
// Move remainder + closing \0
|
||||||
memmove ( at, at + dlen, len - pos - dlen + 1 );
|
memmove ( start, end, ( tb->text + strlen ( tb->text ) ) - end + 1 );
|
||||||
if ( tb->cursor >= pos && tb->cursor < ( pos + dlen ) ) {
|
if ( tb->cursor >= pos && tb->cursor < ( pos + dlen ) ) {
|
||||||
tb->cursor = pos;
|
tb->cursor = pos;
|
||||||
}
|
}
|
||||||
|
@ -511,8 +516,7 @@ void textbox_cursor_del ( textbox *tb )
|
||||||
if ( tb->text == NULL ) {
|
if ( tb->text == NULL ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int index = g_utf8_next_char ( &( tb->text[tb->cursor] ) ) - tb->text;
|
textbox_delete ( tb, tb->cursor, 1 );
|
||||||
textbox_delete ( tb, tb->cursor, index - tb->cursor );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// back up and delete one character
|
// back up and delete one character
|
||||||
|
@ -536,7 +540,7 @@ static void textbox_cursor_bkspc_word ( textbox *tb )
|
||||||
static void textbox_cursor_del_eol ( textbox *tb )
|
static void textbox_cursor_del_eol ( textbox *tb )
|
||||||
{
|
{
|
||||||
if ( tb->cursor >= 0 ) {
|
if ( tb->cursor >= 0 ) {
|
||||||
int length = strlen ( tb->text ) - tb->cursor;
|
int length = g_utf8_strlen ( tb->text, -1 ) - tb->cursor;
|
||||||
if ( length >= 0 ) {
|
if ( length >= 0 ) {
|
||||||
textbox_delete ( tb, tb->cursor, length );
|
textbox_delete ( tb, tb->cursor, length );
|
||||||
}
|
}
|
||||||
|
@ -640,7 +644,7 @@ gboolean textbox_append_char ( textbox *tb, char *pad, int pad_len )
|
||||||
if ( !g_unichar_iscntrl ( g_utf8_get_char ( pad ) ) ) {
|
if ( !g_unichar_iscntrl ( g_utf8_get_char ( pad ) ) ) {
|
||||||
tb->blink = 2;
|
tb->blink = 2;
|
||||||
textbox_insert ( tb, tb->cursor, pad, pad_len );
|
textbox_insert ( tb, tb->cursor, pad, pad_len );
|
||||||
textbox_cursor ( tb, tb->cursor + pad_len );
|
textbox_cursor ( tb, tb->cursor + 1 );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
@ -1152,7 +1152,7 @@ static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t
|
||||||
}
|
}
|
||||||
// Insert string move cursor.
|
// Insert string move cursor.
|
||||||
textbox_insert ( state->text, state->text->cursor, text, dl );
|
textbox_insert ( state->text, state->text->cursor, text, dl );
|
||||||
textbox_cursor ( state->text, state->text->cursor + dl );
|
textbox_cursor ( state->text, state->text->cursor + g_utf8_strlen(text, -1) );
|
||||||
// Force a redraw and refiltering of the text.
|
// Force a redraw and refiltering of the text.
|
||||||
state->update = TRUE;
|
state->update = TRUE;
|
||||||
state->refilter = TRUE;
|
state->refilter = TRUE;
|
||||||
|
|
Loading…
Reference in a new issue