diff --git a/src/app-manager.h b/src/app-manager.h index 151ca85..25eca79 100644 --- a/src/app-manager.h +++ b/src/app-manager.h @@ -8,7 +8,6 @@ #include "canvas.h" #include "graph-manager.h" #include "midi-node.h" -#include "mouse.h" #include "node.h" #include "raylib.h" #include "signal-manager.h" @@ -20,27 +19,27 @@ using json = nlohmann::json; namespace VISEQ::APP { - class AppManager; - void to_json(json& j, const AppManager& A); - void from_json(const json& j, AppManager& A); - class AppManager{ public: + AppManager() : im(gm->getPtr(), sm->getPtr(), canvas), ui(sm->getPtr(), gm->getPtr()) {} - AppManager() : sm(&gm, &mutex), im(&gm, &sm, canvas), mouse(&gm), ui(&sm, &gm) {} std::mutex mutex; std::shared_ptr state = APP::State::get(); std::shared_ptr canvas = std::make_shared(); - VISEQ::GRAPH::GraphManager gm; - VISEQ::SIGNAL::SignalManager sm; + //VISEQ::GRAPH::GraphManager gm; + //VISEQ::SIGNAL::SignalManager sm; + std::shared_ptr gm = std::make_shared(); + std::shared_ptr sm = std::make_shared(gm->getPtr(), &mutex); VISEQ::INTERACTION::InteractionManager im; - VISEQ::APP::Mouse mouse; +// VISEQ::APP::Mouse mouse; UI::AppUI ui; + NLOHMANN_DEFINE_TYPE_INTRUSIVE(AppManager, gm, sm); + void init(){ canvas->camera.target = (Vector2){ state->settings.width/2.0f, state->settings.height/2.0f }; canvas->camera.offset = (Vector2){ state->settings.width/2.0f, state->settings.height/2.0f }; @@ -55,7 +54,7 @@ namespace VISEQ::APP { } void startSignals(){ - sm.startSignalThread(); + sm->startSignalThread(); } void loadState(){ @@ -81,8 +80,8 @@ namespace VISEQ::APP { for(auto n : graph.at("graphmanager").at("nodes")){ std::shared_ptr mn = n; - gm.addNode(mn); - //app.gm.nodes.push_back(mn); + gm->addNode(mn); + //app.gm->nodes.push_back(mn); std::cout << std::format("adding node {}", mn->id) << std::endl; } @@ -90,57 +89,57 @@ namespace VISEQ::APP { int start_id = e.at("start").get(); int end_id = e.at("end").get(); - VEC_WPTR_Node start = gm.getNodesByID(start_id); - VEC_WPTR_Node end = gm.getNodesByID(end_id); + VEC_WPTR_Node start = gm->getNodesByID(start_id); + VEC_WPTR_Node end = gm->getNodesByID(end_id); -// VEC_SPTR_Node start = gm.nodes | RANGE_FILTER([start_id](SPTR_Node n){return n->id == start_id;}) | std::ranges::to(); -// VEC_SPTR_Node end = gm.nodes | RANGE_FILTER([end_id](SPTR_Node n){return n->id == end_id;}) | std::ranges::to(); +// VEC_SPTR_Node start = gm->nodes | RANGE_FILTER([start_id](SPTR_Node n){return n->id == start_id;}) | std::ranges::to(); +// VEC_SPTR_Node end = gm->nodes | RANGE_FILTER([end_id](SPTR_Node n){return n->id == end_id;}) | std::ranges::to(); if(!start.empty() && !end.empty()) { std::cout << std::format("connection {} to {}", start_id, end_id) << std::endl; - gm.addConnection(start.front(), end.front()); + gm->addConnection(start.front(), end.front()); } } - gm.lastEdge().lock()->newId(highest_id); + gm->lastEdge().lock()->newId(highest_id); for(auto s : graph.at("signalmanager").at("signals")){ int start_id = s.at("start").get(); int next_id = s.at("next").get(); int last_id = s.at("last").get(); std::shared_ptr ms = s; - VEC_WPTR_Node start = gm.getNodesByID(start_id); - VEC_WPTR_Node last = gm.getNodesByID(last_id); - VEC_WPTR_Node next = gm.getNodesByID(next_id); + VEC_WPTR_Node start = gm->getNodesByID(start_id); + VEC_WPTR_Node last = gm->getNodesByID(last_id); + VEC_WPTR_Node next = gm->getNodesByID(next_id); ms->start = start.front(); ms->next = next.front(); ms->last = last.front(); - sm.signals.push_back(ms); + sm->signals.push_back(ms); std::cout << std::format("adding signal with start node {}", start_id) << std::endl; } } else { for(int i = 0; i < 4; ++i){ - gm.addMidiNode(Vec2Df{(float)i * state->settings.grid*4 + 7 * state->settings.grid, 2 * state->settings.grid*4}); + gm->addMidiNode(Vec2Df{(float)i * state->settings.grid*4 + 7 * state->settings.grid, 2 * state->settings.grid*4}); } for(int i = 3; i >= 0; --i){ - gm.addMidiNode(Vec2Df{(float)i * state->settings.grid*4 + 7 * state->settings.grid, 3 * state->settings.grid*4}); + gm->addMidiNode(Vec2Df{(float)i * state->settings.grid*4 + 7 * state->settings.grid, 3 * state->settings.grid*4}); } for(int i = 0; i < 8; ++i){ - gm.addConnection(gm.getNode(i), gm.getNode((i+1) % 8)); + gm->addConnection(gm->getNode(i), gm->getNode((i+1) % 8)); } - sm.addSignalAtNode(gm.getFirstNode()); + sm->addSignalAtNode(gm->getFirstNode()); } } void updateMidiPorts(){ - for(auto&n : gm.getMidiNodes()){ + for(auto&n : gm->getMidiNodes()){ auto nc = std::dynamic_pointer_cast(n.lock()); - for(auto& mo : sm.midi.midi_out_ports){ + for(auto& mo : sm->midi.midi_out_ports){ if(!nc->midi_outs.contains(mo.number) && mo.enabled){ nc->midi_outs[mo.number] = {mo.number, mo.port.port_name, false}; } @@ -154,13 +153,12 @@ namespace VISEQ::APP { void update(){ state->update(canvas->camera); canvas->update(); - gm.update(); + gm->update(); mutex.lock(); updateMidiPorts(); mutex.unlock(); - mouse.update(); im.update(); } @@ -171,9 +169,9 @@ namespace VISEQ::APP { canvas->drawStart(); canvas->draw(); - gm.drawNodes(SCREEN_MOUSE, canvas->camera); - gm.drawEdges(SCREEN_MOUSE, canvas->camera); - sm.drawSignals(SCREEN_MOUSE, canvas->camera); + gm->drawNodes(SCREEN_MOUSE, canvas->camera); + gm->drawEdges(SCREEN_MOUSE, canvas->camera); + sm->drawSignals(SCREEN_MOUSE, canvas->camera); im.draw(); @@ -188,13 +186,6 @@ namespace VISEQ::APP { mutex.unlock(); } - /*inline void to_json(json& j, const AppManager& A){*/ - /* j = json{{"graphmanager", A.gm}, {"signalmanager", A.sm}};*/ - /*}*/ - /**/ - /*inline void from_json(const json& j, AppManager& A){*/ - /* j.at("graphmanager").get_to(A.gm); // = json{{"graphmanager", A.gm}, {"signalmanager", A.sm}};*/ - /*}*/ }; } diff --git a/src/clipboard.h b/src/clipboard.h index d728a49..e345567 100644 --- a/src/clipboard.h +++ b/src/clipboard.h @@ -13,14 +13,12 @@ namespace VISEQ::APP { return clipboard.back(); } - void copyNodes(GRAPH::NODES::VEC_WPTR_Node selected_nodes){ - clipboard.emplace_back(); + void copyNodes(GRAPH::NODES::VEC_SPTR_Node selected_nodes){ + if(clipboard.size() == 20) clipboard.pop_back(); + clipboard.emplace(clipboard.begin()); for(auto n : selected_nodes){ - clipboard.back().push_back(n.lock()); - n.lock().deselect(); + clipboard.front().push_back(n); } - //std::ranges::copy(selected_nodes.begin(), selected_nodes.end(), std::back_inserter(clipboard.back())); - //std::ranges::for_each(selected_nodes.begin(), selected_nodes.end(), [](GRAPH::NODES::SPTR_Node n){n->selected = false;}); } }; diff --git a/src/draggable.h b/src/draggable.h index 018ff43..896c41c 100644 --- a/src/draggable.h +++ b/src/draggable.h @@ -54,5 +54,9 @@ namespace VISEQ::BASE { return CheckCollisionPointRec(position, state->selection); } + virtual void deselect() override { + selected = false; + } + }; } diff --git a/src/graph-manager.h b/src/graph-manager.h index 52c8a97..414801c 100644 --- a/src/graph-manager.h +++ b/src/graph-manager.h @@ -38,14 +38,12 @@ namespace VISEQ::GRAPH { NODES::VEC_SPTR_Node nodes; EDGES::VEC_SPTR_Edge edges; - std::map connections; - EDGES::VEC_WPTR_Edge remove_edges; EDGES::VEC_WPTR_Edge split_edges; - VEC_WPTR_Node selected_nodes; + VEC_SPTR_Node selected_nodes; - std::map counter; + std::map counter; std::shared_ptr state = APP::State::get(); @@ -56,10 +54,20 @@ namespace VISEQ::GRAPH { std::shared_ptr getPtr(){ return shared_from_this(); } - + + int getNodesSize(){ + return nodes.size(); + } + void addMidiNode(Vec2Df position){ nodes.emplace_back(std::make_shared(position)); } + + void setMidiPortForAll(int number, bool _state){ + for(auto n : nodes){ + if(n->getNodeType() == NodeType::MIDINODE) std::dynamic_pointer_cast(n)->setMidiPort(number, _state); + } + } void addNode(SPTR_Node node){ nodes.insert(nodes.end(), node); @@ -70,8 +78,8 @@ namespace VISEQ::GRAPH { edges.emplace_back(std::make_shared()); edges.back()->start = from; edges.back()->end = to; - edges.back()->start_conn = from.lock()->connectors.back(); - edges.back()->end_conn = to.lock()->connectors.back(); +// edges.back()->start_conn = from.lock()->connectors.back(); // TODO: crashes on start +// edges.back()->end_conn = to.lock()->connectors.back(); from.lock()->connections.push_back(edges.back()); to.lock()->connections.push_back(edges.back()); } @@ -88,12 +96,12 @@ namespace VISEQ::GRAPH { void deselect(){ std::cout << "deselect" << std::endl; for(auto s : selected_nodes){ - s.lock()->selected = false; + s->selected = false; } selected_nodes.clear(); } - VEC_WPTR_Node getSelection(){ + VEC_SPTR_Node getSelection(){ return selected_nodes; } @@ -112,7 +120,17 @@ namespace VISEQ::GRAPH { nodes.back()->selected = false; } } - + + VEC_SPTR_Node getCopiesOfSelectedNodes(){ + VEC_SPTR_Node copied_nodes; + for(auto n : selected_nodes){ +// if(n->getNodeType() == NodeType::MIDINODE) copied_nodes.insert(copied_nodes.end(), std::make_shared(*n)); + copied_nodes.insert(copied_nodes.end(), std::make_shared(*n)); + copied_nodes.back()->deselect(); + } + return copied_nodes; + } + SPTR_Node copyNode(SPTR_Node n, Vec2Df position){ std::cout << "copy basenode" << std::endl; nodes.insert(nodes.end(), std::make_shared(*n)); @@ -197,11 +215,11 @@ namespace VISEQ::GRAPH { } if(current.lock()->distributionMode == Distribution::ROUNDROBIN){ - if(counter.find(current) == counter.end()) { - counter[current] = 0; + if(counter.find(current.lock()) == counter.end()) { + counter[current.lock()] = 0; } else { - counter[current] = (counter[current] + 1) % possible_connections.size(); - return_path = counter[current]; + counter[current.lock()] = (counter[current.lock()] + 1) % possible_connections.size(); + return_path = counter[current.lock()]; } } @@ -431,13 +449,19 @@ namespace VISEQ::GRAPH { } } - inline void to_json(json& j, const GraphManager& G){ - j = json{{"nodes", G.nodes}, {"edges", G.edges}}; + void drawNodeUI(){ + } - inline void from_json(const json& j, GraphManager& G){ - j.at("nodes").template get_to(G.nodes); - } + NLOHMANN_DEFINE_TYPE_INTRUSIVE(GraphManager, nodes, edges) + + /*inline void to_json(json& j, const GraphManager& G){*/ + /* j = json{{"nodes", G.nodes}, {"edges", G.edges}};*/ + /*}*/ + /**/ + /*inline void from_json(const json& j, GraphManager& G){*/ + /* j.at("nodes").template get_to(G.nodes);*/ + /*}*/ }; } diff --git a/src/interaction-manager.h b/src/interaction-manager.h index 47d54b3..8106a18 100644 --- a/src/interaction-manager.h +++ b/src/interaction-manager.h @@ -52,11 +52,12 @@ namespace VISEQ::INTERACTION{ class InteractionManager{ public: - InteractionManager(GRAPH::GraphManager *gm, SIGNAL::SignalManager *sm, std::shared_ptr canvas) : canvas(canvas), gm(gm), sm(sm) {} + InteractionManager() {} + InteractionManager(std::shared_ptr gm, std::shared_ptr sm, std::shared_ptr canvas) : canvas(canvas), gm(gm), sm(sm) {} std::shared_ptr canvas; - GraphManager *gm; - SIGNAL::SignalManager *sm; + std::shared_ptr gm; + std::shared_ptr sm; VISEQ::APP::Clipboard cb; std::shared_ptr state = APP::State::get(); @@ -66,7 +67,7 @@ namespace VISEQ::INTERACTION{ void update(){ if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_C)){ - VEC_WPTR_Node selected_nodes = gm->getSelection(); + VEC_SPTR_Node selected_nodes = gm->getCopiesOfSelectedNodes(); if(!selected_nodes.empty()) cb.copyNodes(selected_nodes); } @@ -76,7 +77,7 @@ namespace VISEQ::INTERACTION{ } if(IsKeyPressed(KEY_DELETE)){ - removeNodes(gm->selected_nodes | std::ranges::to()); + removeNodes(gm->getSelection()); } if(IsKeyPressed(KEY_TAB)) { @@ -88,7 +89,7 @@ namespace VISEQ::INTERACTION{ void draw(){ doInteraction(); scaleSelection(); - if(!gm->selected_nodes.empty()){ + if(!gm->getSelection().empty()){ DrawRectangleRoundedLines(state->bounding_box, 0.1f, 3, VS_COLOR_LIGHTGREY); scale_handle->draw(); } @@ -96,7 +97,7 @@ namespace VISEQ::INTERACTION{ void removeNodes(VEC_SPTR_Node nodes){ - VEC_SPTR_Node adjacent_nodes = gm->getAdjacentNodes(nodes); + VEC_WPTR_Node adjacent_nodes = gm->getAdjacentNodes(nodes); sm->rerouteSignal(nodes, adjacent_nodes); sm->rebaseSignal(nodes); @@ -105,14 +106,14 @@ namespace VISEQ::INTERACTION{ } void scaleSelection(){ - if(!gm->selected_nodes.empty()){ + if(!gm->getSelection().empty()){ float offset = 30; Vec2Df corner_tl = {50000, 50000}; Vec2Df corner_br = {-50000, -50000}; std::shared_ptr node_tl; std::shared_ptr node_br; - for(auto n : gm->selected_nodes){ + for(auto n : gm->getSelection()){ float x = n->position.x; float y = n->position.y; @@ -132,7 +133,7 @@ namespace VISEQ::INTERACTION{ if(scale_handle->clicked()){ scale_start = (corner_br - corner_tl); - for(auto n : gm->selected_nodes){ + for(auto n : gm->getSelection()){ n->drag_offset = n->position - node_tl->position; } } @@ -140,7 +141,7 @@ namespace VISEQ::INTERACTION{ Vec2Df scale = (scale_handle->position - corner_tl) / scale_start; if(IsKeyDown(KEY_LEFT_SHIFT)) scale.y = scale.x; DrawText(std::format("{:.2f} {:.2f}", scale.x, scale.y).c_str(), corner_br.x+5, corner_br.y+5, 10, RED); - for(auto n : gm->selected_nodes){ + for(auto n : gm->getSelection()){ n->position = node_tl->position + (n->drag_offset * scale); } } else { @@ -185,13 +186,11 @@ namespace VISEQ::INTERACTION{ while(APP::event_queue.size() > 0 && !exit){ auto e = APP::event_queue.front(); - //std::cout << e.item->getType() << " " << e.action << std::endl; if(!connect_once && e.action == APP::Interaction::CONNECT){ auto connector = std::dynamic_pointer_cast(e.item); - auto connector_to = std::dynamic_pointer_cast(connector->partner); + auto connector_to = std::dynamic_pointer_cast(connector->partner.lock()); gm->addConnection(std::dynamic_pointer_cast(connector->parent), std::dynamic_pointer_cast(connector_to->parent)); - std::cout << "connector use count: " << connector->getPtr().use_count() << std::endl; connect_once = true; } @@ -214,7 +213,7 @@ namespace VISEQ::INTERACTION{ if(e.action == APP::Interaction::PICKUP) { node->pickUp(); if(node->selected){ - for(auto s : gm->selected_nodes){ + for(auto s : gm->getSelection()){ s->pickUp(node->position); } } @@ -228,7 +227,7 @@ namespace VISEQ::INTERACTION{ else node->drag(MOD_MOUSE + node->drag_offset); if(node->selected){ - for(auto s : gm->selected_nodes){ + for(auto s : gm->getSelection()){ s->drag(MOD_MOUSE + s->drag_offset); } } @@ -237,7 +236,7 @@ namespace VISEQ::INTERACTION{ if(e.action == APP::Interaction::PUTDOWN) { node->putDown(); if(node->selected){ - for(auto s : gm->selected_nodes){ + for(auto s : gm->getSelection()){ s->putDown(); } } diff --git a/src/mouse.h b/src/mouse.h index 3ff0fc8..dcd2e99 100644 --- a/src/mouse.h +++ b/src/mouse.h @@ -13,8 +13,8 @@ namespace VISEQ::APP { GraphManager *gm; void update(){ - auto hovering_nodes = gm->nodes | RANGE_FILTER([](SPTR_Node n) { return n->hovering() || n->picked_up;}) | std::ranges::to>>(); - + /*auto hovering_nodes = gm->nodes | RANGE_FILTER([](SPTR_Node n) { return n->hovering() || n->picked_up;}) | std::ranges::to>>();*/ + /**/ /*if(!hovering_nodes.empty()){*/ /* hovering_nodes.front()->is_hovering = true;*/ /**/ diff --git a/src/node.h b/src/node.h index 063468b..3c53a6c 100644 --- a/src/node.h +++ b/src/node.h @@ -1,7 +1,5 @@ #pragma once -#include -#include #include #include @@ -57,6 +55,10 @@ namespace VISEQ::GRAPH::NODES { virtual void trigger() {}; + void deselect() override { + selected = false; + } + GraphItemType getType() override{ return GraphItemType::NODE; } diff --git a/src/selectable.h b/src/selectable.h index d9884ab..391d344 100644 --- a/src/selectable.h +++ b/src/selectable.h @@ -21,5 +21,6 @@ namespace VISEQ::BASE { } virtual bool select() = 0; + virtual void deselect() = 0; }; } diff --git a/src/signal-manager.h b/src/signal-manager.h index 733f582..0c9900b 100644 --- a/src/signal-manager.h +++ b/src/signal-manager.h @@ -22,7 +22,7 @@ namespace VISEQ::SIGNAL { public: SignalManager() {} - SignalManager(GraphManager *gm, std::mutex *mutex) : mutex(mutex), gm(gm) {} + SignalManager(std::shared_ptr gm, std::mutex *mutex) : mutex(mutex), gm(gm) {} std::shared_ptr getPtr(){ return shared_from_this(); @@ -31,7 +31,7 @@ namespace VISEQ::SIGNAL { VISEQ::MIDI::Midi midi; std::mutex *mutex; - GraphManager *gm; + std::shared_ptr gm; VEC_SPTR_Signal signals; @@ -79,16 +79,16 @@ namespace VISEQ::SIGNAL { signals.back()->start = node; } - void rerouteSignal(VEC_SPTR_Node nodes, VEC_SPTR_Node adjacent_nodes){ + void rerouteSignal(VEC_SPTR_Node nodes, VEC_WPTR_Node adjacent_nodes){ auto reroute_signals = signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->next.lock());}); for(auto s : reroute_signals){ float dist = 10000000; SPTR_Node next_node; for(auto n : adjacent_nodes){ - if(n->position.dist(s->position) < dist) { - dist = n->position.dist(s->position); - next_node = n; + if(n.lock()->position.dist(s->position) < dist) { + dist = n.lock()->position.dist(s->position); + next_node = n.lock(); } } s->next = next_node; @@ -158,10 +158,8 @@ namespace VISEQ::SIGNAL { } mutex->unlock(); } + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(SignalManager, signals) }; - - inline void to_json(json& j, const SignalManager& G){ - j = json{{"signals", G.signals}}; - } } diff --git a/src/state-io.h b/src/state-io.h index de93399..bb3b451 100644 --- a/src/state-io.h +++ b/src/state-io.h @@ -20,6 +20,37 @@ typedef std::shared_ptr SPTR_GraphItem; typedef std::vector VEC_SPTR_GraphItem; +namespace nlohmann +{ +template +struct adl_serializer> +{ + static void to_json(json& j, const std::shared_ptr& opt) + { + if (opt) + { + j = *opt; + } + else + { + j = nullptr; + } + } + + static void from_json(const json& j, std::shared_ptr& opt) + { + if (j.is_null()) + { + opt = nullptr; + } + else + { + opt.reset(new T(j.get())); + } + } +}; +} + namespace VISEQ::GRAPH::EDGES { using namespace VISEQ::GRAPH::NODES; diff --git a/src/ui.h b/src/ui.h index 5555cde..ff382a2 100644 --- a/src/ui.h +++ b/src/ui.h @@ -17,12 +17,12 @@ namespace VISEQ::APP::UI{ class AppUI{ public: AppUI() {} - AppUI(SIGNAL::SignalManager *sm, GraphManager *gm) : gm(gm), sm(sm) {} + AppUI(std::shared_ptr sm, std::shared_ptr gm) : gm(gm), sm(sm) {} std::shared_ptr state = State::get(); - GraphManager *gm; - SIGNAL::SignalManager *sm; + std::shared_ptr gm; + std::shared_ptr sm; bool bpm_spinner_edit_mode = false; @@ -60,9 +60,7 @@ namespace VISEQ::APP::UI{ if(GuiButton((Rectangle){20, (float)s_midi + 45 + i*20.0f, 240, 20}, "ENABLE FOR ALL")) { for(auto &midis : sm->midi.midi_out_ports){ if(midis.enabled){ - for(auto n : gm->nodes){ - if(n->getNodeType() == NodeType::MIDINODE) std::dynamic_pointer_cast(n)->setMidiPort(midis.number, true); - } + gm->setMidiPortForAll(midis.number, true); } } } @@ -96,7 +94,7 @@ namespace VISEQ::APP::UI{ if(GuiButton((Rectangle){20, (float)s_nodes + 60, 240, 20}, "ADD RANDOM NODE")){ gm->addMidiNode(Vec2Df{200.0f, 200.0f}); } - DrawText(std::format("{}", gm->nodes.size()).c_str(), 20, state->settings.height - 70, 15, VS_COLOR_WHITE); + DrawText(std::format("{}", gm->getNodesSize()).c_str(), 20, state->settings.height - 70, 15, VS_COLOR_WHITE); DrawFPS(20, state->settings.height - 30); } @@ -106,7 +104,7 @@ namespace VISEQ::APP::UI{ } void drawPerNodeConfig(Camera2D camera){ - for(auto& n : gm->nodes | std::views::filter([](std::shared_ptr n){ return n->config; })){ + for(auto& n : gm->getSelection() | std::views::filter([](std::shared_ptr n){ return n->config; })){ Vector2 np = GetWorldToScreen2D((Vector2){n->position.x, n->position.y}, camera); n->config = !GuiWindowBox((Rectangle){np.x + 10, np.y + 10, 240, 440}, "config");