Made tree listing more generic

This commit is contained in:
Yousef Khadadeh 2025-12-21 00:33:04 +03:00
parent 180c930474
commit 86063f373b
7 changed files with 129 additions and 64 deletions

View file

@ -1,6 +1,8 @@
#include "BookmarkManager.hpp"
#include "../World.hpp"
#include "../MainProgram.hpp"
#include "Helpers/NetworkingObjects/NetObjOrderedList.hpp"
#include "Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp"
BookmarkManager::BookmarkManager(World& w):
world(w)
@ -51,5 +53,59 @@ void BookmarkManager::init() {
}
}
void BookmarkManager::setup_list_gui(const std::string& id) {
using namespace NetworkingObjects;
if(bookmarkListRoot) {
std::optional<NetworkingObjects::NetObjID> toDeleteParent;
std::optional<NetworkingObjects::NetObjID> toDeleteObject;
auto& gui = world.main.toolbar.gui;
gui.tree_listing(id, bookmarkListRoot.get_net_id(), GUIStuff::TreeListing::DisplayData{
.getObjInListAtIndex = [&](NetObjID parentId, size_t index) -> std::optional<GUIStuff::TreeListing::DisplayData::ObjInList> {
NetObjOrderedList<BookmarkListItem>& bookmarkParentFolder = *world.netObjMan.get_obj_temporary_ref_from_id<BookmarkListItem>(parentId)->get_folder_list();
if(bookmarkParentFolder.size() <= index)
return std::nullopt;
return GUIStuff::TreeListing::DisplayData::ObjInList{
.id = bookmarkParentFolder.at(index)->obj.get_net_id(),
.isDirectory = bookmarkParentFolder.at(index)->obj->is_folder(),
.isDirectoryOpen = bookmarkParentFolder.at(index)->obj->is_folder() ? bookmarkParentFolder.at(index)->obj->is_folder_open() : false
};
},
.setDirectoryOpen = [&](NetObjID netID, bool newDirectoryOpen) {
world.netObjMan.get_obj_temporary_ref_from_id<BookmarkListItem>(netID)->set_folder_open(newDirectoryOpen);
},
.drawNonDirectoryObjIconGUI = [&](NetObjID netID) {
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
.padding = CLAY_PADDING_ALL(2),
},
}) {
gui.svg_icon("bookmark ico", "data/icons/bookmark.svg");
}
return false;
},
.drawObjGUI = [&](NetObjID parentNetID, NetObjID netID) {
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
},
}) {
gui.text_label(world.netObjMan.get_obj_temporary_ref_from_id<BookmarkListItem>(netID)->get_name());
}
if(gui.svg_icon_button_transparent("delete button", "data/icons/trash.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) {
toDeleteParent = parentNetID;
toDeleteObject = netID;
}
return false;
}
});
if(toDeleteObject.has_value()) {
auto& folderList = world.netObjMan.get_obj_temporary_ref_from_id<BookmarkListItem>(toDeleteParent.value())->get_folder_list();
folderList->erase(folderList, toDeleteObject.value());
}
}
}
void BookmarkManager::scale_up(const WorldScalar& scaleUpAmount) {
}

View file

@ -11,6 +11,7 @@ class BookmarkManager {
BookmarkManager(World& w);
void init();
void scale_up(const WorldScalar& scaleUpAmount);
void setup_list_gui(const std::string& id);
template <typename Archive> void save(Archive& a) const {
}

View file

@ -2,11 +2,9 @@
#include "../GUIManager.hpp"
#include "Helpers/ConvertVec.hpp"
constexpr float ENTRY_HEIGHT = 25.0f;
namespace GUIStuff {
void TreeListing::update(UpdateInputData& io, GUIManager& gui, const NetworkingObjects::NetObjTemporaryPtr<NetworkingObjects::NetObjOrderedList<BookmarkListItem>>& bookmarkList) {
void TreeListing::update(UpdateInputData& io, GUIManager& gui, NetworkingObjects::NetObjID rootObjID, const DisplayData& displayData) {
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}
@ -22,7 +20,7 @@ void TreeListing::update(UpdateInputData& io, GUIManager& gui, const NetworkingO
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT * itemCountToStartAt)}
}
}) {}
recursive_gui(io, gui, bookmarkList, itemCount, itemCountToStartAt, itemCountToEndAt, 0);
recursive_gui(io, gui, displayData, rootObjID, itemCount, itemCountToStartAt, itemCountToEndAt, 0);
if(itemCount > itemCountToEndAt) {
CLAY_AUTO_ID({
.layout = {
@ -34,66 +32,65 @@ void TreeListing::update(UpdateInputData& io, GUIManager& gui, const NetworkingO
}
}
void TreeListing::recursive_gui(UpdateInputData& io, GUIManager& gui, const NetworkingObjects::NetObjTemporaryPtr<NetworkingObjects::NetObjOrderedList<BookmarkListItem>>& bookmarkList, size_t& itemCount, size_t itemCountToStartAt, size_t itemCountToEndAt, size_t listDepth) {
std::optional<NetworkingObjects::NetObjID> toDelete;
for(auto& bookmarkItem : bookmarkList->get_data()) {
if(itemCount >= itemCountToStartAt && itemCount < itemCountToEndAt) {
gui.push_id(itemCount);
bool buttonClicked = false;
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)},
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
},
.backgroundColor = convert_vec4<Clay_Color>((objSelected.has_value() && objSelected.value() == bookmarkItem->obj.get_net_id()) ? io.theme->backColor1 : io.theme->backColor2),
}) {
if(listDepth != 0) {
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(ENTRY_HEIGHT * listDepth), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)}
},
}) {}
}
if(bookmarkItem->obj->is_folder()) {
if(gui.svg_icon_button_transparent("ico", bookmarkItem->obj->is_folder_open() ? "data/icons/droparrow.svg" : "data/icons/droparrowclose.svg", false, ENTRY_HEIGHT)) {
bookmarkItem->obj->set_folder_open(!bookmarkItem->obj->is_folder_open());
buttonClicked = true;
}
}
else {
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(ENTRY_HEIGHT), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)},
.padding = CLAY_PADDING_ALL(2)
}
}) {
gui.svg_icon("ico", "data/icons/bookmark.svg");
}
}
void TreeListing::recursive_gui(UpdateInputData& io, GUIManager& gui, const DisplayData& displayData, NetworkingObjects::NetObjID objID, size_t& itemCount, size_t itemCountToStartAt, size_t itemCountToEndAt, size_t listDepth) {
for(size_t i = 0;; i++) {
std::optional<DisplayData::ObjInList> objInListOptional = displayData.getObjInListAtIndex(objID, i);
if(!objInListOptional.has_value())
break;
else {
auto& objInList = objInListOptional.value();
if(itemCount >= itemCountToStartAt && itemCount < itemCountToEndAt) {
gui.push_id(itemCount);
bool buttonClicked = false;
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)},
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
}
},
.backgroundColor = convert_vec4<Clay_Color>((objSelected.has_value() && objSelected.value() == objInList.id) ? io.theme->backColor1 : io.theme->backColor2),
}) {
gui.text_label(bookmarkItem->obj->get_name());
if(listDepth != 0) {
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(ENTRY_HEIGHT * listDepth), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)}
},
}) {}
}
if(objInList.isDirectory) {
if(gui.svg_icon_button_transparent("ico", objInList.isDirectoryOpen ? "data/icons/droparrow.svg" : "data/icons/droparrowclose.svg", false, ENTRY_HEIGHT)) {
displayData.setDirectoryOpen(objInList.id, !objInList.isDirectoryOpen);
buttonClicked = true;
}
}
else {
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(ENTRY_HEIGHT), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)},
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
},
}) {
buttonClicked |= displayData.drawNonDirectoryObjIconGUI(objInList.id);
}
}
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
}
}) {
buttonClicked |= displayData.drawObjGUI(objID, objInList.id);
}
if(Clay_Hovered() && io.mouse.leftClick && !buttonClicked)
objSelected = objInList.id;
}
if(gui.svg_icon_button_transparent("delete", "data/icons/trash.svg", false, ENTRY_HEIGHT)) {
toDelete = bookmarkItem->obj.get_net_id();
buttonClicked = true;
}
if(Clay_Hovered() && io.mouse.leftClick && !buttonClicked)
objSelected = bookmarkItem->obj.get_net_id();
gui.pop_id();
}
gui.pop_id();
itemCount++;
if(objInList.isDirectoryOpen)
recursive_gui(io, gui, displayData, objInList.id, itemCount, itemCountToStartAt, itemCountToEndAt, listDepth + 1);
}
itemCount++;
if(bookmarkItem->obj->is_folder() && bookmarkItem->obj->is_folder_open())
recursive_gui(io, gui, bookmarkItem->obj->get_folder_list(), itemCount, itemCountToStartAt, itemCountToEndAt, listDepth + 1);
}
if(toDelete.has_value())
bookmarkList->erase(bookmarkList, toDelete.value());
}
void TreeListing::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command) {

View file

@ -1,7 +1,6 @@
#pragma once
#include "Element.hpp"
#include "../../Bookmarks/BookmarkListItem.hpp"
#include <Helpers/NetworkingObjects/NetObjOrderedList.hpp>
#include <Helpers/NetworkingObjects/NetObjID.hpp>
namespace GUIStuff {
@ -9,10 +8,22 @@ class GUIManager;
class TreeListing : public Element {
public:
void update(UpdateInputData& io, GUIManager& gui, const NetworkingObjects::NetObjTemporaryPtr<NetworkingObjects::NetObjOrderedList<BookmarkListItem>>& bookmarkList);
static constexpr float ENTRY_HEIGHT = 25.0f;
struct DisplayData {
struct ObjInList {
NetworkingObjects::NetObjID id;
bool isDirectory = false;
bool isDirectoryOpen = false;
};
std::function<std::optional<ObjInList>(NetworkingObjects::NetObjID, size_t)> getObjInListAtIndex;
std::function<void(NetworkingObjects::NetObjID, bool)> setDirectoryOpen;
std::function<bool(NetworkingObjects::NetObjID)> drawNonDirectoryObjIconGUI;
std::function<bool(NetworkingObjects::NetObjID, NetworkingObjects::NetObjID)> drawObjGUI;
};
void update(UpdateInputData& io, GUIManager& gui, NetworkingObjects::NetObjID rootObjID, const DisplayData& displayData);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command) override;
private:
void recursive_gui(UpdateInputData& io, GUIManager& gui, const NetworkingObjects::NetObjTemporaryPtr<NetworkingObjects::NetObjOrderedList<BookmarkListItem>>& bookmarkList, size_t& itemCount, size_t itemCountToStartAt, size_t itemCountToEndAt, size_t listDepth);
void recursive_gui(UpdateInputData& io, GUIManager& gui, const DisplayData& displayData, NetworkingObjects::NetObjID objID, size_t& itemCount, size_t itemCountToStartAt, size_t itemCountToEndAt, size_t listDepth);
std::optional<NetworkingObjects::NetObjID> objSelected;
};

View file

@ -897,9 +897,9 @@ void GUIManager::list_popup_menu(const std::string& id, Vector2f popupPos, const
}
}
void GUIManager::tree_listing(const std::string& id, const NetworkingObjects::NetObjTemporaryPtr<NetworkingObjects::NetObjOrderedList<BookmarkListItem>>& bookmarkList) {
void GUIManager::tree_listing(const std::string& id, NetworkingObjects::NetObjID rootObjID, const TreeListing::DisplayData& displayData) {
push_id(id);
insert_element<TreeListing>()->update(*io, *this, bookmarkList);
insert_element<TreeListing>()->update(*io, *this, rootObjID, displayData);
pop_id();
}

View file

@ -102,7 +102,7 @@ class GUIManager {
void paint_circle_popup_menu(const std::string& id, const Vector2f& centerPos, const PaintCircleMenu::Data& val, const std::function<void()>& elemUpdate = nullptr);
void list_popup_menu(const std::string& id, Vector2f popupPos, const std::function<void()>& elemUpdate);
void tree_listing(const std::string& id, const NetworkingObjects::NetObjTemporaryPtr<NetworkingObjects::NetObjOrderedList<BookmarkListItem>>& bookmarkList);
void tree_listing(const std::string& id, NetworkingObjects::NetObjID rootObjID, const TreeListing::DisplayData& displayData);
void obstructing_window();

View file

@ -801,7 +801,7 @@ void Toolbar::bookmark_menu(bool justOpened) {
}) {
gui.obstructing_window();
gui.text_label_centered("Bookmarks");
gui.tree_listing("bookmark listing", main.world->bMan.bookmarkListRoot->get_folder_list());
main.world->bMan.setup_list_gui("bookmark menu list");
if(io->mouse.leftClick && !Clay_Hovered() && !justOpened)
bookMenu.popupOpen = false;
}