Merge CUIEx class into CUI

There is no need to separate the UI in two classes anymore, as the dependency on `CRenderTools` has been removed.
This commit is contained in:
Robert Müller 2022-08-07 22:03:34 +02:00
parent 95550fd6a9
commit 51fb3e9a22
16 changed files with 875 additions and 951 deletions

View file

@ -2101,8 +2101,6 @@ if(CLIENT)
skin.h
ui.cpp
ui.h
ui_ex.cpp
ui_ex.h
ui_rect.cpp
ui_rect.h
)

View file

@ -476,7 +476,7 @@ int CMenus::DoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, bool
if(ms_ValueSelectorTextMode && s_pLastTextpID == pID)
{
static float s_NumberBoxID = 0;
UIEx()->DoEditBox(&s_NumberBoxID, pRect, s_aNumStr, sizeof(s_aNumStr), 10.0f, &s_NumberBoxID, false, IGraphics::CORNER_ALL);
UI()->DoEditBox(&s_NumberBoxID, pRect, s_aNumStr, sizeof(s_aNumStr), 10.0f, &s_NumberBoxID, false, IGraphics::CORNER_ALL);
UI()->SetActiveItem(&s_NumberBoxID);
@ -982,7 +982,7 @@ void CMenus::OnInit()
if(g_Config.m_ClSkipStartMenu)
m_ShowStart = false;
UIEx()->Init(UI(), Kernel(), RenderTools(), m_aInputEvents, &m_NumInputEvents);
UI()->InitInputs(m_aInputEvents, &m_NumInputEvents);
m_RefreshButton.Init(UI(), -1);
m_ConnectButton.Init(UI(), -1);
@ -1272,7 +1272,7 @@ int CMenus::Render()
CUIRect Screen = *UI()->Screen();
UI()->MapScreen();
UIEx()->ResetMouseSlow();
UI()->ResetMouseSlow();
static int s_Frame = 0;
if(s_Frame == 0)
@ -1763,7 +1763,7 @@ int CMenus::Render()
TextBox.VSplitRight(60.0f, &TextBox, 0);
UI()->DoLabel(&Label, Localize("Password"), 18.0f, TEXTALIGN_LEFT);
static float s_Offset = 0.0f;
UIEx()->DoEditBox(&g_Config.m_Password, &TextBox, g_Config.m_Password, sizeof(g_Config.m_Password), 12.0f, &s_Offset, true);
UI()->DoEditBox(&g_Config.m_Password, &TextBox, g_Config.m_Password, sizeof(g_Config.m_Password), 12.0f, &s_Offset, true);
}
else if(m_Popup == POPUP_CONNECTING)
{
@ -1990,7 +1990,7 @@ int CMenus::Render()
TextBox.VSplitRight(60.0f, &TextBox, 0);
UI()->DoLabel(&Label, Localize("New name:"), 18.0f, TEXTALIGN_LEFT);
static float s_Offset = 0.0f;
UIEx()->DoEditBox(&s_Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &s_Offset);
UI()->DoEditBox(&s_Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &s_Offset);
}
#if defined(CONF_VIDEORECORDER)
else if(m_Popup == POPUP_RENDER_DEMO)
@ -2113,7 +2113,7 @@ int CMenus::Render()
TextBox.VSplitRight(60.0f, &TextBox, 0);
UI()->DoLabel(&Label, Localize("Video name:"), 18.0f, TEXTALIGN_LEFT);
static float s_Offset = 0.0f;
UIEx()->DoEditBox(&s_Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &s_Offset);
UI()->DoEditBox(&s_Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &s_Offset);
}
else if(m_Popup == POPUP_REPLACE_VIDEO)
{
@ -2227,7 +2227,7 @@ int CMenus::Render()
static float s_Offset = 0.0f;
SUIExEditBoxProperties EditProps;
EditProps.m_pEmptyText = Client()->PlayerName();
UIEx()->DoEditBox(&g_Config.m_PlayerName, &TextBox, g_Config.m_PlayerName, sizeof(g_Config.m_PlayerName), 12.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditProps);
UI()->DoEditBox(&g_Config.m_PlayerName, &TextBox, g_Config.m_PlayerName, sizeof(g_Config.m_PlayerName), 12.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditProps);
}
else if(m_Popup == POPUP_POINTS)
{
@ -2428,7 +2428,7 @@ bool CMenus::OnCursorMove(float x, float y, IInput::ECursorType CursorType)
if(!m_MenuActive)
return false;
UIEx()->ConvertMouseMove(&x, &y, CursorType);
UI()->ConvertMouseMove(&x, &y, CursorType);
m_MousePos.x = clamp(m_MousePos.x + x, 0.f, (float)Graphics()->WindowWidth());
m_MousePos.y = clamp(m_MousePos.y + y, 0.f, (float)Graphics()->WindowHeight());

View file

@ -19,7 +19,6 @@
#include <game/client/component.h>
#include <game/client/ui.h>
#include <game/client/ui_ex.h>
#include <game/voting.h>
#include <game/client/render.h>
@ -78,10 +77,6 @@ class CMenus : public CComponent
char m_aLocalStringHelper[1024];
CUIEx m_UIEx;
CUIEx *UIEx() { return &m_UIEx; }
int DoButton_DemoPlayer(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
int DoButton_Sprite(CButtonContainer *pButtonContainer, int ImageID, int SpriteID, int Checked, const CUIRect *pRect, int Corners);
int DoButton_Toggle(const void *pID, int Checked, const CUIRect *pRect, bool Active);

View file

@ -186,7 +186,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
static float s_ScrollValue = 0;
s_ScrollValue = UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(Input()->KeyPress(KEY_TAB) && m_pClient->m_GameConsole.IsClosed())
{
@ -549,7 +549,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
}
static int s_ClearButton = 0;
static float s_Offset = 0.0f;
if(UIEx()->DoClearableEditBox(&g_Config.m_BrFilterString, &s_ClearButton, &QuickSearch, g_Config.m_BrFilterString, sizeof(g_Config.m_BrFilterString), 12.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditProps))
if(UI()->DoClearableEditBox(&g_Config.m_BrFilterString, &s_ClearButton, &QuickSearch, g_Config.m_BrFilterString, sizeof(g_Config.m_BrFilterString), 12.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditProps))
Client()->ServerBrowserUpdate();
}
@ -576,7 +576,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
static float s_Offset = 0.0f;
if(Input()->KeyPress(KEY_X) && (Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT)) && Input()->ModifierIsPressed())
UI()->SetActiveItem(&g_Config.m_BrExcludeString);
if(UIEx()->DoClearableEditBox(&g_Config.m_BrExcludeString, &s_ClearButton, &QuickExclude, g_Config.m_BrExcludeString, sizeof(g_Config.m_BrExcludeString), 12.0f, &s_Offset, false, IGraphics::CORNER_ALL))
if(UI()->DoClearableEditBox(&g_Config.m_BrExcludeString, &s_ClearButton, &QuickExclude, g_Config.m_BrExcludeString, sizeof(g_Config.m_BrExcludeString), 12.0f, &s_Offset, false, IGraphics::CORNER_ALL))
Client()->ServerBrowserUpdate();
}
@ -610,7 +610,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
ServerAddr.VSplitLeft(SearchExcludeAddrStrMax + 5.0f + ExcludeSearchIconMax + 5.0f, NULL, &ServerAddr);
static int s_ClearButton = 0;
static float s_Offset = 0.0f;
UIEx()->DoClearableEditBox(&g_Config.m_UiServerAddress, &s_ClearButton, &ServerAddr, g_Config.m_UiServerAddress, sizeof(g_Config.m_UiServerAddress), 12.0f, &s_Offset);
UI()->DoClearableEditBox(&g_Config.m_UiServerAddress, &s_ClearButton, &ServerAddr, g_Config.m_UiServerAddress, sizeof(g_Config.m_UiServerAddress), 12.0f, &s_Offset);
// button area
ButtonArea = ConnectButtons;
@ -721,7 +721,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View)
Button.VSplitRight(60.0f, 0, &Button);
ServerFilter.HSplitTop(3.0f, 0, &ServerFilter);
static float s_OffsetGametype = 0.0f;
if(UIEx()->DoEditBox(&g_Config.m_BrFilterGametype, &Button, g_Config.m_BrFilterGametype, sizeof(g_Config.m_BrFilterGametype), FontSize, &s_OffsetGametype))
if(UI()->DoEditBox(&g_Config.m_BrFilterGametype, &Button, g_Config.m_BrFilterGametype, sizeof(g_Config.m_BrFilterGametype), FontSize, &s_OffsetGametype))
Client()->ServerBrowserUpdate();
// server address
@ -730,7 +730,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View)
UI()->DoLabel(&Button, Localize("Server address:"), FontSize, TEXTALIGN_LEFT);
Button.VSplitRight(60.0f, 0, &Button);
static float s_OffsetAddr = 0.0f;
if(UIEx()->DoEditBox(&g_Config.m_BrFilterServerAddress, &Button, g_Config.m_BrFilterServerAddress, sizeof(g_Config.m_BrFilterServerAddress), FontSize, &s_OffsetAddr))
if(UI()->DoEditBox(&g_Config.m_BrFilterServerAddress, &Button, g_Config.m_BrFilterServerAddress, sizeof(g_Config.m_BrFilterServerAddress), FontSize, &s_OffsetAddr))
Client()->ServerBrowserUpdate();
// player country
@ -1358,7 +1358,7 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
Button.VSplitLeft(80.0f, 0, &Button);
static char s_aName[MAX_NAME_LENGTH] = {0};
static float s_OffsetName = 0.0f;
UIEx()->DoEditBox(&s_aName, &Button, s_aName, sizeof(s_aName), FontSize + 2, &s_OffsetName);
UI()->DoEditBox(&s_aName, &Button, s_aName, sizeof(s_aName), FontSize + 2, &s_OffsetName);
ServerFriends.HSplitTop(3.0f, 0, &ServerFriends);
ServerFriends.HSplitTop(19.0f, &Button, &ServerFriends);
@ -1367,7 +1367,7 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
Button.VSplitLeft(80.0f, 0, &Button);
static char s_aClan[MAX_CLAN_LENGTH] = {0};
static float s_OffsetClan = 0.0f;
UIEx()->DoEditBox(&s_aClan, &Button, s_aClan, sizeof(s_aClan), FontSize + 2, &s_OffsetClan);
UI()->DoEditBox(&s_aClan, &Button, s_aClan, sizeof(s_aClan), FontSize + 2, &s_OffsetClan);
ServerFriends.HSplitTop(3.0f, 0, &ServerFriends);
ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends);

View file

@ -160,7 +160,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
TextBox.VSplitRight(60.0f, &TextBox, 0);
UI()->DoLabel(&Label, Localize("New name:"), 18.0f, TEXTALIGN_LEFT);
static float s_Offset = 0.0f;
if(UIEx()->DoEditBox(&s_Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &s_Offset))
if(UI()->DoEditBox(&s_Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &s_Offset))
{
m_aDemoPlayerPopupHint[0] = '\0';
}
@ -563,7 +563,7 @@ void CMenus::UiDoListboxStart(const void *pID, const CUIRect *pRect, float RowHe
if(Num == 0)
gs_ListBoxScrollValue = 0;
else
gs_ListBoxScrollValue = UIEx()->DoScrollbarV(pID, &Scroll, gs_ListBoxScrollValue);
gs_ListBoxScrollValue = UI()->DoScrollbarV(pID, &Scroll, gs_ListBoxScrollValue);
// the list
gs_ListBoxView = gs_ListBoxOriginalView;
@ -1078,7 +1078,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
ListBox.VSplitRight(20.0f, &ListBox, &Scroll);
static float s_ScrollValue = 0;
s_ScrollValue = UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
int PreviousIndex = m_DemolistSelectedIndex;
HandleListInputs(ListBox, s_ScrollValue, 3.0f, &m_ScrollOffset, s_aCols[0].m_Rect.h, m_DemolistSelectedIndex, m_vDemos.size());

View file

@ -633,7 +633,7 @@ void CMenus::RenderServerControl(CUIRect MainView)
EditProps.m_SelectText = true;
}
EditProps.m_pEmptyText = Localize("Search");
UIEx()->DoClearableEditBox(&m_aFilterString, &s_ClearButton, &QuickSearch, m_aFilterString, sizeof(m_aFilterString), 14.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditProps);
UI()->DoClearableEditBox(&m_aFilterString, &s_ClearButton, &QuickSearch, m_aFilterString, sizeof(m_aFilterString), 14.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditProps);
}
Bottom.VSplitRight(120.0f, &Bottom, &Button);
@ -680,7 +680,7 @@ void CMenus::RenderServerControl(CUIRect MainView)
static float s_Offset = 0.0f;
if(Input()->KeyPress(KEY_R) && Input()->ModifierIsPressed())
UI()->SetActiveItem(&m_aCallvoteReason);
UIEx()->DoEditBox(&m_aCallvoteReason, &Reason, m_aCallvoteReason, sizeof(m_aCallvoteReason), 14.0f, &s_Offset, false, IGraphics::CORNER_ALL);
UI()->DoEditBox(&m_aCallvoteReason, &Reason, m_aCallvoteReason, sizeof(m_aCallvoteReason), 14.0f, &s_Offset, false, IGraphics::CORNER_ALL);
// extended features (only available when authed in rcon)
if(Client()->RconAuthed())
@ -751,11 +751,11 @@ void CMenus::RenderServerControl(CUIRect MainView)
Bottom.VSplitLeft(5.0f, 0, &Bottom);
Bottom.VSplitLeft(250.0f, &Button, &Bottom);
static float s_OffsetDesc = 0.0f;
UIEx()->DoEditBox(&s_aVoteDescription, &Button, s_aVoteDescription, sizeof(s_aVoteDescription), 14.0f, &s_OffsetDesc, false, IGraphics::CORNER_ALL);
UI()->DoEditBox(&s_aVoteDescription, &Button, s_aVoteDescription, sizeof(s_aVoteDescription), 14.0f, &s_OffsetDesc, false, IGraphics::CORNER_ALL);
Bottom.VMargin(20.0f, &Button);
static float s_OffsetCmd = 0.0f;
UIEx()->DoEditBox(&s_aVoteCommand, &Button, s_aVoteCommand, sizeof(s_aVoteCommand), 14.0f, &s_OffsetCmd, false, IGraphics::CORNER_ALL);
UI()->DoEditBox(&s_aVoteCommand, &Button, s_aVoteCommand, sizeof(s_aVoteCommand), 14.0f, &s_OffsetCmd, false, IGraphics::CORNER_ALL);
}
}
}
@ -981,7 +981,7 @@ void CMenus::RenderGhost(CUIRect MainView)
View.VSplitRight(20.0f, &View, &Scroll);
static float s_ScrollValue = 0;
s_ScrollValue = UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
int NumGhosts = m_vGhosts.size();
static int s_SelectedIndex = 0;

View file

@ -163,7 +163,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Max demos"), "");
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
Right.HSplitTop(20.0f, &Button, &Right);
g_Config.m_ClAutoDemoMax = static_cast<int>(UIEx()->DoScrollbarH(&g_Config.m_ClAutoDemoMax, &Button, g_Config.m_ClAutoDemoMax / 1000.0f) * 1000.0f + 0.1f);
g_Config.m_ClAutoDemoMax = static_cast<int>(UI()->DoScrollbarH(&g_Config.m_ClAutoDemoMax, &Button, g_Config.m_ClAutoDemoMax / 1000.0f) * 1000.0f + 0.1f);
Right.HSplitTop(SliderGroupMargin, 0, &Right);
Right.HSplitTop(20.0f, &Button, &Right);
@ -177,7 +177,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Max Screenshots"), "");
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
Right.HSplitTop(20.0f, &Button, &Right);
g_Config.m_ClAutoScreenshotMax = static_cast<int>(UIEx()->DoScrollbarH(&g_Config.m_ClAutoScreenshotMax, &Button, g_Config.m_ClAutoScreenshotMax / 1000.0f) * 1000.0f + 0.1f);
g_Config.m_ClAutoScreenshotMax = static_cast<int>(UI()->DoScrollbarH(&g_Config.m_ClAutoScreenshotMax, &Button, g_Config.m_ClAutoScreenshotMax / 1000.0f) * 1000.0f + 0.1f);
}
Left.HSplitTop(10.0f, 0, &Left);
@ -188,7 +188,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Refresh Rate"), "");
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
Left.HSplitTop(20.0f, &Button, &Left);
g_Config.m_ClRefreshRate = static_cast<int>(UIEx()->DoScrollbarH(&g_Config.m_ClRefreshRate, &Button, g_Config.m_ClRefreshRate / 10000.0f) * 10000.0f + 0.1f);
g_Config.m_ClRefreshRate = static_cast<int>(UI()->DoScrollbarH(&g_Config.m_ClRefreshRate, &Button, g_Config.m_ClRefreshRate / 10000.0f) * 10000.0f + 0.1f);
Left.HSplitTop(15.0f, 0, &Left);
CUIRect SettingsButton;
@ -256,7 +256,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
Right.HSplitTop(20.0f, &Button, &Right);
g_Config.m_ClAutoStatboardScreenshotMax =
static_cast<int>(UIEx()->DoScrollbarH(&g_Config.m_ClAutoStatboardScreenshotMax,
static_cast<int>(UI()->DoScrollbarH(&g_Config.m_ClAutoStatboardScreenshotMax,
&Button,
g_Config.m_ClAutoStatboardScreenshotMax / 1000.0f) *
1000.0f +
@ -282,7 +282,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
Right.HSplitTop(20.0f, &Button, &Right);
g_Config.m_ClAutoCSVMax =
static_cast<int>(UIEx()->DoScrollbarH(&g_Config.m_ClAutoCSVMax,
static_cast<int>(UI()->DoScrollbarH(&g_Config.m_ClAutoCSVMax,
&Button,
g_Config.m_ClAutoCSVMax / 1000.0f) *
1000.0f +
@ -327,7 +327,7 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
static float s_OffsetName = 0.0f;
SUIExEditBoxProperties EditProps;
EditProps.m_pEmptyText = pNameFallback;
if(UIEx()->DoEditBox(pName, &Button, pName, sizeof(g_Config.m_PlayerName), 14.0f, &s_OffsetName, false, IGraphics::CORNER_ALL, EditProps))
if(UI()->DoEditBox(pName, &Button, pName, sizeof(g_Config.m_PlayerName), 14.0f, &s_OffsetName, false, IGraphics::CORNER_ALL, EditProps))
{
SetNeedSendInfo();
}
@ -341,7 +341,7 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
str_format(aBuf, sizeof(aBuf), "%s:", Localize("Clan"));
UI()->DoLabel(&Label, aBuf, 14.0f, TEXTALIGN_LEFT);
static float s_OffsetClan = 0.0f;
if(UIEx()->DoEditBox(pClan, &Button, pClan, sizeof(g_Config.m_PlayerClan), 14.0f, &s_OffsetClan))
if(UI()->DoEditBox(pClan, &Button, pClan, sizeof(g_Config.m_PlayerClan), 14.0f, &s_OffsetClan))
{
SetNeedSendInfo();
}
@ -501,7 +501,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
{
static int s_ClearButton = 0;
static float s_Offset = 0.0f;
UIEx()->DoClearableEditBox(g_Config.m_ClSkinPrefix, &s_ClearButton, &SkinPrefixLabel, g_Config.m_ClSkinPrefix, sizeof(g_Config.m_ClSkinPrefix), 14.0f, &s_Offset);
UI()->DoClearableEditBox(g_Config.m_ClSkinPrefix, &s_ClearButton, &SkinPrefixLabel, g_Config.m_ClSkinPrefix, sizeof(g_Config.m_ClSkinPrefix), 14.0f, &s_Offset);
}
SkinPrefix.HSplitTop(2.0f, 0, &SkinPrefix);
@ -587,7 +587,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
static int s_ClearButton = 0;
SUIExEditBoxProperties EditProps;
EditProps.m_pEmptyText = "default";
if(UIEx()->DoClearableEditBox(pSkinName, &s_ClearButton, &Label, pSkinName, sizeof(g_Config.m_ClPlayerSkin), 14.0f, &s_OffsetSkin, false, IGraphics::CORNER_ALL, EditProps))
if(UI()->DoClearableEditBox(pSkinName, &s_ClearButton, &Label, pSkinName, sizeof(g_Config.m_ClPlayerSkin), 14.0f, &s_OffsetSkin, false, IGraphics::CORNER_ALL, EditProps))
{
SetNeedSendInfo();
}
@ -740,7 +740,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
EditPropsSearch.m_SelectText = true;
}
EditPropsSearch.m_pEmptyText = Localize("Search");
if(UIEx()->DoClearableEditBox(&g_Config.m_ClSkinFilterString, &s_ClearButtonSearch, &QuickSearch, g_Config.m_ClSkinFilterString, sizeof(g_Config.m_ClSkinFilterString), 14.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditPropsSearch))
if(UI()->DoClearableEditBox(&g_Config.m_ClSkinFilterString, &s_ClearButtonSearch, &QuickSearch, g_Config.m_ClSkinFilterString, sizeof(g_Config.m_ClSkinFilterString), 14.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditPropsSearch))
s_InitSkinlist = true;
}
@ -952,23 +952,23 @@ float CMenus::RenderSettingsControlsJoystick(CUIRect View)
View.HSplitTop(Spacing, 0, &View);
View.HSplitTop(ButtonHeight, &Button, &View);
const char *apLabels[] = {Localize("Relative", "Ingame controller mode"), Localize("Absolute", "Ingame controller mode")};
UIEx()->DoScrollbarOptionLabeled(&g_Config.m_InpControllerAbsolute, &g_Config.m_InpControllerAbsolute, &Button, Localize("Ingame controller mode"), apLabels, std::size(apLabels));
UI()->DoScrollbarOptionLabeled(&g_Config.m_InpControllerAbsolute, &g_Config.m_InpControllerAbsolute, &Button, Localize("Ingame controller mode"), apLabels, std::size(apLabels));
}
if(!g_Config.m_InpControllerAbsolute)
{
View.HSplitTop(Spacing, 0, &View);
View.HSplitTop(ButtonHeight, &Button, &View);
UIEx()->DoScrollbarOption(&g_Config.m_InpControllerSens, &g_Config.m_InpControllerSens, &Button, Localize("Ingame controller sens."), 1, 500, &CUIEx::ms_LogarithmicScrollbarScale, CUIEx::SCROLLBAR_OPTION_NOCLAMPVALUE);
UI()->DoScrollbarOption(&g_Config.m_InpControllerSens, &g_Config.m_InpControllerSens, &Button, Localize("Ingame controller sens."), 1, 500, &CUI::ms_LogarithmicScrollbarScale, CUI::SCROLLBAR_OPTION_NOCLAMPVALUE);
}
View.HSplitTop(Spacing, 0, &View);
View.HSplitTop(ButtonHeight, &Button, &View);
UIEx()->DoScrollbarOption(&g_Config.m_UiControllerSens, &g_Config.m_UiControllerSens, &Button, Localize("UI controller sens."), 1, 500, &CUIEx::ms_LogarithmicScrollbarScale, CUIEx::SCROLLBAR_OPTION_NOCLAMPVALUE);
UI()->DoScrollbarOption(&g_Config.m_UiControllerSens, &g_Config.m_UiControllerSens, &Button, Localize("UI controller sens."), 1, 500, &CUI::ms_LogarithmicScrollbarScale, CUI::SCROLLBAR_OPTION_NOCLAMPVALUE);
View.HSplitTop(Spacing, 0, &View);
View.HSplitTop(ButtonHeight, &Button, &View);
UIEx()->DoScrollbarOption(&g_Config.m_InpControllerTolerance, &g_Config.m_InpControllerTolerance, &Button, Localize("Controller jitter tolerance"), 0, 50);
UI()->DoScrollbarOption(&g_Config.m_InpControllerTolerance, &g_Config.m_InpControllerTolerance, &Button, Localize("Controller jitter tolerance"), 0, 50);
View.HSplitTop(Spacing, 0, &View);
View.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.125f), IGraphics::CORNER_ALL, 5.0f);
@ -1133,12 +1133,12 @@ void CMenus::RenderSettingsControls(CUIRect MainView)
CUIRect Button;
MouseSettings.HSplitTop(20.0f, &Button, &MouseSettings);
UIEx()->DoScrollbarOption(&g_Config.m_InpMousesens, &g_Config.m_InpMousesens, &Button, Localize("Ingame mouse sens."), 1, 500, &CUIEx::ms_LogarithmicScrollbarScale, CUIEx::SCROLLBAR_OPTION_NOCLAMPVALUE);
UI()->DoScrollbarOption(&g_Config.m_InpMousesens, &g_Config.m_InpMousesens, &Button, Localize("Ingame mouse sens."), 1, 500, &CUI::ms_LogarithmicScrollbarScale, CUI::SCROLLBAR_OPTION_NOCLAMPVALUE);
MouseSettings.HSplitTop(2.0f, 0, &MouseSettings);
MouseSettings.HSplitTop(20.0f, &Button, &MouseSettings);
UIEx()->DoScrollbarOption(&g_Config.m_UiMousesens, &g_Config.m_UiMousesens, &Button, Localize("UI mouse sens."), 1, 500, &CUIEx::ms_LogarithmicScrollbarScale, CUIEx::SCROLLBAR_OPTION_NOCLAMPVALUE);
UI()->DoScrollbarOption(&g_Config.m_UiMousesens, &g_Config.m_UiMousesens, &Button, Localize("UI mouse sens."), 1, 500, &CUI::ms_LogarithmicScrollbarScale, CUI::SCROLLBAR_OPTION_NOCLAMPVALUE);
}
// joystick settings
@ -1507,7 +1507,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
else
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Refresh Rate"), "");
UI()->DoLabel(&Label, aBuf, 14.0f, TEXTALIGN_LEFT);
int NewRefreshRate = static_cast<int>(UIEx()->DoScrollbarH(&g_Config.m_GfxRefreshRate, &Button, (minimum(g_Config.m_GfxRefreshRate, 1000)) / 1000.0f) * 1000.0f + 0.1f);
int NewRefreshRate = static_cast<int>(UI()->DoScrollbarH(&g_Config.m_GfxRefreshRate, &Button, (minimum(g_Config.m_GfxRefreshRate, 1000)) / 1000.0f) * 1000.0f + 0.1f);
if(g_Config.m_GfxRefreshRate <= 1000 || NewRefreshRate < 1000)
g_Config.m_GfxRefreshRate = NewRefreshRate;
@ -1796,7 +1796,7 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
UI()->DoLabel(&Button, Localize("Sample rate"), 14.0f, TEXTALIGN_LEFT);
Button.VSplitLeft(190.0f, 0, &Button);
static float s_Offset = 0.0f;
UIEx()->DoEditBox(&g_Config.m_SndRate, &Button, aBuf, sizeof(aBuf), 14.0f, &s_Offset);
UI()->DoEditBox(&g_Config.m_SndRate, &Button, aBuf, sizeof(aBuf), 14.0f, &s_Offset);
g_Config.m_SndRate = maximum(1, str_toint(aBuf));
m_NeedRestartSound = !s_SndEnable || s_SndRate != g_Config.m_SndRate;
}
@ -1807,7 +1807,7 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
MainView.HSplitTop(20.0f, &Button, &MainView);
Button.VSplitLeft(190.0f, &Label, &Button);
UI()->DoLabel(&Label, Localize("Sound volume"), 14.0f, TEXTALIGN_LEFT);
g_Config.m_SndVolume = (int)(UIEx()->DoScrollbarH(&g_Config.m_SndVolume, &Button, g_Config.m_SndVolume / 100.0f) * 100.0f);
g_Config.m_SndVolume = (int)(UI()->DoScrollbarH(&g_Config.m_SndVolume, &Button, g_Config.m_SndVolume / 100.0f) * 100.0f);
}
// volume slider game sounds
@ -1816,7 +1816,7 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
MainView.HSplitTop(20.0f, &Button, &MainView);
Button.VSplitLeft(190.0f, &Label, &Button);
UI()->DoLabel(&Label, Localize("Game sound volume"), 14.0f, TEXTALIGN_LEFT);
g_Config.m_SndGameSoundVolume = (int)(UIEx()->DoScrollbarH(&g_Config.m_SndGameSoundVolume, &Button, g_Config.m_SndGameSoundVolume / 100.0f) * 100.0f);
g_Config.m_SndGameSoundVolume = (int)(UI()->DoScrollbarH(&g_Config.m_SndGameSoundVolume, &Button, g_Config.m_SndGameSoundVolume / 100.0f) * 100.0f);
}
// volume slider gui sounds
@ -1825,7 +1825,7 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
MainView.HSplitTop(20.0f, &Button, &MainView);
Button.VSplitLeft(190.0f, &Label, &Button);
UI()->DoLabel(&Label, Localize("Chat sound volume"), 14.0f, TEXTALIGN_LEFT);
g_Config.m_SndChatSoundVolume = (int)(UIEx()->DoScrollbarH(&g_Config.m_SndChatSoundVolume, &Button, g_Config.m_SndChatSoundVolume / 100.0f) * 100.0f);
g_Config.m_SndChatSoundVolume = (int)(UI()->DoScrollbarH(&g_Config.m_SndChatSoundVolume, &Button, g_Config.m_SndChatSoundVolume / 100.0f) * 100.0f);
}
// volume slider map sounds
@ -1834,7 +1834,7 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
MainView.HSplitTop(20.0f, &Button, &MainView);
Button.VSplitLeft(190.0f, &Label, &Button);
UI()->DoLabel(&Label, Localize("Map sound volume"), 14.0f, TEXTALIGN_LEFT);
g_Config.m_SndMapSoundVolume = (int)(UIEx()->DoScrollbarH(&g_Config.m_SndMapSoundVolume, &Button, g_Config.m_SndMapSoundVolume / 100.0f) * 100.0f);
g_Config.m_SndMapSoundVolume = (int)(UI()->DoScrollbarH(&g_Config.m_SndMapSoundVolume, &Button, g_Config.m_SndMapSoundVolume / 100.0f) * 100.0f);
}
// volume slider background music
@ -1843,7 +1843,7 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
MainView.HSplitTop(20.0f, &Button, &MainView);
Button.VSplitLeft(190.0f, &Label, &Button);
UI()->DoLabel(&Label, Localize("Background music volume"), 14.0f, TEXTALIGN_LEFT);
g_Config.m_SndBackgroundMusicVolume = (int)(UIEx()->DoScrollbarH(&g_Config.m_SndBackgroundMusicVolume, &Button, g_Config.m_SndBackgroundMusicVolume / 100.0f) * 100.0f);
g_Config.m_SndBackgroundMusicVolume = (int)(UI()->DoScrollbarH(&g_Config.m_SndBackgroundMusicVolume, &Button, g_Config.m_SndBackgroundMusicVolume / 100.0f) * 100.0f);
}
}
@ -2451,7 +2451,7 @@ ColorHSLA CMenus::RenderHSLScrollbars(CUIRect *pRect, unsigned int *pColor, bool
ColorInner = color_cast<ColorRGBA>(ColorHSLA(CurColorPureHSLA.r, *apComponent[1], LightVal, *apComponent[3]));
}
*apComponent[i] = UIEx()->DoScrollbarH(&((char *)pColor)[i], &Button, *apComponent[i], &ColorInner);
*apComponent[i] = UI()->DoScrollbarH(&((char *)pColor)[i], &Button, *apComponent[i], &ColorInner);
}
*pColor = Color.Pack(Alpha);
@ -2589,7 +2589,7 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView)
Section.HSplitTop(LineSize, &Button, &Section);
str_format(aBuf, sizeof(aBuf), "%s: %i%%", Localize("Opacity of freeze bars inside freeze"), g_Config.m_ClFreezeBarsAlphaInsideFreeze);
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
g_Config.m_ClFreezeBarsAlphaInsideFreeze = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClFreezeBarsAlphaInsideFreeze, &Button, g_Config.m_ClFreezeBarsAlphaInsideFreeze / 100.0f) * 100.0f);
g_Config.m_ClFreezeBarsAlphaInsideFreeze = (int)(UI()->DoScrollbarH(&g_Config.m_ClFreezeBarsAlphaInsideFreeze, &Button, g_Config.m_ClFreezeBarsAlphaInsideFreeze / 100.0f) * 100.0f);
}
else
{
@ -2833,7 +2833,7 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView)
Section.HSplitTop(LineSize, &Button, &Section);
str_format(aBuf, sizeof(aBuf), "%s: %i", Localize("Name plates size"), g_Config.m_ClNameplatesSize);
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
g_Config.m_ClNameplatesSize = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClNameplatesSize, &Button, g_Config.m_ClNameplatesSize / 100.0f) * 100.0f + 0.1f);
g_Config.m_ClNameplatesSize = (int)(UI()->DoScrollbarH(&g_Config.m_ClNameplatesSize, &Button, g_Config.m_ClNameplatesSize / 100.0f) * 100.0f + 0.1f);
}
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClNameplatesClan, Localize("Show clan above name plates"), &g_Config.m_ClNameplatesClan, &Section, LineSize);
@ -2843,7 +2843,7 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView)
Section.HSplitTop(LineSize, &Button, &Section);
str_format(aBuf, sizeof(aBuf), "%s: %i", Localize("Clan plates size"), g_Config.m_ClNameplatesClanSize);
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
g_Config.m_ClNameplatesClanSize = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClNameplatesClanSize, &Button, g_Config.m_ClNameplatesClanSize / 100.0f) * 100.0f + 0.1f);
g_Config.m_ClNameplatesClanSize = (int)(UI()->DoScrollbarH(&g_Config.m_ClNameplatesClanSize, &Button, g_Config.m_ClNameplatesClanSize / 100.0f) * 100.0f + 0.1f);
}
else
{
@ -2889,7 +2889,7 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView)
Section.HSplitTop(LineSize, &Button, &Section);
str_format(aBuf, sizeof(aBuf), "%s: %i", Localize("Hook collision line width"), g_Config.m_ClHookCollSize);
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
g_Config.m_ClHookCollSize = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClHookCollSize, &Button, g_Config.m_ClHookCollSize / 20.0f) * 20.0f);
g_Config.m_ClHookCollSize = (int)(UI()->DoScrollbarH(&g_Config.m_ClHookCollSize, &Button, g_Config.m_ClHookCollSize / 20.0f) * 20.0f);
}
{
@ -2897,7 +2897,7 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView)
Section.HSplitTop(LineSize, &Button, &Section);
str_format(aBuf, sizeof(aBuf), "%s: %i%%", Localize("Hook collision line opacity"), g_Config.m_ClHookCollAlpha);
UI()->DoLabel(&Label, aBuf, 13.0f, TEXTALIGN_LEFT);
g_Config.m_ClHookCollAlpha = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClHookCollAlpha, &Button, g_Config.m_ClHookCollAlpha / 100.0f) * 100.0f);
g_Config.m_ClHookCollAlpha = (int)(UI()->DoScrollbarH(&g_Config.m_ClHookCollAlpha, &Button, g_Config.m_ClHookCollAlpha / 100.0f) * 100.0f);
}
static CButtonContainer s_HookCollNoCollResetID, s_HookCollHookableCollResetID, s_HookCollTeeCollResetID;
@ -3001,7 +3001,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
str_format(aBuf, sizeof(aBuf), Localize("Default length: %d"), g_Config.m_ClReplayLength);
UI()->DoLabel(&Label, aBuf, 14.0f, TEXTALIGN_LEFT);
int NewValue = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClReplayLength, &Button, (minimum(g_Config.m_ClReplayLength, 600) - 10) / 590.0f) * 590.0f) + 10;
int NewValue = (int)(UI()->DoScrollbarH(&g_Config.m_ClReplayLength, &Button, (minimum(g_Config.m_ClReplayLength, 600) - 10) / 590.0f) * 590.0f) + 10;
if(g_Config.m_ClReplayLength < 600 || NewValue < 600)
g_Config.m_ClReplayLength = minimum(NewValue, 600);
}
@ -3041,7 +3041,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
Left.HSplitTop(20.0f, &Button, &Left);
Button.VSplitLeft(120.0f, &Label, &Button);
UI()->DoLabel(&Label, Localize("Overlay entities"), 14.0f, TEXTALIGN_LEFT);
g_Config.m_ClOverlayEntities = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClOverlayEntities, &Button, g_Config.m_ClOverlayEntities / 100.0f) * 100.0f);
g_Config.m_ClOverlayEntities = (int)(UI()->DoScrollbarH(&g_Config.m_ClOverlayEntities, &Button, g_Config.m_ClOverlayEntities / 100.0f) * 100.0f);
}
{
@ -3050,7 +3050,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
Button.VSplitLeft(50.0f, &Label, &Button);
UI()->DoLabel(&Label, Localize("Size"), 14.0f, TEXTALIGN_LEFT);
g_Config.m_ClTextEntitiesSize = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClTextEntitiesSize, &Button, g_Config.m_ClTextEntitiesSize / 100.0f) * 100.0f);
g_Config.m_ClTextEntitiesSize = (int)(UI()->DoScrollbarH(&g_Config.m_ClTextEntitiesSize, &Button, g_Config.m_ClTextEntitiesSize / 100.0f) * 100.0f);
if(DoButton_CheckBox(&g_Config.m_ClTextEntities, Localize("Show text entities"), g_Config.m_ClTextEntities, &LeftLeft))
{
@ -3064,7 +3064,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
Button.VSplitLeft(50.0f, &Label, &Button);
UI()->DoLabel(&Label, Localize("Opacity"), 14.0f, TEXTALIGN_LEFT);
g_Config.m_ClShowOthersAlpha = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClShowOthersAlpha, &Button, g_Config.m_ClShowOthersAlpha / 100.0f) * 100.0f);
g_Config.m_ClShowOthersAlpha = (int)(UI()->DoScrollbarH(&g_Config.m_ClShowOthersAlpha, &Button, g_Config.m_ClShowOthersAlpha / 100.0f) * 100.0f);
if(DoButton_CheckBox(&g_Config.m_ClShowOthers, Localize("Show others"), g_Config.m_ClShowOthers == SHOW_OTHERS_ON, &LeftLeft))
{
@ -3093,7 +3093,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "%s: %i", Localize("Default zoom"), g_Config.m_ClDefaultZoom);
UI()->DoLabel(&Label, aBuf, 14.0f, TEXTALIGN_LEFT);
g_Config.m_ClDefaultZoom = static_cast<int>(UIEx()->DoScrollbarH(&g_Config.m_ClDefaultZoom, &Button, g_Config.m_ClDefaultZoom / 20.0f) * 20.0f + 0.1f);
g_Config.m_ClDefaultZoom = static_cast<int>(UI()->DoScrollbarH(&g_Config.m_ClDefaultZoom, &Button, g_Config.m_ClDefaultZoom / 20.0f) * 20.0f + 0.1f);
Right.HSplitTop(20.0f, &Button, &Right);
if(DoButton_CheckBox(&g_Config.m_ClAntiPing, Localize("AntiPing"), g_Config.m_ClAntiPing, &Button))
@ -3164,7 +3164,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
Background.VSplitLeft(100.0f, &Label, &TempLabel);
UI()->DoLabel(&Label, Localize("Map"), 14.0f, TEXTALIGN_LEFT);
static float s_Map = 0.0f;
UIEx()->DoEditBox(g_Config.m_ClBackgroundEntities, &TempLabel, g_Config.m_ClBackgroundEntities, sizeof(g_Config.m_ClBackgroundEntities), 14.0f, &s_Map);
UI()->DoEditBox(g_Config.m_ClBackgroundEntities, &TempLabel, g_Config.m_ClBackgroundEntities, sizeof(g_Config.m_ClBackgroundEntities), 14.0f, &s_Map);
Left.HSplitTop(20.0f, &Button, &Left);
bool UseCurrentMap = str_comp(g_Config.m_ClBackgroundEntities, CURRENT_MAP) == 0;
@ -3206,7 +3206,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
Button.VSplitLeft(5.0f, 0, &Button);
SUIExEditBoxProperties EditProps;
EditProps.m_pEmptyText = Localize("Chat command (e.g. showall 1)");
UIEx()->DoEditBox(g_Config.m_ClRunOnJoin, &Button, g_Config.m_ClRunOnJoin, sizeof(g_Config.m_ClRunOnJoin), 14.0f, &s_RunOnJoin, false, IGraphics::CORNER_ALL, EditProps);
UI()->DoEditBox(g_Config.m_ClRunOnJoin, &Button, g_Config.m_ClRunOnJoin, sizeof(g_Config.m_ClRunOnJoin), 14.0f, &s_RunOnJoin, false, IGraphics::CORNER_ALL, EditProps);
// Updater
#if defined(CONF_AUTOUPDATE)
{

View file

@ -659,7 +659,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
EditProps.m_SelectText = true;
}
EditProps.m_pEmptyText = Localize("Search");
if(UIEx()->DoClearableEditBox(&s_aFilterString[s_CurCustomTab], &s_ClearButton, &QuickSearch, s_aFilterString[s_CurCustomTab], sizeof(s_aFilterString[0]), 14.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditProps))
if(UI()->DoClearableEditBox(&s_aFilterString[s_CurCustomTab], &s_ClearButton, &QuickSearch, s_aFilterString[s_CurCustomTab], sizeof(s_aFilterString[0]), 14.0f, &s_Offset, false, IGraphics::CORNER_ALL, EditProps))
gs_aInitCustomList[s_CurCustomTab] = true;
}

View file

@ -228,7 +228,7 @@ void CGameClient::OnInit()
m_pGraphics->AddWindowResizeListener(OnWindowResizeCB, this);
// propagate pointers
m_UI.Init(Input(), Graphics(), TextRender());
m_UI.Init(Kernel());
m_RenderTools.Init(Graphics(), TextRender());
int64_t Start = time_get();

View file

@ -3,11 +3,15 @@
#include "ui.h"
#include <base/math.h>
#include <base/system.h>
#include <engine/graphics.h>
#include <engine/input.h>
#include <engine/keys.h>
#include <engine/shared/config.h>
#include <game/client/lineinput.h>
#include <limits>
void CUIElement::Init(CUI *pUI, int RequestedRectCount)
@ -73,16 +77,25 @@ void CUIElement::SUIElementRect::Draw(const CUIRect *pRect, ColorRGBA Color, int
UI
*********************************************************/
const CLinearScrollbarScale CUI::ms_LinearScrollbarScale;
const CLogarithmicScrollbarScale CUI::ms_LogarithmicScrollbarScale(25);
float CUI::ms_FontmodHeight = 0.8f;
void CUI::Init(IInput *pInput, IGraphics *pGraphics, ITextRender *pTextRender)
void CUI::Init(IKernel *pKernel)
{
m_pInput = pInput;
m_pGraphics = pGraphics;
m_pTextRender = pTextRender;
m_pGraphics = pKernel->RequestInterface<IGraphics>();
m_pInput = pKernel->RequestInterface<IInput>();
m_pTextRender = pKernel->RequestInterface<ITextRender>();
InitInputs(m_pInput->GetEventsRaw(), m_pInput->GetEventCountRaw());
CUIRect::Init(m_pGraphics);
}
void CUI::InitInputs(IInput::CEvent *pInputEventsArray, int *pInputEventCount)
{
m_pInputEventsArray = pInputEventsArray;
m_pInputEventCount = pInputEventCount;
}
CUI::CUI()
{
m_Enabled = true;
@ -213,6 +226,10 @@ void CUI::ConvertMouseMove(float *pX, float *pY, IInput::ECursorType CursorType)
dbg_break();
break;
}
if(m_MouseSlow)
Factor *= 0.05f;
*pX *= Factor;
*pY *= Factor;
}
@ -551,3 +568,680 @@ void CUI::DoLabelStreamed(CUIElement::SUIElementRect &RectEl, const CUIRect *pRe
{
DoLabelStreamed(RectEl, pRect->x, pRect->y, pRect->w, pRect->h, pText, Size, Align, MaxWidth, AlignVertically, StopAtEnd, StrLen, pReadCursor);
}
bool CUI::DoEditBox(const void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden, int Corners, const SUIExEditBoxProperties &Properties)
{
const bool Inside = MouseHovered(pRect);
bool ReturnValue = false;
bool UpdateOffset = false;
auto &&SetHasSelection = [&](bool HasSelection) {
m_HasSelection = HasSelection;
m_pSelItem = m_HasSelection ? pID : nullptr;
};
auto &&SelectAllText = [&]() {
m_CurSelStart = 0;
int StrLen = str_length(pStr);
TextRender()->UTF8OffToDecodedOff(pStr, StrLen, m_CurSelEnd);
SetHasSelection(true);
m_CurCursor = StrLen;
};
if(LastActiveItem() == pID)
{
if(m_HasSelection && m_pSelItem != pID)
{
SetHasSelection(false);
}
m_CurCursor = minimum(str_length(pStr), m_CurCursor);
bool IsShiftPressed = Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT);
bool IsModPressed = Input()->ModifierIsPressed();
if(Enabled() && !IsShiftPressed && IsModPressed && Input()->KeyPress(KEY_V))
{
const char *pText = Input()->GetClipboardText();
if(pText)
{
int OffsetL = clamp(m_CurCursor, 0, str_length(pStr));
int OffsetR = OffsetL;
if(m_HasSelection)
{
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;
SetHasSelection(false);
}
}
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(Enabled() && !IsShiftPressed && IsModPressed && (Input()->KeyPress(KEY_C) || Input()->KeyPress(KEY_X)))
{
if(m_HasSelection)
{
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))
{
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);
SetHasSelection(false);
if(m_CurCursor > UTF8SelLeft)
m_CurCursor = maximum(0, m_CurCursor - (UTF8SelRight - UTF8SelLeft));
else
m_CurCursor = UTF8SelLeft;
}
}
}
else
Input()->SetClipboardText(pStr);
}
if(Properties.m_SelectText || (Enabled() && !IsShiftPressed && IsModPressed && Input()->KeyPress(KEY_A)))
{
SelectAllText();
}
if(Enabled() && !IsShiftPressed && IsModPressed && Input()->KeyPress(KEY_U))
{
pStr[0] = '\0';
m_CurCursor = 0;
SetHasSelection(false);
ReturnValue = true;
}
for(int i = 0; i < *m_pInputEventCount; i++)
{
int LastCursor = m_CurCursor;
int Len, NumChars;
str_utf8_stats(pStr, StrSize, StrSize, &Len, &NumChars);
int32_t ManipulateChanges = CLineInput::Manipulate(m_pInputEventsArray[i], pStr, StrSize, StrSize, &Len, &m_CurCursor, &NumChars, m_HasSelection ? CLineInput::LINE_INPUT_MODIFY_DONT_DELETE : 0, IsModPressed ? KEY_LCTRL : 0);
ReturnValue |= (ManipulateChanges & (CLineInput::LINE_INPUT_CHANGE_STRING | CLineInput::LINE_INPUT_CHANGE_CHARACTERS_DELETE)) != 0;
// 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;
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;
SetHasSelection(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)
SetHasSelection(false);
else
SetHasSelection(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);
}
}
SetHasSelection(false);
}
}
}
}
if(Inside)
{
SetHotItem(pID);
}
CUIRect Textbox = *pRect;
Textbox.Draw(ColorRGBA(1, 1, 1, 0.5f), Corners, 3.0f);
Textbox.Margin(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 = m_CurCursor;
if(LastActiveItem() == pID && Input()->GetIMEEditingTextLength() > -1)
{
int EditingTextCursor = Input()->GetEditingCursor();
str_copy(aDispEditingText, pDisplayStr);
char aEditingText[IInput::INPUT_TEXT_SIZE + 2];
if(Hidden)
{
// Do not show editing text in password field
str_copy(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 >= m_CurCursor; i--)
aDispEditingText[i + FillCharLen] = aDispEditingText[i];
for(int i = 0; i < FillCharLen; i++)
aDispEditingText[m_CurCursor + i] = aEditingText[i];
DispCursorPos = m_CurCursor + EditingTextCursor + 1;
pDisplayStr = aDispEditingText;
UpdateOffset = true;
}
bool IsEmptyText = false;
if(pDisplayStr[0] == '\0')
{
pDisplayStr = Properties.m_pEmptyText;
IsEmptyText = true;
TextRender()->TextColor(1, 1, 1, 0.75f);
}
DispCursorPos = minimum(DispCursorPos, str_length(pDisplayStr));
bool JustGotActive = false;
if(CheckActiveItem(pID))
{
if(!MouseButton(0))
{
SetActiveItem(nullptr);
}
}
else if(HotItem() == pID)
{
if(MouseButton(0))
{
if(LastActiveItem() != pID)
JustGotActive = true;
SetActiveItem(pID);
}
}
// check if the text has to be moved
if(LastActiveItem() == pID && !JustGotActive && (UpdateOffset || *m_pInputEventCount))
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, DispCursorPos, std::numeric_limits<float>::max());
if(w - *pOffset > Textbox.w)
{
// move to the left
float wt = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1, std::numeric_limits<float>::max());
do
{
*pOffset += minimum(wt - *pOffset - Textbox.w, Textbox.w / 3);
} while(w - *pOffset > Textbox.w + 0.0001f);
}
else if(w - *pOffset < 0.0f)
{
// move to the right
do
{
*pOffset = maximum(0.0f, *pOffset - Textbox.w / 3);
} while(w - *pOffset < -0.0001f);
}
}
ClipEnable(pRect);
Textbox.x -= *pOffset;
CTextCursor SelCursor;
TextRender()->SetCursor(&SelCursor, 0, 0, 16, 0);
bool HasMouseSel = false;
if(LastActiveItem() == pID)
{
if(!m_MouseIsPress && MouseButtonClicked(0))
{
m_MouseIsPress = true;
m_MousePressX = MouseX();
m_MousePressY = MouseY();
}
}
if(m_MouseIsPress)
{
m_MouseCurX = MouseX();
m_MouseCurY = MouseY();
}
HasMouseSel = m_MouseIsPress && !IsEmptyText;
if(m_MouseIsPress && MouseButtonReleased(0))
{
m_MouseIsPress = false;
}
if(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;
}
SLabelProperties Props;
Props.m_pSelCursor = &SelCursor;
Props.m_EnableWidthCheck = IsEmptyText;
DoLabel(&Textbox, pDisplayStr, FontSize, TEXTALIGN_LEFT, Props);
if(LastActiveItem() == pID)
{
if(SelCursor.m_CalculateSelectionMode == TEXT_CURSOR_SELECTION_MODE_CALCULATE)
{
m_CurSelStart = SelCursor.m_SelectionStart;
m_CurSelEnd = SelCursor.m_SelectionEnd;
SetHasSelection(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);
// set the ime cursor
if(LastActiveItem() == pID && !JustGotActive)
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, DispCursorPos, std::numeric_limits<float>::max());
Textbox.x += w;
Input()->SetEditingPosition(Textbox.x, Textbox.y + FontSize);
}
ClipDisable();
return ReturnValue;
}
bool CUI::DoClearableEditBox(const void *pID, const void *pClearID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden, int Corners, const SUIExEditBoxProperties &Properties)
{
CUIRect EditBox;
CUIRect ClearButton;
pRect->VSplitRight(15.0f, &EditBox, &ClearButton);
bool ReturnValue = DoEditBox(pID, &EditBox, pStr, StrSize, FontSize, pOffset, Hidden, Corners & ~IGraphics::CORNER_R, Properties);
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT);
ClearButton.Draw(ColorRGBA(1, 1, 1, 0.33f * ButtonColorMul(pClearID)), Corners & ~IGraphics::CORNER_L, 3.0f);
SLabelProperties Props;
Props.m_AlignVertically = 0;
DoLabel(&ClearButton, "×", ClearButton.h * CUI::ms_FontmodHeight, TEXTALIGN_CENTER, Props);
TextRender()->SetRenderFlags(0);
if(DoButtonLogic(pClearID, 0, &ClearButton))
{
pStr[0] = 0;
SetActiveItem(pID);
ReturnValue = true;
}
return ReturnValue;
}
float CUI::DoScrollbarV(const void *pID, const CUIRect *pRect, float Current)
{
Current = clamp(Current, 0.0f, 1.0f);
// layout
CUIRect Rail;
pRect->Margin(5.0f, &Rail);
CUIRect Handle;
Rail.HSplitTop(clamp(33.0f, Rail.w, Rail.h / 3.0f), &Handle, 0);
Handle.y = Rail.y + (Rail.h - Handle.h) * Current;
// logic
static float s_OffsetY;
const bool InsideRail = MouseHovered(&Rail);
const bool InsideHandle = MouseHovered(&Handle);
bool Grabbed = false; // whether to apply the offset
if(CheckActiveItem(pID))
{
if(MouseButton(0))
{
Grabbed = true;
if(Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT))
m_MouseSlow = true;
}
else
{
SetActiveItem(nullptr);
}
}
else if(HotItem() == pID)
{
if(MouseButton(0))
{
SetActiveItem(pID);
s_OffsetY = MouseY() - Handle.y;
Grabbed = true;
}
}
else if(MouseButtonClicked(0) && !InsideHandle && InsideRail)
{
SetActiveItem(pID);
s_OffsetY = Handle.h / 2.0f;
Grabbed = true;
}
if(InsideHandle)
{
SetHotItem(pID);
}
float ReturnValue = Current;
if(Grabbed)
{
const float Min = Rail.y;
const float Max = Rail.h - Handle.h;
const float Cur = MouseY() - s_OffsetY;
ReturnValue = clamp((Cur - Min) / Max, 0.0f, 1.0f);
}
// render
Rail.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, Rail.w / 2.0f);
float ColorSlider;
if(CheckActiveItem(pID))
ColorSlider = 0.9f;
else if(HotItem() == pID)
ColorSlider = 1.0f;
else
ColorSlider = 0.8f;
Handle.Draw(ColorRGBA(ColorSlider, ColorSlider, ColorSlider, 1.0f), IGraphics::CORNER_ALL, Handle.w / 2.0f);
return ReturnValue;
}
float CUI::DoScrollbarH(const void *pID, const CUIRect *pRect, float Current, const ColorRGBA *pColorInner)
{
Current = clamp(Current, 0.0f, 1.0f);
// layout
CUIRect Rail;
if(pColorInner)
Rail = *pRect;
else
pRect->HMargin(5.0f, &Rail);
CUIRect Handle;
Rail.VSplitLeft(pColorInner ? 8.0f : clamp(33.0f, Rail.h, Rail.w / 3.0f), &Handle, 0);
Handle.x += (Rail.w - Handle.w) * Current;
// logic
static float s_OffsetX;
const bool InsideRail = MouseHovered(&Rail);
const bool InsideHandle = MouseHovered(&Handle);
bool Grabbed = false; // whether to apply the offset
if(CheckActiveItem(pID))
{
if(MouseButton(0))
{
Grabbed = true;
if(Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT))
m_MouseSlow = true;
}
else
{
SetActiveItem(nullptr);
}
}
else if(HotItem() == pID)
{
if(MouseButton(0))
{
SetActiveItem(pID);
s_OffsetX = MouseX() - Handle.x;
Grabbed = true;
}
}
else if(MouseButtonClicked(0) && !InsideHandle && InsideRail)
{
SetActiveItem(pID);
s_OffsetX = Handle.w / 2.0f;
Grabbed = true;
}
if(InsideHandle)
{
SetHotItem(pID);
}
float ReturnValue = Current;
if(Grabbed)
{
const float Min = Rail.x;
const float Max = Rail.w - Handle.w;
const float Cur = MouseX() - s_OffsetX;
ReturnValue = clamp((Cur - Min) / Max, 0.0f, 1.0f);
}
// render
if(pColorInner)
{
CUIRect Slider;
Handle.VMargin(-2.0f, &Slider);
Slider.HMargin(-3.0f, &Slider);
Slider.Draw(ColorRGBA(0.15f, 0.15f, 0.15f, 1.0f), IGraphics::CORNER_ALL, 5.0f);
Slider.Margin(2.0f, &Slider);
Slider.Draw(*pColorInner, IGraphics::CORNER_ALL, 3.0f);
}
else
{
Rail.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, Rail.h / 2.0f);
float ColorSlider;
if(CheckActiveItem(pID))
ColorSlider = 0.9f;
else if(HotItem() == pID)
ColorSlider = 1.0f;
else
ColorSlider = 0.8f;
Handle.Draw(ColorRGBA(ColorSlider, ColorSlider, ColorSlider, 1.0f), IGraphics::CORNER_ALL, Handle.h / 2.0f);
}
return ReturnValue;
}
void CUI::DoScrollbarOption(const void *pID, int *pOption, const CUIRect *pRect, const char *pStr, int Min, int Max, const IScrollbarScale *pScale, unsigned Flags)
{
const bool Infinite = Flags & CUI::SCROLLBAR_OPTION_INFINITE;
const bool NoClampValue = Flags & CUI::SCROLLBAR_OPTION_NOCLAMPVALUE;
dbg_assert(!(Infinite && NoClampValue), "cannot combine SCROLLBAR_OPTION_INFINITE and SCROLLBAR_OPTION_NOCLAMPVALUE");
int Value = *pOption;
if(Infinite)
{
Min += 1;
Max += 1;
if(Value == 0)
Value = Max;
}
char aBufMax[256];
str_format(aBufMax, sizeof(aBufMax), "%s: %i", pStr, Max);
char aBuf[256];
if(!Infinite || Value != Max)
str_format(aBuf, sizeof(aBuf), "%s: %i", pStr, Value);
else
str_format(aBuf, sizeof(aBuf), "%s: ∞", pStr);
if(NoClampValue)
{
// clamp the value internally for the scrollbar
Value = clamp(Value, Min, Max);
}
float FontSize = pRect->h * CUI::ms_FontmodHeight * 0.8f;
float VSplitVal = 10.0f + maximum(TextRender()->TextWidth(0, FontSize, aBuf, -1, std::numeric_limits<float>::max()), TextRender()->TextWidth(0, FontSize, aBufMax, -1, std::numeric_limits<float>::max()));
CUIRect Label, ScrollBar;
pRect->VSplitLeft(VSplitVal, &Label, &ScrollBar);
DoLabel(&Label, aBuf, FontSize, TEXTALIGN_LEFT);
Value = pScale->ToAbsolute(DoScrollbarH(pID, &ScrollBar, pScale->ToRelative(Value, Min, Max)), Min, Max);
if(Infinite)
{
if(Value == Max)
Value = 0;
}
else if(NoClampValue)
{
if((Value == Min && *pOption < Min) || (Value == Max && *pOption > Max))
Value = *pOption; // use previous out of range value instead if the scrollbar is at the edge
}
*pOption = Value;
}
void CUI::DoScrollbarOptionLabeled(const void *pID, int *pOption, const CUIRect *pRect, const char *pStr, const char **ppLabels, int NumLabels, const IScrollbarScale *pScale)
{
const int Max = NumLabels - 1;
int Value = clamp(*pOption, 0, Max);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "%s: %s", pStr, ppLabels[Value]);
float FontSize = pRect->h * CUI::ms_FontmodHeight * 0.8f;
CUIRect Label, ScrollBar;
pRect->VSplitRight(60.0f, &Label, &ScrollBar);
Label.VSplitRight(10.0f, &Label, 0);
DoLabel(&Label, aBuf, FontSize, TEXTALIGN_LEFT);
Value = pScale->ToAbsolute(DoScrollbarH(pID, &ScrollBar, pScale->ToRelative(Value, 0, Max)), 0, Max);
if(HotItem() != pID && !CheckActiveItem(pID) && MouseHovered(pRect) && MouseButtonClicked(0))
Value = (Value + 1) % NumLabels;
*pOption = clamp(Value, 0, Max);
}

View file

@ -12,6 +12,9 @@
#include <string>
#include <vector>
class IGraphics;
class IKernel;
struct SUIAnimator
{
bool m_Active;
@ -27,6 +30,63 @@ struct SUIAnimator
float m_HOffset;
};
class IScrollbarScale
{
public:
virtual float ToRelative(int AbsoluteValue, int Min, int Max) const = 0;
virtual int ToAbsolute(float RelativeValue, int Min, int Max) const = 0;
};
class CLinearScrollbarScale : public IScrollbarScale
{
public:
float ToRelative(int AbsoluteValue, int Min, int Max) const override
{
return (AbsoluteValue - Min) / (float)(Max - Min);
}
int ToAbsolute(float RelativeValue, int Min, int Max) const override
{
return round_to_int(RelativeValue * (Max - Min) + Min + 0.1f);
}
};
class CLogarithmicScrollbarScale : public IScrollbarScale
{
private:
int m_MinAdjustment;
public:
CLogarithmicScrollbarScale(int MinAdjustment)
{
m_MinAdjustment = maximum(MinAdjustment, 1); // must be at least 1 to support Min == 0 with logarithm
}
float ToRelative(int AbsoluteValue, int Min, int Max) const override
{
if(Min < m_MinAdjustment)
{
AbsoluteValue += m_MinAdjustment;
Min += m_MinAdjustment;
Max += m_MinAdjustment;
}
return (log(AbsoluteValue) - log(Min)) / (float)(log(Max) - log(Min));
}
int ToAbsolute(float RelativeValue, int Min, int Max) const override
{
int ResultAdjustment = 0;
if(Min < m_MinAdjustment)
{
Min += m_MinAdjustment;
Max += m_MinAdjustment;
ResultAdjustment = -m_MinAdjustment;
}
return round_to_int(exp(RelativeValue * (log(Max) - log(Min)) + log(Min))) + ResultAdjustment;
}
};
struct SUIExEditBoxProperties
{
bool m_SelectText = false;
const char *m_pEmptyText = "";
};
class CUI;
class CUIElement
@ -120,27 +180,47 @@ class CUI
float m_MouseWorldX, m_MouseWorldY; // in world space
unsigned m_MouseButtons;
unsigned m_LastMouseButtons;
bool m_MouseSlow = false;
IInput::CEvent *m_pInputEventsArray;
int *m_pInputEventCount;
bool m_MouseIsPress = false;
bool m_HasSelection = false;
int m_MousePressX = 0;
int m_MousePressY = 0;
int m_MouseCurX = 0;
int m_MouseCurY = 0;
int m_CurSelStart = 0;
int m_CurSelEnd = 0;
const void *m_pSelItem = nullptr;
int m_CurCursor = 0;
CUIRect m_Screen;
std::vector<CUIRect> m_vClips;
void UpdateClipping();
class IInput *m_pInput;
class IGraphics *m_pGraphics;
class ITextRender *m_pTextRender;
IGraphics *m_pGraphics;
IInput *m_pInput;
ITextRender *m_pTextRender;
std::vector<CUIElement *> m_vpOwnUIElements; // ui elements maintained by CUI class
std::vector<CUIElement *> m_vpUIElements;
public:
static const CLinearScrollbarScale ms_LinearScrollbarScale;
static const CLogarithmicScrollbarScale ms_LogarithmicScrollbarScale;
static float ms_FontmodHeight;
// TODO: Refactor: Fill this in
void Init(class IInput *pInput, class IGraphics *pGraphics, class ITextRender *pTextRender);
class IInput *Input() const { return m_pInput; }
class IGraphics *Graphics() const { return m_pGraphics; }
class ITextRender *TextRender() const { return m_pTextRender; }
void Init(IKernel *pKernel);
void InitInputs(IInput::CEvent *pInputEventsArray, int *pInputEventCount);
IGraphics *Graphics() const { return m_pGraphics; }
IInput *Input() const { return m_pInput; }
ITextRender *TextRender() const { return m_pTextRender; }
CUI();
~CUI();
@ -208,6 +288,7 @@ public:
bool MouseInsideClip() const { return !IsClipped() || MouseInside(ClipArea()); }
bool MouseHovered(const CUIRect *pRect) const { return MouseInside(pRect) && MouseInsideClip(); }
void ConvertMouseMove(float *pX, float *pY, IInput::ECursorType CursorType) const;
void ResetMouseSlow() { m_MouseSlow = false; }
float ButtonColorMulActive() { return 0.5f; }
float ButtonColorMulHot() { return 1.5f; }
@ -232,6 +313,19 @@ public:
void DoLabel(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps, int StrLen = -1, class CTextCursor *pReadCursor = nullptr);
void DoLabelStreamed(CUIElement::SUIElementRect &RectEl, float x, float y, float w, float h, const char *pText, float Size, int Align, float MaxWidth = -1, int AlignVertically = 1, bool StopAtEnd = false, int StrLen = -1, class CTextCursor *pReadCursor = nullptr);
void DoLabelStreamed(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 = nullptr);
bool DoEditBox(const void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden = false, int Corners = IGraphics::CORNER_ALL, const SUIExEditBoxProperties &Properties = {});
bool DoClearableEditBox(const void *pID, const void *pClearID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden = false, int Corners = IGraphics::CORNER_ALL, const SUIExEditBoxProperties &Properties = {});
enum
{
SCROLLBAR_OPTION_INFINITE = 1,
SCROLLBAR_OPTION_NOCLAMPVALUE = 2,
};
float DoScrollbarV(const void *pID, const CUIRect *pRect, float Current);
float DoScrollbarH(const void *pID, const CUIRect *pRect, float Current, const ColorRGBA *pColorInner = nullptr);
void DoScrollbarOption(const void *pID, int *pOption, const CUIRect *pRect, const char *pStr, int Min, int Max, const IScrollbarScale *pScale = &ms_LinearScrollbarScale, unsigned Flags = 0u);
void DoScrollbarOptionLabeled(const void *pID, int *pOption, const CUIRect *pRect, const char *pStr, const char **ppLabels, int NumLabels, const IScrollbarScale *pScale = &ms_LinearScrollbarScale);
};
#endif

View file

@ -1,724 +0,0 @@
#include "ui_ex.h"
#include <base/system.h>
#include <base/math.h>
#include <engine/textrender.h>
#include <engine/keys.h>
#include <game/client/lineinput.h>
#include <game/client/render.h>
#include <limits>
const CLinearScrollbarScale CUIEx::ms_LinearScrollbarScale;
const CLogarithmicScrollbarScale CUIEx::ms_LogarithmicScrollbarScale(25);
CUIEx::CUIEx()
{
m_MouseSlow = false;
}
void CUIEx::Init(CUI *pUI, IKernel *pKernel, CRenderTools *pRenderTools, IInput::CEvent *pInputEventsArray, int *pInputEventCount)
{
m_pUI = pUI;
m_pKernel = pKernel;
m_pRenderTools = pRenderTools;
m_pInputEventsArray = pInputEventsArray;
m_pInputEventCount = pInputEventCount;
m_pInput = Kernel()->RequestInterface<IInput>();
m_pGraphics = Kernel()->RequestInterface<IGraphics>();
m_pTextRender = Kernel()->RequestInterface<ITextRender>();
}
void CUIEx::ConvertMouseMove(float *pX, float *pY, IInput::ECursorType CursorType) const
{
UI()->ConvertMouseMove(pX, pY, CursorType);
if(m_MouseSlow)
{
const float SlowMouseFactor = 0.05f;
*pX *= SlowMouseFactor;
*pY *= SlowMouseFactor;
}
}
float CUIEx::DoScrollbarV(const void *pID, const CUIRect *pRect, float Current)
{
Current = clamp(Current, 0.0f, 1.0f);
// layout
CUIRect Rail;
pRect->Margin(5.0f, &Rail);
CUIRect Handle;
Rail.HSplitTop(clamp(33.0f, Rail.w, Rail.h / 3.0f), &Handle, 0);
Handle.y = Rail.y + (Rail.h - Handle.h) * Current;
// logic
static float s_OffsetY;
const bool InsideRail = UI()->MouseHovered(&Rail);
const bool InsideHandle = UI()->MouseHovered(&Handle);
bool Grabbed = false; // whether to apply the offset
if(UI()->CheckActiveItem(pID))
{
if(UI()->MouseButton(0))
{
Grabbed = true;
if(Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT))
m_MouseSlow = true;
}
else
{
UI()->SetActiveItem(nullptr);
}
}
else if(UI()->HotItem() == pID)
{
if(UI()->MouseButton(0))
{
UI()->SetActiveItem(pID);
s_OffsetY = UI()->MouseY() - Handle.y;
Grabbed = true;
}
}
else if(UI()->MouseButtonClicked(0) && !InsideHandle && InsideRail)
{
UI()->SetActiveItem(pID);
s_OffsetY = Handle.h / 2.0f;
Grabbed = true;
}
if(InsideHandle)
{
UI()->SetHotItem(pID);
}
float ReturnValue = Current;
if(Grabbed)
{
const float Min = Rail.y;
const float Max = Rail.h - Handle.h;
const float Cur = UI()->MouseY() - s_OffsetY;
ReturnValue = clamp((Cur - Min) / Max, 0.0f, 1.0f);
}
// render
Rail.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, Rail.w / 2.0f);
float ColorSlider;
if(UI()->CheckActiveItem(pID))
ColorSlider = 0.9f;
else if(UI()->HotItem() == pID)
ColorSlider = 1.0f;
else
ColorSlider = 0.8f;
Handle.Draw(ColorRGBA(ColorSlider, ColorSlider, ColorSlider, 1.0f), IGraphics::CORNER_ALL, Handle.w / 2.0f);
return ReturnValue;
}
float CUIEx::DoScrollbarH(const void *pID, const CUIRect *pRect, float Current, const ColorRGBA *pColorInner)
{
Current = clamp(Current, 0.0f, 1.0f);
// layout
CUIRect Rail;
if(pColorInner)
Rail = *pRect;
else
pRect->HMargin(5.0f, &Rail);
CUIRect Handle;
Rail.VSplitLeft(pColorInner ? 8.0f : clamp(33.0f, Rail.h, Rail.w / 3.0f), &Handle, 0);
Handle.x += (Rail.w - Handle.w) * Current;
// logic
static float s_OffsetX;
const bool InsideRail = UI()->MouseHovered(&Rail);
const bool InsideHandle = UI()->MouseHovered(&Handle);
bool Grabbed = false; // whether to apply the offset
if(UI()->CheckActiveItem(pID))
{
if(UI()->MouseButton(0))
{
Grabbed = true;
if(Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT))
m_MouseSlow = true;
}
else
{
UI()->SetActiveItem(nullptr);
}
}
else if(UI()->HotItem() == pID)
{
if(UI()->MouseButton(0))
{
UI()->SetActiveItem(pID);
s_OffsetX = UI()->MouseX() - Handle.x;
Grabbed = true;
}
}
else if(UI()->MouseButtonClicked(0) && !InsideHandle && InsideRail)
{
UI()->SetActiveItem(pID);
s_OffsetX = Handle.w / 2.0f;
Grabbed = true;
}
if(InsideHandle)
{
UI()->SetHotItem(pID);
}
float ReturnValue = Current;
if(Grabbed)
{
const float Min = Rail.x;
const float Max = Rail.w - Handle.w;
const float Cur = UI()->MouseX() - s_OffsetX;
ReturnValue = clamp((Cur - Min) / Max, 0.0f, 1.0f);
}
// render
if(pColorInner)
{
CUIRect Slider;
Handle.VMargin(-2.0f, &Slider);
Slider.HMargin(-3.0f, &Slider);
Slider.Draw(ColorRGBA(0.15f, 0.15f, 0.15f, 1.0f), IGraphics::CORNER_ALL, 5.0f);
Slider.Margin(2.0f, &Slider);
Slider.Draw(*pColorInner, IGraphics::CORNER_ALL, 3.0f);
}
else
{
Rail.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, Rail.h / 2.0f);
float ColorSlider;
if(UI()->CheckActiveItem(pID))
ColorSlider = 0.9f;
else if(UI()->HotItem() == pID)
ColorSlider = 1.0f;
else
ColorSlider = 0.8f;
Handle.Draw(ColorRGBA(ColorSlider, ColorSlider, ColorSlider, 1.0f), IGraphics::CORNER_ALL, Handle.h / 2.0f);
}
return ReturnValue;
}
void CUIEx::DoScrollbarOption(const void *pID, int *pOption, const CUIRect *pRect, const char *pStr, int Min, int Max, const IScrollbarScale *pScale, unsigned Flags)
{
const bool Infinite = Flags & CUIEx::SCROLLBAR_OPTION_INFINITE;
const bool NoClampValue = Flags & CUIEx::SCROLLBAR_OPTION_NOCLAMPVALUE;
dbg_assert(!(Infinite && NoClampValue), "cannot combine SCROLLBAR_OPTION_INFINITE and SCROLLBAR_OPTION_NOCLAMPVALUE");
int Value = *pOption;
if(Infinite)
{
Min += 1;
Max += 1;
if(Value == 0)
Value = Max;
}
char aBufMax[256];
str_format(aBufMax, sizeof(aBufMax), "%s: %i", pStr, Max);
char aBuf[256];
if(!Infinite || Value != Max)
str_format(aBuf, sizeof(aBuf), "%s: %i", pStr, Value);
else
str_format(aBuf, sizeof(aBuf), "%s: ∞", pStr);
if(NoClampValue)
{
// clamp the value internally for the scrollbar
Value = clamp(Value, Min, Max);
}
float FontSize = pRect->h * CUI::ms_FontmodHeight * 0.8f;
float VSplitVal = 10.0f + maximum(TextRender()->TextWidth(0, FontSize, aBuf, -1, std::numeric_limits<float>::max()), TextRender()->TextWidth(0, FontSize, aBufMax, -1, std::numeric_limits<float>::max()));
CUIRect Label, ScrollBar;
pRect->VSplitLeft(VSplitVal, &Label, &ScrollBar);
UI()->DoLabel(&Label, aBuf, FontSize, TEXTALIGN_LEFT);
Value = pScale->ToAbsolute(DoScrollbarH(pID, &ScrollBar, pScale->ToRelative(Value, Min, Max)), Min, Max);
if(Infinite)
{
if(Value == Max)
Value = 0;
}
else if(NoClampValue)
{
if((Value == Min && *pOption < Min) || (Value == Max && *pOption > Max))
Value = *pOption; // use previous out of range value instead if the scrollbar is at the edge
}
*pOption = Value;
}
void CUIEx::DoScrollbarOptionLabeled(const void *pID, int *pOption, const CUIRect *pRect, const char *pStr, const char **ppLabels, int NumLabels, const IScrollbarScale *pScale)
{
const int Max = NumLabels - 1;
int Value = clamp(*pOption, 0, Max);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "%s: %s", pStr, ppLabels[Value]);
float FontSize = pRect->h * CUI::ms_FontmodHeight * 0.8f;
CUIRect Label, ScrollBar;
pRect->VSplitRight(60.0f, &Label, &ScrollBar);
Label.VSplitRight(10.0f, &Label, 0);
UI()->DoLabel(&Label, aBuf, FontSize, TEXTALIGN_LEFT);
Value = pScale->ToAbsolute(DoScrollbarH(pID, &ScrollBar, pScale->ToRelative(Value, 0, Max)), 0, Max);
if(UI()->HotItem() != pID && !UI()->CheckActiveItem(pID) && UI()->MouseHovered(pRect) && UI()->MouseButtonClicked(0))
Value = (Value + 1) % NumLabels;
*pOption = clamp(Value, 0, Max);
}
bool CUIEx::DoEditBox(const void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden, int Corners, const SUIExEditBoxProperties &Properties)
{
const bool Inside = UI()->MouseHovered(pRect);
bool ReturnValue = false;
bool UpdateOffset = false;
auto &&SetHasSelection = [&](bool HasSelection) {
m_HasSelection = HasSelection;
m_pSelItem = m_HasSelection ? pID : nullptr;
};
auto &&SelectAllText = [&]() {
m_CurSelStart = 0;
int StrLen = str_length(pStr);
TextRender()->UTF8OffToDecodedOff(pStr, StrLen, m_CurSelEnd);
SetHasSelection(true);
m_CurCursor = StrLen;
};
if(UI()->LastActiveItem() == pID)
{
if(m_HasSelection && m_pSelItem != pID)
{
SetHasSelection(false);
}
m_CurCursor = minimum(str_length(pStr), m_CurCursor);
const bool Enabled = UI()->Enabled();
bool IsShiftPressed = Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT);
bool IsModPressed = Input()->ModifierIsPressed();
if(Enabled && !IsShiftPressed && IsModPressed && Input()->KeyPress(KEY_V))
{
const char *pText = Input()->GetClipboardText();
if(pText)
{
int OffsetL = clamp(m_CurCursor, 0, str_length(pStr));
int OffsetR = OffsetL;
if(m_HasSelection)
{
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;
SetHasSelection(false);
}
}
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(Enabled && !IsShiftPressed && IsModPressed && (Input()->KeyPress(KEY_C) || Input()->KeyPress(KEY_X)))
{
if(m_HasSelection)
{
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))
{
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);
SetHasSelection(false);
if(m_CurCursor > UTF8SelLeft)
m_CurCursor = maximum(0, m_CurCursor - (UTF8SelRight - UTF8SelLeft));
else
m_CurCursor = UTF8SelLeft;
}
}
}
else
Input()->SetClipboardText(pStr);
}
if(Properties.m_SelectText || (Enabled && !IsShiftPressed && IsModPressed && Input()->KeyPress(KEY_A)))
{
SelectAllText();
}
if(Enabled && !IsShiftPressed && IsModPressed && Input()->KeyPress(KEY_U))
{
pStr[0] = '\0';
m_CurCursor = 0;
SetHasSelection(false);
ReturnValue = true;
}
for(int i = 0; i < *m_pInputEventCount; i++)
{
int LastCursor = m_CurCursor;
int Len, NumChars;
str_utf8_stats(pStr, StrSize, StrSize, &Len, &NumChars);
int32_t ManipulateChanges = CLineInput::Manipulate(m_pInputEventsArray[i], pStr, StrSize, StrSize, &Len, &m_CurCursor, &NumChars, m_HasSelection ? CLineInput::LINE_INPUT_MODIFY_DONT_DELETE : 0, IsModPressed ? KEY_LCTRL : 0);
ReturnValue |= (ManipulateChanges & (CLineInput::LINE_INPUT_CHANGE_STRING | CLineInput::LINE_INPUT_CHANGE_CHARACTERS_DELETE)) != 0;
// 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;
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;
SetHasSelection(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)
SetHasSelection(false);
else
SetHasSelection(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);
}
}
SetHasSelection(false);
}
}
}
}
if(Inside)
{
UI()->SetHotItem(pID);
}
CUIRect Textbox = *pRect;
Textbox.Draw(ColorRGBA(1, 1, 1, 0.5f), Corners, 3.0f);
Textbox.Margin(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 = m_CurCursor;
if(UI()->LastActiveItem() == pID && Input()->GetIMEEditingTextLength() > -1)
{
int EditingTextCursor = Input()->GetEditingCursor();
str_copy(aDispEditingText, pDisplayStr);
char aEditingText[IInput::INPUT_TEXT_SIZE + 2];
if(Hidden)
{
// Do not show editing text in password field
str_copy(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 >= m_CurCursor; i--)
aDispEditingText[i + FillCharLen] = aDispEditingText[i];
for(int i = 0; i < FillCharLen; i++)
aDispEditingText[m_CurCursor + i] = aEditingText[i];
DispCursorPos = m_CurCursor + EditingTextCursor + 1;
pDisplayStr = aDispEditingText;
UpdateOffset = true;
}
bool IsEmptyText = false;
if(pDisplayStr[0] == '\0')
{
pDisplayStr = Properties.m_pEmptyText;
IsEmptyText = true;
TextRender()->TextColor(1, 1, 1, 0.75f);
}
DispCursorPos = minimum(DispCursorPos, str_length(pDisplayStr));
bool JustGotActive = false;
if(UI()->CheckActiveItem(pID))
{
if(!UI()->MouseButton(0))
{
UI()->SetActiveItem(nullptr);
}
}
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))
{
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, DispCursorPos, std::numeric_limits<float>::max());
if(w - *pOffset > Textbox.w)
{
// move to the left
float wt = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1, std::numeric_limits<float>::max());
do
{
*pOffset += minimum(wt - *pOffset - Textbox.w, Textbox.w / 3);
} while(w - *pOffset > Textbox.w + 0.0001f);
}
else if(w - *pOffset < 0.0f)
{
// move to the right
do
{
*pOffset = maximum(0.0f, *pOffset - Textbox.w / 3);
} while(w - *pOffset < -0.0001f);
}
}
UI()->ClipEnable(pRect);
Textbox.x -= *pOffset;
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 && !IsEmptyText;
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;
}
SLabelProperties Props;
Props.m_pSelCursor = &SelCursor;
Props.m_EnableWidthCheck = IsEmptyText;
UI()->DoLabel(&Textbox, pDisplayStr, FontSize, TEXTALIGN_LEFT, Props);
if(UI()->LastActiveItem() == pID)
{
if(SelCursor.m_CalculateSelectionMode == TEXT_CURSOR_SELECTION_MODE_CALCULATE)
{
m_CurSelStart = SelCursor.m_SelectionStart;
m_CurSelEnd = SelCursor.m_SelectionEnd;
SetHasSelection(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);
// 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;
Input()->SetEditingPosition(Textbox.x, Textbox.y + FontSize);
}
UI()->ClipDisable();
return ReturnValue;
}
bool CUIEx::DoClearableEditBox(const void *pID, const void *pClearID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden, int Corners, const SUIExEditBoxProperties &Properties)
{
CUIRect EditBox;
CUIRect ClearButton;
pRect->VSplitRight(15.0f, &EditBox, &ClearButton);
bool ReturnValue = DoEditBox(pID, &EditBox, pStr, StrSize, FontSize, pOffset, Hidden, Corners & ~IGraphics::CORNER_R, Properties);
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT);
ClearButton.Draw(ColorRGBA(1, 1, 1, 0.33f * UI()->ButtonColorMul(pClearID)), Corners & ~IGraphics::CORNER_L, 3.0f);
SLabelProperties Props;
Props.m_AlignVertically = 0;
UI()->DoLabel(&ClearButton, "×", ClearButton.h * CUI::ms_FontmodHeight, TEXTALIGN_CENTER, Props);
TextRender()->SetRenderFlags(0);
if(UI()->DoButtonLogic(pClearID, 0, &ClearButton))
{
pStr[0] = 0;
UI()->SetActiveItem(pID);
ReturnValue = true;
}
return ReturnValue;
}

View file

@ -1,128 +0,0 @@
#ifndef GAME_CLIENT_UI_EX_H
#define GAME_CLIENT_UI_EX_H
#include <engine/input.h>
#include <game/client/ui.h>
class CRenderTools;
class IGraphics;
class IKernel;
class ITextRender;
class IScrollbarScale
{
public:
virtual float ToRelative(int AbsoluteValue, int Min, int Max) const = 0;
virtual int ToAbsolute(float RelativeValue, int Min, int Max) const = 0;
};
class CLinearScrollbarScale : public IScrollbarScale
{
public:
float ToRelative(int AbsoluteValue, int Min, int Max) const override
{
return (AbsoluteValue - Min) / (float)(Max - Min);
}
int ToAbsolute(float RelativeValue, int Min, int Max) const override
{
return round_to_int(RelativeValue * (Max - Min) + Min + 0.1f);
}
};
class CLogarithmicScrollbarScale : public IScrollbarScale
{
private:
int m_MinAdjustment;
public:
CLogarithmicScrollbarScale(int MinAdjustment)
{
m_MinAdjustment = maximum(MinAdjustment, 1); // must be at least 1 to support Min == 0 with logarithm
}
float ToRelative(int AbsoluteValue, int Min, int Max) const override
{
if(Min < m_MinAdjustment)
{
AbsoluteValue += m_MinAdjustment;
Min += m_MinAdjustment;
Max += m_MinAdjustment;
}
return (log(AbsoluteValue) - log(Min)) / (float)(log(Max) - log(Min));
}
int ToAbsolute(float RelativeValue, int Min, int Max) const override
{
int ResultAdjustment = 0;
if(Min < m_MinAdjustment)
{
Min += m_MinAdjustment;
Max += m_MinAdjustment;
ResultAdjustment = -m_MinAdjustment;
}
return round_to_int(exp(RelativeValue * (log(Max) - log(Min)) + log(Min))) + ResultAdjustment;
}
};
struct SUIExEditBoxProperties
{
bool m_SelectText = false;
const char *m_pEmptyText = "";
};
class CUIEx
{
CUI *m_pUI;
IInput *m_pInput;
ITextRender *m_pTextRender;
IKernel *m_pKernel;
IGraphics *m_pGraphics;
CRenderTools *m_pRenderTools;
IInput::CEvent *m_pInputEventsArray;
int *m_pInputEventCount;
bool m_MouseIsPress = false;
bool m_HasSelection = false;
int m_MousePressX = 0;
int m_MousePressY = 0;
int m_MouseCurX = 0;
int m_MouseCurY = 0;
bool m_MouseSlow;
int m_CurSelStart = 0;
int m_CurSelEnd = 0;
const void *m_pSelItem = nullptr;
int m_CurCursor = 0;
protected:
CUI *UI() const { return m_pUI; }
IInput *Input() const { return m_pInput; }
ITextRender *TextRender() const { return m_pTextRender; }
IKernel *Kernel() const { return m_pKernel; }
IGraphics *Graphics() const { return m_pGraphics; }
CRenderTools *RenderTools() const { return m_pRenderTools; }
public:
static const CLinearScrollbarScale ms_LinearScrollbarScale;
static const CLogarithmicScrollbarScale ms_LogarithmicScrollbarScale;
CUIEx();
void Init(CUI *pUI, IKernel *pKernel, CRenderTools *pRenderTools, IInput::CEvent *pInputEventsArray, int *pInputEventCount);
void ConvertMouseMove(float *pX, float *pY, IInput::ECursorType CursorType) const;
void ResetMouseSlow() { m_MouseSlow = false; }
enum
{
SCROLLBAR_OPTION_INFINITE = 1,
SCROLLBAR_OPTION_NOCLAMPVALUE = 2,
};
float DoScrollbarV(const void *pID, const CUIRect *pRect, float Current);
float DoScrollbarH(const void *pID, const CUIRect *pRect, float Current, const ColorRGBA *pColorInner = nullptr);
void DoScrollbarOption(const void *pID, int *pOption, const CUIRect *pRect, const char *pStr, int Min, int Max, const IScrollbarScale *pScale = &ms_LinearScrollbarScale, unsigned Flags = 0u);
void DoScrollbarOptionLabeled(const void *pID, int *pOption, const CUIRect *pRect, const char *pStr, const char **ppLabels, int NumLabels, const IScrollbarScale *pScale = &ms_LinearScrollbarScale);
bool DoEditBox(const void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden = false, int Corners = IGraphics::CORNER_ALL, const SUIExEditBoxProperties &Properties = {});
bool DoClearableEditBox(const void *pID, const void *pClearID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden = false, int Corners = IGraphics::CORNER_ALL, const SUIExEditBoxProperties &Properties = {});
};
#endif

View file

@ -294,14 +294,14 @@ bool CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned St
{
if(UI()->LastActiveItem() == pID)
m_EditBoxActive = 2;
return UIEx()->DoEditBox(pID, pRect, pStr, StrSize, FontSize, pOffset, Hidden, Corners);
return UI()->DoEditBox(pID, pRect, pStr, StrSize, FontSize, pOffset, Hidden, Corners);
}
bool CEditor::DoClearableEditBox(void *pID, void *pClearID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *pOffset, bool Hidden, int Corners)
{
if(UI()->LastActiveItem() == pID)
m_EditBoxActive = 2;
return UIEx()->DoClearableEditBox(pID, pClearID, pRect, pStr, StrSize, FontSize, pOffset, Hidden, Corners);
return UI()->DoClearableEditBox(pID, pClearID, pRect, pStr, StrSize, FontSize, pOffset, Hidden, Corners);
}
ColorRGBA CEditor::GetButtonColor(const void *pID, int Checked)
@ -3281,7 +3281,7 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect View)
{
CUIRect Scroll;
LayersBox.VSplitRight(20.0f, &LayersBox, &Scroll);
s_ScrollValue = UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&LayersBox))
{
@ -3968,7 +3968,7 @@ void CEditor::RenderImages(CUIRect ToolBox, CUIRect View)
{
CUIRect Scroll;
ToolBox.VSplitRight(20.0f, &ToolBox, &Scroll);
s_ScrollValue = UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&ToolBox))
{
@ -4182,7 +4182,7 @@ void CEditor::RenderSounds(CUIRect ToolBox, CUIRect View)
{
CUIRect Scroll;
ToolBox.VSplitRight(20.0f, &ToolBox, &Scroll);
s_ScrollValue = UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&ToolBox))
{
@ -4434,7 +4434,7 @@ void CEditor::RenderFileDialog()
m_FileDialogOpening = false;
int Num = (int)(View.h / 17.0f) + 1;
m_FileDialogScrollValue = UIEx()->DoScrollbarV(&m_FileDialogScrollValue, &Scroll, m_FileDialogScrollValue);
m_FileDialogScrollValue = UI()->DoScrollbarV(&m_FileDialogScrollValue, &Scroll, m_FileDialogScrollValue);
int ScrollNum = 0;
for(size_t i = 0; i < m_vFileList.size(); i++)
@ -5501,7 +5501,7 @@ void CEditor::RenderServerSettingsEditor(CUIRect View, bool ShowServerSettingsEd
{
CUIRect Scroll;
ListBox.VSplitRight(20.0f, &ListBox, &Scroll);
s_ScrollValue = UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&ListBox))
{
@ -6317,12 +6317,10 @@ void CEditor::Init()
m_pTextRender = Kernel()->RequestInterface<ITextRender>();
m_pStorage = Kernel()->RequestInterface<IStorage>();
m_pSound = Kernel()->RequestInterface<ISound>();
m_UI.Init(m_pInput, m_pGraphics, m_pTextRender);
m_UI.Init(Kernel());
m_RenderTools.Init(m_pGraphics, m_pTextRender);
m_Map.m_pEditor = this;
UIEx()->Init(UI(), Kernel(), RenderTools(), Input()->GetEventsRaw(), Input()->GetEventCountRaw());
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);
@ -6376,8 +6374,8 @@ void CEditor::OnUpdate()
float MouseRelX = 0.0f, MouseRelY = 0.0f;
IInput::ECursorType CursorType = Input()->CursorRelative(&MouseRelX, &MouseRelY);
if(CursorType != IInput::CURSOR_NONE)
UIEx()->ConvertMouseMove(&MouseRelX, &MouseRelY, CursorType);
UIEx()->ResetMouseSlow();
UI()->ConvertMouseMove(&MouseRelX, &MouseRelY, CursorType);
UI()->ResetMouseSlow();
m_MouseDeltaX += MouseRelX;
m_MouseDeltaY += MouseRelY;

View file

@ -10,7 +10,6 @@
#include <game/client/render.h>
#include <game/client/ui.h>
#include <game/client/ui_ex.h>
#include <game/mapitems.h>
#include <engine/editor.h>
@ -685,7 +684,6 @@ class CEditor : public IEditor
class IStorage *m_pStorage;
CRenderTools m_RenderTools;
CUI m_UI;
CUIEx m_UIEx;
bool m_EditorWasUsedBefore = false;
@ -709,7 +707,6 @@ public:
class ITextRender *TextRender() { return m_pTextRender; }
class IStorage *Storage() { return m_pStorage; }
CUI *UI() { return &m_UI; }
CUIEx *UIEx() { return &m_UIEx; }
CRenderTools *RenderTools() { return &m_RenderTools; }
CEditor() :

View file

@ -1232,7 +1232,7 @@ int CEditor::PopupSelectImage(CEditor *pEditor, CUIRect View, void *pContext)
{
CUIRect Scroll;
ButtonBar.VSplitRight(20.0f, &ButtonBar, &Scroll);
s_ScrollValue = pEditor->UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = pEditor->UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(pEditor->UI()->MouseInside(&Scroll) || pEditor->UI()->MouseInside(&ButtonBar))
{
@ -1340,7 +1340,7 @@ int CEditor::PopupSelectSound(CEditor *pEditor, CUIRect View, void *pContext)
{
CUIRect Scroll;
ButtonBar.VSplitRight(20.0f, &ButtonBar, &Scroll);
s_ScrollValue = pEditor->UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = pEditor->UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(pEditor->UI()->MouseInside(&Scroll) || pEditor->UI()->MouseInside(&ButtonBar))
{
@ -1483,7 +1483,7 @@ int CEditor::PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View, void *pCon
{
CUIRect Scroll;
View.VSplitRight(20.0f, &View, &Scroll);
s_ScrollValue = pEditor->UIEx()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
s_ScrollValue = pEditor->UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(pEditor->UI()->MouseInside(&View) || pEditor->UI()->MouseInside(&Scroll))
{