Skip to content

Commit

Permalink
Merge ddnet#6803
Browse files Browse the repository at this point in the history
6803: Improve font scaling of long editor texts, improve ellipsis r=def- a=Robyt3

For long editor texts (group name, layer name, image name, sound name, file names, tooltips) make use of the font scaling and ellipsis functionality implemented in `DoLabel` instead of implementing it separately in the editor.

Screenshots:
- File dialog:
   - Before: 
![filedialog old](https://github.com/ddnet/ddnet/assets/23437060/1eb9f191-ceb3-491c-8f35-5058ed07c77e)
   - After: 
![filedialog new](https://github.com/ddnet/ddnet/assets/23437060/18b37439-db6f-49a6-ab42-a608dc9c87c6)
- Filename (top menu bar):
   - Before:
![filename old](https://github.com/ddnet/ddnet/assets/23437060/8735204d-f2b3-4443-887f-f9780f660768)
   - After: 
![filename new](https://github.com/ddnet/ddnet/assets/23437060/53ba21c7-dca3-40d9-85ad-f6adfe9b80a6)
- Image name:
   - Before: 
![imagename old](https://github.com/ddnet/ddnet/assets/23437060/2041beca-db09-474f-a265-fb4175404913)
   - After: 
![imagename new](https://github.com/ddnet/ddnet/assets/23437060/801c43d1-0c23-4235-aa40-b82a6df74df6)
- Layer name:
   - Before: 
![layername old](https://github.com/ddnet/ddnet/assets/23437060/b6207c2e-e029-4e36-8179-abccc317dbf3)
   - After: 
![layername new](https://github.com/ddnet/ddnet/assets/23437060/75ef8de1-f3b2-4743-b5a2-257718ef7102)
- Image selection:
   - Before:
![imageselection old](https://github.com/ddnet/ddnet/assets/23437060/c60f020a-faa9-40ba-8ece-f20fc7bf9bfc)
   - After: 
![imageselection new](https://github.com/ddnet/ddnet/assets/23437060/96b4f735-8ba1-4be7-8b81-1eac70c40ccd)

## Checklist

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


Co-authored-by: Robert Müller <robytemueller@gmail.com>
  • Loading branch information
bors[bot] and Robyt3 authored Jul 2, 2023
2 parents ac6ee58 + 2b64a66 commit 35f8475
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 104 deletions.
53 changes: 29 additions & 24 deletions src/game/client/components/menus_browser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
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 | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
TextRender()->TextColor(TextColor);
TextRender()->TextOutlineColor(TextOutlineColor);
UI()->DoLabelStreamed(UIRect, pRect, pText, FontSize, TextAlign, -1.0f);
UI()->DoLabelStreamed(UIRect, pRect, pText, FontSize, TextAlign);
TextRender()->TextOutlineColor(TextRender()->DefaultTextOutlineColor());
TextRender()->TextColor(TextRender()->DefaultTextColor());
TextRender()->SetRenderFlags(0);
Expand Down Expand Up @@ -250,6 +250,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
continue;
}

const float FontSize = 12.0f;
for(int c = 0; c < NumCols; c++)
{
CUIRect Button;
Expand Down Expand Up @@ -285,19 +286,21 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
}
else if(ID == COL_NAME)
{
float FontSize = 12.0f;
SLabelProperties Props;
Props.m_MaxWidth = Button.w;
Props.m_StopAtEnd = true;
Props.m_EnableWidthCheck = false;
bool Printed = false;

if(g_Config.m_BrFilterString[0] && (pItem->m_QuickSearchHit & IServerBrowser::QUICK_SERVERNAME))
Printed = PrintHighlighted(pItem->m_aName, [this, pItem, FontSize, &Button](const char *pFilteredStr, const int FilterLen) {
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 0), &Button, pItem->m_aName, FontSize, TEXTALIGN_ML, Button.w, true, (int)(pFilteredStr - pItem->m_aName));
Printed = PrintHighlighted(pItem->m_aName, [this, pItem, FontSize, Props, &Button](const char *pFilteredStr, const int FilterLen) {
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 0), &Button, pItem->m_aName, FontSize, TEXTALIGN_ML, Props, (int)(pFilteredStr - pItem->m_aName));
TextRender()->TextColor(0.4f, 0.4f, 1.0f, 1);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 1), &Button, pFilteredStr, FontSize, TEXTALIGN_ML, Button.w, true, FilterLen, &pItem->m_pUIElement->Rect(gs_OffsetColName + 0)->m_Cursor);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 1), &Button, pFilteredStr, FontSize, TEXTALIGN_ML, Props, FilterLen, &pItem->m_pUIElement->Rect(gs_OffsetColName + 0)->m_Cursor);
TextRender()->TextColor(1, 1, 1, 1);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 2), &Button, pFilteredStr + FilterLen, FontSize, TEXTALIGN_ML, Button.w, true, -1, &pItem->m_pUIElement->Rect(gs_OffsetColName + 1)->m_Cursor);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 2), &Button, pFilteredStr + FilterLen, FontSize, TEXTALIGN_ML, Props, -1, &pItem->m_pUIElement->Rect(gs_OffsetColName + 1)->m_Cursor);
});
if(!Printed)
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName), &Button, pItem->m_aName, FontSize, TEXTALIGN_ML, Button.w, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName), &Button, pItem->m_aName, FontSize, TEXTALIGN_ML, Props);
}
else if(ID == COL_MAP)
{
Expand All @@ -314,18 +317,21 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
}
}

float FontSize = 12.0f;
SLabelProperties Props;
Props.m_MaxWidth = Button.w;
Props.m_StopAtEnd = true;
Props.m_EnableWidthCheck = false;
bool Printed = false;
if(g_Config.m_BrFilterString[0] && (pItem->m_QuickSearchHit & IServerBrowser::QUICK_MAPNAME))
Printed = PrintHighlighted(pItem->m_aMap, [this, pItem, FontSize, &Button](const char *pFilteredStr, const int FilterLen) {
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 0), &Button, pItem->m_aMap, FontSize, TEXTALIGN_ML, Button.w, true, (int)(pFilteredStr - pItem->m_aMap));
Printed = PrintHighlighted(pItem->m_aMap, [this, pItem, FontSize, Props, &Button](const char *pFilteredStr, const int FilterLen) {
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 0), &Button, pItem->m_aMap, FontSize, TEXTALIGN_ML, Props, (int)(pFilteredStr - pItem->m_aMap));
TextRender()->TextColor(0.4f, 0.4f, 1.0f, 1);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 1), &Button, pFilteredStr, FontSize, TEXTALIGN_ML, Button.w, true, FilterLen, &pItem->m_pUIElement->Rect(gs_OffsetColMap + 0)->m_Cursor);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 1), &Button, pFilteredStr, FontSize, TEXTALIGN_ML, Props, FilterLen, &pItem->m_pUIElement->Rect(gs_OffsetColMap + 0)->m_Cursor);
TextRender()->TextColor(1, 1, 1, 1);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 2), &Button, pFilteredStr + FilterLen, FontSize, TEXTALIGN_ML, Button.w, true, -1, &pItem->m_pUIElement->Rect(gs_OffsetColMap + 1)->m_Cursor);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 2), &Button, pFilteredStr + FilterLen, FontSize, TEXTALIGN_ML, Props, -1, &pItem->m_pUIElement->Rect(gs_OffsetColMap + 1)->m_Cursor);
});
if(!Printed)
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap), &Button, pItem->m_aMap, FontSize, TEXTALIGN_ML, Button.w, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap), &Button, pItem->m_aMap, FontSize, TEXTALIGN_ML, Props);
}
else if(ID == COL_PLAYERS)
{
Expand All @@ -350,8 +356,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
str_format(aTemp, sizeof(aTemp), "%i/%i", pItem->m_NumFilteredPlayers, ServerBrowser()->Max(*pItem));
if(g_Config.m_BrFilterString[0] && (pItem->m_QuickSearchHit & IServerBrowser::QUICK_PLAYER))
TextRender()->TextColor(0.4f, 0.4f, 1.0f, 1);
float FontSize = 12.0f;
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColPlayers), &Button, aTemp, FontSize, TEXTALIGN_MR, -1.0f, false);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColPlayers), &Button, aTemp, FontSize, TEXTALIGN_MR);
TextRender()->TextColor(1, 1, 1, 1);
}
else if(ID == COL_PING)
Expand All @@ -364,20 +369,20 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
TextRender()->TextColor(rgb);
}

float FontSize = 12.0f;
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColPing), &Button, aTemp, FontSize, TEXTALIGN_MR, -1.0f, false);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColPing), &Button, aTemp, FontSize, TEXTALIGN_MR);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
else if(ID == COL_VERSION)
{
const char *pVersion = pItem->m_aVersion;
float FontSize = 12.0f;
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColVersion), &Button, pVersion, FontSize, TEXTALIGN_MR, -1.0f, false);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColVersion), &Button, pVersion, FontSize, TEXTALIGN_MR);
}
else if(ID == COL_GAMETYPE)
{
float FontSize = 12.0f;

SLabelProperties Props;
Props.m_MaxWidth = Button.w;
Props.m_StopAtEnd = true;
Props.m_EnableWidthCheck = false;
if(g_Config.m_UiColorizeGametype)
{
ColorHSLA hsl = ColorHSLA(1.0f, 1.0f, 1.0f);
Expand Down Expand Up @@ -405,11 +410,11 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)

ColorRGBA rgb = color_cast<ColorRGBA>(hsl);
TextRender()->TextColor(rgb);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColGameType), &Button, pItem->m_aGameType, FontSize, TEXTALIGN_ML, Button.w, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColGameType), &Button, pItem->m_aGameType, FontSize, TEXTALIGN_ML, Props);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
else
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColGameType), &Button, pItem->m_aGameType, FontSize, TEXTALIGN_ML, Button.w, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColGameType), &Button, pItem->m_aGameType, FontSize, TEXTALIGN_ML, Props);
}
}
}
Expand Down
49 changes: 33 additions & 16 deletions src/game/client/ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,31 +580,51 @@ struct SCursorAndBoundingBox

static SCursorAndBoundingBox CalcFontSizeCursorHeightAndBoundingBox(ITextRender *pTextRender, const char *pText, int Flags, float &Size, float MaxWidth, const SLabelProperties &LabelProps)
{
const float MinFontSize = 5.0f;
const float MaxTextWidth = LabelProps.m_MaxWidth != -1.0f ? LabelProps.m_MaxWidth : MaxWidth;
const int FlagsWithoutStop = Flags & ~(TEXTFLAG_STOP_AT_END | TEXTFLAG_ELLIPSIS_AT_END);
const float MaxTextWidthWithoutStop = Flags == FlagsWithoutStop ? LabelProps.m_MaxWidth : -1.0f;

float TextBoundingHeight = 0.0f;
float TextHeight = 0.0f;
int LineCount = 0;
float MaxTextWidth = LabelProps.m_MaxWidth != -1 ? LabelProps.m_MaxWidth : MaxWidth;
STextSizeProperties TextSizeProps{};
TextSizeProps.m_pHeight = &TextHeight;
TextSizeProps.m_pMaxCharacterHeightInLine = &TextBoundingHeight;
TextSizeProps.m_pLineCount = &LineCount;
float TextWidth = pTextRender->TextWidth(Size, pText, -1, LabelProps.m_MaxWidth, Flags, TextSizeProps);
while(TextWidth > MaxTextWidth + 0.001f)

float TextWidth;
do
{
if(!LabelProps.m_EnableWidthCheck)
break;
if(Size < 4.0f)
Size = maximum(Size, MinFontSize);
// Only consider stop-at-end and ellipsis-at-end when minimum font size reached or font scaling disabled
if((Size == MinFontSize || !LabelProps.m_EnableWidthCheck) && Flags != FlagsWithoutStop)
TextWidth = pTextRender->TextWidth(Size, pText, -1, LabelProps.m_MaxWidth, Flags, TextSizeProps);
else
TextWidth = pTextRender->TextWidth(Size, pText, -1, MaxTextWidthWithoutStop, FlagsWithoutStop, TextSizeProps);
if(TextWidth <= MaxTextWidth + 0.001f || !LabelProps.m_EnableWidthCheck || Size == MinFontSize)
break;
Size -= 1.0f;
TextWidth = pTextRender->TextWidth(Size, pText, -1, LabelProps.m_MaxWidth, Flags, TextSizeProps);
}
Size--;
} while(true);

SCursorAndBoundingBox Res{};
Res.m_TextSize = vec2(TextWidth, TextHeight);
Res.m_BiggestCharacterHeight = TextBoundingHeight;
Res.m_LineCount = LineCount;
return Res;
}

static int GetFlagsForLabelProperties(const SLabelProperties &LabelProps, const CTextCursor *pReadCursor)
{
if(pReadCursor != nullptr)
return pReadCursor->m_Flags & ~TEXTFLAG_RENDER;

int Flags = 0;
Flags |= LabelProps.m_StopAtEnd ? TEXTFLAG_STOP_AT_END : 0;
Flags |= LabelProps.m_EllipsisAtEnd ? TEXTFLAG_ELLIPSIS_AT_END : 0;
return Flags;
}

vec2 CUI::CalcAlignedCursorPos(const CUIRect *pRect, vec2 TextSize, int Align, const float *pBiggestCharHeight)
{
vec2 Cursor(pRect->x, pRect->y);
Expand Down Expand Up @@ -634,7 +654,7 @@ vec2 CUI::CalcAlignedCursorPos(const CUIRect *pRect, vec2 TextSize, int Align, c

void CUI::DoLabel(const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps)
{
const int Flags = LabelProps.m_StopAtEnd ? TEXTFLAG_STOP_AT_END : 0;
const int Flags = GetFlagsForLabelProperties(LabelProps, nullptr);
const SCursorAndBoundingBox TextBounds = CalcFontSizeCursorHeightAndBoundingBox(TextRender(), pText, Flags, Size, pRect->w, LabelProps);
const vec2 CursorPos = CalcAlignedCursorPos(pRect, TextBounds.m_TextSize, Align, TextBounds.m_LineCount == 1 ? &TextBounds.m_BiggestCharacterHeight : nullptr);

Expand All @@ -646,7 +666,7 @@ void CUI::DoLabel(const CUIRect *pRect, const char *pText, float Size, int Align

void CUI::DoLabel(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps, int StrLen, const CTextCursor *pReadCursor)
{
const int Flags = pReadCursor ? (pReadCursor->m_Flags & ~TEXTFLAG_RENDER) : LabelProps.m_StopAtEnd ? TEXTFLAG_STOP_AT_END : 0;
const int Flags = GetFlagsForLabelProperties(LabelProps, pReadCursor);
const SCursorAndBoundingBox TextBounds = CalcFontSizeCursorHeightAndBoundingBox(TextRender(), pText, Flags, Size, pRect->w, LabelProps);

CTextCursor Cursor;
Expand All @@ -671,7 +691,7 @@ void CUI::DoLabel(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, cons
RectEl.m_Cursor = Cursor;
}

void CUI::DoLabelStreamed(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, float MaxWidth, bool StopAtEnd, int StrLen, const CTextCursor *pReadCursor)
void CUI::DoLabelStreamed(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps, int StrLen, const CTextCursor *pReadCursor)
{
bool NeedsRecreate = false;
bool ColorChanged = RectEl.m_TextColor != TextRender()->GetTextColor() || RectEl.m_TextOutlineColor != TextRender()->GetTextOutlineColor();
Expand Down Expand Up @@ -714,10 +734,7 @@ void CUI::DoLabelStreamed(CUIElement::SUIElementRect &RectEl, const CUIRect *pRe
TmpRect.w = pRect->w;
TmpRect.h = pRect->h;

SLabelProperties Props;
Props.m_MaxWidth = MaxWidth;
Props.m_StopAtEnd = StopAtEnd;
DoLabel(RectEl, &TmpRect, pText, Size, TEXTALIGN_TL, Props, StrLen, pReadCursor);
DoLabel(RectEl, &TmpRect, pText, Size, TEXTALIGN_TL, LabelProps, StrLen, pReadCursor);
}

ColorRGBA ColorText(RectEl.m_TextColor);
Expand Down
3 changes: 2 additions & 1 deletion src/game/client/ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ struct SLabelProperties
{
float m_MaxWidth = -1;
bool m_StopAtEnd = false;
bool m_EllipsisAtEnd = false;
bool m_EnableWidthCheck = true;
};

Expand Down Expand Up @@ -488,7 +489,7 @@ class CUI
void DoLabel(const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps = {});

void DoLabel(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps = {}, int StrLen = -1, const CTextCursor *pReadCursor = nullptr);
void DoLabelStreamed(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, float MaxWidth = -1, bool StopAtEnd = false, int StrLen = -1, const CTextCursor *pReadCursor = nullptr);
void DoLabelStreamed(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps = {}, int StrLen = -1, const CTextCursor *pReadCursor = nullptr);

bool DoEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL);
bool DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL);
Expand Down
Loading

0 comments on commit 35f8475

Please sign in to comment.