From cb08f69e3b4c1c2241bf7cdd5fef914a2c2067dd Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 26 Oct 2024 16:31:23 +0200 Subject: [PATCH] copy nodes with connections --- src/main.cpp | 111 +++++++++++++++++++++++++++----------------- src/node-manager.h | 24 ++++++++++ src/node.h | 1 + src/state-manager.h | 21 ++++++++- 4 files changed, 112 insertions(+), 45 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 253c2c4..44dfe93 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,35 +40,36 @@ bool mouse_clicked = false; bool mouse_touched = false; bool mouse_dragging = false; -//#include "ui.h" - int main(){ srand(time(NULL)); - InitWindow(2560, 1440, "VISEQ"); + + InitWindow(1920, 1080, "VISEQ"); + + int current_monitor = GetCurrentMonitor(); + int monitor_width = GetMonitorWidth(current_monitor); + int monitor_height = GetMonitorHeight(current_monitor); + SetWindowMonitor(current_monitor); + SetWindowState(FLAG_WINDOW_RESIZABLE); + + SetWindowSize(monitor_width - 300, monitor_height - 300); + + //ToggleFullscreen(); + app.ui.init(); - int monitor = 1; //GetCurrentMonitor(); - - SetWindowMonitor(monitor); - - app.settings.fps = 1.0f; + app.settings.fps = 60.0f; app.settings.bpm = 120.0f; - app.settings.grid = 120.0f; //round(((app.settings.fps / (app.settings.bpm / 60.0f)) * app.settings.speed) / 4.0f); // from quarter notes to 16th notes = div by 4 -// app.settings.speed = round((((app.settings.fps / (app.settings.bpm / 60.0f)) / app.settings.grid) / 4.0f) / 10.0f) * 10.0f; + app.settings.grid = 120.0f; // 120px for a 16th note - // 16th note = 120px (festgelegt) - // ganze note = 1920px - // ganze note bei 120bpm = 2s - // 120bpm = 960px/s app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f); - app.settings.width = GetMonitorWidth(monitor); - app.settings.height = GetMonitorHeight(monitor); + app.settings.width = monitor_width; + app.settings.height = monitor_height; - SetTargetFPS(60.0f); + SetTargetFPS(app.settings.fps); camera.target = (Vector2){ app.settings.width/2.0f, app.settings.height/2.0f }; camera.offset = (Vector2){ app.settings.width/2.0f, app.settings.height/2.0f }; @@ -86,24 +87,15 @@ int main(){ app.cm.addConnection(app.nm.nodes[i].id, app.nm.nodes[(i+1) % 8].id); } - app.sm.addSignalAtNode((app.nm.nodes | std::views::values).front().id); - + app.sm.addSignalAtNode((app.nm.nodes | std::views::values).front().id); app.sm.startSignalThread(); - Vec2D drag_offset; - - Vec2D cam_drag_offset; - Vec2D cam_mouse_drag_offset; - - double drag_timer = GetTime(); - - enum InteractionState {HOVER_CANVAS, HOVER_NODE, HOVER_CONNECTOR, DRAG_NODE, CONNECT_NODE, DRAW_SELECTION, DELETE_SELECTED_NODES}; + enum InteractionState {HOVER_CANVAS, HOVER_NODE, HOVER_CONNECTOR, DRAG_NODE, CONNECT_NODE, DRAW_SELECTION, DELETE_SELECTED_NODES, COPY_SELECTED_NODES, PASTE_SELECTED_NODES}; InteractionState istate = HOVER_CANVAS; Vec2D select_start; Rectangle selection; - ToggleFullscreen(); while(!WindowShouldClose()){ @@ -129,6 +121,7 @@ int main(){ Vec2D delta = mouse_delta * (-1.0f/camera.zoom); auto dragging_nodes = app.nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n) { return n.dragging;}); + auto copied_nodes = app.nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n) { return n.copied;}); auto connecting_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.connecting;}); auto selected_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.selected && !n.dragging;}); auto hovering_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, n.position, n.radius);}); @@ -143,6 +136,9 @@ int main(){ 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; switch(istate){ case InteractionState::HOVER_CANVAS: @@ -200,22 +196,31 @@ int main(){ } case InteractionState::DRAG_NODE: { - if(IsKeyDown(KEY_LEFT_CONTROL)) { - dragging_nodes.front().position = (Vec2D){round((mouse_pos.x+dragging_nodes.front().drag_offset.x)/app.settings.grid)*app.settings.grid, round((mouse_pos.y+dragging_nodes.front().drag_offset.y)/app.settings.grid)*app.settings.grid}; - } else { - dragging_nodes.front().position = mouse_pos + dragging_nodes.front().drag_offset; - } - - for(auto &n : selected_nodes){ - if(!n.picked_up) n.drag_offset = n.position - dragging_nodes.front().position; - n.picked_up = true; - n.position = dragging_nodes.front().position + n.drag_offset; - } - - if(mouse_released) { - dragging_nodes.front().dragging = false; + if(!dragging_nodes.empty()){ for(auto &n : selected_nodes){ - n.picked_up = false; + if(!n.picked_up) n.drag_offset = n.position - dragging_nodes.front().position; + n.picked_up = true; + } + + if(IsKeyDown(KEY_LEFT_CONTROL)) { + dragging_nodes.front().position = (Vec2D){round((mouse_pos.x+dragging_nodes.front().drag_offset.x)/app.settings.grid)*app.settings.grid, round((mouse_pos.y+dragging_nodes.front().drag_offset.y)/app.settings.grid)*app.settings.grid}; + } else { + dragging_nodes.front().position = mouse_pos + dragging_nodes.front().drag_offset; + } + + for(auto &n : selected_nodes){ + n.position = dragging_nodes.front().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; @@ -257,6 +262,26 @@ int main(){ app.removeNodes(); break; } + case InteractionState::COPY_SELECTED_NODES: + { + for(auto &n: copied_nodes){ + n.copied = false; + } + for(auto &n: selected_nodes){ + n.copied = true; + n.selected = false; + } + break; + } + case InteractionState::PASTE_SELECTED_NODES: + { + for(auto &n: copied_nodes){ + n.drag_offset = (n.position - copied_nodes.front().position); + } +// app.nm.copyNodes(mouse_pos); + app.copyNodesAndConnections(mouse_pos); + break; + } }; float wheel = GetMouseWheelMove(); diff --git a/src/node-manager.h b/src/node-manager.h index e76ee84..6f15282 100644 --- a/src/node-manager.h +++ b/src/node-manager.h @@ -1,9 +1,11 @@ #pragma once #include "node.h" +#include #include #include #include +#include #include class NodeManager{ @@ -21,6 +23,28 @@ class NodeManager{ return o.front(); } + void copyNodes(Vec2D position){ + for(auto n: nodes | std::ranges::views::filter([](std::pair n){ return n.second.copied;})){ + n.second.position = position + n.second.drag_offset; + n.second.id = iterator; + n.second.copied = false; + n.second.selected = true; + nodes.insert(std::make_pair(iterator, n.second)); + keys.push_back(iterator); + iterator++; + } + } + + int copyNode(int id, Vec2D position){ + Node n = nodes.at(id); + n.position = position; + n.id = iterator; + nodes.insert(std::make_pair(iterator, n)); + keys.push_back(iterator); + iterator++; + return iterator - 1; + } + int addNode(float x, float y){ return addNode(Vec2D(x,y)); } diff --git a/src/node.h b/src/node.h index 20d13f5..8adeb68 100644 --- a/src/node.h +++ b/src/node.h @@ -36,6 +36,7 @@ class Node : public Movable{ bool selected = false; bool erase = false; bool highlighted = false; + bool copied = false; int midi_out = -1; diff --git a/src/state-manager.h b/src/state-manager.h index 082d637..3be0f81 100644 --- a/src/state-manager.h +++ b/src/state-manager.h @@ -44,6 +44,25 @@ class AppState{ } } + void copyNodesAndConnections(Vec2D position){ + auto copy_nodes_ids = nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.copied;}) | std::views::transform([](Node n){return n.id;}) | std::ranges::to>(); + + std::vector copy_connections; + std::ranges::copy_if(cm.connections, std::back_inserter(copy_connections), [copy_nodes_ids](Connection c){return std::ranges::contains(copy_nodes_ids, c.v1) && std::ranges::contains(copy_nodes_ids, c.v2);}); + + for(auto &n : copy_nodes_ids){ + int old_id = n; + int new_id = nm.copyNode(n, position + nm.nodes[n].drag_offset); + + for(auto &c : copy_connections){ + if(c.v1 == old_id) c.v1 = new_id; + if(c.v2 == old_id) c.v2 = new_id; + } + } + + cm.connections.insert(cm.connections.end(), copy_connections.cbegin(), copy_connections.cend()); + } + void removeNodes(){ for(auto &n : nm.nodes){ @@ -66,8 +85,6 @@ class AppState{ if(!nm.nodes.at(c.v2).selected) adjacent_nodes_ids.push_back(c.v2); } -// std::ranges::for_each(adjacent_nodes_ids, [this](int id){ nm.nodes.at(id).highlighted = true;} ); - auto reroute_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){ return std::ranges::contains(erase_nodes_ids, s.next); });