Added a blinking cursor to TextEditComponent.

Also fixed a text field sizing bug and made a small padding adjustment.
This commit is contained in:
Leon Styhre 2021-09-17 21:40:48 +02:00
parent 08790ed1f3
commit bbaf2739d4
2 changed files with 59 additions and 53 deletions

View file

@ -10,25 +10,27 @@
#include "utils/StringUtil.h" #include "utils/StringUtil.h"
#define TEXT_PADDING_HORIZ 10.0f #define TEXT_PADDING_HORIZ 12.0f
#define TEXT_PADDING_VERT 2.0f #define TEXT_PADDING_VERT 2.0f
#define CURSOR_REPEAT_START_DELAY 500 #define CURSOR_REPEAT_START_DELAY 500
#define CURSOR_REPEAT_SPEED 28 // Lower is faster. #define CURSOR_REPEAT_SPEED 28 // Lower is faster.
#define BLINKTIME 1000
TextEditComponent::TextEditComponent(Window* window) TextEditComponent::TextEditComponent(Window* window)
: GuiComponent(window) : GuiComponent{window}
, mBox(window, ":/graphics/textinput.svg") , mBox{window, ":/graphics/textinput.svg"}
, mFocused(false) , mFocused{false}
, mScrollOffset(0.0f, 0.0f) , mScrollOffset{0.0f, 0.0f}
, mCursor(0) , mCursor{0}
, mEditing(false) , mEditing{false}
, mFont(Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT)) , mFont{Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT)}
, mCursorRepeatDir(0) , mCursorRepeatDir{0}
, mBlinkTime{0}
{ {
addChild(&mBox); addChild(&mBox);
onFocusLost(); onFocusLost();
mResolutionAdjustment = -(34.0f * Renderer::getScreenWidthModifier() - 34.0f);
setSize(4096, mFont->getHeight() + (TEXT_PADDING_VERT * Renderer::getScreenHeightModifier())); setSize(4096, mFont->getHeight() + (TEXT_PADDING_VERT * Renderer::getScreenHeightModifier()));
} }
@ -36,6 +38,7 @@ void TextEditComponent::onFocusGained()
{ {
mFocused = true; mFocused = true;
mBox.setImagePath(":/graphics/textinput_focused.svg"); mBox.setImagePath(":/graphics/textinput_focused.svg");
startEditing();
} }
void TextEditComponent::onFocusLost() void TextEditComponent::onFocusLost()
@ -46,9 +49,9 @@ void TextEditComponent::onFocusLost()
void TextEditComponent::onSizeChanged() void TextEditComponent::onSizeChanged()
{ {
mBox.fitTo(mSize, glm::vec3{}, mBox.fitTo(
glm::vec2{-34.0f + mResolutionAdjustment, mSize, glm::vec3{},
-32.0f - (TEXT_PADDING_VERT * Renderer::getScreenHeightModifier())}); glm::vec2{-34.0f, -32.0f - (TEXT_PADDING_VERT * Renderer::getScreenHeightModifier())});
onTextChanged(); // Wrap point probably changed. onTextChanged(); // Wrap point probably changed.
} }
@ -62,6 +65,7 @@ void TextEditComponent::setValue(const std::string& val)
void TextEditComponent::textInput(const std::string& text) void TextEditComponent::textInput(const std::string& text)
{ {
if (mEditing) { if (mEditing) {
mBlinkTime = 0;
mCursorRepeatDir = 0; mCursorRepeatDir = 0;
if (text[0] == '\b') { if (text[0] == '\b') {
if (mCursor > 0) { if (mCursor > 0) {
@ -82,17 +86,17 @@ void TextEditComponent::textInput(const std::string& text)
void TextEditComponent::startEditing() void TextEditComponent::startEditing()
{ {
if (!isMultiline())
setCursor(mText.size());
SDL_StartTextInput(); SDL_StartTextInput();
mEditing = true; mEditing = true;
updateHelpPrompts(); updateHelpPrompts();
mBlinkTime = BLINKTIME / 6;
} }
void TextEditComponent::stopEditing() void TextEditComponent::stopEditing()
{ {
SDL_StopTextInput(); SDL_StopTextInput();
mEditing = false; mEditing = false;
mCursorRepeatDir = 0;
updateHelpPrompts(); updateHelpPrompts();
} }
@ -141,41 +145,33 @@ bool TextEditComponent::input(InputConfig* config, Input input)
return true; return true;
} }
// Done editing (accept changes). if (cursor_left || cursor_right) {
if ((config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_ESCAPE) || mBlinkTime = 0;
(config->getDeviceId() != DEVICE_KEYBOARD &&
(config->isMappedTo("a", input) || config->isMappedTo("b", input)))) {
mTextOrig = mText;
stopEditing();
return true;
}
else if (cursor_left || cursor_right) {
mCursorRepeatDir = cursor_left ? -1 : 1; mCursorRepeatDir = cursor_left ? -1 : 1;
mCursorRepeatTimer = -(CURSOR_REPEAT_START_DELAY - CURSOR_REPEAT_SPEED); mCursorRepeatTimer = -(CURSOR_REPEAT_START_DELAY - CURSOR_REPEAT_SPEED);
moveCursor(mCursorRepeatDir); moveCursor(mCursorRepeatDir);
} }
else if (cursor_up) { // Stop editing and let the button down event be captured by the parent component.
// TODO
}
else if (cursor_down) { else if (cursor_down) {
// TODO stopEditing();
return false;
} }
else if (shoulder_left || shoulder_right) { else if (shoulder_left || shoulder_right) {
mBlinkTime = 0;
mCursorRepeatDir = shoulder_left ? -10 : 10; mCursorRepeatDir = shoulder_left ? -10 : 10;
mCursorRepeatTimer = -(CURSOR_REPEAT_START_DELAY - CURSOR_REPEAT_SPEED); mCursorRepeatTimer = -(CURSOR_REPEAT_START_DELAY - CURSOR_REPEAT_SPEED);
moveCursor(mCursorRepeatDir); moveCursor(mCursorRepeatDir);
} }
// Jump to beginning of text. // Jump to beginning of text.
else if (trigger_left) { else if (trigger_left) {
mBlinkTime = 0;
setCursor(0); setCursor(0);
} }
// Jump to end of text. // Jump to end of text.
else if (trigger_right) { else if (trigger_right) {
mBlinkTime = 0;
setCursor(mText.length()); setCursor(mText.length());
} }
else if (config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedTo("y", input)) {
textInput("\b");
}
else if (config->getDeviceId() == DEVICE_KEYBOARD) { else if (config->getDeviceId() == DEVICE_KEYBOARD) {
switch (input.id) { switch (input.id) {
case SDLK_HOME: { case SDLK_HOME: {
@ -207,6 +203,10 @@ void TextEditComponent::update(int deltaTime)
{ {
updateCursorRepeat(deltaTime); updateCursorRepeat(deltaTime);
GuiComponent::update(deltaTime); GuiComponent::update(deltaTime);
mBlinkTime += deltaTime;
if (mBlinkTime >= BLINKTIME)
mBlinkTime = 0;
} }
void TextEditComponent::updateCursorRepeat(int deltaTime) void TextEditComponent::updateCursorRepeat(int deltaTime)
@ -216,6 +216,7 @@ void TextEditComponent::updateCursorRepeat(int deltaTime)
mCursorRepeatTimer += deltaTime; mCursorRepeatTimer += deltaTime;
while (mCursorRepeatTimer >= CURSOR_REPEAT_SPEED) { while (mCursorRepeatTimer >= CURSOR_REPEAT_SPEED) {
mBlinkTime = 0;
moveCursor(mCursorRepeatDir); moveCursor(mCursorRepeatDir);
mCursorRepeatTimer -= CURSOR_REPEAT_SPEED; mCursorRepeatTimer -= CURSOR_REPEAT_SPEED;
} }
@ -298,7 +299,6 @@ void TextEditComponent::render(const glm::mat4& parentTrans)
Renderer::popClipRect(); Renderer::popClipRect();
// Draw cursor. // Draw cursor.
if (mEditing) {
glm::vec2 cursorPos; glm::vec2 cursorPos;
if (isMultiline()) { if (isMultiline()) {
cursorPos = mFont->getWrappedTextCursorOffset(mText, getTextAreaSize().x, mCursor); cursorPos = mFont->getWrappedTextCursorOffset(mText, getTextAreaSize().x, mCursor);
@ -309,23 +309,29 @@ void TextEditComponent::render(const glm::mat4& parentTrans)
} }
float cursorHeight = mFont->getHeight() * 0.8f; float cursorHeight = mFont->getHeight() * 0.8f;
if (!mEditing) {
Renderer::drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f, Renderer::drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f,
2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0x000000FF, 2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0xC7C7C7FF,
0x000000FF); 0xC7C7C7FF);
}
if (mEditing && mBlinkTime < BLINKTIME / 2) {
Renderer::drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f,
2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0x777777FF,
0x777777FF);
} }
} }
glm::vec2 TextEditComponent::getTextAreaPos() const glm::vec2 TextEditComponent::getTextAreaPos() const
{ {
return glm::vec2{ return glm::vec2{(TEXT_PADDING_HORIZ * Renderer::getScreenWidthModifier()) / 2.0f,
(-mResolutionAdjustment + (TEXT_PADDING_HORIZ * Renderer::getScreenWidthModifier())) / 2.0f,
(TEXT_PADDING_VERT * Renderer::getScreenHeightModifier()) / 2.0f}; (TEXT_PADDING_VERT * Renderer::getScreenHeightModifier()) / 2.0f};
} }
glm::vec2 TextEditComponent::getTextAreaSize() const glm::vec2 TextEditComponent::getTextAreaSize() const
{ {
return glm::vec2{mSize.x + mResolutionAdjustment - return glm::vec2{mSize.x - (TEXT_PADDING_HORIZ * Renderer::getScreenWidthModifier()),
(TEXT_PADDING_HORIZ * Renderer::getScreenWidthModifier()),
mSize.y - (TEXT_PADDING_VERT * Renderer::getScreenHeightModifier())}; mSize.y - (TEXT_PADDING_VERT * Renderer::getScreenHeightModifier())};
} }
@ -333,10 +339,10 @@ std::vector<HelpPrompt> TextEditComponent::getHelpPrompts()
{ {
std::vector<HelpPrompt> prompts; std::vector<HelpPrompt> prompts;
if (mEditing) { if (mEditing) {
prompts.push_back(HelpPrompt("up/down/left/right", "move cursor")); prompts.push_back(HelpPrompt("lt", "first"));
prompts.push_back(HelpPrompt("y", "backspace")); prompts.push_back(HelpPrompt("rt", "last"));
prompts.push_back(HelpPrompt("a", "accept changes")); prompts.push_back(HelpPrompt("left/right", "move cursor"));
prompts.push_back(HelpPrompt("b", "accept changes")); prompts.push_back(HelpPrompt("b", "back"));
} }
else { else {
prompts.push_back(HelpPrompt("a", "edit")); prompts.push_back(HelpPrompt("a", "edit"));

View file

@ -61,6 +61,7 @@ private:
bool mFocused; bool mFocused;
bool mEditing; bool mEditing;
unsigned int mCursor; // Cursor position in characters. unsigned int mCursor; // Cursor position in characters.
int mBlinkTime;
int mCursorRepeatTimer; int mCursorRepeatTimer;
int mCursorRepeatDir; int mCursorRepeatDir;
@ -68,7 +69,6 @@ private:
glm::vec2 mScrollOffset; glm::vec2 mScrollOffset;
NinePatchComponent mBox; NinePatchComponent mBox;
float mResolutionAdjustment;
std::shared_ptr<Font> mFont; std::shared_ptr<Font> mFont;
std::unique_ptr<TextCache> mTextCache; std::unique_ptr<TextCache> mTextCache;