2024-10-25 16:41:37 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
2024-10-26 02:14:41 +02:00
|
|
|
#include "connection.h"
|
2024-10-25 16:41:37 +02:00
|
|
|
#include "datatypes.h"
|
|
|
|
|
#include "node-manager.h"
|
|
|
|
|
#include "connection-manager.h"
|
|
|
|
|
#include "signal-manager.h"
|
|
|
|
|
#include "ui.h"
|
2024-10-27 00:40:57 +02:00
|
|
|
|
2024-10-26 02:14:41 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <ranges>
|
|
|
|
|
#include <vector>
|
2024-10-25 16:41:37 +02:00
|
|
|
|
|
|
|
|
class AppState{
|
|
|
|
|
public:
|
|
|
|
|
|
2024-10-26 02:14:41 +02:00
|
|
|
AppState() : cm(&nm), sm(&nm, &cm, &mutex), ui(&settings, &nm, &cm, &sm) {}
|
2024-10-25 16:41:37 +02:00
|
|
|
|
|
|
|
|
enum States {IDLE, CONFIG};
|
|
|
|
|
|
|
|
|
|
AppSettings settings;
|
|
|
|
|
|
|
|
|
|
States state;
|
|
|
|
|
|
|
|
|
|
std::mutex mutex;
|
|
|
|
|
|
|
|
|
|
ConnectionManager cm;
|
|
|
|
|
SignalManager sm;
|
|
|
|
|
NodeManager nm;
|
|
|
|
|
|
|
|
|
|
AppUI ui;
|
|
|
|
|
|
|
|
|
|
void updateMidiPorts(){
|
2024-10-26 02:14:41 +02:00
|
|
|
for(auto&n : nm.nodes | std::views::values){
|
2024-10-25 16:41:37 +02:00
|
|
|
for(auto& mo : sm.midi.midi_out_ports){
|
|
|
|
|
if(!n.midi_outs.contains(mo.number) && mo.enabled){
|
|
|
|
|
n.midi_outs[mo.number] = {mo.number, mo.port.port_name, false};
|
|
|
|
|
}
|
|
|
|
|
if(n.midi_outs.contains(mo.number) && !mo.enabled){
|
|
|
|
|
n.midi_outs.erase(mo.number);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-26 16:31:23 +02:00
|
|
|
void copyNodesAndConnections(Vec2D<float> position){
|
|
|
|
|
auto copy_nodes_ids = nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.copied;}) | std::views::transform([](Node n){return n.id;}) | std::ranges::to<std::vector<int>>();
|
|
|
|
|
|
|
|
|
|
std::vector<Connection> copy_connections;
|
|
|
|
|
std::ranges::copy_if(cm.connections, std::back_inserter(copy_connections), [copy_nodes_ids](Connection c){return std::ranges::contains(copy_nodes_ids, c.v1) && std::ranges::contains(copy_nodes_ids, c.v2);});
|
|
|
|
|
|
|
|
|
|
for(auto &n : copy_nodes_ids){
|
|
|
|
|
int old_id = n;
|
|
|
|
|
int new_id = nm.copyNode(n, position + nm.nodes[n].drag_offset);
|
2024-10-28 02:07:47 +01:00
|
|
|
nm.nodes[new_id].copied = false;
|
|
|
|
|
nm.nodes[new_id].selected = true;
|
|
|
|
|
|
2024-10-26 16:31:23 +02:00
|
|
|
for(auto &c : copy_connections){
|
|
|
|
|
if(c.v1 == old_id) c.v1 = new_id;
|
|
|
|
|
if(c.v2 == old_id) c.v2 = new_id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cm.connections.insert(cm.connections.end(), copy_connections.cbegin(), copy_connections.cend());
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-26 02:14:41 +02:00
|
|
|
void removeNodes(){
|
|
|
|
|
|
|
|
|
|
for(auto &n : nm.nodes){
|
|
|
|
|
n.second.highlighted = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto erase_nodes = nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.erase;});
|
|
|
|
|
|
|
|
|
|
std::vector<int> erase_nodes_ids;
|
|
|
|
|
for(auto &e : erase_nodes){
|
|
|
|
|
erase_nodes_ids.push_back(e.id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto erase_connections = cm.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);});
|
|
|
|
|
|
|
|
|
|
std::vector<int> adjacent_nodes_ids;
|
|
|
|
|
|
|
|
|
|
for(auto &c : erase_connections){
|
|
|
|
|
if(!nm.nodes.at(c.v1).selected) adjacent_nodes_ids.push_back(c.v1);
|
|
|
|
|
if(!nm.nodes.at(c.v2).selected) adjacent_nodes_ids.push_back(c.v2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto reroute_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
|
|
|
|
return std::ranges::contains(erase_nodes_ids, s.next);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for(auto &s : reroute_signals){
|
|
|
|
|
float dist = 10000000;
|
|
|
|
|
int next_id = -1;
|
|
|
|
|
for(int i : adjacent_nodes_ids){
|
|
|
|
|
if(nm.nodes.at(i).position.dist(&s.position) < dist) {
|
|
|
|
|
dist = nm.nodes.at(i).position.dist(&s.position);
|
|
|
|
|
next_id = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s.next = next_id;
|
|
|
|
|
s.last = next_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto rebase_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
|
|
|
|
return std::ranges::contains(erase_nodes_ids, s.start);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for(auto &s : rebase_signals){
|
|
|
|
|
s.start = s.next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(auto &n : erase_nodes){
|
|
|
|
|
std::erase_if(cm.connections, [n](Connection c){ return c.v1 == n.id || c.v2 == n.id;});
|
|
|
|
|
}
|
|
|
|
|
std::erase_if(nm.nodes, [](std::pair<int, Node> n){ return n.second.erase;});
|
|
|
|
|
nm.keys.clear();
|
|
|
|
|
std::ranges::copy(nm.nodes | std::ranges::views::keys, std::back_inserter(nm.keys));
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-25 16:41:37 +02:00
|
|
|
void draw(Vec2D<float> *mouse_pos, Camera2D *camera){
|
|
|
|
|
mutex.lock();
|
|
|
|
|
updateMidiPorts();
|
2024-10-28 02:07:47 +01:00
|
|
|
mutex.unlock();
|
2024-10-25 16:41:37 +02:00
|
|
|
nm.drawNodes(mouse_pos, camera);
|
|
|
|
|
cm.drawConnections(mouse_pos, camera);
|
|
|
|
|
sm.drawSignals(mouse_pos, camera);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void drawUI(Vec2D<float> *mouse_pos, Camera2D *camera){
|
|
|
|
|
mutex.lock();
|
|
|
|
|
ui.draw(mouse_pos, camera);
|
|
|
|
|
mutex.unlock();
|
|
|
|
|
}
|
|
|
|
|
};
|