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

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();
}
}