3844: Add UI Ex class to share common ui implementations r=def- a=Jupeyy

Between menus and editor for example

Currently only did DoEditBox, as this created crashes in the editor

fixes #3395

It's copy and paste from the implementation of CMenus, except for 4 lines, which i'll mark below

## Checklist

- [x] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test if it works standalone, system.c especially
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Jupeyy <jupjopjap@gmail.com>
This commit is contained in:
bors[bot] 2021-05-26 13:21:01 +00:00 committed by GitHub
commit fbf3d6e943
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 328 additions and 408 deletions

View file

@ -1840,6 +1840,8 @@ if(CLIENT)
skin.h
ui.cpp
ui.h
ui_ex.cpp
ui_ex.h
)
set_src(GAME_EDITOR GLOB src/game/editor
auto_map.cpp

View file

@ -610,251 +610,7 @@ int CMenus::DoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, bool
int CMenus::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden, int Corners, const char *pEmptyText)
{
int Inside = UI()->MouseInside(pRect);
bool ReturnValue = false;
bool UpdateOffset = false;
static int s_AtIndex = 0;
static bool s_DoScroll = false;
static float s_ScrollStart = 0.0f;
FontSize *= UI()->Scale();
if(UI()->LastActiveItem() == pID)
{
int Len = str_length(pStr);
if(Len == 0)
s_AtIndex = 0;
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_V))
{
const char *Text = Input()->GetClipboardText();
if(Text)
{
int Offset = str_length(pStr);
int CharsLeft = StrSize - Offset;
char *pCur = pStr + Offset;
str_utf8_copy(pCur, Text, CharsLeft);
for(int i = 0; i < CharsLeft; i++)
{
if(pCur[i] == 0)
break;
else if(pCur[i] == '\r')
pCur[i] = ' ';
else if(pCur[i] == '\n')
pCur[i] = ' ';
}
s_AtIndex = str_length(pStr);
ReturnValue = true;
}
}
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_C))
{
Input()->SetClipboardText(pStr);
}
/* TODO: Doesn't work, SetClipboardText doesn't retain the string quickly enough?
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_X))
{
Input()->SetClipboardText(pStr);
pStr[0] = '\0';
s_AtIndex = 0;
ReturnValue = true;
}
*/
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_U))
{
pStr[0] = '\0';
s_AtIndex = 0;
ReturnValue = true;
}
if(Inside && UI()->MouseButton(0))
{
s_DoScroll = true;
s_ScrollStart = UI()->MouseX();
int MxRel = (int)(UI()->MouseX() - pRect->x);
for(int i = 1; i <= Len; i++)
{
if(TextRender()->TextWidth(0, FontSize, pStr, i, std::numeric_limits<float>::max()) - *Offset > MxRel)
{
s_AtIndex = i - 1;
break;
}
if(i == Len)
s_AtIndex = Len;
}
}
else if(!UI()->MouseButton(0))
s_DoScroll = false;
else if(s_DoScroll)
{
// do scrolling
if(UI()->MouseX() < pRect->x && s_ScrollStart - UI()->MouseX() > 10.0f)
{
s_AtIndex = maximum(0, s_AtIndex - 1);
s_ScrollStart = UI()->MouseX();
UpdateOffset = true;
}
else if(UI()->MouseX() > pRect->x + pRect->w && UI()->MouseX() - s_ScrollStart > 10.0f)
{
s_AtIndex = minimum(Len, s_AtIndex + 1);
s_ScrollStart = UI()->MouseX();
UpdateOffset = true;
}
}
for(int i = 0; i < m_NumInputEvents; i++)
{
Len = str_length(pStr);
int NumChars = Len;
ReturnValue |= CLineInput::Manipulate(m_aInputEvents[i], pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars);
}
}
bool JustGotActive = false;
if(UI()->ActiveItem() == pID)
{
if(!UI()->MouseButton(0))
{
s_AtIndex = minimum(s_AtIndex, str_length(pStr));
s_DoScroll = false;
UI()->SetActiveItem(0);
}
}
else if(UI()->HotItem() == pID)
{
if(UI()->MouseButton(0))
{
if(UI()->LastActiveItem() != pID)
JustGotActive = true;
UI()->SetActiveItem(pID);
}
}
if(Inside)
{
UI()->SetHotItem(pID);
}
CUIRect Textbox = *pRect;
RenderTools()->DrawUIRect(&Textbox, ColorRGBA(1, 1, 1, 0.5f), Corners, 3.0f);
Textbox.VMargin(2.0f, &Textbox);
Textbox.HMargin(2.0f, &Textbox);
const char *pDisplayStr = pStr;
char aStars[128];
if(Hidden)
{
unsigned s = str_length(pDisplayStr);
if(s >= sizeof(aStars))
s = sizeof(aStars) - 1;
for(unsigned int i = 0; i < s; ++i)
aStars[i] = '*';
aStars[s] = 0;
pDisplayStr = aStars;
}
char aDispEditingText[128 + IInput::INPUT_TEXT_SIZE + 2] = {0};
int DispCursorPos = s_AtIndex;
if(UI()->LastActiveItem() == pID && Input()->GetIMEEditingTextLength() > -1)
{
int EditingTextCursor = Input()->GetEditingCursor();
str_copy(aDispEditingText, pDisplayStr, sizeof(aDispEditingText));
char aEditingText[IInput::INPUT_TEXT_SIZE + 2];
if(Hidden)
{
// Do not show editing text in password field
str_copy(aEditingText, "[*]", sizeof(aEditingText));
EditingTextCursor = 1;
}
else
{
str_format(aEditingText, sizeof(aEditingText), "[%s]", Input()->GetIMEEditingText());
}
int NewTextLen = str_length(aEditingText);
int CharsLeft = (int)sizeof(aDispEditingText) - str_length(aDispEditingText) - 1;
int FillCharLen = minimum(NewTextLen, CharsLeft);
for(int i = str_length(aDispEditingText) - 1; i >= s_AtIndex; i--)
aDispEditingText[i + FillCharLen] = aDispEditingText[i];
for(int i = 0; i < FillCharLen; i++)
aDispEditingText[s_AtIndex + i] = aEditingText[i];
DispCursorPos = s_AtIndex + EditingTextCursor + 1;
pDisplayStr = aDispEditingText;
UpdateOffset = true;
}
if(pDisplayStr[0] == '\0')
{
pDisplayStr = pEmptyText;
TextRender()->TextColor(1, 1, 1, 0.75f);
}
DispCursorPos = minimum(DispCursorPos, str_length(pDisplayStr));
// check if the text has to be moved
if(UI()->LastActiveItem() == pID && !JustGotActive && (UpdateOffset || m_NumInputEvents))
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, DispCursorPos, std::numeric_limits<float>::max());
if(w - *Offset > Textbox.w)
{
// move to the left
float wt = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1, std::numeric_limits<float>::max());
do
{
*Offset += minimum(wt - *Offset - Textbox.w, Textbox.w / 3);
} while(w - *Offset > Textbox.w + 0.0001f);
}
else if(w - *Offset < 0.0f)
{
// move to the right
do
{
*Offset = maximum(0.0f, *Offset - Textbox.w / 3);
} while(w - *Offset < -0.0001f);
}
}
UI()->ClipEnable(pRect);
Textbox.x -= *Offset;
UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1);
TextRender()->TextColor(1, 1, 1, 1);
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
float OnePixelWidth = ((ScreenX1 - ScreenX0) / Graphics()->ScreenWidth());
// render the cursor
if(UI()->LastActiveItem() == pID && !JustGotActive)
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, DispCursorPos, std::numeric_limits<float>::max());
Textbox.x += w;
if((2 * time_get() / time_freq()) % 2)
{
Graphics()->TextureClear();
Graphics()->QuadsBegin();
Graphics()->SetColor(0, 0, 0, 0.3f);
IGraphics::CQuadItem CursorTBack(Textbox.x - (OnePixelWidth * 2.0f) / 2.0f, Textbox.y, OnePixelWidth * 2 * 2.0f, Textbox.h);
Graphics()->QuadsDrawTL(&CursorTBack, 1);
Graphics()->SetColor(1, 1, 1, 1);
IGraphics::CQuadItem CursorT(Textbox.x, Textbox.y + OnePixelWidth * 1.5f, OnePixelWidth * 2.0f, Textbox.h - OnePixelWidth * 1.5f * 2);
Graphics()->QuadsDrawTL(&CursorT, 1);
Graphics()->QuadsEnd();
}
Input()->SetEditingPosition(Textbox.x, Textbox.y + FontSize);
}
UI()->ClipDisable();
return ReturnValue;
return m_UIEx.DoEditBox(pID, pRect, pStr, StrSize, FontSize, Offset, Hidden, Corners, pEmptyText);
}
int CMenus::DoClearableEditBox(void *pID, void *pClearID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden, int Corners, const char *pEmptyText)
@ -1432,6 +1188,8 @@ void CMenus::OnInit()
if(g_Config.m_ClSkipStartMenu)
m_ShowStart = false;
m_UIEx.Init(UI(), Kernel(), RenderTools());
m_RefreshButton.Init(UI());
m_ConnectButton.Init(UI());

View file

@ -15,6 +15,7 @@
#include <game/client/component.h>
#include <game/client/ui.h>
#include <game/client/ui_ex.h>
#include <game/voting.h>
struct CServerProcess
@ -70,6 +71,8 @@ class CMenus : public CComponent
char m_aLocalStringHelper[1024];
CUIEx m_UIEx;
float ButtonColorMulActive() { return 0.5f; }
float ButtonColorMulHot() { return 1.5f; }
float ButtonColorMulDefault() { return 1.0f; }

274
src/game/client/ui_ex.cpp Normal file
View file

@ -0,0 +1,274 @@
#include "ui_ex.h"
#include <engine/client/input.h>
#include <engine/keys.h>
#include <game/client/lineinput.h>
#include <game/client/render.h>
#include <limits>
CUIEx::CUIEx(CUI *pUI, IKernel *pKernel, CRenderTools *pRenderTools)
{
Init(pUI, pKernel, pRenderTools);
}
void CUIEx::Init(CUI *pUI, IKernel *pKernel, CRenderTools *pRenderTools)
{
m_pUI = pUI;
m_pKernel = pKernel;
m_pRenderTools = pRenderTools;
m_pInput = Kernel()->RequestInterface<IInput>();
m_pGraphics = Kernel()->RequestInterface<IGraphics>();
m_pTextRender = Kernel()->RequestInterface<ITextRender>();
}
int CUIEx::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden, int Corners, const char *pEmptyText)
{
int Inside = UI()->MouseInside(pRect);
bool ReturnValue = false;
bool UpdateOffset = false;
static int s_AtIndex = 0;
static bool s_DoScroll = false;
static float s_ScrollStart = 0.0f;
FontSize *= UI()->Scale();
if(UI()->LastActiveItem() == pID)
{
int Len = str_length(pStr);
if(Len == 0)
s_AtIndex = 0;
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_V))
{
const char *Text = Input()->GetClipboardText();
if(Text)
{
int Offset = str_length(pStr);
int CharsLeft = StrSize - Offset;
char *pCur = pStr + Offset;
str_utf8_copy(pCur, Text, CharsLeft);
for(int i = 0; i < CharsLeft; i++)
{
if(pCur[i] == 0)
break;
else if(pCur[i] == '\r')
pCur[i] = ' ';
else if(pCur[i] == '\n')
pCur[i] = ' ';
}
s_AtIndex = str_length(pStr);
ReturnValue = true;
}
}
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_C))
{
Input()->SetClipboardText(pStr);
}
/* TODO: Doesn't work, SetClipboardText doesn't retain the string quickly enough?
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_X))
{
Input()->SetClipboardText(pStr);
pStr[0] = '\0';
s_AtIndex = 0;
ReturnValue = true;
}
*/
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_U))
{
pStr[0] = '\0';
s_AtIndex = 0;
ReturnValue = true;
}
if(Inside && UI()->MouseButton(0))
{
s_DoScroll = true;
s_ScrollStart = UI()->MouseX();
int MxRel = (int)(UI()->MouseX() - pRect->x);
for(int i = 1; i <= Len; i++)
{
if(TextRender()->TextWidth(0, FontSize, pStr, i, std::numeric_limits<float>::max()) - *Offset > MxRel)
{
s_AtIndex = i - 1;
break;
}
if(i == Len)
s_AtIndex = Len;
}
}
else if(!UI()->MouseButton(0))
s_DoScroll = false;
else if(s_DoScroll)
{
// do scrolling
if(UI()->MouseX() < pRect->x && s_ScrollStart - UI()->MouseX() > 10.0f)
{
s_AtIndex = maximum(0, s_AtIndex - 1);
s_ScrollStart = UI()->MouseX();
UpdateOffset = true;
}
else if(UI()->MouseX() > pRect->x + pRect->w && UI()->MouseX() - s_ScrollStart > 10.0f)
{
s_AtIndex = minimum(Len, s_AtIndex + 1);
s_ScrollStart = UI()->MouseX();
UpdateOffset = true;
}
}
for(int i = 0; i < Input()->NumEvents(); i++)
{
Len = str_length(pStr);
int NumChars = Len;
ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars);
}
}
bool JustGotActive = false;
if(UI()->ActiveItem() == pID)
{
if(!UI()->MouseButton(0))
{
s_AtIndex = minimum(s_AtIndex, str_length(pStr));
s_DoScroll = false;
UI()->SetActiveItem(0);
}
}
else if(UI()->HotItem() == pID)
{
if(UI()->MouseButton(0))
{
if(UI()->LastActiveItem() != pID)
JustGotActive = true;
UI()->SetActiveItem(pID);
}
}
if(Inside)
{
UI()->SetHotItem(pID);
}
CUIRect Textbox = *pRect;
RenderTools()->DrawUIRect(&Textbox, ColorRGBA(1, 1, 1, 0.5f), Corners, 3.0f);
Textbox.VMargin(2.0f, &Textbox);
Textbox.HMargin(2.0f, &Textbox);
const char *pDisplayStr = pStr;
char aStars[128];
if(Hidden)
{
unsigned s = str_length(pDisplayStr);
if(s >= sizeof(aStars))
s = sizeof(aStars) - 1;
for(unsigned int i = 0; i < s; ++i)
aStars[i] = '*';
aStars[s] = 0;
pDisplayStr = aStars;
}
char aDispEditingText[128 + IInput::INPUT_TEXT_SIZE + 2] = {0};
int DispCursorPos = s_AtIndex;
if(UI()->LastActiveItem() == pID && Input()->GetIMEEditingTextLength() > -1)
{
int EditingTextCursor = Input()->GetEditingCursor();
str_copy(aDispEditingText, pDisplayStr, sizeof(aDispEditingText));
char aEditingText[IInput::INPUT_TEXT_SIZE + 2];
if(Hidden)
{
// Do not show editing text in password field
str_copy(aEditingText, "[*]", sizeof(aEditingText));
EditingTextCursor = 1;
}
else
{
str_format(aEditingText, sizeof(aEditingText), "[%s]", Input()->GetIMEEditingText());
}
int NewTextLen = str_length(aEditingText);
int CharsLeft = (int)sizeof(aDispEditingText) - str_length(aDispEditingText) - 1;
int FillCharLen = minimum(NewTextLen, CharsLeft);
for(int i = str_length(aDispEditingText) - 1; i >= s_AtIndex; i--)
aDispEditingText[i + FillCharLen] = aDispEditingText[i];
for(int i = 0; i < FillCharLen; i++)
aDispEditingText[s_AtIndex + i] = aEditingText[i];
DispCursorPos = s_AtIndex + EditingTextCursor + 1;
pDisplayStr = aDispEditingText;
UpdateOffset = true;
}
if(pDisplayStr[0] == '\0')
{
pDisplayStr = pEmptyText;
TextRender()->TextColor(1, 1, 1, 0.75f);
}
DispCursorPos = minimum(DispCursorPos, str_length(pDisplayStr));
// check if the text has to be moved
if(UI()->LastActiveItem() == pID && !JustGotActive && (UpdateOffset || Input()->NumEvents()))
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, DispCursorPos, std::numeric_limits<float>::max());
if(w - *Offset > Textbox.w)
{
// move to the left
float wt = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1, std::numeric_limits<float>::max());
do
{
*Offset += minimum(wt - *Offset - Textbox.w, Textbox.w / 3);
} while(w - *Offset > Textbox.w + 0.0001f);
}
else if(w - *Offset < 0.0f)
{
// move to the right
do
{
*Offset = maximum(0.0f, *Offset - Textbox.w / 3);
} while(w - *Offset < -0.0001f);
}
}
UI()->ClipEnable(pRect);
Textbox.x -= *Offset;
UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1);
TextRender()->TextColor(1, 1, 1, 1);
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
float OnePixelWidth = ((ScreenX1 - ScreenX0) / Graphics()->ScreenWidth());
// render the cursor
if(UI()->LastActiveItem() == pID && !JustGotActive)
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, DispCursorPos, std::numeric_limits<float>::max());
Textbox.x += w;
if((2 * time_get() / time_freq()) % 2)
{
Graphics()->TextureClear();
Graphics()->QuadsBegin();
Graphics()->SetColor(0, 0, 0, 0.3f);
IGraphics::CQuadItem CursorTBack(Textbox.x - (OnePixelWidth * 2.0f) / 2.0f, Textbox.y, OnePixelWidth * 2 * 2.0f, Textbox.h);
Graphics()->QuadsDrawTL(&CursorTBack, 1);
Graphics()->SetColor(1, 1, 1, 1);
IGraphics::CQuadItem CursorT(Textbox.x, Textbox.y + OnePixelWidth * 1.5f, OnePixelWidth * 2.0f, Textbox.h - OnePixelWidth * 1.5f * 2);
Graphics()->QuadsDrawTL(&CursorT, 1);
Graphics()->QuadsEnd();
}
Input()->SetEditingPosition(Textbox.x, Textbox.y + FontSize);
}
UI()->ClipDisable();
return ReturnValue;
}

41
src/game/client/ui_ex.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef GAME_CLIENT_UI_EX_H
#define GAME_CLIENT_UI_EX_H
#include "engine/kernel.h"
#include <base/system.h>
#include <game/client/ui.h>
class IInput;
class ITextRender;
class IKernel;
class IGraphics;
class CRenderTools;
class CUIEx
{
CUI *m_pUI;
IInput *m_pInput;
ITextRender *m_pTextRender;
IKernel *m_pKernel;
IGraphics *m_pGraphics;
CRenderTools *m_pRenderTools;
protected:
CUI *UI() { return m_pUI; }
IInput *Input() { return m_pInput; }
ITextRender *TextRender() { return m_pTextRender; }
IKernel *Kernel() { return m_pKernel; }
IGraphics *Graphics() { return m_pGraphics; }
CRenderTools *RenderTools() { return m_pRenderTools; }
public:
CUIEx(CUI *pUI, IKernel *pKernel, CRenderTools *pRenderTools);
CUIEx() {}
void Init(CUI *pUI, IKernel *pKernel, CRenderTools *pRenderTools);
int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden = false, int Corners = CUI::CORNER_ALL, const char *pEmptyText = "");
};
#endif

View file

@ -326,171 +326,9 @@ int CEditor::DoClearableEditBox(void *pID, void *pClearID, const CUIRect *pRect,
return ReturnValue;
}
// copied from gc_menu.cpp, should be more generalized
//extern int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false);
int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden, int Corners)
{
int Inside = UI()->MouseInside(pRect);
bool ReturnValue = false;
bool UpdateOffset = false;
static int s_AtIndex = 0;
static bool s_DoScroll = false;
static float s_ScrollStart = 0.0f;
FontSize *= UI()->Scale();
if(UI()->LastActiveItem() == pID)
{
m_EditBoxActive = 2;
int Len = str_length(pStr);
if(Len == 0)
s_AtIndex = 0;
if(Inside && UI()->MouseButton(0))
{
s_DoScroll = true;
s_ScrollStart = UI()->MouseX();
int MxRel = (int)(UI()->MouseX() - pRect->x);
for(int i = 1; i <= Len; i++)
{
if(TextRender()->TextWidth(0, FontSize, pStr, i, std::numeric_limits<float>::max()) - *Offset > MxRel)
{
s_AtIndex = i - 1;
break;
}
if(i == Len)
s_AtIndex = Len;
}
}
else if(!UI()->MouseButton(0))
s_DoScroll = false;
else if(s_DoScroll)
{
// do scrolling
if(UI()->MouseX() < pRect->x && s_ScrollStart - UI()->MouseX() > 10.0f)
{
s_AtIndex = maximum(0, s_AtIndex - 1);
s_ScrollStart = UI()->MouseX();
UpdateOffset = true;
}
else if(UI()->MouseX() > pRect->x + pRect->w && UI()->MouseX() - s_ScrollStart > 10.0f)
{
s_AtIndex = minimum(Len, s_AtIndex + 1);
s_ScrollStart = UI()->MouseX();
UpdateOffset = true;
}
}
for(int i = 0; i < Input()->NumEvents(); i++)
{
Len = str_length(pStr);
int NumChars = Len;
ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars);
}
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_V))
{
const char *pClipboardText = Input()->GetClipboardText();
if(pClipboardText)
{
str_append(pStr, pClipboardText, StrSize);
str_sanitize_cc(pStr);
s_AtIndex = str_length(pStr);
ReturnValue = true;
}
}
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_C) && pStr[0] != '\0')
{
Input()->SetClipboardText(pStr);
}
}
bool JustGotActive = false;
if(UI()->ActiveItem() == pID)
{
if(!UI()->MouseButton(0))
{
s_AtIndex = minimum(s_AtIndex, str_length(pStr));
s_DoScroll = false;
UI()->SetActiveItem(0);
}
}
else if(UI()->HotItem() == pID)
{
if(UI()->MouseButton(0))
{
if(UI()->LastActiveItem() != pID)
JustGotActive = true;
UI()->SetActiveItem(pID);
}
}
if(Inside)
UI()->SetHotItem(pID);
CUIRect Textbox = *pRect;
RenderTools()->DrawUIRect(&Textbox, ColorRGBA(1, 1, 1, 0.5f), Corners, 3.0f);
Textbox.VMargin(2.0f, &Textbox);
const char *pDisplayStr = pStr;
char aStars[128];
if(Hidden)
{
unsigned s = str_length(pStr);
if(s >= sizeof(aStars))
s = sizeof(aStars) - 1;
for(unsigned int i = 0; i < s; ++i)
aStars[i] = '*';
aStars[s] = 0;
pDisplayStr = aStars;
}
// check if the text has to be moved
if(UI()->LastActiveItem() == pID && !JustGotActive && (UpdateOffset || Input()->NumEvents()))
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex, std::numeric_limits<float>::max());
if(w - *Offset > Textbox.w)
{
// move to the left
float wt = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1, std::numeric_limits<float>::max());
do
{
*Offset += minimum(wt - *Offset - Textbox.w, Textbox.w / 3);
} while(w - *Offset > Textbox.w + 0.0001f);
}
else if(w - *Offset < 0.0f)
{
// move to the right
do
{
*Offset = maximum(0.0f, *Offset - Textbox.w / 3);
} while(w - *Offset < -0.0001f);
}
}
UI()->ClipEnable(pRect);
Textbox.x -= *Offset;
UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1, std::numeric_limits<float>::max());
// render the cursor
if(UI()->LastActiveItem() == pID && !JustGotActive)
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex, std::numeric_limits<float>::max());
Textbox = *pRect;
Textbox.VSplitLeft(2.0f, 0, &Textbox);
Textbox.x += (w - *Offset - TextRender()->TextWidth(0, FontSize, "|", -1, std::numeric_limits<float>::max()) / 2);
if((2 * time_get() / time_freq()) % 2) // make it blink
UI()->DoLabel(&Textbox, "|", FontSize, -1, std::numeric_limits<float>::max());
}
UI()->ClipDisable();
return ReturnValue;
return m_UIEx.DoEditBox(pID, pRect, pStr, StrSize, FontSize, Offset, Hidden, Corners);
}
float CEditor::ButtonColorMul(const void *pID)
@ -6367,6 +6205,8 @@ void CEditor::Init()
m_UI.SetGraphics(m_pGraphics, m_pTextRender);
m_Map.m_pEditor = this;
m_UIEx.Init(UI(), Kernel(), RenderTools());
m_CheckerTexture = Graphics()->LoadTexture("editor/checker.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
m_BackgroundTexture = Graphics()->LoadTexture("editor/background.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
m_CursorTexture = Graphics()->LoadTexture("editor/cursor.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);

View file

@ -17,6 +17,7 @@
#include <game/client/render.h>
#include <game/client/ui.h>
#include <game/client/ui_ex.h>
#include <game/mapitems.h>
#include <engine/editor.h>
@ -639,6 +640,7 @@ class CEditor : public IEditor
class IStorage *m_pStorage;
CRenderTools m_RenderTools;
CUI m_UI;
CUIEx m_UIEx;
public:
class IInput *Input() { return m_pInput; };