#include "interaction-manager.h" #include "connector.h" #include "datatypes.h" #include "node.h" #include "raylib.h" #include "state.h" #include #include namespace VISEQ::INTERACTION{ void InteractionManager::update(){ if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_C)){ VEC_SPTR_Node selected_nodes = gm->getCopiesOfSelectedNodes(); if(!selected_nodes.empty()) cb->copyNodes(selected_nodes); } if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_V)){ VEC_SPTR_Node paste_nodes = cb->pasteNodes(); if(!paste_nodes.empty()) gm->pasteNodesAndEdges(paste_nodes, MOD_MOUSE); } if(IsKeyPressed(KEY_DELETE)){ removeNodes(gm->getSelection()); } if(!KEYS_DOWN.shift && IsKeyPressed(KEY_TAB)) { state->node_mode = (state->node_mode + 1) % 7; } if(KEYS_DOWN.shift && IsKeyPressed(KEY_TAB)) { state->node_mode -= state->node_mode > 0 ? 1 : -6; } } 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_tl; std::shared_ptr 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 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; for(auto e : state->event_queue){ if(!connect_once && e.action == APP::Interaction::CONNECT){ APP::InteractionEvent partner; bool found = false; for(auto ei : state->event_queue){ 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(e.item); if(found && partner != e){ auto connector_to = std::dynamic_pointer_cast(partner.item); connector->partner = connector_to; connector_to->partner = connector; gm->addConnection(std::dynamic_pointer_cast(connector->parent.lock()), std::dynamic_pointer_cast(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(connector->parent.lock()), gm->getLastNode()); } connect_once = true; break; } } while(state->event_queue.size() > 0 && !exit){ auto e = state->event_queue.front(); if(e.action == APP::Interaction::CLICK){ gm->addToSelection(); } 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(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: {} } } state->event_queue.pop_front(); } state->event_queue.clear(); } }