mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-12 19:18:20 +00:00
Refactor tooltips to render last, add some tooltips
This commit is contained in:
parent
d4dcaa2471
commit
faab2ded74
|
@ -1958,6 +1958,8 @@ if(CLIENT)
|
||||||
components/spectator.h
|
components/spectator.h
|
||||||
components/statboard.cpp
|
components/statboard.cpp
|
||||||
components/statboard.h
|
components/statboard.h
|
||||||
|
components/tooltips.cpp
|
||||||
|
components/tooltips.h
|
||||||
components/voting.cpp
|
components/voting.cpp
|
||||||
components/voting.h
|
components/voting.h
|
||||||
gameclient.cpp
|
gameclient.cpp
|
||||||
|
|
|
@ -2832,64 +2832,4 @@ bool CMenus::HandleListInputs(const CUIRect &View, float &ScrollValue, const flo
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewIndex != -1;
|
return NewIndex != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMenus::DoToolTip(const void *pID, const CUIRect *pNearRect, const char *pText, float WidthHint)
|
|
||||||
{
|
|
||||||
static int64_t HoverTime = -1;
|
|
||||||
|
|
||||||
if(!UI()->MouseInside(pNearRect))
|
|
||||||
{
|
|
||||||
if(pID == UI()->ActiveTooltipItem())
|
|
||||||
HoverTime = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UI()->SetActiveTooltipItem(pID);
|
|
||||||
|
|
||||||
if(HoverTime == -1)
|
|
||||||
HoverTime = time_get();
|
|
||||||
|
|
||||||
// Delay tooltip until 1 second passed.
|
|
||||||
if(HoverTime > time_get() - time_freq())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const float MARGIN = 5.0f;
|
|
||||||
|
|
||||||
CUIRect Rect;
|
|
||||||
Rect.w = WidthHint;
|
|
||||||
if(WidthHint < 0.0f)
|
|
||||||
Rect.w = TextRender()->TextWidth(0, 14.0f, pText, -1, -1.0f) + 4.0f;
|
|
||||||
Rect.h = 30.0f;
|
|
||||||
|
|
||||||
CUIRect *pScreen = UI()->Screen();
|
|
||||||
|
|
||||||
// Try the top side.
|
|
||||||
if(pNearRect->y - Rect.h - MARGIN > pScreen->y)
|
|
||||||
{
|
|
||||||
Rect.x = clamp(UI()->MouseX() - Rect.w / 2.0f, MARGIN, pScreen->w - Rect.w - MARGIN);
|
|
||||||
Rect.y = pNearRect->y - Rect.h - MARGIN;
|
|
||||||
}
|
|
||||||
// Try the bottom side.
|
|
||||||
else if(pNearRect->y + pNearRect->h + MARGIN < pScreen->h)
|
|
||||||
{
|
|
||||||
Rect.x = clamp(UI()->MouseX() - Rect.w / 2.0f, MARGIN, pScreen->w - Rect.w - MARGIN);
|
|
||||||
Rect.y = pNearRect->y + pNearRect->h + MARGIN;
|
|
||||||
}
|
|
||||||
// Try the right side.
|
|
||||||
else if(pNearRect->x + pNearRect->w + MARGIN + Rect.w < pScreen->w)
|
|
||||||
{
|
|
||||||
Rect.x = pNearRect->x + pNearRect->w + MARGIN;
|
|
||||||
Rect.y = clamp(UI()->MouseY() - Rect.h / 2.0f, MARGIN, pScreen->h - Rect.h - MARGIN);
|
|
||||||
}
|
|
||||||
// Try the left side.
|
|
||||||
else if(pNearRect->x - Rect.w - MARGIN > pScreen->x)
|
|
||||||
{
|
|
||||||
Rect.x = pNearRect->x - Rect.w - MARGIN;
|
|
||||||
Rect.y = clamp(UI()->MouseY() - Rect.h / 2.0f, MARGIN, pScreen->h - Rect.h - MARGIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderTools()->DrawUIRect(&Rect, ColorRGBA(0.2, 0.2, 0.2, 0.80f), CUI::CORNER_ALL, 5.0f);
|
|
||||||
Rect.Margin(2.0f, &Rect);
|
|
||||||
UI()->DoLabel(&Rect, pText, 14.0f, TEXTALIGN_LEFT);
|
|
||||||
}
|
|
|
@ -530,7 +530,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
{
|
{
|
||||||
m_Dummy ^= 1;
|
m_Dummy ^= 1;
|
||||||
}
|
}
|
||||||
DoToolTip(&m_Dummy, &DummyLabel, Localize("Toggle to edit your dummy settings."));
|
GameClient()->m_Tooltips.DoToolTip(&m_Dummy, &DummyLabel, Localize("Toggle to edit your dummy settings."));
|
||||||
|
|
||||||
Dummy.HSplitTop(20.0f, &DummyLabel, &Dummy);
|
Dummy.HSplitTop(20.0f, &DummyLabel, &Dummy);
|
||||||
|
|
||||||
|
@ -1265,7 +1265,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
||||||
MainView.HSplitTop(20.0f, &Button, &MainView);
|
MainView.HSplitTop(20.0f, &Button, &MainView);
|
||||||
if(DoButton_CheckBox(&g_Config.m_GfxHighDetail, Localize("High Detail"), g_Config.m_GfxHighDetail, &Button))
|
if(DoButton_CheckBox(&g_Config.m_GfxHighDetail, Localize("High Detail"), g_Config.m_GfxHighDetail, &Button))
|
||||||
g_Config.m_GfxHighDetail ^= 1;
|
g_Config.m_GfxHighDetail ^= 1;
|
||||||
DoToolTip(&g_Config.m_GfxHighDetail, &Button, Localize("Allows maps to render with more detail."));
|
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_GfxHighDetail, &Button, Localize("Allows maps to render with more detail."));
|
||||||
|
|
||||||
MainView.HSplitTop(20.0f, &Button, &MainView);
|
MainView.HSplitTop(20.0f, &Button, &MainView);
|
||||||
if(DoButton_CheckBox(&g_Config.m_GfxHighdpi, Localize("Use high DPI"), g_Config.m_GfxHighdpi, &Button))
|
if(DoButton_CheckBox(&g_Config.m_GfxHighdpi, Localize("Use high DPI"), g_Config.m_GfxHighdpi, &Button))
|
||||||
|
@ -2635,6 +2635,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
||||||
{
|
{
|
||||||
g_Config.m_ClRaceGhost ^= 1;
|
g_Config.m_ClRaceGhost ^= 1;
|
||||||
}
|
}
|
||||||
|
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_ClRaceGhost, &Button, Localize("When you cross the start line, show a ghost tee replicating the movements of your best time."));
|
||||||
|
|
||||||
if(g_Config.m_ClRaceGhost)
|
if(g_Config.m_ClRaceGhost)
|
||||||
{
|
{
|
||||||
|
@ -2686,13 +2687,15 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
||||||
Button.VSplitMid(&LeftLeft, &Button);
|
Button.VSplitMid(&LeftLeft, &Button);
|
||||||
|
|
||||||
Button.VSplitLeft(50.0f, &Label, &Button);
|
Button.VSplitLeft(50.0f, &Label, &Button);
|
||||||
UI()->DoLabelScaled(&Label, Localize("Alpha"), 14.0f, TEXTALIGN_LEFT);
|
UI()->DoLabelScaled(&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)(UIEx()->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))
|
if(DoButton_CheckBox(&g_Config.m_ClShowOthers, Localize("Show others"), g_Config.m_ClShowOthers == SHOW_OTHERS_ON, &LeftLeft))
|
||||||
{
|
{
|
||||||
g_Config.m_ClShowOthers = g_Config.m_ClShowOthers != SHOW_OTHERS_ON ? SHOW_OTHERS_ON : SHOW_OTHERS_OFF;
|
g_Config.m_ClShowOthers = g_Config.m_ClShowOthers != SHOW_OTHERS_ON ? SHOW_OTHERS_ON : SHOW_OTHERS_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_ClShowOthersAlpha, &Button, "Adjust the opacity of entities belonging to other teams, such as tees and nameplates");
|
||||||
}
|
}
|
||||||
|
|
||||||
Left.HSplitTop(20.0f, &Button, &Left);
|
Left.HSplitTop(20.0f, &Button, &Left);
|
||||||
|
@ -2707,6 +2710,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
||||||
{
|
{
|
||||||
g_Config.m_ClShowQuads ^= 1;
|
g_Config.m_ClShowQuads ^= 1;
|
||||||
}
|
}
|
||||||
|
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_ClShowQuads, &Button, Localize("Quads are used for background decoration"));
|
||||||
|
|
||||||
Right.HSplitTop(20.0f, &Label, &Right);
|
Right.HSplitTop(20.0f, &Label, &Right);
|
||||||
Label.VSplitLeft(130.0f, &Label, &Button);
|
Label.VSplitLeft(130.0f, &Label, &Button);
|
||||||
|
@ -2720,6 +2724,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
||||||
{
|
{
|
||||||
g_Config.m_ClAntiPing ^= 1;
|
g_Config.m_ClAntiPing ^= 1;
|
||||||
}
|
}
|
||||||
|
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_ClAntiPing, &Button, Localize("Tries to predict other entities to give a feel of low latency."));
|
||||||
|
|
||||||
if(g_Config.m_ClAntiPing)
|
if(g_Config.m_ClAntiPing)
|
||||||
{
|
{
|
||||||
|
|
117
src/game/client/components/tooltips.cpp
Normal file
117
src/game/client/components/tooltips.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#include "tooltips.h"
|
||||||
|
|
||||||
|
#include <game/client/render.h>
|
||||||
|
|
||||||
|
CTooltips::CTooltips()
|
||||||
|
{
|
||||||
|
OnReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTooltips::OnReset()
|
||||||
|
{
|
||||||
|
HoverTime = -1;
|
||||||
|
m_Tooltips.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTooltips::SetActiveTooltip(CTooltip &Tooltip)
|
||||||
|
{
|
||||||
|
if(m_ActiveTooltip.has_value())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_ActiveTooltip.emplace(Tooltip);
|
||||||
|
HoverTime = time_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CTooltips::ClearActiveTooltip()
|
||||||
|
{
|
||||||
|
m_ActiveTooltip.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTooltips::DoToolTip(const void *pID, const CUIRect *pNearRect, const char *pText, float WidthHint)
|
||||||
|
{
|
||||||
|
uintptr_t ID = reinterpret_cast<uintptr_t>(pID);
|
||||||
|
|
||||||
|
const auto &it = m_Tooltips.find(ID);
|
||||||
|
|
||||||
|
if(it == m_Tooltips.end())
|
||||||
|
{
|
||||||
|
CTooltip NewTooltip = {
|
||||||
|
.m_Rect = *pNearRect,
|
||||||
|
.m_pText = pText,
|
||||||
|
.m_WidthHint = WidthHint,
|
||||||
|
};
|
||||||
|
|
||||||
|
m_Tooltips[ID] = NewTooltip;
|
||||||
|
|
||||||
|
CTooltip &Tooltip = m_Tooltips[ID];
|
||||||
|
|
||||||
|
if(UI()->MouseInside(&Tooltip.m_Rect))
|
||||||
|
{
|
||||||
|
SetActiveTooltip(Tooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(UI()->MouseInside(&it->second.m_Rect))
|
||||||
|
{
|
||||||
|
SetActiveTooltip(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTooltips::OnRender()
|
||||||
|
{
|
||||||
|
if(m_ActiveTooltip.has_value())
|
||||||
|
{
|
||||||
|
CTooltip &Tooltip = m_ActiveTooltip.value();
|
||||||
|
|
||||||
|
if(!UI()->MouseInside(&Tooltip.m_Rect))
|
||||||
|
{
|
||||||
|
ClearActiveTooltip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay tooltip until 1 second passed.
|
||||||
|
if(HoverTime > time_get() - time_freq())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const float MARGIN = 5.0f;
|
||||||
|
|
||||||
|
CUIRect Rect;
|
||||||
|
Rect.w = Tooltip.m_WidthHint;
|
||||||
|
if(Tooltip.m_WidthHint < 0.0f)
|
||||||
|
Rect.w = TextRender()->TextWidth(0, 14.0f, Tooltip.m_pText, -1, -1.0f) + 4.0f;
|
||||||
|
Rect.h = 30.0f;
|
||||||
|
|
||||||
|
CUIRect *pScreen = UI()->Screen();
|
||||||
|
|
||||||
|
// Try the top side.
|
||||||
|
if(Tooltip.m_Rect.y - Rect.h - MARGIN > pScreen->y)
|
||||||
|
{
|
||||||
|
Rect.x = clamp(UI()->MouseX() - Rect.w / 2.0f, MARGIN, pScreen->w - Rect.w - MARGIN);
|
||||||
|
Rect.y = Tooltip.m_Rect.y - Rect.h - MARGIN;
|
||||||
|
}
|
||||||
|
// Try the bottom side.
|
||||||
|
else if(Tooltip.m_Rect.y + Tooltip.m_Rect.h + MARGIN < pScreen->h)
|
||||||
|
{
|
||||||
|
Rect.x = clamp(UI()->MouseX() - Rect.w / 2.0f, MARGIN, pScreen->w - Rect.w - MARGIN);
|
||||||
|
Rect.y = Tooltip.m_Rect.y + Tooltip.m_Rect.h + MARGIN;
|
||||||
|
}
|
||||||
|
// Try the right side.
|
||||||
|
else if(Tooltip.m_Rect.x + Tooltip.m_Rect.w + MARGIN + Rect.w < pScreen->w)
|
||||||
|
{
|
||||||
|
Rect.x = Tooltip.m_Rect.x + Tooltip.m_Rect.w + MARGIN;
|
||||||
|
Rect.y = clamp(UI()->MouseY() - Rect.h / 2.0f, MARGIN, pScreen->h - Rect.h - MARGIN);
|
||||||
|
}
|
||||||
|
// Try the left side.
|
||||||
|
else if(Tooltip.m_Rect.x - Rect.w - MARGIN > pScreen->x)
|
||||||
|
{
|
||||||
|
Rect.x = Tooltip.m_Rect.x - Rect.w - MARGIN;
|
||||||
|
Rect.y = clamp(UI()->MouseY() - Rect.h / 2.0f, MARGIN, pScreen->h - Rect.h - MARGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTools()->DrawUIRect(&Rect, ColorRGBA(0.2, 0.2, 0.2, 0.80f), CUI::CORNER_ALL, 5.0f);
|
||||||
|
Rect.Margin(2.0f, &Rect);
|
||||||
|
UI()->DoLabel(&Rect, Tooltip.m_pText, 14.0f, TEXTALIGN_LEFT);
|
||||||
|
}
|
||||||
|
}
|
59
src/game/client/components/tooltips.h
Normal file
59
src/game/client/components/tooltips.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef GAME_CLIENT_COMPONENTS_TOOLTIPS_H
|
||||||
|
#define GAME_CLIENT_COMPONENTS_TOOLTIPS_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <game/client/component.h>
|
||||||
|
#include <game/client/ui.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
struct CTooltip
|
||||||
|
{
|
||||||
|
CUIRect m_Rect;
|
||||||
|
const char *m_pText;
|
||||||
|
float m_WidthHint;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component that manages and renders UI tooltips.
|
||||||
|
*
|
||||||
|
* Should be among the last components to render.
|
||||||
|
*/
|
||||||
|
class CTooltips : public CComponent
|
||||||
|
{
|
||||||
|
std::unordered_map<uintptr_t, CTooltip> m_Tooltips;
|
||||||
|
std::optional<std::reference_wrapper<CTooltip>> m_ActiveTooltip;
|
||||||
|
int64_t HoverTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The passed tooltip is only actually set if there is no currently active tooltip.
|
||||||
|
*
|
||||||
|
* @param Tooltip A reference to the tooltip that should be active.
|
||||||
|
*/
|
||||||
|
void SetActiveTooltip(CTooltip &Tooltip);
|
||||||
|
|
||||||
|
inline void ClearActiveTooltip();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CTooltips();
|
||||||
|
virtual int Sizeof() const override { return sizeof(*this); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the tooltip to a cache and renders it when active.
|
||||||
|
*
|
||||||
|
* On the first call to this function, the data passed is cached, afterwards the calls are used to detect if the tooltip should be activated.
|
||||||
|
*
|
||||||
|
* For now only works correctly with single line tooltips, since Text width calculation gets broken when there are multiple lines.
|
||||||
|
*
|
||||||
|
* @param pID The ID of the tooltip. Usually a reference to some g_Config value.
|
||||||
|
* @param pNearTo Place the tooltip near this rect.
|
||||||
|
* @param pText The text to display in the tooltip
|
||||||
|
*/
|
||||||
|
void DoToolTip(const void *pID, const CUIRect *pNearRect, const char *pText, float WidthHint = -1.0f);
|
||||||
|
|
||||||
|
virtual void OnReset() override;
|
||||||
|
virtual void OnRender() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -137,6 +137,7 @@ void CGameClient::OnConsoleInit()
|
||||||
m_All.Add(&m_Statboard);
|
m_All.Add(&m_Statboard);
|
||||||
m_All.Add(&m_Motd);
|
m_All.Add(&m_Motd);
|
||||||
m_All.Add(&m_Menus);
|
m_All.Add(&m_Menus);
|
||||||
|
m_All.Add(&m_Tooltips);
|
||||||
m_All.Add(&CMenus::m_Binder);
|
m_All.Add(&CMenus::m_Binder);
|
||||||
m_All.Add(&m_GameConsole);
|
m_All.Add(&m_GameConsole);
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include "components/spectator.h"
|
#include "components/spectator.h"
|
||||||
#include "components/statboard.h"
|
#include "components/statboard.h"
|
||||||
#include "components/voting.h"
|
#include "components/voting.h"
|
||||||
|
#include "components/tooltips.h"
|
||||||
|
|
||||||
class CGameInfo
|
class CGameInfo
|
||||||
{
|
{
|
||||||
|
@ -144,6 +145,8 @@ public:
|
||||||
CRaceDemo m_RaceDemo;
|
CRaceDemo m_RaceDemo;
|
||||||
CGhost m_Ghost;
|
CGhost m_Ghost;
|
||||||
|
|
||||||
|
CTooltips m_Tooltips;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class CStack
|
class CStack
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue