16 Commits
Author SHA1 Message Date
tobid7 6547f64d13 fix resize sym 2026-09-18 22:11:08 +02:00
tobid7 2b37204763 remove Font::LoadDefaultFont 2026-09-17 21:35:19 +02:00
tobid7 8c2bcedc93 Testing around 2026-09-16 21:20:45 +02:00
tobid7 01d3eb771e remove the 3ds ifdefs out of the core mat lib
need to find a way to handle mtx stuff in the gfx driver or another way
2026-09-15 07:20:00 +02:00
tobid7 6de3683818 3ds: move ui7 to bottom screne 2026-09-13 14:10:07 +02:00
tobid7 ec49f70c0b Add more gfx backend flags (available features) 2026-09-13 01:24:55 +02:00
tobid7 6284ff885d citro3d: clipping 2026-09-13 01:06:23 +02:00
tobid7 91c245c1a6 dx9 clipping 2026-09-12 17:29:48 +02:00
tobid7 c828166ce4 refactor UI7 clipping 2026-09-10 07:55:37 +02:00
tobid7 c7816ea170 fix close sym 2026-09-09 22:03:19 +02:00
tobid7 0dbf430c0c Implement clipping 2026-09-08 21:15:21 +02:00
tobid7 aec9083ebb small fixes 2026-09-07 22:05:51 +02:00
tobid7 9e6c6fd84d Merge dev-0.7-rewrite into stable 2026-09-06 16:23:08 +02:00
tobid7 0501a4f87c Make UI7::IO::CurrentViewPort a Reference (finally) 2026-03-18 21:33:35 +01:00
tobid7 3d8b57ead6 add .gitattributes file 2026-03-16 20:28:30 +01:00
tobid7 ac37ce9e12 Fix test 2026-03-14 21:15:40 +01:00
31 changed files with 978 additions and 802 deletions
+1 -1
View File
@@ -1 +1 @@
vendor/* linguist-vendored vendor/* linguist-vendored
@@ -29,6 +29,7 @@ class GfxCitro3D : public GfxDriverBase<GfxCitro3DConfig> {
TextureFilter filter = TextureFilter::Linear) override; TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override; void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override; void UploadPools() override;
void ClipRect() override;
private: private:
struct Impl; struct Impl;
@@ -29,6 +29,7 @@ class GfxDirectX9 : public GfxDriverBase<GfxDirectX9Config> {
TextureFilter filter = TextureFilter::Linear) override; TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override; void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override; void UploadPools() override;
void ClipRect() override;
private: private:
struct Impl; struct Impl;
@@ -28,6 +28,7 @@ class GfxOpenGL2 : public GfxDriverBase<GfxOpenGL2Config> {
TextureFilter filter = TextureFilter::Linear) override; TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override; void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override; void UploadPools() override;
void ClipRect() override;
private: private:
void pSetupShaderAttribs(u32 shader); void pSetupShaderAttribs(u32 shader);
@@ -28,6 +28,7 @@ class GfxOpenGL3 : public GfxDriverBase<GfxOpenGL3Config> {
TextureFilter filter = TextureFilter::Linear) override; TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override; void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override; void UploadPools() override;
void ClipRect() override;
private: private:
u32 pShader = 0; u32 pShader = 0;
+12
View File
@@ -141,6 +141,9 @@ void GfxCitro3D::SysInit() {
PDLOG("GfxCitro3D::SysInit();"); PDLOG("GfxCitro3D::SysInit();");
impl = new Impl(); impl = new Impl();
Flags |= PDGfxBackendFlags_FlipUV_Y; Flags |= PDGfxBackendFlags_FlipUV_Y;
Flags |= PDGfxBackendFlags_HasClipRect;
Flags |= PDGfxBackendFlags_ReqPow2;
Flags |= PDGfxBackendFlags_ApproxSDF;
impl->pShaderRaw = Pica::AssembleCode(LIShaderCTR); impl->pShaderRaw = Pica::AssembleCode(LIShaderCTR);
impl->pCode = DVLB_ParseFile((uint32_t*)impl->pShaderRaw.data(), impl->pCode = DVLB_ParseFile((uint32_t*)impl->pShaderRaw.data(),
impl->pShaderRaw.size()); impl->pShaderRaw.size());
@@ -264,6 +267,14 @@ void GfxCitro3D::UploadPools() {
BufInfo_Init(buf); BufInfo_Init(buf);
BufInfo_Add(buf, GetVertexBufPtr(0), sizeof(Li::Vertex), 3, 0x210); BufInfo_Add(buf, GetVertexBufPtr(0), sizeof(Li::Vertex), 3, 0x210);
} }
void GfxCitro3D::ClipRect() {
// This is so cursed but it works
C3D_SetScissor(CurrentHasClip ? GPU_SCISSOR_NORMAL : GPU_SCISSOR_DISABLE,
ViewPort.y - CurrentClip.w - CurrentClip.y,
ViewPort.x - CurrentClip.z - CurrentClip.x,
ViewPort.y - CurrentClip.y, ViewPort.x - CurrentClip.x);
}
} // namespace PD } // namespace PD
#else #else
namespace PD { namespace PD {
@@ -283,5 +294,6 @@ Li::Texture GfxCitro3D::LoadTexture(const std::vector<PD::u8>& pixels, int w,
} }
void GfxCitro3D::DeleteTexture(const Li::Texture& tex) {} void GfxCitro3D::DeleteTexture(const Li::Texture& tex) {}
void GfxCitro3D::UploadPools() {} void GfxCitro3D::UploadPools() {}
void GfxCitro3D::ClipRect() {}
} // namespace PD } // namespace PD
#endif #endif
+17
View File
@@ -112,6 +112,7 @@ void GfxDirectX9::SysInit() {
} }
if (psBlob) psBlob->Release(); if (psBlob) psBlob->Release();
if (errBlob) errBlob->Release(); if (errBlob) errBlob->Release();
Flags |= PDGfxBackendFlags_HasClipRect;
} else { } else {
PDERR( PDERR(
"GfxDirectX9::SysInit Error: pDevice is not set!\nYOu need to include " "GfxDirectX9::SysInit Error: pDevice is not set!\nYOu need to include "
@@ -285,6 +286,21 @@ void GfxDirectX9::UploadPools() {
memcpy(iptr, GetIndexBufPtr(0), GetIndexPoolSize() * sizeof(u16)); memcpy(iptr, GetIndexBufPtr(0), GetIndexPoolSize() * sizeof(u16));
impl->IBO->Unlock(); impl->IBO->Unlock();
} }
void GfxDirectX9::ClipRect() {
if (CurrentHasClip) {
RECT r;
r.left = CurrentClip.x;
r.top = CurrentClip.y;
r.right = CurrentClip.x + CurrentClip.z;
r.bottom = CurrentClip.y + CurrentClip.w;
impl->Device->SetScissorRect(&r);
impl->Device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
} else {
impl->Device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
}
}
} // namespace PD } // namespace PD
#else #else
namespace PD { namespace PD {
@@ -304,5 +320,6 @@ Li::Texture GfxDirectX9::LoadTexture(const std::vector<PD::u8>& pixels, int w,
} }
void GfxDirectX9::DeleteTexture(const Li::Texture& tex) {} void GfxDirectX9::DeleteTexture(const Li::Texture& tex) {}
void GfxDirectX9::UploadPools() {} void GfxDirectX9::UploadPools() {}
void GfxDirectX9::ClipRect() {}
} // namespace PD } // namespace PD
#endif #endif
+12
View File
@@ -73,6 +73,7 @@ void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {
} }
void GfxOpenGL2::SysInit() { void GfxOpenGL2::SysInit() {
Flags |= PDGfxBackendFlags_HasClipRect;
pShader = CreateShaderProgram(pVertCode, pFragCode); pShader = CreateShaderProgram(pVertCode, pFragCode);
glUseProgram(pShader); glUseProgram(pShader);
glGenBuffers(1, &VBO); glGenBuffers(1, &VBO);
@@ -183,6 +184,16 @@ void GfxOpenGL2::UploadPools() {
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndexPoolSize() * sizeof(u16), glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndexPoolSize() * sizeof(u16),
GetIndexBufPtr(0), GL_DYNAMIC_DRAW); GetIndexBufPtr(0), GL_DYNAMIC_DRAW);
} }
void GfxOpenGL2::ClipRect() {
if (CurrentHasClip) {
glEnable(GL_SCISSOR_TEST);
glScissor(CurrentClip.x, ViewPort.y - (CurrentClip.y + CurrentClip.w),
CurrentClip.z, CurrentClip.w);
} else {
glDisable(GL_SCISSOR_TEST);
}
}
} // namespace PD } // namespace PD
#else #else
namespace PD { namespace PD {
@@ -203,5 +214,6 @@ Li::Texture GfxOpenGL2::LoadTexture(const std::vector<PD::u8>& pixels, int w,
void GfxOpenGL2::DeleteTexture(const Li::Texture& tex) {} void GfxOpenGL2::DeleteTexture(const Li::Texture& tex) {}
void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {} void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {}
void GfxOpenGL2::UploadPools() {} void GfxOpenGL2::UploadPools() {}
void GfxOpenGL2::ClipRect() {}
} // namespace PD } // namespace PD
#endif #endif
+12
View File
@@ -11,6 +11,7 @@
namespace PD { namespace PD {
void GfxOpenGL3::SysInit() { void GfxOpenGL3::SysInit() {
Flags |= PDGfxBackendFlags_HasClipRect;
std::string vcode = SpirvHelper::SPV2GLSL( std::string vcode = SpirvHelper::SPV2GLSL(
std::vector<unsigned int>( std::vector<unsigned int>(
Shaders::VertexShader, Shaders::VertexShader,
@@ -159,6 +160,16 @@ void GfxOpenGL3::UploadPools() {
glBindVertexArray(0); glBindVertexArray(0);
} }
void GfxOpenGL3::ClipRect() {
if (CurrentHasClip) {
glEnable(GL_SCISSOR_TEST);
glScissor(CurrentClip.x, ViewPort.y - (CurrentClip.y + CurrentClip.w),
CurrentClip.z, CurrentClip.w);
} else {
glDisable(GL_SCISSOR_TEST);
}
}
} // namespace PD } // namespace PD
#else #else
namespace PD { namespace PD {
@@ -178,5 +189,6 @@ Li::Texture GfxOpenGL3::LoadTexture(const std::vector<PD::u8>& pixels, int w,
} }
void GfxOpenGL3::DeleteTexture(const Li::Texture& tex) {} void GfxOpenGL3::DeleteTexture(const Li::Texture& tex) {}
void GfxOpenGL3::UploadPools() {} void GfxOpenGL3::UploadPools() {}
void GfxOpenGL3::ClipRect() {}
} // namespace PD } // namespace PD
#endif #endif
+1 -22
View File
@@ -56,21 +56,9 @@ struct PD_API Mat4 {
constexpr float* Ptr() { return m.data(); } constexpr float* Ptr() { return m.data(); }
constexpr const float* Ptr() const { return m.data(); } constexpr const float* Ptr() const { return m.data(); }
constexpr float& operator()(int row, int col) { constexpr float& operator()(int row, int col) { return m[col * 4 + row]; }
#ifdef __3DS__
// 3ds is full reverse order iirc
return m[row * 4 + (3 - col)];
#else
return m[col * 4 + row];
#endif
}
constexpr float operator()(int row, int col) const { constexpr float operator()(int row, int col) const {
#ifdef __3DS__
// 3ds is full reverse order iirc
return m[row * 4 + (3 - col)];
#else
return m[col * 4 + row]; return m[col * 4 + row];
#endif
} }
constexpr Mat4 operator*(const Mat4& v) const { constexpr Mat4 operator*(const Mat4& v) const {
@@ -122,21 +110,12 @@ struct PD_API Mat4 {
constexpr static Mat4 Ortho(float l, float r, float b, float t, float n, constexpr static Mat4 Ortho(float l, float r, float b, float t, float n,
float f) { float f) {
Mat4 ret; Mat4 ret;
#ifdef __3DS__ // Patch to rotate the Matrix correctly
ret(0, 1) = 2.f / (t - b);
ret(0, 3) = (b + t) / (b - t);
ret(1, 0) = 2.f / (l - r);
ret(1, 3) = (l + r) / (r - l);
ret(2, 2) = 1.f / (n - f);
ret(2, 3) = 0.5f * (n + f) / (n - f) - 0.5f;
#else
ret(0, 0) = 2.0f / (r - l); ret(0, 0) = 2.0f / (r - l);
ret(0, 3) = -(r + l) / (r - l); ret(0, 3) = -(r + l) / (r - l);
ret(1, 1) = 2.0f / (t - b); ret(1, 1) = 2.0f / (t - b);
ret(1, 3) = -(t + b) / (t - b); ret(1, 3) = -(t + b) / (t - b);
ret(2, 2) = -2.0f / (f - n); ret(2, 2) = -2.0f / (f - n);
ret(2, 3) = -(f + n) / (f - n); ret(2, 3) = -(f + n) / (f - n);
#endif
ret(3, 3) = 1.f; ret(3, 3) = 1.f;
return ret; return ret;
} }
+15 -4
View File
@@ -9,8 +9,11 @@
using PDGfxBackendFlags = PD::u32; using PDGfxBackendFlags = PD::u32;
enum PDGfxBackendFlags_ { enum PDGfxBackendFlags_ {
PDGfxBackendFlags_None = 0, PDGfxBackendFlags_None = 0,
PDGfxBackendFlags_FlipUV_Y = 1 << 0, // Essential for font loading PDGfxBackendFlags_FlipUV_Y = 1 << 0, // Essential for font loading
PDGfxBackendFlags_WindingCW = 1 << 0, // Use CW instead of CCW winding PDGfxBackendFlags_WindingCW = 1 << 1, // Use CW instead of CCW winding
PDGfxBackendFlags_HasClipRect = 1 << 2, // Clip rects supported
PDGfxBackendFlags_ReqPow2 = 1 << 3, // Tex size must be pow of 2
PDGfxBackendFlags_ApproxSDF = 1 << 4, // Fake SDF for non smoothstep systems
}; };
namespace PD { namespace PD {
@@ -65,6 +68,7 @@ class PD_API GfxDriver : public DriverInterface {
virtual void SysReset() {} virtual void SysReset() {}
virtual void Submit(size_t count, size_t start) {} virtual void Submit(size_t count, size_t start) {}
virtual void UploadPools() {} // not every driver requires it virtual void UploadPools() {} // not every driver requires it
virtual void ClipRect() {}
void RegisterTexture(const Li::Texture& tex); void RegisterTexture(const Li::Texture& tex);
void UnregisterTexture(const Li::Texture& tex); void UnregisterTexture(const Li::Texture& tex);
@@ -80,6 +84,8 @@ class PD_API GfxDriver : public DriverInterface {
// State Variables oder so // State Variables oder so
TextureID CurrentTex = 0; TextureID CurrentTex = 0;
bool CurrentTexIsSDF = false; bool CurrentTexIsSDF = false;
bool CurrentHasClip = false;
fvec4 CurrentClip = 0;
Mat4 Projection; Mat4 Projection;
ivec2 ViewPort; ivec2 ViewPort;
std::unordered_map<TextureID, Li::Texture> pTextureRegestry; std::unordered_map<TextureID, Li::Texture> pTextureRegestry;
@@ -136,7 +142,7 @@ class GfxDriverBase : public GfxDriver {
for (size_t i = 0; i < commands.size(); i++) { for (size_t i = 0; i < commands.size(); i++) {
const auto& cmd = commands[i]; const auto& cmd = commands[i];
if (cmd.VertexCount > 0) { if (cmd.VertexCount > 0) {
std::memcpy(pVtxPool.begin() + current_vtx, std::memcpy(reinterpret_cast<void*>(pVtxPool.begin() + current_vtx),
vpool.begin() + cmd.FirstVertex, vpool.begin() + cmd.FirstVertex,
cmd.VertexCount * sizeof(Li::Vertex)); cmd.VertexCount * sizeof(Li::Vertex));
} }
@@ -156,14 +162,19 @@ class GfxDriverBase : public GfxDriver {
while (index < commands.size()) { while (index < commands.size()) {
CurrentTex = commands[index].Tex; CurrentTex = commands[index].Tex;
CurrentTexIsSDF = commands[index].SDF; CurrentTexIsSDF = commands[index].SDF;
CurrentHasClip = commands[index].ClipRectUsed;
CurrentClip = commands[index].ClipRect;
if (!CurrentTex) { if (!CurrentTex) {
CurrentTex = pWhite.GetID(); CurrentTex = pWhite.GetID();
} }
size_t num_indices = 0; size_t num_indices = 0;
ClipRect();
while (index < commands.size() && while (index < commands.size() &&
CurrentTexIsSDF == commands[index].SDF && CurrentTexIsSDF == commands[index].SDF &&
(CurrentTex == commands[index].Tex || (CurrentTex == commands[index].Tex ||
(CurrentTex == pWhite.GetID() && commands[index].Tex == 0))) { (CurrentTex == pWhite.GetID() && commands[index].Tex == 0)) &&
CurrentClip == commands[index].ClipRect &&
CurrentHasClip == commands[index].ClipRectUsed) {
num_indices += commands[index].IndexCount; num_indices += commands[index].IndexCount;
index++; index++;
} }
+3
View File
@@ -28,6 +28,9 @@ class Command {
// Todo: implement // Todo: implement
size_t VertexCountMax = 0; size_t VertexCountMax = 0;
size_t IndexCountMax = 0; size_t IndexCountMax = 0;
// ClipRect
PD::fvec4 ClipRect;
bool ClipRectUsed = false;
}; };
} // namespace Li } // namespace Li
} // namespace PD } // namespace PD
+7 -2
View File
@@ -128,13 +128,18 @@ class PD_API Drawlist {
void PrimTriangle(Command& cmd, const fvec2& a, const fvec2& b, void PrimTriangle(Command& cmd, const fvec2& a, const fvec2& b,
const fvec2& c, const PD::Color& color); const fvec2& c, const PD::Color& color);
void PushClipRect(const fvec4& r) { pClipRects.push_back(r); }
void PopClipRect() {
if (!pClipRects.empty()) pClipRects.pop_back();
}
bool HasClipRect() { return !pClipRects.empty(); }
private: private:
Texture pCurrentTexture; Texture pCurrentTexture;
int pCurrentLayer = 0; int pCurrentLayer = 0;
Pool<Command> pCommands; Pool<Command> pCommands;
Pool<fvec2> pPath; Pool<fvec2> pPath;
Pool<Vertex> pVertices; std::vector<fvec4> pClipRects;
Pool<u16> pIndices;
Font* pFont = nullptr; Font* pFont = nullptr;
float pFontScale = 1.f; float pFontScale = 1.f;
}; };
-6
View File
@@ -56,12 +56,6 @@ class PD_API Font {
*/ */
void LoadTTF(const std::vector<u8>& data, int px_height = 32, void LoadTTF(const std::vector<u8>& data, int px_height = 32,
LiFontFlags flags = LiFontFlags_None); LiFontFlags flags = LiFontFlags_None);
/**
* Function that loads a default integrated font...
* This will only work if PD_LI_INCLUDE_FONTS was set
* on lithium build cause otherwise the font data is not included
*/
void LoadDefaultFont(int id = 0, int pixel_height = 32);
/** /**
* Getter for Codepoint reference * Getter for Codepoint reference
* @return codepoint dataholder reference * @return codepoint dataholder reference
+1 -1
View File
@@ -48,7 +48,7 @@ class PD_API Container {
*/ */
Container(const fvec4& box) Container(const fvec4& box)
: pos(fvec2(box.x, box.y)), size(fvec2(box.z - box.x, box.w - box.y)) {} : pos(fvec2(box.x, box.y)), size(fvec2(box.z - box.x, box.w - box.y)) {}
~Container() = default; virtual ~Container() = default;
/** /**
* Init Function Required by every Object that uses * Init Function Required by every Object that uses
+2
View File
@@ -87,6 +87,8 @@ enum UI7LytAdd_ {
UI7LytAdd_NoCursorUpdate = 1 << 0, ///< Add without cursor alignment UI7LytAdd_NoCursorUpdate = 1 << 0, ///< Add without cursor alignment
UI7LytAdd_NoScrollHandle = 1 << 1, ///< Skip HandleScrolling UI7LytAdd_NoScrollHandle = 1 << 1, ///< Skip HandleScrolling
UI7LytAdd_Front = 1 << 2, ///< Add in front of the list UI7LytAdd_Front = 1 << 2, ///< Add in front of the list
UI7LytAdd_NoGlobalClipping = 1 << 3, ///< Dont use global Layout clip rect
UI7LytAdd_NoClipTitlebar = 1 << 4, ///< Dont clip content behind the titlebar
}; };
/** /**
-5
View File
@@ -85,13 +85,8 @@ PD_API Mat4 Mat4::Perspective(float fov, float aspect, float n, float f) {
Mat4 ret; Mat4 ret;
ret(0, 0) = 1.f / (aspect * _fov); ret(0, 0) = 1.f / (aspect * _fov);
ret(1, 1) = 1.f / _fov; ret(1, 1) = 1.f / _fov;
#ifdef __3DS__
ret(2, 3) = f * n / (n - f);
ret(2, 2) = -(-1.f) * n / (n - f);
#else
ret(2, 2) = -(f + n) / (f - n); ret(2, 2) = -(f + n) / (f - n);
ret(2, 3) = -(2.f * f * n) / (f - n); ret(2, 3) = -(2.f * f * n) / (f - n);
#endif
ret(3, 2) = -1.f; ret(3, 2) = -1.f;
ret(3, 3) = 0.0f; ret(3, 3) = 0.0f;
return ret; return ret;
+2
View File
@@ -56,6 +56,8 @@ void Command::Reset() {
VertexCount = 0; VertexCount = 0;
VertexCountMax = 0; VertexCountMax = 0;
IndexCountMax = 0; IndexCountMax = 0;
ClipRect = 0.f;
ClipRectUsed = false;
} }
Command& Command::Add(const Vertex& vtx) { Command& Command::Add(const Vertex& vtx) {
+5
View File
@@ -43,6 +43,7 @@ PD_API void Drawlist::Clear() {
pPath.ResetFast(); pPath.ResetFast();
pCommands.NoReset(); pCommands.NoReset();
pCurrentLayer = 0; pCurrentLayer = 0;
pClipRects.clear();
} }
/** Command Allocation */ /** Command Allocation */
@@ -51,6 +52,10 @@ PD_API Command& Drawlist::NewCommand() {
cmd->Reset(); cmd->Reset();
cmd->Layer = pCurrentLayer; cmd->Layer = pCurrentLayer;
cmd->Tex = pCurrentTexture.GetID(); cmd->Tex = pCurrentTexture.GetID();
if (HasClipRect()) {
cmd->ClipRectUsed = HasClipRect();
cmd->ClipRect = pClipRects.back();
}
return *cmd; return *cmd;
} }
-2
View File
@@ -195,8 +195,6 @@ PD_API void Font::LoadTTF(const std::vector<u8>& data, int px_height,
} }
} }
PD_API void Font::LoadDefaultFont(int id, int pixel_height) {}
PD_API Font::Codepoint& Font::GetCodepoint(u32 c) { PD_API Font::Codepoint& Font::GetCodepoint(u32 c) {
if (c < 128) { if (c < 128) {
// Direct Access (~11% improvement) // Direct Access (~11% improvement)
+2 -2
View File
@@ -44,13 +44,13 @@ PD_API void Container::HandleInternalInput() {
/** Internal function */ /** Internal function */
PD_API void Container::PreDraw() { PD_API void Container::PreDraw() {
if (pCLipRectUsed) { if (pCLipRectUsed) {
// list->PushClipRect(pClipRect); list->PushClipRect(pClipRect);
} }
} }
/** Internal function */ /** Internal function */
PD_API void Container::PostDraw() { PD_API void Container::PostDraw() {
if (pCLipRectUsed) { if (pCLipRectUsed) {
// list->PopClipRect(); list->PopClipRect();
} }
} }
} // namespace UI7 } // namespace UI7
+1 -1
View File
@@ -28,7 +28,7 @@ SOFTWARE.
namespace PD { namespace PD {
PD_API UI7::IO::IO() : DeltaStats(60), CurrentViewPort("", 0) { PD_API UI7::IO::IO() : CurrentViewPort("", 0), DeltaStats(60) {
/** Probably not the best solution i guess */ /** Probably not the best solution i guess */
// CurrentViewPort = // CurrentViewPort =
// ViewPort::New("Default", ivec4(ivec2(0, 0), pCtx.Gfx()->ViewPort)); // ViewPort::New("Default", ivec4(ivec2(0, 0), pCtx.Gfx()->ViewPort));
+14 -4
View File
@@ -77,6 +77,10 @@ PD_API void Layout::AddObject(Container* obj) {
obj->Update(); obj->Update();
CursorMove(obj->GetSize()); CursorMove(obj->GetSize());
obj->HandleScrolling(ScrollOffset, WorkRect); obj->HandleScrolling(ScrollOffset, WorkRect);
if (Flags & UI7LayoutFlags_UseClipRect) {
obj->SetClipRect(
fvec4(Pos.x, Pos.y + WorkRect.y, Size.x, Size.y - WorkRect.y));
}
Objects.push_back(obj); Objects.push_back(obj);
} }
@@ -93,6 +97,15 @@ PD_API void Layout::AddObjectEx(Container* obj, u32 flags) {
if (!(flags & UI7LytAdd_NoScrollHandle)) { if (!(flags & UI7LytAdd_NoScrollHandle)) {
obj->HandleScrolling(ScrollOffset, WorkRect); obj->HandleScrolling(ScrollOffset, WorkRect);
} }
if (Flags & UI7LayoutFlags_UseClipRect &&
!(flags & UI7LytAdd_NoGlobalClipping)) {
if (flags & UI7LytAdd_NoClipTitlebar) {
obj->SetClipRect(fvec4(Pos.x, Pos.y, Size.x, Size.y));
} else {
obj->SetClipRect(
fvec4(Pos.x, Pos.y + WorkRect.y, Size.x, Size.y - WorkRect.y));
}
}
if (flags & UI7LytAdd_Front) { if (flags & UI7LytAdd_Front) {
Objects.push_front(obj); Objects.push_front(obj);
} else { } else {
@@ -171,9 +184,6 @@ PD_API void Layout::Update() {
it->SetPos(it->GetPos() + Pos); it->SetPos(it->GetPos() + Pos);
it->HandleInput(); it->HandleInput();
it->UnlockInput(); it->UnlockInput();
if (Flags & UI7LayoutFlags_UseClipRect) {
it->SetClipRect(fvec4(Pos, Size));
}
it->PreDraw(); it->PreDraw();
it->Draw(); it->Draw();
it->PostDraw(); it->PostDraw();
@@ -201,7 +211,7 @@ PD_API void Layout::Label(const std::string& label) {
// Layout API // Layout API
auto r = IO.LabelPool.Allocate(); auto r = IO.LabelPool.Allocate();
*r = UI7::Label(label, IO); *r = UI7::Label(label, IO);
r->SetClipRect(fvec4(GetPosition(), GetPosition() + GetSize())); // r->SetClipRect(fvec4(GetPosition(), GetSize()));
AddObject(r); AddObject(r);
} }
Regular → Executable
+404 -400
View File
@@ -1,400 +1,404 @@
/* /*
MIT License MIT License
Copyright (c) 2024 - 2026 René Amthor (tobid7) Copyright (c) 2024 - 2026 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <pd/ui7/containers.hpp> #include <pd/ui7/containers.hpp>
#include <pd/ui7/menu.hpp> #include <pd/ui7/menu.hpp>
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
Menu::Menu(const ID& id, IO& io) : pIO(io), pID(id), pLayout(id, io) { Menu::Menu(const ID& id, IO& io) : pLayout(id, io), pIO(io), pID(id) {
TitleBarHeight = pIO.FontScale * pIO.Font->PixelHeight + pIO.MenuPadding.y; TitleBarHeight = pIO.FontScale * pIO.Font->PixelHeight + pIO.MenuPadding.y;
pLayout.WorkRect.y += TitleBarHeight; pLayout.WorkRect.y += TitleBarHeight;
pLayout.Flags |= UI7LayoutFlags_UseClipRect; pLayout.Flags |= UI7LayoutFlags_UseClipRect;
pLayout.CursorInit(); pLayout.CursorInit();
} }
PD_API void Menu::Label(const std::string& label) { PD_API void Menu::Label(const std::string& label) {
// Layout API // Layout API
auto r = pIO.LabelPool.Allocate(); auto r = pIO.LabelPool.Allocate();
*r = UI7::Label(label, pIO); *r = UI7::Label(label, pIO);
pLayout.AddObject(r); pLayout.AddObject(r);
} }
PD_API bool Menu::Button(const std::string& label) { PD_API bool Menu::Button(const std::string& label) {
bool ret = false; bool ret = false;
u32 id = u32 id =
Strings::FastHash("btn" + label + std::to_string(pLayout.Objects.size())); Strings::FastHash("btn" + label + std::to_string(pLayout.Objects.size()));
Container* r = pLayout.FindObject(id); Container* r = pLayout.FindObject(id);
if (!r) { if (!r) {
r = new UI7::Button(label, pIO); r = new UI7::Button(label, pIO);
r->SetID(id); r->SetID(id);
} }
pLayout.AddObject(r); pLayout.AddObject(r);
if (!r->Skippable()) { if (!r->Skippable()) {
ret = reinterpret_cast<UI7::Button*>(r)->IsPressed(); ret = reinterpret_cast<UI7::Button*>(r)->IsPressed();
} }
return ret; return ret;
} }
PD_API void Menu::Checkbox(const std::string& label, bool& v) { PD_API void Menu::Checkbox(const std::string& label, bool& v) {
u32 id = u32 id =
Strings::FastHash("cbx" + label + std::to_string(pLayout.Objects.size())); Strings::FastHash("cbx" + label + std::to_string(pLayout.Objects.size()));
Container* r = pLayout.FindObject(id); Container* r = pLayout.FindObject(id);
if (!r) { if (!r) {
r = new UI7::Checkbox(label, v, pIO); r = new UI7::Checkbox(label, v, pIO);
r->SetID(id); r->SetID(id);
} }
pLayout.AddObject(r); pLayout.AddObject(r);
} }
PD_API void Menu::Image(Li::Texture img, fvec2 size, Li::Rect uv) { PD_API void Menu::Image(Li::Texture img, fvec2 size, Li::Rect uv) {
auto r = pIO.ImagePool.Allocate(); auto r = pIO.ImagePool.Allocate();
*r = UI7::Image(img, size, uv); *r = UI7::Image(img, size, uv);
pLayout.AddObject(r); pLayout.AddObject(r);
} }
PD_API void Menu::ColorEdit(const std::string& label, u32& clr) { PD_API void Menu::ColorEdit(const std::string& label, u32& clr) {
u32 id = Strings::FastHash("drd" + label); u32 id = Strings::FastHash("drd" + label);
Container* r = pLayout.FindObject(id); Container* r = pLayout.FindObject(id);
if (!r) { if (!r) {
r = new UI7::ColorEdit(label, &clr, pIO); r = new UI7::ColorEdit(label, &clr, pIO);
r->SetID(id); r->SetID(id);
} }
pLayout.AddObject(r); pLayout.AddObject(r);
} }
PD_API void Menu::Separator() { PD_API void Menu::Separator() {
// Dynamic Objects are very simple... // Dynamic Objects are very simple...
DynObj* r = pIO.DynObjPool.Allocate(); DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj( *r = UI7::DynObj(
[=, this](UI7::IO* io, Li::Drawlist* l, UI7::Container* self) { [=, this](UI7::IO* io, Li::Drawlist* l, UI7::Container* self) {
l->DrawRectFilled(self->FinalPos(), self->GetSize(), l->DrawRectFilled(self->FinalPos(), self->GetSize(),
pIO.Theme.Get(UI7Color_TextDead)); pIO.Theme.Get(UI7Color_TextDead));
}); });
// Set size before pushing (cause Cursor Move will require it) // Set size before pushing (cause Cursor Move will require it)
r->SetSize(fvec2( r->SetSize(fvec2(
pLayout.Size.x - pIO.MenuPadding.x * 2 - pLayout.InitialCursorOffset.x, pLayout.Size.x - pIO.MenuPadding.x * 2 - pLayout.InitialCursorOffset.x,
1)); 1));
pLayout.AddObject(r); pLayout.AddObject(r);
} }
PD_API void Menu::SeparatorText(const std::string& label) { PD_API void Menu::SeparatorText(const std::string& label) {
// Also note to use [=] instead of [&] to not undefined access label // Also note to use [=] instead of [&] to not undefined access label
DynObj* r = pIO.DynObjPool.Allocate(); DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj([=, this](UI7::IO* io, Li::Drawlist* l, *r = UI7::DynObj([=, this](UI7::IO* io, Li::Drawlist* l,
UI7::Container* self) { UI7::Container* self) {
l->SetFont(self->GetFont()); l->SetFont(self->GetFont());
fvec2 size = self->GetSize(); fvec2 size = self->GetSize();
fvec2 tdim = io->Font->GetTextBounds(label.c_str(), io->FontScale); fvec2 tdim = io->Font->GetTextBounds(label.c_str(), io->FontScale);
fvec2 pos = self->FinalPos(); fvec2 pos = self->FinalPos();
auto align = pLayout.GetAlignment(); auto align = pLayout.GetAlignment();
vec2 rpos = pLayout.AlignPosition(pos, tdim, vec2 rpos = pLayout.AlignPosition(pos, tdim,
fvec4(pLayout.Pos, pLayout.Size), align); fvec4(pLayout.Pos, pLayout.Size), align);
if (!(align & UI7Align_Left)) { if (!(align & UI7Align_Left)) {
l->DrawRectFilled(fvec2(rpos.x + io->FramePadding.x, tdim.y * 0.5), l->DrawRectFilled(fvec2(rpos.x + io->FramePadding.x, tdim.y * 0.5),
fvec2(pos.x - rpos.x - io->MenuPadding.x, 1), fvec2(pos.x - rpos.x - io->MenuPadding.x, 1),
io->Theme.Get(UI7Color_TextDead)); io->Theme.Get(UI7Color_TextDead));
} }
if (!(align & UI7Align_Right)) { if (!(align & UI7Align_Right)) {
l->DrawRectFilled(pos + fvec2(tdim.x + io->FramePadding.x, tdim.y * 0.5), l->DrawRectFilled(pos + fvec2(tdim.x + io->FramePadding.x, tdim.y * 0.5),
fvec2(size.x - tdim.x - io->MenuPadding.x, 1), fvec2(size.x - tdim.x - io->MenuPadding.x, 1),
io->Theme.Get(UI7Color_TextDead)); io->Theme.Get(UI7Color_TextDead));
} }
l->DrawTextEx(rpos, label.c_str(), io->Theme.Get(UI7Color_Text), 0, l->DrawTextEx(rpos, label.c_str(), io->Theme.Get(UI7Color_Text), 0,
fvec2(pLayout.Size.x, self->GetSize().y)); fvec2(pLayout.Size.x, self->GetSize().y));
}); });
// Set size before pushing (cause Cursor Move will require it) // Set size before pushing (cause Cursor Move will require it)
r->SetSize(fvec2( r->SetSize(fvec2(
pLayout.Size.x - pIO.MenuPadding.x * 2 - pLayout.InitialCursorOffset.x, pLayout.Size.x - pIO.MenuPadding.x * 2 - pLayout.InitialCursorOffset.x,
pIO.Font->PixelHeight * pIO.FontScale)); pIO.Font->PixelHeight * pIO.FontScale));
pLayout.AddObject(r); pLayout.AddObject(r);
} }
PD_API void Menu::HandleFocus() { PD_API void Menu::HandleFocus() {
// Check if menu can be focused for Selective Menu Input API // Check if menu can be focused for Selective Menu Input API
vec4 newarea = fvec4(pLayout.Pos, pLayout.Size); vec4 newarea = fvec4(pLayout.Pos, pLayout.Size);
if (!pIsOpen) { if (!pIsOpen) {
newarea = fvec4(pLayout.Pos, fvec2(pLayout.Size.x, TitleBarHeight)); newarea = fvec4(pLayout.Pos, fvec2(pLayout.Size.x, TitleBarHeight));
} }
if ((PD::Hid::IsEvent(Hid::Event::Down, Hid::Gamepad::Touch) || if ((PD::Hid::IsEvent(Hid::Event::Down, Hid::Gamepad::Touch) ||
PD::Hid::IsEvent(Hid::Event::Down, Hid::Keyboard::MouseLeft)) && PD::Hid::IsEvent(Hid::Event::Down, Hid::Keyboard::MouseLeft)) &&
Li::Math::InBounds(PD::Hid::MousePos(), newarea) && Li::Math::InBounds(PD::Hid::MousePos(), newarea) &&
!Li::Math::InBounds(PD::Hid::MousePos(), !Li::Math::InBounds(PD::Hid::MousePos(),
pIO.InputHandler.FocusedMenuRect)) { pIO.InputHandler.FocusedMenuRect)) {
pIO.InputHandler.FocusedMenu = pID; pIO.InputHandler.FocusedMenu = pID;
} }
if (pIO.InputHandler.FocusedMenu == pID) { if (pIO.InputHandler.FocusedMenu == pID) {
pIO.InputHandler.FocusedMenuRect = newarea; pIO.InputHandler.FocusedMenuRect = newarea;
} }
} }
PD_API void Menu::HandleTitlebarActions() { PD_API void Menu::HandleTitlebarActions() {
// Collapse // Collapse
if (!(Flags & UI7MenuFlags_NoCollapse)) { if (!(Flags & UI7MenuFlags_NoCollapse)) {
vec2 cpos = pLayout.Pos + pIO.FramePadding; vec2 cpos = pLayout.Pos + pIO.FramePadding;
// clr_collapse_tri = UI7Color_FrameBackground; // clr_collapse_tri = UI7Color_FrameBackground;
if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "clbse"), if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "clbse"),
fvec4(cpos, fvec2(18, TitleBarHeight)))) { fvec4(cpos, fvec2(18, TitleBarHeight)))) {
if (pIO.InputHandler.DragReleased) { if (pIO.InputHandler.DragReleased) {
pIsOpen = !pIsOpen; pIsOpen = !pIsOpen;
} }
// clr_collapse_tri = UI7Color_FrameBackgroundHovered; // clr_collapse_tri = UI7Color_FrameBackgroundHovered;
} }
} }
// Close Logic // Close Logic
if (!(Flags & UI7MenuFlags_NoClose) && pIsShown != nullptr) { if (!(Flags & UI7MenuFlags_NoClose) && pIsShown != nullptr) {
fvec2 size = TitleBarHeight - pIO.FramePadding.y * 2; fvec2 size = TitleBarHeight - pIO.FramePadding.y * 2;
fvec2 cpos = fvec2 cpos =
fvec2(pLayout.Pos.x + pLayout.Size.x - size.x - pIO.FramePadding.x, fvec2(pLayout.Pos.x + pLayout.Size.x - size.x - pIO.FramePadding.x,
pLayout.Pos.y + pIO.FramePadding.y); pLayout.Pos.y + pIO.FramePadding.y);
// clr_close_btn = UI7Color_FrameBackground; // clr_close_btn = UI7Color_FrameBackground;
if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "clse"), if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "clse"),
fvec4(cpos, size))) { fvec4(cpos, size))) {
if (pIO.InputHandler.DragReleased) { if (pIO.InputHandler.DragReleased) {
*pIsShown = !(*pIsShown); *pIsShown = !(*pIsShown);
} }
// clr_close_btn = UI7Color_FrameBackgroundHovered; // clr_close_btn = UI7Color_FrameBackgroundHovered;
} }
} }
// Resize logic // Resize logic
if (!(Flags & UI7MenuFlags_NoResize)) { if (!(Flags & UI7MenuFlags_NoResize)) {
vec2 cpos = pLayout.Pos + pLayout.Size - fvec2(20); vec2 cpos = pLayout.Pos + pLayout.Size - fvec2(20);
// clr_close_btn = UI7Color_FrameBackground; // clr_close_btn = UI7Color_FrameBackground;
if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "rszs"), if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "rszs"),
fvec4(cpos, fvec2(20)))) { fvec4(cpos, fvec2(20)))) {
fvec2 szs = pLayout.Size + (pIO.InputHandler.DragPosition - fvec2 szs = pLayout.Size + (pIO.InputHandler.DragPosition -
pIO.InputHandler.DragLastPosition); pIO.InputHandler.DragLastPosition);
if (szs.x < 30) szs.x = 30; if (szs.x < 30) szs.x = 30;
if (szs.y < 30) szs.y = 30; if (szs.y < 30) szs.y = 30;
pLayout.Size = szs; pLayout.Size = szs;
// clr_close_btn = UI7Color_FrameBackgroundHovered; // clr_close_btn = UI7Color_FrameBackgroundHovered;
} }
} }
// Menu Movement // Menu Movement
if (!(Flags & UI7MenuFlags_NoMove)) { if (!(Flags & UI7MenuFlags_NoMove)) {
if (pIO.InputHandler.DragObject( if (pIO.InputHandler.DragObject(
pID.GetName() + "tmv", pID.GetName() + "tmv",
fvec4(pLayout.Pos, fvec2(pLayout.Size.x, TitleBarHeight)))) { fvec4(pLayout.Pos, fvec2(pLayout.Size.x, TitleBarHeight)))) {
if (pIO.InputHandler.DragDoubleRelease) { if (pIO.InputHandler.DragDoubleRelease) {
pIsOpen = !pIsOpen; pIsOpen = !pIsOpen;
} }
pLayout.Pos = pLayout.Pos + (pIO.InputHandler.DragPosition - pLayout.Pos = pLayout.Pos + (pIO.InputHandler.DragPosition -
pIO.InputHandler.DragLastPosition); pIO.InputHandler.DragLastPosition);
// Keep Window In Viewport // Keep Window In Viewport
// Maybe i need to add some operators to vec // Maybe i need to add some operators to vec
pLayout.Pos.x = std::clamp<float>(pLayout.Pos.x, -pLayout.Size.x + 10, pLayout.Pos.x = std::clamp<float>(pLayout.Pos.x, -pLayout.Size.x + 10,
pIO.CurrentViewPort.pSize.z - 10); pIO.CurrentViewPort.pSize.z - 10);
pLayout.Pos.y = pLayout.Pos.y =
std::clamp<float>(pLayout.Pos.y, pIO.CurrentViewPort.pSize.y, std::clamp<float>(pLayout.Pos.y, pIO.CurrentViewPort.pSize.y,
pIO.CurrentViewPort.pSize.w - 10); pIO.CurrentViewPort.pSize.w - 10);
} }
} }
} }
PD_API void Menu::DrawBaseLayout() { PD_API void Menu::DrawBaseLayout() {
if (pIsOpen) { if (pIsOpen) {
/** Resize Sym (Render on Top of Everything) */ /** Resize Sym (Render on Top of Everything) */
if (!(Flags & UI7MenuFlags_NoResize)) { if (!(Flags & UI7MenuFlags_NoResize)) {
DynObj* r = pIO.DynObjPool.Allocate(); DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj([](IO* io, Li::Drawlist* l, UI7::Container* self) { *r = UI7::DynObj([](IO* io, Li::Drawlist* l, UI7::Container* self) {
l->SetLayer(1); l->SetLayer(21);
l->PathAdd(self->FinalPos() + self->GetSize() - fvec2(0, 20)); l->PathAdd(self->FinalPos() + self->GetSize() - fvec2(0, 20));
l->PathAdd(self->FinalPos() + self->GetSize()); l->PathAdd(self->FinalPos() + self->GetSize());
l->PathAdd(self->FinalPos() + self->GetSize() - fvec2(20, 0)); l->PathAdd(self->FinalPos() + self->GetSize() - fvec2(20, 0));
l->PathFill(io->Theme.Get(UI7Color_Button)); l->PathFill(io->Theme.Get(UI7Color_Button));
l->SetLayer(0); l->SetLayer(0);
}); });
r->SetSize( r->SetSize(
fvec2(pLayout.GetSize().x, pLayout.GetSize().y - TitleBarHeight)); fvec2(pLayout.GetSize().x, pLayout.GetSize().y - TitleBarHeight));
r->SetPos(fvec2(0, TitleBarHeight)); r->SetPos(fvec2(0, TitleBarHeight));
pLayout.AddObjectEx(r, pLayout.AddObjectEx(r,
UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle); UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle);
} }
/** Background */ /** Background */
DynObj* r = pIO.DynObjPool.Allocate(); DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj([](IO* io, Li::Drawlist* l, UI7::Container* self) { *r = UI7::DynObj([](IO* io, Li::Drawlist* l, UI7::Container* self) {
l->SetLayer(0); l->SetLayer(0);
l->PathRectEx(self->FinalPos(), self->FinalPos() + self->GetSize(), 10.f, l->PathRectEx(self->FinalPos(), self->FinalPos() + self->GetSize(), 10.f,
LiPathRectFlags_KeepTop | LiPathRectFlags_KeepBot); LiPathRectFlags_KeepTop | LiPathRectFlags_KeepBot);
l->PathFill(io->Theme.Get(UI7Color_Background)); l->PathFill(io->Theme.Get(UI7Color_Background));
/*l->DrawRectFilled(self->FinalPos(), self->GetSize(), /*l->DrawRectFilled(self->FinalPos(), self->GetSize(),
io->Theme.Get(UI7Color_Background));*/ io->Theme.Get(UI7Color_Background));*/
}); });
// Set size before pushing (cause Cursor Move will require it) // Set size before pushing (cause Cursor Move will require it)
r->SetSize( r->SetSize(
fvec2(pLayout.GetSize().x, pLayout.GetSize().y - TitleBarHeight)); fvec2(pLayout.GetSize().x, pLayout.GetSize().y - TitleBarHeight));
r->SetPos(fvec2(0, TitleBarHeight)); r->SetPos(fvec2(0, TitleBarHeight));
pLayout.AddObjectEx(r, UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle | pLayout.AddObjectEx(r, UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle |
UI7LytAdd_Front); UI7LytAdd_Front | UI7LytAdd_NoClipTitlebar);
} }
if (!(Flags & UI7MenuFlags_NoTitlebar)) { if (!(Flags & UI7MenuFlags_NoTitlebar)) {
DynObj* r = pIO.DynObjPool.Allocate(); DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj( *r = UI7::DynObj(
[=, this](UI7::IO* io, Li::Drawlist* l, UI7::Container* self) { [=, this](UI7::IO* io, Li::Drawlist* l, UI7::Container* self) {
l->SetFont(self->GetFont()); l->SetFont(self->GetFont());
l->SetLayer(20); l->SetLayer(20);
/** Header Bar */ /** Header Bar */
l->DrawRectFilled(self->FinalPos(), self->GetSize(), l->DrawRectFilled(self->FinalPos(), self->GetSize(),
io->Theme.Get(UI7Color_Header)); io->Theme.Get(UI7Color_Header));
l->SetLayer(21); l->SetLayer(21);
/** Inline if statement to shift the Text if collapse sym is shown */ /** Inline if statement to shift the Text if collapse sym is shown */
/** What the hell is this code btw (didn't found a better way) */ /** What the hell is this code btw (didn't found a better way) */
l->DrawText(self->FinalPos() + l->DrawText(self->FinalPos() +
fvec2((Flags & UI7MenuFlags_NoCollapse) fvec2((Flags & UI7MenuFlags_NoCollapse)
? pIO.FramePadding.x ? pIO.FramePadding.x
: (TitleBarHeight - pIO.FramePadding.y * 2 + : (TitleBarHeight - pIO.FramePadding.y * 2 +
(io->FramePadding.x * 2)), (io->FramePadding.x * 2)),
2), 2),
pID.GetName().c_str(), io->Theme.Get(UI7Color_Text)); pID.GetName().c_str(), io->Theme.Get(UI7Color_Text));
l->SetLayer(0); l->SetLayer(0);
}); });
r->SetSize(fvec2(pLayout.GetSize().x, TitleBarHeight)); r->SetSize(fvec2(pLayout.GetSize().x, TitleBarHeight));
r->SetPos(0); r->SetPos(0);
pLayout.AddObjectEx(r, UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle); pLayout.AddObjectEx(r, UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle |
UI7LytAdd_NoClipTitlebar);
/** Collapse Sym */
if (!(Flags & UI7MenuFlags_NoCollapse)) { /** Collapse Sym */
DynObj* r = pIO.DynObjPool.Allocate(); if (!(Flags & UI7MenuFlags_NoCollapse)) {
*r = UI7::DynObj([=, this](UI7::IO* io, Li::Drawlist* l, DynObj* r = pIO.DynObjPool.Allocate();
UI7::Container* self) { *r = UI7::DynObj([=, this](UI7::IO* io, Li::Drawlist* l,
/** This sym actually requires layer 21 (i dont know why) */ UI7::Container* self) {
l->SetLayer(21); /** This sym actually requires layer 21 (i dont know why) */
/** l->SetLayer(21);
* Symbol (Position Swapping set by pIsOpen ? openpos : closepos;) /**
*/ * Symbol (Position Swapping set by pIsOpen ? openpos : closepos;)
l->DrawTriangleFilled( */
self->FinalPos(), l->DrawTriangleFilled(
self->FinalPos() + self->FinalPos(),
fvec2(self->GetSize().x, pIsOpen ? 0 : self->GetSize().y * 0.5), self->FinalPos() +
self->FinalPos() + fvec2(self->GetSize().x, pIsOpen ? 0 : self->GetSize().y * 0.5),
fvec2(pIsOpen ? self->GetSize().x * 0.5 : 0, self->GetSize().y), self->FinalPos() +
io->Theme.Get(UI7Color_FrameBackground)); fvec2(pIsOpen ? self->GetSize().x * 0.5 : 0, self->GetSize().y),
l->SetLayer(0); io->Theme.Get(UI7Color_FrameBackground));
}); l->SetLayer(0);
r->SetSize(TitleBarHeight - pIO.FramePadding.y * 2); });
r->SetPos(pIO.FramePadding); r->SetSize(TitleBarHeight - pIO.FramePadding.y * 2);
pLayout.AddObjectEx(r, r->SetPos(pIO.FramePadding);
UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle); pLayout.AddObjectEx(r, UI7LytAdd_NoCursorUpdate |
} UI7LytAdd_NoScrollHandle |
/** Close Sym (only shown if pIsShown is not nullptr) */ UI7LytAdd_NoClipTitlebar);
if (!(Flags & UI7MenuFlags_NoClose) && pIsShown) { }
fvec2 size = TitleBarHeight - pIO.FramePadding.y * 2; // Fixed quad size /** Close Sym (only shown if pIsShown is not nullptr) */
// Need to clamp this way as the math lib lacks a less and greater if (!(Flags & UI7MenuFlags_NoClose) && pIsShown) {
// operator in vec2 (don't checked if it would make sense yet) fvec2 size = TitleBarHeight - pIO.FramePadding.y * 2; // Fixed quad size
size.x = std::clamp(size.x, 5.f, std::numeric_limits<float>::max()); // Need to clamp this way as the math lib lacks a less and greater
size.y = std::clamp(size.y, 5.f, std::numeric_limits<float>::max()); // operator in vec2 (don't checked if it would make sense yet)
// Probably should fix the minsize to be locked on y size.x = std::clamp(size.x, 5.f, std::numeric_limits<float>::max());
fvec2 cpos = size.y = std::clamp(size.y, 5.f, std::numeric_limits<float>::max());
fvec2(pLayout.Pos.x + pLayout.Size.x - size.x - pIO.FramePadding.x, // Probably should fix the minsize to be locked on y
pLayout.Pos.y + pIO.FramePadding.y); fvec2 cpos =
pLayout.DrawList.DrawLine(cpos, cpos + size, fvec2(pLayout.Pos.x + pLayout.Size.x - size.x - pIO.FramePadding.x,
pIO.Theme.Get(UI7Color_FrameBackground), 2); pLayout.Pos.y + pIO.FramePadding.y);
pLayout.DrawList.DrawLine(cpos + fvec2(0, size.y), pLayout.DrawList.SetLayer(21);
cpos + fvec2(size.x, 0), pLayout.DrawList.DrawLine(cpos, cpos + size,
pIO.Theme.Get(UI7Color_FrameBackground), 2); pIO.Theme.Get(UI7Color_FrameBackground), 2);
} pLayout.DrawList.DrawLine(cpos + fvec2(0, size.y),
} cpos + fvec2(size.x, 0),
} pIO.Theme.Get(UI7Color_FrameBackground), 2);
pLayout.DrawList.SetLayer(0);
PD_API void Menu::Update() { }
HandleFocus(); }
if (pLayout.Size == fvec2(0.f) || Flags & UI7MenuFlags_AlwaysAutoSize) { }
pLayout.Size = fvec2(pLayout.MaxPosition) + pIO.MenuPadding * 2;
} PD_API void Menu::Update() {
if (Flags & UI7MenuFlags_VtScrolling) HandleFocus();
pLayout.Flags |= UI7LayoutFlags_VtScrolling; if (pLayout.Size == fvec2(0.f) || Flags & UI7MenuFlags_AlwaysAutoSize) {
if (Flags & UI7MenuFlags_HzScrolling) pLayout.Size = fvec2(pLayout.MaxPosition) + pIO.MenuPadding * 2;
pLayout.Flags |= UI7LayoutFlags_HzScrolling; }
if (!(Flags & UI7MenuFlags_NoTitlebar)) { if (Flags & UI7MenuFlags_VtScrolling)
TitleBarHeight = pIO.FontScale * pIO.Font->PixelHeight + pIO.MenuPadding.y; pLayout.Flags |= UI7LayoutFlags_VtScrolling;
pLayout.WorkRect.y = 5.f + TitleBarHeight; if (Flags & UI7MenuFlags_HzScrolling)
HandleTitlebarActions(); pLayout.Flags |= UI7LayoutFlags_HzScrolling;
} else { if (!(Flags & UI7MenuFlags_NoTitlebar)) {
TitleBarHeight = 0.f; TitleBarHeight = pIO.FontScale * pIO.Font->PixelHeight + pIO.MenuPadding.y;
pLayout.WorkRect.y = 5.f; pLayout.WorkRect.y = 5.f + TitleBarHeight;
} HandleTitlebarActions();
DrawBaseLayout(); } else {
pLayout.Update(); TitleBarHeight = 0.f;
} pLayout.WorkRect.y = 5.f;
}
PD_API bool Menu::BeginTreeNode(const ID& id) { DrawBaseLayout();
// As of some notes this should work: pLayout.Update();
auto n = pTreeNodes.find(id); }
if (n == pTreeNodes.end()) {
pTreeNodes[id] = false; PD_API bool Menu::BeginTreeNode(const ID& id) {
n = pTreeNodes.find(id); // As of some notes this should work:
} auto n = pTreeNodes.find(id);
fvec2 pos = pLayout.Cursor; if (n == pTreeNodes.end()) {
fvec2 tdim = pIO.Font->GetTextBounds(id.GetName().c_str(), pIO.FontScale); pTreeNodes[id] = false;
fvec2 szs = tdim + fvec2(pIO.ItemSpace.x + 10, 0); n = pTreeNodes.find(id);
}
if (n->second) { fvec2 pos = pLayout.Cursor;
pLayout.InitialCursorOffset += 10.f; fvec2 tdim = pIO.Font->GetTextBounds(id.GetName().c_str(), pIO.FontScale);
} fvec2 szs = tdim + fvec2(pIO.ItemSpace.x + 10, 0);
// Object if (n->second) {
DynObj* r = pIO.DynObjPool.Allocate(); pLayout.InitialCursorOffset += 10.f;
*r = UI7::DynObj([=, this](IO* io, Li::Drawlist* l, Container* self) { }
l->SetFont(self->GetFont());
fvec2 ts = self->FinalPos() + fvec2(0, 7); // Object
fvec2 pl[2] = {fvec2(10, 5), fvec2(0, 10)}; DynObj* r = pIO.DynObjPool.Allocate();
if (n->second) { *r = UI7::DynObj([=, this](IO* io, Li::Drawlist* l, Container* self) {
float t = pl[0].y; l->SetFont(self->GetFont());
pl[0].y = pl[1].x; fvec2 ts = self->FinalPos() + fvec2(0, 7);
pl[1].x = t; fvec2 pl[2] = {fvec2(10, 5), fvec2(0, 10)};
} if (n->second) {
l->DrawTriangleFilled(ts, ts + pl[0], ts + pl[1], float t = pl[0].y;
io->Theme.Get(UI7Color_FrameBackground)); pl[0].y = pl[1].x;
pl[1].x = t;
l->DrawText(self->FinalPos() + fvec2(10 + io->ItemSpace.x, 0), }
id.GetName().c_str(), io->Theme.Get(UI7Color_Text)); l->DrawTriangleFilled(ts, ts + pl[0], ts + pl[1],
}); io->Theme.Get(UI7Color_FrameBackground));
/** Yes this new function handler was created for tree nodes */
r->AddInputHandler([=, this](IO* io, Container* self) { l->DrawText(self->FinalPos() + fvec2(10 + io->ItemSpace.x, 0),
if (io->InputHandler.DragObject(ID(pID.GetName() + id.GetName()), id.GetName().c_str(), io->Theme.Get(UI7Color_Text));
fvec4(self->FinalPos(), self->GetSize()))) { });
if (io->InputHandler.DragReleased) { /** Yes this new function handler was created for tree nodes */
n->second = !n->second; r->AddInputHandler([=, this](IO* io, Container* self) {
} if (io->InputHandler.DragObject(ID(pID.GetName() + id.GetName()),
} fvec4(self->FinalPos(), self->GetSize()))) {
}); if (io->InputHandler.DragReleased) {
r->SetPos(pos); n->second = !n->second;
r->SetSize(szs); }
/** Use Add Object as it is faster */ }
pLayout.AddObject(r); });
r->SetPos(pos);
return n->second; r->SetSize(szs);
} /** Use Add Object as it is faster */
pLayout.AddObject(r);
PD_API void UI7::Menu::EndTreeNode() {
pLayout.InitialCursorOffset.x -= 10.f; return n->second;
pLayout.Cursor.x -= 10.f; }
if (pLayout.InitialCursorOffset.x < 0.f) {
pLayout.InitialCursorOffset.x = 0.f; PD_API void UI7::Menu::EndTreeNode() {
} pLayout.InitialCursorOffset.x -= 10.f;
} pLayout.Cursor.x -= 10.f;
} // namespace UI7 if (pLayout.InitialCursorOffset.x < 0.f) {
} // namespace PD pLayout.InitialCursorOffset.x = 0.f;
}
}
} // namespace UI7
} // namespace PD
+359 -349
View File
@@ -1,349 +1,359 @@
/* /*
MIT License MIT License
Copyright (c) 2024 - 2026 René Amthor (tobid7) Copyright (c) 2024 - 2026 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include <pd/ui7/ui7.hpp> #include <pd/ui7/ui7.hpp>
#include "pd/pd_p_api.hpp" #include "pd/pd_p_api.hpp"
#include "pd/ui7/flags.hpp" #include "pd/ui7/flags.hpp"
#define UI7DHX32(x) std::format("{}: {:#08x}", #x, x) #define UI7DHX32(x) std::format("{}: {:#08x}", #x, x)
#define UI7DTF(x) PD::Strings::FormatNanos(x) #define UI7DTF(x) PD::Strings::FormatNanos(x)
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
PD_API std::string GetVersion(bool show_build) { PD_API std::string GetVersion(bool show_build) {
std::stringstream s; std::stringstream s;
s << ((UI7_VERSION >> 24) & 0xFF) << "."; s << ((UI7_VERSION >> 24) & 0xFF) << ".";
s << ((UI7_VERSION >> 16) & 0xFF) << "."; s << ((UI7_VERSION >> 16) & 0xFF) << ".";
s << ((UI7_VERSION >> 8) & 0xFF); s << ((UI7_VERSION >> 8) & 0xFF);
if (show_build) s << "-" << ((UI7_VERSION) & 0xFF); if (show_build) s << "-" << ((UI7_VERSION) & 0xFF);
return s.str(); return s.str();
} }
PD_API void Context::AddViewPort(const ID& id, const ivec4& vp) { PD_API void Context::AddViewPort(const ID& id, const ivec4& vp) {
pIO.AddViewPort(id, vp); pIO.AddViewPort(id, vp);
} }
PD_API void Context::UseViewPort(const ID& id) { PD_API void Context::UseViewPort(const ID& id) {
if (!pIO.ViewPorts.count(id)) { if (!pIO.ViewPorts.count(id)) {
return; return;
} }
pIO.CurrentViewPort = pIO.ViewPorts[id.RawID()]; pIO.CurrentViewPort = pIO.ViewPorts[id.RawID()];
} }
PD_API Menu* Context::BeginMenu(const ID& id, UI7MenuFlags flags, bool* pShow) { PD_API Menu* Context::BeginMenu(const ID& id, UI7MenuFlags flags, bool* pShow) {
if (pCurrent) { if (pCurrent) {
PDERR("UI7: You are already in {} Menu!", pCurrent->pID.GetName()); PDERR("UI7: You are already in {} Menu!", pCurrent->pID.GetName());
return nullptr; return nullptr;
} }
if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(), (u32)id) != if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(), (u32)id) !=
pCurrentMenus.end()) { pCurrentMenus.end()) {
PDERR("UI7: Menu {} already exists!", id.GetName()); PDERR("UI7: Menu {} already exists!", id.GetName());
return nullptr; return nullptr;
} }
pCurrent = pGetOrCreateMenu(id); pCurrent = pGetOrCreateMenu(id);
this->pCurrent->pIsShown = pShow; this->pCurrent->pIsShown = pShow;
if (pCurrent->pIsShown != nullptr) { if (pCurrent->pIsShown != nullptr) {
if (!*pCurrent->pIsShown) { if (!*pCurrent->pIsShown) {
pCurrent = nullptr; pCurrent = nullptr;
return nullptr; return nullptr;
} }
} }
/** Probably we dont even need Input Handling in this stage */ /** Probably we dont even need Input Handling in this stage */
// this->pIO.InputHandler.CurrentMenu = id; // this->pIO.InputHandler.CurrentMenu = id;
pCurrentMenus.push_back(id); pCurrentMenus.push_back(id);
pCurrent->Flags = flags; pCurrent->Flags = flags;
if (!pCurrent->pIsOpen) { if (!pCurrent->pIsOpen) {
pCurrent = nullptr; pCurrent = nullptr;
} }
return pCurrent; return pCurrent;
} }
PD_API void Context::EndMenu() { PD_API void Context::EndMenu() {
/** /**
* Currently it would be a better wy to handle menus as follows * Currently it would be a better wy to handle menus as follows
* *
* The folowing context will generate a new menu as normally but instead * The folowing context will generate a new menu as normally but instead
* of true or false we have m is false (nullptr) or true (some ptr returned) * of true or false we have m is false (nullptr) or true (some ptr returned)
* and after that it should simply out of scope * and after that it should simply out of scope
* (This would probably require some wrapper class to find out if m goes * (This would probably require some wrapper class to find out if m goes
* out of scope) * out of scope)
* ```cpp * ```cpp
* if(auto m = ui7->BeginMenu("Test")) { * if(auto m = ui7->BeginMenu("Test")) {
* m->Label("Show some Text"); * m->Label("Show some Text");
* } * }
* ``` * ```
*/ */
if (!pCurrent) { if (!pCurrent) {
return; return;
} }
pCurrent = nullptr; pCurrent = nullptr;
// pIO.InputHandler.CurrentMenu = 0; // pIO.InputHandler.CurrentMenu = 0;
} }
PD_API void Context::Update() { PD_API void Context::Update() {
/** /**
* Cause Commenting each line looks carbage... * Cause Commenting each line looks carbage...
* This function simply clears the FinalDrawList, Searches for Menu ID's in * This function simply clears the FinalDrawList, Searches for Menu ID's in
* The sorted menu List from last frame to insert them as same order into * The sorted menu List from last frame to insert them as same order into
* the final list. After that it adds new menus to the begin to 'add' new * the final list. After that it adds new menus to the begin to 'add' new
* menus on top. As final step the focused menu gets add to begin * menus on top. As final step the focused menu gets add to begin
* Then the menus update their Input and DraeList Generation in List Order * Then the menus update their Input and DraeList Generation in List Order
* and the DrawLists get Merged into the FDL in reverse Order. At end the List * and the DrawLists get Merged into the FDL in reverse Order. At end the List
* gets cleanup and io gets updated * gets cleanup and io gets updated
* *
* Very simple ... * Very simple ...
*/ */
pIO.FDL.Clear(); pIO.FDL.Clear();
if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(), if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(),
pIO.InputHandler.FocusedMenu) == pCurrentMenus.end()) { pIO.InputHandler.FocusedMenu) == pCurrentMenus.end()) {
pIO.InputHandler.FocusedMenu = 0; pIO.InputHandler.FocusedMenu = 0;
pIO.InputHandler.FocusedMenuRect = fvec4(0); pIO.InputHandler.FocusedMenuRect = fvec4(0);
} }
std::vector<u32> FinalList; std::vector<u32> FinalList;
for (auto it : pDFO) { for (auto it : pDFO) {
if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(), it) != if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(), it) !=
pCurrentMenus.end() && pCurrentMenus.end() &&
it != pIO.InputHandler.FocusedMenu) { it != pIO.InputHandler.FocusedMenu) {
FinalList.push_back(it); FinalList.push_back(it);
} }
} }
for (auto it : pCurrentMenus) { for (auto it : pCurrentMenus) {
if (std::find(FinalList.begin(), FinalList.end(), it) == FinalList.end() && if (std::find(FinalList.begin(), FinalList.end(), it) == FinalList.end() &&
it != pIO.InputHandler.FocusedMenu) { it != pIO.InputHandler.FocusedMenu) {
FinalList.push_back(it); FinalList.push_back(it);
} }
} }
if (pMenus.count(pIO.InputHandler.FocusedMenu)) { if (pMenus.count(pIO.InputHandler.FocusedMenu)) {
FinalList.insert(FinalList.begin(), pIO.InputHandler.FocusedMenu); FinalList.insert(FinalList.begin(), pIO.InputHandler.FocusedMenu);
} }
pDFO = FinalList; pDFO = FinalList;
for (auto& it : FinalList) { for (auto& it : FinalList) {
this->pIO.InputHandler.CurrentMenu = it; this->pIO.InputHandler.CurrentMenu = it;
pMenus[it]->Update(); /** Render */ pMenus[it]->Update(); /** Render */
this->pIO.InputHandler.CurrentMenu = 0; this->pIO.InputHandler.CurrentMenu = 0;
} }
int base_layer = 0; int base_layer = 0;
for (int i = (int)FinalList.size() - 1; i >= 0; i--) { for (int i = (int)FinalList.size() - 1; i >= 0; i--) {
pIO.FDL.SetLayer(base_layer); pIO.FDL.SetLayer(base_layer);
pIO.FDL.Merge(pMenus[FinalList[i]]->pLayout.GetDrawList()); pIO.FDL.Merge(pMenus[FinalList[i]]->pLayout.GetDrawList());
base_layer += 100; base_layer += 100;
} }
pCurrentMenus.clear(); pCurrentMenus.clear();
pIO.Update(); pIO.Update();
pIO.FDL.Optimize(); pIO.FDL.Optimize();
} }
PD_API void Context::AboutMenu(bool* show) { PD_API void Context::AboutMenu(bool* show) {
if (auto m = BeginMenu("About UI7", UI7MenuFlags_Scrolling, show)) { if (auto m = BeginMenu("About UI7", UI7MenuFlags_Scrolling, show)) {
m->Label("Palladium UI7 " + GetVersion()); m->Label("Palladium UI7 " + GetVersion());
m->Separator(); m->Separator();
m->Label("(c) 2023-2025 René Amthor"); m->Label("(c) 2023-2026 René Amthor");
m->Label("UI7 is licensed under the MIT License."); m->Label("UI7 is licensed under the MIT License.");
m->Label("See LICENSE for more information."); m->Label("See LICENSE for more information.");
static bool show_build; static bool show_build;
m->Checkbox("Show Build Info", show_build); m->Checkbox("Show Build Info", show_build);
if (show_build) { if (show_build) {
m->SeparatorText("Build Info"); m->SeparatorText("Build Info");
m->Label("Full Version -> " + GetVersion(true)); m->Label("Full Version -> " + GetVersion(true));
m->Label("sizeof(size_t) -> " + std::to_string(sizeof(size_t))); m->Label("sizeof(size_t) -> " + std::to_string(sizeof(size_t)));
m->Label("sizeof(LI::Vertex) -> " + std::to_string(sizeof(Li::Vertex))); m->Label("sizeof(LI::Vertex) -> " + std::to_string(sizeof(Li::Vertex)));
m->Label("__cplusplus -> " + std::to_string(__cplusplus)); m->Label("__cplusplus -> " + std::to_string(__cplusplus));
m->Label("Compiler -> {}", m->Label("Compiler -> {}",
Strings::GetCompilerVersion()); // + LibInfo::CompiledWith()); Strings::GetCompilerVersion()); // + LibInfo::CompiledWith());
} }
EndMenu(); EndMenu();
} }
} }
PD_API void Context::MetricsMenu(bool* show) { PD_API void Context::MetricsMenu(bool* show) {
if (auto m = BeginMenu("UI7 Metrics", UI7MenuFlags_Scrolling, show)) { if (auto m = BeginMenu("UI7 Metrics", UI7MenuFlags_Scrolling, show)) {
m->Label("Palladium - UI7 " + GetVersion()); m->Label("Palladium - UI7 " + GetVersion());
m->Separator(); m->Separator();
m->Label( m->Label(
std::format("Average {:.3f} ms/f ({:.1f} FPS)", std::format("Average {:.3f} ms/f ({:.1f} FPS)",
((float)pIO.DeltaStats.GetAverage() / 1000.f), ((float)pIO.DeltaStats.GetAverage() / 1000.f),
1000.f / ((float)pIO.DeltaStats.GetAverage() / 1000.f))); 1000.f / ((float)pIO.DeltaStats.GetAverage() / 1000.f)));
m->Label(std::format("NumVertices: {}", pIO.NumVertices)); m->Label(std::format("NumVertices: {}", pIO.NumVertices));
m->Label(std::format("NumIndices: {} -> {} Tris", pIO.NumIndices, m->Label(std::format("NumIndices: {} -> {} Tris", pIO.NumIndices,
pIO.NumIndices / 3)); pIO.NumIndices / 3));
m->Label("Menus: " + std::to_string(pMenus.size())); m->Label("Menus: " + std::to_string(pMenus.size()));
/** Section TimeTrace */ /** Section TimeTrace */
m->SeparatorText("TimeTrace"); m->SeparatorText("TimeTrace");
if (m->BeginTreeNode("Traces (" + if (m->BeginTreeNode("Traces (" +
std::to_string(PD::TT::GetTraceMap().size()) + ")")) { std::to_string(PD::TT::GetTraceMap().size()) + ")")) {
for (auto& it : PD::TT::GetTraceMap()) { for (auto& it : PD::TT::GetTraceMap()) {
if (m->BeginTreeNode(it.second.GetID())) { if (m->BeginTreeNode(it.second.GetID())) {
m->Label("Diff: " + UI7DTF(it.second.GetLastDiff())); m->Label("Diff: " + UI7DTF(it.second.GetLastDiff()));
m->Label("Protocol Len: " + m->Label("Protocol Len: " +
std::to_string(it.second.GetProtocol().GetLen())); std::to_string(it.second.GetProtocol().GetLen()));
m->Label("Average: " + UI7DTF(it.second.GetProtocol().GetAverage())); m->Label("Average: " + UI7DTF(it.second.GetProtocol().GetAverage()));
m->Label("Min: " + UI7DTF(it.second.GetProtocol().GetMin())); m->Label("Min: " + UI7DTF(it.second.GetProtocol().GetMin()));
m->Label("Max: " + UI7DTF(it.second.GetProtocol().GetMax())); m->Label("Max: " + UI7DTF(it.second.GetProtocol().GetMax()));
m->EndTreeNode(); m->EndTreeNode();
} }
} }
m->EndTreeNode(); m->EndTreeNode();
} }
m->SeparatorText("Palladium Info"); m->SeparatorText("Palladium Info");
m->Label("Os Driver: {}", PD::Os::GetDriverName()); m->Label("Os Driver: {}", PD::Os::GetDriverName());
m->Label("Renderer: {}", PD::Gfx::GetDriverName()); if (m->BeginTreeNode(
if (m->BeginTreeNode( std::format("Gfx Driver: {}", PD::Gfx::GetDriverName()))) {
std::string(std::string("Input: ") + PD::Hid::GetDriverName()))) { m->SeparatorText("Features");
/* if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasKeyboard) { if (PD::Gfx::GetFlags() & PDGfxBackendFlags_HasClipRect)
m->Label("- Keyboard Supported"); m->Label("ClipRects");
} if (PD::Gfx::GetFlags() & PDGfxBackendFlags_ReqPow2)
if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasMouse) { m->Label("Texture As Pow of 2");
m->Label("- Mouse Supported"); if (PD::Gfx::GetFlags() & PDGfxBackendFlags_ApproxSDF)
} m->Label("SDF Approximation");
if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasTouch) { m->EndTreeNode();
m->Label("- Touch Supported"); }
} if (m->BeginTreeNode(
if (pIO.pCtx.Hid()->Flags & PD::HidDriver::FLags_HasGamepad) { std::string(std::string("Input: ") + PD::Hid::GetDriverName()))) {
m->Label("- Gamepad Supported"); /* if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasKeyboard) {
}*/ m->Label("- Keyboard Supported");
m->EndTreeNode(); }
} if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasMouse) {
/** Section IO */ m->Label("- Mouse Supported");
m->SeparatorText("IO"); }
if (m->BeginTreeNode("Menus (" + std::to_string(pMenus.size()) + ")")) { if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasTouch) {
for (auto& it : pMenus) { m->Label("- Touch Supported");
if (m->BeginTreeNode(it.second->pID.GetName())) { }
m->Label("Name: " + it.second->pID.GetName()); if (pIO.pCtx.Hid()->Flags & PD::HidDriver::FLags_HasGamepad) {
m->Label(std::format("Pos: {}", it.second->pLayout.GetPosition())); m->Label("- Gamepad Supported");
m->Label(std::format("Size: {}", it.second->pLayout.GetSize())); }*/
m->Label(std::format("WorkRect: {}", it.second->pLayout.WorkRect)); m->EndTreeNode();
m->Label(std::format("Cursor: {}", it.second->pLayout.Cursor)); }
if (m->BeginTreeNode( /** Section IO */
"ID Objects (" + m->SeparatorText("IO");
std::to_string(it.second->pLayout.IDObjects.size()) + ")")) { if (m->BeginTreeNode("Menus (" + std::to_string(pMenus.size()) + ")")) {
for (auto& jt : it.second->pLayout.IDObjects) { for (auto& it : pMenus) {
m->Label(std::format("{:08X}", jt->GetID())); if (m->BeginTreeNode(it.second->pID.GetName())) {
} m->Label("Name: " + it.second->pID.GetName());
m->EndTreeNode(); m->Label(std::format("Pos: {}", it.second->pLayout.GetPosition()));
} m->Label(std::format("Size: {}", it.second->pLayout.GetSize()));
m->EndTreeNode(); m->Label(std::format("WorkRect: {}", it.second->pLayout.WorkRect));
} m->Label(std::format("Cursor: {}", it.second->pLayout.Cursor));
} if (m->BeginTreeNode(
m->EndTreeNode(); "ID Objects (" +
} std::to_string(it.second->pLayout.IDObjects.size()) + ")")) {
if (m->BeginTreeNode("Active Menus (" + for (auto& jt : it.second->pLayout.IDObjects) {
std::to_string(pCurrentMenus.size()) + ")")) { m->Label(std::format("{:08X}", jt->GetID()));
for (auto& it : pCurrentMenus) { }
if (m->BeginTreeNode(pMenus[it]->pID.GetName())) { m->EndTreeNode();
m->Label("Name: " + pMenus[it]->pID.GetName()); }
m->Label(std::format("Pos: {}", pMenus[it]->pLayout.GetPosition())); m->EndTreeNode();
m->Label(std::format("Size: {}", pMenus[it]->pLayout.GetSize())); }
m->Label(std::format("WorkRect: {}", pMenus[it]->pLayout.WorkRect)); }
m->Label(std::format("Cursor: {}", pMenus[it]->pLayout.Cursor)); m->EndTreeNode();
if (m->BeginTreeNode( }
"ID Objects (" + if (m->BeginTreeNode("Active Menus (" +
std::to_string(pMenus[it]->pLayout.IDObjects.size()) + ")")) { std::to_string(pCurrentMenus.size()) + ")")) {
for (auto& jt : pMenus[it]->pLayout.IDObjects) { for (auto& it : pCurrentMenus) {
m->Label(std::format("{:08X}", jt->GetID())); if (m->BeginTreeNode(pMenus[it]->pID.GetName())) {
} m->Label("Name: " + pMenus[it]->pID.GetName());
m->EndTreeNode(); m->Label(std::format("Pos: {}", pMenus[it]->pLayout.GetPosition()));
} m->Label(std::format("Size: {}", pMenus[it]->pLayout.GetSize()));
m->EndTreeNode(); m->Label(std::format("WorkRect: {}", pMenus[it]->pLayout.WorkRect));
} m->Label(std::format("Cursor: {}", pMenus[it]->pLayout.Cursor));
} if (m->BeginTreeNode(
m->EndTreeNode(); "ID Objects (" +
} std::to_string(pMenus[it]->pLayout.IDObjects.size()) + ")")) {
// Well this are Li Drawlists now and they do not count their stats (yet) for (auto& jt : pMenus[it]->pLayout.IDObjects) {
/*if (m->BeginTreeNode("DrawLists (" + m->Label(std::format("{:08X}", jt->GetID()));
std::to_string(pIO.DrawListRegestry.size()) + ")")) { }
for (auto &it : pIO.DrawListRegestry) { m->EndTreeNode();
if (m->BeginTreeNode(it.First.GetName())) { }
m->Label("Vertices: " + std::to_string(it.Second->NumVertices)); m->EndTreeNode();
m->Label("Indices: " + std::to_string(it.Second->NumIndices)); }
m->Label("Base Layer: " + std::to_string(it.Second->Base)); }
m->EndTreeNode(); m->EndTreeNode();
} }
} // Well this are Li Drawlists now and they do not count their stats (yet)
m->EndTreeNode(); /*if (m->BeginTreeNode("DrawLists (" +
}*/ std::to_string(pIO.DrawListRegestry.size()) + ")")) {
m->Label("io->Time: " + Strings::FormatMillis(pIO.Time.Get())); for (auto &it : pIO.DrawListRegestry) {
m->Label(std::format("Delta: {:.3f}", pIO.Delta)); if (m->BeginTreeNode(it.First.GetName())) {
m->Label(std::format("Framerate: {:.2f}", pIO.Framerate)); m->Label("Vertices: " + std::to_string(it.Second->NumVertices));
m->Label(std::format("Focused Menu: {:08X}", pIO.InputHandler.FocusedMenu)); m->Label("Indices: " + std::to_string(it.Second->NumIndices));
m->Label( m->Label("Base Layer: " + std::to_string(it.Second->Base));
std::format("Dragged Object: {:08X}", pIO.InputHandler.DraggedObject)); m->EndTreeNode();
m->Label(std::format("DragTime: {:.2f}s", }
pIO.InputHandler.DragTime.GetSeconds())); }
m->Label( m->EndTreeNode();
std::format("DragDestination: [{}]", pIO.InputHandler.DragDestination)); }*/
m->Label(std::format("DragSource: [{}]", pIO.InputHandler.DragSourcePos)); m->Label("io->Time: " + Strings::FormatMillis(pIO.Time.Get()));
m->Label(std::format("DragPos: [{}]", pIO.InputHandler.DragPosition)); m->Label(std::format("Delta: {:.3f}", pIO.Delta));
m->Label( m->Label(std::format("Framerate: {:.2f}", pIO.Framerate));
std::format("DragLastPos: [{}]", pIO.InputHandler.DragLastPosition)); m->Label(std::format("Focused Menu: {:08X}", pIO.InputHandler.FocusedMenu));
EndMenu(); m->Label(
} std::format("Dragged Object: {:08X}", pIO.InputHandler.DraggedObject));
} m->Label(std::format("DragTime: {:.2f}s",
pIO.InputHandler.DragTime.GetSeconds()));
PD_API void UI7::Context::StyleEditor(bool* show) { m->Label(
if (auto m = BeginMenu("UI7 Style Editor", UI7MenuFlags_Scrolling, show)) { std::format("DragDestination: [{}]", pIO.InputHandler.DragDestination));
m->Label("Palladium - UI7 " + GetVersion() + " Style Editor"); m->Label(std::format("DragSource: [{}]", pIO.InputHandler.DragSourcePos));
m->Separator(); m->Label(std::format("DragPos: [{}]", pIO.InputHandler.DragPosition));
m->DragData("MenuPadding", (float*)&pIO.MenuPadding, 2, 0.f, 100.f); m->Label(
m->DragData("FramePadding", (float*)&pIO.FramePadding, 2, 0.f, 100.f); std::format("DragLastPos: [{}]", pIO.InputHandler.DragLastPosition));
m->DragData("ItemSpace", (float*)&pIO.ItemSpace, 2, 0.f, 100.f); EndMenu();
m->DragData("MinSliderSize", (float*)&pIO.MinSliderDragSize, 2, 1.f, 100.f); }
m->DragData("OverScroll Modifier", &pIO.OverScrollMod, 1, 0.01f, }
std::numeric_limits<float>::max(), 0.01f, 2);
m->Checkbox("Menu Border", pIO.ShowMenuBorder); PD_API void UI7::Context::StyleEditor(bool* show) {
m->Checkbox("Frame Border", pIO.ShowFrameBorder); if (auto m = BeginMenu("UI7 Style Editor", UI7MenuFlags_Scrolling, show)) {
m->SeparatorText("Theme"); m->Label("Palladium - UI7 " + GetVersion() + " Style Editor");
if (m->Button("Dark")) { m->Separator();
UI7::Theme::Default(pIO.Theme); m->DragData("MenuPadding", (float*)&pIO.MenuPadding, 2, 0.f, 100.f);
} m->DragData("FramePadding", (float*)&pIO.FramePadding, 2, 0.f, 100.f);
m->SameLine(); m->DragData("ItemSpace", (float*)&pIO.ItemSpace, 2, 0.f, 100.f);
if (m->Button("Flashbang")) { m->DragData("MinSliderSize", (float*)&pIO.MinSliderDragSize, 2, 1.f, 100.f);
UI7::Theme::Flashbang(pIO.Theme); m->DragData("OverScroll Modifier", &pIO.OverScrollMod, 1, 0.01f,
} std::numeric_limits<float>::max(), 0.01f, 2);
/// Small trick to print without prefix m->Checkbox("Menu Border", pIO.ShowMenuBorder);
#define ts(x) m->ColorEdit(std::string(#x).substr(9), pIO.Theme.GetRef(x)); m->Checkbox("Frame Border", pIO.ShowFrameBorder);
#define ts2(x) \ m->SeparatorText("Theme");
m->DragData(std::string(#x).substr(9), (u8*)&pIO.Theme.GetRef(x), 4, (u8)0, \ if (m->Button("Dark")) {
(u8)255); UI7::Theme::Default(pIO.Theme);
ts(UI7Color_Background); }
ts(UI7Color_Border); m->SameLine();
ts(UI7Color_Button); if (m->Button("Flashbang")) {
ts(UI7Color_ButtonDead); UI7::Theme::Flashbang(pIO.Theme);
ts(UI7Color_ButtonActive); }
ts(UI7Color_ButtonHovered); /// Small trick to print without prefix
ts(UI7Color_Text); #define ts(x) m->ColorEdit(std::string(#x).substr(9), pIO.Theme.GetRef(x));
ts(UI7Color_TextDead); #define ts2(x) \
ts(UI7Color_Header); m->DragData(std::string(#x).substr(9), (u8*)&pIO.Theme.GetRef(x), 4, (u8)0, \
ts(UI7Color_HeaderDead); (u8)255);
ts(UI7Color_Selector); ts(UI7Color_Background);
ts(UI7Color_Checkmark); ts(UI7Color_Border);
ts(UI7Color_FrameBackground); ts(UI7Color_Button);
ts(UI7Color_FrameBackgroundHovered); ts(UI7Color_ButtonDead);
ts(UI7Color_Progressbar); ts(UI7Color_ButtonActive);
ts(UI7Color_ListEven); ts(UI7Color_ButtonHovered);
ts(UI7Color_ListOdd); ts(UI7Color_Text);
this->EndMenu(); ts(UI7Color_TextDead);
} ts(UI7Color_Header);
} ts(UI7Color_HeaderDead);
} // namespace UI7 ts(UI7Color_Selector);
} // namespace PD ts(UI7Color_Checkmark);
ts(UI7Color_FrameBackground);
ts(UI7Color_FrameBackgroundHovered);
ts(UI7Color_Progressbar);
ts(UI7Color_ListEven);
ts(UI7Color_ListOdd);
this->EndMenu();
}
}
} // namespace UI7
} // namespace PD
+55
View File
@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.22)
project(test)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED true)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_EXPORT_COMPILE_COMMANDS true)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
if(${PD_BUILD_SHARED})
message(ERROR "3DS Only supports Static libraries")
endif()
endif()
add_subdirectory(../ palladium)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
add_subdirectory(../backends/3ds pd-3ds)
else()
add_subdirectory(../backends/desktop pd-desktop)
endif()
add_executable(test source/main.cpp
${BKND_SRC})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
target_link_libraries(test PUBLIC pd-3ds palladium)
else()
target_link_libraries(test PUBLIC pd-desktop palladium)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
target_compile_options(palladium PRIVATE
$<$<COMPILE_LANGUAGE:C>:-Wall>
$<$<COMPILE_LANGUAGE:C>:-Wno-psabi>
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Release")
target_compile_options(palladium PRIVATE
$<$<CONFIG:Debug>:-O0 -g>
$<$<CONFIG:Release>:-O3>
)
endif()
# set(RC_FILES
# testassets/ComicNeue.ttf
# testassets/logo.png
# testassets/test.png)
# install(FILES ${RC_FILES} DESTINATION ".")
# else()
# target_link_libraries(test PUBLIC pd-backend-3ds ctru citro3d)
# endif()
+17
View File
@@ -20,9 +20,26 @@ bool ColorTests() {
return true; return true;
} }
bool IDTests() {
std::cout << std::format("HashID32(\"1234\") -> {:016X}",
PD::HashID32("1234").Get())
<< std::endl;
std::cout << std::format("HashID32(\"1235\") -> {:016X}",
PD::HashID32("1235").Get())
<< std::endl;
std::cout << std::format("HashID64(\"1234\") -> {:016X}",
PD::HashID64("1234").Get())
<< std::endl;
std::cout << std::format("HashID64(\"1235\") -> {:016X}",
PD::HashID64("1235").Get())
<< std::endl;
return true;
}
int main() { int main() {
PD::Os::UseDriver<PD::OsDriver>(); PD::Os::UseDriver<PD::OsDriver>();
ColorTests(); ColorTests();
IDTests();
std::cout << PD::Os::GetTime() << std::endl; std::cout << PD::Os::GetTime() << std::endl;
PD::Pool<int> pool; PD::Pool<int> pool;
pool.Init(90); pool.Init(90);
+2
View File
@@ -21,6 +21,8 @@ class OsCtx {
virtual bool Mainloop() { return false; } virtual bool Mainloop() { return false; }
virtual void ClearViewPort() {} virtual void ClearViewPort() {}
virtual void SwapBuffers() {} virtual void SwapBuffers() {}
virtual int GetScreenCount() { return 1; }
virtual void DrawOnScreen(int s = 0) {}
PD::fvec2 PositionTranslate(PD::fvec2 in) { PD::fvec2 PositionTranslate(PD::fvec2 in) {
return fvec2(in.x * pViewPort.x, in.y * pViewPort.y); return fvec2(in.x * pViewPort.x, in.y * pViewPort.y);
} }
+2
View File
@@ -13,6 +13,8 @@ class HorizonCtr : public PD::OsCtx {
bool Mainloop() override; bool Mainloop() override;
void ClearViewPort() override; void ClearViewPort() override;
void SwapBuffers() override; void SwapBuffers() override;
int GetScreenCount() override { return 2; }
void DrawOnScreen(int s) override;
private: private:
struct Impl; struct Impl;
+13 -1
View File
@@ -208,10 +208,17 @@ int main(int argc, char** argv) {
RightStick.pColor = "#00ffff"; RightStick.pColor = "#00ffff";
PD::UI7::Context ui7; PD::UI7::Context ui7;
ui7.GetIO().Font = &font; ui7.GetIO().Font = &font;
#ifdef __3DS__
ui7.AddViewPort("Default", PD::ivec4(0, 0, 320, 240));
ui7.GetIO().FontScale = 0.5f;
#else
ui7.AddViewPort("Default", PD::ivec4(0, 0, 1280, 720)); ui7.AddViewPort("Default", PD::ivec4(0, 0, 1280, 720));
#endif
ui7.UseViewPort("Default"); ui7.UseViewPort("Default");
bool pMetricsWin = true;
while (pOs->Mainloop()) { while (pOs->Mainloop()) {
PD::TT::End("OSCTX::MainLoop"); PD::TT::End("OSCTX::MainLoop");
pOs->DrawOnScreen(0);
pOs->ClearViewPort(); pOs->ClearViewPort();
PD::TT::Scope __st("MainLoop"); PD::TT::Scope __st("MainLoop");
PD::TT::Beg("MainRaw"); PD::TT::Beg("MainRaw");
@@ -301,6 +308,7 @@ int main(int argc, char** argv) {
PD::TT::Beg("BuildUI7Menus"); PD::TT::Beg("BuildUI7Menus");
if (auto m = ui7.BeginMenu("Test")) { if (auto m = ui7.BeginMenu("Test")) {
m->Label("Hello World!"); m->Label("Hello World!");
m->Image(pTex, 128.f);
ui7.EndMenu(); ui7.EndMenu();
} }
if (auto m = ui7.BeginMenu("LI DBG INFO")) { if (auto m = ui7.BeginMenu("LI DBG INFO")) {
@@ -315,14 +323,18 @@ int main(int argc, char** argv) {
m->PopFont(); m->PopFont();
ui7.EndMenu(); ui7.EndMenu();
} }
ui7.MetricsMenu(); ui7.MetricsMenu(&pMetricsWin);
ui7.StyleEditor();
PD::TT::End("BuildUI7Menus"); PD::TT::End("BuildUI7Menus");
PD::TT::Beg("UI7::Context::Update"); PD::TT::Beg("UI7::Context::Update");
ui7.Update(); ui7.Update();
PD::TT::End("UI7::Context::Update"); PD::TT::End("UI7::Context::Update");
PD::Gfx::Reset(); PD::Gfx::Reset();
PD::TT::Beg("PD::Gfx::Draw"); PD::TT::Beg("PD::Gfx::Draw");
pOs->DrawOnScreen(1);
pOs->ClearViewPort();
PD::Gfx::Draw(ui7.GetDrawData()); PD::Gfx::Draw(ui7.GetDrawData());
pOs->DrawOnScreen(0);
PD::Gfx::Draw(pList); PD::Gfx::Draw(pList);
PD::TT::End("PD::Gfx::Draw"); PD::TT::End("PD::Gfx::Draw");
pList.Clear(); pList.Clear();
+15 -2
View File
@@ -16,6 +16,7 @@ struct HorizonCtr::Impl {
C3D_RenderTarget* Top = nullptr; C3D_RenderTarget* Top = nullptr;
C3D_RenderTarget* Bottom = nullptr; C3D_RenderTarget* Bottom = nullptr;
uint32_t* pSocBuf = nullptr; uint32_t* pSocBuf = nullptr;
int CurrentScreen = 0;
}; };
void HorizonCtr::Init() { void HorizonCtr::Init() {
@@ -63,13 +64,25 @@ bool HorizonCtr::Mainloop() {
pViewPort = ivec2(400, 240); pViewPort = ivec2(400, 240);
bool _kill = hidKeysUp() & KEY_START; bool _kill = hidKeysUp() & KEY_START;
C3D_FrameBegin(C3D_FRAME_SYNCDRAW); C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
impl->CurrentScreen = 0;
return aptMainLoop() && !_kill; return aptMainLoop() && !_kill;
} }
void HorizonCtr::ClearViewPort() { void HorizonCtr::ClearViewPort() {
C3D_RenderTargetClear(impl->CurrentScreen ? impl->Bottom : impl->Top,
C3D_CLEAR_ALL, PD::Color(25, 25, 25, 25), 0);
}
void HorizonCtr::DrawOnScreen(int s) {
impl->CurrentScreen = s;
if (s == 0) {
C3D_FrameDrawOn(impl->Top);
pViewPort = PD::ivec2(400, 240);
} else if (s == 1) {
C3D_FrameDrawOn(impl->Bottom);
pViewPort = PD::ivec2(320, 240);
}
PD::Gfx::SetViewPort(pViewPort); PD::Gfx::SetViewPort(pViewPort);
C3D_FrameDrawOn(impl->Top);
C3D_RenderTargetClear(impl->Top, C3D_CLEAR_ALL, PD::Color(25, 25, 25, 25), 0);
} }
void HorizonCtr::SwapBuffers() { C3D_FrameEnd(0); } void HorizonCtr::SwapBuffers() { C3D_FrameEnd(0); }