22using namespace igraphics;
24#define VIRTUAL_KEY_BIT 0x80000000
25#define STB_TEXTEDIT_K_SHIFT 0x40000000
26#define STB_TEXTEDIT_K_CONTROL 0x20000000
27#define STB_TEXTEDIT_K_ALT 0x10000000
29#define STB_TEXTEDIT_K_LEFT (VIRTUAL_KEY_BIT | kVK_LEFT)
30#define STB_TEXTEDIT_K_RIGHT (VIRTUAL_KEY_BIT | kVK_RIGHT)
31#define STB_TEXTEDIT_K_UP (VIRTUAL_KEY_BIT | kVK_UP)
32#define STB_TEXTEDIT_K_DOWN (VIRTUAL_KEY_BIT | kVK_DOWN)
33#define STB_TEXTEDIT_K_LINESTART (VIRTUAL_KEY_BIT | kVK_HOME)
34#define STB_TEXTEDIT_K_LINEEND (VIRTUAL_KEY_BIT | kVK_END)
35#define STB_TEXTEDIT_K_WORDLEFT (STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_CONTROL)
36#define STB_TEXTEDIT_K_WORDRIGHT (STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_CONTROL)
37#define STB_TEXTEDIT_K_TEXTSTART (STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_CONTROL)
38#define STB_TEXTEDIT_K_TEXTEND (STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_CONTROL)
39#define STB_TEXTEDIT_K_DELETE (VIRTUAL_KEY_BIT | kVK_DELETE)
40#define STB_TEXTEDIT_K_BACKSPACE (VIRTUAL_KEY_BIT | kVK_BACK)
41#define STB_TEXTEDIT_K_UNDO (STB_TEXTEDIT_K_CONTROL | 'z')
42#define STB_TEXTEDIT_K_REDO (STB_TEXTEDIT_K_CONTROL | STB_TEXTEDIT_K_SHIFT | 'z')
43#define STB_TEXTEDIT_K_INSERT (VIRTUAL_KEY_BIT | kVK_INSERT)
44#define STB_TEXTEDIT_K_PGUP (VIRTUAL_KEY_BIT | kVK_PRIOR)
45#define STB_TEXTEDIT_K_PGDOWN (VIRTUAL_KEY_BIT | kVK_NEXT)
47#define STB_TEXTEDIT_STRINGLEN(tc) ITextEntryControl::GetLength (tc)
48#define STB_TEXTEDIT_LAYOUTROW ITextEntryControl::Layout
49#define STB_TEXTEDIT_GETWIDTH(tc, n, i) ITextEntryControl::GetCharWidth (tc, n, i)
50#define STB_TEXTEDIT_KEYTOTEXT(key) \
51((key & VIRTUAL_KEY_BIT) ? 0 : ((key & STB_TEXTEDIT_K_CONTROL) ? 0 : (key & (~0xF0000000))));
52#define STB_TEXTEDIT_GETCHAR(tc, i) ITextEntryControl::GetChar (tc, i)
53#define STB_TEXTEDIT_NEWLINE '\n'
54#define STB_TEXTEDIT_IS_SPACE(ch) isspace(ch)
55#define STB_TEXTEDIT_DELETECHARS ITextEntryControl::DeleteChars
56#define STB_TEXTEDIT_INSERTCHARS ITextEntryControl::InsertChars
58#define STB_TEXTEDIT_IMPLEMENTATION
59#include "stb_textedit.h"
62ITextEntryControl::ITextEntryControl()
65 stb_textedit_initialize_state(&mEditState,
true);
67 SetActionFunction([&](
IControl* pCaller) {
71 SetAnimation([&](
IControl* pCaller) {
80 pCaller->OnEndAnimation();
91 g.
FillRect(mText.mTextEntryBGColor, mRECT);
94 Layout(&row,
this, 0);
96 const bool hasSelection = mEditState.select_start != mEditState.select_end;
99 float selectionStart = row.x0, selectionEnd = row.x0;
100 const int start = std::min(mEditState.select_start, mEditState.select_end);
101 const int end = std::max(mEditState.select_start, mEditState.select_end);
102 for (
int i = 0; i < mCharWidths.GetSize() && i < end; ++i)
105 selectionStart += mCharWidths.Get()[i];
107 selectionEnd += mCharWidths.Get()[i];
109 IRECT selectionRect(selectionStart, mRECT.T + row.ymin, selectionEnd, mRECT.T + row.ymax);
110 selectionRect = selectionRect.
GetVPadded(-mText.mSize*0.1f);
111 IBlend blend(EBlend::Default, 0.2f);
112 g.
FillRect(mText.mTextEntryFGColor, selectionRect, &blend);
117 if (mDrawCursor && !hasSelection)
119 float cursorPos = row.x0;
120 for (
int i = 0; i < mCharWidths.GetSize() && i < mEditState.cursor; ++i)
122 cursorPos += mCharWidths.Get()[i];
124 IRECT cursorRect(roundf(cursorPos-1), mRECT.T + row.ymin, roundf(cursorPos), mRECT.T + row.ymax);
125 cursorRect = cursorRect.
GetVPadded(-mText.mSize*0.1f);
126 g.
FillRect(mText.mTextEntryFGColor, cursorRect);
130template<
typename Proc>
131bool ITextEntryControl::CallSTB(Proc proc)
133 auto oldState = mEditState;
136 if(memcmp(&oldState, &mEditState,
sizeof (STB_TexteditState)) != 0)
156 stb_textedit_click(
this, &mEditState, x, y);
163 switch (pMenu->GetChosenItemIdx()) {
164 case 0: Cut();
break;
165 case 1: CopySelection();
break;
166 case 2: Paste();
break;
182 stb_textedit_drag(
this, &mEditState, x, y);
197 stb_textedit_drag(
this, &mEditState, x, y);
233 CallSTB([&]() { stb_textedit_key(
this, &mEditState, STB_TEXTEDIT_K_REDO); });
235 CallSTB([&]() { stb_textedit_key(
this, &mEditState, STB_TEXTEDIT_K_UNDO); });
246 wdl_utf8_parsechar(key.utf8, &stbKey);
250 case kVK_SPACE: stbKey =
' ';
break;
251 case kVK_TAB:
return false;
252 case kVK_DELETE: stbKey = STB_TEXTEDIT_K_DELETE;
break;
253 case kVK_BACK: stbKey = STB_TEXTEDIT_K_BACKSPACE;
break;
254 case kVK_LEFT: stbKey = STB_TEXTEDIT_K_LEFT;
break;
255 case kVK_RIGHT: stbKey = STB_TEXTEDIT_K_RIGHT;
break;
256 case kVK_UP: stbKey = STB_TEXTEDIT_K_UP;
break;
257 case kVK_DOWN: stbKey = STB_TEXTEDIT_K_DOWN;
break;
258 case kVK_PRIOR: stbKey = STB_TEXTEDIT_K_PGUP;
break;
259 case kVK_NEXT: stbKey = STB_TEXTEDIT_K_PGDOWN;
break;
260 case kVK_HOME: stbKey = STB_TEXTEDIT_K_LINESTART;
break;
261 case kVK_END: stbKey = STB_TEXTEDIT_K_LINEEND;
break;
262 case kVK_RETURN: CommitEdit();
break;
263 case kVK_ESCAPE: DismissEdit();
break;
269 if(!pControlInTextEntry)
276 switch (pParam->
Type())
278 case IParam::kTypeEnum:
279 case IParam::kTypeInt:
280 case IParam::kTypeBool:
282 if (key.VK >=
'0' && key.VK <=
'9' && !key.S)
284 if (key.VK >= kVK_NUMPAD0 && key.VK <= kVK_NUMPAD9)
286 if (stbKey ==
'+' || stbKey ==
'-')
291 case IParam::kTypeDouble:
293 if (key.VK >=
'0' && key.VK <=
'9' && !key.S)
295 if (key.VK >= kVK_NUMPAD0 && key.VK <= kVK_NUMPAD9)
297 if (stbKey ==
'+' || stbKey ==
'-' || stbKey ==
'.')
309 stbKey = (key.VK) | VIRTUAL_KEY_BIT;
316 stbKey |= STB_TEXTEDIT_K_CONTROL;
318 stbKey |= STB_TEXTEDIT_K_ALT;
320 stbKey |= STB_TEXTEDIT_K_SHIFT;
322 return CallSTB([&]() { stb_textedit_key(
this, &mEditState, stbKey); }) ?
true :
false;
325void ITextEntryControl::OnEndAnimation()
331void ITextEntryControl::CopySelection()
333 if (mEditState.select_start != mEditState.select_end)
335 const int start = std::min(mEditState.select_start, mEditState.select_end);
336 const int end = std::max(mEditState.select_start, mEditState.select_end);
341void ITextEntryControl::Paste()
343 WDL_String fromClipboard;
344 if (
GetUI()->GetTextFromClipboard(fromClipboard))
348 stb_textedit_paste (
this, &mEditState, uText.data(), (
int) uText.size());
353void ITextEntryControl::Cut()
357 stb_textedit_cut(
this, &mEditState);
361void ITextEntryControl::SelectAll()
364 mEditState.select_start = 0;
365 mEditState.select_end =
static_cast<int>(mEditString.length());
370int ITextEntryControl::DeleteChars(
ITextEntryControl* _this,
size_t pos,
size_t num)
372 _this->mEditString.erase(pos, num);
374 _this->OnTextChange();
379int ITextEntryControl::InsertChars(
ITextEntryControl* _this,
size_t pos,
const char16_t* text,
size_t num)
381 _this->mEditString.insert(pos, text, num);
383 _this->OnTextChange();
390 return _this->mEditString[pos];
396 return static_cast<int>(_this->mEditString.size());
400void ITextEntryControl::Layout(StbTexteditRow* row,
ITextEntryControl* _this,
int start_i)
402 assert (start_i == 0);
404 _this->FillCharWidthCache();
405 float textWidth = 0.;
407 for (
int i = 0; i < _this->mCharWidths.GetSize(); i++)
409 textWidth += _this->mCharWidths.Get()[i];
412 row->num_chars = GetLength(_this);
413 row->baseline_y_delta = 1.25;
415 switch (_this->
GetText().mAlign)
420 row->x1 = row->x0 + textWidth;
425 row->x0 = _this->
GetRECT().
MW() - (textWidth * 0.5f);
426 row->x1 = row->x0 + textWidth;
431 row->x0 = _this->
GetRECT().R - textWidth;
432 row->x1 = row->x0 + textWidth;
436 switch (_this->
GetText().mVAlign)
443 case EVAlign::Middle:
448 case EVAlign::Bottom:
455 row->ymax = row->ymin +
static_cast<float> (_this->
GetText().mSize);
461 _this->FillCharWidthCache();
462 return _this->mCharWidths.Get()[i];
465void ITextEntryControl::OnStateChanged()
470void ITextEntryControl::OnTextChange()
472 mCharWidths.Resize(0,
false);
473 FillCharWidthCache();
476void ITextEntryControl::FillCharWidthCache()
479 if (mCharWidths.GetSize())
482 const int len =
static_cast<int>(mEditString.size());
483 mCharWidths.Resize(len,
false);
484 for (
int i = 0; i < len; ++i)
486 mCharWidths.Get()[i] = MeasureCharWidth(mEditString[i], i == 0 ? 0 : mEditString[i - 1]);
490void ITextEntryControl::CalcCursorSizes()
501float ITextEntryControl::MeasureCharWidth(
char16_t c,
char16_t nc)
511 return tcWidth - ncWidth;
518void ITextEntryControl::CreateTextEntry(
int paramIdx,
const IText& text,
const IRECT& bounds,
int length,
const char* str)
522 mText.mFGColor = mText.mTextEntryFGColor;
525 mEditState.cursor = 0;
531void ITextEntryControl::DismissEdit()
539void ITextEntryControl::CommitEdit()
547void ITextEntryControl::SetStr(
const char* str)
549 mCharWidths.Resize(0,
false);
Utility functions and macros.
A Text entry widget drawn by IGraphics to optionally override platform text entries.
The lowest level base class of an IGraphics control.
const IRECT & GetRECT() const
Get the rectangular draw area for this control, within the graphics context.
virtual void SetText(const IText &txt)
Set the Text object typically used to determine font/layout/size etc of the main text in a control.
double GetAnimationProgress() const
Get the progress in a control's animation, in the range 0-1.
const IParam * GetParam(int valIdx=0) const
Get a const pointer to the IParam object (owned by the editor delegate class), associated with this c...
const IText & GetText() const
Get the Text object for the control.
void SetTargetAndDrawRECTs(const IRECT &bounds)
Set BOTH the draw rect and the target area, within the graphics context for this control.
virtual void SetDirty(bool triggerAction=true, int valIdx=kNoValIdx)
Mark the control as dirty, i.e.
The lowest level base class of an IGraphics context.
void DrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend=0)
Draw some text to the graphics context in a specific rectangle.
void CreatePopupMenu(IControl &control, IPopupMenu &menu, const IRECT &bounds, int valIdx=0)
Shows a pop up/contextual menu in relation to a rectangular region of the graphics context.
void ClearInTextEntryControl()
Called when the text entry is dismissed, to reset mInTextEntry.
virtual bool SetTextInClipboard(const char *str)=0
Set text in the clipboard.
virtual void FillRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill a rectangular region of the graphics context with a color.
void SetControlValueAfterTextEdit(const char *str)
Called by the platform class after returning from a text entry in order to update a control with a ne...
void SetAllControlsDirty()
Calls SetDirty() on every control.
IControl * GetControlInTextEntry()
virtual float MeasureText(const IText &text, const char *str, IRECT &bounds) const
Measure the rectangular region that some text will occupy.
EParamType Type() const
Get the parameter's type.
A Text entry widget drawn by IGraphics.
void OnMouseDown(float x, float y, const IMouseMod &mod) override
Implement this method to respond to a mouse down event on this control.
void Draw(IGraphics &g) override
Draw the control to the graphics context.
void OnMouseDrag(float x, float y, float dX, float dY, const IMouseMod &mod) override
Implement this method to respond to a mouse drag event on this control.
void OnMouseDblClick(float x, float y, const IMouseMod &mod) override
Implement this method to respond to a mouse double click event on this control.
bool OnKeyDown(float x, float y, const IKeyPress &key) override
Implement this method to respond to a key down event on this control.
void OnMouseUp(float x, float y, const IMouseMod &mod) override
Implement this method to respond to a mouse up event on this control.
static std::string UTF16ToUTF8String(const std::u16string &u16str)
Convert UTF-16 std::u16string to UTF-8 std::string using WDL functions.
static std::u16string UTF8ToUTF16String(const char *utf8)
Convert UTF-8 string to UTF-16 std::u16string using WDL functions.
Used to manage composite/blend operations, independent of draw class/platform.
Used for key press info, such as ASCII representation, virtual key (mapped to win32 codes) and modifi...
Used to manage mouse modifiers i.e.
Used to manage a rectangular area, independent of draw class/platform.
IRECT GetVPadded(float padding) const
Get a copy of this IRECT padded in the Y-axis N.B.
bool Contains(const IRECT &rhs) const
Returns true if this IRECT completely contains rhs.
IText is used to manage font and text/text entry style for a piece of text on the UI,...