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