Use SDL text input correctly, add basic composition support
This commit is contained in:
parent
da2ccc70fe
commit
3dbf6d7810
@ -7,3 +7,6 @@ void ClipboardPush(ByteString text);
|
|||||||
ByteString ClipboardPull();
|
ByteString ClipboardPull();
|
||||||
int GetModifiers();
|
int GetModifiers();
|
||||||
unsigned int GetTicks();
|
unsigned int GetTicks();
|
||||||
|
void StartTextInput();
|
||||||
|
void StopTextInput();
|
||||||
|
void SetTextInputRect(int x, int y, int w, int h);
|
||||||
|
@ -60,6 +60,26 @@ bool forceIntegerScaling = true;
|
|||||||
bool resizable = false;
|
bool resizable = false;
|
||||||
|
|
||||||
|
|
||||||
|
void StartTextInput()
|
||||||
|
{
|
||||||
|
SDL_StartTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopTextInput()
|
||||||
|
{
|
||||||
|
SDL_StopTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTextInputRect(int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
SDL_Rect rect;
|
||||||
|
rect.x = x;
|
||||||
|
rect.y = y;
|
||||||
|
rect.w = w;
|
||||||
|
rect.h = h;
|
||||||
|
SDL_SetTextInputRect(&rect);
|
||||||
|
}
|
||||||
|
|
||||||
void ClipboardPush(ByteString text)
|
void ClipboardPush(ByteString text)
|
||||||
{
|
{
|
||||||
SDL_SetClipboardText(text.c_str());
|
SDL_SetClipboardText(text.c_str());
|
||||||
@ -267,6 +287,13 @@ void EventProcess(SDL_Event event)
|
|||||||
}
|
}
|
||||||
engine->onTextInput(ByteString(event.text.text).FromUtf8());
|
engine->onTextInput(ByteString(event.text.text).FromUtf8());
|
||||||
break;
|
break;
|
||||||
|
case SDL_TEXTEDITING:
|
||||||
|
if (SDL_GetModState() & KMOD_GUI)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
engine->onTextEditing(ByteString(event.edit.text).FromUtf8(), event.edit.start);
|
||||||
|
break;
|
||||||
case SDL_MOUSEWHEEL:
|
case SDL_MOUSEWHEEL:
|
||||||
{
|
{
|
||||||
int x = event.wheel.x;
|
int x = event.wheel.x;
|
||||||
|
@ -69,6 +69,25 @@ bool forceIntegerScaling = true;
|
|||||||
bool resizable = false;
|
bool resizable = false;
|
||||||
bool momentumScroll = true;
|
bool momentumScroll = true;
|
||||||
|
|
||||||
|
void StartTextInput()
|
||||||
|
{
|
||||||
|
SDL_StartTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopTextInput()
|
||||||
|
{
|
||||||
|
SDL_StopTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTextInputRect(int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
SDL_Rect rect;
|
||||||
|
rect.x = x;
|
||||||
|
rect.y = y;
|
||||||
|
rect.w = w;
|
||||||
|
rect.h = h;
|
||||||
|
SDL_SetTextInputRect(&rect);
|
||||||
|
}
|
||||||
|
|
||||||
void ClipboardPush(ByteString text)
|
void ClipboardPush(ByteString text)
|
||||||
{
|
{
|
||||||
@ -425,6 +444,13 @@ void EventProcess(SDL_Event event)
|
|||||||
}
|
}
|
||||||
engine->onTextInput(ByteString(event.text.text).FromUtf8());
|
engine->onTextInput(ByteString(event.text.text).FromUtf8());
|
||||||
break;
|
break;
|
||||||
|
case SDL_TEXTEDITING:
|
||||||
|
if (SDL_GetModState() & KMOD_GUI)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
engine->onTextEditing(ByteString(event.edit.text).FromUtf8(), event.edit.start);
|
||||||
|
break;
|
||||||
case SDL_MOUSEWHEEL:
|
case SDL_MOUSEWHEEL:
|
||||||
{
|
{
|
||||||
int x = event.wheel.x;
|
int x = event.wheel.x;
|
||||||
|
@ -1282,8 +1282,6 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
|||||||
switch(scan)
|
switch(scan)
|
||||||
{
|
{
|
||||||
case SDL_SCANCODE_GRAVE:
|
case SDL_SCANCODE_GRAVE:
|
||||||
SDL_StopTextInput();
|
|
||||||
SDL_StartTextInput();
|
|
||||||
c->ShowConsole();
|
c->ShowConsole();
|
||||||
break;
|
break;
|
||||||
case SDL_SCANCODE_SPACE: //Space
|
case SDL_SCANCODE_SPACE: //Space
|
||||||
|
@ -19,7 +19,8 @@ Component::Component(Window* parent_state):
|
|||||||
Position(Point(0,0)),
|
Position(Point(0,0)),
|
||||||
Size(Point(0,0)),
|
Size(Point(0,0)),
|
||||||
Enabled(true),
|
Enabled(true),
|
||||||
Visible(true)
|
Visible(true),
|
||||||
|
DoesTextInput(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -35,7 +36,8 @@ Component::Component(Point position, Point size):
|
|||||||
Position(position),
|
Position(position),
|
||||||
Size(size),
|
Size(size),
|
||||||
Enabled(true),
|
Enabled(true),
|
||||||
Visible(true)
|
Visible(true),
|
||||||
|
DoesTextInput(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -51,7 +53,8 @@ Component::Component():
|
|||||||
Position(Point(0,0)),
|
Position(Point(0,0)),
|
||||||
Size(Point(0,0)),
|
Size(Point(0,0)),
|
||||||
Enabled(true),
|
Enabled(true),
|
||||||
Visible(true)
|
Visible(true),
|
||||||
|
DoesTextInput(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -201,6 +204,10 @@ void Component::OnTextInput(String text)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Component::OnTextEditing(String text)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void Component::OnMouseClick(int localx, int localy, unsigned button)
|
void Component::OnMouseClick(int localx, int localy, unsigned button)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ namespace ui
|
|||||||
ui::Point iconPosition;
|
ui::Point iconPosition;
|
||||||
ui::ContextMenu * menu;
|
ui::ContextMenu * menu;
|
||||||
Graphics * GetGraphics();
|
Graphics * GetGraphics();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Component(Window* parent_state);
|
Component(Window* parent_state);
|
||||||
Component(Point position, Point size);
|
Component(Point position, Point size);
|
||||||
@ -45,6 +46,7 @@ namespace ui
|
|||||||
Point Size;
|
Point Size;
|
||||||
bool Enabled;
|
bool Enabled;
|
||||||
bool Visible;
|
bool Visible;
|
||||||
|
bool DoesTextInput;
|
||||||
|
|
||||||
ui::Appearance Appearance;
|
ui::Appearance Appearance;
|
||||||
//virtual void SetAppearance(ui::Appearance);
|
//virtual void SetAppearance(ui::Appearance);
|
||||||
@ -204,5 +206,6 @@ namespace ui
|
|||||||
virtual void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
virtual void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
|
|
||||||
virtual void OnTextInput(String text);
|
virtual void OnTextInput(String text);
|
||||||
|
virtual void OnTextEditing(String text);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -259,10 +259,40 @@ void Engine::onKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Engine::onTextInput(String text)
|
void Engine::onTextInput(String text)
|
||||||
|
{
|
||||||
|
if (textInput)
|
||||||
{
|
{
|
||||||
if (state_ && !ignoreEvents)
|
if (state_ && !ignoreEvents)
|
||||||
state_->DoTextInput(text);
|
state_->DoTextInput(text);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::onTextEditing(String text, int start)
|
||||||
|
{
|
||||||
|
if (textInput)
|
||||||
|
{
|
||||||
|
// * SDL sends the candidate string in packets of some arbitrary size,
|
||||||
|
// leaving it up to the user to assemble these packets into the
|
||||||
|
// complete candidate string. The start parameter tells us which
|
||||||
|
// portion of the candidate string the current packet spans.
|
||||||
|
// * Sadly, there's no documented way to tell the first or last packet
|
||||||
|
// apart from the rest. While there's also no documented guarantee
|
||||||
|
// that the packets come in order and that there are no gaps or
|
||||||
|
// overlaps between them, the implementation on the SDL side seems to
|
||||||
|
// ensure this. So what we do is just append whatever packet we get
|
||||||
|
// to a buffer, which we reset every time a "first-y looking" packet
|
||||||
|
// arrives. We also forward a textediting event on every packet,
|
||||||
|
// which is redundant, but should be okay, as textediting events are
|
||||||
|
// not supposed to have an effect on the actual text being edited.
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
textEditingBuf.clear();
|
||||||
|
}
|
||||||
|
textEditingBuf.append(text);
|
||||||
|
if (state_ && !ignoreEvents)
|
||||||
|
state_->DoTextEditing(textEditingBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::onMouseClick(int x, int y, unsigned button)
|
void Engine::onMouseClick(int x, int y, unsigned button)
|
||||||
{
|
{
|
||||||
@ -318,3 +348,28 @@ void Engine::onFileDrop(ByteString filename)
|
|||||||
if (state_)
|
if (state_)
|
||||||
state_->DoFileDrop(filename);
|
state_->DoFileDrop(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Engine::StartTextInput()
|
||||||
|
{
|
||||||
|
if (textInput)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
textInput = true;
|
||||||
|
::StartTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::StopTextInput()
|
||||||
|
{
|
||||||
|
if (!textInput)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
::StopTextInput();
|
||||||
|
textInput = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::TextInputRect(Point position, Point size)
|
||||||
|
{
|
||||||
|
::SetTextInputRect(position.X * Scale, position.Y * Scale, size.X * Scale, size.Y * Scale);
|
||||||
|
}
|
||||||
|
@ -33,6 +33,7 @@ namespace ui
|
|||||||
void onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
void onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
void onKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
void onKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
void onTextInput(String text);
|
void onTextInput(String text);
|
||||||
|
void onTextEditing(String text, int start);
|
||||||
void onResize(int newWidth, int newHeight);
|
void onResize(int newWidth, int newHeight);
|
||||||
void onClose();
|
void onClose();
|
||||||
void onFileDrop(ByteString filename);
|
void onFileDrop(ByteString filename);
|
||||||
@ -80,6 +81,10 @@ namespace ui
|
|||||||
|
|
||||||
inline void SetSize(int width, int height);
|
inline void SetSize(int width, int height);
|
||||||
|
|
||||||
|
void StartTextInput();
|
||||||
|
void StopTextInput();
|
||||||
|
void TextInputRect(Point position, Point size);
|
||||||
|
|
||||||
//void SetState(Window* state);
|
//void SetState(Window* state);
|
||||||
//inline State* GetState() { return state_; }
|
//inline State* GetState() { return state_; }
|
||||||
inline Window* GetWindow() { return state_; }
|
inline Window* GetWindow() { return state_; }
|
||||||
@ -95,6 +100,8 @@ namespace ui
|
|||||||
bool forceIntegerScaling = true;
|
bool forceIntegerScaling = true;
|
||||||
bool resizable;
|
bool resizable;
|
||||||
|
|
||||||
|
bool textInput = false;
|
||||||
|
|
||||||
float dt;
|
float dt;
|
||||||
float fps;
|
float fps;
|
||||||
pixel * lastBuffer;
|
pixel * lastBuffer;
|
||||||
@ -125,6 +132,8 @@ namespace ui
|
|||||||
|
|
||||||
bool momentumScroll;
|
bool momentumScroll;
|
||||||
|
|
||||||
|
String textEditingBuf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline void SetMomentumScroll(bool newMomentumScroll)
|
inline void SetMomentumScroll(bool newMomentumScroll)
|
||||||
{
|
{
|
||||||
|
@ -6,10 +6,12 @@
|
|||||||
#include "PowderToy.h"
|
#include "PowderToy.h"
|
||||||
|
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
|
#include "graphics/FontReader.h"
|
||||||
|
|
||||||
#include "gui/interface/Point.h"
|
#include "gui/interface/Point.h"
|
||||||
#include "gui/interface/Keys.h"
|
#include "gui/interface/Keys.h"
|
||||||
#include "gui/interface/Mouse.h"
|
#include "gui/interface/Mouse.h"
|
||||||
|
#include "gui/interface/Engine.h"
|
||||||
|
|
||||||
#include "ContextMenu.h"
|
#include "ContextMenu.h"
|
||||||
|
|
||||||
@ -24,8 +26,11 @@ Textbox::Textbox(Point position, Point size, String textboxText, String textboxP
|
|||||||
characterDown(0),
|
characterDown(0),
|
||||||
mouseDown(false),
|
mouseDown(false),
|
||||||
masked(false),
|
masked(false),
|
||||||
border(true)
|
border(true),
|
||||||
|
inputRectPosition(0, 0),
|
||||||
|
textEditing(false)
|
||||||
{
|
{
|
||||||
|
DoesTextInput = true;
|
||||||
placeHolder = textboxPlaceholder;
|
placeHolder = textboxPlaceholder;
|
||||||
|
|
||||||
SetText(textboxText);
|
SetText(textboxText);
|
||||||
@ -56,6 +61,8 @@ void Textbox::SetPlaceholder(String text)
|
|||||||
|
|
||||||
void Textbox::SetText(String newText)
|
void Textbox::SetText(String newText)
|
||||||
{
|
{
|
||||||
|
StopTextEditing();
|
||||||
|
|
||||||
backingText = newText;
|
backingText = newText;
|
||||||
|
|
||||||
if(masked)
|
if(masked)
|
||||||
@ -69,14 +76,7 @@ void Textbox::SetText(String newText)
|
|||||||
|
|
||||||
cursor = newText.length();
|
cursor = newText.length();
|
||||||
|
|
||||||
if(cursor)
|
resetCursorPosition();
|
||||||
{
|
|
||||||
textWrapper.Index2Point(textWrapper.Clear2Index(cursor), cursorPositionX, cursorPositionY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cursorPositionY = cursorPositionX = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Textbox::ValidInput Textbox::GetInputType()
|
Textbox::ValidInput Textbox::GetInputType()
|
||||||
@ -106,6 +106,8 @@ String Textbox::GetText()
|
|||||||
|
|
||||||
void Textbox::OnContextMenuAction(int item)
|
void Textbox::OnContextMenuAction(int item)
|
||||||
{
|
{
|
||||||
|
StopTextEditing();
|
||||||
|
|
||||||
switch(item)
|
switch(item)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -121,9 +123,16 @@ void Textbox::OnContextMenuAction(int item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Textbox::resetCursorPosition()
|
void Textbox::resetCursorPosition()
|
||||||
|
{
|
||||||
|
if(cursor)
|
||||||
{
|
{
|
||||||
textWrapper.Index2Point(textWrapper.Clear2Index(cursor), cursorPositionX, cursorPositionY);
|
textWrapper.Index2Point(textWrapper.Clear2Index(cursor), cursorPositionX, cursorPositionY);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cursorPositionY = cursorPositionX = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Textbox::TabFocus()
|
void Textbox::TabFocus()
|
||||||
{
|
{
|
||||||
@ -133,6 +142,8 @@ void Textbox::TabFocus()
|
|||||||
|
|
||||||
void Textbox::cutSelection()
|
void Textbox::cutSelection()
|
||||||
{
|
{
|
||||||
|
StopTextEditing();
|
||||||
|
|
||||||
if (HasSelection())
|
if (HasSelection())
|
||||||
{
|
{
|
||||||
if (getLowerSelectionBound() < 0 || getHigherSelectionBound() > (int)backingText.length())
|
if (getLowerSelectionBound() < 0 || getHigherSelectionBound() > (int)backingText.length())
|
||||||
@ -167,20 +178,15 @@ void Textbox::cutSelection()
|
|||||||
updateSelection();
|
updateSelection();
|
||||||
TextPosition(displayTextWrapper.WrappedText());
|
TextPosition(displayTextWrapper.WrappedText());
|
||||||
|
|
||||||
if(cursor)
|
resetCursorPosition();
|
||||||
{
|
|
||||||
textWrapper.Index2Point(textWrapper.Clear2Index(cursor), cursorPositionX, cursorPositionY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cursorPositionY = cursorPositionX = 0;
|
|
||||||
}
|
|
||||||
if (actionCallback.change)
|
if (actionCallback.change)
|
||||||
actionCallback.change();
|
actionCallback.change();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Textbox::pasteIntoSelection()
|
void Textbox::pasteIntoSelection()
|
||||||
{
|
{
|
||||||
|
StopTextEditing();
|
||||||
|
|
||||||
String newText = format::CleanString(ClipboardPull().FromUtf8(), false, true, inputType != Multiline, inputType == Number || inputType == Numeric);
|
String newText = format::CleanString(ClipboardPull().FromUtf8(), false, true, inputType != Multiline, inputType == Number || inputType == Numeric);
|
||||||
if (HasSelection())
|
if (HasSelection())
|
||||||
{
|
{
|
||||||
@ -237,14 +243,7 @@ void Textbox::pasteIntoSelection()
|
|||||||
updateSelection();
|
updateSelection();
|
||||||
TextPosition(displayTextWrapper.WrappedText());
|
TextPosition(displayTextWrapper.WrappedText());
|
||||||
|
|
||||||
if(cursor)
|
resetCursorPosition();
|
||||||
{
|
|
||||||
textWrapper.Index2Point(textWrapper.Clear2Index(cursor), cursorPositionX, cursorPositionY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cursorPositionY = cursorPositionX = 0;
|
|
||||||
}
|
|
||||||
if (actionCallback.change)
|
if (actionCallback.change)
|
||||||
actionCallback.change();
|
actionCallback.change();
|
||||||
}
|
}
|
||||||
@ -280,6 +279,10 @@ bool Textbox::StringValid(String text)
|
|||||||
void Textbox::Tick(float dt)
|
void Textbox::Tick(float dt)
|
||||||
{
|
{
|
||||||
Label::Tick(dt);
|
Label::Tick(dt);
|
||||||
|
if (GetParentWindow() && Visible && Enabled && IsFocused())
|
||||||
|
{
|
||||||
|
ui::Engine::Ref().TextInputRect(GetScreenPos() + textPosition + inputRectPosition - Point(1, 3), Point(Size.X - textPosition.X - inputRectPosition.X, FONT_H + 2));
|
||||||
|
}
|
||||||
if (!IsFocused())
|
if (!IsFocused())
|
||||||
{
|
{
|
||||||
keyDown = 0;
|
keyDown = 0;
|
||||||
@ -336,19 +339,23 @@ void Textbox::OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
|||||||
switch(key)
|
switch(key)
|
||||||
{
|
{
|
||||||
case SDLK_HOME:
|
case SDLK_HOME:
|
||||||
|
StopTextEditing();
|
||||||
cursor = 0;
|
cursor = 0;
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
break;
|
break;
|
||||||
case SDLK_END:
|
case SDLK_END:
|
||||||
|
StopTextEditing();
|
||||||
cursor = backingText.length();
|
cursor = backingText.length();
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
break;
|
break;
|
||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
|
StopTextEditing();
|
||||||
if(cursor > 0)
|
if(cursor > 0)
|
||||||
cursor--;
|
cursor--;
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
break;
|
break;
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
|
StopTextEditing();
|
||||||
if (cursor < (int)backingText.length())
|
if (cursor < (int)backingText.length())
|
||||||
cursor++;
|
cursor++;
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
@ -356,6 +363,7 @@ void Textbox::OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
|||||||
case SDLK_DELETE:
|
case SDLK_DELETE:
|
||||||
if(ReadOnly)
|
if(ReadOnly)
|
||||||
break;
|
break;
|
||||||
|
StopTextEditing();
|
||||||
if (HasSelection())
|
if (HasSelection())
|
||||||
{
|
{
|
||||||
if (getLowerSelectionBound() < 0 || getHigherSelectionBound() > (int)backingText.length())
|
if (getLowerSelectionBound() < 0 || getHigherSelectionBound() > (int)backingText.length())
|
||||||
@ -382,6 +390,7 @@ void Textbox::OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
|||||||
case SDLK_BACKSPACE:
|
case SDLK_BACKSPACE:
|
||||||
if (ReadOnly)
|
if (ReadOnly)
|
||||||
break;
|
break;
|
||||||
|
StopTextEditing();
|
||||||
if (HasSelection())
|
if (HasSelection())
|
||||||
{
|
{
|
||||||
if (getLowerSelectionBound() < 0 || getHigherSelectionBound() > (int)backingText.length())
|
if (getLowerSelectionBound() < 0 || getHigherSelectionBound() > (int)backingText.length())
|
||||||
@ -455,19 +464,18 @@ void Textbox::AfterTextChange(bool changed)
|
|||||||
updateSelection();
|
updateSelection();
|
||||||
TextPosition(displayTextWrapper.WrappedText());
|
TextPosition(displayTextWrapper.WrappedText());
|
||||||
|
|
||||||
if(cursor)
|
resetCursorPosition();
|
||||||
{
|
|
||||||
textWrapper.Index2Point(textWrapper.Clear2Index(cursor), cursorPositionX, cursorPositionY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cursorPositionY = cursorPositionX = 0;
|
|
||||||
}
|
|
||||||
if (changed && actionCallback.change)
|
if (changed && actionCallback.change)
|
||||||
actionCallback.change();
|
actionCallback.change();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Textbox::OnTextInput(String text)
|
void Textbox::OnTextInput(String text)
|
||||||
|
{
|
||||||
|
StopTextEditing();
|
||||||
|
InsertText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Textbox::InsertText(String text)
|
||||||
{
|
{
|
||||||
if (StringValid(text) && !ReadOnly)
|
if (StringValid(text) && !ReadOnly)
|
||||||
{
|
{
|
||||||
@ -501,21 +509,80 @@ void Textbox::OnTextInput(String text)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Textbox::StartTextEditing()
|
||||||
|
{
|
||||||
|
if (ReadOnly || textEditing)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
textEditing = true;
|
||||||
|
selectionIndexLSave1 = selectionIndexL.clear_index;
|
||||||
|
selectionIndexHSave1 = selectionIndexH.clear_index;
|
||||||
|
backingTextSave1 = backingText;
|
||||||
|
cursorSave1 = cursor;
|
||||||
|
InsertText(String(""));
|
||||||
|
selectionIndexLSave2 = selectionIndexL.clear_index;
|
||||||
|
selectionIndexHSave2 = selectionIndexH.clear_index;
|
||||||
|
backingTextSave2 = backingText;
|
||||||
|
cursorSave2 = cursor;
|
||||||
|
inputRectPosition.X = cursorPositionX;
|
||||||
|
inputRectPosition.Y = cursorPositionY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Textbox::StopTextEditing()
|
||||||
|
{
|
||||||
|
if (ReadOnly || !textEditing)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
textEditing = false;
|
||||||
|
backingText = backingTextSave1;
|
||||||
|
AfterTextChange(true);
|
||||||
|
selectionIndexL = textWrapper.Clear2Index(selectionIndexLSave1);
|
||||||
|
selectionIndexH = textWrapper.Clear2Index(selectionIndexHSave1);
|
||||||
|
selectionIndex0 = selectionIndexL;
|
||||||
|
selectionIndex1 = selectionIndexH;
|
||||||
|
cursor = cursorSave1;
|
||||||
|
updateSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Textbox::OnTextEditing(String text)
|
||||||
|
{
|
||||||
|
if (!StringValid(text) || ReadOnly)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!text.size())
|
||||||
|
{
|
||||||
|
StopTextEditing();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StartTextEditing();
|
||||||
|
backingText = backingTextSave2;
|
||||||
|
AfterTextChange(true);
|
||||||
|
selectionIndexL = textWrapper.Clear2Index(selectionIndexLSave2);
|
||||||
|
selectionIndexH = textWrapper.Clear2Index(selectionIndexHSave2);
|
||||||
|
selectionIndex0 = selectionIndexL;
|
||||||
|
selectionIndex1 = selectionIndexH;
|
||||||
|
cursor = cursorSave2;
|
||||||
|
updateSelection();
|
||||||
|
InsertText(text);
|
||||||
|
selectionIndex1 = textWrapper.Clear2Index(cursor);
|
||||||
|
selectionIndex0 = textWrapper.Clear2Index(cursor - int(text.size()));
|
||||||
|
selectionIndexL = selectionIndex0;
|
||||||
|
selectionIndexH = selectionIndex1;
|
||||||
|
updateSelection();
|
||||||
|
}
|
||||||
|
|
||||||
void Textbox::OnMouseClick(int x, int y, unsigned button)
|
void Textbox::OnMouseClick(int x, int y, unsigned button)
|
||||||
{
|
{
|
||||||
if (button != SDL_BUTTON_RIGHT)
|
if (button != SDL_BUTTON_RIGHT)
|
||||||
{
|
{
|
||||||
|
StopTextEditing();
|
||||||
mouseDown = true;
|
mouseDown = true;
|
||||||
auto index = textWrapper.Point2Index(x-textPosition.X, y-textPosition.Y);
|
auto index = textWrapper.Point2Index(x-textPosition.X, y-textPosition.Y);
|
||||||
cursor = index.raw_index;
|
cursor = index.raw_index;
|
||||||
if(cursor)
|
resetCursorPosition();
|
||||||
{
|
|
||||||
textWrapper.Index2Point(index, cursorPositionX, cursorPositionY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cursorPositionY = cursorPositionX = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Label::OnMouseClick(x, y, button);
|
Label::OnMouseClick(x, y, button);
|
||||||
}
|
}
|
||||||
@ -532,14 +599,7 @@ void Textbox::OnMouseMoved(int localx, int localy, int dx, int dy)
|
|||||||
{
|
{
|
||||||
auto index = textWrapper.Point2Index(localx-textPosition.X, localy-textPosition.Y);
|
auto index = textWrapper.Point2Index(localx-textPosition.X, localy-textPosition.Y);
|
||||||
cursor = index.raw_index;
|
cursor = index.raw_index;
|
||||||
if(cursor)
|
resetCursorPosition();
|
||||||
{
|
|
||||||
textWrapper.Index2Point(index, cursorPositionX, cursorPositionY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cursorPositionY = cursorPositionX = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Label::OnMouseMoved(localx, localy, dx, dy);
|
Label::OnMouseMoved(localx, localy, dx, dy);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,9 @@ struct TextboxAction
|
|||||||
class Textbox : public Label
|
class Textbox : public Label
|
||||||
{
|
{
|
||||||
void AfterTextChange(bool changed);
|
void AfterTextChange(bool changed);
|
||||||
|
void InsertText(String text);
|
||||||
|
void StartTextEditing();
|
||||||
|
void StopTextEditing();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool ReadOnly;
|
bool ReadOnly;
|
||||||
@ -53,6 +56,7 @@ public:
|
|||||||
void OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
void OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
||||||
void OnTextInput(String text) override;
|
void OnTextInput(String text) override;
|
||||||
|
void OnTextEditing(String text) override;
|
||||||
void Draw(const Point& screenPos) override;
|
void Draw(const Point& screenPos) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -68,6 +72,21 @@ protected:
|
|||||||
String backingText;
|
String backingText;
|
||||||
String placeHolder;
|
String placeHolder;
|
||||||
|
|
||||||
|
// * Cursor state to reset to before inserting actual input in StopTextEditing.
|
||||||
|
int selectionIndexLSave1;
|
||||||
|
int selectionIndexHSave1;
|
||||||
|
String backingTextSave1;
|
||||||
|
int cursorSave1;
|
||||||
|
|
||||||
|
// * Cursor state to reset to before inserting a candidate string in OnTextEditing.
|
||||||
|
int selectionIndexLSave2;
|
||||||
|
int selectionIndexHSave2;
|
||||||
|
String backingTextSave2;
|
||||||
|
int cursorSave2;
|
||||||
|
|
||||||
|
Point inputRectPosition;
|
||||||
|
bool textEditing;
|
||||||
|
|
||||||
virtual void cutSelection();
|
virtual void cutSelection();
|
||||||
virtual void pasteIntoSelection();
|
virtual void pasteIntoSelection();
|
||||||
};
|
};
|
||||||
|
@ -261,6 +261,16 @@ void Window::DoTick(float dt)
|
|||||||
if (debugMode)
|
if (debugMode)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (focusedComponent_ && focusedComponent_->Visible && focusedComponent_->Enabled && focusedComponent_->DoesTextInput)
|
||||||
|
{
|
||||||
|
ui::Engine::Ref().StartTextInput();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui::Engine::Ref().StopTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
//on mouse hover
|
//on mouse hover
|
||||||
for (int i = Components.size() - 1; i >= 0 && !halt; --i)
|
for (int i = Components.size() - 1; i >= 0 && !halt; --i)
|
||||||
{
|
{
|
||||||
@ -435,6 +445,21 @@ void Window::DoTextInput(String text)
|
|||||||
finalise();
|
finalise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::DoTextEditing(String text)
|
||||||
|
{
|
||||||
|
if (focusedComponent_ != NULL)
|
||||||
|
{
|
||||||
|
if (focusedComponent_->Enabled && focusedComponent_->Visible)
|
||||||
|
focusedComponent_->OnTextEditing(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stop)
|
||||||
|
OnTextEditing(text);
|
||||||
|
if (destruct)
|
||||||
|
finalise();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Window::DoMouseDown(int x_, int y_, unsigned button)
|
void Window::DoMouseDown(int x_, int y_, unsigned button)
|
||||||
{
|
{
|
||||||
//on mouse click
|
//on mouse click
|
||||||
|
@ -68,6 +68,7 @@ namespace ui
|
|||||||
virtual void DoKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
virtual void DoKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
virtual void DoKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
virtual void DoKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
virtual void DoTextInput(String text);
|
virtual void DoTextInput(String text);
|
||||||
|
virtual void DoTextEditing(String text);
|
||||||
|
|
||||||
// Sets halt and destroy, this causes the Windows to stop sending events and remove itself.
|
// Sets halt and destroy, this causes the Windows to stop sending events and remove itself.
|
||||||
void SelfDestruct();
|
void SelfDestruct();
|
||||||
@ -107,6 +108,7 @@ namespace ui
|
|||||||
virtual void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) {}
|
virtual void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) {}
|
||||||
virtual void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) {}
|
virtual void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) {}
|
||||||
virtual void OnTextInput(String text) {}
|
virtual void OnTextInput(String text) {}
|
||||||
|
virtual void OnTextEditing(String text) {}
|
||||||
std::vector<Component*> Components;
|
std::vector<Component*> Components;
|
||||||
Component *focusedComponent_;
|
Component *focusedComponent_;
|
||||||
Component *hoverComponent;
|
Component *hoverComponent;
|
||||||
|
Reference in New Issue
Block a user