diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1c27a7a..b2a8aeb 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -80,7 +80,11 @@ set(sources "src/main.cpp"
"src/DrawingProgram/EllipseDrawEditTool.cpp"
"src/DrawingProgram/RectDrawEditTool.cpp"
"src/DrawingProgram/TextBoxEditTool.cpp"
+ "src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp"
+ "src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp"
"src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp"
+ "src/DrawingProgram/Layers/DrawingProgramLayerFolder.cpp"
+ "src/DrawingProgram/Layers/DrawingProgramLayer.cpp"
"src/CanvasComponents/CanvasComponentContainer.cpp"
"src/CanvasComponents/CanvasComponentAllocator.cpp"
"src/CanvasComponents/BrushStrokeCanvasComponent.cpp"
diff --git a/data/icons/layer.svg b/data/icons/layer.svg
new file mode 100644
index 0000000..e65f8a1
--- /dev/null
+++ b/data/icons/layer.svg
@@ -0,0 +1,87 @@
+
+
+
+
diff --git a/src/Bookmarks/BookmarkManager.cpp b/src/Bookmarks/BookmarkManager.cpp
index 4c83a4a..33dd3a1 100644
--- a/src/Bookmarks/BookmarkManager.cpp
+++ b/src/Bookmarks/BookmarkManager.cpp
@@ -68,6 +68,7 @@ void BookmarkManager::setup_list_gui(const std::string& id) {
},
.drawObjGUI = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) {
auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(idPair.object);
+ bool isButtonClicked = false;
if(Clay_Hovered() && gui.io->mouse.leftClick >= 2 && !tempPtr->is_folder() && selectionData.objsSelected.contains(idPair.object) && !gui.io->key.leftCtrl && !gui.io->key.leftShift)
tempPtr->get_bookmark_data().jump_to(world);
CLAY_AUTO_ID({
@@ -80,14 +81,14 @@ void BookmarkManager::setup_list_gui(const std::string& id) {
}
if(!tempPtr->is_folder() && gui.svg_icon_button_transparent("jump button", "data/icons/jump.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) {
tempPtr->get_bookmark_data().jump_to(world);
- return true;
+ isButtonClicked = true;
}
if(gui.svg_icon_button_transparent("delete button", "data/icons/trash.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) {
toDeleteParent = idPair.parent;
toDeleteObject = idPair.object;
- return true;
+ isButtonClicked = true;
}
- return false;
+ return isButtonClicked;
},
.moveObjectsToListAtIndex = [&](NetObjID listObj, size_t index, const std::vector& objsToInsert) {
world.netObjMan.send_multi_update_messsage([&]() {
diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp
index 4c95cc3..e47739b 100644
--- a/src/DrawingProgram/DrawingProgram.cpp
+++ b/src/DrawingProgram/DrawingProgram.cpp
@@ -33,6 +33,7 @@
DrawingProgram::DrawingProgram(World& initWorld):
world(initWorld),
compCache(*this),
+ layerMan(*this),
selection(*this)
{
drawTool = DrawingProgramToolBase::allocate_tool_type(*this, DrawingProgramToolType::BRUSH);
@@ -43,6 +44,7 @@ void DrawingProgram::init() {
components = world.netObjMan.make_obj>();
set_component_list_callbacks();
}
+ layerMan.init();
}
void DrawingProgram::set_component_list_callbacks() {
@@ -93,6 +95,7 @@ void DrawingProgram::clear_draw_cache() {
void DrawingProgram::write_components_server(cereal::PortableBinaryOutputArchive& a) {
components.write_create_message(a);
+ layerMan.write_components_server(a);
}
void DrawingProgram::read_components_client(cereal::PortableBinaryInputArchive& a) {
@@ -102,6 +105,7 @@ void DrawingProgram::read_components_client(cereal::PortableBinaryInputArchive&
});
compCache.test_rebuild(components->get_data(), true);
set_component_list_callbacks();
+ layerMan.read_components_client(a);
}
void DrawingProgram::toolbar_gui() {
diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp
index ec743f6..bd39694 100644
--- a/src/DrawingProgram/DrawingProgram.hpp
+++ b/src/DrawingProgram/DrawingProgram.hpp
@@ -16,6 +16,7 @@
#include "DrawingProgramToolBase.hpp"
#include
#include
+#include "Layers/DrawingProgramLayerManager.hpp"
class World;
@@ -49,6 +50,7 @@ class DrawingProgram {
DrawingProgramCache compCache;
+ DrawingProgramLayerManager layerMan;
CanvasComponentContainer::NetListOwnerPtr components;
Vector4f* get_foreground_color_ptr();
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayer.cpp b/src/DrawingProgram/Layers/DrawingProgramLayer.cpp
new file mode 100644
index 0000000..a9702f2
--- /dev/null
+++ b/src/DrawingProgram/Layers/DrawingProgramLayer.cpp
@@ -0,0 +1,6 @@
+#include "DrawingProgramLayer.hpp"
+
+void DrawingProgramLayer::draw(SkCanvas* canvas, const DrawData& drawData) {
+ for(auto& p : components->get_data())
+ p->obj->draw(canvas, drawData);
+}
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayer.hpp b/src/DrawingProgram/Layers/DrawingProgramLayer.hpp
index 7b98fc9..7349533 100644
--- a/src/DrawingProgram/Layers/DrawingProgramLayer.hpp
+++ b/src/DrawingProgram/Layers/DrawingProgramLayer.hpp
@@ -6,5 +6,7 @@ class DrawingProgramLayerListItem;
class DrawingProgramLayer {
public:
+ void draw(SkCanvas* canvas, const DrawData& drawData);
+
CanvasComponentContainer::NetListOwnerPtr components;
};
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerFolder.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.cpp
new file mode 100644
index 0000000..54c11fc
--- /dev/null
+++ b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.cpp
@@ -0,0 +1,7 @@
+#include "DrawingProgramLayerFolder.hpp"
+#include "DrawingProgramLayerListItem.hpp"
+
+void DrawingProgramLayerFolder::draw(SkCanvas* canvas, const DrawData& drawData) {
+ for(auto& p : folderList->get_data())
+ p->obj->draw(canvas, drawData);
+}
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp
index cd11c27..4d5f57b 100644
--- a/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp
+++ b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp
@@ -1,10 +1,14 @@
#pragma once
#include
+#include
+#include "../../DrawData.hpp"
class DrawingProgramLayerListItem;
class DrawingProgramLayerFolder {
public:
+ void draw(SkCanvas* canvas, const DrawData& drawData);
+
NetworkingObjects::NetObjOwnerPtr> folderList;
bool isFolderOpen = false;
};
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp
index 7537480..023acbe 100644
--- a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp
+++ b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp
@@ -43,6 +43,17 @@ DrawingProgramLayer& DrawingProgramLayerListItem::get_layer() const {
return *layerData;
}
+void DrawingProgramLayerListItem::draw(SkCanvas* canvas, const DrawData& drawData) const {
+ if(displayData->visible) {
+ canvas->saveLayerAlphaf(nullptr, displayData->alpha);
+ if(folderData)
+ folderData->draw(canvas, drawData);
+ else
+ layerData->draw(canvas, drawData);
+ canvas->restore();
+ }
+}
+
void DrawingProgramLayerListItem::set_name(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, const std::string& newName) const {
if(nameData && nameData->name != newName) {
nameData->name = newName;
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp
index 9dd0396..aeaf0db 100644
--- a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp
+++ b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp
@@ -18,6 +18,7 @@ class DrawingProgramLayerListItem {
DrawingProgramLayer& get_layer() const;
static void register_class(World& w);
void reassign_netobj_ids_call();
+ void draw(SkCanvas* canvas, const DrawData& drawData) const;
void set_name(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, const std::string& newName) const;
const std::string& get_name() const;
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp
new file mode 100644
index 0000000..f97348b
--- /dev/null
+++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp
@@ -0,0 +1,20 @@
+#include "DrawingProgramLayerManager.hpp"
+#include "../../World.hpp"
+
+DrawingProgramLayerManager::DrawingProgramLayerManager(DrawingProgram& drawProg):
+ drawP(drawProg), // initialize drawP first for next objects to be initialized properly
+ listGUI(*this)
+{}
+
+void DrawingProgramLayerManager::init() {
+ if(drawP.world.netObjMan.is_server())
+ layerTreeRoot = drawP.world.netObjMan.make_obj_from_ptr(new DrawingProgramLayerListItem(drawP.world.netObjMan, "ROOT", true));
+}
+
+void DrawingProgramLayerManager::write_components_server(cereal::PortableBinaryOutputArchive& a) {
+ layerTreeRoot.write_create_message(a);
+}
+
+void DrawingProgramLayerManager::read_components_client(cereal::PortableBinaryInputArchive& a) {
+ layerTreeRoot = drawP.world.netObjMan.read_create_message(a, nullptr);
+}
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp
new file mode 100644
index 0000000..1f657ad
--- /dev/null
+++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp
@@ -0,0 +1,17 @@
+#pragma once
+#include "DrawingProgramLayerListItem.hpp"
+#include "DrawingProgramLayerManagerGUI.hpp"
+
+class DrawingProgramLayerManager {
+ private:
+ DrawingProgram& drawP;
+ friend class DrawingProgramLayerManagerGUI;
+ NetworkingObjects::NetObjOwnerPtr layerTreeRoot;
+
+ public:
+ DrawingProgramLayerManager(DrawingProgram& drawProg);
+ void init();
+ void write_components_server(cereal::PortableBinaryOutputArchive& a);
+ void read_components_client(cereal::PortableBinaryInputArchive& a);
+ DrawingProgramLayerManagerGUI listGUI;
+};
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp
new file mode 100644
index 0000000..08a9ba3
--- /dev/null
+++ b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp
@@ -0,0 +1,197 @@
+#include "DrawingProgramLayerManagerGUI.hpp"
+#include "DrawingProgramLayerManager.hpp"
+#include "../DrawingProgram.hpp"
+#include "../../World.hpp"
+#include "../../MainProgram.hpp"
+
+DrawingProgramLayerManagerGUI::DrawingProgramLayerManagerGUI(DrawingProgramLayerManager& drawLayerMan):
+ layerMan(drawLayerMan)
+{}
+
+void DrawingProgramLayerManagerGUI::refresh_gui_data() {
+ selectionData = GUIStuff::TreeListing::SelectionData();
+ oldSelection.clear();
+ nameToEdit.clear();
+ nameForNew.clear();
+ alphaValToEdit = 0.0f;
+}
+
+void DrawingProgramLayerManagerGUI::setup_list_gui(const std::string& id) {
+ using namespace NetworkingObjects;
+ auto& world = layerMan.drawP.world;
+ if(layerMan.layerTreeRoot) {
+ auto& gui = world.main.toolbar.gui;
+ gui.push_id(id);
+ if(layerMan.layerTreeRoot->get_folder().folderList->empty()) {
+ gui.text_label_centered("No layers exist.");
+ selectionData = GUIStuff::TreeListing::SelectionData();
+ oldSelection.clear();
+ nameToEdit.clear();
+ }
+ else {
+ std::optional toDeleteParent;
+ std::optional toDeleteObject;
+ gui.tree_listing("list", layerMan.layerTreeRoot.get_net_id(), GUIStuff::TreeListing::DisplayData{
+ .getObjInListAtIndex = [&](NetObjID parentId, size_t index) -> std::optional {
+ NetObjOrderedList& parentFolder = *world.netObjMan.get_obj_temporary_ref_from_id(parentId)->get_folder().folderList;
+ if(parentFolder.size() <= index)
+ return std::nullopt;
+ return GUIStuff::TreeListing::DisplayData::ObjInList{
+ .id = parentFolder.at(index)->obj.get_net_id(),
+ .isDirectory = parentFolder.at(index)->obj->is_folder(),
+ .isDirectoryOpen = parentFolder.at(index)->obj->is_folder() ? parentFolder.at(index)->obj->get_folder().isFolderOpen : false
+ };
+ },
+ .getIndexOfObjInList = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) {
+ return world.netObjMan.get_obj_temporary_ref_from_id(idPair.parent)->get_folder().folderList->get(idPair.object)->pos;
+ },
+ .setDirectoryOpen = [&](NetObjID netID, bool newDirectoryOpen) {
+ world.netObjMan.get_obj_temporary_ref_from_id(netID)->get_folder().isFolderOpen = 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("ico", "data/icons/layer.svg");
+ }
+ return false;
+ },
+ .drawObjGUI = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) {
+ auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(idPair.object);
+ bool isButtonClicked = false;
+ if(Clay_Hovered() && gui.io->mouse.leftClick >= 2 && !tempPtr->is_folder() && selectionData.objsSelected.contains(idPair.object) && !gui.io->key.leftCtrl && !gui.io->key.leftShift)
+ std::cout << "Double clicked layer!" << std::endl;
+ 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(tempPtr->get_name());
+ }
+ if(gui.svg_icon_button_transparent("visible button", tempPtr->get_visible() ? "data/icons/eyeopen.svg" : "data/icons/eyeclose.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) {
+ tempPtr->set_visible(world.delayedUpdateObjectManager, !tempPtr->get_visible());
+ isButtonClicked = true;
+ }
+ if(gui.svg_icon_button_transparent("delete button", "data/icons/trash.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) {
+ toDeleteParent = idPair.parent;
+ toDeleteObject = idPair.object;
+ isButtonClicked = true;
+ }
+ return isButtonClicked;
+ },
+ .moveObjectsToListAtIndex = [&](NetObjID listObj, size_t index, const std::vector& objsToInsert) {
+ world.netObjMan.send_multi_update_messsage([&]() {
+ std::unordered_map> toEraseMap;
+ uint32_t newIndex = index;
+ std::vector> toInsertObjPtrs;
+ auto& listPtr = world.netObjMan.get_obj_temporary_ref_from_id(listObj)->get_folder().folderList;
+
+ for(size_t i = 0; i < objsToInsert.size(); i++) {
+ toEraseMap[objsToInsert[i].parent].emplace(objsToInsert[i].object);
+ if(newIndex != 0 && objsToInsert[i].parent == listObj && listPtr->get(objsToInsert[i].object)->pos <= index)
+ newIndex--;
+ }
+
+ for(auto& [listToEraseFrom, setToErase] : toEraseMap) {
+ auto& listToEraseFromPtr = world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder().folderList;
+ listToEraseFromPtr->erase_unordered_set(listToEraseFromPtr, setToErase, &toInsertObjPtrs);
+ }
+
+ std::vector>> toInsert;
+ for(uint32_t i = 0; i < objsToInsert.size(); i++) {
+ auto it = std::find_if(toInsertObjPtrs.begin(), toInsertObjPtrs.end(), [id = objsToInsert[i].object](NetObjOwnerPtr& objPtr) {
+ return objPtr.get_net_id() == id;
+ });
+ toInsert.emplace_back(newIndex + i, std::move(*it));
+ toInsert.back().second.reassign_ids();
+ }
+ listPtr->insert_ordered_list_and_send_create(listPtr, toInsert);
+ }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
+ }
+ }, selectionData);
+
+
+ if(selectionData.objsSelected != oldSelection) {
+ oldSelection = selectionData.objsSelected;
+ if(selectionData.objsSelected.size() == 1) {
+ NetObjTemporaryPtr tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(*selectionData.objsSelected.begin());
+ if(tempPtr) {
+ nameToEdit = tempPtr->get_name();
+ alphaValToEdit = tempPtr->get_alpha();
+ }
+ else {
+ nameToEdit.clear();
+ alphaValToEdit = 0.0f;
+ }
+ }
+ else {
+ nameToEdit.clear();
+ alphaValToEdit = 0.0f;
+ }
+ }
+
+ if(toDeleteObject.has_value()) {
+ auto& folderList = world.netObjMan.get_obj_temporary_ref_from_id(toDeleteParent.value())->get_folder().folderList;
+ folderList->erase(folderList, toDeleteObject.value());
+ }
+ }
+
+ gui.left_to_right_line_layout([&]() {
+ bool addByEnter = false;
+ gui.input_text("input new name", &nameForNew, true, [&](GUIStuff::SelectionHelper& s) {
+ addByEnter = s.selected && gui.io->key.enter;
+ });
+
+ if(gui.svg_icon_button("create new layer", "data/icons/plusbold.svg", false, gui.SMALL_BUTTON_SIZE) || addByEnter)
+ create_in_proper_position(new DrawingProgramLayerListItem(world.netObjMan, nameForNew, false));
+ else if(gui.svg_icon_button("create new folder", "data/icons/folderbold.svg", false, gui.SMALL_BUTTON_SIZE)) {
+ auto newFolderObjInfo = create_in_proper_position(new DrawingProgramLayerListItem(world.netObjMan, nameForNew, true));
+ newFolderObjInfo->obj->get_folder().isFolderOpen = true;
+ }
+ });
+
+ if(selectionData.objsSelected.size() == 1) {
+ NetObjTemporaryPtr tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(*selectionData.objsSelected.begin());
+ if(tempPtr) {
+ gui.text_label_centered(tempPtr->is_folder() ? "Edit Layer Folder" : "Edit Layer");
+ gui.input_text_field("input edit name", "Name", &nameToEdit);
+ tempPtr->set_name(world.delayedUpdateObjectManager, nameToEdit);
+ gui.slider_scalar_field("input alpha slider", "Alpha", &alphaValToEdit, 0.0f, 1.0f, 2);
+ tempPtr->set_alpha(world.delayedUpdateObjectManager, alphaValToEdit);
+ }
+ }
+
+ gui.pop_id();
+ }
+}
+
+NetworkingObjects::NetObjOrderedListObjectInfoPtr DrawingProgramLayerManagerGUI::try_to_create_in_proper_position(DrawingProgramLayerListItem* newItem) {
+ using namespace NetworkingObjects;
+ auto& world = layerMan.drawP.world;
+ if(selectionData.orderedObjsSelected.empty())
+ return nullptr;
+ auto& backObjParentObjectPair = selectionData.orderedObjsSelected.back();
+ NetObjTemporaryPtr parentPtr = world.netObjMan.get_obj_temporary_ref_from_id(backObjParentObjectPair.parent);
+ if(!parentPtr)
+ return nullptr;
+ NetObjTemporaryPtr objectPtr = world.netObjMan.get_obj_temporary_ref_from_id(backObjParentObjectPair.object);
+ if(!objectPtr)
+ return nullptr;
+ if(objectPtr->is_folder()) {
+ objectPtr->get_folder().isFolderOpen = true;
+ return objectPtr->get_folder().folderList->push_back_and_send_create(objectPtr->get_folder().folderList, newItem);
+ }
+ uint32_t insertPos = parentPtr->get_folder().folderList->get(objectPtr.get_net_id())->pos;
+ return parentPtr->get_folder().folderList->insert_and_send_create(parentPtr->get_folder().folderList, insertPos + 1, newItem);
+}
+
+NetworkingObjects::NetObjOrderedListObjectInfoPtr DrawingProgramLayerManagerGUI::create_in_proper_position(DrawingProgramLayerListItem* newItem) {
+ auto toRet = try_to_create_in_proper_position(newItem);
+ if(!toRet)
+ return layerMan.layerTreeRoot->get_folder().folderList->push_back_and_send_create(layerMan.layerTreeRoot->get_folder().folderList, newItem);
+ return toRet;
+}
diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp
new file mode 100644
index 0000000..0d002d8
--- /dev/null
+++ b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp
@@ -0,0 +1,26 @@
+#pragma once
+#include
+#include
+#include "../../GUIStuff/Elements/TreeListing.hpp"
+#include "DrawingProgramLayerListItem.hpp"
+
+class World;
+class DrawingProgramLayerManager;
+
+class DrawingProgramLayerManagerGUI {
+ public:
+ DrawingProgramLayerManagerGUI(DrawingProgramLayerManager& layerManager);
+ void refresh_gui_data();
+ void setup_list_gui(const std::string& id);
+ private:
+ NetworkingObjects::NetObjOrderedListObjectInfoPtr try_to_create_in_proper_position(DrawingProgramLayerListItem* newItem);
+ NetworkingObjects::NetObjOrderedListObjectInfoPtr create_in_proper_position(DrawingProgramLayerListItem* newItem);
+
+ GUIStuff::TreeListing::SelectionData selectionData;
+ std::unordered_set oldSelection;
+ std::string nameToEdit;
+ std::string nameForNew;
+ float alphaValToEdit = 0.0f;
+
+ DrawingProgramLayerManager& layerMan;
+};
diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp
index 4cd386c..39e87c4 100644
--- a/src/Toolbar.cpp
+++ b/src/Toolbar.cpp
@@ -463,6 +463,7 @@ void Toolbar::top_toolbar() {
bool menuPopUpJustOpen = false;
bool bookmarkMenuPopUpJustOpen = false;
bool gridMenuPopUpJustOpen = false;
+ bool layerMenuPopUpJustOpen = false;
if(gui.svg_icon_button_transparent("Main Menu Button", "data/icons/menu.svg", menuPopUpOpen)) {
menuPopUpOpen = true;
menuPopUpJustOpen = true;
@@ -486,6 +487,14 @@ void Toolbar::top_toolbar() {
gridMenuPopUpJustOpen = true;
}
}
+ if(gui.svg_icon_button_transparent("Layer Menu Button", "data/icons/layer.svg", layerMenuPopupOpen)) {
+ if(layerMenuPopupOpen)
+ layerMenuPopupOpen = false;
+ else {
+ layerMenuPopupOpen = true;
+ layerMenuPopUpJustOpen = true;
+ }
+ }
if(gui.svg_icon_button_transparent("Bookmark Menu Button", "data/icons/bookmark.svg", bookmarkMenuPopupOpen)) {
if(bookmarkMenuPopupOpen)
bookmarkMenuPopupOpen = false;
@@ -502,6 +511,8 @@ void Toolbar::top_toolbar() {
grid_menu(gridMenuPopUpJustOpen);
if(bookmarkMenuPopupOpen)
bookmark_menu(bookmarkMenuPopUpJustOpen);
+ if(layerMenuPopupOpen)
+ layer_menu(layerMenuPopUpJustOpen);
if(menuPopUpOpen) {
CLAY_AUTO_ID({
.layout = {
@@ -810,6 +821,31 @@ void Toolbar::bookmark_menu(bool justOpened) {
gui.pop_id();
}
+void Toolbar::layer_menu(bool justOpened) {
+ gui.push_id("layer menu");
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0, 600) },
+ .padding = CLAY_PADDING_ALL(io->theme->padding1),
+ .childGap = io->theme->childGap1,
+ .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP},
+ .layoutDirection = CLAY_TOP_TO_BOTTOM
+ },
+ .backgroundColor = convert_vec4(io->theme->backColor1),
+ .cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1),
+ .floating = {.offset = {.x = 0, .y = static_cast(io->theme->padding1)}, .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT}
+ }) {
+ gui.obstructing_window();
+ gui.text_label_centered("Layers");
+ main.world->drawProg.layerMan.listGUI.setup_list_gui("layer menu list");
+ if(io->mouse.leftClick && !Clay_Hovered() && !justOpened) {
+ layerMenuPopupOpen = false;
+ main.world->drawProg.layerMan.listGUI.refresh_gui_data();
+ }
+ }
+ gui.pop_id();
+}
+
std::unique_ptr Toolbar::build_paragraph_from_chat_message(const ChatMessage& message, float alpha) {
skia::textlayout::ParagraphStyle pStyle;
pStyle.setTextAlign(skia::textlayout::TextAlign::kLeft);
diff --git a/src/Toolbar.hpp b/src/Toolbar.hpp
index f922652..55b9eb7 100644
--- a/src/Toolbar.hpp
+++ b/src/Toolbar.hpp
@@ -103,6 +103,7 @@ class Toolbar {
void grid_menu(bool justOpened);
void stop_displaying_grid_menu();
void bookmark_menu(bool justOpened);
+ void layer_menu(bool justOpened);
void drawing_program_gui();
void options_menu();
void file_picker_gui();
@@ -189,6 +190,7 @@ class Toolbar {
} generalSettingsOptions = GSETTINGS_GENERAL;
bool bookmarkMenuPopupOpen = false;
+ bool layerMenuPopupOpen = false;
struct GridMenu {
bool popupOpen = false;
diff --git a/src/UndoManager.cpp b/src/UndoManager.cpp
index 4528354..9beb771 100644
--- a/src/UndoManager.cpp
+++ b/src/UndoManager.cpp
@@ -1,6 +1,8 @@
#include "UndoManager.hpp"
#include
+// NOTE: It might be possible to track net objects through their raw pointer values instead of NetObjIDs, as the NetObjID is just reassigned when moved, and it isn't reallocated.
+
bool UndoManager::can_undo() {
return !undoQueue.empty();
}
diff --git a/src/World.cpp b/src/World.cpp
index ab9ebc0..28552ae 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include "DrawingProgram/Layers/DrawingProgramLayerListItem.hpp"
#include "Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp"
#include "Helpers/NetworkingObjects/NetObjUnorderedSet.hpp"
#include "CommandList.hpp"
@@ -116,6 +117,8 @@ void World::init_net_obj_type_list() {
CanvasComponentAllocator::register_class(*this);
CanvasComponentContainer::register_class(netObjMan);
NetworkingObjects::register_ordered_list_class(netObjMan);
+ DrawingProgramLayerListItem::register_class(*this);
+ NetworkingObjects::register_ordered_list_class(netObjMan);
canvasTheme.register_class();
ClientData::register_class(*this);
NetworkingObjects::register_unordered_set_class(netObjMan);