diff --git a/src/app-manager.h b/src/app-manager.h index aa537a8..f960529 100644 --- a/src/app-manager.h +++ b/src/app-manager.h @@ -2,17 +2,15 @@ #include #include +#include "interaction-manager.h" #include "nlohmann/json.hpp" -#include "clipboard.h" #include "datatypes.h" #include "canvas.h" #include "graph-manager.h" -#include "interaction-event.h" #include "midi-node.h" #include "mouse.h" #include "node.h" #include "raylib.h" -#include "selectable.h" #include "signal-manager.h" #include "state.h" #include "ui.h" @@ -30,18 +28,18 @@ namespace VISEQ::APP { class AppManager{ public: - AppManager() : sm(&gm, &mutex), mouse(&gm), ui(&sm, &gm) {} + 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::APP::Clipboard cb; + VISEQ::INTERACTION::InteractionManager im; VISEQ::APP::Mouse mouse; - std::shared_ptr state = APP::State::get(); - UI::AppUI ui; void init(){ @@ -60,7 +58,7 @@ namespace VISEQ::APP { void startSignals(){ sm.startSignalThread(); } - + void loadState(){ if(std::filesystem::exists("state.json")){ std::ifstream f("state.json"); @@ -152,104 +150,6 @@ namespace VISEQ::APP { } } - void removeNodes(VEC_SPTR_Node nodes){ - - VEC_SPTR_Node adjacent_nodes = gm.getAdjacentNodes(nodes); - - sm.rerouteSignal(nodes, adjacent_nodes); - sm.rebaseSignal(nodes); - - gm.removeNodesAndEdges(nodes); - } - - void doInteraction(){ - bool exit = false; - bool once = false; - state->mouse_z = canvas->z_index; - - while(event_queue.size() > 0 && !exit){ - auto e = event_queue.front(); - std::cout << e.item->getType() << " " << e.action << std::endl; - - if(e.action == Interaction::HOVER){ - state->mouse_z = e.item->z_index; - std::cout << state->mouse_z << std::endl; - } - - if(e.item->getType() == GraphItemType::CANVAS) { - if(e.action == Interaction::SELECT) { - gm.select(); - std::cout << "app canvas select" << std::endl; - canvas->clearSelectionRect(); - } - if(e.action == Interaction::DESELECT) { - std::cout << "app canvas deselect" << std::endl; - gm.deselect(); - } - } - - if(!once && e.item->getType() == GraphItemType::NODE){ - auto node = std::dynamic_pointer_cast(e.item); - if(e.action == Interaction::PICKUP) { - node->pickUp(); - if(node->selected){ - for(auto s : gm.selected_nodes){ - s->pickUp(node->position); - } - } - once = true; - } - if(e.action == Interaction::DRAG) { - if(KEYS_DOWN.ctrl) node->drag(MOD_MOUSE); - else node->drag(MOD_MOUSE + node->drag_offset); - - if(node->selected){ - for(auto s : gm.selected_nodes){ - s->drag(MOD_MOUSE + s->drag_offset); - } - } - once = true; - } - if(e.action == Interaction::PUTDOWN) { - node->putDown(); - if(node->selected){ - for(auto s : gm.selected_nodes){ - s->putDown(); - } - } - } - } - if(exit) break; - - if(!once && (e.item->getType() == GraphItemType::CONNECTOR || e.item->getType() == GraphItemType::CANVAS)) { - switch(e.action){ - case VISEQ::APP::Interaction::PICKUP: - { - e.item->pickUp(); - once = true; - break; - } - case VISEQ::APP::Interaction::DRAG: - { - e.item->drag(MOD_MOUSE); - once = true; - break; - } - case VISEQ::APP::Interaction::PUTDOWN: - { - e.item->putDown(); - break; - } - default: - {} - } - } - - event_queue.pop_front(); - } - event_queue.clear(); - } - void update(){ state->update(canvas->camera); canvas->update(); @@ -258,18 +158,9 @@ namespace VISEQ::APP { updateMidiPorts(); mutex.unlock(); - doInteraction(); mouse.update(); + im.update(); - if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_C)){ - VEC_SPTR_Node selected_nodes = gm.getSelection(); - if(!selected_nodes.empty()) cb.pushNodes(selected_nodes); - } - - if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_V)){ - VEC_SPTR_Node paste_nodes = cb.pullNodes(); - if(!paste_nodes.empty()) gm.pasteNodesAndEdges(paste_nodes, MOD_MOUSE); - } } void draw(){ @@ -282,6 +173,8 @@ namespace VISEQ::APP { gm.drawEdges(SCREEN_MOUSE, canvas->camera); sm.drawSignals(SCREEN_MOUSE, canvas->camera); + im.draw(); + canvas->drawEnd(); drawUI(); EndDrawing(); diff --git a/src/canvas.h b/src/canvas.h index 6c90620..be43a79 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -61,7 +61,7 @@ namespace VISEQ::APP::CANVAS { std::shared_ptr getPtr(){ return shared_from_this(); } - + virtual void update() override { camera_delta = state->mouse_delta * (-1.0f/camera.zoom); diff --git a/src/connector.h b/src/connector.h index 52812da..2c169c4 100644 --- a/src/connector.h +++ b/src/connector.h @@ -57,6 +57,7 @@ namespace VISEQ::GRAPH { if(new_partner) { //TODO what happens if a new partner is connected? new_partner = false; + state->pushEvent({getPtr(), APP::Interaction::CONNECT}); } } diff --git a/src/datatypes.h b/src/datatypes.h index 518239a..6caaec2 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -33,7 +33,7 @@ namespace VISEQ::GRAPH::NODES { namespace VISEQ::GRAPH{ - enum GraphItemType {NODE, EDGE, CONNECTOR, CANVAS}; + enum GraphItemType {NODE, EDGE, CONNECTOR, CANVAS, HANDLE}; enum NodeType {OSCNODE, MIDINODE, CONFIGNODE}; enum EdgeType {MIDIEDGE, CONFIGEDGE}; } diff --git a/src/edge.h b/src/edge.h index 9774031..08725ea 100644 --- a/src/edge.h +++ b/src/edge.h @@ -1,5 +1,6 @@ #pragma once +#include "connector.h" #include "graph-item.h" #include #include "node.h" diff --git a/src/graph-manager.h b/src/graph-manager.h index 446c0ef..4e86f96 100644 --- a/src/graph-manager.h +++ b/src/graph-manager.h @@ -2,7 +2,6 @@ #include "datatypes.h" -#include "draggable.h" #include "state.h" #include "vmath.h" #include "raylib.h" @@ -34,14 +33,19 @@ using namespace VISEQ::GRAPH::EDGES; namespace VISEQ::GRAPH { - class GraphManager{ + class GraphManager : public std::enable_shared_from_this{ public: GraphManager() {} + std::shared_ptr getPtr(){ + return shared_from_this(); + } + NODES::VEC_SPTR_Node nodes; EDGES::VEC_SPTR_Edge edges; + std::map connections; EDGES::VEC_SPTR_Edge remove_edges; EDGES::VEC_SPTR_Edge split_edges; @@ -51,17 +55,25 @@ namespace VISEQ::GRAPH { std::map counter; std::shared_ptr state = APP::State::get(); + + SPTR_Node addMidiNode(Vec2Df position){ + nodes.emplace_back(std::make_shared(position)); + return nodes.back(); + } - NODES::SPTR_Node getRandomNode(){ - VEC_SPTR_GraphItem o; - std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); - return std::dynamic_pointer_cast(o.front()); + void addNode(SPTR_Node node){ + nodes.insert(nodes.end(), node); + nodes.back()->init(); } - EDGES::SPTR_Edge getRandomEdge(){ - VEC_SPTR_GraphItem o; - std::ranges::sample(edges, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); - return std::dynamic_pointer_cast(o.front()); + void addConnection(SPTR_Node from, SPTR_Node to){ + if(from != to) { + edges.emplace_back(std::make_shared()); + edges.back()->start = from; + edges.back()->end = to; + from->connections.push_back(edges.back()); + to->connections.push_back(edges.back()); + } } void select(){ @@ -84,12 +96,7 @@ namespace VISEQ::GRAPH { return selected_nodes; //return nodes | RANGE_FILTER([](SPTR_Node n){return n->selected;}) | std::ranges::to(); } - - void addNode(SPTR_Node node){ - nodes.insert(nodes.end(), node); - nodes.back()->init(); - } - + void copyNodes(VEC_SPTR_Node _nodes, Vec2Df position){ for(auto n: _nodes){ nodes.insert(nodes.end(), std::make_shared(*n)); @@ -119,12 +126,7 @@ namespace VISEQ::GRAPH { nodes.back()->setPosition(position); return nodes.back(); } - - SPTR_Node addMidiNode(Vec2Df position){ - nodes.emplace_back(std::make_shared(position)); - return nodes.back(); - } - + void setNodeMode(int mode){ for(auto n: nodes){ n->SMode(mode); @@ -135,10 +137,28 @@ namespace VISEQ::GRAPH { counter.clear(); } - SPTR_Node next_node(SPTR_Node current, SPTR_Node last){ - std::vector> active_connectors; - + NODES::SPTR_Node getRandomNode(){ + VEC_SPTR_GraphItem o; + std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); + return std::dynamic_pointer_cast(o.front()); } + + EDGES::SPTR_Edge getRandomEdge(){ + VEC_SPTR_GraphItem o; + std::ranges::sample(edges, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); + return std::dynamic_pointer_cast(o.front()); + } + + SPTR_Node getClosestNode(Vec2Df position){ + auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->picked_up;}) | std::ranges::to(); + std::sort(neighbors.begin(), neighbors.end(), [position](SPTR_Node na, SPTR_Node nb){ return na->position.dist(position) < nb->position.dist(position);}); + return neighbors.front(); + } + + /*SPTR_Node next_node(SPTR_Node current, SPTR_Node last){*/ + /* std::vector> active_connectors;*/ + /**/ + /*}*/ SPTR_Node next(SPTR_Node current, SPTR_Node last){ VEC_SPTR_Edge possible_connections = current->connections | RANGE_FILTER([current](SPTR_Edge c){ @@ -180,22 +200,6 @@ namespace VISEQ::GRAPH { return possible_connections.at(return_path)->getNextNode(current); } - SPTR_Node getClosestNode(Vec2Df position){ - auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->picked_up;}) | std::ranges::to(); - std::sort(neighbors.begin(), neighbors.end(), [position](SPTR_Node na, SPTR_Node nb){ return na->position.dist(position) < nb->position.dist(position);}); - return neighbors.front(); - } - - void addConnection(SPTR_Node from, SPTR_Node to){ - if(from != to) { - edges.emplace_back(std::make_shared()); - edges.back()->start = from; - edges.back()->end = to; - from->connections.push_back(edges.back()); - to->connections.push_back(edges.back()); - } - } - void splitEdge(SPTR_Edge edge){ split_edges.push_back(edge); } diff --git a/src/interaction-event.h b/src/interaction-event.h index 0d50e4c..700e5d6 100644 --- a/src/interaction-event.h +++ b/src/interaction-event.h @@ -6,7 +6,7 @@ namespace VISEQ::APP{ - enum Interaction {NONE, HOVER, CLICK, HOLD, RELEASE, PICKUP, DRAG, PUTDOWN, SELECT, DESELECT}; + enum Interaction {NONE, HOVER, CLICK, HOLD, RELEASE, PICKUP, DRAG, PUTDOWN, SELECT, DESELECT, CONNECT}; struct InteractionEvent{ std::shared_ptr item; diff --git a/src/interaction-manager.h b/src/interaction-manager.h new file mode 100644 index 0000000..0e04fe3 --- /dev/null +++ b/src/interaction-manager.h @@ -0,0 +1,274 @@ +#pragma once + +#include "clipboard.h" +#include "connector.h" +#include "datatypes.h" +#include "draggable.h" +#include "graph-item.h" +#include "graph-manager.h" +#include "interaction-event.h" +#include "raylib.h" +#include "signal-manager.h" +#include "state.h" +#include "canvas.h" +#include + +namespace VISEQ::INTERACTION{ + class ScaleHandle : public BASE::Draggable, public GraphItem{ + public: + ScaleHandle(){} + + float radius = 6; + + std::shared_ptr getPtr(){ + return std::static_pointer_cast(shared_from_this()); + } + + virtual GRAPH::GraphItemType getType() override { + return GraphItemType::HANDLE; + } + + virtual bool hovering() override { + return CheckCollisionPointCircle(SCREEN_MOUSE, position, radius); + } + + virtual void update() override { + if(hovering()) state->pushEvent({getPtr(), APP::Interaction::HOVER}); + if(hovering() && clicked()) state->pushEvent({getPtr(), APP::Interaction::PICKUP}); + if(pickedUp()) state->pushEvent({getPtr(), APP::Interaction::DRAG}); + if(picked_up && released()) state->pushEvent({getPtr(), APP::Interaction::PUTDOWN}); + } + + virtual void draw() override { + DrawCircleV(position, radius, VS_COLOR_SUN); + } + + virtual bool select() override { + return false; + } + }; + + class InteractionManager{ + public: + InteractionManager(GRAPH::GraphManager *gm, SIGNAL::SignalManager *sm, std::shared_ptr canvas) : canvas(canvas), gm(gm), sm(sm) {} + + std::shared_ptr canvas; + GraphManager *gm; + SIGNAL::SignalManager *sm; + VISEQ::APP::Clipboard cb; + + std::shared_ptr state = APP::State::get(); + + Vec2Df scale_start; + std::shared_ptr scale_handle = std::make_shared(); + + void update(){ + doInteraction(); + if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_C)){ + VEC_SPTR_Node selected_nodes = gm->getSelection(); + if(!selected_nodes.empty()) cb.pushNodes(selected_nodes); + } + + if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_V)){ + VEC_SPTR_Node paste_nodes = cb.pullNodes(); + if(!paste_nodes.empty()) gm->pasteNodesAndEdges(paste_nodes, MOD_MOUSE); + } + + if(IsKeyPressed(KEY_DELETE)){ + removeNodes(gm->selected_nodes | std::ranges::to()); + } + + if(IsKeyPressed(KEY_TAB)) { + state->node_mode = (state->node_mode + 1) % 3; + } + + scaleSelection(); + } + + void removeNodes(VEC_SPTR_Node nodes){ + + VEC_SPTR_Node adjacent_nodes = gm->getAdjacentNodes(nodes); + + sm->rerouteSignal(nodes, adjacent_nodes); + sm->rebaseSignal(nodes); + + gm->removeNodesAndEdges(nodes); + } + + void scaleSelection(){ + if(!gm->selected_nodes.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){ + float x = n->position.x; + float y = n->position.y; + + if(x < corner_tl.x && y < corner_tl.y) node_tl = n; + if(x > corner_br.x && y > corner_br.y) node_br = n; + + if(x <= corner_tl.x) corner_tl.x = x; + if(x >= corner_br.x) corner_br.x = x; + if(y <= corner_tl.y) corner_tl.y = y; + if(y >= corner_br.y) corner_br.y = y; + } + corner_tl -= Vec2Df(offset, offset); + corner_br += Vec2Df(offset, offset); + state->bounding_box = (Rectangle){corner_tl.x, corner_tl.y, corner_br.x - corner_tl.x, corner_br.y - corner_tl.y}; + + scale_handle->update(); + + if(scale_handle->clicked()){ + scale_start = (corner_br - corner_tl); + for(auto n : gm->selected_nodes){ + n->drag_offset = n->position - node_tl->position; + } + } + if(scale_handle->picked_up){ + 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){ + n->position = node_tl->position + (n->drag_offset * scale); + } + } else { + scale_handle->position = corner_br; + } + } + } + + void snapPolar(std::shared_ptr dragNode){ + float steps = round((dragNode->neighbors.front()->position.dist(SCREEN_MOUSE)) / state->settings.grid) * state->settings.grid; + if(dragNode->neighbors.size() > 1){ + Vec2Df dn1 = dragNode->neighbors[0]->position; + Vec2Df dn2 = dragNode->neighbors[1]->position; + Vec2Df v1_orth = dn1.center(dn2); + + if(dn1.x < dn2.x) std::swap(dn1,dn2); + + float dist = dn1.dist(dn2); + float dist_orth = std::sqrt(std::pow(steps,2) - std::pow(dist/2,2)); + + if(SCREEN_MOUSE.y < v1_orth.y) dist_orth *= -1; + + Vec2Df v1_orth_t = v1_orth + (dn1-dn2).norm().orth() * dist_orth; + DrawLineV(dn1, dn2, VS_COLOR_RED); + DrawLineV(v1_orth, v1_orth_t, VS_COLOR_RED); + DrawCircleV(v1_orth, 3.0f, VS_COLOR_RED); + dragNode->position = v1_orth_t; + } else if(!dragNode->neighbors.empty()){ + float pol_r = steps; + float pol_theta = Vector2Angle(Vec2Df{1,0},(SCREEN_MOUSE - dragNode->neighbors.front()->position)); + Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); + dragNode->position = dragNode->neighbors.front()->position + polar; + } + } + + void doInteraction(){ + bool exit = false; + bool once = false; + state->mouse_z = canvas->z_index; + + while(APP::event_queue.size() > 0 && !exit){ + auto e = APP::event_queue.front(); + std::cout << e.item->getType() << " " << e.action << std::endl; + + if(e.action == APP::Interaction::CONNECT){ + auto connector = std::dynamic_pointer_cast(e.item); + auto connector_to = std::dynamic_pointer_cast(connector->partner); + gm->addConnection(std::dynamic_pointer_cast(connector->parent), std::dynamic_pointer_cast(connector_to->parent)); + } + + if(e.action == APP::Interaction::HOVER){ + state->mouse_z = e.item->z_index; + std::cout << state->mouse_z << std::endl; + } + + if(e.item->getType() == GraphItemType::CANVAS) { + if(e.action == APP::Interaction::SELECT) { + gm->select(); + std::cout << "app canvas select" << std::endl; + canvas->clearSelectionRect(); + } + if(e.action == APP::Interaction::DESELECT) { + std::cout << "app canvas deselect" << std::endl; + gm->deselect(); + } + } + + if(!once && e.item->getType() == GraphItemType::NODE){ + auto node = std::dynamic_pointer_cast(e.item); + if(e.action == APP::Interaction::PICKUP) { + node->pickUp(); + if(node->selected){ + for(auto s : gm->selected_nodes){ + s->pickUp(node->position); + } + } + once = true; + } + if(e.action == APP::Interaction::DRAG) { + if(KEYS_DOWN.ctrl) node->drag(MOD_MOUSE); + else if(KEYS_DOWN.shift) { + snapPolar(node); + } + else node->drag(MOD_MOUSE + node->drag_offset); + + if(node->selected){ + for(auto s : gm->selected_nodes){ + s->drag(MOD_MOUSE + s->drag_offset); + } + } + once = true; + } + if(e.action == APP::Interaction::PUTDOWN) { + node->putDown(); + if(node->selected){ + for(auto s : gm->selected_nodes){ + s->putDown(); + } + } + } + } + if(exit) break; + + if(!once && (e.item->getType() == GraphItemType::CONNECTOR || e.item->getType() == GraphItemType::CANVAS || e.item->getType() == GraphItemType::HANDLE)) { + switch(e.action){ + case VISEQ::APP::Interaction::PICKUP: + { + e.item->pickUp(); + once = true; + break; + } + case VISEQ::APP::Interaction::DRAG: + { + e.item->drag(MOD_MOUSE); + once = true; + break; + } + case VISEQ::APP::Interaction::PUTDOWN: + { + e.item->putDown(); + break; + } + default: + {} + } + } + + APP::event_queue.pop_front(); + } + APP::event_queue.clear(); + } + + void draw(){ + if(!gm->selected_nodes.empty()){ + DrawRectangleRoundedLines(state->bounding_box, 0.1f, 3, VS_COLOR_LIGHTGREY); + scale_handle->draw(); + } + } + }; +} diff --git a/src/main.cpp b/src/main.cpp index 99b91c1..1d734e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,104 +61,7 @@ int main(){ app.update(); app.draw(); - /*else if(IsKeyDown(KEY_LEFT_SHIFT)){*/ - /* float steps = round((dragNode->neighbors.front()->position.dist(mouse_pos)) / state->settings.grid) * state->settings.grid;*/ - /* if(dragNode->neighbors.size() > 1){*/ - /* Vec2Df dn1 = dragNode->neighbors[0]->position;*/ - /* Vec2Df dn2 = dragNode->neighbors[1]->position;*/ - /* Vec2Df v1_orth = dn1.center(dn2);*/ - /**/ - /* if(dn1.x < dn2.x) std::swap(dn1,dn2);*/ - /**/ - /* float dist = dn1.dist(dn2);*/ - /* float dist_orth = std::sqrt(std::pow(steps,2) - std::pow(dist/2,2));*/ - /**/ - /* if(mouse_pos.y < v1_orth.y) dist_orth *= -1;*/ - /**/ - /* Vec2Df v1_orth_t = v1_orth + (dn1-dn2).norm().orth() * dist_orth;*/ - /* DrawLineV(dn1, dn2, VS_COLOR_RED);*/ - /* DrawLineV(v1_orth, v1_orth_t, VS_COLOR_RED);*/ - /* DrawCircleV(v1_orth, 3.0f, VS_COLOR_RED);*/ - /* dragNode->position = v1_orth_t;*/ - /* } else if(!dragNode->neighbors.empty()){*/ - /* float pol_r = steps;*/ - /* float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - dragNode->neighbors.front()->position));*/ - /* Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); */ - /* dragNode->position = dragNode->neighbors.front()->position + polar;*/ - /* }*/ - // auto dragging_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->dragging;}); - /*auto connecting_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->connecting;});*/ - /*auto selected_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->selected && !n->picked_up;}) | std::ranges::to();*/ - /*auto hovering_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->hovering();});*/ - /*auto hovering_connectors = app.gm.nodes | RANGE_FILTER([&mouse_pos](SPTR_Node n) { return CheckCollisionPointCircle(mouse_pos, (n->position - ((n->position - mouse_pos)).norm() * (n->radius + 14.0f)), 8.0f);});*/ - /**/ - /*for(auto &n : app.gm.nodes ){*/ - /* if(hovering_connectors.empty()) n->hover_connect = false;*/ - /*}*/ - /**/ - /*if(istate != InteractionState::ADD_NODES_MENU && !mouse_down && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::HOVER_CANVAS;*/ - /*if((mouse_clicked || mouse_down || mouse_released) && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty() && istate != InteractionState::SCALE_SELECTION) istate = InteractionState::DRAW_SELECTION;*/ - /**/ - /*if(!hovering_nodes.empty() && !mouse_down && !mouse_right_down) istate = InteractionState::HOVER_NODE;*/ - /*if(!dragging_nodes.empty()) istate = InteractionState::DRAG_NODE; */ - /*if(!hovering_connectors.empty() && !mouse_right_down && istate == InteractionState::HOVER_CANVAS) istate = InteractionState::HOVER_CONNECTOR;*/ - /*if(!connecting_nodes.empty()) istate = InteractionState::CONNECT_NODE;*/ - /**/ - /*if(!selected_nodes.empty() && IsKeyPressed(KEY_DELETE)) istate = InteractionState::DELETE_SELECTED_NODES;*/ - /*if(!selected_nodes.empty() && IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C)) istate = InteractionState::COPY_SELECTED_NODES;*/ - /**/ - /*if(!copied_nodes.empty() && IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V)) istate = InteractionState::PASTE_SELECTED_NODES;*/ - /**/ - /*if(IsKeyPressed(KEY_TAB)) {*/ - /* state->settings.mode = (state->settings.mode + 1) % 3;*/ - /* app.gm.setNodeMode(state->settings.mode);*/ - /*}*/ - /*if(!selected_nodes.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 : selected_nodes){*/ - /* float x = n->position.x;*/ - /* float y = n->position.y;*/ - /**/ - /* if(x < corner_tl.x && y < corner_tl.y) node_tl = n;*/ - /* if(x > corner_br.x && y > corner_br.y) node_br = n;*/ - /**/ - /* if(x <= corner_tl.x) corner_tl.x = x;*/ - /* if(x >= corner_br.x) corner_br.x = x;*/ - /* if(y <= corner_tl.y) corner_tl.y = y;*/ - /* if(y >= corner_br.y) corner_br.y = y;*/ - /* }*/ - /* corner_tl -= Vec2Df(offset, offset);*/ - /* corner_br += Vec2Df(offset, offset);*/ - /**/ - /* DrawRectangleLines(corner_tl.x, corner_tl.y, (corner_br.x - corner_tl.x), (corner_br.y - corner_tl.y), VS_COLOR_LIGHTGREY);*/ - /* DrawCircleV(corner_br, 5, YELLOW);*/ - /**/ - /* if(istate == InteractionState::SCALE_SELECTION && mouse_released){*/ - /* istate = InteractionState::HOVER_CANVAS;*/ - /* }*/ - /* if(mouse_clicked && corner_br.dist(mouse_pos) < 10){*/ - /* scale_start = (corner_br - corner_tl);*/ - /* for(auto n : selected_nodes){*/ - /* n->drag_offset = n->position - node_tl->position;*/ - /* }*/ - /* istate = InteractionState::SCALE_SELECTION;*/ - /* }*/ - /* if(istate == InteractionState::SCALE_SELECTION && mouse_down){*/ - /* Vec2Df scale = (mouse_pos - 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 : selected_nodes){*/ - /* n->position = node_tl->position + (n->drag_offset * scale);*/ - /* }*/ - /* istate = InteractionState::SCALE_SELECTION;*/ - /* }*/ - /*}*/ /*switch(istate){*/ /* case InteractionState::SCALE_SELECTION:*/ @@ -186,189 +89,6 @@ int main(){ /* DrawCircleLines(node_menu_position.x, node_menu_position.y, 32, VS_COLOR_DARKGREY);*/ /**/ /* }*/ - /* case InteractionState::DRAW_SELECTION:*/ - /* {*/ - /* if(mouse_clicked){*/ - /* select_start = mouse_pos;*/ - /* }*/ - /* if(mouse_down){*/ - /* Vec2Df select1 = {mouse_pos.x > select_start.x ? select_start.x : mouse_pos.x, mouse_pos.y > select_start.y ? select_start.y : mouse_pos.y};*/ - /* Vec2Df select2 = {mouse_pos.x > select_start.x ? mouse_pos.x - select_start.x : select_start.x - mouse_pos.x, mouse_pos.y > select_start.y ? mouse_pos.y - select_start.y : select_start.y - mouse_pos.y};*/ - /* DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150});*/ - /* selection = (Rectangle){select1.x, select1.y, select2.x, select2.y};*/ - /**/ - /* for(auto& n : app.gm.nodes){*/ - /* if(CheckCollisionPointRec(n->position, selection)) {*/ - /* n->in_rect = true;*/ - /* } else {*/ - /* n->in_rect = false;*/ - /* }*/ - /* }*/ - /* }*/ - /**/ - /* if(mouse_released){ */ - /* int n_selected = 0;*/ - /* for(auto& n : app.gm.nodes){*/ - /* if(CheckCollisionPointRec(n->position, selection)) {*/ - /* n->selected = true;*/ - /* n->in_rect = false;*/ - /* n_selected++;*/ - /* } else {*/ - /* if(!IsKeyDown(KEY_LEFT_SHIFT)) n->selected = false;*/ - /* }*/ - /* }*/ - /* if(n_selected > 0) copied_nodes.clear();*/ - /* selection = (Rectangle){0,0,0,0};*/ - /* }*/ - /* break;*/ - /* }*/ - /* case InteractionState::HOVER_NODE:*/ - /* {*/ - /* if(mouse_clicked) {*/ - /* if(IsKeyDown(KEY_LEFT_SHIFT)) {*/ - /* hovering_nodes.front()->selected = true;*/ - /* } else {*/ - /* hovering_nodes.front()->dragging = true;*/ - /* hovering_nodes.front()->drag_offset = hovering_nodes.front()->position - mouse_pos;*/ - /* }*/ - /* }*/ - /* if(mouse_right_clicked) hovering_nodes.front()->config = true;*/ - /* break;*/ - /* }*/ - /* case InteractionState::DRAG_NODE:*/ - /* {*/ - /* if(!dragging_nodes.empty()){*/ - /* SPTR_Node dragNode = dragging_nodes.front();*/ - /**/ - /* for(auto &n : selected_nodes){*/ - /* if(!n->picked_up) n->drag_offset = n->position - dragNode->position;*/ - /* n->picked_up = true;*/ - /* }*/ - /**/ - /* if(IsKeyDown(KEY_LEFT_CONTROL)) {*/ - /* dragNode->position.x = round((mouse_pos.x + dragNode->drag_offset.x) / state->settings.grid) * state->settings.grid;*/ - /* dragNode->position.y = round((mouse_pos.y + dragNode->drag_offset.y) / state->settings.grid) * state->settings.grid;*/ - /* } else if(IsKeyDown(KEY_LEFT_SHIFT)){*/ - /* float steps = round((dragNode->neighbors.front()->position.dist(mouse_pos)) / state->settings.grid) * state->settings.grid;*/ - /* if(dragNode->neighbors.size() > 1){*/ - /* Vec2Df dn1 = dragNode->neighbors[0]->position;*/ - /* Vec2Df dn2 = dragNode->neighbors[1]->position;*/ - /* Vec2Df v1_orth = dn1.center(dn2);*/ - /**/ - /* if(dn1.x < dn2.x) std::swap(dn1,dn2);*/ - /**/ - /* float dist = dn1.dist(dn2);*/ - /* float dist_orth = std::sqrt(std::pow(steps,2) - std::pow(dist/2,2));*/ - /**/ - /* if(mouse_pos.y < v1_orth.y) dist_orth *= -1;*/ - /**/ - /* Vec2Df v1_orth_t = v1_orth + (dn1-dn2).norm().orth() * dist_orth;*/ - /* DrawLineV(dn1, dn2, VS_COLOR_RED);*/ - /* DrawLineV(v1_orth, v1_orth_t, VS_COLOR_RED);*/ - /* DrawCircleV(v1_orth, 3.0f, VS_COLOR_RED);*/ - /* dragNode->position = v1_orth_t;*/ - /* } else if(!dragNode->neighbors.empty()){*/ - /* float pol_r = steps;*/ - /* float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - dragNode->neighbors.front()->position));*/ - /* Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); */ - /* dragNode->position = dragNode->neighbors.front()->position + polar;*/ - /* }*/ - /* } else {*/ - /* dragNode->position = mouse_pos + dragNode->drag_offset;*/ - /* }*/ - /**/ - /* for(auto &n : selected_nodes){*/ - /* n->position = dragNode->position + n->drag_offset;*/ - /* }*/ - /**/ - /* if(mouse_released) {*/ - /* for(auto &n : dragging_nodes){*/ - /* n->dragging = false;*/ - /* n->picked_up = false;*/ - /* }*/ - /* for(auto &n : selected_nodes){*/ - /* n->picked_up = false;*/ - /* n->dragging = false;*/ - /* }*/ - /* }*/ - /* }*/ - /* break;*/ - /* }*/ - /* case InteractionState::HOVER_CONNECTOR:*/ - /* {*/ - /* if(!hovering_connectors.empty()){*/ - /* hovering_connectors.front()->hover_connect = true;*/ - /* if(mouse_clicked) hovering_connectors.front()->connecting = true;*/ - /* }*/ - /* break;*/ - /* }*/ - /* case InteractionState::CONNECT_NODE:*/ - /* {*/ - /* Vec2Df connector_position = connecting_nodes.front()->position - ((connecting_nodes.front()->position - mouse_pos)).norm() * (connecting_nodes.front()->radius + 14.0f);*/ - /* Vec2Df target_position = mouse_pos;*/ - /**/ - /* if(IsKeyDown(KEY_LEFT_CONTROL)) {*/ - /* target_position.x = round((mouse_pos.x) / state->settings.grid) * state->settings.grid;*/ - /* target_position.y = round((mouse_pos.y) / state->settings.grid) * state->settings.grid;*/ - /* } else if(IsKeyDown(KEY_LEFT_SHIFT)){*/ - /* std::shared_ptr closest = app.gm.getClosestNode(mouse_pos);*/ - /* float steps = round((closest->position.dist(mouse_pos)) / state->settings.grid) * state->settings.grid;*/ - /* float pol_r = steps;*/ - /* float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - closest->position));*/ - /**/ - /* Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); */ - /* target_position = closest->position + polar;*/ - /* } else {*/ - /* target_position = mouse_pos;*/ - /* }*/ - /**/ - /* if(connecting_nodes.front()->connecting && mouse_down){*/ - /* DrawLine(connector_position.x, connector_position.y, target_position.x, target_position.y, (Color){229, 181, 103, 255});*/ - /* connecting_nodes.front()->hover_connect = true;*/ - /* }*/ - /**/ - /* if(!hovering_connectors.empty()) {*/ - /* hovering_connectors.front()->hover_connect = true;*/ - /* }*/ - /**/ - /* if(mouse_released) {*/ - /* if(&hovering_nodes.front() != &connecting_nodes.front() && &connecting_nodes.front() != &hovering_connectors.front()){*/ - /* if(!hovering_nodes.empty()){*/ - /* app.gm.addConnection(connecting_nodes.front(), hovering_nodes.front());*/ - /* } else if(!hovering_connectors.empty()){*/ - /* app.gm.addConnection(connecting_nodes.front(), hovering_connectors.front());*/ - /* } else {*/ - /* SPTR_Node new_node = app.gm.copyNode(std::dynamic_pointer_cast(connecting_nodes.front()), target_position);*/ - /* new_node->connecting = false;*/ - /* app.gm.addConnection(connecting_nodes.front(), new_node);*/ - /* }*/ - /* }*/ - /* connecting_nodes.front()->connecting = false;*/ - /* istate = InteractionState::HOVER_CANVAS;*/ - /* }*/ - /* break;*/ - /* }*/ - /* case InteractionState::DELETE_SELECTED_NODES:*/ - /* {*/ - /* app.removeNodes(selected_nodes | std::ranges::to());*/ - /* break;*/ - /* }*/ - /* case InteractionState::COPY_SELECTED_NODES:*/ - /* {*/ - /* std::ranges::copy(selected_nodes.begin(), selected_nodes.end(), std::back_inserter(copied_nodes));*/ - /* std::ranges::for_each(selected_nodes.begin(), selected_nodes.end(), [](SPTR_Node n){n->selected = false;});*/ - /* selected_nodes.clear();*/ - /* break;*/ - /* }*/ - /* case InteractionState::PASTE_SELECTED_NODES:*/ - /* {*/ - /* for(auto n: copied_nodes){*/ - /* n->drag_offset = (n->position - copied_nodes.front()->position);*/ - /* }*/ - /* app.copyNodesAndConnections(copied_nodes, mouse_pos);*/ - /* //copied_nodes.clear();*/ - /* break;*/ - /* }*/ /*};*/ } diff --git a/src/midi-node.h b/src/midi-node.h index 7f67a37..33da7cf 100644 --- a/src/midi-node.h +++ b/src/midi-node.h @@ -82,6 +82,10 @@ namespace VISEQ::GRAPH::NODES { int GGate(){ return midi_gate; } + void update() override { + Node::update(); + mode = state->node_mode; + } void interact(){ float wheel = GetMouseWheelMove(); diff --git a/src/signal-manager.h b/src/signal-manager.h index 7257c6b..d92d134 100644 --- a/src/signal-manager.h +++ b/src/signal-manager.h @@ -18,12 +18,16 @@ namespace VISEQ::SIGNAL { typedef std::shared_ptr SPTR_Signal; typedef std::vector VEC_SPTR_Signal; - class SignalManager{ + class SignalManager : public std::enable_shared_from_this{ public: SignalManager() {} SignalManager(GraphManager *gm, std::mutex *mutex) : mutex(mutex), gm(gm) {} + std::shared_ptr getPtr(){ + return shared_from_this(); + } + VISEQ::MIDI::Midi midi; std::mutex *mutex; diff --git a/src/state.h b/src/state.h index e38fb1a..14c38f1 100644 --- a/src/state.h +++ b/src/state.h @@ -78,6 +78,7 @@ namespace VISEQ::APP{ ModifierKeys keys_released; Rectangle selection; + Rectangle bounding_box; Vec2Df mouse_delta;