Skip to content

Commit f087e2e

Browse files
authored
Add a basic chat (#52)
Add chat Add IsCapturingMouse function to CameraUtil Add entt InputSingleton with global non-widget specific keyboard events Fix some text wrapping issues Add RefreshClipper function to UIUtil Add WasJustFocusedWidget and AddOnKeyboard Luau functions to UI namespace Fix issue with Luau stack on UIHandler event calls Add GetFontSize, SetFontSize, GetWidth, GetHeight, GetWrapIndent, SetWrapIndent functions to Text widget Add ForceRefresh function to Widget and Button widget Add autoScrollToStart and fillFromBottom settings to Scrollbox widget Add global listener to open escape menu when pressing escape TODO: Still needs server functionality
1 parent 0a72568 commit f087e2e

File tree

24 files changed

+1114
-236
lines changed

24 files changed

+1114
-236
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace ECS::Components::UI
1717
u8 borderSize : 1 = 0;
1818
u8 borderColor : 1 = 0;
1919
u8 wrapWidth : 1 = 0;
20+
u8 wrapIndent : 1 = 0;
2021
};
2122
SetFlags setFlags;
2223

@@ -26,6 +27,7 @@ namespace ECS::Components::UI
2627
f32 borderSize;
2728
Color borderColor;
2829
f32 wrapWidth;
30+
u8 wrapIndent = 0;
2931

3032
std::string onClickTemplate;
3133
std::string onHoverTemplate;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
#include <Base/Types.h>
3+
#include <Base/Memory/StackAllocator.h>
4+
5+
#include <robinhood/robinhood.h>
6+
#include <entt/entt.hpp>
7+
#include <map>
8+
9+
namespace ECS::Singletons
10+
{
11+
struct InputSingleton
12+
{
13+
public:
14+
InputSingleton() {}
15+
16+
// Input handling for scripts
17+
std::vector<i32> globalKeyboardEvents;
18+
19+
robin_hood::unordered_map<u32, u32> eventIDToKeyboardEventIndex; // Maps event ID to index in globalKeyboardEvents
20+
};
21+
}

Source/Game-Lib/Game-Lib/ECS/Singletons/UISingleton.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace ECS::Singletons
3131
entt::entity clickedEntity = entt::null;
3232
entt::entity hoveredEntity = entt::null;
3333
entt::entity focusedEntity = entt::null;
34+
entt::entity justFocusedEntity = entt::null; // If it was just focused this frame
3435
entt::entity cursorCanvasEntity = entt::null;
3536

3637
// Cursor canvas

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
#include "Game-Lib/ECS/Components/UI/EventInputInfo.h"
77
#include "Game-Lib/ECS/Components/UI/Panel.h"
88
#include "Game-Lib/ECS/Components/UI/Widget.h"
9+
#include "Game-Lib/ECS/Singletons/InputSingleton.h"
910
#include "Game-Lib/ECS/Singletons/UISingleton.h"
11+
#include "Game-Lib/ECS/Util/CameraUtil.h"
1012
#include "Game-Lib/ECS/Util/UIUtil.h"
1113
#include "Game-Lib/ECS/Util/Transform2D.h"
1214
#include "Game-Lib/Rendering/Debug/DebugRenderer.h"
@@ -348,9 +350,7 @@ namespace ECS::Systems::UI
348350
return false;
349351
}
350352

351-
ECS::Util::UI::CallUnicodeEvent(eventInputInfo->onKeyboardEvent, widget->scriptWidget, unicode);
352-
353-
return true;
353+
return ECS::Util::UI::CallUnicodeEvent(eventInputInfo->onKeyboardEvent, widget->scriptWidget, unicode);
354354
}
355355

356356
return false;
@@ -360,7 +360,8 @@ namespace ECS::Systems::UI
360360
{
361361
auto& ctx = registry.ctx();
362362
auto* uiSingleton = ctx.find<Singletons::UISingleton>();
363-
if (!uiSingleton)
363+
auto* inputSingleton = ctx.find<Singletons::InputSingleton>();
364+
if (!uiSingleton || !inputSingleton)
364365
return false;
365366

366367
if (uiSingleton->focusedEntity != entt::null)
@@ -372,9 +373,21 @@ namespace ECS::Systems::UI
372373
return false;
373374
}
374375

375-
ECS::Util::UI::CallKeyboardEvent(eventInputInfo->onKeyboardEvent, widget->scriptWidget, key, static_cast<i32>(action), static_cast<i32>(modifier));
376-
377-
return true;
376+
if (ECS::Util::UI::CallKeyboardEvent(eventInputInfo->onKeyboardEvent, widget->scriptWidget, key, static_cast<i32>(action), static_cast<i32>(modifier)))
377+
{
378+
return true;
379+
}
380+
}
381+
382+
if (!ECS::Util::CameraUtil::IsCapturingMouse())
383+
{
384+
for (i32 keyboardEvent : inputSingleton->globalKeyboardEvents)
385+
{
386+
if (ECS::Util::UI::CallKeyboardEvent(keyboardEvent, key, static_cast<i32>(action), static_cast<i32>(modifier)))
387+
{
388+
return true;
389+
}
390+
}
378391
}
379392

380393
return false;
@@ -654,5 +667,7 @@ namespace ECS::Systems::UI
654667
ECS::Util::UI::CallLuaEvent(eventInputInfo->onFocusHeldEvent, Scripting::UI::UIInputEvent::FocusHeld, widget.scriptWidget, deltaTime);
655668
}
656669
}
670+
671+
uiSingleton.justFocusedEntity = entt::null;
657672
}
658673
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ namespace ECS::Util
6565
}
6666
}
6767

68+
bool IsCapturingMouse()
69+
{
70+
entt::registry* registry = ServiceLocator::GetEnttRegistries()->gameRegistry;
71+
entt::registry::context& ctx = registry->ctx();
72+
73+
auto& activeCamera = ctx.get<ECS::Singletons::ActiveCamera>();
74+
auto& freeFlyingCameraSettings = ctx.get<ECS::Singletons::FreeflyingCameraSettings>();
75+
auto& orbitalCameraSettings = ctx.get<ECS::Singletons::OrbitalCameraSettings>();
76+
77+
if (activeCamera.entity == freeFlyingCameraSettings.entity)
78+
{
79+
return freeFlyingCameraSettings.captureMouse;
80+
}
81+
else if (activeCamera.entity == orbitalCameraSettings.entity)
82+
{
83+
return orbitalCameraSettings.captureMouse;
84+
}
85+
86+
return false;
87+
}
88+
6889
void CenterOnObject(const vec3& position, f32 radius)
6990
{
7091
entt::registry* registry = ServiceLocator::GetEnttRegistries()->gameRegistry;

Source/Game-Lib/Game-Lib/ECS/Util/CameraUtil.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace ECS::Util
66
namespace CameraUtil
77
{
88
void SetCaptureMouse(bool capture);
9+
bool IsCapturingMouse();
910
void CenterOnObject(const vec3& position, f32 radius);
1011
}
1112
}

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

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ namespace ECS::Util
245245

246246
if (textTemplate.setFlags.wrapWidth)
247247
{
248-
textComp.text = GenWrapText(textComp.rawText, font, textTemplate.size, textTemplate.borderSize, textTemplate.wrapWidth);
248+
textComp.text = GenWrapText(textComp.rawText, font, textTemplate.size, textTemplate.borderSize, textTemplate.wrapWidth, textTemplate.wrapIndent);
249249
}
250250

251251
vec2 textSize = font->CalculateTextSize(textComp.text.c_str(), textTemplate.size, textTemplate.borderSize);
@@ -339,6 +339,8 @@ namespace ECS::Util
339339
}
340340
}
341341

342+
uiSingleton.justFocusedEntity = uiSingleton.focusedEntity;
343+
342344
entt::entity oldFocus = uiSingleton.focusedEntity;
343345
if (oldFocus != entt::null)
344346
{
@@ -395,7 +397,7 @@ namespace ECS::Util
395397

396398
if (textTemplate.setFlags.wrapWidth)
397399
{
398-
textComponent.text = GenWrapText(textComponent.rawText, font, textTemplate.size, textTemplate.borderSize, textTemplate.wrapWidth);
400+
textComponent.text = GenWrapText(textComponent.rawText, font, textTemplate.size, textTemplate.borderSize, textTemplate.wrapWidth, textTemplate.wrapIndent);
399401
}
400402

401403
textComponent.sizeChanged |= oldLength != textComponent.text.size();
@@ -439,6 +441,25 @@ namespace ECS::Util
439441
registry->emplace_or_replace<ECS::Components::UI::DirtyCanvasTag>(widget.scriptWidget->canvasEntity);
440442
}
441443

444+
void RefreshClipper(entt::registry* registry, entt::entity entity)
445+
{
446+
auto* clipper = registry->try_get<ECS::Components::UI::Clipper>(entity);
447+
448+
if (clipper == nullptr)
449+
return;
450+
451+
if (clipper->clipRegionOverrideEntity == entt::null)
452+
{
453+
registry->emplace_or_replace<ECS::Components::UI::DirtyWidgetClipper>(entity);
454+
registry->emplace_or_replace<ECS::Components::UI::DirtyChildClipper>(entity);
455+
}
456+
else
457+
{
458+
registry->emplace_or_replace<ECS::Components::UI::DirtyWidgetClipper>(clipper->clipRegionOverrideEntity);
459+
registry->emplace_or_replace<ECS::Components::UI::DirtyChildClipper>(clipper->clipRegionOverrideEntity);
460+
}
461+
}
462+
442463
void ResetTemplate(entt::registry* registry, entt::entity entity)
443464
{
444465
auto& ctx = registry->ctx();
@@ -614,25 +635,34 @@ namespace ECS::Util
614635
uiHandler->CallUIInputEvent(state, eventRef, inputEvent, widget, value);
615636
}
616637

617-
void CallKeyboardEvent(i32 eventRef, Scripting::UI::Widget* widget, i32 key, i32 actionMask, i32 modifierMask)
638+
bool CallKeyboardEvent(i32 eventRef, Scripting::UI::Widget* widget, i32 key, i32 actionMask, i32 modifierMask)
618639
{
619640
Scripting::LuaManager* luaManager = ServiceLocator::GetLuaManager();
620641
lua_State* state = luaManager->GetInternalState();
621642

622643
Scripting::UI::UIHandler* uiHandler = luaManager->GetLuaHandler<Scripting::UI::UIHandler*>(Scripting::LuaHandlerType::UI);
623-
uiHandler->CallKeyboardInputEvent(state, eventRef, widget, key, actionMask, modifierMask);
644+
return uiHandler->CallKeyboardInputEvent(state, eventRef, widget, key, actionMask, modifierMask);
624645
}
625646

626-
void CallUnicodeEvent(i32 eventRef, Scripting::UI::Widget* widget, u32 unicode)
647+
bool CallKeyboardEvent(i32 eventRef, i32 key, i32 actionMask, i32 modifierMask)
627648
{
628649
Scripting::LuaManager* luaManager = ServiceLocator::GetLuaManager();
629650
lua_State* state = luaManager->GetInternalState();
630651

631652
Scripting::UI::UIHandler* uiHandler = luaManager->GetLuaHandler<Scripting::UI::UIHandler*>(Scripting::LuaHandlerType::UI);
632-
uiHandler->CallKeyboardUnicodeEvent(state, eventRef, widget, unicode);
653+
return uiHandler->CallKeyboardInputEvent(state, eventRef, key, actionMask, modifierMask);
654+
}
655+
656+
bool CallUnicodeEvent(i32 eventRef, Scripting::UI::Widget* widget, u32 unicode)
657+
{
658+
Scripting::LuaManager* luaManager = ServiceLocator::GetLuaManager();
659+
lua_State* state = luaManager->GetInternalState();
660+
661+
Scripting::UI::UIHandler* uiHandler = luaManager->GetLuaHandler<Scripting::UI::UIHandler*>(Scripting::LuaHandlerType::UI);
662+
return uiHandler->CallKeyboardUnicodeEvent(state, eventRef, widget, unicode);
633663
}
634664

635-
std::string GenWrapText(const std::string& text, Renderer::Font* font, f32 fontSize, f32 borderSize, f32 maxWidth)
665+
std::string GenWrapText(const std::string& text, Renderer::Font* font, f32 fontSize, f32 borderSize, f32 maxWidth, u8 indents)
636666
{
637667
// Early exit if entire text fits within maxWidth
638668
f32 totalWidth = 0;
@@ -658,6 +688,8 @@ namespace ECS::Util
658688
std::string buffer; // Batch write buffer
659689
buffer.reserve(text.size() + text.size() / 4); // Reserve for buffer to minimize reallocations
660690

691+
f32 indentWidth = font->CalculateCharWidth(' ', fontSize, borderSize);
692+
661693
for (size_t i = 0; i < text.length(); ++i)
662694
{
663695
char c = text[i];
@@ -669,10 +701,17 @@ namespace ECS::Util
669701
{
670702
size_t wordLength = i - wordStart;
671703

704+
// Line is longer than maxWidth, wrap it
672705
if (currentLineWidth + currentWordWidth > maxWidth)
673706
{
674707
buffer += '\n';
675708
currentLineWidth = 0;
709+
710+
for(u8 j = 0; j < indents; ++j)
711+
{
712+
buffer += ' '; // Add indentation
713+
currentLineWidth += indentWidth;
714+
}
676715
}
677716

678717
buffer.append(text, wordStart, wordLength);
@@ -681,12 +720,18 @@ namespace ECS::Util
681720
if (c == ' ')
682721
{
683722
buffer += ' ';
684-
currentLineWidth += font->CalculateCharWidth(c, fontSize, borderSize);
723+
currentLineWidth += indentWidth;
685724
}
686725
else // Newline
687726
{
688727
buffer += '\n';
689728
currentLineWidth = 0;
729+
730+
for (u8 j = 0; j < indents; ++j)
731+
{
732+
buffer += ' '; // Add indentation
733+
currentLineWidth += indentWidth;
734+
}
690735
}
691736

692737
wordStart = i + 1;
@@ -697,23 +742,34 @@ namespace ECS::Util
697742
currentWordWidth += font->CalculateCharWidth(c, fontSize, borderSize);
698743

699744
// Force break for long words
700-
if (currentWordWidth > maxWidth)
745+
if (currentLineWidth + currentWordWidth > maxWidth)
701746
{
702747
buffer.append(text, wordStart, i - wordStart);
703748
buffer += '\n';
704749
wordStart = i;
705750
currentWordWidth = font->CalculateCharWidth(c, fontSize, borderSize);
706751
currentLineWidth = currentWordWidth;
752+
753+
for (u8 j = 0; j < indents; ++j)
754+
{
755+
buffer += ' '; // Add indentation
756+
currentLineWidth += indentWidth;
757+
}
707758
}
708759
}
709760
}
710761

711-
// Handle the last word
762+
// Handle the last word if we are force breaking
712763
if (wordStart < text.length())
713764
{
714765
if (currentLineWidth + currentWordWidth > maxWidth)
715766
{
716767
buffer += '\n';
768+
769+
for (u8 j = 0; j < indents; ++j)
770+
{
771+
buffer += ' '; // Add indentation
772+
}
717773
}
718774
buffer.append(text, wordStart, text.length() - wordStart);
719775
}

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace ECS::Util
3838

3939
void RefreshText(entt::registry* registry, entt::entity entity, std::string_view newText);
4040
void RefreshTemplate(entt::registry* registry, entt::entity entity, ECS::Components::UI::EventInputInfo& eventInputInfo);
41+
void RefreshClipper(entt::registry* registry, entt::entity entity);
4142

4243
void ResetTemplate(entt::registry* registry, entt::entity entity); // Sets it back to base
4344
void ApplyTemplateAdditively(entt::registry* registry, entt::entity entity, u32 templateHash);
@@ -48,10 +49,11 @@ namespace ECS::Util
4849
void CallLuaEvent(i32 eventRef, Scripting::UI::UIInputEvent inputEvent, Scripting::UI::Widget* widget, f32 value);
4950
void CallLuaEvent(i32 eventRef, Scripting::UI::UIInputEvent inputEvent, Scripting::UI::Widget* widget, vec2 value);
5051

51-
void CallKeyboardEvent(i32 eventRef, Scripting::UI::Widget* widget, i32 key, i32 actionMask, i32 modifierMask);
52-
void CallUnicodeEvent(i32 eventRef, Scripting::UI::Widget* widget, u32 unicode);
52+
bool CallKeyboardEvent(i32 eventRef, Scripting::UI::Widget* widget, i32 key, i32 actionMask, i32 modifierMask);
53+
bool CallKeyboardEvent(i32 eventRef, i32 key, i32 actionMask, i32 modifierMask);
54+
bool CallUnicodeEvent(i32 eventRef, Scripting::UI::Widget* widget, u32 unicode);
5355

54-
std::string GenWrapText(const std::string& text, Renderer::Font* font, f32 fontSize, f32 borderSize, f32 maxWidth);
56+
std::string GenWrapText(const std::string& text, Renderer::Font* font, f32 fontSize, f32 borderSize, f32 maxWidth, u8 indents);
5557
void ReplaceTextNewLines(std::string& input);
5658
}
5759
}

Source/Game-Lib/Game-Lib/Rendering/Canvas/CanvasRenderer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ void CanvasRenderer::CreatePermanentResources()
514514

515515
// Blending
516516
pipelineDesc.states.blendState.renderTargets[0].blendEnable = true;
517-
pipelineDesc.states.blendState.renderTargets[0].srcBlend = Renderer::BlendMode::ONE;
517+
pipelineDesc.states.blendState.renderTargets[0].srcBlend = Renderer::BlendMode::SRC_ALPHA;
518518
pipelineDesc.states.blendState.renderTargets[0].destBlend = Renderer::BlendMode::INV_SRC_ALPHA;
519519
pipelineDesc.states.blendState.renderTargets[0].srcBlendAlpha = Renderer::BlendMode::ONE;
520520
pipelineDesc.states.blendState.renderTargets[0].destBlendAlpha = Renderer::BlendMode::INV_SRC_ALPHA;
@@ -543,7 +543,7 @@ void CanvasRenderer::CreatePermanentResources()
543543

544544
// Blending
545545
pipelineDesc.states.blendState.renderTargets[0].blendEnable = true;
546-
pipelineDesc.states.blendState.renderTargets[0].srcBlend = Renderer::BlendMode::ONE;
546+
pipelineDesc.states.blendState.renderTargets[0].srcBlend = Renderer::BlendMode::SRC_ALPHA;
547547
pipelineDesc.states.blendState.renderTargets[0].destBlend = Renderer::BlendMode::INV_SRC_ALPHA;
548548
pipelineDesc.states.blendState.renderTargets[0].srcBlendAlpha = Renderer::BlendMode::ONE;
549549
pipelineDesc.states.blendState.renderTargets[0].destBlendAlpha = Renderer::BlendMode::INV_SRC_ALPHA;

0 commit comments

Comments
 (0)