testime: draw a blinking cursor at the text insertion point

This commit is contained in:
Sam Lantinga 2024-06-27 13:29:37 -07:00
parent 3d525331aa
commit 50250adba7
1 changed files with 38 additions and 29 deletions

View File

@ -40,6 +40,8 @@
#endif #endif
#define MAX_TEXT_LENGTH 256 #define MAX_TEXT_LENGTH 256
#define CURSOR_BLINK_INTERVAL_MS 500
static SDLTest_CommonState *state; static SDLTest_CommonState *state;
static SDL_FRect textRect, markedRect; static SDL_FRect textRect, markedRect;
static SDL_Color lineColor = { 0, 0, 0, 255 }; static SDL_Color lineColor = { 0, 0, 0, 255 };
@ -47,6 +49,8 @@ static SDL_Color backColor = { 255, 255, 255, 255 };
static SDL_Color textColor = { 0, 0, 0, 255 }; static SDL_Color textColor = { 0, 0, 0, 255 };
static char text[MAX_TEXT_LENGTH], markedText[MAX_TEXT_LENGTH]; static char text[MAX_TEXT_LENGTH], markedText[MAX_TEXT_LENGTH];
static int cursor = 0; static int cursor = 0;
static SDL_bool cursor_visible;
static Uint64 last_cursor_change;
#ifdef HAVE_SDL_TTF #ifdef HAVE_SDL_TTF
static TTF_Font *font; static TTF_Font *font;
#else #else
@ -461,18 +465,20 @@ static void CleanupVideo(void)
#endif #endif
} }
static void _Redraw(int rendererID) static void RedrawWindow(int rendererID)
{ {
SDL_Renderer *renderer = state->renderers[rendererID]; SDL_Renderer *renderer = state->renderers[rendererID];
SDL_FRect drawnTextRect, cursorRect, underlineRect; SDL_FRect drawnTextRect, cursorRect, underlineRect;
drawnTextRect.x = textRect.x;
drawnTextRect.y = 0;
drawnTextRect.w = 0;
drawnTextRect.h = 0;
SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a); SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
SDL_RenderFillRect(renderer, &textRect); SDL_RenderFillRect(renderer, &textRect);
/* Initialize the drawn text rectangle for the cursor */
drawnTextRect.x = textRect.x;
drawnTextRect.y = textRect.y + (textRect.h - UNIFONT_GLYPH_SIZE * UNIFONT_DRAW_SCALE) / 2;
drawnTextRect.w = 0.0f;
drawnTextRect.h = UNIFONT_GLYPH_SIZE * UNIFONT_DRAW_SCALE;
if (*text) { if (*text) {
#ifdef HAVE_SDL_TTF #ifdef HAVE_SDL_TTF
SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor); SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor);
@ -510,6 +516,7 @@ static void _Redraw(int rendererID)
#endif #endif
} }
/* The marked text rectangle is the text area that hasn't been filled by committed text */
markedRect.x = textRect.x + drawnTextRect.w; markedRect.x = textRect.x + drawnTextRect.w;
markedRect.w = textRect.w - drawnTextRect.w; markedRect.w = textRect.w - drawnTextRect.w;
if (markedRect.w < 0) { if (markedRect.w < 0) {
@ -520,16 +527,14 @@ static void _Redraw(int rendererID)
SDL_StartTextInput(state->windows[0]); SDL_StartTextInput(state->windows[0]);
} }
cursorRect = drawnTextRect; /* Update the drawn text rectangle for composition text, after the committed text */
cursorRect.x += cursorRect.w;
cursorRect.w = 2;
cursorRect.h = drawnTextRect.h;
drawnTextRect.x += drawnTextRect.w; drawnTextRect.x += drawnTextRect.w;
drawnTextRect.w = 0; drawnTextRect.w = 0;
SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a); /* Set the cursor to the new location, we'll update it as we go, below */
SDL_RenderFillRect(renderer, &markedRect); cursorRect = drawnTextRect;
cursorRect.w = 2;
cursorRect.h = drawnTextRect.h;
if (markedText[0]) { if (markedText[0]) {
#ifdef HAVE_SDL_TTF #ifdef HAVE_SDL_TTF
@ -585,10 +590,8 @@ static void _Redraw(int rendererID)
} }
#endif #endif
if (cursor > 0) {
cursorRect.y = drawnTextRect.y; cursorRect.y = drawnTextRect.y;
cursorRect.h = drawnTextRect.h; cursorRect.h = drawnTextRect.h;
}
underlineRect = markedRect; underlineRect = markedRect;
underlineRect.y = drawnTextRect.y + drawnTextRect.h - 2; underlineRect.y = drawnTextRect.y + drawnTextRect.h - 2;
@ -599,16 +602,25 @@ static void _Redraw(int rendererID)
SDL_RenderFillRect(renderer, &underlineRect); SDL_RenderFillRect(renderer, &underlineRect);
} }
/* Draw the cursor */
Uint64 now = SDL_GetTicks();
if ((now - last_cursor_change) >= CURSOR_BLINK_INTERVAL_MS) {
cursor_visible = !cursor_visible;
last_cursor_change = now;
}
if (cursor_visible) {
SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a); SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
SDL_RenderFillRect(renderer, &cursorRect); SDL_RenderFillRect(renderer, &cursorRect);
}
{ {
SDL_Rect inputrect; SDL_Rect inputrect;
inputrect.x = (int)markedRect.x; /* The input rect is a square at the cursor insertion point */
inputrect.y = (int)markedRect.y; inputrect.x = (int)cursorRect.x;
inputrect.w = (int)markedRect.w; inputrect.y = (int)cursorRect.y;
inputrect.h = (int)markedRect.h; inputrect.w = (int)cursorRect.h;
inputrect.h = (int)cursorRect.h;
SDL_SetTextInputRect(state->windows[0], &inputrect); SDL_SetTextInputRect(state->windows[0], &inputrect);
} }
} }
@ -625,7 +637,7 @@ static void Redraw(void)
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
/* Sending in the window id to let the font renderers know which one we're working with. */ /* Sending in the window id to let the font renderers know which one we're working with. */
_Redraw(i); RedrawWindow(i);
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }
@ -697,7 +709,7 @@ int main(int argc, char *argv[])
SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
} }
Redraw();
/* Main render loop */ /* Main render loop */
done = 0; done = 0;
while (!done) { while (!done) {
@ -709,7 +721,6 @@ int main(int argc, char *argv[])
switch (event.key.key) { switch (event.key.key) {
case SDLK_RETURN: case SDLK_RETURN:
text[0] = 0x00; text[0] = 0x00;
Redraw();
break; break;
case SDLK_BACKSPACE: case SDLK_BACKSPACE:
/* Only delete text if not in editing mode. */ /* Only delete text if not in editing mode. */
@ -736,8 +747,6 @@ int main(int argc, char *argv[])
break; break;
} }
} while (1); } while (1);
Redraw();
} }
break; break;
default: default:
@ -771,7 +780,6 @@ int main(int argc, char *argv[])
/* After text inputted, we can clear up markedText because it */ /* After text inputted, we can clear up markedText because it */
/* is committed */ /* is committed */
markedText[0] = 0; markedText[0] = 0;
Redraw();
break; break;
case SDL_EVENT_TEXT_EDITING: case SDL_EVENT_TEXT_EDITING:
@ -780,13 +788,14 @@ int main(int argc, char *argv[])
SDL_strlcpy(markedText, event.edit.text, sizeof(markedText)); SDL_strlcpy(markedText, event.edit.text, sizeof(markedText));
cursor = event.edit.start; cursor = event.edit.start;
Redraw();
break; break;
default: default:
break; break;
} }
} }
Redraw();
} }
SDL_free(fontname); SDL_free(fontname);
CleanupVideo(); CleanupVideo();