mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #4171
4171: Add basic selection support for ui ex edit boxes r=def- a=Jupeyy This changes the hotkey for "exclude" to CTRL + SHIFT + X, because else it collides with Cutting strings out of a selection This is defs not perfect, it basically ignores keyboard keys that could also alter selection (e.g. shift + right) but i didnt want to break the IME stuff, bcs i don't understand it ## 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:
commit
26d54f8c8c
|
@ -176,6 +176,9 @@ struct STextContainer
|
|||
|
||||
int m_RenderFlags;
|
||||
|
||||
bool m_HasCursor;
|
||||
bool m_HasSelection;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
m_pFont = NULL;
|
||||
|
@ -193,6 +196,9 @@ struct STextContainer
|
|||
m_UnscaledFontSize = 0.f;
|
||||
|
||||
m_RenderFlags = 0;
|
||||
|
||||
m_HasCursor = false;
|
||||
m_HasSelection = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -212,6 +218,8 @@ class CTextRender : public IEngineTextRender
|
|||
std::vector<CFont *> m_Fonts;
|
||||
CFont *m_pCurFont;
|
||||
|
||||
int64_t m_CursorRenderTime;
|
||||
|
||||
int GetFreeTextContainerIndex()
|
||||
{
|
||||
if(m_FirstFreeTextContainerIndex == -1)
|
||||
|
@ -614,10 +622,8 @@ public:
|
|||
m_pDefaultFont = 0;
|
||||
m_FTLibrary = 0;
|
||||
|
||||
// GL_LUMINANCE can be good for debugging
|
||||
//m_FontTextureFormat = GL_ALPHA;
|
||||
|
||||
m_RenderFlags = 0;
|
||||
m_CursorRenderTime = time_get_microseconds();
|
||||
}
|
||||
|
||||
virtual ~CTextRender()
|
||||
|
@ -809,6 +815,9 @@ public:
|
|||
pCursor->m_ReleaseMouseY = 0;
|
||||
pCursor->m_SelectionStart = 0;
|
||||
pCursor->m_SelectionEnd = 0;
|
||||
|
||||
pCursor->m_CursorMode = TEXT_CURSOR_CURSOR_MODE_NONE;
|
||||
pCursor->m_CursorCharacter = -1;
|
||||
}
|
||||
|
||||
virtual void MoveCursor(CTextCursor *pCursor, float x, float y)
|
||||
|
@ -969,7 +978,7 @@ public:
|
|||
|
||||
AppendTextContainer(pCursor, ContainerIndex, pText, Length);
|
||||
|
||||
if(TextContainer.m_StringInfo.m_CharacterQuads.size() == 0 && IsRendered)
|
||||
if(TextContainer.m_StringInfo.m_CharacterQuads.size() == 0 && TextContainer.m_StringInfo.m_SelectionQuadContainerIndex == -1 && IsRendered)
|
||||
{
|
||||
FreeTextContainer(ContainerIndex);
|
||||
return -1;
|
||||
|
@ -977,7 +986,7 @@ public:
|
|||
else
|
||||
{
|
||||
TextContainer.m_StringInfo.m_QuadNum = TextContainer.m_StringInfo.m_CharacterQuads.size();
|
||||
if(Graphics()->IsTextBufferingEnabled() && IsRendered)
|
||||
if(Graphics()->IsTextBufferingEnabled() && IsRendered && !TextContainer.m_StringInfo.m_CharacterQuads.empty())
|
||||
{
|
||||
if((TextContainer.m_RenderFlags & TEXT_RENDER_FLAG_NO_AUTOMATIC_QUAD_UPLOAD) == 0)
|
||||
{
|
||||
|
@ -1064,6 +1073,13 @@ public:
|
|||
|
||||
bool IsRendered = (pCursor->m_Flags & TEXTFLAG_RENDER) != 0;
|
||||
|
||||
IGraphics::CQuadItem CursorQuads[2];
|
||||
bool HasCursor = false;
|
||||
|
||||
float CursorInnerWidth = (((ScreenX1 - ScreenX0) / Graphics()->ScreenWidth())) * 2;
|
||||
float CursorOuterWidth = CursorInnerWidth * 2;
|
||||
float CursorOuterInnerDiff = (CursorOuterWidth - CursorInnerWidth) / 2;
|
||||
|
||||
std::vector<IGraphics::CQuadItem> SelectionQuads;
|
||||
bool SelectionStarted = false;
|
||||
bool SelectionUsedPress = false;
|
||||
|
@ -1071,15 +1087,22 @@ public:
|
|||
int SelectionStartChar = -1;
|
||||
int SelectionEndChar = -1;
|
||||
|
||||
auto &&CheckInsideChar = [&](bool CheckOuter, int CursorX, int CursorY, float LastCharX, float LastCharWidth, float CharX, float CharWidth, float CharY) -> bool {
|
||||
if((LastCharX - LastCharWidth / 2 <= CursorX &&
|
||||
CharX + CharWidth / 2 > CursorX &&
|
||||
CharY - Size <= CursorY &&
|
||||
CharY > CursorY) ||
|
||||
(CheckOuter &&
|
||||
CharY - Size > CursorY))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto &&CheckSelectionStart = [&](bool CheckOuter, int CursorX, int CursorY, int &SelectionChar, bool &SelectionUsedCase, float LastCharX, float LastCharWidth, float CharX, float CharWidth, float CharY) {
|
||||
if(!SelectionStarted && !SelectionUsedCase)
|
||||
{
|
||||
if((LastCharX - LastCharWidth / 2 <= CursorX &&
|
||||
CharX + CharWidth / 2 > CursorX &&
|
||||
CharY - Size <= CursorY &&
|
||||
CharY > CursorY) ||
|
||||
(CheckOuter &&
|
||||
CharY - Size > CursorY))
|
||||
if(CheckInsideChar(CheckOuter, CursorX, CursorY, LastCharX, LastCharWidth, CharX, CharWidth, CharY))
|
||||
{
|
||||
SelectionChar = CharacterCounter;
|
||||
SelectionStarted = !SelectionStarted;
|
||||
|
@ -1087,14 +1110,21 @@ public:
|
|||
}
|
||||
}
|
||||
};
|
||||
auto &&CheckOutsideChar = [&](bool CheckOuter, int CursorX, int CursorY, float CharX, float CharWidth, float CharY) -> bool {
|
||||
if((CharX + CharWidth / 2 > CursorX &&
|
||||
CharY - Size <= CursorY &&
|
||||
CharY > CursorY) ||
|
||||
(CheckOuter &&
|
||||
CharY <= CursorY))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto &&CheckSelectionEnd = [&](bool CheckOuter, int CursorX, int CursorY, int &SelectionChar, bool &SelectionUsedCase, float CharX, float CharWidth, float CharY) {
|
||||
if(SelectionStarted && !SelectionUsedCase)
|
||||
{
|
||||
if((CharX + CharWidth / 2 > CursorX &&
|
||||
CharY - Size <= CursorY &&
|
||||
CharY > CursorY) ||
|
||||
(CheckOuter &&
|
||||
CharY <= CursorY))
|
||||
if(CheckOutsideChar(CheckOuter, CursorX, CursorY, CharX, CharWidth, CharY))
|
||||
{
|
||||
SelectionChar = CharacterCounter;
|
||||
SelectionStarted = !SelectionStarted;
|
||||
|
@ -1123,13 +1153,17 @@ public:
|
|||
++LineCount;
|
||||
};
|
||||
|
||||
if(pCursor->m_CalculateSelectionMode != TEXT_CURSOR_SELECTION_MODE_NONE)
|
||||
if(pCursor->m_CalculateSelectionMode != TEXT_CURSOR_SELECTION_MODE_NONE || pCursor->m_CursorMode != TEXT_CURSOR_CURSOR_MODE_NONE)
|
||||
{
|
||||
if(IsRendered)
|
||||
{
|
||||
if(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex != -1)
|
||||
Graphics()->QuadContainerReset(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex);
|
||||
}
|
||||
|
||||
// if in calculate mode, also calculate the cursor
|
||||
if(pCursor->m_CursorMode == TEXT_CURSOR_CURSOR_MODE_CALCULATE)
|
||||
pCursor->m_CursorCharacter = -1;
|
||||
}
|
||||
|
||||
while(pCurrent < pEnd && (pCursor->m_MaxLines < 1 || LineCount <= pCursor->m_MaxLines))
|
||||
|
@ -1141,6 +1175,7 @@ public:
|
|||
int Wlen = minimum(WordLength((char *)pCurrent), (int)(pEnd - pCurrent));
|
||||
CTextCursor Compare = *pCursor;
|
||||
Compare.m_CalculateSelectionMode = TEXT_CURSOR_SELECTION_MODE_NONE;
|
||||
Compare.m_CursorMode = TEXT_CURSOR_CURSOR_MODE_NONE;
|
||||
Compare.m_X = DrawX;
|
||||
Compare.m_Y = DrawY;
|
||||
Compare.m_Flags &= ~TEXTFLAG_RENDER;
|
||||
|
@ -1152,6 +1187,7 @@ public:
|
|||
// word can't be fitted in one line, cut it
|
||||
CTextCursor Cutter = *pCursor;
|
||||
Cutter.m_CalculateSelectionMode = TEXT_CURSOR_SELECTION_MODE_NONE;
|
||||
Cutter.m_CursorMode = TEXT_CURSOR_CURSOR_MODE_NONE;
|
||||
Cutter.m_GlyphCount = 0;
|
||||
Cutter.m_CharCount = 0;
|
||||
Cutter.m_X = DrawX;
|
||||
|
@ -1284,12 +1320,20 @@ public:
|
|||
float SelWidth = (CharX + maximum(Advance, CharWidth - OutLineRealDiff / 2)) - (LastSelX + LastSelWidth);
|
||||
float SelX = (LastSelX + LastSelWidth);
|
||||
|
||||
if(pCursor->m_CursorMode == TEXT_CURSOR_CURSOR_MODE_CALCULATE)
|
||||
{
|
||||
if(pCursor->m_CursorCharacter == -1 && CheckInsideChar(CharacterCounter == 0, pCursor->m_ReleaseMouseX, pCursor->m_ReleaseMouseY, CharacterCounter == 0 ? std::numeric_limits<float>::lowest() : LastCharX, LastCharWidth, CharX, CharWidth, TmpY))
|
||||
{
|
||||
pCursor->m_CursorCharacter = CharacterCounter;
|
||||
}
|
||||
}
|
||||
|
||||
if(pCursor->m_CalculateSelectionMode == TEXT_CURSOR_SELECTION_MODE_CALCULATE)
|
||||
{
|
||||
if(CharacterCounter == 0)
|
||||
{
|
||||
CheckSelectionStart(true, pCursor->m_PressMouseX, pCursor->m_PressMouseY, SelectionStartChar, SelectionUsedPress, LastCharX, LastCharWidth, CharX, CharWidth, TmpY);
|
||||
CheckSelectionStart(true, pCursor->m_ReleaseMouseX, pCursor->m_ReleaseMouseY, SelectionEndChar, SelectionUsedRelease, LastCharX, LastCharWidth, CharX, CharWidth, TmpY);
|
||||
CheckSelectionStart(true, pCursor->m_PressMouseX, pCursor->m_PressMouseY, SelectionStartChar, SelectionUsedPress, std::numeric_limits<float>::lowest(), 0, CharX, CharWidth, TmpY);
|
||||
CheckSelectionStart(true, pCursor->m_ReleaseMouseX, pCursor->m_ReleaseMouseY, SelectionEndChar, SelectionUsedRelease, std::numeric_limits<float>::lowest(), 0, CharX, CharWidth, TmpY);
|
||||
}
|
||||
|
||||
// if selection didn't start and the mouse pos is atleast on 50% of the right side of the character start
|
||||
|
@ -1303,15 +1347,27 @@ public:
|
|||
if((int)CharacterCounter == pCursor->m_SelectionStart)
|
||||
{
|
||||
SelectionStarted = !SelectionStarted;
|
||||
SelectionStartChar = CharacterCounter;
|
||||
SelectionUsedPress = true;
|
||||
}
|
||||
if((int)CharacterCounter == pCursor->m_SelectionEnd)
|
||||
{
|
||||
SelectionStarted = !SelectionStarted;
|
||||
SelectionEndChar = CharacterCounter;
|
||||
SelectionUsedRelease = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(pCursor->m_CursorMode != TEXT_CURSOR_CURSOR_MODE_NONE)
|
||||
{
|
||||
if((int)CharacterCounter == pCursor->m_CursorCharacter)
|
||||
{
|
||||
HasCursor = true;
|
||||
CursorQuads[0] = IGraphics::CQuadItem(SelX - CursorOuterInnerDiff, DrawY, CursorOuterWidth, Size);
|
||||
CursorQuads[1] = IGraphics::CQuadItem(SelX, DrawY + CursorOuterInnerDiff, CursorInnerWidth, Size - CursorOuterInnerDiff * 2);
|
||||
}
|
||||
}
|
||||
|
||||
pCursor->m_MaxCharacterHeight = maximum(pCursor->m_MaxCharacterHeight, CharHeight + BearingY);
|
||||
|
||||
if(NextCharacter == 0 && (RenderFlags & TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE) != 0 && Character != ' ')
|
||||
|
@ -1377,25 +1433,52 @@ public:
|
|||
}
|
||||
else if(pCursor->m_CalculateSelectionMode == TEXT_CURSOR_SELECTION_MODE_SET)
|
||||
{
|
||||
if((int)CharacterCounter == pCursor->m_SelectionStart)
|
||||
{
|
||||
SelectionStarted = !SelectionStarted;
|
||||
SelectionStartChar = CharacterCounter;
|
||||
SelectionUsedPress = true;
|
||||
}
|
||||
if((int)CharacterCounter == pCursor->m_SelectionEnd)
|
||||
{
|
||||
SelectionStarted = !SelectionStarted;
|
||||
SelectionEndChar = CharacterCounter;
|
||||
SelectionUsedRelease = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!SelectionQuads.empty() && SelectionUsedPress && SelectionUsedRelease)
|
||||
if(pCursor->m_CursorMode != TEXT_CURSOR_CURSOR_MODE_NONE)
|
||||
{
|
||||
if(pCursor->m_CursorMode == TEXT_CURSOR_CURSOR_MODE_CALCULATE && pCursor->m_CursorCharacter == -1 && CheckOutsideChar(true, pCursor->m_ReleaseMouseX, pCursor->m_ReleaseMouseY, std::numeric_limits<float>::max(), 0, DrawY + Size))
|
||||
{
|
||||
pCursor->m_CursorCharacter = CharacterCounter;
|
||||
}
|
||||
|
||||
if((int)CharacterCounter == pCursor->m_CursorCharacter)
|
||||
{
|
||||
HasCursor = true;
|
||||
CursorQuads[0] = IGraphics::CQuadItem((LastSelX + LastSelWidth) - CursorOuterInnerDiff, DrawY, CursorOuterWidth, Size);
|
||||
CursorQuads[1] = IGraphics::CQuadItem((LastSelX + LastSelWidth), DrawY + CursorOuterInnerDiff, CursorInnerWidth, Size - CursorOuterInnerDiff * 2);
|
||||
}
|
||||
}
|
||||
|
||||
bool HasSelection = !SelectionQuads.empty() && SelectionUsedPress && SelectionUsedRelease;
|
||||
if((HasSelection || HasCursor) && IsRendered)
|
||||
{
|
||||
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
||||
if(SelectionQuads.size() > 0)
|
||||
{
|
||||
if(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex == -1)
|
||||
TextContainer.m_StringInfo.m_SelectionQuadContainerIndex = Graphics()->CreateQuadContainer();
|
||||
if(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex == -1)
|
||||
TextContainer.m_StringInfo.m_SelectionQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
||||
if(HasCursor)
|
||||
Graphics()->QuadContainerAddQuads(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, CursorQuads, 2);
|
||||
if(HasSelection)
|
||||
Graphics()->QuadContainerAddQuads(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, &SelectionQuads[0], (int)SelectionQuads.size());
|
||||
Graphics()->QuadContainerUpload(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex);
|
||||
|
||||
pCursor->m_SelectionStart = SelectionStartChar;
|
||||
pCursor->m_SelectionEnd = SelectionEndChar;
|
||||
}
|
||||
TextContainer.m_HasCursor = HasCursor;
|
||||
TextContainer.m_HasSelection = HasSelection;
|
||||
|
||||
pCursor->m_SelectionStart = SelectionStartChar;
|
||||
pCursor->m_SelectionEnd = SelectionEndChar;
|
||||
}
|
||||
|
||||
// even if no text is drawn the cursor position will be adjusted
|
||||
|
@ -1407,7 +1490,8 @@ public:
|
|||
}
|
||||
|
||||
// just deletes and creates text container
|
||||
virtual void RecreateTextContainer(CTextCursor *pCursor, int TextContainerIndex, const char *pText, int Length = -1)
|
||||
virtual void
|
||||
RecreateTextContainer(CTextCursor *pCursor, int TextContainerIndex, const char *pText, int Length = -1)
|
||||
{
|
||||
DeleteTextContainer(TextContainerIndex);
|
||||
CreateTextContainer(pCursor, pText, Length);
|
||||
|
@ -1459,70 +1543,89 @@ public:
|
|||
|
||||
if(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex != -1)
|
||||
{
|
||||
Graphics()->TextureClear();
|
||||
Graphics()->SetColor(m_SelectionColor);
|
||||
Graphics()->RenderQuadContainerEx(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, 0, -1, 0, 0);
|
||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
/*static int64_t s_CursorRenderTime = time_get_microseconds();
|
||||
|
||||
if((time_get_microseconds() - s_CursorRenderTime) > 500000)
|
||||
Graphics()->RenderQuadContainer(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, 0, 1);
|
||||
if((time_get_microseconds() - s_CursorRenderTime) > 1000000)
|
||||
s_CursorRenderTime = time_get_microseconds();*/
|
||||
}
|
||||
|
||||
if(Graphics()->IsTextBufferingEnabled())
|
||||
{
|
||||
Graphics()->TextureClear();
|
||||
// render buffered text
|
||||
Graphics()->RenderText(TextContainer.m_StringInfo.m_QuadBufferContainerIndex, TextContainer.m_StringInfo.m_QuadNum, pFont->m_CurTextureDimensions[0], pFont->m_aTextures[0].Id(), pFont->m_aTextures[1].Id(), (float *)pTextColor, (float *)pTextOutlineColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// render tiles
|
||||
float UVScale = 1.0f / pFont->m_CurTextureDimensions[0];
|
||||
|
||||
Graphics()->FlushVertices();
|
||||
Graphics()->TextureSet(pFont->m_aTextures[1]);
|
||||
|
||||
Graphics()->QuadsBegin();
|
||||
|
||||
for(size_t i = 0; i < TextContainer.m_StringInfo.m_QuadNum; ++i)
|
||||
if(TextContainer.m_HasSelection)
|
||||
{
|
||||
STextCharQuad &TextCharQuad = TextContainer.m_StringInfo.m_CharacterQuads[i];
|
||||
|
||||
Graphics()->SetColor(TextCharQuad.m_Vertices[0].m_Color.m_R / 255.f * pTextOutlineColor->m_R, TextCharQuad.m_Vertices[0].m_Color.m_G / 255.f * pTextOutlineColor->m_G, TextCharQuad.m_Vertices[0].m_Color.m_B / 255.f * pTextOutlineColor->m_B, TextCharQuad.m_Vertices[0].m_Color.m_A / 255.f * pTextOutlineColor->m_A);
|
||||
|
||||
Graphics()->QuadsSetSubset(TextCharQuad.m_Vertices[0].m_U * UVScale, TextCharQuad.m_Vertices[0].m_V * UVScale, TextCharQuad.m_Vertices[2].m_U * UVScale, TextCharQuad.m_Vertices[2].m_V * UVScale);
|
||||
IGraphics::CQuadItem QuadItem(TextCharQuad.m_Vertices[0].m_X, TextCharQuad.m_Vertices[0].m_Y, TextCharQuad.m_Vertices[1].m_X - TextCharQuad.m_Vertices[0].m_X, TextCharQuad.m_Vertices[2].m_Y - TextCharQuad.m_Vertices[0].m_Y);
|
||||
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
||||
Graphics()->TextureClear();
|
||||
Graphics()->SetColor(m_SelectionColor);
|
||||
Graphics()->RenderQuadContainerEx(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, TextContainer.m_HasCursor ? 2 : 0, -1, 0, 0);
|
||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if(pTextColor->m_A != 0)
|
||||
if(TextContainer.m_StringInfo.m_QuadNum > 0)
|
||||
{
|
||||
if(Graphics()->IsTextBufferingEnabled())
|
||||
{
|
||||
Graphics()->QuadsEndKeepVertices();
|
||||
Graphics()->TextureClear();
|
||||
// render buffered text
|
||||
Graphics()->RenderText(TextContainer.m_StringInfo.m_QuadBufferContainerIndex, TextContainer.m_StringInfo.m_QuadNum, pFont->m_CurTextureDimensions[0], pFont->m_aTextures[0].Id(), pFont->m_aTextures[1].Id(), (float *)pTextColor, (float *)pTextOutlineColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// render tiles
|
||||
float UVScale = 1.0f / pFont->m_CurTextureDimensions[0];
|
||||
|
||||
Graphics()->TextureSet(pFont->m_aTextures[0]);
|
||||
Graphics()->FlushVertices();
|
||||
Graphics()->TextureSet(pFont->m_aTextures[1]);
|
||||
|
||||
Graphics()->QuadsBegin();
|
||||
|
||||
for(size_t i = 0; i < TextContainer.m_StringInfo.m_QuadNum; ++i)
|
||||
{
|
||||
STextCharQuad &TextCharQuad = TextContainer.m_StringInfo.m_CharacterQuads[i];
|
||||
unsigned char CR = (unsigned char)((float)(TextCharQuad.m_Vertices[0].m_Color.m_R) * pTextColor->m_R);
|
||||
unsigned char CG = (unsigned char)((float)(TextCharQuad.m_Vertices[0].m_Color.m_G) * pTextColor->m_G);
|
||||
unsigned char CB = (unsigned char)((float)(TextCharQuad.m_Vertices[0].m_Color.m_B) * pTextColor->m_B);
|
||||
unsigned char CA = (unsigned char)((float)(TextCharQuad.m_Vertices[0].m_Color.m_A) * pTextColor->m_A);
|
||||
Graphics()->ChangeColorOfQuadVertices((int)i, CR, CG, CB, CA);
|
||||
|
||||
Graphics()->SetColor(TextCharQuad.m_Vertices[0].m_Color.m_R / 255.f * pTextOutlineColor->m_R, TextCharQuad.m_Vertices[0].m_Color.m_G / 255.f * pTextOutlineColor->m_G, TextCharQuad.m_Vertices[0].m_Color.m_B / 255.f * pTextOutlineColor->m_B, TextCharQuad.m_Vertices[0].m_Color.m_A / 255.f * pTextOutlineColor->m_A);
|
||||
|
||||
Graphics()->QuadsSetSubset(TextCharQuad.m_Vertices[0].m_U * UVScale, TextCharQuad.m_Vertices[0].m_V * UVScale, TextCharQuad.m_Vertices[2].m_U * UVScale, TextCharQuad.m_Vertices[2].m_V * UVScale);
|
||||
IGraphics::CQuadItem QuadItem(TextCharQuad.m_Vertices[0].m_X, TextCharQuad.m_Vertices[0].m_Y, TextCharQuad.m_Vertices[1].m_X - TextCharQuad.m_Vertices[0].m_X, TextCharQuad.m_Vertices[2].m_Y - TextCharQuad.m_Vertices[0].m_Y);
|
||||
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
||||
}
|
||||
|
||||
// render non outlined
|
||||
Graphics()->QuadsDrawCurrentVertices(false);
|
||||
}
|
||||
else
|
||||
Graphics()->QuadsEnd();
|
||||
if(pTextColor->m_A != 0)
|
||||
{
|
||||
Graphics()->QuadsEndKeepVertices();
|
||||
|
||||
// reset
|
||||
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
||||
Graphics()->TextureSet(pFont->m_aTextures[0]);
|
||||
|
||||
for(size_t i = 0; i < TextContainer.m_StringInfo.m_QuadNum; ++i)
|
||||
{
|
||||
STextCharQuad &TextCharQuad = TextContainer.m_StringInfo.m_CharacterQuads[i];
|
||||
unsigned char CR = (unsigned char)((float)(TextCharQuad.m_Vertices[0].m_Color.m_R) * pTextColor->m_R);
|
||||
unsigned char CG = (unsigned char)((float)(TextCharQuad.m_Vertices[0].m_Color.m_G) * pTextColor->m_G);
|
||||
unsigned char CB = (unsigned char)((float)(TextCharQuad.m_Vertices[0].m_Color.m_B) * pTextColor->m_B);
|
||||
unsigned char CA = (unsigned char)((float)(TextCharQuad.m_Vertices[0].m_Color.m_A) * pTextColor->m_A);
|
||||
Graphics()->ChangeColorOfQuadVertices((int)i, CR, CG, CB, CA);
|
||||
}
|
||||
|
||||
// render non outlined
|
||||
Graphics()->QuadsDrawCurrentVertices(false);
|
||||
}
|
||||
else
|
||||
Graphics()->QuadsEnd();
|
||||
|
||||
// reset
|
||||
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
if(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex != -1)
|
||||
{
|
||||
if(TextContainer.m_HasCursor)
|
||||
{
|
||||
int64_t CurTime = time_get_microseconds();
|
||||
|
||||
Graphics()->TextureClear();
|
||||
if((CurTime - m_CursorRenderTime) > 500000)
|
||||
{
|
||||
Graphics()->SetColor(*pTextOutlineColor);
|
||||
Graphics()->RenderQuadContainerEx(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, 0, 1, 0, 0);
|
||||
Graphics()->SetColor(*pTextColor);
|
||||
Graphics()->RenderQuadContainerEx(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, 1, 1, 0, 0);
|
||||
}
|
||||
if((CurTime - m_CursorRenderTime) > 1000000)
|
||||
m_CursorRenderTime = time_get_microseconds();
|
||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1735,6 +1838,69 @@ public:
|
|||
return OffUTF8Start != -1 && OffUTF8End != -1;
|
||||
}
|
||||
|
||||
virtual bool UTF8OffToDecodedOff(const char *pText, int UTF8Off, int &DecodedOff)
|
||||
{
|
||||
const char *pIt = pText;
|
||||
|
||||
DecodedOff = -1;
|
||||
|
||||
int CharCount = 0;
|
||||
while(*pIt)
|
||||
{
|
||||
if((int)(intptr_t)(pIt - pText) == UTF8Off)
|
||||
{
|
||||
DecodedOff = CharCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *pTmp = pIt;
|
||||
int Character = str_utf8_decode(&pTmp);
|
||||
if(Character == -1)
|
||||
return false;
|
||||
|
||||
pIt = pTmp;
|
||||
++CharCount;
|
||||
}
|
||||
|
||||
if((int)(std::intptr_t)(pIt - pText) == UTF8Off)
|
||||
{
|
||||
DecodedOff = CharCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool DecodedOffToUTF8Off(const char *pText, int DecodedOff, int &UTF8Off)
|
||||
{
|
||||
const char *pIt = pText;
|
||||
|
||||
UTF8Off = -1;
|
||||
|
||||
int CharCount = 0;
|
||||
while(*pIt)
|
||||
{
|
||||
const char *pTmp = pIt;
|
||||
int Character = str_utf8_decode(&pTmp);
|
||||
if(Character == -1)
|
||||
return false;
|
||||
|
||||
if(CharCount == DecodedOff)
|
||||
{
|
||||
UTF8Off = (int)((std::intptr_t)(pIt - pText));
|
||||
return true;
|
||||
}
|
||||
|
||||
pIt = pTmp;
|
||||
++CharCount;
|
||||
}
|
||||
|
||||
if(CharCount == DecodedOff)
|
||||
UTF8Off = (int)((std::intptr_t)(pIt - pText));
|
||||
|
||||
return UTF8Off != -1;
|
||||
}
|
||||
|
||||
virtual void OnWindowResize()
|
||||
{
|
||||
bool FoundTextContainer = false;
|
||||
|
|
|
@ -45,6 +45,16 @@ enum ETextCursorSelectionMode
|
|||
TEXT_CURSOR_SELECTION_MODE_SET,
|
||||
};
|
||||
|
||||
enum ETextCursorCursorMode
|
||||
{
|
||||
// ignore any kind of cursor
|
||||
TEXT_CURSOR_CURSOR_MODE_NONE = 0,
|
||||
// calculates the cursor based on the mouse release cursor position
|
||||
TEXT_CURSOR_CURSOR_MODE_CALCULATE,
|
||||
// sets the cursor based on the current character (this value has to be decoded character offset)
|
||||
TEXT_CURSOR_CURSOR_MODE_SET,
|
||||
};
|
||||
|
||||
class CTextCursor
|
||||
{
|
||||
public:
|
||||
|
@ -71,6 +81,7 @@ public:
|
|||
// these coordinates are repsected if selection mode is set to calculate @see ETextCursorSelectionMode
|
||||
int m_PressMouseX;
|
||||
int m_PressMouseY;
|
||||
// these coordinates are repsected if selection/cursor mode is set to calculate @see ETextCursorSelectionMode / @see ETextCursorCursorMode
|
||||
int m_ReleaseMouseX;
|
||||
int m_ReleaseMouseY;
|
||||
|
||||
|
@ -78,6 +89,10 @@ public:
|
|||
// also note, that these are the character offsets decoded
|
||||
int m_SelectionStart;
|
||||
int m_SelectionEnd;
|
||||
|
||||
ETextCursorCursorMode m_CursorMode;
|
||||
// note this is the decoded character offset
|
||||
int m_CursorCharacter;
|
||||
};
|
||||
|
||||
struct STextRenderColor
|
||||
|
@ -155,6 +170,8 @@ public:
|
|||
virtual int CalculateTextWidth(const char *pText, int TextLength, int FontWidth, int FontHeight) = 0;
|
||||
|
||||
virtual bool SelectionToUTF8OffSets(const char *pText, int SelStart, int SelEnd, int &OffUTF8Start, int &OffUTF8End) = 0;
|
||||
virtual bool UTF8OffToDecodedOff(const char *pText, int UTF8Off, int &DecodedOff) = 0;
|
||||
virtual bool DecodedOffToUTF8Off(const char *pText, int DecodedOff, int &UTF8Off) = 0;
|
||||
|
||||
// old foolish interface
|
||||
virtual void TextColor(float r, float g, float b, float a) = 0;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <base/tl/sorted_array.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <limits>
|
||||
#include <math.h>
|
||||
|
||||
#include <game/generated/client_data.h>
|
||||
|
@ -571,7 +572,8 @@ void CGameConsole::OnRender()
|
|||
Info.m_Offset = pConsole->m_CompletionRenderOffset;
|
||||
Info.m_Width = Screen.w;
|
||||
Info.m_pCurrentCmd = pConsole->m_aCompletionBuffer;
|
||||
TextRender()->SetCursor(&Info.m_Cursor, x + Info.m_Offset, y + RowHeight + 2.0f, FontSize, TEXTFLAG_RENDER);
|
||||
TextRender()->SetCursor(&Info.m_Cursor, x + Info.m_Offset, y + RowHeight + 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
||||
Info.m_Cursor.m_LineWidth = std::numeric_limits<float>::max();
|
||||
|
||||
// render prompt
|
||||
CTextCursor Cursor;
|
||||
|
@ -636,9 +638,7 @@ void CGameConsole::OnRender()
|
|||
Cursor.m_LineWidth = Screen.w - 10.0f - x;
|
||||
|
||||
TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset(Editing));
|
||||
static float MarkerOffset = TextRender()->TextWidth(0, FontSize, "|", -1, -1.0f) / 3;
|
||||
CTextCursor Marker = Cursor;
|
||||
Marker.m_X -= MarkerOffset;
|
||||
Marker.m_LineWidth = -1;
|
||||
TextRender()->TextEx(&Marker, "|", -1);
|
||||
TextRender()->TextEx(&Cursor, aInputString + pConsole->m_Input.GetCursorOffset(Editing), -1);
|
||||
|
|
|
@ -555,7 +555,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
|||
|
||||
static int s_ClearButton = 0;
|
||||
static float Offset = 0.0f;
|
||||
if(Input()->KeyPress(KEY_X) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL)))
|
||||
if(Input()->KeyPress(KEY_X) && (Input()->KeyPress(KEY_LSHIFT) || Input()->KeyPress(KEY_RSHIFT)) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL)))
|
||||
UI()->SetActiveItem(&g_Config.m_BrExcludeString);
|
||||
if(DoClearableEditBox(&g_Config.m_BrExcludeString, &s_ClearButton, &QuickExclude, g_Config.m_BrExcludeString, sizeof(g_Config.m_BrExcludeString), 12.0f, &Offset, false, CUI::CORNER_ALL))
|
||||
Client()->ServerBrowserUpdate();
|
||||
|
|
|
@ -55,12 +55,17 @@ void CLineInput::Add(const char *pString)
|
|||
m_CursorPos = m_Len;
|
||||
}
|
||||
|
||||
bool CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr)
|
||||
static bool IsNotAWordChar(signed char c)
|
||||
{
|
||||
return (c > 0 && c < '0') || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || (c > 'z'); // all non chars in ascii -- random
|
||||
}
|
||||
|
||||
int32_t CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr, int32_t ModifyFlags, int ModifierKey)
|
||||
{
|
||||
int NumChars = *pNumCharsPtr;
|
||||
int CursorPos = *pCursorPosPtr;
|
||||
int Len = *pStrLenPtr;
|
||||
bool Changes = false;
|
||||
int32_t Changes = 0;
|
||||
|
||||
if(CursorPos > Len)
|
||||
CursorPos = Len;
|
||||
|
@ -91,7 +96,7 @@ bool CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, in
|
|||
CursorPos += CharSize;
|
||||
Len += CharSize;
|
||||
NumChars += CharCount;
|
||||
Changes = true;
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_STRING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,35 +104,90 @@ bool CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, in
|
|||
if(Event.m_Flags & IInput::FLAG_PRESS)
|
||||
{
|
||||
int Key = Event.m_Key;
|
||||
if(Key == KEY_BACKSPACE && CursorPos > 0)
|
||||
if(Key == KEY_BACKSPACE)
|
||||
{
|
||||
int NewCursorPos = str_utf8_rewind(pStr, CursorPos);
|
||||
int CharSize = CursorPos - NewCursorPos;
|
||||
mem_move(pStr + NewCursorPos, pStr + CursorPos, Len - NewCursorPos - CharSize + 1); // +1 == null term
|
||||
CursorPos = NewCursorPos;
|
||||
Len -= CharSize;
|
||||
if(CharSize > 0)
|
||||
--NumChars;
|
||||
Changes = true;
|
||||
if((ModifyFlags & LINE_INPUT_MODIFY_DONT_DELETE) == 0 && CursorPos > 0)
|
||||
{
|
||||
int NewCursorPos = str_utf8_rewind(pStr, CursorPos);
|
||||
int CharSize = CursorPos - NewCursorPos;
|
||||
mem_move(pStr + NewCursorPos, pStr + CursorPos, Len - NewCursorPos - CharSize + 1); // +1 == null term
|
||||
CursorPos = NewCursorPos;
|
||||
Len -= CharSize;
|
||||
if(CharSize > 0)
|
||||
--NumChars;
|
||||
}
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_CHARACTERS_DELETE;
|
||||
}
|
||||
else if(Key == KEY_DELETE && CursorPos < Len)
|
||||
else if(Key == KEY_DELETE)
|
||||
{
|
||||
int p = str_utf8_forward(pStr, CursorPos);
|
||||
int CharSize = p - CursorPos;
|
||||
mem_move(pStr + CursorPos, pStr + CursorPos + CharSize, Len - CursorPos - CharSize + 1); // +1 == null term
|
||||
Len -= CharSize;
|
||||
if(CharSize > 0)
|
||||
--NumChars;
|
||||
Changes = true;
|
||||
if((ModifyFlags & LINE_INPUT_MODIFY_DONT_DELETE) == 0 && CursorPos < Len)
|
||||
{
|
||||
int p = str_utf8_forward(pStr, CursorPos);
|
||||
int CharSize = p - CursorPos;
|
||||
mem_move(pStr + CursorPos, pStr + CursorPos + CharSize, Len - CursorPos - CharSize + 1); // +1 == null term
|
||||
Len -= CharSize;
|
||||
if(CharSize > 0)
|
||||
--NumChars;
|
||||
}
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_CHARACTERS_DELETE;
|
||||
}
|
||||
else if(Key == KEY_LEFT)
|
||||
{
|
||||
if(ModifierKey == KEY_LCTRL)
|
||||
{
|
||||
bool MovedCursor = false;
|
||||
int OldCursorPos = CursorPos;
|
||||
CursorPos = str_utf8_rewind(pStr, CursorPos);
|
||||
if(OldCursorPos != CursorPos)
|
||||
MovedCursor = true;
|
||||
bool WasNonWordChar = IsNotAWordChar(pStr[CursorPos]);
|
||||
while((!WasNonWordChar && !IsNotAWordChar(pStr[CursorPos])) || (WasNonWordChar && IsNotAWordChar(pStr[CursorPos])))
|
||||
{
|
||||
CursorPos = str_utf8_rewind(pStr, CursorPos);
|
||||
if(CursorPos == 0)
|
||||
break;
|
||||
}
|
||||
if(MovedCursor && ((!WasNonWordChar && IsNotAWordChar(pStr[CursorPos])) || (WasNonWordChar && !IsNotAWordChar(pStr[CursorPos]))))
|
||||
CursorPos = str_utf8_forward(pStr, CursorPos);
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(CursorPos > 0)
|
||||
CursorPos = str_utf8_rewind(pStr, CursorPos);
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_CURSOR;
|
||||
}
|
||||
}
|
||||
else if(Key == KEY_RIGHT)
|
||||
{
|
||||
if(ModifierKey == KEY_LCTRL)
|
||||
{
|
||||
bool WasNonWordChar = IsNotAWordChar(pStr[CursorPos]);
|
||||
while((!WasNonWordChar && !IsNotAWordChar(pStr[CursorPos])) || (WasNonWordChar && IsNotAWordChar(pStr[CursorPos])))
|
||||
{
|
||||
CursorPos = str_utf8_forward(pStr, CursorPos);
|
||||
if(CursorPos >= Len)
|
||||
break;
|
||||
}
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(CursorPos < Len)
|
||||
CursorPos = str_utf8_forward(pStr, CursorPos);
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_CURSOR;
|
||||
}
|
||||
}
|
||||
else if(Key == KEY_LEFT && CursorPos > 0)
|
||||
CursorPos = str_utf8_rewind(pStr, CursorPos);
|
||||
else if(Key == KEY_RIGHT && CursorPos < Len)
|
||||
CursorPos = str_utf8_forward(pStr, CursorPos);
|
||||
else if(Key == KEY_HOME)
|
||||
{
|
||||
CursorPos = 0;
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
|
||||
}
|
||||
else if(Key == KEY_END)
|
||||
{
|
||||
CursorPos = Len;
|
||||
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
|
||||
}
|
||||
}
|
||||
|
||||
*pNumCharsPtr = NumChars;
|
||||
|
@ -155,5 +215,5 @@ void CLineInput::DeleteFromCursor()
|
|||
|
||||
void CLineInput::ProcessInput(IInput::CEvent e)
|
||||
{
|
||||
Manipulate(e, m_aStr, MAX_SIZE, MAX_CHARS, &m_Len, &m_CursorPos, &m_NumChars);
|
||||
Manipulate(e, m_aStr, MAX_SIZE, MAX_CHARS, &m_Len, &m_CursorPos, &m_NumChars, 0, 0);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,22 @@ class CLineInput
|
|||
int m_FakeCursorPos;
|
||||
|
||||
public:
|
||||
static bool Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr);
|
||||
enum ELineInputChanges
|
||||
{
|
||||
// string was changed
|
||||
LINE_INPUT_CHANGE_STRING = 1 << 0,
|
||||
// characters were removed from the string
|
||||
LINE_INPUT_CHANGE_CHARACTERS_DELETE = 1 << 1,
|
||||
// cursor was changed or tried to change(e.g. pressing right at the last char in the string)
|
||||
LINE_INPUT_CHANGE_CURSOR = 1 << 2,
|
||||
LINE_INPUT_CHANGE_WARP_CURSOR = 1 << 3,
|
||||
};
|
||||
enum ELineInputModifyFlags
|
||||
{
|
||||
// don't delete characters
|
||||
LINE_INPUT_MODIFY_DONT_DELETE = 1 << 0,
|
||||
};
|
||||
static int32_t Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr, int32_t ModifyFlags, int ModifierKey);
|
||||
|
||||
class CCallback
|
||||
{
|
||||
|
|
|
@ -430,7 +430,7 @@ int CUI::DoPickerLogic(const void *pID, const CUIRect *pRect, float *pX, float *
|
|||
return 1;
|
||||
}
|
||||
|
||||
float CUI::DoTextLabel(float x, float y, float w, float h, const char *pText, float Size, int Align, float MaxWidth, int AlignVertically, bool StopAtEnd)
|
||||
float CUI::DoTextLabel(float x, float y, float w, float h, const char *pText, float Size, int Align, float MaxWidth, int AlignVertically, bool StopAtEnd, class CTextCursor *pSelCursor)
|
||||
{
|
||||
float AlignedSize = 0;
|
||||
float MaxCharacterHeightInLine = 0;
|
||||
|
@ -460,15 +460,33 @@ float CUI::DoTextLabel(float x, float y, float w, float h, const char *pText, fl
|
|||
CTextCursor Cursor;
|
||||
TextRender()->SetCursor(&Cursor, AlignmentHori, AlignmentVert, Size, Flags);
|
||||
Cursor.m_LineWidth = (float)MaxWidth;
|
||||
if(pSelCursor)
|
||||
{
|
||||
Cursor.m_CursorMode = pSelCursor->m_CursorMode;
|
||||
Cursor.m_CursorCharacter = pSelCursor->m_CursorCharacter;
|
||||
Cursor.m_CalculateSelectionMode = pSelCursor->m_CalculateSelectionMode;
|
||||
Cursor.m_PressMouseX = pSelCursor->m_PressMouseX;
|
||||
Cursor.m_PressMouseY = pSelCursor->m_PressMouseY;
|
||||
Cursor.m_ReleaseMouseX = pSelCursor->m_ReleaseMouseX;
|
||||
Cursor.m_ReleaseMouseY = pSelCursor->m_ReleaseMouseY;
|
||||
|
||||
Cursor.m_SelectionStart = pSelCursor->m_SelectionStart;
|
||||
Cursor.m_SelectionEnd = pSelCursor->m_SelectionEnd;
|
||||
}
|
||||
|
||||
TextRender()->TextEx(&Cursor, pText, -1);
|
||||
|
||||
if(pSelCursor)
|
||||
{
|
||||
*pSelCursor = Cursor;
|
||||
}
|
||||
|
||||
return tw;
|
||||
}
|
||||
|
||||
void CUI::DoLabel(const CUIRect *r, const char *pText, float Size, int Align, float MaxWidth, int AlignVertically)
|
||||
void CUI::DoLabel(const CUIRect *r, const char *pText, float Size, int Align, float MaxWidth, int AlignVertically, CTextCursor *pSelCursor)
|
||||
{
|
||||
DoTextLabel(r->x, r->y, r->w, r->h, pText, Size, Align, MaxWidth, AlignVertically);
|
||||
DoTextLabel(r->x, r->y, r->w, r->h, pText, Size, Align, MaxWidth, AlignVertically, false, pSelCursor);
|
||||
}
|
||||
|
||||
void CUI::DoLabelScaled(const CUIRect *r, const char *pText, float Size, int Align, float MaxWidth, int AlignVertically)
|
||||
|
|
|
@ -273,8 +273,8 @@ public:
|
|||
int DoButtonLogic(const void *pID, const char *pText /* TODO: Refactor: Remove */, int Checked, const CUIRect *pRect);
|
||||
int DoPickerLogic(const void *pID, const CUIRect *pRect, float *pX, float *pY);
|
||||
|
||||
float DoTextLabel(float x, float y, float w, float h, const char *pText, float Size, int Align, float MaxWidth = -1, int AlignVertically = 1, bool StopAtEnd = false);
|
||||
void DoLabel(const CUIRect *pRect, const char *pText, float Size, int Align, float MaxWidth = -1, int AlignVertically = 1);
|
||||
float DoTextLabel(float x, float y, float w, float h, const char *pText, float Size, int Align, float MaxWidth = -1, int AlignVertically = 1, bool StopAtEnd = false, class CTextCursor *pSelCursor = NULL);
|
||||
void DoLabel(const CUIRect *pRect, const char *pText, float Size, int Align, float MaxWidth = -1, int AlignVertically = 1, class CTextCursor *pSelCursor = NULL);
|
||||
void DoLabelScaled(const CUIRect *pRect, const char *pText, float Size, int Align, float MaxWidth = -1, int AlignVertically = 1);
|
||||
|
||||
void DoLabel(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, float MaxWidth = -1, int AlignVertically = 1, bool StopAtEnd = false, int StrLen = -1, class CTextCursor *pReadCursor = NULL);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#include "ui_ex.h"
|
||||
|
||||
#include <base/system.h>
|
||||
|
||||
#include <base/math.h>
|
||||
#include <engine/textrender.h>
|
||||
|
||||
#include <engine/client/input.h>
|
||||
#include <engine/keys.h>
|
||||
|
||||
|
@ -31,126 +36,216 @@ int CUIEx::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSi
|
|||
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;
|
||||
m_CurCursor = minimum(str_length(pStr), m_CurCursor);
|
||||
|
||||
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_V))
|
||||
bool IsShiftPressed = Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT);
|
||||
bool IsCtrlPressed = Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL);
|
||||
|
||||
if(!IsShiftPressed && IsCtrlPressed && Input()->KeyPress(KEY_V))
|
||||
{
|
||||
const char *Text = Input()->GetClipboardText();
|
||||
if(Text)
|
||||
const char *pText = Input()->GetClipboardText();
|
||||
if(pText)
|
||||
{
|
||||
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++)
|
||||
int OffsetL = minimum(str_length(pStr), m_CurCursor);
|
||||
int OffsetR = OffsetL;
|
||||
|
||||
if(m_HasSelection)
|
||||
{
|
||||
if(pCur[i] == 0)
|
||||
break;
|
||||
else if(pCur[i] == '\r')
|
||||
pCur[i] = ' ';
|
||||
else if(pCur[i] == '\n')
|
||||
pCur[i] = ' ';
|
||||
int SelLeft = minimum(m_CurSelStart, m_CurSelEnd);
|
||||
int SelRight = maximum(m_CurSelStart, m_CurSelEnd);
|
||||
int UTF8SelLeft = -1;
|
||||
int UTF8SelRight = -1;
|
||||
if(TextRender()->SelectionToUTF8OffSets(pStr, SelLeft, SelRight, UTF8SelLeft, UTF8SelRight))
|
||||
{
|
||||
OffsetL = UTF8SelLeft;
|
||||
OffsetR = UTF8SelRight;
|
||||
m_HasSelection = false;
|
||||
}
|
||||
}
|
||||
s_AtIndex = str_length(pStr);
|
||||
|
||||
std::string NewStr(pStr, OffsetL);
|
||||
|
||||
int WrittenChars = 0;
|
||||
|
||||
const char *pIt = pText;
|
||||
while(*pIt)
|
||||
{
|
||||
const char *pTmp = pIt;
|
||||
int Character = str_utf8_decode(&pTmp);
|
||||
if(Character == -1 || Character == 0)
|
||||
break;
|
||||
|
||||
if(Character == '\r' || Character == '\n')
|
||||
{
|
||||
NewStr.append(1, ' ');
|
||||
++WrittenChars;
|
||||
}
|
||||
else
|
||||
{
|
||||
NewStr.append(pIt, (std::intptr_t)(pTmp - pIt));
|
||||
WrittenChars += (int)(std::intptr_t)(pTmp - pIt);
|
||||
}
|
||||
|
||||
pIt = pTmp;
|
||||
}
|
||||
|
||||
NewStr.append(pStr + OffsetR);
|
||||
|
||||
str_copy(pStr, NewStr.c_str(), StrSize);
|
||||
|
||||
m_CurCursor = OffsetL + WrittenChars;
|
||||
ReturnValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyPress(KEY_C))
|
||||
if(!IsShiftPressed && IsCtrlPressed && (Input()->KeyPress(KEY_C) || Input()->KeyPress(KEY_X)))
|
||||
{
|
||||
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(m_HasSelection)
|
||||
{
|
||||
if(TextRender()->TextWidth(0, FontSize, pStr, i, std::numeric_limits<float>::max()) - *Offset > MxRel)
|
||||
int SelLeft = minimum(m_CurSelStart, m_CurSelEnd);
|
||||
int SelRight = maximum(m_CurSelStart, m_CurSelEnd);
|
||||
int UTF8SelLeft = -1;
|
||||
int UTF8SelRight = -1;
|
||||
if(TextRender()->SelectionToUTF8OffSets(pStr, SelLeft, SelRight, UTF8SelLeft, UTF8SelRight))
|
||||
{
|
||||
s_AtIndex = i - 1;
|
||||
break;
|
||||
std::string NewStr(&pStr[UTF8SelLeft], UTF8SelRight - UTF8SelLeft);
|
||||
Input()->SetClipboardText(NewStr.c_str());
|
||||
if(Input()->KeyPress(KEY_X))
|
||||
{
|
||||
NewStr = std::string(pStr, UTF8SelLeft) + std::string(pStr + UTF8SelRight);
|
||||
str_copy(pStr, NewStr.c_str(), StrSize);
|
||||
m_HasSelection = false;
|
||||
if(m_CurCursor > UTF8SelLeft)
|
||||
m_CurCursor = maximum(0, m_CurCursor - (UTF8SelRight - UTF8SelLeft));
|
||||
else
|
||||
m_CurCursor = UTF8SelLeft;
|
||||
}
|
||||
}
|
||||
|
||||
if(i == Len)
|
||||
s_AtIndex = Len;
|
||||
}
|
||||
else
|
||||
Input()->SetClipboardText(pStr);
|
||||
}
|
||||
else if(!UI()->MouseButton(0))
|
||||
s_DoScroll = false;
|
||||
else if(s_DoScroll)
|
||||
|
||||
if(!IsShiftPressed && IsCtrlPressed && Input()->KeyPress(KEY_A))
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
m_CurSelStart = 0;
|
||||
int StrLen = str_length(pStr);
|
||||
TextRender()->UTF8OffToDecodedOff(pStr, StrLen, m_CurSelEnd);
|
||||
m_HasSelection = true;
|
||||
m_CurCursor = StrLen;
|
||||
}
|
||||
|
||||
if(!IsShiftPressed && IsCtrlPressed && Input()->KeyPress(KEY_U))
|
||||
{
|
||||
pStr[0] = '\0';
|
||||
m_CurCursor = 0;
|
||||
ReturnValue = true;
|
||||
}
|
||||
|
||||
for(int i = 0; i < *m_pInputEventCount; i++)
|
||||
{
|
||||
Len = str_length(pStr);
|
||||
int32_t ManipulateChanges = 0;
|
||||
int LastCursor = m_CurCursor;
|
||||
int Len = str_length(pStr);
|
||||
int NumChars = Len;
|
||||
ReturnValue |= CLineInput::Manipulate(m_pInputEventsArray[i], pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars);
|
||||
}
|
||||
}
|
||||
ManipulateChanges = CLineInput::Manipulate(m_pInputEventsArray[i], pStr, StrSize, StrSize, &Len, &m_CurCursor, &NumChars, m_HasSelection ? CLineInput::LINE_INPUT_MODIFY_DONT_DELETE : 0, IsCtrlPressed ? KEY_LCTRL : 0);
|
||||
ReturnValue |= (ManipulateChanges & (CLineInput::LINE_INPUT_CHANGE_STRING | CLineInput::LINE_INPUT_CHANGE_CHARACTERS_DELETE)) != 0;
|
||||
|
||||
bool JustGotActive = false;
|
||||
// if cursor changed, reset selection
|
||||
if(ManipulateChanges != 0)
|
||||
{
|
||||
if(m_HasSelection && (ManipulateChanges & (CLineInput::LINE_INPUT_CHANGE_STRING | CLineInput::LINE_INPUT_CHANGE_CHARACTERS_DELETE)) != 0)
|
||||
{
|
||||
int OffsetL = 0;
|
||||
int OffsetR = 0;
|
||||
|
||||
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);
|
||||
bool IsReverseSel = m_CurSelStart > m_CurSelEnd;
|
||||
|
||||
int ExtraNew = 0;
|
||||
int ExtraOld = 0;
|
||||
// selection correction from added chars
|
||||
if(IsReverseSel)
|
||||
{
|
||||
TextRender()->UTF8OffToDecodedOff(pStr, m_CurCursor, ExtraNew);
|
||||
TextRender()->UTF8OffToDecodedOff(pStr, LastCursor, ExtraOld);
|
||||
}
|
||||
|
||||
int SelLeft = minimum(m_CurSelStart, m_CurSelEnd);
|
||||
int SelRight = maximum(m_CurSelStart, m_CurSelEnd);
|
||||
int UTF8SelLeft = -1;
|
||||
int UTF8SelRight = -1;
|
||||
if(TextRender()->SelectionToUTF8OffSets(pStr, SelLeft + (ExtraNew - ExtraOld), SelRight + (ExtraNew - ExtraOld), UTF8SelLeft, UTF8SelRight))
|
||||
{
|
||||
OffsetL = UTF8SelLeft;
|
||||
OffsetR = UTF8SelRight;
|
||||
m_HasSelection = false;
|
||||
}
|
||||
|
||||
std::string NewStr(pStr, OffsetL);
|
||||
|
||||
NewStr.append(pStr + OffsetR);
|
||||
|
||||
str_copy(pStr, NewStr.c_str(), StrSize);
|
||||
|
||||
if(!IsReverseSel)
|
||||
m_CurCursor = clamp<int>(m_CurCursor - (UTF8SelRight - UTF8SelLeft), 0, NewStr.length());
|
||||
}
|
||||
|
||||
if(IsShiftPressed && (ManipulateChanges & CLineInput::LINE_INPUT_CHANGE_STRING) == 0)
|
||||
{
|
||||
int CursorPosDecoded = -1;
|
||||
int LastCursorPosDecoded = -1;
|
||||
|
||||
if(!m_HasSelection)
|
||||
{
|
||||
m_CurSelStart = -1;
|
||||
m_CurSelEnd = -1;
|
||||
}
|
||||
|
||||
if(TextRender()->UTF8OffToDecodedOff(pStr, m_CurCursor, CursorPosDecoded))
|
||||
{
|
||||
if(TextRender()->UTF8OffToDecodedOff(pStr, LastCursor, LastCursorPosDecoded))
|
||||
{
|
||||
if(!m_HasSelection)
|
||||
{
|
||||
m_CurSelStart = LastCursorPosDecoded;
|
||||
m_CurSelEnd = LastCursorPosDecoded;
|
||||
}
|
||||
m_CurSelEnd += (CursorPosDecoded - LastCursorPosDecoded);
|
||||
}
|
||||
}
|
||||
if(m_CurSelStart == m_CurSelEnd)
|
||||
m_HasSelection = false;
|
||||
else
|
||||
m_HasSelection = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_HasSelection && (ManipulateChanges & CLineInput::LINE_INPUT_CHANGE_CURSOR) != 0)
|
||||
{
|
||||
if(m_CurSelStart < m_CurSelEnd)
|
||||
{
|
||||
if(m_CurCursor >= LastCursor)
|
||||
m_CurCursor = LastCursor;
|
||||
else
|
||||
TextRender()->DecodedOffToUTF8Off(pStr, m_CurSelStart, m_CurCursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_CurCursor <= LastCursor)
|
||||
m_CurCursor = LastCursor;
|
||||
else
|
||||
TextRender()->DecodedOffToUTF8Off(pStr, m_CurSelStart, m_CurCursor);
|
||||
}
|
||||
}
|
||||
m_HasSelection = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +274,7 @@ int CUIEx::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSi
|
|||
}
|
||||
|
||||
char aDispEditingText[128 + IInput::INPUT_TEXT_SIZE + 2] = {0};
|
||||
int DispCursorPos = s_AtIndex;
|
||||
int DispCursorPos = m_CurCursor;
|
||||
if(UI()->LastActiveItem() == pID && Input()->GetIMEEditingTextLength() > -1)
|
||||
{
|
||||
int EditingTextCursor = Input()->GetEditingCursor();
|
||||
|
@ -198,11 +293,11 @@ int CUIEx::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSi
|
|||
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--)
|
||||
for(int i = str_length(aDispEditingText) - 1; i >= m_CurCursor; i--)
|
||||
aDispEditingText[i + FillCharLen] = aDispEditingText[i];
|
||||
for(int i = 0; i < FillCharLen; i++)
|
||||
aDispEditingText[s_AtIndex + i] = aEditingText[i];
|
||||
DispCursorPos = s_AtIndex + EditingTextCursor + 1;
|
||||
aDispEditingText[m_CurCursor + i] = aEditingText[i];
|
||||
DispCursorPos = m_CurCursor + EditingTextCursor + 1;
|
||||
pDisplayStr = aDispEditingText;
|
||||
UpdateOffset = true;
|
||||
}
|
||||
|
@ -215,6 +310,24 @@ int CUIEx::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSi
|
|||
|
||||
DispCursorPos = minimum(DispCursorPos, str_length(pDisplayStr));
|
||||
|
||||
bool JustGotActive = false;
|
||||
if(UI()->ActiveItem() == pID)
|
||||
{
|
||||
if(!UI()->MouseButton(0))
|
||||
{
|
||||
UI()->SetActiveItem(0);
|
||||
}
|
||||
}
|
||||
else if(UI()->HotItem() == pID)
|
||||
{
|
||||
if(UI()->MouseButton(0))
|
||||
{
|
||||
if(UI()->LastActiveItem() != pID)
|
||||
JustGotActive = true;
|
||||
UI()->SetActiveItem(pID);
|
||||
}
|
||||
}
|
||||
|
||||
// check if the text has to be moved
|
||||
if(UI()->LastActiveItem() == pID && !JustGotActive && (UpdateOffset || *m_pInputEventCount))
|
||||
{
|
||||
|
@ -240,34 +353,71 @@ int CUIEx::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSi
|
|||
UI()->ClipEnable(pRect);
|
||||
Textbox.x -= *Offset;
|
||||
|
||||
UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1);
|
||||
CTextCursor SelCursor;
|
||||
TextRender()->SetCursor(&SelCursor, 0, 0, 16, 0);
|
||||
|
||||
bool HasMouseSel = false;
|
||||
if(UI()->LastActiveItem() == pID)
|
||||
{
|
||||
if(!m_MouseIsPress && UI()->MouseButtonClicked(0))
|
||||
{
|
||||
m_MouseIsPress = true;
|
||||
m_MousePressX = UI()->MouseX();
|
||||
m_MousePressY = UI()->MouseY();
|
||||
}
|
||||
}
|
||||
|
||||
if(m_MouseIsPress)
|
||||
{
|
||||
m_MouseCurX = UI()->MouseX();
|
||||
m_MouseCurY = UI()->MouseY();
|
||||
}
|
||||
HasMouseSel = m_MouseIsPress;
|
||||
if(m_MouseIsPress && UI()->MouseButtonReleased(0))
|
||||
{
|
||||
m_MouseIsPress = false;
|
||||
}
|
||||
|
||||
if(UI()->LastActiveItem() == pID)
|
||||
{
|
||||
int CursorPos = -1;
|
||||
TextRender()->UTF8OffToDecodedOff(pDisplayStr, DispCursorPos, CursorPos);
|
||||
|
||||
SelCursor.m_CursorMode = HasMouseSel ? TEXT_CURSOR_CURSOR_MODE_CALCULATE : TEXT_CURSOR_CURSOR_MODE_SET;
|
||||
SelCursor.m_CursorCharacter = CursorPos;
|
||||
SelCursor.m_CalculateSelectionMode = HasMouseSel ? TEXT_CURSOR_SELECTION_MODE_CALCULATE : (m_HasSelection ? TEXT_CURSOR_SELECTION_MODE_SET : TEXT_CURSOR_SELECTION_MODE_NONE);
|
||||
SelCursor.m_PressMouseX = m_MousePressX;
|
||||
SelCursor.m_PressMouseY = m_MousePressY;
|
||||
SelCursor.m_ReleaseMouseX = m_MouseCurX;
|
||||
SelCursor.m_ReleaseMouseY = m_MouseCurY;
|
||||
SelCursor.m_SelectionStart = m_CurSelStart;
|
||||
SelCursor.m_SelectionEnd = m_CurSelEnd;
|
||||
}
|
||||
|
||||
UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1, -1, 1, &SelCursor);
|
||||
|
||||
if(UI()->LastActiveItem() == pID)
|
||||
{
|
||||
if(SelCursor.m_CalculateSelectionMode == TEXT_CURSOR_SELECTION_MODE_CALCULATE)
|
||||
{
|
||||
m_CurSelStart = SelCursor.m_SelectionStart;
|
||||
m_CurSelEnd = SelCursor.m_SelectionEnd;
|
||||
m_HasSelection = m_CurSelStart != m_CurSelEnd;
|
||||
}
|
||||
if(SelCursor.m_CursorMode == TEXT_CURSOR_CURSOR_MODE_CALCULATE)
|
||||
{
|
||||
TextRender()->DecodedOffToUTF8Off(pDisplayStr, SelCursor.m_CursorCharacter, DispCursorPos);
|
||||
m_CurCursor = DispCursorPos;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// set the ime 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);
|
||||
float PosToMid = (Textbox.h - FontSize) / 2.0f;
|
||||
IGraphics::CQuadItem CursorTBack(Textbox.x - (OnePixelWidth * 2.0f) / 2.0f, Textbox.y + PosToMid, OnePixelWidth * 2 * 2.0f, FontSize);
|
||||
Graphics()->QuadsDrawTL(&CursorTBack, 1);
|
||||
Graphics()->SetColor(1, 1, 1, 1);
|
||||
IGraphics::CQuadItem CursorT(Textbox.x, Textbox.y + PosToMid + OnePixelWidth * 1.5f, OnePixelWidth * 2.0f, FontSize - OnePixelWidth * 1.5f * 2);
|
||||
Graphics()->QuadsDrawTL(&CursorT, 1);
|
||||
Graphics()->QuadsEnd();
|
||||
}
|
||||
|
||||
Input()->SetEditingPosition(Textbox.x, Textbox.y + FontSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,18 @@ class CUIEx
|
|||
IInput::CEvent *m_pInputEventsArray;
|
||||
int *m_pInputEventCount;
|
||||
|
||||
bool m_MouseIsPress;
|
||||
bool m_HasSelection;
|
||||
|
||||
int m_MousePressX = 0;
|
||||
int m_MousePressY = 0;
|
||||
int m_MouseCurX = 0;
|
||||
int m_MouseCurY = 0;
|
||||
int m_CurSelStart = 0;
|
||||
int m_CurSelEnd = 0;
|
||||
|
||||
int m_CurCursor = 0;
|
||||
|
||||
protected:
|
||||
CUI *UI() { return m_pUI; }
|
||||
IInput *Input() { return m_pInput; }
|
||||
|
|
Loading…
Reference in a new issue