diff --git a/src/config-node.h b/src/config-node.h index f91760b..f6b5617 100644 --- a/src/config-node.h +++ b/src/config-node.h @@ -43,8 +43,8 @@ namespace VISEQ::GRAPH::NODES { gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){232, 125, 62, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); break;} } - if(!dragging && !selected && !in_rect && !hovering) DrawCircle(position.x, position.y, radius, gate_color); - if(selected || dragging || in_rect || hovering) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); + if(!picked_up && !selected && !in_rect && !hovering()) DrawCircle(position.x, position.y, radius, gate_color); + if(selected || picked_up || in_rect || hovering()) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); if(distributionMode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK); if(distributionMode == Distribution::ROUNDROBIN) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_YELLOW); diff --git a/src/connectable.h b/src/connectable.h new file mode 100644 index 0000000..8606e11 --- /dev/null +++ b/src/connectable.h @@ -0,0 +1,15 @@ +#pragma once + +namespace VISEQ::BASE { + class Connectable{ + public: + Connectable() {} + virtual ~Connectable() {} + + virtual void draw(){ + + + } + + }; +} diff --git a/src/connector.h b/src/connector.h new file mode 100644 index 0000000..9909300 --- /dev/null +++ b/src/connector.h @@ -0,0 +1,46 @@ +#pragma once + +#include "draggable.h" +#include "edge.h" +#include "vmath.h" +#include + +namespace VISEQ::GRAPH { + class Connector : public BASE::Draggable{ + public: + Connector() {} + Connector(float orbit) : orbit(orbit) {} + + std::shared_ptr partner; + + float radius = 5.0f; + float orbit = 14.0f; + + virtual bool hovering() override { + Vec2Df mp = {GetMousePosition().x, GetMousePosition().y}; + return CheckCollisionPointCircle(mp, position, radius); + } + + void updatePosition(Vec2Df pos){ + position = pos; + } + + void update() override{ + if(pickedUp()) drag(); + if(released()) putDown(); + } + + void draw() { + + Vec2Df connector = position - ((position - mouse)).norm() * (radius + orbit); + float opacity = 150.0f - Clamp(position.dist(mouse), 0.0f, 150.0f); + + if(hover_connect){ + DrawCircle(connector.x, connector.y, 8.0f, (Color){108, 153, 187, 255}); + } else { + DrawCircle(connector.x, connector.y, 8.0f, (Color){108, 153, 187, (unsigned char)opacity}); + } + + } + }; +} diff --git a/src/draggable.h b/src/draggable.h new file mode 100644 index 0000000..dd0dc28 --- /dev/null +++ b/src/draggable.h @@ -0,0 +1,37 @@ +#pragma once + +#include "interactable.h" +#include "moveable.h" +#include "vmath.h" + +namespace VISEQ::BASE { + class Draggable : public Movable, public Interactable{ + public: + Draggable() {} + Draggable(float x, float y) : Movable(Vec2Df(x, y), 960.0f) {} + Draggable(Vec2Df p) : Movable(p, 960.0f) {} + virtual ~Draggable() {} + + Vec2Df drag_offset; + + bool picked_up = false; + + virtual bool pickedUp() { + Vec2Df mp = {GetMousePosition().x, GetMousePosition().y}; + if(clicked() && held()) { + picked_up = true; + drag_offset = position - mp; + } + return picked_up; + } + + virtual void drag() { + Vec2Df mp = {GetMousePosition().x, GetMousePosition().y}; + position = mp + drag_offset; + } + + virtual void putDown(){ + picked_up = false; + } + }; +} diff --git a/src/graph-manager.h b/src/graph-manager.h index e52b10f..b7abb92 100644 --- a/src/graph-manager.h +++ b/src/graph-manager.h @@ -143,7 +143,7 @@ namespace VISEQ::GRAPH { } SPTR_Node getClosestNode(Vec2Df position){ - auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->dragging;}) | std::ranges::to(); + 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(); } @@ -236,7 +236,7 @@ namespace VISEQ::GRAPH { unsigned char opacity_from = 250.0f - Clamp(from_to_handle.dist(mouse_pos), 0.0f, 220.0f); unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f); - if(!c->start->dragging && !c->end->dragging){ + if(!c->start->picked_up && !c->end->picked_up){ // On/Off switches on both sides if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, c->pass_forward ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) c->pass_forward = !c->pass_forward; if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c->pass_backward ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c->pass_backward = !c->pass_backward; @@ -262,8 +262,9 @@ namespace VISEQ::GRAPH { void drawNodes(Vec2Df mouse_pos, Camera2D camera){ float min_d = 480; for(auto n : nodes){ - if(n->dragging){ - auto neighbors_local = nodes | RANGE_FILTER([mouse_pos](SPTR_Node n){ return !n->dragging && !n->selected && n->position.dist(mouse_pos) < 960;}) | std::ranges::to(); + n->update(); + if(n->picked_up){ + auto neighbors_local = nodes | RANGE_FILTER([mouse_pos](SPTR_Node n){ return !n->picked_up && !n->selected && n->position.dist(mouse_pos) < 960;}) | std::ranges::to(); std::sort(neighbors_local.begin(), neighbors_local.end(), [n, mouse_pos](SPTR_Node na, SPTR_Node nb){ return na->position.dist(mouse_pos) < nb->position.dist(mouse_pos);}); if(!neighbors_local.empty()){ min_d = neighbors_local.front()->position.dist(mouse_pos); diff --git a/src/interactable.h b/src/interactable.h index 3d64560..9ea3b50 100644 --- a/src/interactable.h +++ b/src/interactable.h @@ -1,5 +1,7 @@ #pragma once +#include "raylib.h" +#include "vmath.h" namespace VISEQ::BASE { class Interactable{ @@ -7,12 +9,19 @@ namespace VISEQ::BASE { Interactable() {} virtual ~Interactable() {} - virtual bool hovering(); + virtual bool hovering() = 0; + + virtual bool clicked() { + return hovering() && IsMouseButtonPressed(MOUSE_BUTTON_LEFT); + } - virtual bool clicked(); - virtual bool held(); - virtual bool pickedUp(); - virtual bool released(); + virtual bool held() { + return IsMouseButtonDown(MOUSE_BUTTON_LEFT); + } + + virtual bool released() { + return IsMouseButtonReleased(MOUSE_BUTTON_LEFT); + } }; } diff --git a/src/main.cpp b/src/main.cpp index f757ed2..fc36e20 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -193,360 +193,356 @@ int main(){ Vec2Df mouse_delta = {GetMouseDelta().x, GetMouseDelta().y}; Vec2Df delta = mouse_delta * (-1.0f/camera.zoom); - 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->dragging;}) | std::ranges::to(); - auto hovering_nodes = app.gm.nodes | RANGE_FILTER([&mouse_pos](SPTR_Node n) { return CheckCollisionPointCircle(mouse_pos, n->position, n->radius);}); - 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);}); + // 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)) {*/ + /* app.settings.mode = (app.settings.mode + 1) % 3;*/ + /* app.gm.setNodeMode(app.settings.mode);*/ + /*}*/ - for(auto &n : app.gm.nodes ){ - if(hovering_nodes.empty()) n->hovering = false; - if(hovering_connectors.empty()) n->hover_connect = false; - } + /*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;*/ + /* }*/ + /*}*/ - 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; + /*switch(istate){*/ + /* case InteractionState::SCALE_SELECTION:*/ + /* case InteractionState::HOVER_CANVAS:*/ + /* {*/ + /* for(auto &n : app.gm.nodes){ */ + /* n->hover_connect = false;*/ + /* }*/ + /* if(mouse_right_clicked){*/ + /* drag_distance = 0;*/ + /* }*/ + /* if(mouse_right_down) {*/ + /* camera.target = Vector2Add(camera.target, delta);*/ + /* drag_distance += delta.length();*/ + /* }*/ + /* if(mouse_right_released && drag_distance < 5) {*/ + /* node_menu_position = mouse_pos;*/ + /* istate = InteractionState::ADD_NODES_MENU;*/ + /* }*/ + /* break;*/ + /* }*/ + /* case InteractionState::ADD_NODES_MENU:*/ + /* {*/ + /* DrawCircleV(node_menu_position, 30, VS_COLOR_LIGHTGREY);*/ + /* 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) / app.settings.grid) * app.settings.grid;*/ + /* dragNode->position.y = round((mouse_pos.y + dragNode->drag_offset.y) / app.settings.grid) * app.settings.grid;*/ + /* } else if(IsKeyDown(KEY_LEFT_SHIFT)){*/ + /* float steps = round((dragNode->neighbors.front()->position.dist(mouse_pos)) / app.settings.grid) * app.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) / app.settings.grid) * app.settings.grid;*/ + /* target_position.y = round((mouse_pos.y) / app.settings.grid) * app.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)) / app.settings.grid) * app.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;*/ + /* }*/ + /*};*/ - 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)) { - app.settings.mode = (app.settings.mode + 1) % 3; - app.gm.setNodeMode(app.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: - case InteractionState::HOVER_CANVAS: - { - for(auto &n : app.gm.nodes){ - n->hover_connect = false; - } - if(mouse_right_clicked){ - drag_distance = 0; - } - if(mouse_right_down) { - camera.target = Vector2Add(camera.target, delta); - drag_distance += delta.length(); - } - if(mouse_right_released && drag_distance < 5) { - node_menu_position = mouse_pos; - istate = InteractionState::ADD_NODES_MENU; - } - break; - } - case InteractionState::ADD_NODES_MENU: - { - DrawCircleV(node_menu_position, 30, VS_COLOR_LIGHTGREY); - 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) / app.settings.grid) * app.settings.grid; - dragNode->position.y = round((mouse_pos.y + dragNode->drag_offset.y) / app.settings.grid) * app.settings.grid; - } else if(IsKeyDown(KEY_LEFT_SHIFT)){ - float steps = round((dragNode->neighbors.front()->position.dist(mouse_pos)) / app.settings.grid) * app.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) / app.settings.grid) * app.settings.grid; - target_position.y = round((mouse_pos.y) / app.settings.grid) * app.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)) / app.settings.grid) * app.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()->hovering = true; - connecting_nodes.front()->hover_connect = true; - } - - if(!hovering_connectors.empty()) { - hovering_connectors.front()->hovering = true; - hovering_connectors.front()->hover_connect = true; - } - if(!hovering_nodes.empty()) hovering_nodes.front()->hovering = 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; - } - }; - - float wheel = GetMouseWheelMove(); - if(wheel != 0){ - if(!hovering_nodes.empty() && hovering_nodes.front()->getNodeType() == NodeType::MIDINODE) { - VEC_SPTR_Node modify_nodes; - std::copy_if(selected_nodes.begin(), selected_nodes.end(), std::back_inserter(modify_nodes), [](SPTR_Node n){ return n->getNodeType() == NodeType::MIDINODE;}); - if(selected_nodes.empty()) std::copy_if(hovering_nodes.begin(), hovering_nodes.end(), std::back_inserter(modify_nodes), [modify_nodes](SPTR_Node n){ return n->getNodeType() == NodeType::MIDINODE && !std::ranges::contains(modify_nodes, n);}); - - for(auto n : modify_nodes){ - std::shared_ptr midiNode = std::dynamic_pointer_cast(n); - if(IsKeyDown(KEY_LEFT_CONTROL) && !IsKeyDown(KEY_LEFT_ALT)){ - switch(app.settings.mode){ - case 0:{ - midiNode->midi_note += wheel; - break;} - case 1:{ - midiNode->midi_cc += wheel; - break;} - case 2:{ - midiNode->midi_pitch_bend += wheel; - break;} - }; - if(midiNode->midi_note < 0 ) midiNode->midi_note = VISEQ::MIDI::Notes.size()-1; - if(midiNode->midi_note >= VISEQ::MIDI::Notes.size() ) midiNode->midi_note = 0; - - if(midiNode->midi_cc < 0 ) midiNode->midi_cc = 127; - if(midiNode->midi_cc > 127 ) midiNode->midi_cc = 0; - - if(midiNode->midi_pitch_bend < 0 ) midiNode->midi_pitch_bend = 0; - if(midiNode->midi_pitch_bend > 16383 ) midiNode->midi_pitch_bend = 16383; - - } else if(IsKeyDown(KEY_LEFT_SHIFT) && !IsKeyDown(KEY_LEFT_ALT)) { - midiNode->midi_velocity += wheel; - if(midiNode->midi_velocity < 0 ) midiNode->midi_velocity = 127; - if(midiNode->midi_velocity > 127 ) midiNode->midi_velocity = 0; - } else if(IsKeyDown(KEY_LEFT_ALT)) { - switch(app.settings.mode){ - case 0:{ - float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f); - midiNode->midi_gate += incr; - if(midiNode->midi_gate < 0 ) midiNode->midi_gate = 0; - break;} - case 1:{ - midiNode->midi_cc_value += wheel; - if(midiNode->midi_cc_value < 0 ) midiNode->midi_cc_value = 0; - if(midiNode->midi_cc_value > 127 ) midiNode->midi_cc_value = 127; - break;} - case 2:{ - float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f); - midiNode->midi_pitch_bend += incr; - if(midiNode->midi_pitch_bend < 0 ) midiNode->midi_pitch_bend = 0; - if(midiNode->midi_pitch_bend > 16383 ) midiNode->midi_pitch_bend = 16383; - break;} - }; - } - } - } - if(!IsKeyDown(KEY_LEFT_SHIFT) && !IsKeyDown(KEY_LEFT_CONTROL) && !IsKeyDown(KEY_LEFT_ALT)){ - Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera); - camera.offset = GetMousePosition(); - camera.target = mouseWorldPos; - float scaleFactor = 1.0f + (0.25f*fabsf(wheel)); - if (wheel < 0) scaleFactor = 1.0f/scaleFactor; - camera.zoom = Clamp(camera.zoom*scaleFactor, 0.125f, 64.0f); - } - } + /*float wheel = GetMouseWheelMove();*/ + /*if(wheel != 0){*/ + /* if(!hovering_nodes.empty() && hovering_nodes.front()->getNodeType() == NodeType::MIDINODE) {*/ + /* VEC_SPTR_Node modify_nodes;*/ + /* std::copy_if(selected_nodes.begin(), selected_nodes.end(), std::back_inserter(modify_nodes), [](SPTR_Node n){ return n->getNodeType() == NodeType::MIDINODE;});*/ + /* if(selected_nodes.empty()) std::copy_if(hovering_nodes.begin(), hovering_nodes.end(), std::back_inserter(modify_nodes), [modify_nodes](SPTR_Node n){ return n->getNodeType() == NodeType::MIDINODE && !std::ranges::contains(modify_nodes, n);});*/ + /**/ + /* for(auto n : modify_nodes){*/ + /* std::shared_ptr midiNode = std::dynamic_pointer_cast(n);*/ + /* if(IsKeyDown(KEY_LEFT_CONTROL) && !IsKeyDown(KEY_LEFT_ALT)){*/ + /* switch(app.settings.mode){*/ + /* case 0:{*/ + /* midiNode->midi_note += wheel;*/ + /* break;}*/ + /* case 1:{*/ + /* midiNode->midi_cc += wheel;*/ + /* break;}*/ + /* case 2:{*/ + /* midiNode->midi_pitch_bend += wheel;*/ + /* break;}*/ + /* };*/ + /* if(midiNode->midi_note < 0 ) midiNode->midi_note = VISEQ::MIDI::Notes.size()-1;*/ + /* if(midiNode->midi_note >= VISEQ::MIDI::Notes.size() ) midiNode->midi_note = 0;*/ + /**/ + /* if(midiNode->midi_cc < 0 ) midiNode->midi_cc = 127;*/ + /* if(midiNode->midi_cc > 127 ) midiNode->midi_cc = 0;*/ + /**/ + /* if(midiNode->midi_pitch_bend < 0 ) midiNode->midi_pitch_bend = 0;*/ + /* if(midiNode->midi_pitch_bend > 16383 ) midiNode->midi_pitch_bend = 16383;*/ + /**/ + /* } else if(IsKeyDown(KEY_LEFT_SHIFT) && !IsKeyDown(KEY_LEFT_ALT)) {*/ + /* midiNode->midi_velocity += wheel;*/ + /* if(midiNode->midi_velocity < 0 ) midiNode->midi_velocity = 127;*/ + /* if(midiNode->midi_velocity > 127 ) midiNode->midi_velocity = 0; */ + /* } else if(IsKeyDown(KEY_LEFT_ALT)) {*/ + /* switch(app.settings.mode){*/ + /* case 0:{*/ + /* float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f);*/ + /* midiNode->midi_gate += incr;*/ + /* if(midiNode->midi_gate < 0 ) midiNode->midi_gate = 0;*/ + /* break;}*/ + /* case 1:{*/ + /* midiNode->midi_cc_value += wheel;*/ + /* if(midiNode->midi_cc_value < 0 ) midiNode->midi_cc_value = 0;*/ + /* if(midiNode->midi_cc_value > 127 ) midiNode->midi_cc_value = 127;*/ + /* break;}*/ + /* case 2:{*/ + /* float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f);*/ + /* midiNode->midi_pitch_bend += incr;*/ + /* if(midiNode->midi_pitch_bend < 0 ) midiNode->midi_pitch_bend = 0;*/ + /* if(midiNode->midi_pitch_bend > 16383 ) midiNode->midi_pitch_bend = 16383;*/ + /* break;}*/ + /* };*/ + /* }*/ + /* }*/ + /* }*/ + /* if(!IsKeyDown(KEY_LEFT_SHIFT) && !IsKeyDown(KEY_LEFT_CONTROL) && !IsKeyDown(KEY_LEFT_ALT)){*/ + /* Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);*/ + /* camera.offset = GetMousePosition();*/ + /* camera.target = mouseWorldPos;*/ + /* float scaleFactor = 1.0f + (0.25f*fabsf(wheel));*/ + /* if (wheel < 0) scaleFactor = 1.0f/scaleFactor;*/ + /* camera.zoom = Clamp(camera.zoom*scaleFactor, 0.125f, 64.0f);*/ + /* }*/ + /*}*/ for(int x = -app.settings.grid*100; x < app.settings.grid*100; x+=app.settings.grid){ for(int y = -app.settings.grid*100; y < app.settings.grid*100; y+=app.settings.grid){ diff --git a/src/midi-node.h b/src/midi-node.h index 53d3175..438dee7 100644 --- a/src/midi-node.h +++ b/src/midi-node.h @@ -112,8 +112,8 @@ namespace VISEQ::GRAPH::NODES { gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){232, 125, 62, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); break;} } - if(!dragging && !selected && !in_rect && !hovering) DrawCircle(position.x, position.y, radius, gate_color); - if(selected || dragging || in_rect || hovering) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); + if(!picked_up && !selected && !in_rect && !hovering()) DrawCircle(position.x, position.y, radius, gate_color); + if(selected || picked_up || in_rect || hovering()) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); if(distributionMode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK); if(distributionMode == Distribution::ROUNDROBIN) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_YELLOW); diff --git a/src/moveable.h b/src/moveable.h index 7f5ed4a..04efb20 100644 --- a/src/moveable.h +++ b/src/moveable.h @@ -1,6 +1,6 @@ #pragma once -#include "datatypes.h" +#include "vmath.h" namespace VISEQ::BASE { class Movable{ @@ -16,15 +16,10 @@ namespace VISEQ::BASE { Vec2Df position; Vec2Df direction; - - Vec2Df drag_offset; bool in_rect = false; - bool picked_up = false; - bool dragging = false; bool hover_connect = false; - bool hovering = false; bool connecting = false; bool selected = false; bool highlighted = false; diff --git a/src/node.h b/src/node.h index d27511d..33e9a29 100644 --- a/src/node.h +++ b/src/node.h @@ -3,9 +3,11 @@ #include #include +#include "connector.h" #include "datatypes.h" +#include "draggable.h" #include "graph-item.h" -#include "moveable.h" +#include "vmath.h" namespace VISEQ::GRAPH::EDGES{ class Edge; @@ -13,29 +15,46 @@ namespace VISEQ::GRAPH::EDGES{ namespace VISEQ::GRAPH::NODES { - class Node : public BASE::Movable, public GraphItem{ + class Node : public BASE::Draggable, public GraphItem{ public: Node() {} - Node(float x, float y) : Movable(Vec2Df(x, y), 960.0f) {} - Node(Vec2Df p) : Movable(p, 960.0f) {} + Node(float x, float y) : Draggable(Vec2Df(x, y)) {} + Node(Vec2Df p) : Draggable(p) {} NodeType nodeType; std::vector> neighbors; std::vector> connections; + std::vector> connectors; + Distribution distributionMode = Distribution::GEOMETRIC; float radius = 15.0f; bool config = false; + virtual NodeType getNodeType() const {return nodeType;} virtual void SMode(int mode) {}; virtual int GGate() {return 0;}; virtual int GActive() {return 0;}; virtual void trigger() {}; + + virtual bool hovering() override { + Vec2Df mp = {GetMousePosition().x, GetMousePosition().y}; + return CheckCollisionPointCircle(mp, position, radius); + } + + void update() override{ + if(pickedUp()) drag(); + if(released()) putDown(); + for(auto c : connectors){ + c->update(position); + } + } + void draw(Vec2Df mouse_pos, Camera2D cam) override {} }; diff --git a/src/state-manager.h b/src/state-manager.h index 1e34dda..e83e203 100644 --- a/src/state-manager.h +++ b/src/state-manager.h @@ -127,7 +127,7 @@ namespace VISEQ::APP { } std::erase_if(gm.nodes, [nodes](SPTR_Node n){ return std::ranges::contains(nodes, n);}); } - + void draw(Vec2Df mouse_pos, Camera2D camera){ mutex.lock(); updateMidiPorts();