2013-08-18 14:16:11 +00:00
|
|
|
#include "TextEditComponent.h"
|
|
|
|
#include "../Log.h"
|
2013-10-04 23:24:41 +00:00
|
|
|
#include "../resources/Font.h"
|
2013-08-19 15:36:48 +00:00
|
|
|
#include "../Window.h"
|
|
|
|
#include "../Renderer.h"
|
2013-08-18 14:16:11 +00:00
|
|
|
|
|
|
|
TextEditComponent::TextEditComponent(Window* window) : GuiComponent(window),
|
2013-09-14 15:58:34 +00:00
|
|
|
mBox(window, ":/textbox.png"), mFocused(false),
|
2013-09-12 21:35:44 +00:00
|
|
|
mScrollOffset(0.0f, 0.0f), mCursor(0), mEditing(false)
|
2013-08-18 14:16:11 +00:00
|
|
|
{
|
|
|
|
addChild(&mBox);
|
|
|
|
|
|
|
|
onFocusLost();
|
|
|
|
|
2013-08-21 17:40:39 +00:00
|
|
|
setSize(256, (float)getFont()->getHeight());
|
2013-08-18 14:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextEditComponent::onFocusGained()
|
|
|
|
{
|
2013-09-14 15:58:34 +00:00
|
|
|
mBox.setImagePath(":/textbox_glow.png");
|
|
|
|
mBox.setEdgeColor(0x51CCFF00 | getOpacity());
|
|
|
|
|
2013-08-19 14:05:30 +00:00
|
|
|
SDL_StartTextInput();
|
2013-08-19 15:36:48 +00:00
|
|
|
mFocused = true;
|
2013-08-18 14:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextEditComponent::onFocusLost()
|
|
|
|
{
|
2013-09-14 15:58:34 +00:00
|
|
|
mBox.setImagePath(":/textbox.png");
|
|
|
|
mBox.setEdgeColor(0xFFFFFF00 | getOpacity());
|
|
|
|
|
2013-08-19 14:05:30 +00:00
|
|
|
SDL_StopTextInput();
|
2013-08-19 15:36:48 +00:00
|
|
|
mFocused = false;
|
2013-08-18 14:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextEditComponent::onSizeChanged()
|
|
|
|
{
|
2013-09-14 15:58:34 +00:00
|
|
|
mBox.fitTo(getSize());
|
2013-08-18 14:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextEditComponent::setValue(const std::string& val)
|
|
|
|
{
|
|
|
|
mText = val;
|
2013-08-21 19:49:33 +00:00
|
|
|
onTextChanged();
|
2013-08-18 14:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string TextEditComponent::getValue() const
|
|
|
|
{
|
|
|
|
return mText;
|
|
|
|
}
|
|
|
|
|
2013-08-19 15:36:48 +00:00
|
|
|
void TextEditComponent::textInput(const char* text)
|
2013-08-18 14:16:11 +00:00
|
|
|
{
|
2013-09-07 22:43:36 +00:00
|
|
|
if(mEditing)
|
2013-08-19 15:36:48 +00:00
|
|
|
{
|
|
|
|
if(text[0] == '\b')
|
|
|
|
{
|
2013-09-07 22:43:36 +00:00
|
|
|
if(mCursor > 0)
|
|
|
|
{
|
|
|
|
mText.erase(mText.begin() + mCursor - 1, mText.begin() + mCursor);
|
|
|
|
mCursor--;
|
|
|
|
}
|
2013-08-19 15:36:48 +00:00
|
|
|
}else{
|
2013-09-07 22:43:36 +00:00
|
|
|
mText.insert(mCursor, text);
|
|
|
|
mCursor++;
|
2013-08-19 15:36:48 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-21 19:49:33 +00:00
|
|
|
|
|
|
|
onTextChanged();
|
2013-09-07 22:43:36 +00:00
|
|
|
onCursorChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TextEditComponent::input(InputConfig* config, Input input)
|
|
|
|
{
|
|
|
|
if(input.value == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if(config->isMappedTo("a", input) && mFocused && !mEditing)
|
|
|
|
{
|
|
|
|
mEditing = true;
|
2014-01-25 23:34:29 +00:00
|
|
|
updateHelpPrompts();
|
2013-09-07 22:43:36 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mEditing)
|
|
|
|
{
|
|
|
|
if(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_RETURN)
|
|
|
|
{
|
2013-09-12 21:35:44 +00:00
|
|
|
if(isMultiline())
|
2014-01-25 23:34:29 +00:00
|
|
|
{
|
2013-09-12 21:35:44 +00:00
|
|
|
textInput("\n");
|
2014-01-25 23:34:29 +00:00
|
|
|
}else{
|
2013-09-14 15:58:34 +00:00
|
|
|
mEditing = false;
|
2014-01-25 23:34:29 +00:00
|
|
|
updateHelpPrompts();
|
|
|
|
}
|
2013-09-12 21:35:44 +00:00
|
|
|
|
2013-09-07 22:43:36 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-14 15:58:34 +00:00
|
|
|
if((config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_ESCAPE) || (config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedTo("b", input)))
|
2013-09-07 22:43:36 +00:00
|
|
|
{
|
|
|
|
mEditing = false;
|
2014-01-25 23:34:29 +00:00
|
|
|
updateHelpPrompts();
|
2013-09-07 22:43:36 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(config->isMappedTo("up", input))
|
|
|
|
{
|
|
|
|
|
|
|
|
}else if(config->isMappedTo("down", input))
|
|
|
|
{
|
|
|
|
|
|
|
|
}else if(config->isMappedTo("left", input))
|
|
|
|
{
|
|
|
|
mCursor--;
|
|
|
|
if(mCursor < 0)
|
|
|
|
mCursor = 0;
|
|
|
|
|
|
|
|
onCursorChanged();
|
|
|
|
}else if(config->isMappedTo("right", input))
|
|
|
|
{
|
|
|
|
mCursor++;
|
|
|
|
if(mText.length() == 0)
|
|
|
|
mCursor = 0;
|
2013-09-12 21:35:44 +00:00
|
|
|
if(mCursor >= (int)mText.length())
|
|
|
|
mCursor = mText.length();
|
2013-09-07 22:43:36 +00:00
|
|
|
|
|
|
|
onCursorChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
//consume all input when editing text
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2013-08-21 19:49:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextEditComponent::onTextChanged()
|
|
|
|
{
|
2013-08-22 01:08:36 +00:00
|
|
|
std::shared_ptr<Font> f = getFont();
|
|
|
|
|
2013-09-12 21:35:44 +00:00
|
|
|
std::string wrappedText = (isMultiline() ? f->wrapText(mText, mSize.x()) : mText);
|
2013-08-22 01:08:36 +00:00
|
|
|
mTextCache = std::unique_ptr<TextCache>(f->buildTextCache(wrappedText, 0, 0, 0x00000000 | getOpacity()));
|
2013-09-20 23:55:05 +00:00
|
|
|
|
|
|
|
if(mCursor > (int)mText.length())
|
|
|
|
mCursor = mText.length();
|
2013-08-21 19:49:33 +00:00
|
|
|
}
|
|
|
|
|
2013-09-07 22:43:36 +00:00
|
|
|
void TextEditComponent::onCursorChanged()
|
2013-08-21 19:49:33 +00:00
|
|
|
{
|
2013-09-07 22:43:36 +00:00
|
|
|
std::shared_ptr<Font> font = getFont();
|
|
|
|
|
2013-09-12 21:35:44 +00:00
|
|
|
if(isMultiline())
|
2013-09-07 22:43:36 +00:00
|
|
|
{
|
2013-09-12 21:35:44 +00:00
|
|
|
Eigen::Vector2f textSize = font->getWrappedTextCursorOffset(mText, mSize.x(), mCursor);
|
|
|
|
|
|
|
|
if(mScrollOffset.y() + mSize.y() < textSize.y() + font->getHeight()) //need to scroll down?
|
|
|
|
{
|
|
|
|
mScrollOffset[1] = textSize.y() - mSize.y() + font->getHeight();
|
|
|
|
}else if(mScrollOffset.y() > textSize.y()) //need to scroll up?
|
|
|
|
{
|
|
|
|
mScrollOffset[1] = textSize.y();
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
Eigen::Vector2f cursorPos = font->sizeText(mText.substr(0, mCursor));
|
|
|
|
|
|
|
|
if(mScrollOffset.x() + mSize.x() < cursorPos.x())
|
|
|
|
{
|
|
|
|
mScrollOffset[0] = cursorPos.x() - mSize.x();
|
|
|
|
}else if(mScrollOffset.x() > cursorPos.x())
|
|
|
|
{
|
|
|
|
mScrollOffset[0] = cursorPos.x();
|
|
|
|
}
|
2013-09-07 22:43:36 +00:00
|
|
|
}
|
2013-08-19 15:36:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextEditComponent::render(const Eigen::Affine3f& parentTrans)
|
|
|
|
{
|
|
|
|
Eigen::Affine3f trans = getTransform() * parentTrans;
|
|
|
|
renderChildren(trans);
|
|
|
|
|
2013-09-07 22:43:36 +00:00
|
|
|
Eigen::Vector2i clipPos((int)trans.translation().x(), (int)trans.translation().y());
|
|
|
|
Eigen::Vector3f dimScaled = trans * Eigen::Vector3f(mSize.x(), mSize.y(), 0);
|
|
|
|
Eigen::Vector2i clipDim((int)dimScaled.x() - trans.translation().x(), (int)dimScaled.y() - trans.translation().y());
|
|
|
|
Renderer::pushClipRect(clipPos, clipDim);
|
|
|
|
|
2013-09-12 21:35:44 +00:00
|
|
|
trans.translate(Eigen::Vector3f(-mScrollOffset.x(), -mScrollOffset.y(), 0));
|
2013-09-07 22:43:36 +00:00
|
|
|
|
2013-08-19 15:36:48 +00:00
|
|
|
Renderer::setMatrix(trans);
|
2013-09-07 22:43:36 +00:00
|
|
|
|
|
|
|
std::shared_ptr<Font> f = getFont();
|
2013-08-22 01:08:36 +00:00
|
|
|
if(mTextCache != NULL)
|
|
|
|
{
|
|
|
|
f->renderTextCache(mTextCache.get());
|
|
|
|
}
|
2013-09-07 22:43:36 +00:00
|
|
|
|
|
|
|
//draw cursor
|
|
|
|
if(mEditing)
|
|
|
|
{
|
2013-09-12 21:35:44 +00:00
|
|
|
Eigen::Vector2f cursorPos;
|
|
|
|
if(isMultiline())
|
|
|
|
{
|
|
|
|
cursorPos = f->getWrappedTextCursorOffset(mText, mSize.x(), mCursor);
|
|
|
|
}else{
|
|
|
|
cursorPos = f->sizeText(mText.substr(0, mCursor));
|
|
|
|
cursorPos[1] = 0;
|
|
|
|
}
|
|
|
|
|
2013-09-14 15:58:34 +00:00
|
|
|
Renderer::drawRect((int)cursorPos.x(), (int)cursorPos.y(), 3, f->getHeight(), 0x000000FF);
|
2013-09-07 22:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Renderer::popClipRect();
|
2013-08-19 15:36:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<Font> TextEditComponent::getFont()
|
|
|
|
{
|
2013-10-04 23:09:54 +00:00
|
|
|
return Font::get(FONT_SIZE_SMALL);
|
2013-08-18 14:16:11 +00:00
|
|
|
}
|
2013-09-12 21:35:44 +00:00
|
|
|
|
|
|
|
bool TextEditComponent::isMultiline()
|
|
|
|
{
|
|
|
|
return (getSize().y() > (float)getFont()->getHeight());
|
|
|
|
}
|
|
|
|
|
2013-09-20 23:55:05 +00:00
|
|
|
bool TextEditComponent::isEditing() const
|
|
|
|
{
|
|
|
|
return mEditing;
|
|
|
|
}
|
2014-01-25 23:34:29 +00:00
|
|
|
|
|
|
|
std::vector<HelpPrompt> TextEditComponent::getHelpPrompts()
|
|
|
|
{
|
|
|
|
std::vector<HelpPrompt> prompts;
|
|
|
|
if(mEditing)
|
|
|
|
{
|
|
|
|
prompts.push_back(HelpPrompt("up/down/left/right", "move cursor"));
|
|
|
|
prompts.push_back(HelpPrompt("b", "stop editing"));
|
|
|
|
}else{
|
|
|
|
prompts.push_back(HelpPrompt("a", "edit"));
|
|
|
|
}
|
|
|
|
return prompts;
|
|
|
|
}
|