Compare commits

...

3 Commits

Author SHA1 Message Date
dbffb7f316 # 0.3.2
Implement Path render API into drawlist
Add some new drawing functions (need to make Rectangle -> RectFilled
Add Menu Border
ReSetup the Menu Input and Rendering API to fix flickering when moving
2025-03-21 16:23:17 +01:00
6738fda55c # 0.3.1-1
- Add Deltatime usage for Overscroll as well as a config value for ids multiplier
- Add Function to Layout to remove all ID Objects
- Add step and precision to DragData as well as setting min and max to their type limits
- Use the Address for now for the id of the DragData (cause with tree nodes opened backwars all DragData will share the same data reference)
- Add a fix to MaxPosition in Layout to be actually the max Position on X axis
2025-03-16 20:03:08 +01:00
35272687f6 # Changes 0.3.1
- Add Layout API and let Menu use it
- Add DragData (for float, double, int, etc)
- Add IO Delta calculation to not require a users delta value
- Add Config Var for SLider drag min size
- Remove Hid::Ref input of Containers as IO DragApi is used
- Containers that accept input will require an ID to function
2025-03-14 15:14:45 +01:00
25 changed files with 1024 additions and 529 deletions

View File

@ -52,7 +52,7 @@ execute_process(
) )
# Set Project # Set Project
project(palladium LANGUAGES C CXX VERSION 0.3.0) project(palladium LANGUAGES C CXX VERSION 0.3.2)
option(PD_BUILD_TESTS "Sets if TestApp and TestBench get build" OFF) option(PD_BUILD_TESTS "Sets if TestApp and TestBench get build" OFF)
@ -131,6 +131,7 @@ source/app/error.cpp)
set(UI7_SRC set(UI7_SRC
source/ui7/drawlist.cpp source/ui7/drawlist.cpp
source/ui7/io.cpp source/ui7/io.cpp
source/ui7/layout.cpp
source/ui7/menu.cpp source/ui7/menu.cpp
source/ui7/theme.cpp source/ui7/theme.cpp
source/ui7/ui7.cpp source/ui7/ui7.cpp
@ -138,6 +139,7 @@ source/ui7/container/container.cpp
source/ui7/container/button.cpp source/ui7/container/button.cpp
source/ui7/container/checkbox.cpp source/ui7/container/checkbox.cpp
source/ui7/container/coloredit.cpp source/ui7/container/coloredit.cpp
source/ui7/container/dragdata.cpp
source/ui7/container/image.cpp source/ui7/container/image.cpp
source/ui7/container/label.cpp) source/ui7/container/label.cpp)

View File

@ -36,7 +36,7 @@ make install
| pd-lithium | 0.2.9 | 3ds | pd-core, pd-image pd-lib3ds, citro3d | | pd-lithium | 0.2.9 | 3ds | pd-core, pd-image pd-lib3ds, citro3d |
| pd-sound | 0.2.4 | 3ds | pd-core, mpg123 | | pd-sound | 0.2.4 | 3ds | pd-core, mpg123 |
| pd-overlays | 0.2.4 | 3ds | pd-core, pd-image, pd-lib3ds, pd-lithium, pd-ui7 | | pd-overlays | 0.2.4 | 3ds | pd-core, pd-image, pd-lib3ds, pd-lithium, pd-ui7 |
| pd-ui7 | 0.2.9 | 3ds | pd-core, pd-image, pd-lib3ds, pd-lithium | | pd-ui7 | 0.3.1 | 3ds | pd-core, pd-image, pd-lib3ds, pd-lithium |
| pd-app | 0.2.4 | 3ds | pd-core, pd-image, pd-lib3ds, pd-lithium | | pd-app | 0.2.4 | 3ds | pd-core, pd-image, pd-lib3ds, pd-lithium |
## Credits ## Credits

View File

@ -54,9 +54,8 @@ class Button : public Container {
/** /**
* Override for the Input Handler * Override for the Input Handler
* @note This function is usally called by Menu::Update * @note This function is usally called by Menu::Update
* @param inp Reference to the Input Handler
*/ */
void HandleInput(Hid::Ref inp) override; void HandleInput() override;
/** /**
* Override for the Rendering Handler * Override for the Rendering Handler
* @note This function is usally called by Menu::Update * @note This function is usally called by Menu::Update

View File

@ -50,9 +50,8 @@ class Checkbox : public Container {
/** /**
* Override for the Input Handler * Override for the Input Handler
* @note This function is usally called by Menu::Update * @note This function is usally called by Menu::Update
* @param inp Reference to the Input Handler
*/ */
void HandleInput(Hid::Ref inp) override; void HandleInput() override;
/** /**
* Override for the Rendering Handler * Override for the Rendering Handler
* @note This function is usally called by Menu::Update * @note This function is usally called by Menu::Update

View File

@ -25,6 +25,7 @@ SOFTWARE.
#include <pd/ui7/container/container.hpp> #include <pd/ui7/container/container.hpp>
#include <pd/ui7/io.hpp> #include <pd/ui7/io.hpp>
#include <pd/ui7/layout.hpp>
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
@ -51,9 +52,8 @@ class ColorEdit : public Container {
/** /**
* Override for the Input Handler * Override for the Input Handler
* @note This function is usally called by Menu::Update * @note This function is usally called by Menu::Update
* @param inp Reference to the Input Handler
*/ */
void HandleInput(Hid::Ref inp) override; void HandleInput() override;
/** /**
* Override for the Rendering Handler * Override for the Rendering Handler
* @note This function is usally called by Menu::Update * @note This function is usally called by Menu::Update
@ -68,6 +68,8 @@ class ColorEdit : public Container {
u32* color_ref = nullptr; ///< Color Reference u32* color_ref = nullptr; ///< Color Reference
u32 initial_color; ///< Initial Color u32 initial_color; ///< Initial Color
std::string label; ///< Label of the Button std::string label; ///< Label of the Button
Layout::Ref layout; ///< Layout to open
bool is_shown = false; ///< AHow Layout Editor
}; };
} // namespace UI7 } // namespace UI7
} // namespace PD } // namespace PD

View File

@ -103,7 +103,7 @@ class Container : public SmartCtor<Container> {
*/ */
void HandleScrolling(vec2 scrolling, vec4 viewport); void HandleScrolling(vec2 scrolling, vec4 viewport);
/** Template function for Input Handling */ /** Template function for Input Handling */
virtual void HandleInput(Hid::Ref inp) {} virtual void HandleInput() {}
/** Tamplate function for Object rendering */ /** Tamplate function for Object rendering */
virtual void Draw() {} virtual void Draw() {}
/** Template function to update internal data (if needed) */ /** Template function to update internal data (if needed) */

View File

@ -0,0 +1,90 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
SOFTWARE.
*/
#include <pd/ui7/container/container.hpp>
#include <pd/ui7/io.hpp>
namespace PD {
namespace UI7 {
/**
* DragData Object can take a datatype or a list
* and modifys these by moving left or right when dragging
*/
template <typename T>
class DragData : public Container {
public:
/**
* Constructor
* @param label Label of the Button
* @param data Data reference (Supported types can be seen in dragdata.cpp)
* @param num_elms Number of Array elements (for exaple with use ofvec4)
* @param io IO Reference
* @param min minimum number using Minimum limit
* @param max Maximum number set by max limit by default
* @param step To set the modifier for drag movement
* @param precision for float and double to set precision
*/
DragData(const std::string& label, T* data, size_t num_elms, UI7::IO::Ref io,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(), T step = 1,
int precision = 1) {
PD::Assert(data != nullptr, "Input Data Address is null!");
this->label = label;
this->data = data;
this->elm_count = num_elms;
this->min = min;
this->max = max;
this->step = step;
this->precision = precision;
this->tdim = io->Ren->GetTextDimensions(label);
}
~DragData() = default;
/**
* Override for the Input Handler
* @note This function is usally called by Menu::Update
*/
void HandleInput() override;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
/** Function to Update Size if framepadding changes */
void Update() override;
private:
vec2 tdim; ///< Text size
std::string label; ///< Label of the Button
T* data;
size_t elm_count = 0;
T min;
T max;
T step;
int precision = 1;
};
} // namespace UI7
} // namespace PD

View File

@ -26,5 +26,6 @@ SOFTWARE.
#include <pd/ui7/container/button.hpp> #include <pd/ui7/container/button.hpp>
#include <pd/ui7/container/checkbox.hpp> #include <pd/ui7/container/checkbox.hpp>
#include <pd/ui7/container/coloredit.hpp> #include <pd/ui7/container/coloredit.hpp>
#include <pd/ui7/container/dragdata.hpp>
#include <pd/ui7/container/image.hpp> #include <pd/ui7/container/image.hpp>
#include <pd/ui7/container/label.hpp> #include <pd/ui7/container/label.hpp>

View File

@ -25,6 +25,7 @@ SOFTWARE.
#include <pd/core/common.hpp> #include <pd/core/common.hpp>
#include <pd/lithium/renderer.hpp> #include <pd/lithium/renderer.hpp>
#include <pd/ui7/flags.hpp>
#include <pd/ui7/theme.hpp> #include <pd/ui7/theme.hpp>
namespace PD { namespace PD {
@ -39,6 +40,15 @@ class DrawList : public SmartCtor<DrawList> {
DrawList(LI::Renderer::Ref r) { ren = r; } DrawList(LI::Renderer::Ref r) { ren = r; }
~DrawList() = default; ~DrawList() = default;
/**
* Draw a Rectangle (LINED)
* @param pos position of the rect
* @param size Size of the rect
* @param clr Color of the rect
* @param thickness Thickness of the lines
*/
void AddRect(const vec2& pos, const vec2& size, const UI7Color& clr,
int thickness = 1);
/** /**
* Render a Rectangle * Render a Rectangle
* @param pos Position * @param pos Position
@ -48,12 +58,43 @@ class DrawList : public SmartCtor<DrawList> {
void AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr); void AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr);
/** /**
* Render a Triangle * Render a Triangle
* @param pos0 Position a * @param a Position a
* @param pos1 Position b * @param b Position b
* @param pos2 Position c * @param c Position c
* @param clr Color
* @param thickness Thickness of the lines
*/
void AddTriangle(const vec2& a, const vec2& b, const vec2& c,
const UI7Color& clr, int thickness = 1);
/**
* Render a Filled Triangle
* @param a Position a
* @param b Position b
* @param c Position c
* @param clr Color * @param clr Color
*/ */
void AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2, const UI7Color& clr); void AddTriangleFilled(const vec2& a, const vec2& b, const vec2& c,
const UI7Color& clr);
/**
* Add a Lined Circle
* @param pos Center position
* @param rad radius of the circle
* @param col Color of the Circle
* @param num_segments Number of Segments (0 = auto)
* @param thickness thickness of the line
*/
void AddCircle(const vec2& pos, float rad, UI7Color col, int num_segments = 0,
int thickness = 1);
/**
* Add a Circle
* @param pos Center position
* @param rad radius of the circle
* @param col Color of the Circle
* @param num_segments Number of Segments (0 = auto)
*/
void AddCircleFilled(const vec2& pos, float rad, UI7Color col,
int num_segments = 0);
/** /**
* Render a Text * Render a Text
* @param pos Position * @param pos Position
@ -82,6 +123,24 @@ class DrawList : public SmartCtor<DrawList> {
*/ */
void AddLine(const vec2& a, const vec2& b, const UI7Color& clr, int t = 1); void AddLine(const vec2& a, const vec2& b, const UI7Color& clr, int t = 1);
/**
* Take list of points and display it as a line on screen
* @param points List of Positions
* @param clr Color of the Line
* @param flags Additional Flags (Close for go back to starting point)
* @param thickness Thickness of the Line
*/
void AddPolyLine(const std::vector<vec2>& points, const UI7Color& clr,
UI7DrawFlags flags = 0, int thickness = 1);
/**
* Take a List ofpoints and display it as Filled Shape
* @note Keep in mind to setup the list of points clockwise
* @param points List of Points
* @param clr Color of the shape
*/
void AddConvexPolyFilled(const std::vector<vec2>& points,
const UI7Color& clr);
/** Clear the Drawlist */ /** Clear the Drawlist */
void Clear(); void Clear();
/** Process [Render] the Drawlist */ /** Process [Render] the Drawlist */
@ -98,6 +157,61 @@ class DrawList : public SmartCtor<DrawList> {
/** Setter fot the Layer */ /** Setter fot the Layer */
void Layer(int v) { layer = v; } void Layer(int v) { layer = v; }
/** Path API */
/**
* Function to reserve Memory to prevent overhead on
* pusing a lot of points with PathNext
* @param num_points Number of Positions you want to add
*/
void PathReserve(size_t num_points) {
Path.reserve(Path.size() + num_points);
}
/**
* Clear current Path
* @note PathStroke and PathFill will automatically clear
*/
void PathClear() { Path.clear(); }
/**
* Add a Point to the Path
* @note Keep in mind that this function is used for
* setting the starting point
* @param v Position to add
*/
void PathNext(const vec2& v) { Path.push_back(v); }
/**
* Path Stroke Create Line from point to point
* @note For Primitives like Rect or Triangle mak sure to use
* UI7DrawFlags_Close to add a line back to the starting point
* @param clr Color od the line
* @param thickness Thickness of the line
* @param flags Additional Drawflags
*/
void PathStroke(const UI7Color& clr, int thickness = 1,
UI7DrawFlags flags = 0) {
AddPolyLine(Path, clr, flags, thickness);
Path.clear();
}
/**
* Fill a Path with a Color
* @note **IMPORTANT: ** Paths need to be setup clockwise
* to be rendered correctly
* @param clr Fill Color
*/
void PathFill(const UI7Color& clr) {
AddConvexPolyFilled(Path, clr);
Path.clear();
}
void PathArcToN(const vec2& c, float radius, float a_min, float a_max,
int segments);
/// @brief Create a Path Rect (uses to Positions instead of Pos/Size)
/// @param a Top Left Position
/// @param b Bottom Right Position
/// @param rounding rounding
/// @param flags DrawFlags (for special rounding rules)
void PathRect(vec2 a, vec2 b, float rounding = 0.f, UI7DrawFlags flags = 0);
private: private:
/** Base Layer offset (Internal Used) */ /** Base Layer offset (Internal Used) */
int BaseLayer() const { return base; } int BaseLayer() const { return base; }
@ -114,6 +228,7 @@ class DrawList : public SmartCtor<DrawList> {
std::stack<vec4> clip_rects; ///< Stack containing Scissor Areas std::stack<vec4> clip_rects; ///< Stack containing Scissor Areas
u32 num_vertices; ///< Number of Vertices u32 num_vertices; ///< Number of Vertices
u32 num_indices; ///< Number of Indices u32 num_indices; ///< Number of Indices
std::vector<vec2> Path;
// Map for Auto Static Text // Map for Auto Static Text
std::unordered_map<u32, LI::StaticText::Ref> static_text; std::unordered_map<u32, LI::StaticText::Ref> static_text;
// List of Drawcommands generated // List of Drawcommands generated

View File

@ -29,6 +29,10 @@ using UI7MenuFlags = unsigned int;
using UI7Align = unsigned int; using UI7Align = unsigned int;
/** 32Bit Value to store Context (IO) flags */ /** 32Bit Value to store Context (IO) flags */
using UI7IOFlags = unsigned int; using UI7IOFlags = unsigned int;
/** 32Bit Value for Layout Flags */
using UI7LayoutFlags = unsigned int;
/** 32Bit value for DrawFlags */
using UI7DrawFlags = unsigned int;
/** Menu Flags */ /** Menu Flags */
enum UI7MenuFlags_ { enum UI7MenuFlags_ {
@ -48,6 +52,18 @@ enum UI7MenuFlags_ {
UI7MenuFlags_Scrolling = UI7MenuFlags_HzScrolling | UI7MenuFlags_VtScrolling, UI7MenuFlags_Scrolling = UI7MenuFlags_HzScrolling | UI7MenuFlags_VtScrolling,
}; };
/** UI7 Layout Flags */
enum UI7LayoutFlags_ {
UI7LayoutFlags_None = 0, ///< No Flags used
UI7LayoutFlags_UseClipRect = 1 << 0, ///< Enable ClipRect
};
enum UI7DrawFlags_ {
UI7DrawFlags_None = 0,
UI7DrawFlags_Close = 1 << 0, ///< Close a PolyLine
UI7DrawFlags_AALines = 1 << 1, ///< Anti aliased Lines
};
/** UI7 Context Flags */ /** UI7 Context Flags */
enum UI7IOFlags_ { enum UI7IOFlags_ {
UI7IOFlags_None = 0, ///< No Additional Config available UI7IOFlags_None = 0, ///< No Additional Config available

View File

@ -61,6 +61,7 @@ class IO : public SmartCtor<IO> {
float Framerate = 0.f; float Framerate = 0.f;
float Delta = 0.f; float Delta = 0.f;
u64 LastTime = 0;
TimeStats::Ref DeltaStats; TimeStats::Ref DeltaStats;
Timer::Ref Time; Timer::Ref Time;
Hid::Ref Inp; Hid::Ref Inp;
@ -69,6 +70,10 @@ class IO : public SmartCtor<IO> {
vec2 MenuPadding = 5.f; vec2 MenuPadding = 5.f;
vec2 FramePadding = 5.f; vec2 FramePadding = 5.f;
vec2 ItemSpace = vec2(5.f, 2.f); vec2 ItemSpace = vec2(5.f, 2.f);
vec2 MinSliderDragSize = 10.f; // Min height (Vt) and Min Width (Hz)
bool ShowMenuBorder = true;
bool ShowFrameBorder = false; // not implemented yet
float OverScrollMod = 0.15f;
u64 DoubleClickTime = 500; // Milliseconds u64 DoubleClickTime = 500; // Milliseconds
std::vector<std::pair<UI7::ID, DrawList::Ref>> DrawListRegestry; std::vector<std::pair<UI7::ID, DrawList::Ref>> DrawListRegestry;
DrawList::Ref Back; DrawList::Ref Back;

120
include/pd/ui7/layout.hpp Normal file
View File

@ -0,0 +1,120 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
SOFTWARE.
*/
#include <pd/core/common.hpp>
#include <pd/ui7/container/container.hpp>
#include <pd/ui7/drawlist.hpp>
#include <pd/ui7/flags.hpp>
#include <pd/ui7/io.hpp>
namespace PD {
namespace UI7 {
class Layout : public PD::SmartCtor<Layout> {
public:
Layout(const ID& id, IO::Ref io) : ID(id) {
this->IO = io;
DrawList = UI7::DrawList::New(io->Ren);
Scrolling[0] = false;
Scrolling[1] = false;
CursorInit();
Pos = vec2(0, 0);
Size = vec2(320, 240);
WorkRect = vec4(IO->MenuPadding, Size - (vec2(2) * IO->MenuPadding));
}
~Layout() = default;
const std::string& GetName() const { return ID.GetName(); }
const UI7::ID& GetID() const { return this->ID; }
const vec2& GetPosition() const { return Pos; }
void SetPosition(const vec2& v) { Pos = v; }
const vec2& GetSize() const { return Size; }
void SetSize(const vec2& v) { Size = v; }
UI7::DrawList::Ref GetDrawList() { return DrawList; }
void CursorInit();
void SameLine();
void CursorMove(const vec2& size);
bool ObjectWorkPos(vec2& movpos);
void AddObject(Container::Ref obj);
Container::Ref FindObject(u32 id);
void ClearIDObjects() { IDObjects.clear(); }
vec2 AlignPosition(vec2 pos, vec2 size, vec4 area, UI7Align alignment);
/** Get the Alignment for Current State */
UI7Align GetAlignment() {
/// if temp alignment is used then return it and
/// reset tmpalign
if (TempAlign) {
auto t = TempAlign;
TempAlign = 0;
return t;
}
return Alignment;
}
void SetAlign(UI7Align a) { Alignment = a; }
void NextAlign(UI7Align a) { TempAlign = a; }
void Update();
private:
friend class Menu;
friend class Context;
// Base Components
UI7::ID ID;
UI7::IO::Ref IO;
UI7::DrawList::Ref DrawList;
// Positioning
vec2 Pos;
vec2 Size;
UI7Align Alignment = UI7Align_Default;
UI7Align TempAlign;
// Cursor
vec2 Cursor;
vec2 InitialCursorOffset;
vec2 BackupCursor;
vec2 SamelineCursor;
vec2 BeforeSameLine;
vec2 LastObjSize;
vec2 MaxPosition;
vec4 WorkRect;
// Scrolling
vec2 ScrollOffset;
bool Scrolling[2];
// Objects
std::vector<Container::Ref> Objects;
std::vector<Container::Ref> IDObjects;
};
} // namespace UI7
} // namespace PD

View File

@ -30,6 +30,7 @@ SOFTWARE.
#include <pd/ui7/flags.hpp> #include <pd/ui7/flags.hpp>
#include <pd/ui7/id.hpp> #include <pd/ui7/id.hpp>
#include <pd/ui7/io.hpp> #include <pd/ui7/io.hpp>
#include <pd/ui7/layout.hpp>
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
@ -47,12 +48,11 @@ class Menu : public SmartCtor<Menu> {
this->id = id; this->id = id;
this->name = id.GetName(); this->name = id.GetName();
/// Set Default Values here /// Set Default Values here
scrolling[0] = false;
scrolling[1] = false;
scrollbar[0] = false; scrollbar[0] = false;
scrollbar[1] = false; scrollbar[1] = false;
scroll_allowed[0] = false; scroll_allowed[0] = false;
scroll_allowed[1] = false; scroll_allowed[1] = false;
Layout = UI7::Layout::New(id, io);
} }
~Menu() = default; ~Menu() = default;
@ -88,6 +88,22 @@ class Menu : public SmartCtor<Menu> {
* @param color Color reference to edit * @param color Color reference to edit
*/ */
void ColorEdit(const std::string& label, u32* color); void ColorEdit(const std::string& label, u32* color);
void DragFloat(const std::string& label, float* data, size_t num_elms);
template <typename T>
void DragData(const std::string& label, T* data, size_t num_elms = 1,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(), T step = 1,
int precision = 1) {
u32 id = Strings::FastHash("drd" + label + std::to_string((u32)data));
Container::Ref r = Layout->FindObject(id);
if (!r) {
r = PD::New<UI7::DragData<T>>(label, data, num_elms, io, min, max, step,
precision);
r->SetID(id);
}
Layout->AddObject(r);
}
// Basic API // Basic API
/** /**
@ -102,7 +118,7 @@ class Menu : public SmartCtor<Menu> {
void EndTreeNode(); void EndTreeNode();
/** Add the Next Objext to the same line */ /** Add the Next Objext to the same line */
void SameLine(); void SameLine() { Layout->SameLine(); }
/** Add a Separator Line */ /** Add a Separator Line */
void Separator(); void Separator();
/** /**
@ -128,23 +144,14 @@ class Menu : public SmartCtor<Menu> {
* Set a Temp alignment op for the next Object * Set a Temp alignment op for the next Object
* @param a Alignment Operation * @param a Alignment Operation
*/ */
void NextAlign(UI7Align a) { tmpalign = a; } void NextAlign(UI7Align a) { Layout->NextAlign(a); }
/** /**
* Align Every Single Object by this operationset * Align Every Single Object by this operationset
* @param a Alignment * @param a Alignment
*/ */
void PushAlignment(UI7Align a) { alignment = a; } void PushAlignment(UI7Align a) { Layout->SetAlign(a); }
/** Use default alignment */ /** Use default alignment */
void PopAlignment() { alignment = UI7Align_Default; } void PopAlignment() { Layout->Alignment = UI7Align_Default; }
/**
* Get a New Position depending on the Alignment
* @param pos Current Position
* @param size Object size
* @param view Viewport [position and size]
* @param a Alignment Operations
* @return new position based on the alignment
*/
static vec2 AlignPos(vec2 pos, vec2 size, vec4 view, UI7Align a);
/** /**
* Returns a Reference to the theme * Returns a Reference to the theme
* @return Reference to the base Theme of the context * @return Reference to the base Theme of the context
@ -166,35 +173,6 @@ class Menu : public SmartCtor<Menu> {
// API for Custom Objects // API for Custom Objects
/**
* Handles the Position of Objects in Scrolling Menu
* @note As Containers have their own FUnc to handle this, this
* function is only useful to Render Live Objects whicch cannot be aligned
* by the internal Alignment Api
* @param pos position reference to write the new position to
* @param size size of the Object
* @return if the object can be skipped in rendering
*/
bool HandleScrolling(vec2& pos, const vec2& size);
/**
* Get the Cursor Position
* @return Cursor Pos
*/
vec2 Cursor() const { return view_area.xy() + cursor; }
/**
* Set the Cursor position
* @note The old Position can be restored with RestoreCursor
* @param v New Position
*/
void Cursor(const vec2& v) {
bcursor = cursor;
cursor = v;
}
/** Restore to the last cursor Position */
void RestoreCursor() {
cursor = bcursor;
bcursor = vec2();
}
/** Return if a Vertical Scrollbar exists */ /** Return if a Vertical Scrollbar exists */
bool HasVerticalScrollbar() { return scrollbar[1]; } bool HasVerticalScrollbar() { return scrollbar[1]; }
/** Return if a Horizontal Scrollbar exists */ /** Return if a Horizontal Scrollbar exists */
@ -206,43 +184,13 @@ class Menu : public SmartCtor<Menu> {
* @note Could destroy some basic functionality * @note Could destroy some basic functionality
*/ */
void TitleBarHeight(float v) { tbh = v; } void TitleBarHeight(float v) { tbh = v; }
/**
* Init the Cursor
* @note Useful when using with a Custom TitlebarHeight
*/
void CursorInit() { Cursor(io->MenuPadding + vec2(0, tbh)); }
/**
* Move the Cursor for new Object
* @param szs Size of the current Object
*/
void CursorMove(const vec2& szs);
/** Get the ViewArea of the Menu */
vec4 ViewArea() const { return view_area; }
/**
* Get the Main Area of the Menu
* (only relevant for input)
*/
vec4 MainArea() const { return main_area; }
/**
* Set a MainArea for input
* @param v Area where Objects can receive inputs
*/
void MainArea(const vec4& v) { main_area = v; }
/** Get The Scrolling offset */
vec2 ScrollOffset() const { return scrolling_off; }
/**
* Set a Scrolling offset
* @param v Custom Scrolling offset
*/
void ScrollOffset(const vec2& v) { scrolling_off = v; }
/** Get the Current Scrollmodification value */
vec2 ScrollMod() const { return scroll_mod; }
/** /**
* Animated Scroll to Position * Animated Scroll to Position
* @param pos Destination Position * @param pos Destination Position
*/ */
void ScrollTo(vec2 pos) { void ScrollTo(vec2 pos) {
scroll_anim.From(scrolling_off) scroll_anim.From(Layout->ScrollOffset)
.To(pos) .To(pos)
.In(1.f) .In(1.f)
.As(scroll_anim.EaseInOutSine); .As(scroll_anim.EaseInOutSine);
@ -252,19 +200,6 @@ class Menu : public SmartCtor<Menu> {
// Objects API // Objects API
/**
* Push an object to the current ListHandler
* @param obj Object reference to use
* @return Reference to the Object (from a time
* where ObjectPush(Container::New()) was used)
*/
Container::Ref ObjectPush(Container::Ref obj);
/**
* Search for an Object by an id
* @param id 32 Bit hash/id
* @return the found Object or nullptr
*/
Container::Ref FindIDObj(u32 id);
/** /**
* Create a Parent Container to move and edit all sub * Create a Parent Container to move and edit all sub
* instances at once * instances at once
@ -276,7 +211,8 @@ class Menu : public SmartCtor<Menu> {
// Draw List // Draw List
/** Get DrawList */ /** Get DrawList */
DrawList::Ref GetDrawList() { return main; } DrawList::Ref GetDrawList() { return Layout->DrawList; }
UI7::Layout::Ref GetLayout() { return Layout; }
// Advanced // Advanced
@ -305,43 +241,6 @@ class Menu : public SmartCtor<Menu> {
/** Handle things like scrolling */ /** Handle things like scrolling */
void PostHandler(); void PostHandler();
// Basic Settings
/**
* Set Backup Cursor
* @param v Position
*/
void BackupCursor(const vec2& v) { bcursor = v; }
/** Get Sameline Cursor */
vec2 SameLineCursor() const { return slcursor; }
/**
* Set Sameline Cursor
* @param v Position
*/
void SameLineCursor(const vec2& v) { slcursor = v; }
/**
* Set View Area
* @param v vec4 containing pos and size
*/
void ViewArea(const vec4& v) { view_area = v; }
/**
* Set Scroll Modification
* @param v Mod
*/
void ScrollMod(const vec2& v) { scroll_mod = v; }
/** Get the Alignment for Current State */
UI7Align GetAlignment() {
/// if temp alignment is used then return it and
/// reset tmpalign
if (tmpalign) {
auto t = tmpalign;
tmpalign = 0;
return t;
}
return alignment;
}
/** Internal Processing */ /** Internal Processing */
void Update(float delta); void Update(float delta);
@ -363,21 +262,9 @@ class Menu : public SmartCtor<Menu> {
// Data // Data
// Default Alignment for all Objects
UI7Align alignment = UI7Align_Default;
UI7Align tmpalign = 0; ///< Temp Alignment [only used once]
UI7MenuFlags flags = 0; ///< Menu Flags UI7MenuFlags flags = 0; ///< Menu Flags
u32 id; ///< Menu ID u32 id; ///< Menu ID
std::string name; ///< Menu Name std::string name; ///< Menu Name
vec2 cursor; ///< Current Cursor Position
vec2 icursoroff; ///< Initial Cursor Offset (Also in Newline)
vec2 bcursor; ///< Backup Cursor
vec2 slcursor; ///< Sameline Cursor
vec4 view_area; ///< view Area (Position and Size)
vec4 main_area; ///< Main Area [Input related]
vec2 scrolling_off; ///< Scrolling Position
bool scrolling[2]; ///< Is Hz or Vt Scrolling Enabled
vec2 scroll_mod; ///< Scroll Modificator
float tbh; ///< Titlebar height float tbh; ///< Titlebar height
bool scrollbar[2]; ///< Is Hz or Vt Scrollbar rendered bool scrollbar[2]; ///< Is Hz or Vt Scrollbar rendered
bool scroll_allowed[2]; ///< Is Hz or Vt Scrolling Alowed bool scroll_allowed[2]; ///< Is Hz or Vt Scrolling Alowed
@ -389,20 +276,9 @@ class Menu : public SmartCtor<Menu> {
// Objects API // Objects API
std::vector<Container::Ref> objects; ///< Current frame Objects std::vector<Container*> join; ///< List of Combined Objects
std::vector<Container::Ref> idobjs; ///< Objects using an ID int count_btn = 0; ///< Count for Button ID Prefix
std::vector<Container*> join; ///< List of Combined Objects int count_cbx = 0; ///< Cound for Checkbox ID Prefix
int count_btn = 0; ///< Count for Button ID Prefix
int count_cbx = 0; ///< Cound for Checkbox ID Prefix
// DrawList
DrawList::Ref main; ///< Main Drawlist
vec2 max; ///< Max Position
vec2 mouse; ///< Mouse/Touch Position
vec2 bslpos; ///< Before Sameline Position
vec2 last_size; ///< Last Object Size
UI7::IO::Ref io; ///< IO Reference UI7::IO::Ref io; ///< IO Reference
@ -411,6 +287,12 @@ class Menu : public SmartCtor<Menu> {
// Animations System // Animations System
Tween<vec2> scroll_anim; ///< for Scroll to Animation Tween<vec2> scroll_anim; ///< for Scroll to Animation
// Layout API
PD::UI7::Layout::Ref Layout;
UI7Color clr_close_btn = UI7Color_FrameBackground;
UI7Color clr_collapse_tri = UI7Color_FrameBackground;
}; };
} // namespace UI7 } // namespace UI7
} // namespace PD } // namespace PD

View File

@ -34,6 +34,7 @@ using UI7Color = PD::u32;
/** Theme Color */ /** Theme Color */
enum UI7Color_ { enum UI7Color_ {
UI7Color_Background, ///< UI7 Menu Background UI7Color_Background, ///< UI7 Menu Background
UI7Color_Border, ///< Menu/Frame Border Color
UI7Color_Button, ///< UI7 Button Idle Color UI7Color_Button, ///< UI7 Button Idle Color
UI7Color_ButtonDead, ///< UI7 Disabled Button Color UI7Color_ButtonDead, ///< UI7 Disabled Button Color
UI7Color_ButtonActive, ///< UI7 Pressed Button Color UI7Color_ButtonActive, ///< UI7 Pressed Button Color

View File

@ -37,7 +37,7 @@ SOFTWARE.
* Major Minor Patch Build * Major Minor Patch Build
* 0x01010000 -> 1.1.0-0 * 0x01010000 -> 1.1.0-0
*/ */
#define UI7_VERSION 0x00030000 #define UI7_VERSION 0x00030200
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {

View File

@ -25,7 +25,7 @@ SOFTWARE.
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
void Button::HandleInput(Hid::Ref inp) { void Button::HandleInput() {
/// Ensure to only check input once /// Ensure to only check input once
if (inp_done) { if (inp_done) {
return; return;

View File

@ -25,7 +25,7 @@ SOFTWARE.
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
void Checkbox::HandleInput(Hid::Ref inp) { void Checkbox::HandleInput() {
/// Ensure to only check input once /// Ensure to only check input once
if (inp_done) { if (inp_done) {
return; return;

View File

@ -22,10 +22,11 @@ SOFTWARE.
*/ */
#include <pd/ui7/container/coloredit.hpp> #include <pd/ui7/container/coloredit.hpp>
#include <pd/ui7/container/label.hpp>
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
void ColorEdit::HandleInput(Hid::Ref inp) { void ColorEdit::HandleInput() {
/// Ensure to only check input once /// Ensure to only check input once
if (inp_done) { if (inp_done) {
return; return;
@ -34,6 +35,7 @@ void ColorEdit::HandleInput(Hid::Ref inp) {
if (screen->ScreenType() == Screen::Bottom) { if (screen->ScreenType() == Screen::Bottom) {
if (io->DragObject(this->GetID(), vec4(FinalPos(), size))) { if (io->DragObject(this->GetID(), vec4(FinalPos(), size))) {
if (io->DragReleased) { if (io->DragReleased) {
is_shown = !is_shown;
} }
} }
} }
@ -45,6 +47,14 @@ void ColorEdit::Draw() {
list->AddRectangle(FinalPos(), vec2(20, 20), *color_ref); list->AddRectangle(FinalPos(), vec2(20, 20), *color_ref);
list->AddText(FinalPos() + vec2(io->ItemSpace.x() + 20, 0), label, list->AddText(FinalPos() + vec2(io->ItemSpace.x() + 20, 0), label,
io->Theme->Get(UI7Color_Text)); io->Theme->Get(UI7Color_Text));
if (is_shown) {
if (!layout) {
layout = Layout::New(GetID(), io);
}
layout->AddObject(PD::New<Label>("Hello World!", io->Ren));
layout->Update();
io->RegisterDrawList(GetID(), layout->GetDrawList());
}
} }
void ColorEdit::Update() { void ColorEdit::Update() {

View File

@ -0,0 +1,113 @@
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
SOFTWARE.
*/
#include <pd/ui7/container/dragdata.hpp>
#include <pd/ui7/container/label.hpp>
#include <type_traits>
namespace PD {
namespace UI7 {
// Setup Supported Datatypes (Probably making this Object
// header only to not care about datatype support)
template class DragData<float>;
template class DragData<int>;
template class DragData<double>;
template class DragData<u8>;
template class DragData<u16>;
template class DragData<u32>;
template class DragData<u64>;
template <typename T>
void DragData<T>::HandleInput() {
/// Ensure to only check input once
if (inp_done) {
return;
}
Assert(screen.get(), "Screen is not set up!");
if (screen->ScreenType() == Screen::Bottom) {
float off_x = 0;
for (size_t i = 0; i < elm_count; i++) {
std::string p;
if constexpr (std::is_floating_point_v<T>) {
p = std::format("{:.{}f}", data[i], precision);
} else {
p = std::format("{}", data[i]);
}
vec2 tdim = io->Ren->GetTextDimensions(p);
// Unsafe but is the fastest solution
if (io->DragObject(
this->GetID() + i + 1,
vec4(FinalPos() + vec2(off_x, 0), tdim + io->FramePadding))) {
data[i] = std::clamp(T(data[i] + (step * (io->DragPosition[0] -
io->DragLastPosition[0]))),
this->min, this->max);
}
off_x += tdim.x() + io->ItemSpace.x() + io->FramePadding.x();
}
}
inp_done = true;
}
template <typename T>
void DragData<T>::Draw() {
Assert(io.get() && list.get(), "Did you run Container::Init correctly?");
io->Ren->OnScreen(screen);
float off_x = 0.f;
for (size_t i = 0; i < elm_count; i++) {
std::string p;
if constexpr (std::is_floating_point_v<T>) {
p = std::format("{:.{}f}", data[i], precision);
} else {
p = std::format("{}", data[i]);
}
vec2 td = io->Ren->GetTextDimensions(p);
list->AddRectangle(FinalPos() + vec2(off_x, 0), td + io->FramePadding,
io->Theme->Get(UI7Color_Button));
list->Layer(list->Layer() + 1);
list->AddText(FinalPos() + vec2(off_x, 0), p, io->Theme->Get(UI7Color_Text),
LITextFlags_AlignMid, td + io->FramePadding);
list->Layer(list->Layer() - 1);
off_x += td.x() + io->ItemSpace.x() + io->FramePadding.x();
}
list->AddText(FinalPos() + vec2(off_x, io->FramePadding.y() * 0.5), label,
io->Theme->Get(UI7Color_Text));
}
template <typename T>
void DragData<T>::Update() {
Assert(io.get(), "Did you run Container::Init correctly?");
// Probably need to find a faster solution (caching sizes calculated here)
float off_x = 0;
for (size_t i = 0; i < elm_count; i++) {
std::string p;
if constexpr (std::is_floating_point_v<T>) {
p = std::format("{:.{}f}", data[i], precision);
} else {
p = std::format("{}", data[i]);
}
vec2 tdim = io->Ren->GetTextDimensions(p);
off_x += tdim.x() + io->ItemSpace.x() + io->FramePadding.x();
}
this->SetSize(vec2(tdim.x() + off_x, tdim.y() + io->FramePadding.y()));
}
} // namespace UI7
} // namespace PD

View File

@ -26,40 +26,88 @@ SOFTWARE.
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
void DrawList::PathArcToN(const vec2& c, float radius, float a_min, float a_max,
int segments) {
// Path.push_back(c);
PathReserve(segments + 1);
for (int i = 0; i < segments; i++) {
float a = a_min + ((float)i / (float)segments) * (a_max - a_min);
PathNext(vec2(c.x() + std::cos(a) * radius, c.y() + std::sin(a) * radius));
}
}
void DrawList::PathRect(vec2 a, vec2 b, float rounding, UI7DrawFlags flags) {
if (rounding == 0.f) {
PathNext(a);
PathNext(vec2(b.x(), a.y()));
PathNext(b);
PathNext(vec2(a.x(), b.y()));
} else {
PathArcToN(vec2(a.x() + rounding, a.y() + rounding), rounding, 4*6, 4*9, 21);
PathArcToN(vec2(b.x() - rounding, a.y() + rounding), rounding, 4*9, 4*12, 21);
PathArcToN(vec2(b.x() - rounding, b.y() - rounding), rounding, 4*0, 4*3, 21);
PathArcToN(vec2(a.x() + rounding, b.y() - rounding), rounding, 4*3, 4*6, 21);
}
}
void DrawList::AddRect(const vec2& pos, const vec2& size, const UI7Color& clr,
int thickness) {
if (!ren->InBox(pos, size, ren->GetViewport())) {
return;
}
ren->UseTex();
PathRect(pos, pos + size);
PathStroke(clr, thickness, UI7DrawFlags_Close);
}
void DrawList::AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr) { void DrawList::AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr) {
if (!ren->InBox(pos, szs, ren->GetViewport())) { if (!ren->InBox(pos, szs, ren->GetViewport())) {
return; return;
} }
auto rect = ren->CreateRect(pos, szs, 0.f);
auto cmd = LI::Command::New();
ren->UseTex(); ren->UseTex();
ren->SetupCommand(cmd); PathRect(pos, pos + szs);
cmd->Layer(layer); PathFill(clr);
if (!clip_rects.empty()) {
cmd->SetScissorMode(LI::ScissorMode_Normal);
cmd->ScissorRect(clip_rects.top());
}
ren->QuadCommand(cmd, rect, vec4(0.f, 1.f, 1.f, 0.f), clr);
commands.push_back(std::make_pair(
ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd));
} }
void DrawList::AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2, void DrawList::AddTriangle(const vec2& a, const vec2& b, const vec2& c,
const UI7Color& clr) { const UI7Color& clr, int thickness) {
if (!ren->InBox(pos0, pos1, pos2, ren->GetViewport())) {
return;
}
auto cmd = LI::Command::New();
ren->UseTex(); ren->UseTex();
ren->SetupCommand(cmd); PathNext(a);
cmd->Layer(layer); PathNext(b);
if (!clip_rects.empty()) { PathNext(c);
cmd->SetScissorMode(LI::ScissorMode_Normal); PathStroke(clr, thickness, UI7DrawFlags_Close);
cmd->ScissorRect(clip_rects.top()); }
void DrawList::AddTriangleFilled(const vec2& a, const vec2& b, const vec2& c,
const UI7Color& clr) {
ren->UseTex();
PathNext(a);
PathNext(b);
PathNext(c);
PathFill(clr);
}
void DrawList::AddCircle(const vec2& pos, float rad, UI7Color col,
int num_segments, int thickness) {
if (num_segments <= 0) {
// Auto Segment
} else {
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
PathArcToN(pos, rad, 0.f, am, num_segments);
} }
ren->TriangleCommand(cmd, pos0, pos1, pos2, clr); ren->UseTex();
commands.push_back(std::make_pair( PathStroke(col, thickness, UI7DrawFlags_Close);
ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd)); }
void DrawList::AddCircleFilled(const vec2& pos, float rad, UI7Color col,
int num_segments) {
if (num_segments <= 0) {
// Auto Segment
} else {
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
PathArcToN(pos, rad, 0.f, am, num_segments);
}
ren->UseTex();
PathFill(col);
} }
void DrawList::AddText(vec2 pos, const std::string& text, const UI7Color& clr, void DrawList::AddText(vec2 pos, const std::string& text, const UI7Color& clr,
@ -123,16 +171,62 @@ void DrawList::AddLine(const vec2& a, const vec2& b, const UI7Color& clr,
!ren->InBox(b, ren->GetViewport())) { !ren->InBox(b, ren->GetViewport())) {
return; return;
} }
auto line = ren->CreateLine(a, b, t);
auto cmd = LI::Command::New();
ren->UseTex(); ren->UseTex();
PathNext(a);
PathNext(b);
PathStroke(clr, t);
}
// TODO: Don't render OOS
void DrawList::AddPolyLine(const std::vector<vec2>& points, const UI7Color& clr,
UI7DrawFlags flags, int thickness) {
if (points.size() < 2) {
return;
}
auto cmd = LI::Command::New();
ren->SetupCommand(cmd); ren->SetupCommand(cmd);
cmd->Layer(layer); cmd->Layer(layer);
if (!clip_rects.empty()) { if (!clip_rects.empty()) {
cmd->SetScissorMode(LI::ScissorMode_Normal); cmd->SetScissorMode(LI::ScissorMode_Normal);
cmd->ScissorRect(clip_rects.top()); cmd->ScissorRect(clip_rects.top());
} }
ren->QuadCommand(cmd, line, vec4(0.f, 1.f, 1.f, 0.f), clr); bool close = (flags & UI7DrawFlags_Close);
int num_points = close ? (int)points.size() : (int)points.size() - 1;
if (flags & UI7DrawFlags_AALines) {
// TODO: Find a way to draw less garbage looking lines
} else {
// Non antialiased lines look awful when rendering with thickness != 1
for (int i = 0; i < num_points; i++) {
int j = (i + 1) == (int)points.size() ? 0 : (i + 1);
auto line = ren->CreateLine(points[i], points[j], thickness);
ren->QuadCommand(cmd, line, vec4(0.f, 1.f, 1.f, 0.f), clr);
}
}
commands.push_back(std::make_pair(
ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd));
}
// TODO: Don't render OOS (Probably make it with a define as it
// would probably be faster to render out of screen than checking if
// it could be skipped)
void DrawList::AddConvexPolyFilled(const std::vector<vec2>& points,
const UI7Color& clr) {
if (points.size() < 3) {
return; // Need at least three points
}
auto cmd = LI::Command::New();
ren->SetupCommand(cmd);
cmd->Layer(layer);
if (!clip_rects.empty()) {
cmd->SetScissorMode(LI::ScissorMode_Normal);
cmd->ScissorRect(clip_rects.top());
}
for (int i = 2; i < (int)points.size(); i++) {
cmd->PushIndex(0).PushIndex(i).PushIndex(i - 1);
}
for (int i = 0; i < (int)points.size(); i++) {
cmd->PushVertex(LI::Vertex(points[i], vec2(0, 0), clr));
}
commands.push_back(std::make_pair( commands.push_back(std::make_pair(
ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd)); ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd));
} }

View File

@ -26,6 +26,10 @@ SOFTWARE.
namespace PD { namespace PD {
void UI7::IO::Update() { void UI7::IO::Update() {
u64 current = Sys::GetNanoTime();
Delta = static_cast<float>(current - LastTime) / 1000000.f;
LastTime = current;
DeltaStats->Add(Delta * 1000);
Time->Update(); Time->Update();
DragTime->Update(); DragTime->Update();
DragReleased = false; DragReleased = false;

118
source/ui7/layout.cpp Normal file
View File

@ -0,0 +1,118 @@
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
SOFTWARE.
*/
#include <pd/ui7/layout.hpp>
namespace PD {
namespace UI7 {
void Layout::CursorInit() { Cursor = WorkRect.xy(); }
void Layout::SameLine() {
BackupCursor = LastObjSize;
Cursor = SamelineCursor;
}
void Layout::CursorMove(const vec2& size) {
LastObjSize = size;
SamelineCursor = Cursor + vec2(size[0] + IO->ItemSpace[0], 0);
if (BeforeSameLine[1]) {
Cursor = vec2(IO->MenuPadding[0],
Cursor[1] + BeforeSameLine[1] + IO->ItemSpace[1]);
BeforeSameLine = 0.f;
} else {
Cursor = vec2(IO->MenuPadding[0] + InitialCursorOffset[0],
Cursor[1] + size[1] + IO->ItemSpace[1]);
}
// Logical Issue here as x should use a max check
MaxPosition = vec2(std::max(MaxPosition[0], SamelineCursor[0]), Cursor[1]);
}
bool Layout::ObjectWorkPos(vec2& movpos) {
if (Scrolling[1]) {
movpos[1] -= ScrollOffset[1];
if (!IO->Ren->InBox(movpos, LastObjSize,
vec4(WorkRect.xy(), WorkRect.xy() + WorkRect.zw()))) {
return true;
}
}
return false;
}
void Layout::AddObject(Container::Ref obj) {
obj->Init(IO, DrawList);
obj->SetPos(AlignPosition(Cursor, obj->GetSize(), WorkRect, GetAlignment()));
obj->Update();
CursorMove(obj->GetSize());
obj->HandleScrolling(ScrollOffset, WorkRect);
Objects.push_back(obj);
}
Container::Ref Layout::FindObject(u32 id) {
for (auto& it : IDObjects) {
if (it->GetID() == id) {
return it;
}
}
return nullptr;
}
vec2 Layout::AlignPosition(vec2 pos, vec2 size, vec4 area, UI7Align alignment) {
vec2 p = pos;
if (alignment & UI7Align_Center) {
p[0] = (area[0] + area[2]) * 0.5 - (pos[0] - area[0] + size[0] * 0.5);
} else if (alignment & UI7Align_Right) {
}
if (alignment & UI7Align_Mid) {
p[1] = (area[1] + area[3]) * 0.5 - (pos[1] - area[1] + size[1] * 0.5);
} else if (alignment & UI7Align_Bottom) {
}
return p;
}
void Layout::Update() {
for (auto& it : Objects) {
if (it->GetID() != 0 && !FindObject(it->GetID())) {
IDObjects.push_back(it);
}
if (!it->Skippable()) {
it->SetPos(it->GetPos() + Pos);
it->HandleInput();
it->UnlockInput();
it->Draw();
}
}
std::vector<size_t> tbr;
for (size_t i = 0; i < IDObjects.size(); i++) {
if (IDObjects[i]->Removable()) {
tbr.push_back(i);
}
}
for (auto& it : tbr) {
IDObjects.erase(IDObjects.begin() + it);
}
Objects.clear();
WorkRect = vec4(WorkRect.xy(), Size - IO->MenuPadding);
CursorInit();
}
} // namespace UI7
} // namespace PD

View File

@ -28,27 +28,20 @@ SOFTWARE.
namespace PD { namespace PD {
namespace UI7 { namespace UI7 {
void UI7::Menu::Label(const std::string& label) { void UI7::Menu::Label(const std::string& label) {
Container::Ref r = ObjectPush(PD::New<UI7::Label>(label, io->Ren)); // Layout API
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment())); auto r = PD::New<UI7::Label>(label, io->Ren);
CursorMove(r->GetSize()); Layout->AddObject(r);
r->Init(io, main);
r->HandleScrolling(scrolling_off, view_area);
} }
bool UI7::Menu::Button(const std::string& label) { bool UI7::Menu::Button(const std::string& label) {
bool ret = false; bool ret = false;
u32 id = Strings::FastHash("btn" + label + std::to_string(count_btn++)); u32 id = Strings::FastHash("btn" + label + std::to_string(count_btn++));
Container::Ref r = FindIDObj(id); Container::Ref r = Layout->FindObject(id);
if (!r) { if (!r) {
r = PD::New<UI7::Button>(label, io); r = PD::New<UI7::Button>(label, io);
r->SetID(id); r->SetID(id);
r->Init(io, main);
} }
ObjectPush(r); Layout->AddObject(r);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
r->Update();
CursorMove(r->GetSize());
r->HandleScrolling(scrolling_off, view_area);
if (!r->Skippable()) { if (!r->Skippable()) {
ret = std::static_pointer_cast<UI7::Button>(r)->IsPressed(); ret = std::static_pointer_cast<UI7::Button>(r)->IsPressed();
} }
@ -57,40 +50,38 @@ bool UI7::Menu::Button(const std::string& label) {
void UI7::Menu::ColorEdit(const std::string& label, u32* color) { void UI7::Menu::ColorEdit(const std::string& label, u32* color) {
u32 id = Strings::FastHash("cle" + label + std::to_string(count_btn++)); u32 id = Strings::FastHash("cle" + label + std::to_string(count_btn++));
Container::Ref r = FindIDObj(id); Container::Ref r = Layout->FindObject(id);
if (!r) { if (!r) {
r = PD::New<UI7::ColorEdit>(label, color, io); r = PD::New<UI7::ColorEdit>(label, color, io);
r->SetID(id); r->SetID(id);
r->Init(io, main);
} }
ObjectPush(r); Layout->AddObject(r);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment())); }
r->Update();
CursorMove(r->GetSize()); void UI7::Menu::DragFloat(const std::string& label, float* data,
r->HandleScrolling(scrolling_off, view_area); size_t num_elms) {
u32 id = Strings::FastHash("dfl" + label + std::to_string(count_btn++));
Container::Ref r = Layout->FindObject(id);
if (!r) {
r = PD::New<UI7::DragData<float>>(label, data, num_elms, io);
r->SetID(id);
}
Layout->AddObject(r);
} }
void UI7::Menu::Checkbox(const std::string& label, bool& v) { void UI7::Menu::Checkbox(const std::string& label, bool& v) {
u32 id = Strings::FastHash("cbx" + label + std::to_string(count_cbx++)); u32 id = Strings::FastHash("cbx" + label + std::to_string(count_cbx++));
Container::Ref r = FindIDObj(id); Container::Ref r = Layout->FindObject(id);
if (!r) { if (!r) {
r = PD::New<UI7::Checkbox>(label, v, io); r = PD::New<UI7::Checkbox>(label, v, io);
r->SetID(id); r->SetID(id);
r->Init(io, main);
} }
ObjectPush(r); Layout->AddObject(r);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
r->Update();
CursorMove(r->GetSize());
r->HandleScrolling(scrolling_off, view_area);
} }
void UI7::Menu::Image(Texture::Ref img, vec2 size, LI::Rect uv) { void UI7::Menu::Image(Texture::Ref img, vec2 size, LI::Rect uv) {
Container::Ref r = ObjectPush(PD::New<UI7::Image>(img, size, uv)); Container::Ref r = PD::New<UI7::Image>(img, size, uv);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment())); Layout->AddObject(r);
CursorMove(r->GetSize());
r->Init(io, main);
r->HandleScrolling(scrolling_off, view_area);
} }
void UI7::Menu::DebugLabels(Menu::Ref m, Menu::Ref t) { void UI7::Menu::DebugLabels(Menu::Ref m, Menu::Ref t) {
@ -105,10 +96,11 @@ void UI7::Menu::DebugLabels(Menu::Ref m, Menu::Ref t) {
s << std::hex << std::setw(8) << std::setfill('0') << m->id; s << std::hex << std::setw(8) << std::setfill('0') << m->id;
s << std::dec << "]"; s << std::dec << "]";
t->Label(s.str()); t->Label(s.str());
t->Label(std::format("Max Size: {:.2f}, {:.2f}", m->max.x(), m->max.y())); t->Label(std::format("Max Size: {:.2f}, {:.2f}", m->Layout->MaxPosition.x(),
m->Layout->MaxPosition.y()));
t->Label(std::format("Pos: {:.2f}, {:.2f} Size: {:.2f}, {:.2f}", t->Label(std::format("Pos: {:.2f}, {:.2f} Size: {:.2f}, {:.2f}",
m->view_area.x(), m->view_area.y(), m->view_area.z(), m->Layout->Pos.x(), m->Layout->Pos.y(),
m->view_area.w())); m->Layout->Size.x(), m->Layout->Size.y()));
t->Label(std::format("Flags: {:#08x}", m->flags)); t->Label(std::format("Flags: {:#08x}", m->flags));
t->Label( t->Label(
"Pre: " + "Pre: " +
@ -132,66 +124,31 @@ void UI7::Menu::Update(float delta) {
TT::Scope st("MUPT_" + name); TT::Scope st("MUPT_" + name);
scroll_anim.Update(delta); scroll_anim.Update(delta);
if (!scroll_anim.IsFinished()) { if (!scroll_anim.IsFinished()) {
scrolling_off = scroll_anim; Layout->ScrollOffset = scroll_anim;
} }
if (!(flags & UI7MenuFlags_NoClipRect)) { if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PushClipRect(vec4(view_area.x() + io->MenuPadding[0], Layout->DrawList->PushClipRect(
view_area.y() + tbh, vec4(Layout->Pos.x() + io->MenuPadding[0], Layout->Pos.y() + tbh,
view_area.x() + view_area.z() - io->MenuPadding[0], Layout->Pos.x() + Layout->Size.x() - io->MenuPadding[0],
view_area.y() + view_area.w())); Layout->Pos.y() + Layout->Size.y()));
}
main->Layer(10); // Render to Layer 10
std::vector<int> tbr;
for (int i = 0; i < (int)objects.size(); i++) {
auto& it = objects[i];
if (it->GetID() != 0 && !FindIDObj(it->GetID())) {
idobjs.push_back(it);
}
if (!it->Skippable()) {
if (scroll_mod[1] == 0.f) {
it->HandleInput(io->Inp);
}
/// Unlock Input after to ensure nothing is checked twice
it->UnlockInput();
it->Draw();
}
}
for (int i = 0; i < (int)idobjs.size(); i++) {
if (idobjs[i]->Removable()) {
tbr.push_back(i);
}
}
for (auto it : tbr) {
idobjs.erase(idobjs.begin() + it);
} }
Layout->GetDrawList()->Layer(10);
Layout->Update();
if (!(flags & UI7MenuFlags_NoClipRect)) { if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PopClipRect(); Layout->DrawList->PopClipRect();
} }
this->objects.clear();
PostScrollHandler(); PostScrollHandler();
} }
void UI7::Menu::CursorMove(const vec2& size) {
last_size = size;
slcursor = cursor + vec2(size[0] + io->ItemSpace[0], 0);
if (bslpos[1]) {
cursor = vec2(io->MenuPadding[0], cursor[1] + bslpos[1] + io->ItemSpace[1]);
bslpos = vec2();
} else {
cursor = vec2(io->MenuPadding[0] + icursoroff[0],
cursor[1] + size[1] + io->ItemSpace[1]);
}
max = vec2(slcursor[0], cursor[1]);
}
void UI7::Menu::PreHandler(UI7MenuFlags flags) { void UI7::Menu::PreHandler(UI7MenuFlags flags) {
TT::Scope st("MPRE_" + name); TT::Scope st("MPRE_" + name);
// No touch means no Input System // No touch means no Input System
UI7Color header = has_touch ? UI7Color_HeaderDead : UI7Color_Header; UI7Color header = has_touch ? UI7Color_HeaderDead : UI7Color_Header;
DrawList::Ref list = Layout->GetDrawList();
// Check if menu can be focused for Selective Menu Input API // Check if menu can be focused for Selective Menu Input API
vec4 newarea = view_area; vec4 newarea = vec4(Layout->Pos, Layout->Size);
if (!is_open) { if (!is_open) {
newarea = vec4(view_area.xy(), vec2(view_area.z(), tbh)); newarea = vec4(Layout->Pos, vec2(Layout->Size.x(), tbh));
} }
if (has_touch && io->Inp->IsDown(io->Inp->Touch) && if (has_touch && io->Inp->IsDown(io->Inp->Touch) &&
io->Ren->InBox(io->Inp->TouchPos(), newarea) && io->Ren->InBox(io->Inp->TouchPos(), newarea) &&
@ -206,23 +163,17 @@ void UI7::Menu::PreHandler(UI7MenuFlags flags) {
count_btn = 0; count_btn = 0;
count_cbx = 0; count_cbx = 0;
tbh = 0.f; tbh = 0.f;
CursorInit();
main_area = view_area;
this->flags = flags; this->flags = flags;
this->scrolling[0] = flags & UI7MenuFlags_HzScrolling; Layout->Scrolling[1] = flags & UI7MenuFlags_VtScrolling;
this->scrolling[1] = flags & UI7MenuFlags_VtScrolling;
has_touch = io->Ren->CurrentScreen()->ScreenType() == Screen::Bottom; has_touch = io->Ren->CurrentScreen()->ScreenType() == Screen::Bottom;
if (!(flags & UI7MenuFlags_NoBackground) && is_open) {
main->Layer(0);
main->AddRectangle(view_area.xy() + vec2(0, tbh),
view_area.zw() - vec2(0, tbh),
io->Theme->Get(UI7Color_Background));
}
if (!(flags & UI7MenuFlags_NoTitlebar)) { if (!(flags & UI7MenuFlags_NoTitlebar)) {
// Title bar setup and Rendering // Title bar setup and Rendering
tbh = io->Ren->TextScale() * 30.f; tbh = io->Ren->TextScale() * 30.f;
main->Layer(20); CollapseHandler();
main->AddRectangle(view_area.xy(), vec2(view_area.z(), tbh), CloseButtonHandler();
MoveHandler();
list->Layer(20);
list->AddRectangle(Layout->Pos, vec2(Layout->Size.x(), tbh),
io->Theme->Get(header)); io->Theme->Get(header));
vec2 tpos(io->MenuPadding[0], vec2 tpos(io->MenuPadding[0],
tbh * 0.5 - io->Ren->GetTextDimensions(name).y() * 0.5); tbh * 0.5 - io->Ren->GetTextDimensions(name).y() * 0.5);
@ -234,83 +185,127 @@ void UI7::Menu::PreHandler(UI7MenuFlags flags) {
tpos = 0; tpos = 0;
tflags = LITextFlags_AlignMid; tflags = LITextFlags_AlignMid;
} }
main->Layer(main->Layer() + 1); list->Layer(list->Layer() + 1);
if (!(flags & UI7MenuFlags_NoClipRect)) { if (!(flags & UI7MenuFlags_NoClipRect)) {
int extra = is_shown != nullptr && !(flags & UI7MenuFlags_NoClose) int extra = is_shown != nullptr && !(flags & UI7MenuFlags_NoClose)
? (20 + io->ItemSpace.x()) ? (20 + io->ItemSpace.x())
: 0; : 0;
main->PushClipRect(vec4( Layout->DrawList->PushClipRect(
view_area.xy(), vec4(Layout->Pos, vec2(Layout->Pos.x() + Layout->Size.x() - extra,
vec2(view_area.x() + view_area.z() - extra, view_area.y() + tbh))); Layout->Pos.y() + tbh)));
} }
main->AddText(view_area.xy() + tpos, this->name, list->AddText(Layout->Pos + tpos, this->name, io->Theme->Get(UI7Color_Text),
io->Theme->Get(UI7Color_Text), tflags, tflags, vec2(Layout->Size.x(), tbh));
vec2(view_area.z(), tbh));
if (!(flags & UI7MenuFlags_NoClipRect)) { if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PopClipRect(); Layout->DrawList->PopClipRect();
} }
main_area[1] = tbh;
CursorInit(); /// Close Button Rendering
CollapseHandler(); if (!(flags & UI7MenuFlags_NoClose) && is_shown) {
CloseButtonHandler(); vec2 cpos =
MoveHandler(); vec2(Layout->Pos.x() + Layout->Size.x() - 12 - io->FramePadding.x(),
Layout->Pos.y() + io->FramePadding.y());
Layout->GetDrawList()->AddLine(cpos, cpos + 12,
io->Theme->Get(clr_close_btn), 2);
Layout->GetDrawList()->AddLine(cpos + vec2(0, 12), cpos + vec2(12, 0),
io->Theme->Get(clr_close_btn), 2);
}
/// Collapse Triangle Rendering
if (!(flags & UI7MenuFlags_NoCollapse)) {
vec2 cpos = Layout->Pos + io->FramePadding;
vec2 positions[2] = {
vec2(12, 6),
vec2(0, 12),
};
if (is_open) {
float t = positions[0].y();
positions[0].y() = positions[1].x();
positions[1].x() = t;
}
Layout->GetDrawList()->AddTriangleFilled(
cpos, cpos + positions[0], cpos + positions[1],
io->Theme->Get(clr_collapse_tri));
}
Layout->WorkRect[1] = io->MenuPadding[1] + tbh;
Layout->CursorInit();
}
if (!(flags & UI7MenuFlags_NoBackground) && is_open) {
list->Layer(0);
list->AddRectangle(Layout->Pos + vec2(0, tbh), Layout->Size - vec2(0, tbh),
io->Theme->Get(UI7Color_Background));
}
if (io->ShowMenuBorder) {
vec2 bsize = Layout->Size;
if (!is_open) {
bsize[1] = tbh;
}
list->Layer(20);
list->AddRect(Layout->Pos, bsize, io->Theme->Get(UI7Color_Border));
} }
// Add a clip Rect for Separators // Add a clip Rect for Separators
if (!(flags & UI7MenuFlags_NoClipRect)) { if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PushClipRect(vec4(view_area.x() + io->MenuPadding[0], Layout->DrawList->PushClipRect(
view_area.y() + tbh, vec4(Layout->Pos.x() + io->MenuPadding[0], Layout->Pos.y() + tbh,
view_area.x() + view_area.z() - io->MenuPadding[0], Layout->Pos.x() + Layout->Size.x() - io->MenuPadding[0],
view_area.y() + view_area.w())); Layout->Pos.y() + Layout->Size.y()));
} }
main->Layer(10); list->Layer(10);
TT::Beg("MUSR_" + name); TT::Beg("MUSR_" + name);
} }
void UI7::Menu::PostHandler() { void UI7::Menu::PostHandler() {
TT::Scope st("MPOS_" + name); TT::Scope st("MPOS_" + name);
TT::End("MUSR_" + name); TT::End("MUSR_" + name);
// Remove the Clip Rect
if (!(flags & UI7MenuFlags_NoClipRect)) {
Layout->DrawList->PopClipRect();
}
ResizeHandler(); ResizeHandler();
if (scrolling[1]) { if (Layout->Scrolling[1]) {
scroll_allowed[1] = (max[1] > view_area.w() - io->MenuPadding[1]); scroll_allowed[1] =
if (max[1] < view_area.w() - io->MenuPadding[1]) { (Layout->MaxPosition[1] > Layout->Size.y() - io->MenuPadding[1]);
scrolling_off[1] = 0.f; if (Layout->MaxPosition[1] < Layout->Size.y() - io->MenuPadding[1]) {
Layout->ScrollOffset[1] = 0.f;
} }
scrollbar[1] = scroll_allowed[1]; scrollbar[1] = scroll_allowed[1];
if (scrollbar[1]) { if (scrollbar[1]) {
/// Setup Some Variables hare [they are self described] /// Setup Some Variables hare [they are self described]
int screen_w = view_area.z(); int screen_w = Layout->Size.x();
int tsp = io->MenuPadding[1] + tbh; int tsp = io->MenuPadding[1] + tbh;
int slider_w = 4; int slider_w = 4;
int szs = view_area.w() - tsp - io->MenuPadding[1]; int szs = Layout->Size.y() - tsp - io->MenuPadding[1];
/// Actually dont have a Horizontal bar yet /// Actually dont have a Horizontal bar yet
if (scrollbar[0]) szs -= slider_w - 2; if (scrollbar[0]) szs -= slider_w - 2;
int lslider_h = 20; // Dont go less heigt for the drag int lslider_h =
float slider_h = (szs - 4) * (float(szs - 4) / max[1]); io->MinSliderDragSize.y(); // Dont go less heigt for the drag
float slider_h = (szs - 4) * (float(szs - 4) / Layout->MaxPosition[1]);
/// Visual Slider Height (How it looks in the end) /// Visual Slider Height (How it looks in the end)
int vslider_h = std::clamp(slider_h, float(lslider_h), float(szs - 4)); int vslider_h = std::clamp(slider_h, float(lslider_h), float(szs - 4));
/// Check if we overscroll to the bottom and Auto scroll back... /// Check if we overscroll to the bottom and Auto scroll back...
/// Probably schould use Tween ENgine here /// Probably schould use Tween ENgine here
if (scrolling_off[1] > max[1] - view_area[3] && max[1] != 0.f && if (Layout->ScrollOffset[1] > Layout->MaxPosition[1] - Layout->Size.y() &&
max[1] >= view_area[3] - io->MenuPadding[1]) { Layout->MaxPosition[1] != 0.f &&
scrolling_off[1] -= 3.f; Layout->MaxPosition[1] >= Layout->Size.y() - io->MenuPadding[1]) {
if (scrolling_off[1] < max[1] - view_area[3]) { Layout->ScrollOffset[1] -= io->OverScrollMod * io->Delta;
scrolling_off[1] = max[1] - view_area[3]; if (Layout->ScrollOffset[1] <
Layout->MaxPosition[1] - Layout->Size.y()) {
Layout->ScrollOffset[1] = Layout->MaxPosition[1] - Layout->Size.y();
} }
} }
/// Do the Same as above just for Overscroll back to the top /// Do the Same as above just for Overscroll back to the top
if (scrolling_off[1] < 0) { if (Layout->ScrollOffset[1] < 0) {
scrolling_off[1] += 3.f; Layout->ScrollOffset[1] += io->OverScrollMod * io->Delta;
if (scrolling_off[1] > 0) { if (Layout->ScrollOffset[1] > 0) {
scrolling_off[1] = 0; Layout->ScrollOffset[1] = 0;
} }
} }
/// Effect /// Effect
if (scroll_mod[1] != 0) { /*if (scroll_mod[1] != 0) {
scrolling_off[1] += scroll_mod[1]; Layout->ScrollOffset[1] += scroll_mod[1];
} }
if (scroll_mod[1] < 0.f) { if (scroll_mod[1] < 0.f) {
scroll_mod[1] += 0.4f; scroll_mod[1] += 0.4f;
@ -323,121 +318,92 @@ void UI7::Menu::PostHandler() {
if (scroll_mod[1] < 0.f) { if (scroll_mod[1] < 0.f) {
scroll_mod[1] = 0; scroll_mod[1] = 0;
} }
} }*/
UI7Color sldr_drag = UI7Color_Button; UI7Color sldr_drag = UI7Color_Button;
/// Slider Dragging???? /// Slider Dragging????
/// Probably need a new API for this /// Probably need a new API for this
if (has_touch && if (has_touch &&
io->DragObject(name + "sldr", vec4(view_area.x() + screen_w - 12, io->DragObject(name + "sldr", vec4(Layout->Pos.x() + screen_w - 12,
view_area.y() + tsp, 8, szs)) && Layout->Pos.y() + tsp, 8, szs)) &&
!io->DragReleasedAW) { !io->DragReleasedAW) {
sldr_drag = UI7Color_ButtonHovered; sldr_drag = UI7Color_ButtonHovered;
float drag_center = vslider_h / 2.0f; float drag_center = vslider_h / 2.0f;
float drag_pos = std::clamp( float drag_pos = std::clamp(
static_cast<float>( static_cast<float>(
((io->DragPosition[1] - view_area.y()) - tsp - drag_center) / ((io->DragPosition[1] - Layout->Pos.y()) - tsp - drag_center) /
(szs - vslider_h - 4)), (szs - vslider_h - 4)),
0.0f, 1.0f); 0.0f, 1.0f);
scrolling_off[1] = drag_pos * (max[1] - view_area.w()); Layout->ScrollOffset[1] =
drag_pos * (Layout->MaxPosition[1] - Layout->Size.y());
} }
int srpos = int srpos =
tsp + std::clamp(float(szs - vslider_h - 4) * tsp + std::clamp(float(szs - vslider_h - 4) *
(scrolling_off[1] / (max[1] - view_area[3])), (Layout->ScrollOffset[1] /
(Layout->MaxPosition[1] - Layout->Size.y())),
0.f, float(szs - vslider_h - 4)); 0.f, float(szs - vslider_h - 4));
/// Rendering Stage /// Rendering Stage
main->Layer(20); auto list = Layout->DrawList;
main->AddRectangle(view_area.xy() + vec2(screen_w - 12, tsp), list->Layer(20);
list->AddRectangle(Layout->Pos + vec2(screen_w - 12, tsp),
vec2(slider_w * 2, szs), vec2(slider_w * 2, szs),
io->Theme->Get(UI7Color_FrameBackground)); io->Theme->Get(UI7Color_FrameBackground));
main->AddRectangle(view_area.xy() + vec2(screen_w - 10, tsp + 2), list->AddRectangle(Layout->Pos + vec2(screen_w - 10, tsp + 2),
vec2(slider_w, szs - 4), vec2(slider_w, szs - 4),
io->Theme->Get(UI7Color_FrameBackgroundHovered)); io->Theme->Get(UI7Color_FrameBackgroundHovered));
main->AddRectangle(view_area.xy() + vec2(screen_w - 10, srpos + 2), list->AddRectangle(Layout->Pos + vec2(screen_w - 10, srpos + 2),
vec2(slider_w, vslider_h), io->Theme->Get(sldr_drag)); vec2(slider_w, vslider_h), io->Theme->Get(sldr_drag));
} }
} }
// Remove the Clip Rect
if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PopClipRect();
}
}
void UI7::Menu::SameLine() {
bslpos = last_size;
cursor = slcursor;
} }
void UI7::Menu::Separator() { void UI7::Menu::Separator() {
vec2 pos = Cursor(); vec2 pos = Layout->Cursor;
vec2 size = vec2(view_area.z() - (scrollbar[1] ? 24 : 10), 1); vec2 size = vec2(Layout->Size.x() - (scrollbar[1] ? 24 : 10), 1);
CursorMove(size); Layout->CursorMove(size);
if (HandleScrolling(pos, size)) { if (Layout->ObjectWorkPos(pos)) {
return; return;
} }
main->AddRectangle(pos, size, io->Theme->Get(UI7Color_TextDead)); Layout->GetDrawList()->AddRectangle(Layout->Pos + pos, size,
io->Theme->Get(UI7Color_TextDead));
} }
void UI7::Menu::SeparatorText(const std::string& label) { void UI7::Menu::SeparatorText(const std::string& label) {
vec2 size = vec2(view_area.z() - (scrollbar[1] ? 24 : 10), 1); vec2 size = vec2(Layout->Size.x() - (scrollbar[1] ? 24 : 10), 1);
vec2 tdim = io->Ren->GetTextDimensions(label); vec2 tdim = io->Ren->GetTextDimensions(label);
vec2 pos = Cursor(); vec2 pos = Layout->Cursor;
CursorMove(vec2(size.x(), tdim.y())); Layout->CursorMove(vec2(size.x(), tdim.y()));
if (HandleScrolling(pos, size)) { if (Layout->ObjectWorkPos(pos)) {
return; return;
} }
auto alignment = GetAlignment(); auto alignment = Layout->GetAlignment();
vec2 rpos = AlignPos(pos, tdim, view_area, alignment); vec2 rpos = Layout->AlignPosition(Layout->Pos + pos, tdim,
vec4(Layout->Pos, Layout->Size), alignment);
if (!(alignment & UI7Align_Left)) { if (!(alignment & UI7Align_Left)) {
main->AddRectangle( Layout->GetDrawList()->AddRectangle(
rpos + vec2(-(rpos[0] - view_area[0] - io->MenuPadding[0]), rpos + vec2(-(rpos[0] - Layout->Pos.x() - io->MenuPadding[0]),
tdim.y() * 0.5), tdim.y() * 0.5),
vec2(rpos[0] - view_area[0] - io->MenuPadding[0] - io->FramePadding[0], vec2(rpos[0] - Layout->Pos.x() - io->MenuPadding[0] -
io->FramePadding[0],
size.y()), size.y()),
io->Theme->Get(UI7Color_TextDead)); io->Theme->Get(UI7Color_TextDead));
} }
if (!(alignment & UI7Align_Right)) { if (!(alignment & UI7Align_Right)) {
main->AddRectangle( Layout->GetDrawList()->AddRectangle(
rpos + vec2(tdim.x() + io->FramePadding[0], tdim.y() * 0.5), rpos + vec2(tdim.x() + io->FramePadding[0], tdim.y() * 0.5),
vec2(size.x() - (tdim.x() + io->FramePadding[0]), size.y()), vec2(size.x() - (tdim.x() + io->FramePadding[0]), size.y()),
io->Theme->Get(UI7Color_TextDead)); io->Theme->Get(UI7Color_TextDead));
} }
main->AddText(rpos, label, io->Theme->Get(UI7Color_Text), 0, Layout->GetDrawList()->AddText(rpos, label, io->Theme->Get(UI7Color_Text), 0,
vec2(view_area.z(), 20)); vec2(Layout->Size.x(), 20));
}
bool UI7::Menu::HandleScrolling(vec2& pos, const vec2& size) {
if (scrolling[1]) {
pos -= vec2(0, scrolling_off.y());
if (!io->Ren->InBox(
pos, size, vec4(view_area.xy(), view_area.xy() + view_area.zw()))) {
return true;
}
}
return false;
}
Container::Ref UI7::Menu::ObjectPush(Container::Ref obj) {
this->objects.push_back(obj);
obj->SetParent(this->tmp_parent);
return obj;
}
Container::Ref UI7::Menu::FindIDObj(u32 id) {
for (auto& it : idobjs) {
if (it->GetID() == id) {
return it;
}
}
return nullptr;
} }
void UI7::Menu::Join() { void UI7::Menu::Join() {
Assert(objects.size(), "Objects list is empty!"); Assert(Layout->Objects.size(), "Objects list is empty!");
join.push_back(objects.back().get()); join.push_back(Layout->Objects.back().get());
} }
void UI7::Menu::JoinAlign(UI7Align a) { void UI7::Menu::JoinAlign(UI7Align a) {
@ -454,10 +420,12 @@ void UI7::Menu::JoinAlign(UI7Align a) {
} }
vec2 off; vec2 off;
if (a & UI7Align_Center) { if (a & UI7Align_Center) {
off[0] = (view_area[0] + view_area[2] * 0.5) - (spos[0] + szs[0] * 0.5); off[0] =
(Layout->Pos.x() + Layout->Size.x() * 0.5) - (spos[0] + szs[0] * 0.5);
} }
if (a & UI7Align_Mid) { if (a & UI7Align_Mid) {
off[1] = (view_area[1] + view_area[3] * 0.5) - (spos[1] + szs[1] * 0.5); off[1] =
(Layout->Pos.y() + Layout->Size.y() * 0.5) - (spos[1] + szs[1] * 0.5);
} }
for (auto it : join) { for (auto it : join) {
it->SetPos(it->GetPos() + off); it->SetPos(it->GetPos() + off);
@ -465,27 +433,16 @@ void UI7::Menu::JoinAlign(UI7Align a) {
join.clear(); join.clear();
} }
vec2 UI7::Menu::AlignPos(vec2 pos, vec2 size, vec4 view, UI7Align a) {
vec2 np = pos;
if (a & UI7Align_Center) {
np[0] = (view[0] + view[2] * 0.5) - ((pos[0] - view[0]) + size[0] * 0.5);
}
if (a & UI7Align_Mid) {
np[1] = (view[1] + view[3] * 0.5) - ((pos[1] - view[1]) + size[1] * 0.5);
}
return np;
}
void UI7::Menu::AfterAlign(UI7Align a) { void UI7::Menu::AfterAlign(UI7Align a) {
Container* ref = objects.back().get(); Container* ref = Layout->Objects.back().get();
vec2 p = ref->GetPos(); vec2 p = ref->GetPos();
vec2 s = ref->GetSize(); vec2 s = ref->GetSize();
vec2 np = p; vec2 np = p;
if (a & UI7Align_Center) { if (a & UI7Align_Center) {
np[0] = (view_area[0] + view_area[2] * 0.5) - (p[0] + s[0] * 0.5); np[0] = (Layout->Pos.x() + Layout->Size.x() * 0.5) - (p[0] + s[0] * 0.5);
} }
if (a & UI7Align_Mid) { if (a & UI7Align_Mid) {
np[1] = (view_area[1] + view_area[3] * 0.5) - (p[1] + s[1] * 0.5); np[1] = (Layout->Pos.y() + Layout->Size.y() * 0.5) - (p[1] + s[1] * 0.5);
} }
ref->SetPos(np); ref->SetPos(np);
} }
@ -503,17 +460,17 @@ bool UI7::Menu::BeginTreeNode(const UI7::ID& id) {
tree_nodes[(u32)id] = false; tree_nodes[(u32)id] = false;
n = tree_nodes.find((u32)id); n = tree_nodes.find((u32)id);
} }
vec2 pos = Cursor(); vec2 pos = Layout->Cursor;
vec2 tdim = io->Ren->GetTextDimensions(id.GetName()); vec2 tdim = io->Ren->GetTextDimensions(id.GetName());
vec2 size = vec2(tdim.x() + 10 + io->ItemSpace[0], tdim.y()); vec2 size = vec2(tdim.x() + 10 + io->ItemSpace[0], tdim.y());
if (n->second) { if (n->second) {
icursoroff.x() += 10.f; Layout->InitialCursorOffset.x() += 10.f;
} }
CursorMove(size); Layout->CursorMove(size);
if (HandleScrolling(pos, size)) { if (Layout->ObjectWorkPos(pos)) {
return n->second; return n->second;
} }
vec2 ts = pos + vec2(0, 3); vec2 ts = Layout->Pos + pos + vec2(0, 3);
vec2 positions[2] = { vec2 positions[2] = {
vec2(10, 5), vec2(10, 5),
vec2(0, 10), vec2(0, 10),
@ -523,16 +480,19 @@ bool UI7::Menu::BeginTreeNode(const UI7::ID& id) {
positions[0].y() = positions[1].x(); positions[0].y() = positions[1].x();
positions[1].x() = t; positions[1].x() = t;
} }
main->AddTriangle(ts, ts + positions[0], ts + positions[1], Layout->GetDrawList()->AddTriangleFilled(
io->Theme->Get(UI7Color_FrameBackground)); ts, ts + positions[0], ts + positions[1],
main->AddText(pos + vec2(10 + io->ItemSpace[0], 0), id.GetName(), io->Theme->Get(UI7Color_FrameBackground));
io->Theme->Get(UI7Color_Text)); Layout->GetDrawList()->AddText(
if (has_touch && io->DragObject(name + id.GetName(), vec4(pos, size))) { Layout->Pos + pos + vec2(10 + io->ItemSpace[0], 0), id.GetName(),
io->Theme->Get(UI7Color_Text));
if (has_touch &&
io->DragObject(name + id.GetName(), vec4(Layout->Pos + pos, size))) {
if (io->DragReleased) { if (io->DragReleased) {
n->second = !n->second; n->second = !n->second;
if (!n->second) { if (!n->second) {
icursoroff.x() -= 10.f; Layout->InitialCursorOffset.x() -= 10;
cursor.x() -= 10; Layout->Cursor.x() -= 10;
} }
} }
} }
@ -540,30 +500,28 @@ bool UI7::Menu::BeginTreeNode(const UI7::ID& id) {
} }
void UI7::Menu::EndTreeNode() { void UI7::Menu::EndTreeNode() {
icursoroff.x() -= 10.f; Layout->InitialCursorOffset.x() -= 10.f;
cursor.x() -= 10; Layout->Cursor.x() -= 10.f;
if (icursoroff.x() < 0.f) { if (Layout->InitialCursorOffset.x() < 0.f) {
icursoroff.x() = 0.f; Layout->InitialCursorOffset.x() = 0.f;
} }
} }
void UI7::Menu::CloseButtonHandler() { void UI7::Menu::CloseButtonHandler() {
// Close Logic // Close Logic
if (!(flags & UI7MenuFlags_NoClose) && is_shown != nullptr) { if (!(flags & UI7MenuFlags_NoClose) && is_shown != nullptr) {
vec2 cpos = vec2(view_area.x() + view_area.z() - 12 - io->FramePadding.x(), vec2 cpos =
view_area.y() + io->FramePadding.y()); vec2(Layout->Pos.x() + Layout->Size.x() - 12 - io->FramePadding.x(),
Layout->Pos.y() + io->FramePadding.y());
UI7Color clr = UI7Color_FrameBackground; clr_close_btn = UI7Color_FrameBackground;
if (has_touch && if (has_touch &&
io->DragObject(UI7::ID(name + "clse"), vec4(cpos, vec2(12)))) { io->DragObject(UI7::ID(name + "clse"), vec4(cpos, vec2(12)))) {
if (io->DragReleased) { if (io->DragReleased) {
*is_shown = !(*is_shown); *is_shown = !(*is_shown);
} }
clr = UI7Color_FrameBackgroundHovered; clr_close_btn = UI7Color_FrameBackgroundHovered;
} }
main->AddLine(cpos, cpos + 12, io->Theme->Get(clr), 2);
main->AddLine(cpos + vec2(0, 12), cpos + vec2(12, 0), io->Theme->Get(clr),
2);
} }
} }
@ -571,18 +529,17 @@ void UI7::Menu::ResizeHandler() {
if (!(flags & UI7MenuFlags_NoResize)) { if (!(flags & UI7MenuFlags_NoResize)) {
if (has_touch && if (has_touch &&
io->DragObject(name + "rszs", io->DragObject(name + "rszs",
vec4(view_area.xy() + view_area.zw() - 20, 20))) { vec4(Layout->Pos + Layout->Size - 20, 20))) {
vec2 szs = view_area.zw() + (io->DragPosition - io->DragLastPosition); vec2 szs = Layout->Size + (io->DragPosition - io->DragLastPosition);
if (szs.x() < 30) szs[0] = 30; if (szs.x() < 30) szs[0] = 30;
if (szs.y() < 30) szs[1] = 30; if (szs.y() < 30) szs[1] = 30;
view_area = vec4(view_area.xy(), szs); Layout->Size = szs;
} }
// front->AddRectangle(view_area.xy() + view_area.zw() - 20, 20, Layout->DrawList->Layer(21);
// 0xffffffff); Not vidible dor some reason Layout->DrawList->AddTriangleFilled(Layout->Pos + Layout->Size,
// int l = front->Layer(); Layout->Pos + Layout->Size - vec2(0, 15),
// front->Layer(l + 1); Layout->Pos + Layout->Size - vec2(15, 0),
// front->AddTriangle(10, vec2(10, 0), vec2(10, 0), 0xffffffff); io->Theme->Get(UI7Color_FrameBackground));
// front->Layer(l);
} }
} }
@ -591,13 +548,11 @@ void UI7::Menu::MoveHandler() {
if (!(flags & UI7MenuFlags_NoMove)) { if (!(flags & UI7MenuFlags_NoMove)) {
if (has_touch && if (has_touch &&
io->DragObject(name + "tmv", io->DragObject(name + "tmv",
vec4(view_area.xy(), vec2(view_area.z(), tbh)))) { vec4(Layout->Pos, vec2(Layout->Size.x(), tbh)))) {
if (io->DragDoubleRelease) { if (io->DragDoubleRelease) {
is_open = !is_open; is_open = !is_open;
} }
view_area = Layout->Pos = Layout->Pos + (io->DragPosition - io->DragLastPosition);
vec4(view_area.xy() + (io->DragPosition - io->DragLastPosition),
view_area.zw());
} }
} }
} }
@ -605,39 +560,29 @@ void UI7::Menu::MoveHandler() {
void UI7::Menu::CollapseHandler() { void UI7::Menu::CollapseHandler() {
// Collapse logic // Collapse logic
if (!(flags & UI7MenuFlags_NoCollapse)) { if (!(flags & UI7MenuFlags_NoCollapse)) {
vec2 cpos = view_area.xy() + io->FramePadding; vec2 cpos = Layout->Pos + io->FramePadding;
UI7Color clr = UI7Color_FrameBackground; clr_collapse_tri = UI7Color_FrameBackground;
if (has_touch && if (has_touch &&
io->DragObject(UI7::ID(name + "clbse"), vec4(cpos, vec2(18, tbh)))) { io->DragObject(UI7::ID(name + "clbse"), vec4(cpos, vec2(18, tbh)))) {
if (io->DragReleased) { if (io->DragReleased) {
is_open = !is_open; is_open = !is_open;
} }
clr = UI7Color_FrameBackgroundHovered; clr_collapse_tri = UI7Color_FrameBackgroundHovered;
} }
vec2 positions[2] = {
vec2(12, 6),
vec2(0, 12),
};
if (is_open) {
float t = positions[0].y();
positions[0].y() = positions[1].x();
positions[1].x() = t;
}
main->AddTriangle(cpos, cpos + positions[0], cpos + positions[1],
io->Theme->Get(clr));
} }
} }
void UI7::Menu::PostScrollHandler() { void UI7::Menu::PostScrollHandler() {
if (has_touch && io->DragObject(id, view_area) && scrolling[1] && if (has_touch && io->DragObject(id, vec4(Layout->Pos, Layout->Size)) &&
flags & UI7MenuFlags_VtScrolling && Layout->Scrolling[1] && flags & UI7MenuFlags_VtScrolling &&
max[1] - view_area.w() + io->MenuPadding[1] > 0) { Layout->MaxPosition.y() - Layout->Size.y() + io->MenuPadding[1] > 0) {
if (io->DragReleased) { if (io->DragReleased) {
scroll_mod = (io->DragPosition - io->DragLastPosition); // scroll_mod = (io->DragPosition - io->DragLastPosition);
} else { } else {
scrolling_off[1] = std::clamp( Layout->ScrollOffset[1] = std::clamp(
scrolling_off[1] - (io->DragPosition.y() - io->DragLastPosition.y()), Layout->ScrollOffset[1] -
-40.f, (max[1] - view_area.w()) + 40.f); (io->DragPosition.y() - io->DragLastPosition.y()),
-40.f, (Layout->MaxPosition.y() - Layout->Size.y()) + 40.f);
} }
} }
} }

View File

@ -29,7 +29,8 @@ namespace UI7 {
void Theme::Default(Theme& theme) { void Theme::Default(Theme& theme) {
theme.Set(UI7Color_Text, Color("#FFFFFFFF")); theme.Set(UI7Color_Text, Color("#FFFFFFFF"));
theme.Set(UI7Color_TextDead, Color("#AAAAAAFF")); theme.Set(UI7Color_TextDead, Color("#AAAAAAFF"));
theme.Set(UI7Color_Background, Color("#222222aa")); theme.Set(UI7Color_Background, Color("#222222ff"));
theme.Set(UI7Color_Border, Color("#999999ff"));
theme.Set(UI7Color_Button, Color("#111111FF")); theme.Set(UI7Color_Button, Color("#111111FF"));
theme.Set(UI7Color_ButtonDead, Color("#080808FF")); theme.Set(UI7Color_ButtonDead, Color("#080808FF"));
theme.Set(UI7Color_ButtonActive, Color("#2A2A2AFF")); theme.Set(UI7Color_ButtonActive, Color("#2A2A2AFF"));
@ -49,10 +50,11 @@ void Theme::Flashbang(Theme& theme) {
theme.Set(UI7Color_Text, Color("#000000FF")); theme.Set(UI7Color_Text, Color("#000000FF"));
theme.Set(UI7Color_TextDead, Color("#333333FF")); theme.Set(UI7Color_TextDead, Color("#333333FF"));
theme.Set(UI7Color_Background, Color("#eeeeeeFF")); theme.Set(UI7Color_Background, Color("#eeeeeeFF"));
theme.Set(UI7Color_Border, Color("#777777ff"));
theme.Set(UI7Color_Button, Color("#ccccccFF")); theme.Set(UI7Color_Button, Color("#ccccccFF"));
theme.Set(UI7Color_ButtonDead, Color("#bbbbbbFF")); theme.Set(UI7Color_ButtonDead, Color("#bbbbbbFF"));
theme.Set(UI7Color_ButtonActive, Color("#ccccccFF")); theme.Set(UI7Color_ButtonActive, Color("#ccccccFF"));
theme.Set(UI7Color_ButtonHovered, Color("#cbcbcbFF")); theme.Set(UI7Color_ButtonHovered, Color("#acacacFF"));
theme.Set(UI7Color_Header, Color("#ddddddFF")); theme.Set(UI7Color_Header, Color("#ddddddFF"));
theme.Set(UI7Color_HeaderDead, Color("#cdcdcdFF")); theme.Set(UI7Color_HeaderDead, Color("#cdcdcdFF"));
theme.Set(UI7Color_Selector, Color("#222222FF")); theme.Set(UI7Color_Selector, Color("#222222FF"));

View File

@ -61,16 +61,13 @@ bool UI7::Context::BeginMenu(const ID& id, UI7MenuFlags flags, bool* show) {
auto menu = this->menus.find(id); auto menu = this->menus.find(id);
if (menu == this->menus.end()) { if (menu == this->menus.end()) {
this->menus[id] = Menu::New(id, io); this->menus[id] = Menu::New(id, io);
this->menus[id]->ViewArea(this->io->Ren->GetViewport()); this->menus[id]->Layout->SetSize(io->Ren->GetViewport().zw());
menu = this->menus.find(id); menu = this->menus.find(id);
} }
this->current = menu->second; this->current = menu->second;
this->current->is_shown = show; this->current->is_shown = show;
this->io->CurrentMenu = this->current->id; this->io->CurrentMenu = this->current->id;
if (!this->current->main) { io->RegisterDrawList(id, this->current->Layout->GetDrawList());
this->current->main = DrawList::New(io->Ren);
}
io->RegisterDrawList(id, this->current->main);
this->current->PreHandler(flags); this->current->PreHandler(flags);
amenus.push_back(this->current->GetID()); amenus.push_back(this->current->GetID());
if (!this->current->is_open) { if (!this->current->is_open) {
@ -98,11 +95,9 @@ void UI7::Context::EndMenu() {
this->io->CurrentMenu = 0; this->io->CurrentMenu = 0;
} }
void UI7::Context::Update(float delta) { void UI7::Context::Update(float) {
TT::Scope st("UI7_Update"); TT::Scope st("UI7_Update");
Assert(current == nullptr, "Still in a Menu!"); Assert(current == nullptr, "Still in a Menu!");
this->io->Delta = delta;
io->DeltaStats->Add(io->Delta * 1000);
bool focused_exist = false; bool focused_exist = false;
for (auto it : amenus) { for (auto it : amenus) {
auto m = menus[it]; auto m = menus[it];
@ -212,14 +207,14 @@ void UI7::Context::MetricsMenu(bool* show) {
for (auto& it : menus) { for (auto& it : menus) {
if (m->BeginTreeNode(it.second->name)) { if (m->BeginTreeNode(it.second->name)) {
m->Label("Name: " + it.second->name); m->Label("Name: " + it.second->name);
m->Label("Pos: " + UI7DV2N(it.second->view_area.xy())); m->Label("Pos: " + UI7DV2N(it.second->Layout->GetPosition()));
m->Label("Size: " + UI7DV2N(it.second->view_area.zw())); m->Label("Size: " + UI7DV2N(it.second->Layout->GetSize()));
m->Label("Main Area: " + UI7DV4N(it.second->main_area)); m->Label("Work Rect: " + UI7DV4N(it.second->Layout->WorkRect));
m->Label("Cursor: " + UI7DV2N(it.second->cursor)); m->Label("Cursor: " + UI7DV2N(it.second->Layout->Cursor));
if (m->BeginTreeNode("ID Objects (" + if (m->BeginTreeNode(
std::to_string(it.second->idobjs.size()) + "ID Objects (" +
")")) { std::to_string(it.second->Layout->IDObjects.size()) + ")")) {
for (auto& jt : it.second->idobjs) { for (auto& jt : it.second->Layout->IDObjects) {
m->Label(UI7DHX32(jt->GetID())); m->Label(UI7DHX32(jt->GetID()));
} }
m->EndTreeNode(); m->EndTreeNode();
@ -261,36 +256,14 @@ void UI7::Context::StyleEditor(bool* show) {
m->Label("Palladium - UI7 " + GetVersion() + " Style Editor"); m->Label("Palladium - UI7 " + GetVersion() + " Style Editor");
m->Separator(); m->Separator();
m->Label(std::format("MenuPadding: {}, {}", io->MenuPadding.x(), m->DragData("MenuPadding", (float*)&io->MenuPadding, 2, 0.f, 100.f);
io->MenuPadding.y())); m->DragData("FramePadding", (float*)&io->FramePadding, 2, 0.f, 100.f);
m->SameLine(); m->DragData("ItemSpace", (float*)&io->ItemSpace, 2, 0.f, 100.f);
if (m->Button("-")) { m->DragData("MinSliderSize", (float*)&io->MinSliderDragSize, 2, 1.f, 100.f);
io->MenuPadding -= 1; m->DragData("OverScroll Modifier", &io->OverScrollMod, 1, 0.01f,
} std::numeric_limits<float>::max(), 0.01f, 2);
m->SameLine(); m->Checkbox("Menu Border", io->ShowMenuBorder);
if (m->Button("+")) { m->Checkbox("Frame Border", io->ShowFrameBorder);
io->MenuPadding += 1;
}
m->Label(std::format("FramePadding: {}, {}", io->FramePadding.x(),
io->FramePadding.y()));
m->SameLine();
if (m->Button("-")) {
io->FramePadding -= 1;
}
m->SameLine();
if (m->Button("+")) {
io->FramePadding += 1;
}
m->Label(
std::format("ItemSpace: {}, {}", io->ItemSpace.x(), io->ItemSpace.y()));
m->SameLine();
if (m->Button("-")) {
io->ItemSpace -= 1;
}
m->SameLine();
if (m->Button("+")) {
io->ItemSpace += 1;
}
m->SeparatorText("Theme"); m->SeparatorText("Theme");
if (m->Button("Dark")) { if (m->Button("Dark")) {
UI7::Theme::Default(*io->Theme.get()); UI7::Theme::Default(*io->Theme.get());
@ -301,22 +274,26 @@ void UI7::Context::StyleEditor(bool* show) {
} }
/// Small trick to print without prefix /// Small trick to print without prefix
#define ts(x) m->ColorEdit(std::string(#x).substr(9), &io->Theme->GetRef(x)); #define ts(x) m->ColorEdit(std::string(#x).substr(9), &io->Theme->GetRef(x));
ts(UI7Color_Background); #define ts2(x) \
ts(UI7Color_Button); m->DragData(std::string(#x).substr(9), (u8*)&io->Theme->GetRef(x), 4, (u8)0, \
ts(UI7Color_ButtonDead); (u8)255);
ts(UI7Color_ButtonActive); ts2(UI7Color_Background);
ts(UI7Color_ButtonHovered); ts2(UI7Color_Border);
ts(UI7Color_Text); ts2(UI7Color_Button);
ts(UI7Color_TextDead); ts2(UI7Color_ButtonDead);
ts(UI7Color_Header); ts2(UI7Color_ButtonActive);
ts(UI7Color_HeaderDead); ts2(UI7Color_ButtonHovered);
ts(UI7Color_Selector); ts2(UI7Color_Text);
ts(UI7Color_Checkmark); ts2(UI7Color_TextDead);
ts(UI7Color_FrameBackground); ts2(UI7Color_Header);
ts(UI7Color_FrameBackgroundHovered); ts2(UI7Color_HeaderDead);
ts(UI7Color_Progressbar); ts2(UI7Color_Selector);
ts(UI7Color_ListEven); ts2(UI7Color_Checkmark);
ts(UI7Color_ListOdd); ts2(UI7Color_FrameBackground);
ts2(UI7Color_FrameBackgroundHovered);
ts2(UI7Color_Progressbar);
ts2(UI7Color_ListEven);
ts2(UI7Color_ListOdd);
this->EndMenu(); this->EndMenu();
} }
} }