Skip to content

Commit 237672f

Browse files
committed
Add CharacterSelect and CharacterCreation screens
Add CharacterSelect screen Add CharacterCreation screen Add ScrollBox widget Add AtlasPanel widget Fix various UI related issues
1 parent 1c73d2e commit 237672f

29 files changed

+2308
-284
lines changed

Source/Game-Lib/Game-Lib/ECS/Components/UI/Clipper.h

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22
#include <Base/Types.h>
33

4+
#include <entt/entt.hpp>
5+
46
namespace ECS::Components::UI
57
{
68
struct Clipper
@@ -9,6 +11,8 @@ namespace ECS::Components::UI
911
bool clipChildren = false;
1012
vec2 clipRegionMin = vec2(0.0f, 0.0f);
1113
vec2 clipRegionMax = vec2(1.0f, 1.0f);
14+
entt::entity clipRegionOverrideEntity = entt::null;
15+
1216
bool hasClipMaskTexture = false;
1317
std::string clipMaskTexture = "";
1418
};

Source/Game-Lib/Game-Lib/ECS/Components/UI/EventInputInfo.h

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace ECS::Components::UI
1919
i32 onMouseDownEvent = -1;
2020
i32 onMouseUpEvent = -1;
2121
i32 onMouseHeldEvent = -1;
22+
i32 onMouseScrollEvent = -1;
2223

2324
i32 onHoverBeginEvent = -1;
2425
i32 onHoverEndEvent = -1;

Source/Game-Lib/Game-Lib/ECS/Components/UI/Panel.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace ECS::Components::UI
88
public:
99
u32 layer;
1010

11-
u32 templateIndex;
11+
i32 templateIndex = -1;
1212

1313
i32 gpuVertexIndex = -1;
1414
i32 gpuDataIndex = -1;

Source/Game-Lib/Game-Lib/ECS/Components/UI/PanelTemplate.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ namespace ECS::Components::UI
2424

2525
std::string background;
2626
std::string foreground;
27-
Color color;
28-
f32 cornerRadius;
27+
Color color = Color::White;
28+
f32 cornerRadius = 0.0f;
2929
::UI::Box texCoords;
3030
::UI::Box nineSliceCoords;
3131

Source/Game-Lib/Game-Lib/ECS/Components/UI/Text.h

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace ECS::Components::UI
66
struct Text
77
{
88
public:
9+
std::string rawText;
910
std::string text;
1011
u32 layer;
1112

Source/Game-Lib/Game-Lib/ECS/Systems/UI/HandleInput.cpp

+61
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,67 @@ namespace ECS::Systems::UI
258258
return false;
259259
});
260260

261+
keybindGroup->AddMouseScrollCallback([&registry, inputManager](f32 xPos, f32 yPos)
262+
{
263+
auto& ctx = registry.ctx();
264+
auto& uiSingleton = ctx.get<Singletons::UISingleton>();
265+
266+
vec2 mousePos = inputManager->GetMousePosition();
267+
268+
Renderer::Renderer* renderer = ServiceLocator::GetGameRenderer()->GetRenderer();
269+
const vec2& renderSize = renderer->GetRenderSize();
270+
mousePos.y = renderSize.y - mousePos.y; // Flipped because UI is bottom-left origin
271+
272+
mousePos = mousePos / renderSize;
273+
mousePos *= vec2(Renderer::Settings::UI_REFERENCE_WIDTH, Renderer::Settings::UI_REFERENCE_HEIGHT);
274+
275+
for (auto& pair : uiSingleton.allHoveredEntities)
276+
{
277+
entt::entity entity = pair.second;
278+
279+
auto* eventInputInfo = registry.try_get<Components::UI::EventInputInfo>(entity);
280+
281+
if (!eventInputInfo)
282+
{
283+
continue;
284+
}
285+
286+
auto& widget = registry.get<Components::UI::Widget>(entity);
287+
288+
i32 scrollEvent = eventInputInfo->onMouseScrollEvent;
289+
290+
bool hasInputEvent = scrollEvent != -1;
291+
292+
i32 focusBeginEvent = eventInputInfo->onFocusBeginEvent;
293+
i32 focusEndEvent = eventInputInfo->onFocusEndEvent;
294+
i32 focusHeldEvent = eventInputInfo->onFocusHeldEvent;
295+
bool isFocusable = widget.IsFocusable();
296+
bool hasFocusEvent = (focusBeginEvent != -1 || focusEndEvent != -1 || focusHeldEvent != -1) && isFocusable;
297+
298+
if (hasInputEvent)
299+
{
300+
vec2 scrollPos = vec2(xPos, yPos);
301+
ECS::Util::UI::CallLuaEvent(scrollEvent, Scripting::UI::UIInputEvent::MouseScroll, widget.scriptWidget, scrollPos);
302+
303+
if (hasFocusEvent)
304+
{
305+
ECS::Util::UI::FocusWidgetEntity(&registry, entity);
306+
}
307+
else
308+
{
309+
ECS::Util::UI::FocusWidgetEntity(&registry, entt::null);
310+
}
311+
312+
uiSingleton.clickedEntity = entity;
313+
return true;
314+
}
315+
}
316+
317+
ECS::Util::UI::FocusWidgetEntity(&registry, entt::null);
318+
319+
return false;
320+
});
321+
261322
keybindGroup->AddMouseInputValidator("MouseUIInputValidator", [&registry](i32 key, KeybindAction action, KeybindModifier modifier) -> bool
262323
{
263324
auto& ctx = registry.ctx();

Source/Game-Lib/Game-Lib/ECS/Util/UIUtil.cpp

+51-34
Original file line numberDiff line numberDiff line change
@@ -134,43 +134,47 @@ namespace ECS::Util
134134
auto& panelComp = registry->emplace<ECS::Components::UI::Panel>(entity);
135135
panelComp.layer = layer;
136136

137-
u32 templateNameHash = StringUtils::fnv1a_32(templateName, strlen(templateName));
138-
u32 templateIndex = uiSingleton.templateHashToPanelTemplateIndex[templateNameHash];
139-
panelComp.templateIndex = templateIndex;
140-
141-
const ECS::Components::UI::PanelTemplate& panelTemplate = uiSingleton.panelTemplates[templateIndex];
142-
143137
// Set this texts specific template data
144138
ECS::Components::UI::PanelTemplate& panelTemplateComp = registry->emplace<ECS::Components::UI::PanelTemplate>(entity);
145-
panelTemplateComp = panelTemplate;
139+
140+
// Copy template if provided
141+
if (templateName != nullptr)
142+
{
143+
u32 templateNameHash = StringUtils::fnv1a_32(templateName, strlen(templateName));
144+
u32 templateIndex = uiSingleton.templateHashToPanelTemplateIndex[templateNameHash];
145+
146+
const ECS::Components::UI::PanelTemplate& panelTemplate = uiSingleton.panelTemplates[templateIndex];
147+
panelTemplateComp = panelTemplate;
148+
panelComp.templateIndex = templateIndex;
149+
}
146150

147151
// Event Input Info
148152
auto& eventInputInfo = registry->emplace<ECS::Components::UI::EventInputInfo>(entity);
149153

150-
if (!panelTemplate.onClickTemplate.empty())
154+
if (!panelTemplateComp.onClickTemplate.empty())
151155
{
152-
SetTemplateEventHash(uiSingleton.templateHashToPanelTemplateIndex, templateName, panelTemplate.onClickTemplate, eventInputInfo.onClickTemplateHash);
156+
SetTemplateEventHash(uiSingleton.templateHashToPanelTemplateIndex, templateName, panelTemplateComp.onClickTemplate, eventInputInfo.onClickTemplateHash);
153157
}
154-
if (!panelTemplate.onHoverTemplate.empty())
158+
if (!panelTemplateComp.onHoverTemplate.empty())
155159
{
156-
SetTemplateEventHash(uiSingleton.templateHashToPanelTemplateIndex, templateName, panelTemplate.onHoverTemplate, eventInputInfo.onHoverTemplateHash);
160+
SetTemplateEventHash(uiSingleton.templateHashToPanelTemplateIndex, templateName, panelTemplateComp.onHoverTemplate, eventInputInfo.onHoverTemplateHash);
157161
}
158-
if (!panelTemplate.onUninteractableTemplate.empty())
162+
if (!panelTemplateComp.onUninteractableTemplate.empty())
159163
{
160-
SetTemplateEventHash(uiSingleton.templateHashToPanelTemplateIndex, templateName, panelTemplate.onUninteractableTemplate, eventInputInfo.onUninteractableTemplateHash);
164+
SetTemplateEventHash(uiSingleton.templateHashToPanelTemplateIndex, templateName, panelTemplateComp.onUninteractableTemplate, eventInputInfo.onUninteractableTemplateHash);
161165
}
162166

163-
eventInputInfo.onMouseDownEvent = panelTemplate.onMouseDownEvent;
164-
eventInputInfo.onMouseUpEvent = panelTemplate.onMouseUpEvent;
165-
eventInputInfo.onMouseHeldEvent = panelTemplate.onMouseHeldEvent;
167+
eventInputInfo.onMouseDownEvent = panelTemplateComp.onMouseDownEvent;
168+
eventInputInfo.onMouseUpEvent = panelTemplateComp.onMouseUpEvent;
169+
eventInputInfo.onMouseHeldEvent = panelTemplateComp.onMouseHeldEvent;
166170

167-
eventInputInfo.onHoverBeginEvent = panelTemplate.onHoverBeginEvent;
168-
eventInputInfo.onHoverEndEvent = panelTemplate.onHoverEndEvent;
169-
eventInputInfo.onHoverHeldEvent = panelTemplate.onHoverHeldEvent;
171+
eventInputInfo.onHoverBeginEvent = panelTemplateComp.onHoverBeginEvent;
172+
eventInputInfo.onHoverEndEvent = panelTemplateComp.onHoverEndEvent;
173+
eventInputInfo.onHoverHeldEvent = panelTemplateComp.onHoverHeldEvent;
170174

171-
eventInputInfo.onFocusBeginEvent = panelTemplate.onFocusBeginEvent;
172-
eventInputInfo.onFocusEndEvent = panelTemplate.onFocusEndEvent;
173-
eventInputInfo.onFocusHeldEvent = panelTemplate.onFocusHeldEvent;
175+
eventInputInfo.onFocusBeginEvent = panelTemplateComp.onFocusBeginEvent;
176+
eventInputInfo.onFocusEndEvent = panelTemplateComp.onFocusEndEvent;
177+
eventInputInfo.onFocusHeldEvent = panelTemplateComp.onFocusHeldEvent;
174178

175179
return entity;
176180
}
@@ -207,9 +211,10 @@ namespace ECS::Util
207211

208212
// Text
209213
auto& textComp = registry->emplace<ECS::Components::UI::Text>(entity);
210-
textComp.text = text;
214+
textComp.rawText = text;
211215
textComp.layer = layer;
212-
ReplaceTextNewLines(textComp.text);
216+
ReplaceTextNewLines(textComp.rawText);
217+
textComp.text = textComp.rawText;
213218

214219
u32 templateNameHash = StringUtils::fnv1a_32(templateName, strlen(templateName));
215220
u32 templateIndex = uiSingleton.templateHashToTextTemplateIndex[templateNameHash];
@@ -221,7 +226,7 @@ namespace ECS::Util
221226

222227
if (textTemplate.setFlags.wrapWidth)
223228
{
224-
textComp.text = GenWrapText(textComp.text, font, textTemplate.size, textTemplate.borderSize, textTemplate.wrapWidth);
229+
textComp.text = GenWrapText(textComp.rawText, font, textTemplate.size, textTemplate.borderSize, textTemplate.wrapWidth);
225230
}
226231

227232
vec2 textSize = font->CalculateTextSize(textComp.text.c_str(), textTemplate.size, textTemplate.borderSize);
@@ -267,11 +272,14 @@ namespace ECS::Util
267272
entt::entity entity = registry->create();
268273

269274
// Transform
275+
auto& parentTransformComp = registry->get<ECS::Components::Transform2D>(parent);
276+
const vec2& parentSize = parentTransformComp.GetSize();
270277
auto& transformComp = registry->emplace<ECS::Components::Transform2D>(entity);
271278

272279
transform2DSystem.ParentEntityTo(parent, entity);
273280
transform2DSystem.SetLayer(entity, layer);
274281
transform2DSystem.SetLocalPosition(entity, pos);
282+
transform2DSystem.SetSize(entity, parentSize);
275283

276284
// Widget
277285
auto& widgetComp = registry->emplace<ECS::Components::UI::Widget>(entity);
@@ -357,23 +365,23 @@ namespace ECS::Util
357365

358366
ECS::Components::UI::Text& textComponent = registry->get<ECS::Components::UI::Text>(entity);
359367

360-
size_t newLength = newText.size();
361-
362-
textComponent.sizeChanged |= newLength != textComponent.text.size();
363-
textComponent.hasGrown |= newLength > textComponent.text.size();
368+
size_t oldLength = textComponent.text.size();
364369

365370
textComponent.text = newText;
366371
ReplaceTextNewLines(textComponent.text);
367372

368-
const ECS::Components::UI::TextTemplate& textTemplate = uiSingleton.textTemplates[textComponent.templateIndex];
373+
const ECS::Components::UI::TextTemplate& textTemplate = registry->get<ECS::Components::UI::TextTemplate>(entity);
369374

370375
Renderer::Font* font = Renderer::Font::GetFont(renderer, textTemplate.font);
371376

372377
if (textTemplate.setFlags.wrapWidth)
373378
{
374-
textComponent.text = GenWrapText(textComponent.text, font, textTemplate.size, textTemplate.borderSize, textTemplate.wrapWidth);
379+
textComponent.text = GenWrapText(textComponent.rawText, font, textTemplate.size, textTemplate.borderSize, textTemplate.wrapWidth);
375380
}
376381

382+
textComponent.sizeChanged |= oldLength != textComponent.text.size();
383+
textComponent.hasGrown |= oldLength < textComponent.text.size();
384+
377385
vec2 textSize = font->CalculateTextSize(textComponent.text, textTemplate.size, textTemplate.borderSize);
378386
transform2DSystem.SetSize(entity, textSize);
379387

@@ -421,9 +429,15 @@ namespace ECS::Util
421429
auto& panel = registry->get<ECS::Components::UI::Panel>(entity);
422430
auto& panelTemplateComp = registry->get<ECS::Components::UI::PanelTemplate>(entity);
423431

424-
auto& panelTemplate = uiSingleton.panelTemplates[panel.templateIndex];
425-
426-
panelTemplateComp = panelTemplate;
432+
if (panel.templateIndex == -1)
433+
{
434+
panelTemplateComp = ECS::Components::UI::PanelTemplate();
435+
}
436+
else
437+
{
438+
auto& panelTemplate = uiSingleton.panelTemplates[panel.templateIndex];
439+
panelTemplateComp = panelTemplate;
440+
}
427441

428442
if (panelTemplateComp.setFlags.texCoords)
429443
{
@@ -622,6 +636,9 @@ namespace ECS::Util
622636
{
623637
char c = text[i];
624638

639+
if (!font->IsValidGlyph(c))
640+
continue;
641+
625642
if (c == ' ' || c == '\n')
626643
{
627644
size_t wordLength = i - wordStart;

0 commit comments

Comments
 (0)