Permalink
Browse files

Rework in-game console & UI text editing.

The cursor position is now a character count, not a byte count.
However, the maximum length remains in bytes.
  • Loading branch information...
Darren Salt
Darren Salt committed May 4, 2012
1 parent 336e188 commit 263e3667c3badfc254f963928b1e34b5274b9ccf
View
@@ -724,6 +724,7 @@ set( CGAMEGPP
${GPP_DIR}/src/cgame/cg_particles.c
${GPP_DIR}/src/cgame/cg_tutorial.c
${GPP_DIR}/src/ui/ui_shared.c
+ ${GPP_DIR}/src/ui/ui_utf8.c
${MOUNT_DIR}/engine/qcommon/q_math.c
${MOUNT_DIR}/engine/qcommon/q_shared.c
${GPP_DIR}/src/cgame/cg_api.c
@@ -771,6 +772,7 @@ set( UIGPP
${GPP_DIR}/src/game/bg_lib.c
${MOUNT_DIR}/engine/qcommon/q_math.c
${MOUNT_DIR}/engine/qcommon/q_shared.c
+ ${GPP_DIR}/src/ui/ui_utf8.c
${GPP_DIR}/src/ui/ui_api.c
)
View
@@ -514,69 +514,50 @@ void Field_KeyDownEvent( field_t *edit, int key )
}
key = tolower( key );
- len = strlen( edit->buffer );
- s = &edit->buffer[ edit->cursor ];
- width = Q_UTF8Width( edit->buffer + edit->cursor );
+ len = Q_UTF8Strlen( edit->buffer );
+ s = &edit->buffer[ Field_CursorToOffset( edit ) ];
+ width = Q_UTF8Width( s );
switch ( key )
{
case K_DEL:
- if ( edit->cursor + width < len )
+ if ( *s )
{
- memmove( edit->buffer + edit->cursor,
- edit->buffer + edit->cursor + width, len - edit->cursor );
+ memmove( s, s + width, strlen( s + width ) + 1 );
}
break;
case K_RIGHTARROW:
- if ( edit->cursor + width < len )
+ if ( edit->cursor < len )
{
- edit->cursor += width;
+ edit->cursor++;
}
break;
case K_LEFTARROW:
- while ( edit->cursor > 0 )
+ if ( edit->cursor > 0 )
{
edit->cursor--;
- if( !Q_UTF8ContByte( edit->buffer[ edit->cursor ] ) )
- {
- break;
- }
}
break;
- case K_HOME:
- edit->cursor = 0;
-
case 'a':
if ( keys[ K_CTRL ].down )
{
+ case K_HOME:
edit->cursor = 0;
}
break;
- case K_END:
- while( s > edit->buffer && edit->cursor > 0 && Q_UTF8ContByte( *s ) )
- {
- edit->cursor--;
- s--;
- }
- break;
-
case 'e':
if ( keys[ K_CTRL ].down )
{
- while( s > edit->buffer && edit->cursor > 0 && Q_UTF8ContByte( *s ) )
- {
- edit->cursor--;
- s--;
- }
- break;
+ case K_END:
+ edit->cursor = len;
}
break;
@@ -591,13 +572,9 @@ void Field_KeyDownEvent( field_t *edit, int key )
{
edit->scroll = edit->cursor;
}
- else if ( edit->cursor >= edit->scroll + edit->widthInChars + Q_UTF8Width( edit->buffer + edit->scroll ) && edit->cursor <= len )
+ else if ( edit->cursor >= edit->scroll + edit->widthInChars )
{
edit->scroll = edit->cursor - edit->widthInChars + 1;
- while( Q_UTF8ContByte( edit->buffer[ edit->scroll ] && edit->scroll > 0 ) )
- {
- edit->scroll--;
- }
}
}
@@ -608,7 +585,7 @@ Field_CharEvent
*/
void Field_CharEvent( field_t *edit, const char *s )
{
- int len, width;
+ int len, width, oldWidth, offset;
if ( *s == 'v' - 'a' + 1 ) // ctrl-v is paste
{
@@ -627,21 +604,20 @@ void Field_CharEvent( field_t *edit, const char *s )
if ( *s == 'h' - 'a' + 1 ) // ctrl-h is backspace
{
- while ( edit->cursor > 0 )
+ if ( edit->cursor )
{
- qboolean isContinue = Q_UTF8ContByte( edit->buffer[ edit->cursor - 1 ] );
- memmove( edit->buffer + edit->cursor - 1,
- edit->buffer + edit->cursor, len + 1 - edit->cursor );
- edit->cursor--;
+ int posFrom, posTo;
+
+ posFrom = Field_CursorToOffset( edit );
+ --edit->cursor;
+ posTo = Field_CursorToOffset( edit );
+
+ memmove( edit->buffer + posTo, edit->buffer + posFrom, len + 1 - posFrom );
if ( edit->cursor < edit->scroll )
{
edit->scroll--;
}
- if( !isContinue )
- {
- break;
- }
}
return;
@@ -656,7 +632,7 @@ void Field_CharEvent( field_t *edit, const char *s )
if ( *s == 'e' - 'a' + 1 ) // ctrl-e is end
{
- edit->cursor = len;
+ edit->cursor = Field_OffsetToCursor( edit, len );
edit->scroll = edit->cursor - edit->widthInChars;
return;
}
@@ -669,47 +645,27 @@ void Field_CharEvent( field_t *edit, const char *s )
return;
}
- if ( key_overstrikeMode )
- {
- if ( edit->cursor == MAX_EDIT_LINE - 1 )
- {
- return;
- }
+ width = Q_UTF8Width( s );
+ offset = Field_CursorToOffset( edit );
- edit->buffer[ edit->cursor ] = *s;
- edit->cursor++;
- }
- else // insert mode
+ // if overstrike, adjust the width according to what's being replaced
+ // (at end-of-string, just insert)
+ oldWidth = ( key_overstrikeMode && edit->buffer[ offset ] ) ? Q_UTF8Width( edit->buffer + offset ) : 0;
+
+ if ( len + width - oldWidth >= MAX_EDIT_LINE )
{
- width = Q_UTF8Width( s );
- if ( len == MAX_EDIT_LINE - 1 )
- {
- return; // all full
- }
+ return;
+ }
- if( edit->cursor + width >= MAX_EDIT_LINE )
- {
- return;
- }
- memmove( edit->buffer + edit->cursor + width,
- edit->buffer + edit->cursor, len + 1 - edit->cursor );
+ memmove( edit->buffer + offset + width,
+ edit->buffer + offset + oldWidth, len + 1 - offset - oldWidth );
+ Com_Memcpy( edit->buffer + offset, s, width );
+ ++edit->cursor;
- Com_Memcpy( edit->buffer + edit->cursor, s, width );
- edit->cursor += width;
- }
- if ( edit->cursor >= edit->widthInChars )
- {
do
{
edit->scroll++;
- } while( Q_UTF8ContByte( edit->buffer[ edit->scroll ] ) && edit->scroll < edit->cursor );
-
- }
-
- if ( edit->cursor == len + 1 )
- {
- edit->buffer[ edit->cursor ] = 0;
- }
+ } while ( edit->cursor >= edit->scroll +edit->widthInChars );
}
/*
@@ -969,18 +925,7 @@ void Console_Key( int key )
if ( ( key == K_MWHEELUP && keys[ K_SHIFT ].down ) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
( ( tolower( key ) == 'p' ) && keys[ K_CTRL ].down ) )
{
- Q_strncpyz( g_consoleField.buffer, Hist_Prev(), sizeof( g_consoleField.buffer ) );
- g_consoleField.cursor = strlen( g_consoleField.buffer );
-
- if ( g_consoleField.cursor >= g_consoleField.widthInChars )
- {
- g_consoleField.scroll = g_consoleField.cursor - g_consoleField.widthInChars + 1;
- }
- else
- {
- g_consoleField.scroll = 0;
- }
-
+ Field_Set( &g_consoleField, Hist_Prev() );
con.acLength = 0;
return;
}
@@ -993,17 +938,7 @@ void Console_Key( int key )
if ( history )
{
- Q_strncpyz( g_consoleField.buffer, history, sizeof( g_consoleField.buffer ) );
- g_consoleField.cursor = strlen( g_consoleField.buffer );
-
- if ( g_consoleField.cursor >= g_consoleField.widthInChars )
- {
- g_consoleField.scroll = g_consoleField.cursor - g_consoleField.widthInChars + 1;
- }
- else
- {
- g_consoleField.scroll = 0;
- }
+ Field_Set( &g_consoleField, history );
}
else if ( g_consoleField.buffer[ 0 ] )
{
@@ -3991,6 +3991,17 @@ void Field_Clear( field_t *edit )
edit->scroll = 0;
}
+/*
+==================
+Field_SetCursor
+==================
+*/
+void Field_SetCursor( field_t *edit, int cursor )
+{
+ edit->cursor = cursor;
+ edit->scroll = ( cursor > edit->widthInChars ) ? ( cursor - edit->widthInChars ) : 0;
+}
+
/*
==================
Field_Set
@@ -4000,16 +4011,42 @@ void Field_Set( field_t *edit, const char *content )
{
memset( edit->buffer, 0, MAX_EDIT_LINE );
strncpy( edit->buffer, content, MAX_EDIT_LINE );
- edit->cursor = strlen( edit->buffer );
+ Field_SetCursor( edit, Q_UTF8Strlen( edit->buffer ) );
+}
- if ( edit->cursor > edit->widthInChars )
+/*
+==================
+Field_CursorToOffset
+==================
+*/
+int Field_CursorToOffset( field_t *edit )
+{
+ int i = -1, j = 0;
+
+ while ( ++i < edit->cursor )
{
- edit->scroll = edit->cursor - edit->widthInChars;
+ j += Q_UTF8Width( edit->buffer + j );
}
- else
+
+ return j;
+}
+
+/*
+==================
+Field_OffsetToCursor
+==================
+*/
+int Field_OffsetToCursor( field_t *edit, int offset )
+{
+ int i = 0, j = 0;
+
+ while ( i < offset )
{
- edit->scroll = 0;
+ i += Q_UTF8Width( edit->buffer + i );
+ ++j;
}
+
+ return j;
}
/*
@@ -4019,23 +4056,19 @@ Field_WordDelete
*/
void Field_WordDelete( field_t *edit )
{
- while ( edit->cursor )
- {
- if ( edit->buffer[ edit->cursor - 1 ] != ' ' )
- {
- edit->buffer[ edit->cursor - 1 ] = 0;
- edit->cursor--;
- }
- else
- {
- edit->cursor--;
+ int index = Field_CursorToOffset( edit );
+ int start = index;
- if ( edit->buffer[ edit->cursor - 1 ] != ' ' )
- {
- return;
- }
- }
- }
+ // search back past spaces
+ while ( --index >= 0 && edit->buffer[ index ] == ' ' ) {}
+
+ // search back past non-spaces
+ if ( index ) while ( --index >= 0 && edit->buffer[ index ] != ' ' ) {}
+
+ // strcpy would probably do, but possible overlap
+ memmove( edit->buffer + index, edit->buffer + start, strlen( edit->buffer + start ) + 1 );
+
+ Field_SetCursor( edit, Field_OffsetToCursor( edit, index ) );
}
static const char *completionString;
@@ -4215,7 +4248,7 @@ static qboolean Field_Complete( void )
Q_strncpyz( &completionField->buffer[ completionOffset ], shortestMatch,
sizeof( completionField->buffer ) - completionOffset );
- completionField->cursor = strlen( completionField->buffer );
+ completionField->cursor = Q_UTF8Strlen( completionField->buffer );
if ( matchCount == 1 )
{
@@ -927,6 +927,9 @@ void Field_CompleteDelay( void );
void Field_CompleteCommand( char *cmd,
qboolean doCommands, qboolean doCvars );
+int Field_OffsetToCursor( field_t *edit, int offset );
+int Field_CursorToOffset( field_t *edit );
+
/*
==============================================================
Oops, something went wrong.

0 comments on commit 263e366

Please sign in to comment.