From 679de3ae941c4610f6e841b73d2ebf79bd226a52 Mon Sep 17 00:00:00 2001 From: tobid7 Date: Fri, 3 Apr 2026 15:17:43 +0200 Subject: [PATCH] Add Input functionality to Ultra - Add point InSpace check to PD::Li::Math - Add Universal AlignmentCenter flag for Horizontal and and Vertical Alignment - Add Fallbackfont to Layout (if you dont want to set font per object) - Add Button Object WIP - Rename OnHover to OnFocus and add OnUnfocus - Move font and FontScale to ElementBase (for fallback logic etc) - Add UpdateInput func to ElementBase - Corectly Set fontScale in Text Rendering - Update ecample --- include/pd/lithium/math.hpp | 1 + include/pd/ultra/elems/button.hpp | 56 ++++++++++++++++++++++++++++++ include/pd/ultra/elems/element.hpp | 25 +++++++++++-- include/pd/ultra/elems/text.hpp | 4 --- include/pd/ultra/flags.hpp | 2 ++ include/pd/ultra/layout.hpp | 8 +++++ source/lithium/math.cpp | 5 +++ source/ultra/elems/button.cpp | 46 ++++++++++++++++++++++++ source/ultra/elems/element.cpp | 31 +++++++++++++++-- source/ultra/elems/text.cpp | 5 +-- source/ultra/layout.cpp | 1 + tests/gfx/source/main.cpp | 30 +++++++++++----- 12 files changed, 195 insertions(+), 19 deletions(-) create mode 100644 include/pd/ultra/elems/button.hpp create mode 100644 source/ultra/elems/button.cpp diff --git a/include/pd/lithium/math.hpp b/include/pd/lithium/math.hpp index 5bade85..808a5de 100644 --- a/include/pd/lithium/math.hpp +++ b/include/pd/lithium/math.hpp @@ -10,6 +10,7 @@ PD_API bool InBounds(const fvec2& pos, const fvec2& size, const fvec4& rect); PD_API bool InBounds(const fvec2& pos, const fvec4& rect); PD_API bool InBounds(const fvec2& a, const fvec2& b, const fvec2& c, const fvec4& rect); +PD_API bool InSpace(const PD::fvec2& pos, const Rect& rect); PD_API void RotateCorner(fvec2& pos, float sinus, float cosinus); PD_API Rect PrimRect(const fvec2& pos, const fvec2& size, float angle = 0.f); PD_API Rect PrimLine(const fvec2& a, const fvec2& b, int t = 1); diff --git a/include/pd/ultra/elems/button.hpp b/include/pd/ultra/elems/button.hpp new file mode 100644 index 0000000..7590b84 --- /dev/null +++ b/include/pd/ultra/elems/button.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +namespace PD { +namespace Ultra { +class PD_API Button : public ElementBase { + public: + Button() {} + Button(const PD::fvec2& pos, const PD::fvec2& size, const PD::Color& color, + float rounding = 0.f, UltraAlignment align = 0) + : pColor(color), pRounding(rounding) { + this->pAlignment = align; + this->pPos = pos; + this->pSize = size; + } + Button(float x, float y, float w, float h, const PD::Color& color, + float rounding = 0.f, UltraAlignment align = 0) + : pColor(color), pRounding(rounding) { + this->pAlignment = align; + this->pPos = PD::fvec2(x, y); + this->pSize = PD::fvec2(w, h); + } + ~Button() {} + + void Draw(PD::Li::Drawlist& l) override; + void Update() override; + void SetColor(const PD::Color& color) { pColor = color; } + void SetFocusedColor(const PD::Color& color) { pHovered = color; } + void SetTextColor(const PD::Color& color) { pTextColor = color; } + void SetRounding(float r) { pRounding = r; } + void SetLined(bool v) { pLined = v; } + void SetThickness(int v) { pThickness = v; } + void SetText(const std::string& text) { pText = text; } + void SetAutoSizePadding(const PD::fvec2& size) { pAsp = size; } + + // Discard these funcs + void OnFocus(EventFunc func) override {} + void OnUnFocus(EventFunc func) override {} + + private: + std::string pText; + PD::Color pRenderColor; + PD::Color pColor; + PD::Color pHovered; + PD::Color pTextColor; + float pRounding = 0.f; + bool pLined = false; + int pThickness = 1.f; + // Auto-Size-Padding + PD::fvec2 pAsp = PD::fvec2(30, 10); +}; +} // namespace Ultra + +} // namespace PD \ No newline at end of file diff --git a/include/pd/ultra/elems/element.hpp b/include/pd/ultra/elems/element.hpp index e186ee6..8391ac4 100644 --- a/include/pd/ultra/elems/element.hpp +++ b/include/pd/ultra/elems/element.hpp @@ -27,16 +27,32 @@ class PD_API ElementBase { void SetSize(const PD::fvec2& size) { pSize = size; } void SetSize(float w, float h) { pSize = PD::fvec2(w, h); } /** - * Executed every frame + * Executed on Hovering * Elemnents can override / discard this func */ - virtual void OnHover(EventFunc func) { pHover = func; } + virtual void OnFocus(EventFunc func) { pHover = func; } + /** + * Executed on Mocing out of the space + * Elemnents can override / discard this func + */ + virtual void OnUnFocus(EventFunc func) { pUnHover = func; } /** * Executrd on KeyUp event * Elemnents can override / discard this func */ virtual void OnPress(EventFunc func) { pPress = func; } + void SetFontScale(float s = 1.f) { pFontScale = 1.f; } + float GetFontScale() const { return pFontScale; } + + void SetFont(PD::Li::Font& font) { pFont = &font; } + + void SetFontIfNull(PD::Li::Font& font) { + if (!pFont) pFont = &font; + } + + virtual void UpdateInput(); + protected: friend class Container; void SetParent(Container* c) { pParent = c; } @@ -48,7 +64,12 @@ class PD_API ElementBase { PD::fvec2 pSize; PD::Li::Rect pRenderspace; EventFunc pHover = nullptr; + EventFunc pUnHover = nullptr; EventFunc pPress = nullptr; + bool pFocued = false; + // Not used by every object btw + PD::Li::Font* pFont = nullptr; + float pFontScale = 1.f; }; } // namespace Ultra } // namespace PD \ No newline at end of file diff --git a/include/pd/ultra/elems/text.hpp b/include/pd/ultra/elems/text.hpp index 148dd01..e5bc315 100644 --- a/include/pd/ultra/elems/text.hpp +++ b/include/pd/ultra/elems/text.hpp @@ -15,14 +15,10 @@ class PD_API Text : public ElementBase { void SetColor(const PD::Color& color) { pColor = color; } void SetText(const std::string& text) { pText = text; } - void SetFont(PD::Li::Font& font) { pFont = &font; } - void SetScale(float scale) { pScale = scale; } private: PD::Color pColor; - float pScale = 1.f; std::string pText; - PD::Li::Font* pFont = nullptr; }; } // namespace Ultra diff --git a/include/pd/ultra/flags.hpp b/include/pd/ultra/flags.hpp index 7014e41..34e1113 100644 --- a/include/pd/ultra/flags.hpp +++ b/include/pd/ultra/flags.hpp @@ -15,4 +15,6 @@ enum UltraAlignment_ { UltraAlignment_TopRight = UltraAlignment_Top | UltraAlignment_Right, UltraAlignment_BotLeft = UltraAlignment_Bot | UltraAlignment_Left, UltraAlignment_BotRight = UltraAlignment_Bot | UltraAlignment_Right, + UltraAlignment_Center = + UltraAlignment_CenterVertical | UltraAlignment_CenterHorizontal, }; \ No newline at end of file diff --git a/include/pd/ultra/layout.hpp b/include/pd/ultra/layout.hpp index df665c0..cd17920 100644 --- a/include/pd/ultra/layout.hpp +++ b/include/pd/ultra/layout.hpp @@ -11,7 +11,15 @@ class PD_API Layout : public Container { Layout() {} ~Layout() {} + /** + * Set a fallback font if you dont want to explicitly set a font for every + * objectt individually + */ + void SetFont(PD::Li::Font& font) { pFont = &font; } void Render(PD::Li::Drawlist& list); + + private: + PD::Li::Font* pFont = nullptr; }; } // namespace Ultra } // namespace PD \ No newline at end of file diff --git a/source/lithium/math.cpp b/source/lithium/math.cpp index 1417320..eddfb6b 100644 --- a/source/lithium/math.cpp +++ b/source/lithium/math.cpp @@ -20,6 +20,11 @@ PD_API bool InBounds(const fvec2& a, const fvec2& b, const fvec2& c, (a.x > 0 && b.x > 0 && c.x > 0) || (a.y > 0 && b.y > 0 && c.y > 0)); } +PD_API bool InSpace(const PD::fvec2& pos, const Rect& rect) { + return (pos.x > rect.Top.x && pos.x < rect.Top.z && pos.y > rect.Top.y && + pos.y < rect.Bot.y); +} + PD_API void RotateCorner(fvec2& pos, float sinus, float cosinus) { float x = pos.x * cosinus - pos.y * sinus; float y = pos.y * cosinus - pos.x * sinus; diff --git a/source/ultra/elems/button.cpp b/source/ultra/elems/button.cpp new file mode 100644 index 0000000..90616c5 --- /dev/null +++ b/source/ultra/elems/button.cpp @@ -0,0 +1,46 @@ +#include +#include +#include + +namespace PD { +namespace Ultra { +PD_API void Button::Draw(PD::Li::Drawlist& l) { + float r = pRounding; + if (pParent) r = pParent->GetCanvas().VTranslateSize(r).x; + l.PathRect(pRenderspace.TopLeft(), pRenderspace.BotRight(), r); + if (pLined) { + l.PathStroke(pRenderColor, pThickness, LiDrawFlags_Close); + } else { + l.PathFill(pRenderColor); + } + if (!pFont) return; // discard here if we dont have a font + PD::fvec2 off = 0.f; + if (pParent) off = pParent->GetCanvas().VTranslateSize(pAsp) * 0.5; + l.SetFont(pFont); + l.SetFontscale(pParent->GetCanvas().VTranslateFontscale(pFontScale)); + l.DrawText(pRenderspace.TopLeft() + off, pText.c_str(), pTextColor); +} + +PD_API void Button::Update() { + pRenderColor = pColor; + if (!pParent || !pFont) ElementBase::Update(); + PD::fvec2 size = pSize; + if (size == PD::fvec2(0)) { + size = pFont->GetTextBounds( + pText.c_str(), + pParent->GetCanvas().VTranslateFontscale(pFontScale)) + + pParent->GetCanvas().VTranslateSize(pAsp); + } else { + size = pParent->GetCanvas().VTranslateSize(size); + } + pRenderspace = pParent->GetCanvas().VTranslateObject( + pParent->GetTopLeft() + pPos, size, pAlignment, true); + if (PD::Li::Math::InSpace(PD::Hid::MousePos(), pRenderspace)) { + pRenderColor = pHovered; + } else { + pRenderColor = pColor; + } + UpdateInput(); +} +} // namespace Ultra +} // namespace PD \ No newline at end of file diff --git a/source/ultra/elems/element.cpp b/source/ultra/elems/element.cpp index b86fc8b..1b32568 100644 --- a/source/ultra/elems/element.cpp +++ b/source/ultra/elems/element.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -12,11 +13,35 @@ PD_API bool ElementBase::RevisionUpdate(PD::u32 req) { } } PD_API void ElementBase::Update() { - if (!pParent) pRenderspace = PD::fvec4(pPos, pPos + pSize); - pRenderspace = pParent->GetCanvas().VTranslateObject( - pParent->GetTopLeft() + pPos, pSize, pAlignment); + if (!pParent) + pRenderspace = PD::fvec4(pPos, pPos + pSize); + else + pRenderspace = pParent->GetCanvas().VTranslateObject( + pParent->GetTopLeft() + pPos, pSize, pAlignment); + UpdateInput(); /*pRenderspace = PD::fvec4(pParent->GetTopLeft() + pPos, pParent->GetTopLeft() + pPos + pSize);*/ } + +PD_API void ElementBase::UpdateInput() { + if (PD::Li::Math::InSpace( + PD::Hid::MousePos(), + PD::fvec4(pRenderspace.TopLeft(), pRenderspace.BotRight()))) { + if (pHover && !pFocued) { + pHover(); + pFocued = true; + } + if (PD::Hid::IsEvent(PD::Hid::Event::Up, PD::Hid::Gamepad::Touch)) { + if (pPress) { + pPress(); + } + } + } else { + if (pUnHover && pFocued) { + pUnHover(); + pFocued = false; + } + } +} } // namespace Ultra } // namespace PD \ No newline at end of file diff --git a/source/ultra/elems/text.cpp b/source/ultra/elems/text.cpp index 08472d1..c75290f 100644 --- a/source/ultra/elems/text.cpp +++ b/source/ultra/elems/text.cpp @@ -6,6 +6,7 @@ namespace Ultra { PD_API void Text::Draw(PD::Li::Drawlist& l) { if (!pFont) return; l.SetFont(pFont); + l.SetFontscale(pParent->GetCanvas().VTranslateFontscale(pFontScale)); l.DrawText(pRenderspace.TopLeft(), pText.c_str(), pColor); } @@ -14,8 +15,8 @@ PD_API void Text::Update() { if (!pParent) ElementBase::Update(); pRenderspace = pParent->GetCanvas().VTranslateObject( pParent->GetTopLeft() + pPos, - pFont->GetTextBounds(pText.c_str(), - pParent->GetCanvas().VTranslateFontscale(pScale)), + pFont->GetTextBounds( + pText.c_str(), pParent->GetCanvas().VTranslateFontscale(pFontScale)), pAlignment, true); } } // namespace Ultra diff --git a/source/ultra/layout.cpp b/source/ultra/layout.cpp index 737c25e..70ae232 100644 --- a/source/ultra/layout.cpp +++ b/source/ultra/layout.cpp @@ -7,6 +7,7 @@ PD_API void Layout::Render(PD::Li::Drawlist& list) { float fc = list.GetFontScale(); list.SetFontscale(GetCanvas().VTranslateFontscale(fc)); for (auto& it : GetElements()) { + it->SetFontIfNull(*pFont); it->Update(); it->Draw(list); } diff --git a/tests/gfx/source/main.cpp b/tests/gfx/source/main.cpp index b47db88..6fca03b 100644 --- a/tests/gfx/source/main.cpp +++ b/tests/gfx/source/main.cpp @@ -4,10 +4,13 @@ #include //// +#include +#include #include #include #include #include + //// PD::OsCtx* pOs = nullptr; @@ -25,24 +28,36 @@ const char* ResourcePath(const char* in) { class MainMenu : public PD::Ultra::Layout { public: MainMenu(PD::Li::Font& font) { + SetFont(font); SetBaseViewport(PD::ivec2(1280, 720)); pBackground.SetSize(800, 450); - pBackground.SetColor(PD::Color("#ffffffff")); + pBackground.SetColor("#ffffffff"); pBackground.SetAlignment(UltraAlignment_CenterHorizontal | UltraAlignment_CenterVertical); Push(pBackground); - pText.SetColor(PD::Color("#000000")); - pText.SetText("Hello World"); - pText.SetAlignment(UltraAlignment_CenterHorizontal | - UltraAlignment_CenterVertical); - pText.SetFont(font); + pText.SetColor("#ffffff"); + pText.SetText("MousePos: "); + pText.SetAlignment(UltraAlignment_TopLeft); Push(pText); + pBtn.SetText("Test"); + pBtn.SetAlignment(UltraAlignment_Center); + pBtn.SetColor("#1273fb"); + pBtn.SetFocusedColor("#0011ff"); + pBtn.SetTextColor("#ffffff"); + pBtn.SetRounding(10); + pBtn.OnPress([]() { PD::Log("Btn Pressed..."); }); + Push(pBtn); } ~MainMenu() {} + void Update() { + pText.SetText(std::format("MousePos: {}", PD::Hid::MousePos())); + } + private: PD::Ultra::Rect pBackground; PD::Ultra::Text pText; + PD::Ultra::Button pBtn; }; class App { @@ -51,6 +66,7 @@ class App { ~App() {} void Update(PD::ivec2 vp, PD::Li::Drawlist& list) { + main.Update(); main.SetViewport(vp); main.Render(list); } @@ -92,8 +108,6 @@ int main(int argc, char** argv) { pOs->ClearViewPort(); PD::Li::ResetPools(); // Move to other place (or refactor this) app.Update(pOs->GetViewport(), pList); - pList.DrawText(5, std::format("Mouse: {}", PD::Hid::MousePos()).c_str(), - PD::Color("#ffffffff")); PD::Gfx::Reset(); PD::Gfx::Draw(pList); pList.Clear();