heavy restructuring with smart pointers, not finished
This commit is contained in:
+12
-14
@@ -1,9 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "connection.h"
|
#include "edge.h"
|
||||||
#include "node-manager.h"
|
#include "node-manager.h"
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
#include "raymath.h"
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -28,19 +27,12 @@ class ConnectionManager{
|
|||||||
std::vector<int> next_node_ids;
|
std::vector<int> next_node_ids;
|
||||||
|
|
||||||
for(auto& c : connections){
|
for(auto& c : connections){
|
||||||
if((c.v1 == current && c.v1_v2) || (c.v2 == current && c.v2_v1)) {
|
if((c.node_id_start == current && c.start_end) || (c.node_id_end == current && c.end_start)) {
|
||||||
c.active = false;
|
c.active = false;
|
||||||
possible_connections.push_back(&c);
|
possible_connections.push_back(&c);
|
||||||
next_node_ids.push_back( c.v1 == current ? c.v2 : c.v1 );
|
next_node_ids.push_back( c.node_id_start == current ? c.node_id_end : c.node_id_start );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if(possible_connections.size() == 2) {*/
|
|
||||||
/* int next = next_node_ids[0] == last ? next_node_ids[1] : next_node_ids[0];*/
|
|
||||||
/* if(possible_connections[0]->v1 == next || possible_connections[0]->v2 == next) possible_connections[0]->active = true;*/
|
|
||||||
/* if(possible_connections[1]->v1 == next || possible_connections[1]->v2 == next) possible_connections[1]->active = true;*/
|
|
||||||
/* return next;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
if(possible_connections.empty()) return -1;
|
if(possible_connections.empty()) return -1;
|
||||||
|
|
||||||
@@ -50,7 +42,7 @@ class ConnectionManager{
|
|||||||
Vec2D<float> coming_from = (nm->nodes.at(current).position - nm->nodes.at(last).position).norm();
|
Vec2D<float> coming_from = (nm->nodes.at(current).position - nm->nodes.at(last).position).norm();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(auto n : possible_connections){
|
for(auto n : possible_connections){
|
||||||
int next_position = n->v1 == current ? n->v2 : n->v1;
|
int next_position = n->node_id_start == current ? n->node_id_end : n->node_id_start;
|
||||||
float angle_v1_v2 = coming_from.norm().dot((nm->nodes.at(next_position).position - nm->nodes.at(current).position).norm());
|
float angle_v1_v2 = coming_from.norm().dot((nm->nodes.at(next_position).position - nm->nodes.at(current).position).norm());
|
||||||
if(angle_v1_v2 > angle) {
|
if(angle_v1_v2 > angle) {
|
||||||
return_path = i;
|
return_path = i;
|
||||||
@@ -74,16 +66,22 @@ class ConnectionManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
possible_connections.at(return_path)->active = true;
|
possible_connections.at(return_path)->active = true;
|
||||||
return possible_connections.at(return_path)->v1 == current ? possible_connections.at(return_path)->v2 : possible_connections.at(return_path)->v1;
|
return possible_connections.at(return_path)->node_id_start == current ? possible_connections.at(return_path)->node_id_end : possible_connections.at(return_path)->node_id_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addConnection(int from, int to){
|
void addConnection(int from, int to){
|
||||||
connections.emplace_back(&nm->nodes, from, to);
|
connections.emplace_back(nm, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void splitConnection(Connection *c){
|
||||||
|
Vec2D<float> center = c->node_start->position.center(c->node_end->position);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
||||||
std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
||||||
for(auto& c : connections){
|
for(auto& c : connections){
|
||||||
|
if(c.split) splitConnection(&c);
|
||||||
c.draw(mouse_pos, cam);
|
c.draw(mouse_pos, cam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "button.h"
|
|
||||||
#include "datatypes.h"
|
|
||||||
#include "graph-item.h"
|
|
||||||
#include "node.h"
|
|
||||||
#include "raylib.h"
|
|
||||||
|
|
||||||
class Connection : public GraphItem{
|
|
||||||
|
|
||||||
public:
|
|
||||||
Connection(std::map<int, Node> *nodes, int v1, int v2) : v1(v1), v2(v2), nodes(nodes) {}
|
|
||||||
|
|
||||||
int v1;
|
|
||||||
int v2;
|
|
||||||
|
|
||||||
std::map<int, Node> *nodes;
|
|
||||||
|
|
||||||
bool v1_v2 = true;
|
|
||||||
bool v2_v1 = true;
|
|
||||||
bool active = false;
|
|
||||||
bool remove = false;
|
|
||||||
bool config = false;
|
|
||||||
|
|
||||||
float connector_offset = 8.0f;
|
|
||||||
float switches_offset = 25.0f;
|
|
||||||
|
|
||||||
void flip(){
|
|
||||||
int vt = v1;
|
|
||||||
v1 = v2;
|
|
||||||
v2 = vt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(Vec2D<float> *mouse_pos, Camera2D *cam){
|
|
||||||
Vec2D<float> v1_position = nodes->at(v1).position - ((nodes->at(v1).position - nodes->at(v2).position)).norm() * (nodes->at(v1).radius + connector_offset);
|
|
||||||
Vec2D<float> v2_position = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position)).norm() * (nodes->at(v2).radius + connector_offset);
|
|
||||||
float v1_v2_distance = v1_position.dist(&v2_position);
|
|
||||||
|
|
||||||
float midi_gate_v1 = Clamp((4.f / 1000.f) * nodes->at(v1).midi_gate, 1.f, 4.f);
|
|
||||||
float midi_gate_v2 = Clamp((4.f / 1000.f) * nodes->at(v2).midi_gate, 1.f, 4.f);
|
|
||||||
// Line with small connector circles
|
|
||||||
|
|
||||||
Color c = {229, 181, 103, 255};
|
|
||||||
if(active) c = {108, 153, 187, 255};
|
|
||||||
DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, c);
|
|
||||||
|
|
||||||
if(midi_gate_v1 == 4.0f) c = VS_COLOR_RED;
|
|
||||||
DrawCircle(v1_position.x, v1_position.y, midi_gate_v1, c);
|
|
||||||
|
|
||||||
c = {229, 181, 103, 255};
|
|
||||||
if(midi_gate_v2 == 4.0f) c = VS_COLOR_RED;
|
|
||||||
DrawCircle(v2_position.x, v2_position.y, midi_gate_v2, c);
|
|
||||||
|
|
||||||
if(v1_v2_distance < 100) switches_offset = v1_v2_distance/2.3f;
|
|
||||||
Vec2D<float> from_to_handle = nodes->at(v1).position - ((nodes->at(v1).position - nodes->at(v2).position)).norm() * (nodes->at(v1).radius + switches_offset);
|
|
||||||
Vec2D<float> to_from_handle = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position)).norm() * (nodes->at(v2).radius + switches_offset);
|
|
||||||
Vec2D<float> middle_handle = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position))*0.5f;
|
|
||||||
// Vec2D<float> config_handle = nodes.at(v2)->position - ((nodes.at(v2)->position - nodes.at(v1)->position))*0.66f;
|
|
||||||
Vec2D<float> flip_handle = middle_handle + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*0.2, 0.f, 20.f) : 1.0f);
|
|
||||||
|
|
||||||
|
|
||||||
// Dynamic opacity by distance to mouse
|
|
||||||
unsigned char opacity = 150.0f - Clamp(middle_handle.dist(mouse_pos), 0.0f, 150.0f);
|
|
||||||
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);
|
|
||||||
|
|
||||||
// On/Off switches on both sides
|
|
||||||
if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, v1_v2 ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) v1_v2 = !v1_v2;
|
|
||||||
if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, v2_v1 ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) v2_v1 = !v2_v1;
|
|
||||||
|
|
||||||
if(!v1_v2){
|
|
||||||
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle;
|
|
||||||
Vec2D<float> block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + from_to_handle;
|
|
||||||
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_from});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!v2_v1){
|
|
||||||
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle;
|
|
||||||
Vec2D<float> block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + to_from_handle;
|
|
||||||
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_to});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(ViButton(mouse_pos, flip_handle.x, flip_handle.y, 8.0f, (Color){232, 50, 32, opacity} )) remove = true;
|
|
||||||
//if(ViButton(mouse_pos, config_handle.x, config_handle.y, 8.0f, (Color){158, 134, 200, opacity})) config = !config;
|
|
||||||
//if(ViButton(mouse_pos, config_handle.x + flip_handle.x, config_handle.y + flip_handle.y, 8.0f, (Color){158, 0, 200, opacity})) flip();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
+10
-7
@@ -75,7 +75,10 @@ class Vec2D{
|
|||||||
};
|
};
|
||||||
|
|
||||||
Vec2D norm() { return *this / length();};
|
Vec2D norm() { return *this / length();};
|
||||||
|
|
||||||
|
Vec2D center(Vec2D v){
|
||||||
|
return Vec2D<T>{x,y} + (Vec2D<T>{x,y} - v)*0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
Vec2D& operator=(const Vec2D& vec){
|
Vec2D& operator=(const Vec2D& vec){
|
||||||
if (this == &vec){
|
if (this == &vec){
|
||||||
@@ -125,32 +128,32 @@ class Vec2D{
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vec2D<T> operator+(const Vec2D<T>& left, const Vec2D<T>& right){
|
Vec2D<T> operator+(const Vec2D<T> left, const Vec2D<T> right){
|
||||||
return Vec2D<T>(left.x + right.x, left.y + right.y);
|
return Vec2D<T>(left.x + right.x, left.y + right.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vec2D<T> operator-(const Vec2D<T>& left, const Vec2D<T>& right){
|
Vec2D<T> operator-(const Vec2D<T> left, const Vec2D<T> right){
|
||||||
return Vec2D<T>(left.x - right.x, left.y - right.y);
|
return Vec2D<T>(left.x - right.x, left.y - right.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vec2D<T> operator*(const Vec2D<T>& left, const Vec2D<T>& right){
|
Vec2D<T> operator*(const Vec2D<T> left, const Vec2D<T> right){
|
||||||
return Vec2D<T>(left.x * right.x, left.y * right.y);
|
return Vec2D<T>(left.x * right.x, left.y * right.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vec2D<T> operator/(const Vec2D<T>& left, const Vec2D<T>& right){
|
Vec2D<T> operator/(const Vec2D<T> left, const Vec2D<T> right){
|
||||||
return Vec2D<T>(left.x / right.x, left.y / right.y);
|
return Vec2D<T>(left.x / right.x, left.y / right.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vec2D<T> operator/(const Vec2D<T>& left, T scalar){
|
Vec2D<T> operator/(const Vec2D<T> left, T scalar){
|
||||||
return Vec2D<T>(left.x / scalar, left.y / scalar);
|
return Vec2D<T>(left.x / scalar, left.y / scalar);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vec2D<T> operator*(const Vec2D<T>& left, T scalar){
|
Vec2D<T> operator*(const Vec2D<T> left, T scalar){
|
||||||
return Vec2D<T>(left.x * scalar, left.y * scalar);
|
return Vec2D<T>(left.x * scalar, left.y * scalar);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "graph-item.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Node;
|
||||||
|
|
||||||
|
class Edge : public GraphItem{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Edge(std::shared_ptr<Node> start, std::shared_ptr<Node> end) : start(start), end(end) {}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> start;
|
||||||
|
std::shared_ptr<Node> end;
|
||||||
|
|
||||||
|
bool pass_forward = true;
|
||||||
|
bool pass_backward = true;
|
||||||
|
|
||||||
|
bool active = false;
|
||||||
|
bool remove = false;
|
||||||
|
bool config = false;
|
||||||
|
bool split = false;
|
||||||
|
|
||||||
|
float connector_offset = 8.0f;
|
||||||
|
float switches_offset = 25.0f;
|
||||||
|
|
||||||
|
std::shared_ptr<Node> getNextNode(std::shared_ptr<Node> origin){
|
||||||
|
return start == origin ? end : start;
|
||||||
|
}
|
||||||
|
};
|
||||||
+6
-4
@@ -1,13 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "raylib.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class GraphItem{
|
class GraphItem{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int id;
|
std::vector<std::shared_ptr<GraphItem>> neighbors;
|
||||||
GraphItemType type;
|
|
||||||
std::vector<int> connections;
|
virtual void draw(Vec2D<float> mouse, Camera2D cam) = 0;
|
||||||
|
virtual ~GraphItem() = default;
|
||||||
};
|
};
|
||||||
|
|||||||
+107
-67
@@ -1,11 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
#include "graph-item.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "connection.h"
|
#include "edge.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class GraphManager{
|
class GraphManager{
|
||||||
|
|
||||||
@@ -13,89 +18,72 @@ class GraphManager{
|
|||||||
|
|
||||||
GraphManager() {}
|
GraphManager() {}
|
||||||
|
|
||||||
std::map<int, Node> nodes;
|
std::vector<std::shared_ptr<Node>> nodes;
|
||||||
std::vector<Connection> connections;
|
std::vector<std::shared_ptr<Edge>> edges;
|
||||||
|
|
||||||
|
std::map<std::shared_ptr<Node>, int> counter;
|
||||||
|
|
||||||
|
std::shared_ptr<Node> getRandomNode(){
|
||||||
|
std::vector<std::shared_ptr<GraphItem>> o;
|
||||||
|
std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
||||||
|
return std::dynamic_pointer_cast<Node>(o.front());
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> keys;
|
std::shared_ptr<Edge> getRandomEdge(){
|
||||||
int iterator = 0;
|
std::vector<std::shared_ptr<GraphItem>> o;
|
||||||
|
std::ranges::sample(edges, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
||||||
std::map<int, int> counter;
|
return std::dynamic_pointer_cast<Edge>(o.front());
|
||||||
|
|
||||||
int getRandomNode(){
|
|
||||||
std::vector<int> o;
|
|
||||||
std::ranges::sample(keys, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
|
||||||
return o.front();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyNodes(Vec2D<float> position){
|
void copyNodes(std::vector<std::shared_ptr<Node>> nodes, Vec2D<float> position){
|
||||||
for(auto n: nodes | std::ranges::views::filter([](std::pair<int, Node> n){ return n.second.copied;})){
|
for(auto n: nodes){
|
||||||
n.second.position = position + n.second.drag_offset;
|
auto nc = std::make_shared<Node>(n);
|
||||||
n.second.id = iterator;
|
nc->position = position + nc->drag_offset;
|
||||||
n.second.copied = false;
|
nc->selected = true;
|
||||||
n.second.selected = true;
|
nodes.push_back(nc);
|
||||||
nodes.insert(std::make_pair(iterator, n.second));
|
|
||||||
keys.push_back(iterator);
|
|
||||||
iterator++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int copyNode(int id, Vec2D<float> position){
|
void copyNode(std::shared_ptr<Node> n, Vec2D<float> position){
|
||||||
Node n = nodes.at(id);
|
auto nc = std::make_shared<Node>(n);
|
||||||
n.position = position;
|
nc->setPosition(position);
|
||||||
n.id = iterator;
|
nodes.push_back(nc);
|
||||||
nodes.insert(std::make_pair(iterator, n));
|
|
||||||
keys.push_back(iterator);
|
|
||||||
iterator++;
|
|
||||||
return iterator - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setNodeMode(int mode){
|
std::shared_ptr<Node> addNode(float x, float y){
|
||||||
for(auto &n : nodes | std::ranges::views::values){
|
|
||||||
n.mode = mode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int addNode(float x, float y){
|
|
||||||
return addNode(Vec2D<float>(x,y));
|
return addNode(Vec2D<float>(x,y));
|
||||||
}
|
}
|
||||||
|
|
||||||
int addNode(Vec2D<float> position){
|
std::shared_ptr<Node> addNode(Vec2D<float> position){
|
||||||
nodes.emplace(std::make_pair(iterator, Node(iterator, position, 15.0f)));
|
nodes.emplace_back(std::make_shared<Node>(position));
|
||||||
keys.push_back(iterator);
|
return nodes.back();
|
||||||
iterator++;
|
|
||||||
return iterator - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void triggerNode(int node){
|
void setNodeMode(int mode){
|
||||||
nodes.at(node).trigger();
|
for(auto n: nodes){
|
||||||
|
n->setMode(mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset(){
|
void reset(){
|
||||||
counter.clear();
|
counter.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int next(int current, int last){
|
std::shared_ptr<Node> next(std::shared_ptr<Node> current, std::shared_ptr<Node> last){
|
||||||
std::vector<Connection*> possible_connections;
|
std::vector<std::shared_ptr<Edge>> possible_connections = current->connections | std::ranges::views::filter([current](std::shared_ptr<Edge> c){
|
||||||
std::vector<int> next_node_ids;
|
return (c->start == current && c->pass_forward) || (c->end == current && c->pass_backward);
|
||||||
|
}) | std::ranges::to<std::vector<std::shared_ptr<Edge>>>();
|
||||||
|
|
||||||
for(auto& c : connections){
|
if(possible_connections.empty()) return std::shared_ptr<Node>(nullptr);
|
||||||
if((c.v1 == current && c.v1_v2) || (c.v2 == current && c.v2_v1)) {
|
|
||||||
c.active = false;
|
|
||||||
possible_connections.push_back(&c);
|
|
||||||
next_node_ids.push_back( c.v1 == current ? c.v2 : c.v1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(possible_connections.empty()) return -1;
|
|
||||||
|
|
||||||
int return_path = 0;
|
int return_path = 0;
|
||||||
float angle = -1;
|
float angle = -1;
|
||||||
if(nodes.at(current).distributionMode == Distribution::GEOMETRIC){
|
if(current->distributionMode == Distribution::GEOMETRIC){
|
||||||
Vec2D<float> coming_from = (nodes.at(current).position - nodes.at(last).position).norm();
|
Vec2D<float> coming_from = (current->position - last->position).norm();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(auto n : possible_connections){
|
for(auto n : possible_connections){
|
||||||
int next_position = n->v1 == current ? n->v2 : n->v1;
|
std::shared_ptr<Node> next_node = n->getNextNode(current);
|
||||||
float angle_v1_v2 = coming_from.norm().dot((nodes.at(next_position).position - nodes.at(current).position).norm());
|
float angle_v1_v2 = coming_from.norm().dot((next_node->position - current->position).norm());
|
||||||
if(angle_v1_v2 > angle) {
|
if(angle_v1_v2 > angle) {
|
||||||
return_path = i;
|
return_path = i;
|
||||||
angle = angle_v1_v2;
|
angle = angle_v1_v2;
|
||||||
@@ -104,7 +92,7 @@ class GraphManager{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nodes.at(current).distributionMode == Distribution::ROUNDROBIN){
|
if(current->distributionMode == Distribution::ROUNDROBIN){
|
||||||
if(counter.find(current) == counter.end()) {
|
if(counter.find(current) == counter.end()) {
|
||||||
counter[current] = 0;
|
counter[current] = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -113,24 +101,76 @@ class GraphManager{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nodes.at(current).distributionMode == Distribution::RANDOM){
|
if(current->distributionMode == Distribution::RANDOM){
|
||||||
return_path = rand() % possible_connections.size();
|
return_path = rand() % possible_connections.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
possible_connections.at(return_path)->active = true;
|
possible_connections.at(return_path)->active = true;
|
||||||
return possible_connections.at(return_path)->v1 == current ? possible_connections.at(return_path)->v2 : possible_connections.at(return_path)->v1;
|
return possible_connections.at(return_path)->getNextNode(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addConnection(int from, int to){
|
void addConnection(std::shared_ptr<Node> from, std::shared_ptr<Node> to){
|
||||||
connections.emplace_back(&nodes, from, to);
|
edges.emplace_back(std::make_shared<Edge>(from, to));
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
||||||
std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
// std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
||||||
for(auto& c : connections){
|
for(auto& c : edges){
|
||||||
c.draw(mouse_pos, cam);
|
Vec2D<float> v1_position = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->connector_offset);
|
||||||
|
Vec2D<float> v2_position = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->connector_offset);
|
||||||
|
float v1_v2_distance = v1_position.dist(&v2_position);
|
||||||
|
|
||||||
|
float midi_gate_v1 = Clamp((4.f / 1000.f) * c->start->midi_gate, 1.f, 4.f);
|
||||||
|
float midi_gate_v2 = Clamp((4.f / 1000.f) * c->end->midi_gate, 1.f, 4.f);
|
||||||
|
// Line with small connector circles
|
||||||
|
|
||||||
|
Color col = {229, 181, 103, 255};
|
||||||
|
if(c.active) col = {108, 153, 187, 255};
|
||||||
|
DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, col);
|
||||||
|
|
||||||
|
if(midi_gate_v1 == 4.0f) col = VS_COLOR_RED;
|
||||||
|
DrawCircle(v1_position.x, v1_position.y, midi_gate_v1, col);
|
||||||
|
|
||||||
|
col = {229, 181, 103, 255};
|
||||||
|
if(midi_gate_v2 == 4.0f) col = VS_COLOR_RED;
|
||||||
|
DrawCircle(v2_position.x, v2_position.y, midi_gate_v2, col);
|
||||||
|
|
||||||
|
if(v1_v2_distance < 100) c.switches_offset = v1_v2_distance/2.3f;
|
||||||
|
Vec2D<float> from_to_handle = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c.switches_offset);
|
||||||
|
Vec2D<float> to_from_handle = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c.switches_offset);
|
||||||
|
Vec2D<float> middle_handle = c->end->position - ((c->end->position - c->start->position))*0.4f;
|
||||||
|
Vec2D<float> middle_handle_2 = c->end->position - ((c->end->position - c->start->position))*0.6f;
|
||||||
|
Vec2D<float> flip_handle = middle_handle + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*0.2, 0.f, 20.f) : 1.0f);
|
||||||
|
Vec2D<float> flip_handle_2 = middle_handle_2 + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*-0.2, -20.f, 0.f) : 1.0f);
|
||||||
|
|
||||||
|
|
||||||
|
// Dynamic opacity by distance to mouse
|
||||||
|
unsigned char opacity = 150.0f - Clamp(middle_handle.dist(mouse_pos), 0.0f, 150.0f);
|
||||||
|
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);
|
||||||
|
|
||||||
|
// On/Off switches on both sides
|
||||||
|
if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, c->start_end ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) c->start_end = !c->start_end;
|
||||||
|
if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c.end_start ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c.end_start = !c.end_start;
|
||||||
|
|
||||||
|
if(!c->start_end){
|
||||||
|
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle;
|
||||||
|
Vec2D<float> block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + from_to_handle;
|
||||||
|
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_from});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!c.end_start){
|
||||||
|
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle;
|
||||||
|
Vec2D<float> block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + to_from_handle;
|
||||||
|
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_to});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(ViButton(mouse_pos, flip_handle.x, flip_handle.y, 8.0f, (Color){232, 50, 32, opacity} )) c.remove = true;
|
||||||
|
if(ViButton(mouse_pos, flip_handle_2.x, flip_handle_2.y, 8.0f, (Color){232, 50, 32, opacity} )) c.split = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawNodes(Vec2D<float> *mouse_pos, Camera2D *camera){
|
void drawNodes(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||||
auto neighbors = nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){ return !n.dragging && !n.selected;}) | std::ranges::to<std::vector<Node>>();
|
auto neighbors = nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){ return !n.dragging && !n.selected;}) | std::ranges::to<std::vector<Node>>();
|
||||||
float min_d = 480;
|
float min_d = 480;
|
||||||
|
|||||||
+25
-27
@@ -6,6 +6,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#define RAYGUI_IMPLEMENTATION
|
#define RAYGUI_IMPLEMENTATION
|
||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
@@ -67,17 +68,17 @@ int main(){
|
|||||||
camera.zoom = 1.0f;
|
camera.zoom = 1.0f;
|
||||||
|
|
||||||
for(int i = 0; i < 4; ++i){
|
for(int i = 0; i < 4; ++i){
|
||||||
app.nm.addNode((float)i * app.settings.grid*4 + 10 * app.settings.grid, 5 * app.settings.grid*4);
|
app.gm.addNode((float)i * app.settings.grid*4 + 10 * app.settings.grid, 5 * app.settings.grid*4);
|
||||||
}
|
}
|
||||||
for(int i = 3; i >= 0; --i){
|
for(int i = 3; i >= 0; --i){
|
||||||
app.nm.addNode((float)i * app.settings.grid*4 + 10 * app.settings.grid, 6 * app.settings.grid*4);
|
app.gm.addNode((float)i * app.settings.grid*4 + 10 * app.settings.grid, 6 * app.settings.grid*4);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < 8; ++i){
|
for(int i = 0; i < 8; ++i){
|
||||||
app.cm.addConnection(app.nm.nodes[i].id, app.nm.nodes[(i+1) % 8].id);
|
app.gm.addConnection(app.gm.nodes[i].id, app.gm.nodes[(i+1) % 8].id);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.sm.addSignalAtNode((app.nm.nodes | std::views::values).front().id);
|
app.sm.addSignalAtNode((app.gm.nodes | std::views::values).front().id);
|
||||||
app.sm.startSignalThread();
|
app.sm.startSignalThread();
|
||||||
|
|
||||||
enum InteractionState {HOVER_CANVAS, HOVER_NODE, HOVER_CONNECTOR, DRAG_NODE, CONNECT_NODE, DRAW_SELECTION, DELETE_SELECTED_NODES, COPY_SELECTED_NODES, PASTE_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};
|
||||||
@@ -109,15 +110,16 @@ int main(){
|
|||||||
|
|
||||||
Vec2D<float> mouse_delta = {GetMouseDelta().x, GetMouseDelta().y};
|
Vec2D<float> mouse_delta = {GetMouseDelta().x, GetMouseDelta().y};
|
||||||
Vec2D<float> delta = mouse_delta * (-1.0f/camera.zoom);
|
Vec2D<float> delta = mouse_delta * (-1.0f/camera.zoom);
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Node>> copied_nodes;
|
||||||
|
|
||||||
auto dragging_nodes = app.nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n) { return n.dragging;});
|
auto dragging_nodes = app.gm.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.gm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.connecting;});
|
||||||
auto connecting_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.connecting;});
|
auto selected_nodes = app.gm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.selected && !n.dragging;});
|
||||||
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.gm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, n.position, n.radius);});
|
||||||
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);});
|
auto hovering_connectors = app.gm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, (n.position - ((n.position - mouse_pos)).norm() * (n.radius + 14.0f)), 8.0f);});
|
||||||
auto hovering_connectors = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, (n.position - ((n.position - mouse_pos)).norm() * (n.radius + 14.0f)), 8.0f);});
|
|
||||||
|
|
||||||
for(auto &n : app.nm.nodes | std::ranges::views::values){
|
for(auto &n : app.gm.nodes | std::ranges::views::values){
|
||||||
if(hovering_nodes.empty()) n.hovering = false;
|
if(hovering_nodes.empty()) n.hovering = false;
|
||||||
if(hovering_connectors.empty()) n.hover_connect = false;
|
if(hovering_connectors.empty()) n.hover_connect = false;
|
||||||
}
|
}
|
||||||
@@ -137,13 +139,13 @@ int main(){
|
|||||||
|
|
||||||
if(IsKeyPressed(KEY_TAB)) {
|
if(IsKeyPressed(KEY_TAB)) {
|
||||||
app.settings.mode = (app.settings.mode + 1) % 3;
|
app.settings.mode = (app.settings.mode + 1) % 3;
|
||||||
app.nm.setNodeMode(app.settings.mode);
|
app.gm.setNodeMode(app.settings.mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(istate){
|
switch(istate){
|
||||||
case InteractionState::HOVER_CANVAS:
|
case InteractionState::HOVER_CANVAS:
|
||||||
{
|
{
|
||||||
for(auto &n : app.nm.nodes | std::ranges::views::values){
|
for(auto &n : app.gm.nodes | std::ranges::views::values){
|
||||||
n.hover_connect = false;
|
n.hover_connect = false;
|
||||||
}
|
}
|
||||||
if(mouse_right_down) {
|
if(mouse_right_down) {
|
||||||
@@ -162,7 +164,7 @@ int main(){
|
|||||||
DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150});
|
DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150});
|
||||||
selection = (Rectangle){select1.x, select1.y, select2.x, select2.y};
|
selection = (Rectangle){select1.x, select1.y, select2.x, select2.y};
|
||||||
|
|
||||||
for(auto& n : app.nm.nodes | std::views::values){
|
for(auto& n : app.gm.nodes | std::views::values){
|
||||||
if(CheckCollisionPointRec(n.position, selection)) {
|
if(CheckCollisionPointRec(n.position, selection)) {
|
||||||
n.in_rect = true;
|
n.in_rect = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -172,7 +174,7 @@ int main(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(mouse_released){
|
if(mouse_released){
|
||||||
for(auto& n : app.nm.nodes | std::views::values){
|
for(auto& n : app.gm.nodes | std::views::values){
|
||||||
if(CheckCollisionPointRec(n.position, selection)) {
|
if(CheckCollisionPointRec(n.position, selection)) {
|
||||||
n.selected = true;
|
n.selected = true;
|
||||||
n.in_rect = false;
|
n.in_rect = false;
|
||||||
@@ -259,12 +261,12 @@ int main(){
|
|||||||
if(mouse_released) {
|
if(mouse_released) {
|
||||||
if(&hovering_nodes.front() != &connecting_nodes.front() && &connecting_nodes.front() != &hovering_connectors.front()){
|
if(&hovering_nodes.front() != &connecting_nodes.front() && &connecting_nodes.front() != &hovering_connectors.front()){
|
||||||
if(!hovering_nodes.empty()){
|
if(!hovering_nodes.empty()){
|
||||||
app.cm.addConnection(connecting_nodes.front().id, hovering_nodes.front().id);
|
app.gm.addConnection(connecting_nodes.front().id, hovering_nodes.front().id);
|
||||||
} else if(!hovering_connectors.empty()){
|
} else if(!hovering_connectors.empty()){
|
||||||
app.cm.addConnection(connecting_nodes.front().id, hovering_connectors.front().id);
|
app.gm.addConnection(connecting_nodes.front().id, hovering_connectors.front().id);
|
||||||
} else {
|
} else {
|
||||||
int id = app.nm.addNode(mouse_pos.x, mouse_pos.y);
|
int id = app.gm.addNode(mouse_pos.x, mouse_pos.y);
|
||||||
app.cm.addConnection(connecting_nodes.front().id, id);
|
app.gm.addConnection(connecting_nodes.front().id, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
connecting_nodes.front().connecting = false;
|
connecting_nodes.front().connecting = false;
|
||||||
@@ -282,13 +284,7 @@ int main(){
|
|||||||
}
|
}
|
||||||
case InteractionState::COPY_SELECTED_NODES:
|
case InteractionState::COPY_SELECTED_NODES:
|
||||||
{
|
{
|
||||||
for(auto &n: copied_nodes){
|
std::copy(selected_nodes.begin(), selected_nodes.end(), copied_nodes.begin());
|
||||||
n.copied = false;
|
|
||||||
}
|
|
||||||
for(auto &n: selected_nodes){
|
|
||||||
n.copied = true;
|
|
||||||
n.selected = false;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InteractionState::PASTE_SELECTED_NODES:
|
case InteractionState::PASTE_SELECTED_NODES:
|
||||||
@@ -296,7 +292,9 @@ int main(){
|
|||||||
for(auto &n: copied_nodes){
|
for(auto &n: copied_nodes){
|
||||||
n.drag_offset = (n.position - copied_nodes.front().position);
|
n.drag_offset = (n.position - copied_nodes.front().position);
|
||||||
}
|
}
|
||||||
// app.nm.copyNodes(mouse_pos);
|
// app.gm.copyNodes(mouse_pos);
|
||||||
|
//app.gm.copyNodes(selected_nodes, mouse_pos);
|
||||||
|
|
||||||
app.copyNodesAndConnections(mouse_pos);
|
app.copyNodesAndConnections(mouse_pos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+156
@@ -0,0 +1,156 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "node.h"
|
||||||
|
#include "raymath.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#define R 14.0f
|
||||||
|
|
||||||
|
struct NodeMidiOut{
|
||||||
|
int i;
|
||||||
|
std::string name;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MidiNode : public Node{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool send_note = true;
|
||||||
|
bool send_cc = false;
|
||||||
|
bool send_pc = false;
|
||||||
|
bool send_pitch_bend = false;
|
||||||
|
|
||||||
|
int midi_out = -1;
|
||||||
|
|
||||||
|
std::map<int, NodeMidiOut> midi_outs;
|
||||||
|
|
||||||
|
bool gui_midi_channel_edit = false;
|
||||||
|
bool gui_midi_note_edit = false;
|
||||||
|
bool gui_midi_velocity_edit = false;
|
||||||
|
bool gui_midi_gate_edit = false;
|
||||||
|
|
||||||
|
bool triggered = false;
|
||||||
|
|
||||||
|
int mode = 0;
|
||||||
|
|
||||||
|
int midi_note_channel = 1;
|
||||||
|
int midi_note = 48;
|
||||||
|
int midi_velocity = 60;
|
||||||
|
int midi_gate = 25; // gate time in milliseconds
|
||||||
|
|
||||||
|
int midi_cc_channel = 0;
|
||||||
|
int midi_cc = 0;
|
||||||
|
int midi_cc_value = 0;
|
||||||
|
|
||||||
|
int midi_pc_channel = 0;
|
||||||
|
int midi_pc = 0;
|
||||||
|
int midi_pc_value = 0;
|
||||||
|
|
||||||
|
int midi_pitch_bend_channel = 0;
|
||||||
|
int midi_pitch_bend = 8192;
|
||||||
|
|
||||||
|
float start = 0;
|
||||||
|
float fade = 0;
|
||||||
|
float time = 0;
|
||||||
|
float last = 0;
|
||||||
|
|
||||||
|
void setMidiPort(int midi_port, bool state){
|
||||||
|
midi_outs[midi_port].enabled = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trigger(){
|
||||||
|
triggered = true;
|
||||||
|
start = GetTime();
|
||||||
|
fade = midi_gate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMode(int _mode) override{
|
||||||
|
mode = _mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Vec2D<float> mouse, Camera2D cam) override {
|
||||||
|
last = time;
|
||||||
|
time = GetTime();
|
||||||
|
if(time - start >= (float)midi_gate / 1000.0f){
|
||||||
|
triggered = false;
|
||||||
|
fade = 0;
|
||||||
|
} else {
|
||||||
|
fade -= (time - last)*1000.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawRing(position, radius, radius+4, 0, 360, 24, (Color){60, 60, 60, 255});
|
||||||
|
DrawRing(position, radius, radius+4, 0.0f - 90.0f, (360.0f/127.0f) * midi_velocity - 90.0f, 24, (Color){158, 134, 200, 255});
|
||||||
|
DrawCircleLinesV(position, radius + 4, (Color){100, 100, 100, 255});
|
||||||
|
|
||||||
|
float midi_gate_map = round((255.f / midi_gate) * fade);
|
||||||
|
|
||||||
|
Color gate_color = VS_COLOR_GREEN;
|
||||||
|
|
||||||
|
switch(mode){
|
||||||
|
case 0:{
|
||||||
|
gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){180, 210, 115, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE);
|
||||||
|
break;}
|
||||||
|
case 1:{
|
||||||
|
gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){229, 181, 103, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE);
|
||||||
|
break;}
|
||||||
|
case 2:{
|
||||||
|
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(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);
|
||||||
|
|
||||||
|
if(selected) DrawCircleLinesV(position, radius+8, (Color){158, 255, 210, 255});
|
||||||
|
|
||||||
|
if(IsKeyDown(KEY_LEFT_ALT)){
|
||||||
|
float value = 0;
|
||||||
|
int offset_gate = 0;
|
||||||
|
switch(mode){
|
||||||
|
case 0:
|
||||||
|
value = (float)midi_gate/1000.0f;
|
||||||
|
offset_gate = MeasureText(std::format("{:.2f}", value).c_str(), 12);
|
||||||
|
DrawText(std::format("{:.2f}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
value = (float)midi_cc_value;
|
||||||
|
offset_gate = MeasureText(std::format("{}", value).c_str(), 12);
|
||||||
|
DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE );
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value = (float)midi_pitch_bend;
|
||||||
|
offset_gate = MeasureText(std::format("{}", value).c_str(), 12);
|
||||||
|
DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(mode){
|
||||||
|
case 0:{
|
||||||
|
int offset = MeasureText(MIDI::Notes[(int)midi_note].c_str(), 12);
|
||||||
|
DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE );
|
||||||
|
break;}
|
||||||
|
case 1:{
|
||||||
|
int offset = MeasureText(std::format("{}", midi_cc).c_str(), 12);
|
||||||
|
DrawText(std::format("{}", midi_cc).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE );
|
||||||
|
break;}
|
||||||
|
case 2:{
|
||||||
|
int offset = MeasureText(std::format("{}", midi_pitch_bend).c_str(), 12);
|
||||||
|
DrawText(std::format("{}", midi_pitch_bend).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE );
|
||||||
|
break;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D<float> connector = position - ((position - mouse)).norm() * (radius + R);
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200});
|
||||||
|
}
|
||||||
|
};
|
||||||
+16
-4
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "raylib.h"
|
|
||||||
|
|
||||||
class Movable{
|
class Movable{
|
||||||
|
|
||||||
@@ -17,9 +16,22 @@ class Movable{
|
|||||||
Vec2D<float> position;
|
Vec2D<float> position;
|
||||||
Vec2D<float> direction;
|
Vec2D<float> direction;
|
||||||
|
|
||||||
virtual void update(int fps) {};
|
Vec2D<float> 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;
|
||||||
|
bool copied = false;
|
||||||
|
|
||||||
|
bool erase = false;
|
||||||
|
|
||||||
|
virtual void setPosition(Vec2D<float> _position) {position = _position;}
|
||||||
virtual void update(double frametime) {};
|
virtual void update(double frametime) {};
|
||||||
virtual void update() {};
|
virtual void update() {};
|
||||||
virtual void draw(Vec2D<float> *mouse, Camera2D *cam) {};
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-2
@@ -20,7 +20,9 @@ class NodeManager{
|
|||||||
std::vector<int> keys;
|
std::vector<int> keys;
|
||||||
int iterator = 0;
|
int iterator = 0;
|
||||||
|
|
||||||
std::vector<std::string> fractions = {"1/32","1/16","3/32","1/8","5/32","3/16","7/32","1/4","9/32","5/16","11/32","3/8","13/32","7/16","15/32","1/2","17/32","9/16","19/32","5/8","21/32","11/16","23/32","3/4","25/32","13/16","27/32","7/8","29/32","15/16","31/32","1/1"};
|
Node* node(int id){
|
||||||
|
return &nodes.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
int getRandomNode(){
|
int getRandomNode(){
|
||||||
std::vector<int> o;
|
std::vector<int> o;
|
||||||
@@ -80,7 +82,7 @@ class NodeManager{
|
|||||||
for(auto it = (neighbors.begin()); it != neighbors.end(); it++, i++){
|
for(auto it = (neighbors.begin()); it != neighbors.end(); it++, i++){
|
||||||
float d = it->position.dist(n.position);
|
float d = it->position.dist(n.position);
|
||||||
if(d > 0 && d < min_d*1.5 && d < 960) {
|
if(d > 0 && d < min_d*1.5 && d < 960) {
|
||||||
std::string frac = fractions.at((int)Clamp(round(d/60) - 1, 0, 31));
|
std::string frac = MIDI::Fractions.at((int)Clamp(round(d/60) - 1, 0, 31));
|
||||||
Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",d).c_str(), 10.0f, 2.0f);
|
Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",d).c_str(), 10.0f, 2.0f);
|
||||||
Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f);
|
Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f);
|
||||||
|
|
||||||
|
|||||||
+9
-159
@@ -1,178 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <memory>
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
|
|
||||||
|
#include "edge.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "graph-item.h"
|
#include "graph-item.h"
|
||||||
#include "moveable.h"
|
#include "moveable.h"
|
||||||
#include "raymath.h"
|
|
||||||
|
|
||||||
#define R 14.0f
|
|
||||||
|
|
||||||
struct NodeMidiOut{
|
|
||||||
int i;
|
|
||||||
std::string name;
|
|
||||||
bool enabled;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Node : public Movable, public GraphItem{
|
class Node : public Movable, public GraphItem{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Node() {}
|
Node() {}
|
||||||
Node(int id, float x, float y, float r) : Movable(Vec2D<float>(x, y), 0.0f), GraphItem(id), radius(r) {}
|
Node(float x, float y) : Movable(Vec2D<float>(x, y), 0.0f) {}
|
||||||
Node(int id, Vec2D<float> p, float r) : Movable(p, 0.0f), GraphItem(id), radius(r) {}
|
Node(Vec2D<float> p) : Movable(p, 0.0f) {}
|
||||||
|
|
||||||
Node *neighbor = nullptr;
|
Node *neighbor = nullptr;
|
||||||
|
|
||||||
float radius;
|
std::vector<std::shared_ptr<Edge>> connections;
|
||||||
|
|
||||||
bool picked_up = false;
|
|
||||||
bool dragging = false;
|
|
||||||
bool in_rect = false;
|
|
||||||
bool hover_connect = false;
|
|
||||||
bool hovering = false;
|
|
||||||
bool connecting = false;
|
|
||||||
bool config = false;
|
|
||||||
bool selected = false;
|
|
||||||
bool erase = false;
|
|
||||||
bool highlighted = false;
|
|
||||||
bool copied = false;
|
|
||||||
bool triggered = false;
|
|
||||||
|
|
||||||
bool send_note = true;
|
|
||||||
bool send_cc = false;
|
|
||||||
bool send_pc = false;
|
|
||||||
bool send_pitch_bend = false;
|
|
||||||
|
|
||||||
int midi_out = -1;
|
|
||||||
|
|
||||||
Vec2D<float> drag_offset;
|
|
||||||
|
|
||||||
std::map<int, NodeMidiOut> midi_outs;
|
|
||||||
|
|
||||||
bool gui_midi_channel_edit = false;
|
|
||||||
bool gui_midi_note_edit = false;
|
|
||||||
bool gui_midi_velocity_edit = false;
|
|
||||||
bool gui_midi_gate_edit = false;
|
|
||||||
|
|
||||||
int mode = 0;
|
|
||||||
|
|
||||||
int midi_note_channel = 1;
|
|
||||||
int midi_note = 48;
|
|
||||||
int midi_velocity = 60;
|
|
||||||
int midi_gate = 25; // gate time in milliseconds
|
|
||||||
|
|
||||||
int midi_cc_channel = 0;
|
|
||||||
int midi_cc = 0;
|
|
||||||
int midi_cc_value = 0;
|
|
||||||
|
|
||||||
int midi_pc_channel = 0;
|
|
||||||
int midi_pc = 0;
|
|
||||||
int midi_pc_value = 0;
|
|
||||||
|
|
||||||
int midi_pitch_bend_channel = 0;
|
|
||||||
int midi_pitch_bend = 8192;
|
|
||||||
|
|
||||||
float start = 0;
|
|
||||||
float fade = 0;
|
|
||||||
float time = 0;
|
|
||||||
float last = 0;
|
|
||||||
|
|
||||||
Distribution distributionMode = Distribution::GEOMETRIC;
|
Distribution distributionMode = Distribution::GEOMETRIC;
|
||||||
|
|
||||||
|
float radius = 15.0f;
|
||||||
|
bool config = false;
|
||||||
|
|
||||||
void setMidiPort(int midi_port, bool state){
|
virtual void setMode(int mode) = 0;
|
||||||
midi_outs[midi_port].enabled = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void trigger(){
|
|
||||||
triggered = true;
|
|
||||||
start = GetTime();
|
|
||||||
fade = midi_gate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(Vec2D<float> *mouse, Camera2D *cam) {
|
|
||||||
last = time;
|
|
||||||
time = GetTime();
|
|
||||||
if(time - start >= (float)midi_gate / 1000.0f){
|
|
||||||
triggered = false;
|
|
||||||
fade = 0;
|
|
||||||
} else {
|
|
||||||
fade -= (time - last)*1000.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawRing(position, radius, radius+4, 0, 360, 24, (Color){60, 60, 60, 255});
|
|
||||||
DrawRing(position, radius, radius+4, 0.0f - 90.0f, (360.0f/127.0f) * midi_velocity - 90.0f, 24, (Color){158, 134, 200, 255});
|
|
||||||
DrawCircleLinesV(position, radius + 4, (Color){100, 100, 100, 255});
|
|
||||||
|
|
||||||
float midi_gate_map = round((255.f / midi_gate) * fade);
|
|
||||||
|
|
||||||
Color gate_color = VS_COLOR_GREEN;
|
|
||||||
|
|
||||||
switch(mode){
|
|
||||||
case 0:{
|
|
||||||
gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){180, 210, 115, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE);
|
|
||||||
break;}
|
|
||||||
case 1:{
|
|
||||||
gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){229, 181, 103, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE);
|
|
||||||
break;}
|
|
||||||
case 2:{
|
|
||||||
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(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);
|
|
||||||
|
|
||||||
if(selected) DrawCircleLinesV(position, radius+8, (Color){158, 255, 210, 255});
|
|
||||||
|
|
||||||
if(IsKeyDown(KEY_LEFT_ALT)){
|
|
||||||
float value = 0;
|
|
||||||
int offset_gate = 0;
|
|
||||||
switch(mode){
|
|
||||||
case 0:
|
|
||||||
value = (float)midi_gate/1000.0f;
|
|
||||||
offset_gate = MeasureText(std::format("{:.2f}", value).c_str(), 12);
|
|
||||||
DrawText(std::format("{:.2f}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE );
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
value = (float)midi_cc_value;
|
|
||||||
offset_gate = MeasureText(std::format("{}", value).c_str(), 12);
|
|
||||||
DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE );
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
value = (float)midi_pitch_bend;
|
|
||||||
offset_gate = MeasureText(std::format("{}", value).c_str(), 12);
|
|
||||||
DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch(mode){
|
|
||||||
case 0:{
|
|
||||||
int offset = MeasureText(MIDI::Notes[(int)midi_note].c_str(), 12);
|
|
||||||
DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE );
|
|
||||||
break;}
|
|
||||||
case 1:{
|
|
||||||
int offset = MeasureText(std::format("{}", midi_cc).c_str(), 12);
|
|
||||||
DrawText(std::format("{}", midi_cc).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE );
|
|
||||||
break;}
|
|
||||||
case 2:{
|
|
||||||
int offset = MeasureText(std::format("{}", midi_pitch_bend).c_str(), 12);
|
|
||||||
DrawText(std::format("{}", midi_pitch_bend).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE );
|
|
||||||
break;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2D<float> connector = position - ((position - *mouse)).norm() * (radius + R);
|
|
||||||
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});
|
|
||||||
}
|
|
||||||
if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class SignalManager{
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SignalManager() {}
|
SignalManager() {}
|
||||||
SignalManager(GraphManager *gm, std::mutex *mutex) : mutex(mutex), gm(gm), nm(nm) {}
|
SignalManager(GraphManager *gm, std::mutex *mutex) : mutex(mutex), gm(gm) {}
|
||||||
|
|
||||||
Midi midi;
|
Midi midi;
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ class SignalManager{
|
|||||||
|
|
||||||
void reset(){
|
void reset(){
|
||||||
for(auto &s : signals){
|
for(auto &s : signals){
|
||||||
s.position = gm->nodes[s.start].position + Vec2D<float>{0.1, 0.1};
|
s.position = gm->node(s.start)->position + Vec2D<float>{0.1, 0.1};
|
||||||
s.next = s.start;
|
s.next = s.start;
|
||||||
s.last = s.start;
|
s.last = s.start;
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ class SignalManager{
|
|||||||
|
|
||||||
void addSignalAtNode(int node_id){
|
void addSignalAtNode(int node_id){
|
||||||
Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200};
|
Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200};
|
||||||
signals.emplace(signals.end(), Signal(gm->nodes[node_id].position.x+1, gm->nodes[node_id].position.y+1, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
signals.emplace(signals.end(), Signal(gm->node(node_id)->position.x+1, gm->node(node_id)->position.y+1, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
||||||
signals.back().next = node_id;
|
signals.back().next = node_id;
|
||||||
signals.back().last = node_id;
|
signals.back().last = node_id;
|
||||||
signals.back().start = node_id;
|
signals.back().start = node_id;
|
||||||
@@ -75,18 +75,18 @@ class SignalManager{
|
|||||||
mutex->lock();
|
mutex->lock();
|
||||||
if(play){
|
if(play){
|
||||||
for(auto& s : signals){
|
for(auto& s : signals){
|
||||||
s.direction = (gm->node(s.next).position - s.position).norm();
|
s.direction = (gm->node(s.next)->position - s.position).norm();
|
||||||
s.update(diff.count());
|
s.update(diff.count());
|
||||||
if(s.position.dist(&gm->nodes[s.next].position) < 0.6f) {
|
if(s.position.dist(&gm->node(s.next)->position) < 0.6f) {
|
||||||
int n = gm->next(s.next, s.last);
|
int n = gm->next(s.next, s.last);
|
||||||
gm->triggerNode(s.next);
|
gm->triggerNode(s.next);
|
||||||
|
|
||||||
if(n != s.next && n != -1) {
|
if(n != s.next && n != -1) {
|
||||||
for(auto &m : gm->nodes[s.next].midi_outs){
|
for(auto &m : gm->node(s.next)->midi_outs){
|
||||||
if(m.second.enabled) {
|
if(m.second.enabled) {
|
||||||
if(gm->nodes[s.next].send_note) midi.note(m.second.i, gm->nodes[s.next].midi_note_channel, gm->nodes[s.next].midi_note, gm->nodes[s.next].midi_velocity, gm->nodes[s.next].midi_gate);
|
if(gm->node(s.next)->send_note) midi.note(m.second.i, gm->node(s.next)->midi_note_channel, gm->node(s.next)->midi_note, gm->node(s.next)->midi_velocity, gm->node(s.next)->midi_gate);
|
||||||
if(gm->nodes[s.next].send_cc) midi.cc(m.second.i, gm->nodes[s.next].midi_cc_channel, gm->nodes[s.next].midi_cc, gm->nodes[s.next].midi_cc_value);
|
if(gm->node(s.next)->send_cc) midi.cc(m.second.i, gm->node(s.next)->midi_cc_channel, gm->node(s.next)->midi_cc, gm->node(s.next)->midi_cc_value);
|
||||||
if(gm->nodes[s.next].send_pitch_bend) midi.pitch_bend(m.second.i, gm->nodes[s.next].midi_pitch_bend_channel, gm->nodes[s.next].midi_pitch_bend);
|
if(gm->node(s.next)->send_pitch_bend) midi.pitch_bend(m.second.i, gm->node(s.next)->midi_pitch_bend_channel, gm->node(s.next)->midi_pitch_bend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.last = s.next;
|
s.last = s.next;
|
||||||
|
|||||||
+9
-9
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "connection.h"
|
#include "edge.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "graph-manager.h"
|
#include "graph-manager.h"
|
||||||
#include "signal-manager.h"
|
#include "signal-manager.h"
|
||||||
@@ -45,8 +45,8 @@ class AppState{
|
|||||||
void copyNodesAndConnections(Vec2D<float> position){
|
void copyNodesAndConnections(Vec2D<float> position){
|
||||||
auto copy_nodes_ids = gm.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<int>>();
|
auto copy_nodes_ids = gm.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<int>>();
|
||||||
|
|
||||||
std::vector<Connection> copy_connections;
|
std::vector<Edge> copy_connections;
|
||||||
std::ranges::copy_if(gm.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);});
|
std::ranges::copy_if(gm.connections, std::back_inserter(copy_connections), [copy_nodes_ids](Edge c){return std::ranges::contains(copy_nodes_ids, c.node_id_start) && std::ranges::contains(copy_nodes_ids, c.node_id_end);});
|
||||||
|
|
||||||
for(auto &n : copy_nodes_ids){
|
for(auto &n : copy_nodes_ids){
|
||||||
int old_id = n;
|
int old_id = n;
|
||||||
@@ -55,8 +55,8 @@ class AppState{
|
|||||||
gm.nodes[new_id].selected = true;
|
gm.nodes[new_id].selected = true;
|
||||||
|
|
||||||
for(auto &c : copy_connections){
|
for(auto &c : copy_connections){
|
||||||
if(c.v1 == old_id) c.v1 = new_id;
|
if(c.node_id_start == old_id) c.node_id_start = new_id;
|
||||||
if(c.v2 == old_id) c.v2 = new_id;
|
if(c.node_id_end == old_id) c.node_id_end = new_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,13 +76,13 @@ class AppState{
|
|||||||
erase_nodes_ids.push_back(e.id);
|
erase_nodes_ids.push_back(e.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto erase_connections = gm.connections | std::ranges::views::filter([erase_nodes_ids](Connection c){ return std::ranges::contains(erase_nodes_ids, c.v1) || std::ranges::contains(erase_nodes_ids, c.v2);});
|
auto erase_connections = gm.connections | std::ranges::views::filter([erase_nodes_ids](Edge c){ return std::ranges::contains(erase_nodes_ids, c.node_id_start) || std::ranges::contains(erase_nodes_ids, c.node_id_end);});
|
||||||
|
|
||||||
std::vector<int> adjacent_nodes_ids;
|
std::vector<int> adjacent_nodes_ids;
|
||||||
|
|
||||||
for(auto &c : erase_connections){
|
for(auto &c : erase_connections){
|
||||||
if(!gm.nodes.at(c.v1).selected) adjacent_nodes_ids.push_back(c.v1);
|
if(!gm.nodes.at(c.node_id_start).selected) adjacent_nodes_ids.push_back(c.node_id_start);
|
||||||
if(!gm.nodes.at(c.v2).selected) adjacent_nodes_ids.push_back(c.v2);
|
if(!gm.nodes.at(c.node_id_end).selected) adjacent_nodes_ids.push_back(c.node_id_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto reroute_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
auto reroute_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
||||||
@@ -111,7 +111,7 @@ class AppState{
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(auto &n : erase_nodes){
|
for(auto &n : erase_nodes){
|
||||||
std::erase_if(gm.connections, [n](Connection c){ return c.v1 == n.id || c.v2 == n.id;});
|
std::erase_if(gm.connections, [n](Edge c){ return c.node_id_start == n.id || c.node_id_end == n.id;});
|
||||||
}
|
}
|
||||||
std::erase_if(gm.nodes, [](std::pair<int, Node> n){ return n.second.erase;});
|
std::erase_if(gm.nodes, [](std::pair<int, Node> n){ return n.second.erase;});
|
||||||
gm.keys.clear();
|
gm.keys.clear();
|
||||||
|
|||||||
Reference in New Issue
Block a user