This commit is contained in:
“sctt” 2022-08-23 19:17:19 +02:00
commit cb9680eaff
27 changed files with 1108 additions and 679 deletions

View file

@ -2103,6 +2103,8 @@ if(CLIENT)
ui.h
ui_rect.cpp
ui_rect.h
ui_scrollregion.cpp
ui_scrollregion.h
)
set_src(GAME_EDITOR GLOB src/game/editor
auto_map.cpp

View file

@ -2997,6 +2997,18 @@ const char *str_rchr(const char *haystack, char needle)
return strrchr(haystack, needle);
}
int str_countchr(const char *haystack, char needle)
{
int count = 0;
while(*haystack)
{
if(*haystack == needle)
count++;
haystack++;
}
return count;
}
void str_hex(char *dst, int dst_size, const void *data, int data_size)
{
static const char hex[] = "0123456789ABCDEF";

View file

@ -1588,6 +1588,23 @@ const char *str_find(const char *haystack, const char *needle);
*/
const char *str_rchr(const char *haystack, char needle);
/*
Function: str_countchr
Counts the number of occurrences of a character in a string.
Parameters:
haystack - String to count in
needle - Character to count
Returns:
The number of characters in the haystack string matching
the needle character.
Remarks:
- The strings are treated as zero-terminated strings.
*/
int str_countchr(const char *haystack, char needle);
/*
Function: str_hex
Takes a datablock and generates a hex string of it, with spaces

View file

@ -324,7 +324,6 @@ MACRO_CONFIG_INT(ClShowOthers, cl_show_others, 0, 0, 2, CFGFLAG_CLIENT | CFGFLAG
MACRO_CONFIG_INT(ClShowOthersAlpha, cl_show_others_alpha, 40, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show players in other teams (alpha value, 0 invisible, 100 fully visible)")
MACRO_CONFIG_INT(ClOverlayEntities, cl_overlay_entities, 0, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Overlay game tiles with a percentage of opacity")
MACRO_CONFIG_INT(ClShowQuads, cl_showquads, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show quads (only interesting for mappers, or if your system has extremely bad performance)")
MACRO_CONFIG_INT(ClZoomBackgroundLayers, cl_zoom_background_layers, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Zoom background layers")
MACRO_CONFIG_COL(ClBackgroundColor, cl_background_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background color") // 0 0 128
MACRO_CONFIG_COL(ClBackgroundEntitiesColor, cl_background_entities_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities) color") // 0 0 128
MACRO_CONFIG_STR(ClBackgroundEntities, cl_background_entities, 100, "", CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities)")

View file

@ -621,7 +621,7 @@ void CHud::RenderCursor()
if(!m_pClient->m_Snap.m_pLocalCharacter || Client()->State() == IClient::STATE_DEMOPLAYBACK)
return;
RenderTools()->MapScreenToGroup(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y, Layers()->GameGroup());
RenderTools()->MapScreenToInterface(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y);
// render cursor
int CurWeapon = m_pClient->m_Snap.m_pLocalCharacter->m_Weapon % NUM_WEAPONS;

View file

@ -1562,6 +1562,7 @@ void CMapLayers::OnRender()
for(int g = 0; g < m_pLayers->NumGroups(); g++)
{
CMapItemGroup *pGroup = m_pLayers->GetGroup(g);
CMapItemGroupEx *pGroupEx = m_pLayers->GetGroupEx(g);
if(!pGroup)
{
@ -1575,7 +1576,7 @@ void CMapLayers::OnRender()
{
// set clipping
float aPoints[4];
RenderTools()->MapScreenToGroup(Center.x, Center.y, m_pLayers->GameGroup(), GetCurCamera()->m_Zoom);
RenderTools()->MapScreenToGroup(Center.x, Center.y, m_pLayers->GameGroup(), m_pLayers->GameGroupEx(), GetCurCamera()->m_Zoom);
Graphics()->GetScreen(&aPoints[0], &aPoints[1], &aPoints[2], &aPoints[3]);
float x0 = (pGroup->m_ClipX - aPoints[0]) / (aPoints[2] - aPoints[0]);
float y0 = (pGroup->m_ClipY - aPoints[1]) / (aPoints[3] - aPoints[1]);
@ -1593,12 +1594,7 @@ void CMapLayers::OnRender()
(int)((x1 - x0) * Graphics()->ScreenWidth()), (int)((y1 - y0) * Graphics()->ScreenHeight()));
}
if((!g_Config.m_ClZoomBackgroundLayers || m_Type == TYPE_FULL_DESIGN) && !pGroup->m_ParallaxX && !pGroup->m_ParallaxY)
{
RenderTools()->MapScreenToGroup(Center.x, Center.y, pGroup, 1.0f);
}
else
RenderTools()->MapScreenToGroup(Center.x, Center.y, pGroup, GetCurCamera()->m_Zoom);
RenderTools()->MapScreenToGroup(Center.x, Center.y, pGroup, pGroupEx, GetCurCamera()->m_Zoom);
for(int l = 0; l < pGroup->m_NumLayers; l++)
{

View file

@ -113,14 +113,14 @@ class CMenus : public CComponent
Text.HMargin(pRect->h >= 20.0f ? 2.0f : 1.0f, &Text);
Text.HMargin((Text.h * FontFactor) / 2.0f, &Text);
if(!UIElement.AreRectsInit() || HintRequiresStringCheck || HintCanChangePositionOrSize || UIElement.Get(0)->m_UITextContainer == -1)
if(!UIElement.AreRectsInit() || HintRequiresStringCheck || HintCanChangePositionOrSize || UIElement.Rect(0)->m_UITextContainer == -1)
{
bool NeedsRecalc = !UIElement.AreRectsInit() || UIElement.Get(0)->m_UITextContainer == -1;
bool NeedsRecalc = !UIElement.AreRectsInit() || UIElement.Rect(0)->m_UITextContainer == -1;
if(HintCanChangePositionOrSize)
{
if(UIElement.AreRectsInit())
{
if(UIElement.Get(0)->m_X != pRect->x || UIElement.Get(0)->m_Y != pRect->y || UIElement.Get(0)->m_Width != pRect->w || UIElement.Get(0)->m_Y != pRect->h)
if(UIElement.Rect(0)->m_X != pRect->x || UIElement.Rect(0)->m_Y != pRect->y || UIElement.Rect(0)->m_Width != pRect->w || UIElement.Rect(0)->m_Y != pRect->h)
{
NeedsRecalc = true;
}
@ -132,7 +132,7 @@ class CMenus : public CComponent
if(UIElement.AreRectsInit())
{
pText = GetTextLambda();
if(str_comp(UIElement.Get(0)->m_Text.c_str(), pText) != 0)
if(str_comp(UIElement.Rect(0)->m_Text.c_str(), pText) != 0)
{
NeedsRecalc = true;
}
@ -158,7 +158,7 @@ class CMenus : public CComponent
Color.a *= UI()->ButtonColorMulDefault();
Graphics()->SetColor(Color);
CUIElement::SUIElementRect &NewRect = *UIElement.Get(i);
CUIElement::SUIElementRect &NewRect = *UIElement.Rect(i);
NewRect.m_UIRectQuadContainer = Graphics()->CreateRectQuadContainer(pRect->x, pRect->y, pRect->w, pRect->h, r, Corners);
NewRect.m_X = pRect->x;
@ -185,11 +185,11 @@ class CMenus : public CComponent
else if(UI()->HotItem() == pID)
Index = 1;
Graphics()->TextureClear();
Graphics()->RenderQuadContainer(UIElement.Get(Index)->m_UIRectQuadContainer, -1);
Graphics()->RenderQuadContainer(UIElement.Rect(Index)->m_UIRectQuadContainer, -1);
ColorRGBA ColorText(TextRender()->DefaultTextColor());
ColorRGBA ColorTextOutline(TextRender()->DefaultTextOutlineColor());
if(UIElement.Get(0)->m_UITextContainer != -1)
TextRender()->RenderTextContainer(UIElement.Get(0)->m_UITextContainer, ColorText, ColorTextOutline);
if(UIElement.Rect(0)->m_UITextContainer != -1)
TextRender()->RenderTextContainer(UIElement.Rect(0)->m_UITextContainer, ColorText, ColorTextOutline);
return UI()->DoButtonLogic(pID, Checked, pRect);
}

View file

@ -286,13 +286,13 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
{
CUIRect r = Row;
r.Margin(0.5f, &r);
pItem->m_pUIElement->Get(0)->Draw(&r, ColorRGBA(1, 1, 1, 0.5f), IGraphics::CORNER_ALL, 4.0f);
pItem->m_pUIElement->Rect(0)->Draw(&r, ColorRGBA(1, 1, 1, 0.5f), IGraphics::CORNER_ALL, 4.0f);
}
else if(UI()->MouseHovered(&Row))
{
CUIRect r = Row;
r.Margin(0.5f, &r);
pItem->m_pUIElement->Get(0)->Draw(&r, ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
pItem->m_pUIElement->Rect(0)->Draw(&r, ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
}
if(UI()->DoButtonLogic(pItem, Selected, &Row))
@ -328,22 +328,22 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
{
if(pItem->m_Flags & SERVER_FLAG_PASSWORD)
{
RenderBrowserIcons(*pItem->m_pUIElement->Get(gs_OffsetColFlagLock + 0), &Button, {0.75f, 0.75f, 0.75f, 1}, TextRender()->DefaultTextOutlineColor(), "\xEF\x80\xA3", TEXTALIGN_CENTER);
RenderBrowserIcons(*pItem->m_pUIElement->Rect(gs_OffsetColFlagLock + 0), &Button, {0.75f, 0.75f, 0.75f, 1}, TextRender()->DefaultTextOutlineColor(), "\xEF\x80\xA3", TEXTALIGN_CENTER);
}
}
else if(ID == COL_FLAG_FAV)
{
if(pItem->m_Favorite != TRISTATE::NONE)
{
RenderBrowserIcons(*pItem->m_pUIElement->Get(gs_OffsetColFav + 0), &Button, {0.94f, 0.4f, 0.4f, 1}, TextRender()->DefaultTextOutlineColor(), "\xEF\x80\x84", TEXTALIGN_CENTER);
RenderBrowserIcons(*pItem->m_pUIElement->Rect(gs_OffsetColFav + 0), &Button, {0.94f, 0.4f, 0.4f, 1}, TextRender()->DefaultTextOutlineColor(), "\xEF\x80\x84", TEXTALIGN_CENTER);
}
}
else if(ID == COL_FLAG_OFFICIAL)
{
if(pItem->m_Official && g_Config.m_UiPage != PAGE_DDNET && g_Config.m_UiPage != PAGE_KOG)
{
RenderBrowserIcons(*pItem->m_pUIElement->Get(gs_OffsetColOff + 0), &Button, {0.4f, 0.7f, 0.94f, 1}, {0.0f, 0.0f, 0.0f, 1.0f}, "\xEF\x82\xA3", TEXTALIGN_CENTER);
RenderBrowserIcons(*pItem->m_pUIElement->Get(gs_OffsetColOff + 1), &Button, {0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, "\xEF\x80\x8C", TEXTALIGN_CENTER, true);
RenderBrowserIcons(*pItem->m_pUIElement->Rect(gs_OffsetColOff + 0), &Button, {0.4f, 0.7f, 0.94f, 1}, {0.0f, 0.0f, 0.0f, 1.0f}, "\xEF\x82\xA3", TEXTALIGN_CENTER);
RenderBrowserIcons(*pItem->m_pUIElement->Rect(gs_OffsetColOff + 1), &Button, {0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, "\xEF\x80\x8C", TEXTALIGN_CENTER, true);
}
}
else if(ID == COL_NAME)
@ -356,17 +356,17 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
const char *pStr = str_utf8_find_nocase(pItem->m_aName, g_Config.m_BrFilterString);
if(pStr)
{
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColName + 0), &Button, pItem->m_aName, FontSize, TEXTALIGN_LEFT, Button.w, 1, true, (int)(pStr - pItem->m_aName));
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 0), &Button, pItem->m_aName, FontSize, TEXTALIGN_LEFT, Button.w, 1, true, (int)(pStr - pItem->m_aName));
TextRender()->TextColor(0.4f, 0.4f, 1.0f, 1);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColName + 1), &Button, pStr, FontSize, TEXTALIGN_LEFT, Button.w, 1, true, (int)str_length(g_Config.m_BrFilterString), &pItem->m_pUIElement->Get(gs_OffsetColName + 0)->m_Cursor);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 1), &Button, pStr, FontSize, TEXTALIGN_LEFT, Button.w, 1, true, (int)str_length(g_Config.m_BrFilterString), &pItem->m_pUIElement->Rect(gs_OffsetColName + 0)->m_Cursor);
TextRender()->TextColor(1, 1, 1, 1);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColName + 2), &Button, pStr + str_length(g_Config.m_BrFilterString), FontSize, TEXTALIGN_LEFT, Button.w, 1, true, -1, &pItem->m_pUIElement->Get(gs_OffsetColName + 1)->m_Cursor);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName + 2), &Button, pStr + str_length(g_Config.m_BrFilterString), FontSize, TEXTALIGN_LEFT, Button.w, 1, true, -1, &pItem->m_pUIElement->Rect(gs_OffsetColName + 1)->m_Cursor);
}
else
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColName), &Button, pItem->m_aName, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName), &Button, pItem->m_aName, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
}
else
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColName), &Button, pItem->m_aName, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColName), &Button, pItem->m_aName, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
}
else if(ID == COL_MAP)
{
@ -379,7 +379,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
if(g_Config.m_BrIndicateFinished && pItem->m_HasRank == 1)
{
RenderBrowserIcons(*pItem->m_pUIElement->Get(gs_OffsetColFlagLock + 1), &Icon, TextRender()->DefaultTextColor(), TextRender()->DefaultTextOutlineColor(), "\xEF\x84\x9E", TEXTALIGN_CENTER);
RenderBrowserIcons(*pItem->m_pUIElement->Rect(gs_OffsetColFlagLock + 1), &Icon, TextRender()->DefaultTextColor(), TextRender()->DefaultTextOutlineColor(), "\xEF\x84\x9E", TEXTALIGN_CENTER);
}
}
@ -391,17 +391,17 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
const char *pStr = str_utf8_find_nocase(pItem->m_aMap, g_Config.m_BrFilterString);
if(pStr)
{
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColMap + 0), &Button, pItem->m_aMap, FontSize, TEXTALIGN_LEFT, Button.w, 1, true, (int)(pStr - pItem->m_aMap));
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 0), &Button, pItem->m_aMap, FontSize, TEXTALIGN_LEFT, Button.w, 1, true, (int)(pStr - pItem->m_aMap));
TextRender()->TextColor(0.4f, 0.4f, 1.0f, 1);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColMap + 1), &Button, pStr, FontSize, TEXTALIGN_LEFT, Button.w, 1, true, (int)str_length(g_Config.m_BrFilterString), &pItem->m_pUIElement->Get(gs_OffsetColMap + 0)->m_Cursor);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 1), &Button, pStr, FontSize, TEXTALIGN_LEFT, Button.w, 1, true, (int)str_length(g_Config.m_BrFilterString), &pItem->m_pUIElement->Rect(gs_OffsetColMap + 0)->m_Cursor);
TextRender()->TextColor(1, 1, 1, 1);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColMap + 2), &Button, pStr + str_length(g_Config.m_BrFilterString), FontSize, TEXTALIGN_LEFT, Button.w, 1, true, -1, &pItem->m_pUIElement->Get(gs_OffsetColMap + 1)->m_Cursor);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap + 2), &Button, pStr + str_length(g_Config.m_BrFilterString), FontSize, TEXTALIGN_LEFT, Button.w, 1, true, -1, &pItem->m_pUIElement->Rect(gs_OffsetColMap + 1)->m_Cursor);
}
else
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColMap), &Button, pItem->m_aMap, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap), &Button, pItem->m_aMap, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
}
else
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColMap), &Button, pItem->m_aMap, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColMap), &Button, pItem->m_aMap, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
}
else if(ID == COL_PLAYERS)
{
@ -411,14 +411,14 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
{
Button.VSplitLeft(Button.h, &Icon, &Button);
Icon.Margin(2.0f, &Icon);
RenderBrowserIcons(*pItem->m_pUIElement->Get(gs_OffsetColFav + 1), &Icon, {0.94f, 0.4f, 0.4f, 1}, TextRender()->DefaultTextOutlineColor(), "\xEF\x80\x84", TEXTALIGN_LEFT);
RenderBrowserIcons(*pItem->m_pUIElement->Rect(gs_OffsetColFav + 1), &Icon, {0.94f, 0.4f, 0.4f, 1}, TextRender()->DefaultTextOutlineColor(), "\xEF\x80\x84", TEXTALIGN_LEFT);
}
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->Get(gs_OffsetColPlayers), &Button, aTemp, FontSize, TEXTALIGN_RIGHT, -1, 1, false);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColPlayers), &Button, aTemp, FontSize, TEXTALIGN_RIGHT, -1, 1, false);
TextRender()->TextColor(1, 1, 1, 1);
}
else if(ID == COL_PING)
@ -432,14 +432,14 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
}
float FontSize = 12.0f;
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColPing), &Button, aTemp, FontSize, TEXTALIGN_RIGHT, -1, 1, false);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColPing), &Button, aTemp, FontSize, TEXTALIGN_RIGHT, -1, 1, false);
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->Get(gs_OffsetColVersion), &Button, pVersion, FontSize, TEXTALIGN_RIGHT, -1, 1, false);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColVersion), &Button, pVersion, FontSize, TEXTALIGN_RIGHT, -1, 1, false);
}
else if(ID == COL_GAMETYPE)
{
@ -466,11 +466,11 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
ColorRGBA rgb = color_cast<ColorRGBA>(hsl);
TextRender()->TextColor(rgb);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColGameType), &Button, pItem->m_aGameType, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColGameType), &Button, pItem->m_aGameType, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
else
UI()->DoLabelStreamed(*pItem->m_pUIElement->Get(gs_OffsetColGameType), &Button, pItem->m_aGameType, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
UI()->DoLabelStreamed(*pItem->m_pUIElement->Rect(gs_OffsetColGameType), &Button, pItem->m_aGameType, FontSize, TEXTALIGN_LEFT, Button.w, 1, true);
}
}
}

View file

@ -20,6 +20,7 @@
#include <game/client/gameclient.h>
#include <game/client/render.h>
#include <game/client/ui.h>
#include <game/client/ui_scrollregion.h>
#include <game/localization.h>
#include "menus.h"
@ -450,14 +451,30 @@ void CMenus::RenderServerInfo(CUIRect MainView)
}
// motd
Motd.HSplitTop(10.0f, 0, &Motd);
const float MotdFontSize = 16.0f;
Motd.HSplitTop(10.0f, nullptr, &Motd);
Motd.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
Motd.Margin(5.0f, &Motd);
y = 0.0f;
x = 5.0f;
TextRender()->Text(0, Motd.x + x, Motd.y + y, 32, Localize("MOTD"), -1.0f);
y += 32.0f + 5.0f;
TextRender()->Text(0, Motd.x + x, Motd.y + y, 16, m_pClient->m_Motd.m_aServerMotd, Motd.w);
Motd.HMargin(5.0f, &Motd);
Motd.VMargin(10.0f, &Motd);
CUIRect MotdHeader;
Motd.HSplitTop(2.0f * MotdFontSize, &MotdHeader, &Motd);
Motd.HSplitTop(5.0f, nullptr, &Motd);
TextRender()->Text(nullptr, MotdHeader.x, MotdHeader.y, 2.0f * MotdFontSize, Localize("MOTD"), -1.0f);
static CScrollRegion s_ScrollRegion;
vec2 ScrollOffset(0.0f, 0.0f);
CScrollRegionParams ScrollParams;
ScrollParams.m_ScrollUnit = 5 * MotdFontSize;
s_ScrollRegion.Begin(&Motd, &ScrollOffset, &ScrollParams);
Motd.y += ScrollOffset.y;
CUIRect MotdTextArea;
Motd.HSplitTop((str_countchr(m_pClient->m_Motd.m_aServerMotd, '\n') + 1) * MotdFontSize, &MotdTextArea, &Motd);
s_ScrollRegion.AddRect(MotdTextArea);
TextRender()->Text(nullptr, MotdTextArea.x, MotdTextArea.y, MotdFontSize, m_pClient->m_Motd.m_aServerMotd, MotdTextArea.w);
s_ScrollRegion.End();
}
bool CMenus::RenderServerControlServer(CUIRect MainView)

View file

@ -19,6 +19,7 @@
#include <game/client/gameclient.h>
#include <game/client/render.h>
#include <game/client/ui.h>
#include <game/client/ui_scrollregion.h>
#include <game/localization.h>
#include "binds.h"
@ -927,7 +928,7 @@ float CMenus::RenderSettingsControlsJoystick(CUIRect View)
const float Spacing = 2.0f;
const float BackgroundHeight = NumOptions * (ButtonHeight + Spacing) + (NumOptions == 1 ? 0 : Spacing);
if(View.h < BackgroundHeight)
return BackgroundHeight; // TODO: make this less hacky by porting CScrollRegion from vanilla
return BackgroundHeight;
View.HSplitTop(BackgroundHeight, &View, 0);
@ -1107,110 +1108,120 @@ void CMenus::RenderSettingsControls(CUIRect MainView)
}
}
// controls in a scrollable listbox
static int s_ControlsList = 0;
static int s_SelectedControl = -1;
static float s_ScrollValue = 0;
static int s_OldSelected = 0;
// scrollable controls
static float s_JoystickSettingsHeight = 0.0f; // we calculate this later and don't render until enough space is available
// Hacky values: Size of 10.0f per item for smoother scrolling, 72 elements
// fits the current size of controls settings
const float PseudoItemSize = 10.0f;
UiDoListboxStart(&s_ControlsList, &MainView, PseudoItemSize, Localize("Controls"), "", 72 + (int)ceilf(s_JoystickSettingsHeight / PseudoItemSize + 0.5f), 1, s_SelectedControl, s_ScrollValue);
CUIRect MouseSettings, MovementSettings, WeaponSettings, VotingSettings, ChatSettings, DummySettings, MiscSettings, JoystickSettings, ResetButton;
CListboxItem Item = UiDoListboxNextItem(&s_OldSelected, false, false, true);
Item.m_Rect.HSplitTop(10.0f, 0, &Item.m_Rect);
Item.m_Rect.VSplitMid(&MouseSettings, &VotingSettings);
static CScrollRegion s_ScrollRegion;
vec2 ScrollOffset(0.0f, 0.0f);
CScrollRegionParams ScrollParams;
ScrollParams.m_ScrollUnit = 120.0f;
s_ScrollRegion.Begin(&MainView, &ScrollOffset, &ScrollParams);
MainView.y += ScrollOffset.y;
const float FontSize = 14.0f;
const float Margin = 10.0f;
const float HeaderHeight = FontSize + 5.0f + Margin;
CUIRect MouseSettings, MovementSettings, WeaponSettings, VotingSettings, ChatSettings, DummySettings, MiscSettings, JoystickSettings, ResetButton;
MainView.VSplitMid(&MouseSettings, &VotingSettings);
// mouse settings
{
MouseSettings.VMargin(5.0f, &MouseSettings);
MouseSettings.HSplitTop(80.0f, &MouseSettings, &JoystickSettings);
MouseSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
MouseSettings.VMargin(10.0f, &MouseSettings);
if(s_ScrollRegion.AddRect(MouseSettings))
{
MouseSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
MouseSettings.VMargin(10.0f, &MouseSettings);
TextRender()->Text(0, MouseSettings.x, MouseSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Mouse"), -1.0f);
TextRender()->Text(0, MouseSettings.x, MouseSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Mouse"), -1.0f);
MouseSettings.HSplitTop(HeaderHeight, 0, &MouseSettings);
MouseSettings.HSplitTop(HeaderHeight, 0, &MouseSettings);
CUIRect Button;
MouseSettings.HSplitTop(20.0f, &Button, &MouseSettings);
UI()->DoScrollbarOption(&g_Config.m_InpMousesens, &g_Config.m_InpMousesens, &Button, Localize("Ingame mouse sens."), 1, 500, &CUI::ms_LogarithmicScrollbarScale, CUI::SCROLLBAR_OPTION_NOCLAMPVALUE);
CUIRect Button;
MouseSettings.HSplitTop(20.0f, &Button, &MouseSettings);
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(2.0f, 0, &MouseSettings);
MouseSettings.HSplitTop(20.0f, &Button, &MouseSettings);
UI()->DoScrollbarOption(&g_Config.m_UiMousesens, &g_Config.m_UiMousesens, &Button, Localize("UI mouse sens."), 1, 500, &CUI::ms_LogarithmicScrollbarScale, CUI::SCROLLBAR_OPTION_NOCLAMPVALUE);
MouseSettings.HSplitTop(20.0f, &Button, &MouseSettings);
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
{
JoystickSettings.HSplitTop(Margin, 0, &JoystickSettings);
JoystickSettings.HSplitTop(s_JoystickSettingsHeight, &JoystickSettings, &MovementSettings);
JoystickSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
JoystickSettings.VMargin(Margin, &JoystickSettings);
JoystickSettings.HSplitTop(s_JoystickSettingsHeight + HeaderHeight + Margin, &JoystickSettings, &MovementSettings);
if(s_ScrollRegion.AddRect(JoystickSettings))
{
JoystickSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
JoystickSettings.VMargin(Margin, &JoystickSettings);
TextRender()->Text(0, JoystickSettings.x, JoystickSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Controller"), -1.0f);
TextRender()->Text(0, JoystickSettings.x, JoystickSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Controller"), -1.0f);
JoystickSettings.HSplitTop(HeaderHeight, 0, &JoystickSettings);
s_JoystickSettingsHeight = RenderSettingsControlsJoystick(JoystickSettings) + HeaderHeight + Margin; // + Margin for another bottom margin
JoystickSettings.HSplitTop(HeaderHeight, 0, &JoystickSettings);
s_JoystickSettingsHeight = RenderSettingsControlsJoystick(JoystickSettings);
}
}
// movement settings
{
MovementSettings.HSplitTop(Margin, 0, &MovementSettings);
MovementSettings.HSplitTop(365.0f, &MovementSettings, &WeaponSettings);
MovementSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
MovementSettings.VMargin(Margin, &MovementSettings);
if(s_ScrollRegion.AddRect(MovementSettings))
{
MovementSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
MovementSettings.VMargin(Margin, &MovementSettings);
TextRender()->Text(0, MovementSettings.x, MovementSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Movement"), -1.0f);
TextRender()->Text(0, MovementSettings.x, MovementSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Movement"), -1.0f);
MovementSettings.HSplitTop(HeaderHeight, 0, &MovementSettings);
DoSettingsControlsButtons(0, 15, MovementSettings);
MovementSettings.HSplitTop(HeaderHeight, 0, &MovementSettings);
DoSettingsControlsButtons(0, 15, MovementSettings);
}
}
// weapon settings
{
WeaponSettings.HSplitTop(Margin, 0, &WeaponSettings);
WeaponSettings.HSplitTop(190.0f, &WeaponSettings, &ResetButton);
WeaponSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
WeaponSettings.VMargin(Margin, &WeaponSettings);
if(s_ScrollRegion.AddRect(WeaponSettings))
{
WeaponSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
WeaponSettings.VMargin(Margin, &WeaponSettings);
TextRender()->Text(0, WeaponSettings.x, WeaponSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Weapon"), -1.0f);
TextRender()->Text(0, WeaponSettings.x, WeaponSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Weapon"), -1.0f);
WeaponSettings.HSplitTop(HeaderHeight, 0, &WeaponSettings);
DoSettingsControlsButtons(15, 22, WeaponSettings);
WeaponSettings.HSplitTop(HeaderHeight, 0, &WeaponSettings);
DoSettingsControlsButtons(15, 22, WeaponSettings);
}
}
// defaults
{
ResetButton.HSplitTop(Margin, 0, &ResetButton);
ResetButton.HSplitTop(40.0f, &ResetButton, 0);
ResetButton.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
ResetButton.HMargin(10.0f, &ResetButton);
ResetButton.VMargin(30.0f, &ResetButton);
ResetButton.HSplitTop(20.0f, &ResetButton, 0);
static CButtonContainer s_DefaultButton;
if(DoButton_Menu(&s_DefaultButton, Localize("Reset to defaults"), 0, &ResetButton))
if(s_ScrollRegion.AddRect(ResetButton))
{
m_pClient->m_Binds.SetDefaults();
ResetButton.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
ResetButton.HMargin(10.0f, &ResetButton);
ResetButton.VMargin(30.0f, &ResetButton);
static CButtonContainer s_DefaultButton;
if(DoButton_Menu(&s_DefaultButton, Localize("Reset to defaults"), 0, &ResetButton))
{
m_pClient->m_Binds.SetDefaults();
g_Config.m_InpMousesens = 200;
g_Config.m_UiMousesens = 200;
g_Config.m_InpMousesens = 200;
g_Config.m_UiMousesens = 200;
g_Config.m_InpControllerEnable = 0;
g_Config.m_InpControllerGUID[0] = '\0';
g_Config.m_InpControllerAbsolute = 0;
g_Config.m_InpControllerSens = 100;
g_Config.m_InpControllerX = 0;
g_Config.m_InpControllerY = 1;
g_Config.m_InpControllerTolerance = 5;
g_Config.m_UiControllerSens = 100;
g_Config.m_InpControllerEnable = 0;
g_Config.m_InpControllerGUID[0] = '\0';
g_Config.m_InpControllerAbsolute = 0;
g_Config.m_InpControllerSens = 100;
g_Config.m_InpControllerX = 0;
g_Config.m_InpControllerY = 1;
g_Config.m_InpControllerTolerance = 5;
g_Config.m_UiControllerSens = 100;
}
}
}
@ -1218,55 +1229,67 @@ void CMenus::RenderSettingsControls(CUIRect MainView)
{
VotingSettings.VMargin(5.0f, &VotingSettings);
VotingSettings.HSplitTop(80.0f, &VotingSettings, &ChatSettings);
VotingSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
VotingSettings.VMargin(Margin, &VotingSettings);
if(s_ScrollRegion.AddRect(VotingSettings))
{
VotingSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
VotingSettings.VMargin(Margin, &VotingSettings);
TextRender()->Text(0, VotingSettings.x, VotingSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Voting"), -1.0f);
TextRender()->Text(0, VotingSettings.x, VotingSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Voting"), -1.0f);
VotingSettings.HSplitTop(HeaderHeight, 0, &VotingSettings);
DoSettingsControlsButtons(22, 24, VotingSettings);
VotingSettings.HSplitTop(HeaderHeight, 0, &VotingSettings);
DoSettingsControlsButtons(22, 24, VotingSettings);
}
}
// chat settings
{
ChatSettings.HSplitTop(Margin, 0, &ChatSettings);
ChatSettings.HSplitTop(145.0f, &ChatSettings, &DummySettings);
ChatSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
ChatSettings.VMargin(Margin, &ChatSettings);
if(s_ScrollRegion.AddRect(ChatSettings))
{
ChatSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
ChatSettings.VMargin(Margin, &ChatSettings);
TextRender()->Text(0, ChatSettings.x, ChatSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Chat"), -1.0f);
TextRender()->Text(0, ChatSettings.x, ChatSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Chat"), -1.0f);
ChatSettings.HSplitTop(HeaderHeight, 0, &ChatSettings);
DoSettingsControlsButtons(24, 29, ChatSettings);
ChatSettings.HSplitTop(HeaderHeight, 0, &ChatSettings);
DoSettingsControlsButtons(24, 29, ChatSettings);
}
}
// dummy settings
{
DummySettings.HSplitTop(Margin, 0, &DummySettings);
DummySettings.HSplitTop(100.0f, &DummySettings, &MiscSettings);
DummySettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
DummySettings.VMargin(Margin, &DummySettings);
if(s_ScrollRegion.AddRect(DummySettings))
{
DummySettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
DummySettings.VMargin(Margin, &DummySettings);
TextRender()->Text(0, DummySettings.x, DummySettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Dummy"), -1.0f);
TextRender()->Text(0, DummySettings.x, DummySettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Dummy"), -1.0f);
DummySettings.HSplitTop(HeaderHeight, 0, &DummySettings);
DoSettingsControlsButtons(29, 32, DummySettings);
DummySettings.HSplitTop(HeaderHeight, 0, &DummySettings);
DoSettingsControlsButtons(29, 32, DummySettings);
}
}
// misc settings
{
MiscSettings.HSplitTop(Margin, 0, &MiscSettings);
MiscSettings.HSplitTop(300.0f, &MiscSettings, 0);
MiscSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
MiscSettings.VMargin(Margin, &MiscSettings);
if(s_ScrollRegion.AddRect(MiscSettings))
{
MiscSettings.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 10.0f);
MiscSettings.VMargin(Margin, &MiscSettings);
TextRender()->Text(0, MiscSettings.x, MiscSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Miscellaneous"), -1.0f);
TextRender()->Text(0, MiscSettings.x, MiscSettings.y + (HeaderHeight - FontSize) / 2.f, FontSize, Localize("Miscellaneous"), -1.0f);
MiscSettings.HSplitTop(HeaderHeight, 0, &MiscSettings);
DoSettingsControlsButtons(32, 44, MiscSettings);
MiscSettings.HSplitTop(HeaderHeight, 0, &MiscSettings);
DoSettingsControlsButtons(32, 44, MiscSettings);
}
}
UiDoListboxEnd(&s_ScrollValue, 0);
s_ScrollRegion.End();
}
int CMenus::RenderDropDown(int &CurDropDownState, CUIRect *pRect, int CurSelection, const void **pIDs, const char **pStr, int PickNum, CButtonContainer *pButtonContainer, float &ScrollVal)

View file

@ -101,7 +101,7 @@ void CNamePlates::RenderNameplatePos(vec2 Position, const CNetObj_PlayerInfo *pP
// create nameplates at standard zoom
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
RenderTools()->MapScreenToGroup(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y, Layers()->GameGroup());
RenderTools()->MapScreenToInterface(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y);
m_aNamePlates[ClientID].m_NameTextWidth = TextRender()->TextWidth(0, FontSize, pName, -1, -1.0f);
@ -126,7 +126,7 @@ void CNamePlates::RenderNameplatePos(vec2 Position, const CNetObj_PlayerInfo *pP
// create nameplates at standard zoom
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
RenderTools()->MapScreenToGroup(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y, Layers()->GameGroup());
RenderTools()->MapScreenToInterface(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y);
m_aNamePlates[ClientID].m_ClanNameTextWidth = TextRender()->TextWidth(0, FontSizeClan, pClan, -1, -1.0f);

View file

@ -374,6 +374,8 @@ void CGameClient::OnInit()
void CGameClient::OnUpdate()
{
CUIElementBase::Init(UI()); // update static pointer because game and editor use separate UI
// handle mouse movement
float x = 0.0f, y = 0.0f;
IInput::ECursorType CursorType = Input()->CursorRelative(&x, &y);

View file

@ -15,6 +15,7 @@
#include <game/generated/protocol.h>
#include <game/mapitems.h>
#include <game/mapitems_ex.h>
static float gs_SpriteWScale;
static float gs_SpriteHScale;
@ -389,10 +390,15 @@ void CRenderTools::CalcScreenParams(float Aspect, float Zoom, float *pWidth, flo
}
void CRenderTools::MapScreenToWorld(float CenterX, float CenterY, float ParallaxX, float ParallaxY,
float OffsetX, float OffsetY, float Aspect, float Zoom, float *pPoints)
float ParallaxZoom, float OffsetX, float OffsetY, float Aspect, float Zoom, float *pPoints)
{
float Width, Height;
CalcScreenParams(Aspect, Zoom, &Width, &Height);
float Scale = (ParallaxZoom * (Zoom - 1.0f) + 100.0f) / 100.0f / Zoom;
Width *= Scale;
Height *= Scale;
CenterX *= ParallaxX / 100.0f;
CenterY *= ParallaxY / 100.0f;
pPoints[0] = OffsetX + CenterX - Width / 2;
@ -401,10 +407,19 @@ void CRenderTools::MapScreenToWorld(float CenterX, float CenterY, float Parallax
pPoints[3] = pPoints[1] + Height;
}
void CRenderTools::MapScreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup, float Zoom)
void CRenderTools::MapScreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup, CMapItemGroupEx *pGroupEx, float Zoom)
{
float ParallaxZoom = GetParallaxZoom(pGroup, pGroupEx);
float aPoints[4];
MapScreenToWorld(CenterX, CenterY, pGroup->m_ParallaxX, pGroup->m_ParallaxY,
MapScreenToWorld(CenterX, CenterY, pGroup->m_ParallaxX, pGroup->m_ParallaxY, ParallaxZoom,
pGroup->m_OffsetX, pGroup->m_OffsetY, Graphics()->ScreenAspect(), Zoom, aPoints);
Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]);
}
void CRenderTools::MapScreenToInterface(float CenterX, float CenterY)
{
float aPoints[4];
MapScreenToWorld(CenterX, CenterY, 100.0f, 100.0f, 100.0f,
0, 0, Graphics()->ScreenAspect(), 1.0f, aPoints);
Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]);
}

View file

@ -20,6 +20,7 @@ struct CDataSprite;
struct CDataSprite;
struct CEnvPoint;
struct CMapItemGroup;
struct CMapItemGroupEx;
struct CQuad;
class CTeeRenderInfo
@ -126,8 +127,9 @@ public:
// helpers
void CalcScreenParams(float Aspect, float Zoom, float *pWidth, float *pHeight);
void MapScreenToWorld(float CenterX, float CenterY, float ParallaxX, float ParallaxY,
float OffsetX, float OffsetY, float Aspect, float Zoom, float *pPoints);
void MapScreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup, float Zoom = 1.0f);
float ParallaxZoom, float OffsetX, float OffsetY, float Aspect, float Zoom, float *pPoints);
void MapScreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup, CMapItemGroupEx *pGroupEx, float Zoom);
void MapScreenToInterface(float CenterX, float CenterY);
// DDRace

View file

@ -82,6 +82,13 @@ const CLinearScrollbarScale CUI::ms_LinearScrollbarScale;
const CLogarithmicScrollbarScale CUI::ms_LogarithmicScrollbarScale(25);
float CUI::ms_FontmodHeight = 0.8f;
CUI *CUIElementBase::s_pUI = nullptr;
IClient *CUIElementBase::Client() const { return s_pUI->Client(); }
IGraphics *CUIElementBase::Graphics() const { return s_pUI->Graphics(); }
IInput *CUIElementBase::Input() const { return s_pUI->Input(); }
ITextRender *CUIElementBase::TextRender() const { return s_pUI->TextRender(); }
void CUI::Init(IKernel *pKernel)
{
m_pClient = pKernel->RequestInterface<IClient>();
@ -90,6 +97,7 @@ void CUI::Init(IKernel *pKernel)
m_pTextRender = pKernel->RequestInterface<ITextRender>();
InitInputs(m_pInput->GetEventsRaw(), m_pInput->GetEventCountRaw());
CUIRect::Init(m_pGraphics);
CUIElementBase::Init(this);
}
void CUI::InitInputs(IInput::CEvent *pInputEventsArray, int *pInputEventCount)

View file

@ -131,15 +131,12 @@ protected:
CUI *UI() const { return m_pUI; }
std::vector<SUIElementRect> m_vUIRects;
// used for marquees or other user implemented things
int64_t m_ElementTime;
public:
CUIElement() = default;
void Init(CUI *pUI, int RequestedRectCount);
SUIElementRect *Get(size_t Index)
SUIElementRect *Rect(size_t Index)
{
return &m_vUIRects[Index];
}
@ -161,6 +158,21 @@ struct SLabelProperties
bool m_EnableWidthCheck = true;
};
class CUIElementBase
{
private:
static CUI *s_pUI;
public:
static void Init(CUI *pUI) { s_pUI = pUI; }
IClient *Client() const;
IGraphics *Graphics() const;
IInput *Input() const;
ITextRender *TextRender() const;
CUI *UI() const { return s_pUI; }
};
class CButtonContainer
{
};

View file

@ -0,0 +1,220 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <base/system.h>
#include <base/vmath.h>
#include <engine/client.h>
#include <engine/keys.h>
#include "ui_scrollregion.h"
CScrollRegion::CScrollRegion()
{
m_ScrollY = 0.0f;
m_ContentH = 0.0f;
m_AnimTime = 0.0f;
m_AnimInitScrollY = 0.0f;
m_AnimTargetScrollY = 0.0f;
m_RequestScrollY = -1.0f;
m_ContentScrollOff = vec2(0.0f, 0.0f);
m_Params = CScrollRegionParams();
}
void CScrollRegion::Begin(CUIRect *pClipRect, vec2 *pOutOffset, CScrollRegionParams *pParams)
{
if(pParams)
m_Params = *pParams;
const bool ContentOverflows = m_ContentH > pClipRect->h;
const bool ForceShowScrollbar = m_Params.m_Flags & CScrollRegionParams::FLAG_CONTENT_STATIC_WIDTH;
CUIRect ScrollBarBg;
bool HasScrollBar = ContentOverflows || ForceShowScrollbar;
CUIRect *pModifyRect = HasScrollBar ? pClipRect : nullptr;
pClipRect->VSplitRight(m_Params.m_ScrollbarWidth, pModifyRect, &ScrollBarBg);
ScrollBarBg.Margin(m_Params.m_ScrollbarMargin, &m_RailRect);
// only show scrollbar if required
if(HasScrollBar)
{
if(m_Params.m_ScrollbarBgColor.a > 0.0f)
ScrollBarBg.Draw(m_Params.m_ScrollbarBgColor, IGraphics::CORNER_R, 4.0f);
if(m_Params.m_RailBgColor.a > 0.0f)
m_RailRect.Draw(m_Params.m_RailBgColor, IGraphics::CORNER_ALL, m_RailRect.w / 2.0f);
}
if(!ContentOverflows)
m_ContentScrollOff.y = 0.0f;
if(m_Params.m_ClipBgColor.a > 0.0f)
pClipRect->Draw(m_Params.m_ClipBgColor, HasScrollBar ? IGraphics::CORNER_L : IGraphics::CORNER_ALL, 4.0f);
UI()->ClipEnable(pClipRect);
m_ClipRect = *pClipRect;
m_ContentH = 0.0f;
*pOutOffset = m_ContentScrollOff;
}
void CScrollRegion::End()
{
UI()->ClipDisable();
// only show scrollbar if content overflows
if(m_ContentH <= m_ClipRect.h)
return;
// scroll wheel
CUIRect RegionRect = m_ClipRect;
RegionRect.w += m_Params.m_ScrollbarWidth;
const float AnimationDuration = 0.5f;
if(UI()->Enabled() && UI()->MouseHovered(&RegionRect))
{
const bool IsPageScroll = Input()->KeyIsPressed(KEY_LALT) || Input()->KeyIsPressed(KEY_RALT);
const float ScrollUnit = IsPageScroll ? m_ClipRect.h : m_Params.m_ScrollUnit;
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP))
{
m_AnimTime = AnimationDuration;
m_AnimInitScrollY = m_ScrollY;
m_AnimTargetScrollY -= ScrollUnit;
}
else if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN))
{
m_AnimTime = AnimationDuration;
m_AnimInitScrollY = m_ScrollY;
m_AnimTargetScrollY += ScrollUnit;
}
}
const float SliderHeight = maximum(m_Params.m_SliderMinHeight, m_ClipRect.h / m_ContentH * m_RailRect.h);
CUIRect Slider = m_RailRect;
Slider.h = SliderHeight;
const float MaxSlider = m_RailRect.h - SliderHeight;
const float MaxScroll = m_ContentH - m_ClipRect.h;
if(m_RequestScrollY >= 0.0f)
{
m_AnimTargetScrollY = m_RequestScrollY;
m_AnimTime = 0.0f;
m_RequestScrollY = -1.0f;
}
m_AnimTargetScrollY = clamp(m_AnimTargetScrollY, 0.0f, MaxScroll);
if(absolute(m_AnimInitScrollY - m_AnimTargetScrollY) < 0.5f)
m_AnimTime = 0.0f;
if(m_AnimTime > 0.0f)
{
m_AnimTime -= Client()->RenderFrameTime();
float AnimProgress = (1.0f - powf(m_AnimTime / AnimationDuration, 3.0f)); // cubic ease out
m_ScrollY = m_AnimInitScrollY + (m_AnimTargetScrollY - m_AnimInitScrollY) * AnimProgress;
}
else
{
m_ScrollY = m_AnimTargetScrollY;
}
Slider.y += m_ScrollY / MaxScroll * MaxSlider;
bool Hovered = false;
bool Grabbed = false;
const void *pID = &m_ScrollY;
const bool InsideSlider = UI()->MouseHovered(&Slider);
const bool InsideRail = UI()->MouseHovered(&m_RailRect);
if(UI()->CheckActiveItem(pID) && UI()->MouseButton(0))
{
float MouseY = UI()->MouseY();
m_ScrollY += (MouseY - (Slider.y + m_SliderGrabPos.y)) / MaxSlider * MaxScroll;
m_SliderGrabPos.y = clamp(m_SliderGrabPos.y, 0.0f, SliderHeight);
m_AnimTargetScrollY = m_ScrollY;
m_AnimTime = 0.0f;
Grabbed = true;
}
else if(InsideSlider)
{
UI()->SetHotItem(pID);
if(!UI()->CheckActiveItem(pID) && UI()->MouseButtonClicked(0))
{
UI()->SetActiveItem(pID);
m_SliderGrabPos.y = UI()->MouseY() - Slider.y;
m_AnimTargetScrollY = m_ScrollY;
m_AnimTime = 0.0f;
}
Hovered = true;
}
else if(InsideRail && UI()->MouseButtonClicked(0))
{
m_ScrollY += (UI()->MouseY() - (Slider.y + Slider.h / 2.0f)) / MaxSlider * MaxScroll;
UI()->SetActiveItem(pID);
m_SliderGrabPos.y = Slider.h / 2.0f;
m_AnimTargetScrollY = m_ScrollY;
m_AnimTime = 0.0f;
Hovered = true;
}
else if(UI()->CheckActiveItem(pID) && !UI()->MouseButton(0))
{
UI()->SetActiveItem(nullptr);
}
m_ScrollY = clamp(m_ScrollY, 0.0f, MaxScroll);
m_ContentScrollOff.y = -m_ScrollY;
Slider.Draw(m_Params.SliderColor(Grabbed, Hovered), IGraphics::CORNER_ALL, Slider.w / 2.0f);
}
bool CScrollRegion::AddRect(const CUIRect &Rect, bool ShouldScrollHere)
{
m_LastAddedRect = Rect;
// Round up and add 1 to fix pixel clipping at the end of the scrolling area
m_ContentH = maximum(ceilf(Rect.y + Rect.h - (m_ClipRect.y + m_ContentScrollOff.y)) + 1.0f, m_ContentH);
if(ShouldScrollHere)
ScrollHere();
return !IsRectClipped(Rect);
}
void CScrollRegion::ScrollHere(EScrollOption Option)
{
const float MinHeight = minimum(m_ClipRect.h, m_LastAddedRect.h);
const float TopScroll = m_LastAddedRect.y - (m_ClipRect.y + m_ContentScrollOff.y);
switch(Option)
{
case SCROLLHERE_TOP:
m_RequestScrollY = TopScroll;
break;
case SCROLLHERE_BOTTOM:
m_RequestScrollY = TopScroll - (m_ClipRect.h - MinHeight);
break;
case SCROLLHERE_KEEP_IN_VIEW:
default:
const float DeltaY = m_LastAddedRect.y - m_ClipRect.y;
if(DeltaY < 0)
m_RequestScrollY = TopScroll;
else if(DeltaY > (m_ClipRect.h - MinHeight))
m_RequestScrollY = TopScroll - (m_ClipRect.h - MinHeight);
break;
}
}
bool CScrollRegion::IsRectClipped(const CUIRect &Rect) const
{
return (m_ClipRect.x > (Rect.x + Rect.w) || (m_ClipRect.x + m_ClipRect.w) < Rect.x || m_ClipRect.y > (Rect.y + Rect.h) || (m_ClipRect.y + m_ClipRect.h) < Rect.y);
}
bool CScrollRegion::IsScrollbarShown() const
{
return m_ContentH > m_ClipRect.h;
}
bool CScrollRegion::IsAnimating() const
{
return m_AnimTime > 0.0f;
}

View file

@ -0,0 +1,123 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef GAME_CLIENT_UI_SCROLLREGION_H
#define GAME_CLIENT_UI_SCROLLREGION_H
#include "ui.h"
struct CScrollRegionParams
{
float m_ScrollbarWidth;
float m_ScrollbarMargin;
float m_SliderMinHeight;
float m_ScrollUnit;
ColorRGBA m_ClipBgColor;
ColorRGBA m_ScrollbarBgColor;
ColorRGBA m_RailBgColor;
ColorRGBA m_SliderColor;
ColorRGBA m_SliderColorHover;
ColorRGBA m_SliderColorGrabbed;
unsigned m_Flags;
enum
{
FLAG_CONTENT_STATIC_WIDTH = 1 << 0,
};
CScrollRegionParams()
{
m_ScrollbarWidth = 20.0f;
m_ScrollbarMargin = 5.0f;
m_SliderMinHeight = 25.0f;
m_ScrollUnit = 10.0f;
m_ClipBgColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
m_ScrollbarBgColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
m_RailBgColor = ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f);
m_SliderColor = ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f);
m_SliderColorHover = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
m_SliderColorGrabbed = ColorRGBA(0.9f, 0.9f, 0.9f, 1.0f);
m_Flags = 0;
}
ColorRGBA SliderColor(bool Active, bool Hovered) const
{
if(Active)
return m_SliderColorGrabbed;
else if(Hovered)
return m_SliderColorHover;
return m_SliderColor;
}
};
/*
Usage:
-- Initialization --
static CScrollRegion s_ScrollRegion;
vec2 ScrollOffset(0, 0);
s_ScrollRegion.Begin(&ScrollRegionRect, &ScrollOffset);
Content = ScrollRegionRect;
Content.y += ScrollOffset.y;
-- "Register" your content rects --
CUIRect Rect;
Content.HSplitTop(SomeValue, &Rect, &Content);
s_ScrollRegion.AddRect(Rect);
-- [Optional] Knowing if a rect is clipped --
s_ScrollRegion.IsRectClipped(Rect);
-- [Optional] Scroll to a rect (to the last added rect)--
...
s_ScrollRegion.AddRect(Rect);
s_ScrollRegion.ScrollHere(Option);
-- [Convenience] Add rect and check for visibility at the same time
if(s_ScrollRegion.AddRect(Rect))
// The rect is visible (not clipped)
-- [Convenience] Add rect and scroll to it if it's selected
if(s_ScrollRegion.AddRect(Rect, ScrollToSelection && IsSelected))
// The rect is visible (not clipped)
-- End --
s_ScrollRegion.End();
*/
// Instances of CScrollRegion must be static, as member addresses are used as UI item IDs
class CScrollRegion : private CUIElementBase
{
private:
float m_ScrollY;
float m_ContentH;
float m_RequestScrollY; // [0, ContentHeight]
float m_AnimTime;
float m_AnimInitScrollY;
float m_AnimTargetScrollY;
CUIRect m_ClipRect;
CUIRect m_RailRect;
CUIRect m_LastAddedRect; // saved for ScrollHere()
vec2 m_SliderGrabPos; // where did user grab the slider
vec2 m_ContentScrollOff;
CScrollRegionParams m_Params;
public:
enum EScrollOption
{
SCROLLHERE_KEEP_IN_VIEW = 0,
SCROLLHERE_TOP,
SCROLLHERE_BOTTOM,
};
CScrollRegion();
void Begin(CUIRect *pClipRect, vec2 *pOutOffset, CScrollRegionParams *pParams = nullptr);
void End();
bool AddRect(const CUIRect &Rect, bool ShouldScrollHere = false); // returns true if the added rect is visible (not clipped)
void ScrollHere(EScrollOption Option = SCROLLHERE_KEEP_IN_VIEW);
bool IsRectClipped(const CUIRect &Rect) const;
bool IsScrollbarShown() const;
bool IsAnimating() const;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@
#include <game/client/render.h>
#include <game/client/ui.h>
#include <game/mapitems.h>
#include <game/mapitems_ex.h>
#include <engine/editor.h>
#include <engine/graphics.h>
@ -187,6 +188,8 @@ public:
int m_ParallaxX;
int m_ParallaxY;
int m_CustomParallaxZoom;
int m_ParallaxZoom;
int m_UseClipping;
int m_ClipX;
@ -253,6 +256,12 @@ public:
}
}*/
void OnEdited()
{
if(!m_CustomParallaxZoom)
m_ParallaxZoom = GetParallaxZoomDefault(m_ParallaxX, m_ParallaxY);
}
void Clear()
{
m_vpLayers.clear();
@ -788,6 +797,7 @@ public:
m_GuiActive = true;
m_ProofBorders = false;
m_PreviewZoom = false;
m_ShowTileInfo = false;
m_ShowDetail = true;
@ -962,6 +972,8 @@ public:
bool m_ShowMousePointer;
bool m_GuiActive;
bool m_ProofBorders;
bool m_PreviewZoom;
float m_MouseWScale = 1.0f; // Mouse (i.e. UI) scale relative to the World (selected Group)
float m_MouseX = 0.0f;
float m_MouseY = 0.0f;
float m_MouseWorldX = 0.0f;
@ -1114,9 +1126,10 @@ public:
bool IsEnvelopeUsed(int EnvelopeIndex) const;
void RenderImages(CUIRect Toolbox, CUIRect View);
void RenderLayers(CUIRect Toolbox, CUIRect View);
void RenderSounds(CUIRect Toolbox, CUIRect View);
void RenderLayers(CUIRect LayersBox);
void RenderImagesList(CUIRect Toolbox);
void RenderSelectedImage(CUIRect View);
void RenderSounds(CUIRect Toolbox);
void RenderModebar(CUIRect View);
void RenderStatusbar(CUIRect View);
void RenderEnvelopeEditor(CUIRect View);
@ -1128,7 +1141,7 @@ public:
void AddFileDialogEntry(int Index, CUIRect *pView);
void SelectGameLayer();
void SortImages();
void SelectLayerByTile(float &Scroll);
bool SelectLayerByTile();
//Tile Numbers For Explanations - TODO: Add/Improve tiles and explanations
enum

View file

@ -184,6 +184,10 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
// save group name
StrToInts(GItem.m_aName, sizeof(GItem.m_aName) / sizeof(int), pGroup->m_aName);
CMapItemGroupEx GItemEx;
GItemEx.m_Version = CMapItemGroupEx::CURRENT_VERSION;
GItemEx.m_ParallaxZoom = pGroup->m_ParallaxZoom;
for(const auto &pLayer : pGroup->m_vpLayers)
{
if(pLayer->m_Type == LAYERTYPE_TILES)
@ -331,7 +335,9 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
}
}
df.AddItem(MAPITEMTYPE_GROUP, GroupCount++, sizeof(GItem), &GItem);
df.AddItem(MAPITEMTYPE_GROUP, GroupCount, sizeof(GItem), &GItem);
df.AddItem(MAPITEMTYPE_GROUP_EX, GroupCount, sizeof(GItemEx), &GItemEx);
GroupCount++;
}
// save envelopes
@ -581,9 +587,15 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
int Start, Num;
DataFile.GetType(MAPITEMTYPE_GROUP, &Start, &Num);
int StartEx, NumEx;
DataFile.GetType(MAPITEMTYPE_GROUP_EX, &StartEx, &NumEx);
for(int g = 0; g < Num; g++)
{
CMapItemGroup *pGItem = (CMapItemGroup *)DataFile.GetItem(Start + g, nullptr, nullptr);
CMapItemGroupEx *pGItemEx = nullptr;
if(NumEx)
pGItemEx = (CMapItemGroupEx *)DataFile.GetItem(StartEx + g, nullptr, nullptr);
if(pGItem->m_Version < 1 || pGItem->m_Version > CMapItemGroup::CURRENT_VERSION)
continue;
@ -607,6 +619,9 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
if(pGItem->m_Version >= 3)
IntsToStr(pGItem->m_aName, sizeof(pGroup->m_aName) / sizeof(int), pGroup->m_aName);
pGroup->m_ParallaxZoom = GetParallaxZoom(pGItem, pGItemEx);
pGroup->m_CustomParallaxZoom = pGroup->m_ParallaxZoom != GetParallaxZoomDefault(pGroup->m_ParallaxX, pGroup->m_ParallaxY);
for(int l = 0; l < pGItem->m_NumLayers; l++)
{
CLayer *pLayer = nullptr;

View file

@ -10,6 +10,8 @@
#include <engine/shared/config.h>
#include <engine/storage.h>
#include <game/client/ui_scrollregion.h>
#include "editor.h"
// popup menu handling
@ -320,6 +322,8 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View, void *pContext)
PROP_POS_Y,
PROP_PARA_X,
PROP_PARA_Y,
PROP_CUSTOM_ZOOM,
PROP_PARA_ZOOM,
PROP_USE_CLIPPING,
PROP_CLIP_X,
PROP_CLIP_Y,
@ -334,6 +338,8 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View, void *pContext)
{"Pos Y", -pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_OffsetY, PROPTYPE_INT_SCROLL, -1000000, 1000000},
{"Para X", pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ParallaxX, PROPTYPE_INT_SCROLL, -1000000, 1000000},
{"Para Y", pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ParallaxY, PROPTYPE_INT_SCROLL, -1000000, 1000000},
{"Custom Zoom", pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_CustomParallaxZoom, PROPTYPE_BOOL, 0, 1},
{"Para Zoom", pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ParallaxZoom, PROPTYPE_INT_SCROLL, -1000000, 1000000},
{"Use Clipping", pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_UseClipping, PROPTYPE_BOOL, 0, 1},
{"Clip X", pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ClipX, PROPTYPE_INT_SCROLL, -1000000, 1000000},
@ -364,6 +370,13 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View, void *pContext)
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ParallaxX = NewVal;
else if(Prop == PROP_PARA_Y)
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ParallaxY = NewVal;
else if(Prop == PROP_CUSTOM_ZOOM)
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_CustomParallaxZoom = NewVal;
else if(Prop == PROP_PARA_ZOOM)
{
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_CustomParallaxZoom = 1;
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ParallaxZoom = NewVal;
}
else if(Prop == PROP_POS_X)
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_OffsetX = -NewVal;
else if(Prop == PROP_POS_Y)
@ -378,6 +391,8 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View, void *pContext)
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ClipW = NewVal;
else if(Prop == PROP_CLIP_H)
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ClipH = NewVal;
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->OnEdited();
}
return 0;
@ -1234,54 +1249,29 @@ static int g_SelectImageCurrent = -100;
int CEditor::PopupSelectImage(CEditor *pEditor, CUIRect View, void *pContext)
{
CUIRect ButtonBar, ImageView;
View.VSplitLeft(80.0f, &ButtonBar, &View);
View.VSplitLeft(150.0f, &ButtonBar, &View);
View.Margin(10.0f, &ImageView);
int ShowImage = g_SelectImageCurrent;
static float s_ScrollValue = 0;
float ImagesHeight = pEditor->m_Map.m_vpImages.size() * 14;
float ScrollDifference = ImagesHeight - ButtonBar.h;
const float RowHeight = 14.0f;
static CScrollRegion s_ScrollRegion;
vec2 ScrollOffset(0.0f, 0.0f);
CScrollRegionParams ScrollParams;
ScrollParams.m_ScrollbarWidth = 10.0f;
ScrollParams.m_ScrollbarMargin = 3.0f;
ScrollParams.m_ScrollUnit = RowHeight * 5;
s_ScrollRegion.Begin(&ButtonBar, &ScrollOffset, &ScrollParams);
ButtonBar.y += ScrollOffset.y;
if(pEditor->m_Map.m_vpImages.size() > 20) // Do we need a scrollbar?
{
CUIRect Scroll;
ButtonBar.VSplitRight(20.0f, &ButtonBar, &Scroll);
s_ScrollValue = pEditor->UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
if(pEditor->UI()->MouseInside(&Scroll) || pEditor->UI()->MouseInside(&ButtonBar))
{
int ScrollNum = (int)((ImagesHeight - ButtonBar.h) / 14.0f) + 1;
if(ScrollNum > 0)
{
if(pEditor->Input()->KeyPress(KEY_MOUSE_WHEEL_UP))
s_ScrollValue = clamp(s_ScrollValue - 1.0f / ScrollNum, 0.0f, 1.0f);
if(pEditor->Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN))
s_ScrollValue = clamp(s_ScrollValue + 1.0f / ScrollNum, 0.0f, 1.0f);
}
}
}
float ImageStartAt = ScrollDifference * s_ScrollValue;
if(ImageStartAt < 0.0f)
ImageStartAt = 0.0f;
float ImageStopAt = ImagesHeight - ScrollDifference * (1 - s_ScrollValue);
float ImageCur = 0.0f;
for(int i = -1; i < (int)pEditor->m_Map.m_vpImages.size(); i++)
{
if(ImageCur > ImageStopAt)
break;
if(ImageCur < ImageStartAt)
{
ImageCur += 14.0f;
continue;
}
ImageCur += 14.0f;
CUIRect Button;
ButtonBar.HSplitTop(14.0f, &Button, &ButtonBar);
ButtonBar.HSplitTop(RowHeight, &Button, &ButtonBar);
if(!s_ScrollRegion.AddRect(Button))
continue;
Button.HSplitTop(12.0f, &Button, 0);
if(pEditor->UI()->MouseInside(&Button))
ShowImage = i;
@ -1298,6 +1288,8 @@ int CEditor::PopupSelectImage(CEditor *pEditor, CUIRect View, void *pContext)
}
}
s_ScrollRegion.End();
if(ShowImage >= 0 && (size_t)ShowImage < pEditor->m_Map.m_vpImages.size())
{
if(ImageView.h < ImageView.w)
@ -1325,7 +1317,7 @@ void CEditor::PopupSelectImageInvoke(int Current, float x, float y)
static int s_SelectImagePopupId = 0;
g_SelectImageSelected = -100;
g_SelectImageCurrent = Current;
UiInvokePopupMenu(&s_SelectImagePopupId, 0, x, y, 400, 300, PopupSelectImage);
UiInvokePopupMenu(&s_SelectImagePopupId, 0, x, y, 450, 300, PopupSelectImage);
}
int CEditor::PopupSelectImageResult()

View file

@ -3,6 +3,7 @@
#include "layers.h"
#include "mapitems.h"
#include "mapitems_ex.h"
#include <engine/map.h>
@ -10,9 +11,12 @@ CLayers::CLayers()
{
m_GroupsNum = 0;
m_GroupsStart = 0;
m_GroupsExNum = 0;
m_GroupsExStart = 0;
m_LayersNum = 0;
m_LayersStart = 0;
m_pGameGroup = 0;
m_pGameGroupEx = 0;
m_pGameLayer = 0;
m_pMap = 0;
@ -27,6 +31,7 @@ void CLayers::Init(class IKernel *pKernel)
{
m_pMap = pKernel->RequestInterface<IMap>();
m_pMap->GetType(MAPITEMTYPE_GROUP, &m_GroupsStart, &m_GroupsNum);
m_pMap->GetType(MAPITEMTYPE_GROUP_EX, &m_GroupsExStart, &m_GroupsExNum);
m_pMap->GetType(MAPITEMTYPE_LAYER, &m_LayersStart, &m_LayersNum);
m_pTeleLayer = 0;
@ -38,6 +43,7 @@ void CLayers::Init(class IKernel *pKernel)
for(int g = 0; g < NumGroups(); g++)
{
CMapItemGroup *pGroup = GetGroup(g);
CMapItemGroupEx *pGroupEx = GetGroupEx(g);
for(int l = 0; l < pGroup->m_NumLayers; l++)
{
CMapItemLayer *pLayer = GetLayer(pGroup->m_StartLayer + l);
@ -50,6 +56,7 @@ void CLayers::Init(class IKernel *pKernel)
{
m_pGameLayer = pTilemap;
m_pGameGroup = pGroup;
m_pGameGroupEx = pGroupEx;
// make sure the game group has standard settings
m_pGameGroup->m_OffsetX = 0;
@ -66,6 +73,9 @@ void CLayers::Init(class IKernel *pKernel)
m_pGameGroup->m_ClipH = 0;
}
if(pGroupEx)
pGroupEx->m_ParallaxZoom = 100;
//break;
}
if(pTilemap->m_Flags & TILESLAYERFLAG_TELE)
@ -119,6 +129,7 @@ void CLayers::InitBackground(class IMap *pMap)
{
m_pMap = pMap;
m_pMap->GetType(MAPITEMTYPE_GROUP, &m_GroupsStart, &m_GroupsNum);
m_pMap->GetType(MAPITEMTYPE_GROUP_EX, &m_GroupsExStart, &m_GroupsExNum);
m_pMap->GetType(MAPITEMTYPE_LAYER, &m_LayersStart, &m_LayersNum);
//following is here to prevent crash using standard map as background
@ -131,6 +142,7 @@ void CLayers::InitBackground(class IMap *pMap)
for(int g = 0; g < NumGroups(); g++)
{
CMapItemGroup *pGroup = GetGroup(g);
CMapItemGroupEx *pGroupEx = GetGroupEx(g);
for(int l = 0; l < pGroup->m_NumLayers; l++)
{
CMapItemLayer *pLayer = GetLayer(pGroup->m_StartLayer + l);
@ -143,6 +155,7 @@ void CLayers::InitBackground(class IMap *pMap)
{
m_pGameLayer = pTilemap;
m_pGameGroup = pGroup;
m_pGameGroupEx = pGroupEx;
// make sure the game group has standard settings
m_pGameGroup->m_OffsetX = 0;
@ -158,6 +171,10 @@ void CLayers::InitBackground(class IMap *pMap)
m_pGameGroup->m_ClipW = 0;
m_pGameGroup->m_ClipH = 0;
}
if(pGroupEx)
pGroupEx->m_ParallaxZoom = 100;
//We don't care about tile layers.
}
}
@ -206,6 +223,15 @@ CMapItemGroup *CLayers::GetGroup(int Index) const
return static_cast<CMapItemGroup *>(m_pMap->GetItem(m_GroupsStart + Index, 0, 0));
}
CMapItemGroupEx *CLayers::GetGroupEx(int Index) const
{
// Map doesn't have GroupEx items or GroupEx indexes don't match groups for some other reason. Lets turn them off completely to be safe.
if(m_GroupsExNum != m_GroupsNum)
return nullptr;
return static_cast<CMapItemGroupEx *>(m_pMap->GetItem(m_GroupsExStart + Index, 0, 0));
}
CMapItemLayer *CLayers::GetLayer(int Index) const
{
return static_cast<CMapItemLayer *>(m_pMap->GetItem(m_LayersStart + Index, 0, 0));

View file

@ -7,6 +7,7 @@ class IKernel;
class IMap;
struct CMapItemGroup;
struct CMapItemGroupEx;
struct CMapItemLayer;
struct CMapItemLayerTilemap;
@ -14,9 +15,12 @@ class CLayers
{
int m_GroupsNum;
int m_GroupsStart;
int m_GroupsExNum;
int m_GroupsExStart;
int m_LayersNum;
int m_LayersStart;
CMapItemGroup *m_pGameGroup;
CMapItemGroupEx *m_pGameGroupEx;
CMapItemLayerTilemap *m_pGameLayer;
IMap *m_pMap;
@ -30,8 +34,10 @@ public:
int NumLayers() const { return m_LayersNum; }
IMap *Map() const { return m_pMap; }
CMapItemGroup *GameGroup() const { return m_pGameGroup; }
CMapItemGroupEx *GameGroupEx() const { return m_pGameGroupEx; }
CMapItemLayerTilemap *GameLayer() const { return m_pGameLayer; }
CMapItemGroup *GetGroup(int Index) const;
CMapItemGroupEx *GetGroupEx(int Index) const;
CMapItemLayer *GetLayer(int Index) const;
// DDRace

View file

@ -1,7 +1,21 @@
#include "mapitems_ex.h"
#include <base/math.h>
#include <engine/shared/uuid_manager.h>
int GetParallaxZoom(const CMapItemGroup *pGroup, const CMapItemGroupEx *pGroupEx)
{
if(pGroupEx)
return pGroupEx->m_ParallaxZoom;
return GetParallaxZoomDefault(pGroup->m_ParallaxX, pGroup->m_ParallaxY);
}
int GetParallaxZoomDefault(int ParallaxX, int ParallaxY)
{
return clamp(maximum(ParallaxX, ParallaxY), 0, 100);
}
void RegisterMapItemTypeUuids(CUuidManager *pManager)
{
#define UUID(id, name) pManager->RegisterName(id, name);

View file

@ -2,6 +2,8 @@
#define GAME_MAPITEMS_EX_H
#include <game/generated/protocol.h>
#include "mapitems.h"
enum
{
__MAPITEMTYPE_UUID_HELPER = OFFSET_MAPITEMTYPE_UUID - 1,
@ -43,5 +45,23 @@ struct CMapItemAutoMapperConfig
int m_Flags;
};
struct CMapItemGroupEx
{
enum
{
CURRENT_VERSION = 1
};
int m_Version;
// ItemGroup's perceived distance from camera when zooming. Similar to how
// Parallax{X,Y} works when camera is moving along the X and Y axes,
// this setting applies to camera moving closer or away (zooming in or out).
int m_ParallaxZoom;
};
int GetParallaxZoom(const CMapItemGroup *pGroup, const CMapItemGroupEx *pGroupEx);
int GetParallaxZoomDefault(int ParallaxX, int ParallaxY);
void RegisterMapItemTypeUuids(class CUuidManager *pManager);
#endif // GAME_MAPITEMS_EX_H

View file

@ -2,3 +2,4 @@
UUID(MAPITEMTYPE_TEST, "mapitemtype-test@ddnet.tw")
UUID(MAPITEMTYPE_AUTOMAPPER_CONFIG, "mapitemtype-automapper-config@ddnet.tw")
UUID(MAPITEMTYPE_GROUP_EX, "mapitemtype-group@ddnet.tw")