Files
viseq/src/interaction-manager.cpp
T

258 lines
9.5 KiB
C++
Raw Normal View History

2026-01-06 02:44:18 +01:00
#include "interaction-manager.h"
#include "connector.h"
#include "datatypes.h"
#include "node.h"
#include "raylib.h"
#include "state.h"
#include <algorithm>
#include <memory>
namespace VISEQ::INTERACTION{
2026-05-04 20:30:16 +02:00
2026-01-06 02:44:18 +01:00
void InteractionManager::update(){
if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_C)){
VEC_SPTR_Node selected_nodes = gm->getCopiesOfSelectedNodes();
2026-06-24 18:11:34 +02:00
if(!selected_nodes.empty()) cb->copyNodes(selected_nodes);
2026-01-06 02:44:18 +01:00
}
if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_V)){
2026-06-24 18:11:34 +02:00
VEC_SPTR_Node paste_nodes = cb->pasteNodes();
2026-01-06 02:44:18 +01:00
if(!paste_nodes.empty()) gm->pasteNodesAndEdges(paste_nodes, MOD_MOUSE);
}
if(IsKeyPressed(KEY_DELETE)){
removeNodes(gm->getSelection());
}
if(!KEYS_DOWN.shift && IsKeyPressed(KEY_TAB)) {
gm->cycleModeOfSelectedNodes(true);
2026-01-06 02:44:18 +01:00
}
if(KEYS_DOWN.shift && IsKeyPressed(KEY_TAB)) {
gm->cycleModeOfSelectedNodes(false);
2026-01-06 02:44:18 +01:00
}
}
void InteractionManager::draw(){
doInteraction();
scaleSelection();
if(!gm->getSelection().empty()){
DrawRectangleRoundedLines(state->bounding_box, 0.1f, 3, VS_COLOR_LIGHTGREY);
scale_handle->draw();
}
}
void InteractionManager::removeNodes(VEC_SPTR_Node nodes){
VEC_WPTR_Node adjacent_nodes = gm->getAdjacentNodes(nodes);
sm->rerouteSignal(nodes, adjacent_nodes);
sm->rebaseSignal(nodes);
gm->removeNodesAndEdges(nodes);
}
void InteractionManager::scaleSelection(){
if(!gm->getSelection().empty()){
float offset = 30;
Vec2Df corner_tl = {50000, 50000};
Vec2Df corner_br = {-50000, -50000};
std::shared_ptr<Node> node_tl;
std::shared_ptr<Node> node_br;
for(auto n : gm->getSelection()){
float x = n->position.x;
float y = n->position.y;
if(x < corner_tl.x && y < corner_tl.y) node_tl = n;
if(x > corner_br.x && y > corner_br.y) node_br = n;
if(x <= corner_tl.x) corner_tl.x = x;
if(x >= corner_br.x) corner_br.x = x;
if(y <= corner_tl.y) corner_tl.y = y;
if(y >= corner_br.y) corner_br.y = y;
}
corner_tl -= Vec2Df(offset, offset);
corner_br += Vec2Df(offset, offset);
state->bounding_box = (Rectangle){corner_tl.x, corner_tl.y, corner_br.x - corner_tl.x, corner_br.y - corner_tl.y};
scale_handle->update();
if(scale_handle->clicked()){
scale_start = (corner_br - corner_tl);
for(auto n : gm->getSelection()){
n->drag_offset = n->position - node_tl->position;
}
}
if(scale_handle->picked_up){
Vec2Df scale = (scale_handle->position - corner_tl) / scale_start;
if(IsKeyDown(KEY_LEFT_SHIFT)) scale.y = scale.x;
DrawText(std::format("{:.2f} {:.2f}", scale.x, scale.y).c_str(), corner_br.x+5, corner_br.y+5, 10, RED);
for(auto n : gm->getSelection()){
n->position = node_tl->position + (n->drag_offset * scale);
}
} else {
scale_handle->position = corner_br;
}
}
}
void InteractionManager::snapPolar(std::shared_ptr<Node> dragNode){
float steps = round((dragNode->neighbors.front()->position.dist(SCREEN_MOUSE)) / state->settings.grid) * state->settings.grid;
if(dragNode->neighbors.size() > 1){
Vec2Df dn1 = dragNode->neighbors[0]->position;
Vec2Df dn2 = dragNode->neighbors[1]->position;
Vec2Df v1_orth = dn1.center(dn2);
if(dn1.x < dn2.x) std::swap(dn1,dn2);
float dist = dn1.dist(dn2);
float dist_orth = std::sqrt(std::pow(steps,2) - std::pow(dist/2,2));
if(SCREEN_MOUSE.y < v1_orth.y) dist_orth *= -1;
Vec2Df v1_orth_t = v1_orth + (dn1-dn2).norm().orth() * dist_orth;
DrawLineV(dn1, dn2, VS_COLOR_RED);
DrawLineV(v1_orth, v1_orth_t, VS_COLOR_RED);
DrawCircleV(v1_orth, 3.0f, VS_COLOR_RED);
dragNode->position = v1_orth_t;
} else if(!dragNode->neighbors.empty()){
float pol_r = steps;
float pol_theta = Vector2Angle(Vec2Df{1,0},(SCREEN_MOUSE - dragNode->neighbors.front()->position));
Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta);
dragNode->position = dragNode->neighbors.front()->position + polar;
}
}
void InteractionManager::doInteraction(){
bool exit = false;
bool once = false;
bool connect_once = false;
state->mouse_z = canvas->z_index;
2026-05-04 18:40:00 +02:00
for(auto e : state->event_queue){
2026-01-06 02:44:18 +01:00
if(!connect_once && e.action == APP::Interaction::CONNECT){
APP::InteractionEvent partner;
bool found = false;
2026-05-04 18:40:00 +02:00
for(auto ei : state->event_queue){
2026-01-06 02:44:18 +01:00
if(ei.action == APP::Interaction::HOVER && ei.item->getType() == GraphItemType::CONNECTOR) {
std::cout << "YEAH" << std::endl;
partner = ei;
found = true;
break;
}
}
auto connector = std::dynamic_pointer_cast<Connector>(e.item);
if(found && partner != e){
auto connector_to = std::dynamic_pointer_cast<Connector>(partner.item);
connector->partner = connector_to;
connector_to->partner = connector;
gm->addConnection(std::dynamic_pointer_cast<Node>(connector->parent.lock()), std::dynamic_pointer_cast<Node>(connector_to->parent.lock()));
} else if (partner != e){
if(KEYS_DOWN.alt){
gm->createConfigNode(SCREEN_MOUSE);
} else {
gm->createMidiNode(SCREEN_MOUSE);
}
gm->addConnection(std::dynamic_pointer_cast<Node>(connector->parent.lock()), gm->getLastNode());
}
connect_once = true;
break;
}
}
2026-05-04 18:40:00 +02:00
while(state->event_queue.size() > 0 && !exit){
auto e = state->event_queue.front();
if(e.action == APP::Interaction::CLICK){
gm->addToSelection();
}
2026-01-06 02:44:18 +01:00
if(e.action == APP::Interaction::RIGHTCLICK){
gm->addToSelection();
state->context_menu = !state->context_menu;
}
if(state->context_menu) break;
if(e.action == APP::Interaction::HOVER){
state->mouse_z = e.item->z_index;
}
if(e.item->getType() == GraphItemType::CANVAS) {
if(e.action == APP::Interaction::SELECT) {
gm->select();
canvas->clearSelectionRect();
}
if(e.action == APP::Interaction::DESELECT) {
gm->deselect();
}
}
if(!once && e.item->getType() == GraphItemType::NODE){
auto node = std::dynamic_pointer_cast<Node>(e.item);
if(e.action == APP::Interaction::PICKUP) {
node->pickUp();
if(node->selected){
for(auto s : gm->getSelection()){
s->pickUp(node->position);
}
}
once = true;
}
if(e.action == APP::Interaction::DRAG) {
if(KEYS_DOWN.ctrl) node->drag(MOD_MOUSE);
else if(KEYS_DOWN.shift) {
snapPolar(node);
}
else node->drag(MOD_MOUSE + node->drag_offset);
if(node->selected){
for(auto s : gm->getSelection()){
s->drag(MOD_MOUSE + s->drag_offset);
}
}
once = true;
}
if(e.action == APP::Interaction::PUTDOWN) {
node->putDown();
if(node->selected){
for(auto s : gm->getSelection()){
s->putDown();
}
}
}
}
if(exit) break;
if(!once && (e.item->getType() == GraphItemType::CONNECTOR || e.item->getType() == GraphItemType::CANVAS || e.item->getType() == GraphItemType::HANDLE)) {
switch(e.action){
case VISEQ::APP::Interaction::PICKUP:
{
e.item->pickUp();
once = true;
break;
}
case VISEQ::APP::Interaction::DRAG:
{
e.item->drag(MOD_MOUSE);
once = true;
break;
}
case VISEQ::APP::Interaction::PUTDOWN:
{
e.item->putDown();
break;
}
default:
{}
}
}
2026-05-04 18:40:00 +02:00
state->event_queue.pop_front();
2026-01-06 02:44:18 +01:00
}
2026-05-04 18:40:00 +02:00
state->event_queue.clear();
2026-01-06 02:44:18 +01:00
}
}