# 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
This commit is contained in:
tobid7 2025-03-14 15:14:45 +01:00
parent ba77dc9b42
commit 35272687f6
21 changed files with 688 additions and 469 deletions

View File

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

View File

@ -54,9 +54,8 @@ class Button : public Container {
/**
* Override for the Input Handler
* @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
* @note This function is usally called by Menu::Update

View File

@ -50,9 +50,8 @@ class Checkbox : public Container {
/**
* Override for the Input Handler
* @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
* @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/io.hpp>
#include <pd/ui7/layout.hpp>
namespace PD {
namespace UI7 {
@ -51,9 +52,8 @@ class ColorEdit : public Container {
/**
* Override for the Input Handler
* @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
* @note This function is usally called by Menu::Update
@ -68,6 +68,8 @@ class ColorEdit : public Container {
u32* color_ref = nullptr; ///< Color Reference
u32 initial_color; ///< Initial Color
std::string label; ///< Label of the Button
Layout::Ref layout; ///< Layout to open
bool is_shown = false; ///< AHow Layout Editor
};
} // namespace UI7
} // namespace PD

View File

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

View File

@ -0,0 +1,79 @@
#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 pos Base Position
* @param lr Reference to the Renderer
*/
DragData(const std::string& label, T* data, size_t num_elms, UI7::IO::Ref io,
T min = 0, T max = 100) {
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->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;
};
} // namespace UI7
} // namespace PD

View File

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

View File

@ -29,6 +29,8 @@ using UI7MenuFlags = unsigned int;
using UI7Align = unsigned int;
/** 32Bit Value to store Context (IO) flags */
using UI7IOFlags = unsigned int;
/** 32Bit Value for Layout Flags */
using UI7LayoutFlags = unsigned int;
/** Menu Flags */
enum UI7MenuFlags_ {
@ -48,6 +50,12 @@ enum UI7MenuFlags_ {
UI7MenuFlags_Scrolling = UI7MenuFlags_HzScrolling | UI7MenuFlags_VtScrolling,
};
/** UI7 Layout Flags */
enum UI7LayoutFlags_ {
UI7LayoutFlags_None = 0, ///< No Flags used
UI7LayoutFlags_UseClipRect = 1 << 0, ///< Enable ClipRect
};
/** UI7 Context Flags */
enum UI7IOFlags_ {
UI7IOFlags_None = 0, ///< No Additional Config available

View File

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

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

@ -0,0 +1,119 @@
#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);
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/id.hpp>
#include <pd/ui7/io.hpp>
#include <pd/ui7/layout.hpp>
namespace PD {
namespace UI7 {
@ -47,12 +48,11 @@ class Menu : public SmartCtor<Menu> {
this->id = id;
this->name = id.GetName();
/// Set Default Values here
scrolling[0] = false;
scrolling[1] = false;
scrollbar[0] = false;
scrollbar[1] = false;
scroll_allowed[0] = false;
scroll_allowed[1] = false;
Layout = UI7::Layout::New(id, io);
}
~Menu() = default;
@ -88,6 +88,19 @@ class Menu : public SmartCtor<Menu> {
* @param color Color reference to edit
*/
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 = 0, T max = 100) {
u32 id = Strings::FastHash("dfl" + label + std::to_string(count_btn++));
Container::Ref r = Layout->FindObject(id);
if (!r) {
r = PD::New<UI7::DragData<T>>(label, data, num_elms, io, min, max);
r->SetID(id);
}
Layout->AddObject(r);
}
// Basic API
/**
@ -102,7 +115,7 @@ class Menu : public SmartCtor<Menu> {
void EndTreeNode();
/** Add the Next Objext to the same line */
void SameLine();
void SameLine() { Layout->SameLine(); }
/** Add a Separator Line */
void Separator();
/**
@ -128,23 +141,14 @@ class Menu : public SmartCtor<Menu> {
* Set a Temp alignment op for the next Object
* @param a Alignment Operation
*/
void NextAlign(UI7Align a) { tmpalign = a; }
void NextAlign(UI7Align a) { Layout->NextAlign(a); }
/**
* Align Every Single Object by this operationset
* @param a Alignment
*/
void PushAlignment(UI7Align a) { alignment = a; }
void PushAlignment(UI7Align a) { Layout->SetAlign(a); }
/** Use default alignment */
void PopAlignment() { 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);
void PopAlignment() { Layout->Alignment = UI7Align_Default; }
/**
* Returns a Reference to the theme
* @return Reference to the base Theme of the context
@ -166,35 +170,6 @@ class Menu : public SmartCtor<Menu> {
// 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 */
bool HasVerticalScrollbar() { return scrollbar[1]; }
/** Return if a Horizontal Scrollbar exists */
@ -206,43 +181,13 @@ class Menu : public SmartCtor<Menu> {
* @note Could destroy some basic functionality
*/
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
* @param pos Destination Position
*/
void ScrollTo(vec2 pos) {
scroll_anim.From(scrolling_off)
scroll_anim.From(Layout->ScrollOffset)
.To(pos)
.In(1.f)
.As(scroll_anim.EaseInOutSine);
@ -252,19 +197,6 @@ class Menu : public SmartCtor<Menu> {
// 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
* instances at once
@ -276,7 +208,8 @@ class Menu : public SmartCtor<Menu> {
// Draw List
/** Get DrawList */
DrawList::Ref GetDrawList() { return main; }
DrawList::Ref GetDrawList() { return Layout->DrawList; }
UI7::Layout::Ref GetLayout() { return Layout; }
// Advanced
@ -305,43 +238,6 @@ class Menu : public SmartCtor<Menu> {
/** Handle things like scrolling */
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 */
void Update(float delta);
@ -363,21 +259,9 @@ class Menu : public SmartCtor<Menu> {
// Data
// Default Alignment for all Objects
UI7Align alignment = UI7Align_Default;
UI7Align tmpalign = 0; ///< Temp Alignment [only used once]
UI7MenuFlags flags = 0; ///< Menu Flags
u32 id; ///< Menu ID
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
bool scrollbar[2]; ///< Is Hz or Vt Scrollbar rendered
bool scroll_allowed[2]; ///< Is Hz or Vt Scrolling Alowed
@ -389,20 +273,9 @@ class Menu : public SmartCtor<Menu> {
// Objects API
std::vector<Container::Ref> objects; ///< Current frame Objects
std::vector<Container::Ref> idobjs; ///< Objects using an ID
std::vector<Container*> join; ///< List of Combined Objects
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
std::vector<Container*> join; ///< List of Combined Objects
int count_btn = 0; ///< Count for Button ID Prefix
int count_cbx = 0; ///< Cound for Checkbox ID Prefix
UI7::IO::Ref io; ///< IO Reference
@ -411,6 +284,9 @@ class Menu : public SmartCtor<Menu> {
// Animations System
Tween<vec2> scroll_anim; ///< for Scroll to Animation
// Layout API
PD::UI7::Layout::Ref Layout;
};
} // namespace UI7
} // namespace PD

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,101 @@
/*
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("{:.1f}", data[i]);
} 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] + (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("{:.1f}", data[i]);
} 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, 0), label,
io->Theme->Get(UI7Color_Text));
}
template <typename T>
void DragData<T>::Update() {
Assert(io.get(), "Did you run Container::Init correctly?");
this->SetSize(vec2(tdim.x() + io->ItemSpace.x() + 20, 20));
}
} // namespace UI7
} // namespace PD

View File

@ -26,6 +26,10 @@ SOFTWARE.
namespace PD {
void UI7::IO::Update() {
u64 current = Sys::GetNanoTime();
Delta = static_cast<float>(current - LastTime) / 1000000.f;
LastTime = current;
DeltaStats->Add(Delta * 1000);
Time->Update();
DragTime->Update();
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(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 UI7 {
void UI7::Menu::Label(const std::string& label) {
Container::Ref r = ObjectPush(PD::New<UI7::Label>(label, io->Ren));
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
CursorMove(r->GetSize());
r->Init(io, main);
r->HandleScrolling(scrolling_off, view_area);
// Layout API
auto r = PD::New<UI7::Label>(label, io->Ren);
Layout->AddObject(r);
}
bool UI7::Menu::Button(const std::string& label) {
bool ret = false;
u32 id = Strings::FastHash("btn" + label + std::to_string(count_btn++));
Container::Ref r = FindIDObj(id);
Container::Ref r = Layout->FindObject(id);
if (!r) {
r = PD::New<UI7::Button>(label, io);
r->SetID(id);
r->Init(io, main);
}
ObjectPush(r);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
r->Update();
CursorMove(r->GetSize());
r->HandleScrolling(scrolling_off, view_area);
Layout->AddObject(r);
if (!r->Skippable()) {
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) {
u32 id = Strings::FastHash("cle" + label + std::to_string(count_btn++));
Container::Ref r = FindIDObj(id);
Container::Ref r = Layout->FindObject(id);
if (!r) {
r = PD::New<UI7::ColorEdit>(label, color, io);
r->SetID(id);
r->Init(io, main);
}
ObjectPush(r);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
r->Update();
CursorMove(r->GetSize());
r->HandleScrolling(scrolling_off, view_area);
Layout->AddObject(r);
}
void UI7::Menu::DragFloat(const std::string& label, float* data,
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) {
u32 id = Strings::FastHash("cbx" + label + std::to_string(count_cbx++));
Container::Ref r = FindIDObj(id);
Container::Ref r = Layout->FindObject(id);
if (!r) {
r = PD::New<UI7::Checkbox>(label, v, io);
r->SetID(id);
r->Init(io, main);
}
ObjectPush(r);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
r->Update();
CursorMove(r->GetSize());
r->HandleScrolling(scrolling_off, view_area);
Layout->AddObject(r);
}
void UI7::Menu::Image(Texture::Ref img, vec2 size, LI::Rect uv) {
Container::Ref r = ObjectPush(PD::New<UI7::Image>(img, size, uv));
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
CursorMove(r->GetSize());
r->Init(io, main);
r->HandleScrolling(scrolling_off, view_area);
Container::Ref r = PD::New<UI7::Image>(img, size, uv);
Layout->AddObject(r);
}
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::dec << "]";
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}",
m->view_area.x(), m->view_area.y(), m->view_area.z(),
m->view_area.w()));
m->Layout->Pos.x(), m->Layout->Pos.y(),
m->Layout->Size.x(), m->Layout->Size.y()));
t->Label(std::format("Flags: {:#08x}", m->flags));
t->Label(
"Pre: " +
@ -132,66 +124,31 @@ void UI7::Menu::Update(float delta) {
TT::Scope st("MUPT_" + name);
scroll_anim.Update(delta);
if (!scroll_anim.IsFinished()) {
scrolling_off = scroll_anim;
Layout->ScrollOffset = scroll_anim;
}
if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PushClipRect(vec4(view_area.x() + io->MenuPadding[0],
view_area.y() + tbh,
view_area.x() + view_area.z() - io->MenuPadding[0],
view_area.y() + view_area.w()));
}
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->DrawList->PushClipRect(
vec4(Layout->Pos.x() + io->MenuPadding[0], Layout->Pos.y() + tbh,
Layout->Pos.x() + Layout->Size.x() - io->MenuPadding[0],
Layout->Pos.y() + Layout->Size.y()));
}
Layout->GetDrawList()->Layer(10);
Layout->Update();
if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PopClipRect();
Layout->DrawList->PopClipRect();
}
this->objects.clear();
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) {
TT::Scope st("MPRE_" + name);
// No touch means no Input System
UI7Color header = has_touch ? UI7Color_HeaderDead : UI7Color_Header;
DrawList::Ref list = Layout->GetDrawList();
// 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) {
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) &&
io->Ren->InBox(io->Inp->TouchPos(), newarea) &&
@ -206,23 +163,19 @@ void UI7::Menu::PreHandler(UI7MenuFlags flags) {
count_btn = 0;
count_cbx = 0;
tbh = 0.f;
CursorInit();
main_area = view_area;
this->flags = flags;
this->scrolling[0] = flags & UI7MenuFlags_HzScrolling;
this->scrolling[1] = flags & UI7MenuFlags_VtScrolling;
Layout->Scrolling[1] = flags & UI7MenuFlags_VtScrolling;
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),
list->Layer(0);
list->AddRectangle(Layout->Pos + vec2(0, tbh), Layout->Size - vec2(0, tbh),
io->Theme->Get(UI7Color_Background));
}
if (!(flags & UI7MenuFlags_NoTitlebar)) {
// Title bar setup and Rendering
tbh = io->Ren->TextScale() * 30.f;
main->Layer(20);
main->AddRectangle(view_area.xy(), vec2(view_area.z(), tbh),
list->Layer(20);
list->AddRectangle(Layout->Pos, vec2(Layout->Size.x(), tbh),
io->Theme->Get(header));
vec2 tpos(io->MenuPadding[0],
tbh * 0.5 - io->Ren->GetTextDimensions(name).y() * 0.5);
@ -234,35 +187,34 @@ void UI7::Menu::PreHandler(UI7MenuFlags flags) {
tpos = 0;
tflags = LITextFlags_AlignMid;
}
main->Layer(main->Layer() + 1);
list->Layer(list->Layer() + 1);
if (!(flags & UI7MenuFlags_NoClipRect)) {
int extra = is_shown != nullptr && !(flags & UI7MenuFlags_NoClose)
? (20 + io->ItemSpace.x())
: 0;
main->PushClipRect(vec4(
view_area.xy(),
vec2(view_area.x() + view_area.z() - extra, view_area.y() + tbh)));
Layout->DrawList->PushClipRect(
vec4(Layout->Pos, vec2(Layout->Pos.x() + Layout->Size.x() - extra,
Layout->Pos.y() + tbh)));
}
main->AddText(view_area.xy() + tpos, this->name,
io->Theme->Get(UI7Color_Text), tflags,
vec2(view_area.z(), tbh));
list->AddText(Layout->Pos + tpos, this->name, io->Theme->Get(UI7Color_Text),
tflags, vec2(Layout->Size.x(), tbh));
if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PopClipRect();
Layout->DrawList->PopClipRect();
}
main_area[1] = tbh;
CursorInit();
Layout->WorkRect[1] = io->MenuPadding[1] + tbh;
Layout->CursorInit();
CollapseHandler();
CloseButtonHandler();
MoveHandler();
}
// Add a clip Rect for Separators
if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PushClipRect(vec4(view_area.x() + io->MenuPadding[0],
view_area.y() + tbh,
view_area.x() + view_area.z() - io->MenuPadding[0],
view_area.y() + view_area.w()));
Layout->DrawList->PushClipRect(
vec4(Layout->Pos.x() + io->MenuPadding[0], Layout->Pos.y() + tbh,
Layout->Pos.x() + Layout->Size.x() - io->MenuPadding[0],
Layout->Pos.y() + Layout->Size.y()));
}
main->Layer(10);
list->Layer(10);
TT::Beg("MUSR_" + name);
}
@ -270,47 +222,51 @@ void UI7::Menu::PostHandler() {
TT::Scope st("MPOS_" + name);
TT::End("MUSR_" + name);
ResizeHandler();
if (scrolling[1]) {
scroll_allowed[1] = (max[1] > view_area.w() - io->MenuPadding[1]);
if (max[1] < view_area.w() - io->MenuPadding[1]) {
scrolling_off[1] = 0.f;
if (Layout->Scrolling[1]) {
scroll_allowed[1] =
(Layout->MaxPosition[1] > Layout->Size.y() - io->MenuPadding[1]);
if (Layout->MaxPosition[1] < Layout->Size.y() - io->MenuPadding[1]) {
Layout->ScrollOffset[1] = 0.f;
}
scrollbar[1] = scroll_allowed[1];
if (scrollbar[1]) {
/// 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 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
if (scrollbar[0]) szs -= slider_w - 2;
int lslider_h = 20; // Dont go less heigt for the drag
float slider_h = (szs - 4) * (float(szs - 4) / max[1]);
int lslider_h =
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)
int vslider_h = std::clamp(slider_h, float(lslider_h), float(szs - 4));
/// Check if we overscroll to the bottom and Auto scroll back...
/// Probably schould use Tween ENgine here
if (scrolling_off[1] > max[1] - view_area[3] && max[1] != 0.f &&
max[1] >= view_area[3] - io->MenuPadding[1]) {
scrolling_off[1] -= 3.f;
if (scrolling_off[1] < max[1] - view_area[3]) {
scrolling_off[1] = max[1] - view_area[3];
if (Layout->ScrollOffset[1] > Layout->MaxPosition[1] - Layout->Size.y() &&
Layout->MaxPosition[1] != 0.f &&
Layout->MaxPosition[1] >= Layout->Size.y() - io->MenuPadding[1]) {
Layout->ScrollOffset[1] -= 3.f;
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
if (scrolling_off[1] < 0) {
scrolling_off[1] += 3.f;
if (scrolling_off[1] > 0) {
scrolling_off[1] = 0;
if (Layout->ScrollOffset[1] < 0) {
Layout->ScrollOffset[1] += 3.f;
if (Layout->ScrollOffset[1] > 0) {
Layout->ScrollOffset[1] = 0;
}
}
/// Effect
if (scroll_mod[1] != 0) {
scrolling_off[1] += scroll_mod[1];
/*if (scroll_mod[1] != 0) {
Layout->ScrollOffset[1] += scroll_mod[1];
}
if (scroll_mod[1] < 0.f) {
scroll_mod[1] += 0.4f;
@ -323,121 +279,96 @@ void UI7::Menu::PostHandler() {
if (scroll_mod[1] < 0.f) {
scroll_mod[1] = 0;
}
}
}*/
UI7Color sldr_drag = UI7Color_Button;
/// Slider Dragging????
/// Probably need a new API for this
if (has_touch &&
io->DragObject(name + "sldr", vec4(view_area.x() + screen_w - 12,
view_area.y() + tsp, 8, szs)) &&
io->DragObject(name + "sldr", vec4(Layout->Pos.x() + screen_w - 12,
Layout->Pos.y() + tsp, 8, szs)) &&
!io->DragReleasedAW) {
sldr_drag = UI7Color_ButtonHovered;
float drag_center = vslider_h / 2.0f;
float drag_pos = std::clamp(
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)),
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 =
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));
/// Rendering Stage
main->Layer(20);
main->AddRectangle(view_area.xy() + vec2(screen_w - 12, tsp),
auto list = Layout->DrawList;
list->Layer(20);
list->AddRectangle(Layout->Pos + vec2(screen_w - 12, tsp),
vec2(slider_w * 2, szs),
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),
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));
}
}
// Remove the Clip Rect
if (!(flags & UI7MenuFlags_NoClipRect)) {
main->PopClipRect();
Layout->DrawList->PopClipRect();
}
}
void UI7::Menu::SameLine() {
bslpos = last_size;
cursor = slcursor;
}
void UI7::Menu::Separator() {
vec2 pos = Cursor();
vec2 size = vec2(view_area.z() - (scrollbar[1] ? 24 : 10), 1);
CursorMove(size);
if (HandleScrolling(pos, size)) {
vec2 pos = Layout->Cursor;
vec2 size = vec2(Layout->Size.x() - (scrollbar[1] ? 24 : 10), 1);
Layout->CursorMove(size);
if (Layout->ObjectWorkPos(pos)) {
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) {
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 pos = Cursor();
CursorMove(vec2(size.x(), tdim.y()));
vec2 pos = Layout->Cursor;
Layout->CursorMove(vec2(size.x(), tdim.y()));
if (HandleScrolling(pos, size)) {
if (Layout->ObjectWorkPos(pos)) {
return;
}
auto alignment = GetAlignment();
vec2 rpos = AlignPos(pos, tdim, view_area, alignment);
auto alignment = Layout->GetAlignment();
vec2 rpos = Layout->AlignPosition(Layout->Pos + pos, tdim,
vec4(Layout->Pos, Layout->Size), alignment);
if (!(alignment & UI7Align_Left)) {
main->AddRectangle(
rpos + vec2(-(rpos[0] - view_area[0] - io->MenuPadding[0]),
Layout->GetDrawList()->AddRectangle(
rpos + vec2(-(rpos[0] - Layout->Pos.x() - io->MenuPadding[0]),
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()),
io->Theme->Get(UI7Color_TextDead));
}
if (!(alignment & UI7Align_Right)) {
main->AddRectangle(
Layout->GetDrawList()->AddRectangle(
rpos + vec2(tdim.x() + io->FramePadding[0], tdim.y() * 0.5),
vec2(size.x() - (tdim.x() + io->FramePadding[0]), size.y()),
io->Theme->Get(UI7Color_TextDead));
}
main->AddText(rpos, label, io->Theme->Get(UI7Color_Text), 0,
vec2(view_area.z(), 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;
Layout->GetDrawList()->AddText(rpos, label, io->Theme->Get(UI7Color_Text), 0,
vec2(Layout->Size.x(), 20));
}
void UI7::Menu::Join() {
Assert(objects.size(), "Objects list is empty!");
join.push_back(objects.back().get());
Assert(Layout->Objects.size(), "Objects list is empty!");
join.push_back(Layout->Objects.back().get());
}
void UI7::Menu::JoinAlign(UI7Align a) {
@ -454,10 +385,12 @@ void UI7::Menu::JoinAlign(UI7Align a) {
}
vec2 off;
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) {
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) {
it->SetPos(it->GetPos() + off);
@ -465,27 +398,16 @@ void UI7::Menu::JoinAlign(UI7Align a) {
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) {
Container* ref = objects.back().get();
Container* ref = Layout->Objects.back().get();
vec2 p = ref->GetPos();
vec2 s = ref->GetSize();
vec2 np = p;
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) {
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);
}
@ -503,17 +425,17 @@ bool UI7::Menu::BeginTreeNode(const UI7::ID& id) {
tree_nodes[(u32)id] = false;
n = tree_nodes.find((u32)id);
}
vec2 pos = Cursor();
vec2 pos = Layout->Cursor;
vec2 tdim = io->Ren->GetTextDimensions(id.GetName());
vec2 size = vec2(tdim.x() + 10 + io->ItemSpace[0], tdim.y());
if (n->second) {
icursoroff.x() += 10.f;
Layout->InitialCursorOffset.x() += 10.f;
}
CursorMove(size);
if (HandleScrolling(pos, size)) {
Layout->CursorMove(size);
if (Layout->ObjectWorkPos(pos)) {
return n->second;
}
vec2 ts = pos + vec2(0, 3);
vec2 ts = Layout->Pos + pos + vec2(0, 3);
vec2 positions[2] = {
vec2(10, 5),
vec2(0, 10),
@ -523,16 +445,18 @@ bool UI7::Menu::BeginTreeNode(const UI7::ID& id) {
positions[0].y() = positions[1].x();
positions[1].x() = t;
}
main->AddTriangle(ts, ts + positions[0], ts + positions[1],
io->Theme->Get(UI7Color_FrameBackground));
main->AddText(pos + vec2(10 + io->ItemSpace[0], 0), id.GetName(),
io->Theme->Get(UI7Color_Text));
if (has_touch && io->DragObject(name + id.GetName(), vec4(pos, size))) {
Layout->GetDrawList()->AddTriangle(ts, ts + positions[0], ts + positions[1],
io->Theme->Get(UI7Color_FrameBackground));
Layout->GetDrawList()->AddText(
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) {
n->second = !n->second;
if (!n->second) {
icursoroff.x() -= 10.f;
cursor.x() -= 10;
Layout->InitialCursorOffset.x() -= 10;
Layout->Cursor.x() -= 10;
}
}
}
@ -540,18 +464,19 @@ bool UI7::Menu::BeginTreeNode(const UI7::ID& id) {
}
void UI7::Menu::EndTreeNode() {
icursoroff.x() -= 10.f;
cursor.x() -= 10;
if (icursoroff.x() < 0.f) {
icursoroff.x() = 0.f;
Layout->InitialCursorOffset.x() -= 10.f;
Layout->Cursor.x() -= 10.f;
if (Layout->InitialCursorOffset.x() < 0.f) {
Layout->InitialCursorOffset.x() = 0.f;
}
}
void UI7::Menu::CloseButtonHandler() {
// Close Logic
if (!(flags & UI7MenuFlags_NoClose) && is_shown != nullptr) {
vec2 cpos = vec2(view_area.x() + view_area.z() - 12 - io->FramePadding.x(),
view_area.y() + io->FramePadding.y());
vec2 cpos =
vec2(Layout->Pos.x() + Layout->Size.x() - 12 - io->FramePadding.x(),
Layout->Pos.y() + io->FramePadding.y());
UI7Color clr = UI7Color_FrameBackground;
if (has_touch &&
@ -561,9 +486,9 @@ void UI7::Menu::CloseButtonHandler() {
}
clr = 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);
Layout->GetDrawList()->AddLine(cpos, cpos + 12, io->Theme->Get(clr), 2);
Layout->GetDrawList()->AddLine(cpos + vec2(0, 12), cpos + vec2(12, 0),
io->Theme->Get(clr), 2);
}
}
@ -571,13 +496,17 @@ void UI7::Menu::ResizeHandler() {
if (!(flags & UI7MenuFlags_NoResize)) {
if (has_touch &&
io->DragObject(name + "rszs",
vec4(view_area.xy() + view_area.zw() - 20, 20))) {
vec2 szs = view_area.zw() + (io->DragPosition - io->DragLastPosition);
vec4(Layout->Pos + Layout->Size - 20, 20))) {
vec2 szs = Layout->Size + (io->DragPosition - io->DragLastPosition);
if (szs.x() < 30) szs[0] = 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->AddTriangle(Layout->Pos + Layout->Size,
Layout->Pos + Layout->Size - vec2(0, 10),
Layout->Pos + Layout->Size - vec2(10, 0),
io->Theme->Get(UI7Color_FrameBackground));
// front->AddRectangle(Layout->Pos + Layout->Size - 20, 20,
// 0xffffffff); Not vidible dor some reason
// int l = front->Layer();
// front->Layer(l + 1);
@ -591,13 +520,11 @@ void UI7::Menu::MoveHandler() {
if (!(flags & UI7MenuFlags_NoMove)) {
if (has_touch &&
io->DragObject(name + "tmv",
vec4(view_area.xy(), vec2(view_area.z(), tbh)))) {
vec4(Layout->Pos, vec2(Layout->Size.x(), tbh)))) {
if (io->DragDoubleRelease) {
is_open = !is_open;
}
view_area =
vec4(view_area.xy() + (io->DragPosition - io->DragLastPosition),
view_area.zw());
Layout->Pos = Layout->Pos + (io->DragPosition - io->DragLastPosition);
}
}
}
@ -605,7 +532,7 @@ void UI7::Menu::MoveHandler() {
void UI7::Menu::CollapseHandler() {
// Collapse logic
if (!(flags & UI7MenuFlags_NoCollapse)) {
vec2 cpos = view_area.xy() + io->FramePadding;
vec2 cpos = Layout->Pos + io->FramePadding;
UI7Color clr = UI7Color_FrameBackground;
if (has_touch &&
io->DragObject(UI7::ID(name + "clbse"), vec4(cpos, vec2(18, tbh)))) {
@ -623,21 +550,22 @@ void UI7::Menu::CollapseHandler() {
positions[0].y() = positions[1].x();
positions[1].x() = t;
}
main->AddTriangle(cpos, cpos + positions[0], cpos + positions[1],
io->Theme->Get(clr));
Layout->GetDrawList()->AddTriangle(
cpos, cpos + positions[0], cpos + positions[1], io->Theme->Get(clr));
}
}
void UI7::Menu::PostScrollHandler() {
if (has_touch && io->DragObject(id, view_area) && scrolling[1] &&
flags & UI7MenuFlags_VtScrolling &&
max[1] - view_area.w() + io->MenuPadding[1] > 0) {
if (has_touch && io->DragObject(id, vec4(Layout->Pos, Layout->Size)) &&
Layout->Scrolling[1] && flags & UI7MenuFlags_VtScrolling &&
Layout->MaxPosition.y() - Layout->Size.y() + io->MenuPadding[1] > 0) {
if (io->DragReleased) {
scroll_mod = (io->DragPosition - io->DragLastPosition);
// scroll_mod = (io->DragPosition - io->DragLastPosition);
} else {
scrolling_off[1] = std::clamp(
scrolling_off[1] - (io->DragPosition.y() - io->DragLastPosition.y()),
-40.f, (max[1] - view_area.w()) + 40.f);
Layout->ScrollOffset[1] = std::clamp(
Layout->ScrollOffset[1] -
(io->DragPosition.y() - io->DragLastPosition.y()),
-40.f, (Layout->MaxPosition.y() - Layout->Size.y()) + 40.f);
}
}
}

View File

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