palladium/source/ui7/menu.cpp
tobid7 f87c103d8d # Stage 1.8
- Renderer now vould use more screen Objects
- Register default Top and Bottom Screens (for Overlays and UI7)
- Make ToHex an Inline header func
- Add GetCompilerVersion
- Add Library Compile And Version Info to common
- Remove z of vertex object and shader in position
- Add Container base and SubContainers to UI7
- Add abillity to Join Multiple Objects in Same Line and Center them
- Fix LayerOrder Bug for updating texts in DrawList
2025-02-02 20:32:07 +01:00

332 lines
10 KiB
C++

#include <pd/common/sys.hpp>
#include <pd/common/timetrace.hpp>
#include <pd/ui7/menu.hpp>
namespace PD {
namespace UI7 {
void UI7::Menu::Label(const std::string& label) {
Container::Ref r =
ObjectPush(PD::New<UI7::Label>(label, Cursor(), this->back->ren));
CursorMove(r->GetSize());
r->Init(main->ren, main, linked_theme);
r->HandleScrolling(scrolling_off, view_area);
}
bool UI7::Menu::Button(const std::string& label) {
bool ret = false;
u32 id = Strings::FastHash("btn" + label);
Container::Ref r = FindIDObj(id);
if (!r) {
r = ObjectPush(PD::New<UI7::Button>(label, Cursor(), this->back->ren));
r->SetID(id);
r->Init(main->ren, main, linked_theme);
} else {
ObjectPush(r);
r->SetPos(Cursor());
}
CursorMove(r->GetSize());
r->HandleScrolling(scrolling_off, view_area);
if (!r->Skippable()) {
ret = std::static_pointer_cast<UI7::Button>(r)->IsPressed();
}
return ret;
}
void UI7::Menu::Checkbox(const std::string& label, bool& v) {
u32 id = Strings::FastHash("cbx" + label);
Container::Ref r = FindIDObj(id);
if (!r) {
r = ObjectPush(PD::New<UI7::Checkbox>(label, Cursor(), v, this->back->ren));
r->SetID(id);
r->Init(main->ren, main, linked_theme);
} else {
ObjectPush(r);
r->SetPos(Cursor());
}
CursorMove(r->GetSize());
r->HandleScrolling(scrolling_off, view_area);
}
void UI7::Menu::Image(Texture::Ref img, vec2 size) {
Container::Ref r =
ObjectPush(PD::New<UI7::Image>(img, Cursor(), this->back->ren, size));
CursorMove(r->GetSize());
r->Init(main->ren, main, linked_theme);
r->HandleScrolling(scrolling_off, view_area);
}
void UI7::Menu::DebugLabels() {
std::stringstream s;
s << "Name: " << name << " [";
s << std::hex << std::setw(8) << std::setfill('0') << id;
s << std::dec << "]";
this->Label(s.str());
this->Label(
"Pre: " +
Strings::FormatNanos(
Sys::GetTraceRef("MPRE_" + name)->GetProtocol()->GetAverage()));
this->Label(
"Post: " +
Strings::FormatNanos(
Sys::GetTraceRef("MPOS_" + name)->GetProtocol()->GetAverage()));
this->Label(
"Update: " +
Strings::FormatNanos(
Sys::GetTraceRef("MUPT_" + name)->GetProtocol()->GetAverage()));
this->Label(
"MUser: " +
Strings::FormatNanos(
Sys::GetTraceRef("MUSR_" + name)->GetProtocol()->GetAverage()));
}
void UI7::Menu::Update(float delta) {
TT::Scope st("MUPT_" + name);
for (auto& it : objects) {
if (it->GetID() != 0 && !FindIDObj(it->GetID())) {
idobjs.push_back(it);
}
if (!it->Skippable()) {
it->HandleInput(inp);
/// Unlock Input after to ensure nothing is checked twice
it->UnlockInput();
it->Draw();
}
}
this->back->Process();
this->main->Process();
this->front->Process();
this->objects.clear();
}
void UI7::Menu::CursorMove(const vec2& size) {
last_size = size;
slcursor = cursor + vec2(size[0] + 5, 0);
if (bslpos[1]) {
cursor = vec2(5, cursor[1] + bslpos[1] + 5);
bslpos = vec2();
} else {
cursor = vec2(5, cursor[1] + size[1] + 5);
}
max = vec2(slcursor[0], cursor[1]);
}
void UI7::Menu::PreHandler(UI7MenuFlags flags) {
TT::Scope st("MPRE_" + name);
TT::Beg("MUSR_" + name);
this->back->BaseLayer(30);
this->main->BaseLayer(40);
this->front->BaseLayer(50);
Cursor(vec2(5, 5));
this->flags = flags;
this->scrolling[0] = flags & UI7MenuFlags_HzScrolling;
this->scrolling[1] = flags & UI7MenuFlags_VtScrolling;
has_touch =
main->GetRenderer()->CurrentScreen()->ScreenType() == Screen::Bottom;
if (!(flags & UI7MenuFlags_NoBackground)) {
back->AddRectangle(0, view_area.zw(),
linked_theme->Get(UI7Color_Background));
}
if (!(flags & UI7MenuFlags_NoTitlebar)) {
tbh = front->GetRenderer()->TextScale() * 30.f;
front->AddRectangle(0, vec2(view_area.z(), tbh),
linked_theme->Get(UI7Color_Header));
vec2 tpos(5, tbh * 0.5 - front->ren->GetTextDimensions(name).y() * 0.5);
LITextFlags tflags = LITextFlags_None;
if (flags & UI7MenuFlags_CenterTitle) {
tpos = 0;
tflags = LITextFlags_AlignMid;
}
front->AddText(tpos, this->name, linked_theme->Get(UI7Color_Text), tflags,
vec2(view_area.z(), tbh));
Cursor(vec2(5, tbh + 5));
}
}
void UI7::Menu::PostHandler() {
TT::Scope st("MPOS_" + name);
if (scrolling[1]) {
scroll_allowed[1] = (max[1] > 235);
scrollbar[1] = scroll_allowed[1];
if (scrollbar[1]) {
/// Setup Some Variables hare [they are self described]
int screen_w = view_area.z();
int tsp = 5 + tbh;
int slider_w = 4;
int szs = view_area.w() - tsp - 5;
/// 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]);
/// 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] - 5) {
scrolling_off[1] -= 3.f;
if (scrolling_off[1] < max[1] - view_area[3]) {
scrolling_off[1] = max[1] - view_area[3];
}
}
/// 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;
}
}
/// Dont overscroll to much
if (scrolling_off[1] < -40 ||
scrolling_off[1] > max[1] - view_area[3] + 40) {
scroll_mod[1] = 0.f;
}
/// The pain :(
if (has_touch) {
vec2 tpos = inp->TouchPos();
if (inp->IsDown(inp->Touch)) {
mouse = tpos;
} else if (inp->IsUp(inp->Touch)) {
mouse = vec2();
}
if (inp->IsHeld(inp->Touch)) {
if (!front->ren->InBox(tpos, vec4(view_area[2] - 13, tbh + 5, 8,
view_area[3] - tbh - 10))) {
if (scrolling_off[1] < max[1] - view_area[3] + 40 &&
scrolling_off[1] > -40) {
/// Cursor Mod
float cm = mouse[1] - tpos[1];
if (scroll_mod[1] <= 4.f && scroll_mod[1] >= -4.f && cm != 0) {
scroll_mod[1] = cm;
}
}
mouse = tpos;
}
}
}
/// Effect
if (scroll_mod[1] != 0) {
scrolling_off[1] += scroll_mod[1];
}
if (scroll_mod[1] < 0.f) {
scroll_mod[1] += 0.4f;
if (scroll_mod[1] > 0.f) {
scroll_mod[1] = 0;
}
}
if (scroll_mod[1] > 0.f) {
scroll_mod[1] -= 0.4f;
if (scroll_mod[1] < 0.f) {
scroll_mod[1] = 0;
}
}
int srpos =
tsp + std::clamp(float(szs - vslider_h - 4) *
(scrolling_off[1] / (max[1] - view_area[3])),
0.f, float(szs - vslider_h - 4));
/// Rendering Stage
front->AddRectangle(vec2(screen_w - 12, tsp), vec2(slider_w * 2, szs),
linked_theme->Get(UI7Color_FrameBackground));
front->AddRectangle(vec2(screen_w - 10, tsp + 2), vec2(slider_w, szs - 4),
linked_theme->Get(UI7Color_FrameBackgroundHovered));
front->AddRectangle(vec2(screen_w - 10, srpos + 2),
vec2(slider_w, vslider_h),
linked_theme->Get(UI7Color_Button));
}
}
TT::End("MUSR_" + name);
}
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)) {
return;
}
main->AddRectangle(pos, size, linked_theme->Get(UI7Color_TextDead));
}
void UI7::Menu::SeparatorText(const std::string& label) {
vec2 size = vec2(view_area.z() - (scrollbar[1] ? 24 : 10), 1);
vec2 tdim = this->back->GetRenderer()->GetTextDimensions(label);
vec2 pos = Cursor();
CursorMove(vec2(size.x(), tdim.y() - 4)); // Fix to make gap not to large
if (HandleScrolling(pos, size)) {
return;
}
/// Label pos for better overview
vec2 lpos = pos + vec2((view_area.z() - 10) * 0.5 - tdim.x() * 0.5, 0);
main->AddRectangle(pos + vec2(0, tdim.y() * 0.5),
vec2(lpos.x() - pos.x() - 5, size.y()),
linked_theme->Get(UI7Color_TextDead));
main->AddRectangle(pos + vec2(lpos.x() + tdim.x(), tdim.y() * 0.5),
vec2(size.x() - (lpos.x() + tdim.x()), size.y()),
linked_theme->Get(UI7Color_TextDead));
main->AddText(lpos, label, linked_theme->Get(UI7Color_Text), 0,
vec2(view_area.z(), 20));
}
bool UI7::Menu::HandleScrolling(vec2& pos, const vec2& size) {
if (scrolling[1]) {
vec2 p = pos;
pos -= vec2(0, scrolling_off.y());
if (pos.y() > view_area.w() ||
(pos.y() + size.y() < tbh - 5 && p.y() > tbh)) {
return true;
}
}
return false;
}
Container::Ref UI7::Menu::ObjectPush(Container::Ref obj) {
this->objects.push_back(obj);
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() {
Assert(objects.size(), "Objects list is empty!");
join.push_back(objects.back().get());
}
void UI7::Menu::JoinOpHzCenter() {
this->Join();
float spos = join.front()->GetPos().x();
float szs = join.back()->GetPos().x() + join.back()->GetSize().x() - spos;
float off = (view_area.x() + view_area.z() * 0.5) - (spos + szs * 0.5);
for (auto it : join) {
it->SetPos(it->GetPos() + vec2(off, 0.f));
}
join.clear();
}
void UI7::Menu::AfterAlignCenter() {
Container* ref = objects.back().get();
vec2 p = ref->GetPos();
vec2 s = ref->GetSize();
float newx = (view_area.x() + view_area.z() * 0.5) - (p.x() + s.x() * 0.5);
ref->SetPos(vec2(newx, p.y()));
}
} // namespace UI7
} // namespace PD