From 95620a5f0712e177b54d329911cf56c4cb622594 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 6 Nov 2024 02:28:37 +0100 Subject: [PATCH] two node snap for triangles --- src/graph-item.h | 2 - src/graph-manager.h | 19 ++++---- src/main.cpp | 28 ++++++++++-- src/node.h | 5 +- src/state-manager.h | 2 +- src/ui.h | 108 ++++++++++++++++++++++---------------------- 6 files changed, 89 insertions(+), 75 deletions(-) diff --git a/src/graph-item.h b/src/graph-item.h index ea0d3c3..6baf3c3 100644 --- a/src/graph-item.h +++ b/src/graph-item.h @@ -13,9 +13,7 @@ namespace VISEQ::GRAPH { GraphItem(const GraphItem& G) { newId(-1); graphItemType = G.graphItemType; - neighbors = G.neighbors; } - std::vector> neighbors; GraphItemType graphItemType; int id = 0; diff --git a/src/graph-manager.h b/src/graph-manager.h index 06e548f..22f926f 100644 --- a/src/graph-manager.h +++ b/src/graph-manager.h @@ -246,20 +246,21 @@ namespace VISEQ::GRAPH { } void drawNodes(Vec2Df mouse_pos, Camera2D camera){ - auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->dragging && !n->selected;}) | std::ranges::to(); float min_d = 480; for(auto n : nodes){ if(n->dragging){ - std::sort(neighbors.begin(), neighbors.end(), [n, mouse_pos](SPTR_Node na, SPTR_Node nb){ return na->position.dist(mouse_pos) < nb->position.dist(mouse_pos);}); - if(neighbors.size() > 1){ - min_d = neighbors.front()->position.dist(mouse_pos); - n->neighbor = neighbors.front(); - DrawCircleLinesV(n->neighbor->position, 20.0f, VS_COLOR_PINK); - for(auto nb : neighbors){ + 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(); + 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); + DrawCircleLinesV(neighbors_local.front()->position, 22.0f, VS_COLOR_PINK); + n->neighbors = neighbors_local | std::ranges::views::filter([mouse_pos, min_d](SPTR_Node n){return abs(n->position.dist(mouse_pos) - min_d) < 5;}) | std::ranges::to(); + for(auto nb : n->neighbors){ + DrawCircleLinesV(nb->position, 20.0f, VS_COLOR_RED); float d = nb->position.dist(mouse_pos); float dn = nb->position.dist(n->position); if(d > 0 && d < min_d*1.5 && d < 960) { - std::string frac = MIDI::Fractions.at((int)Clamp(round(dn/60) - 1, 0, 31)); + std::string frac = MIDI::Fractions.at(std::clamp(round(dn/60) - 1, 0, 31)); Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",dn).c_str(), 10.0f, 2.0f); Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f); @@ -270,7 +271,7 @@ namespace VISEQ::GRAPH { float rotation = Vector2Angle((Vector2){1,0}, (n->position - nb->position)) * RAD2DEG; DrawTextPro(GetFontDefault(), std::format("{:.1f}",dn).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); - if(nb == neighbors.front() && IsKeyDown(KEY_LEFT_SHIFT)) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); + if(IsKeyDown(KEY_LEFT_SHIFT)) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); Vec2Df n_position = n->position - ((n->position - nb->position)).norm() * 20.0f; Vec2Df nb_position = nb->position - ((nb->position - n->position)).norm() * 20.0f; DrawLineV(n_position, nb_position, VS_COLOR_PINK); diff --git a/src/main.cpp b/src/main.cpp index 3b09906..f6edcf0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -289,12 +289,30 @@ int main(){ 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->neighbor->position.dist(mouse_pos)) / app.settings.grid) * app.settings.grid; - float pol_r = steps; - float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - dragNode->neighbor->position)); + 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); - Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); - dragNode->position = dragNode->neighbor->position + polar; + 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; } diff --git a/src/node.h b/src/node.h index 4fc931a..5ad3fee 100644 --- a/src/node.h +++ b/src/node.h @@ -21,9 +21,8 @@ namespace VISEQ::GRAPH::NODES { Node(Vec2Df p) : Movable(p, 0.0f) {} NodeType nodeType; - - std::shared_ptr neighbor; - + + std::vector> neighbors; std::vector> connections; Distribution distributionMode = Distribution::GEOMETRIC; diff --git a/src/state-manager.h b/src/state-manager.h index ad8773e..39a1c45 100644 --- a/src/state-manager.h +++ b/src/state-manager.h @@ -68,7 +68,7 @@ namespace VISEQ::APP { } new_node->copied = false; - new_node->selected = false; + new_node->selected = true; for(auto c : copy_connections){ if(c->start == old_node) { diff --git a/src/ui.h b/src/ui.h index b3549c3..25fc20e 100644 --- a/src/ui.h +++ b/src/ui.h @@ -103,20 +103,18 @@ namespace VISEQ::APP::UI{ GuiPanel((Rectangle){left,-30,280,(float)settings->height + 31}, ""); const int s_controls = 25; - - } void drawPerNodeConfig(Camera2D *camera){ for(auto& n : gm->nodes | std::views::filter([](std::shared_ptr n){ return n->config; })){ Vector2 np = GetWorldToScreen2D((Vector2){n->position.x, n->position.y}, *camera); - + n->config = !GuiWindowBox((Rectangle){np.x + 10, np.y + 10, 240, 440}, "config"); int option = n->distributionMode; GuiToggleGroup((Rectangle){ np.x + 20, np.y + 40, 73, 20 }, "GEO;RR;RAND", &option); n->distributionMode = (Distribution)option; - + GuiLabel((Rectangle){np.x + 20, np.y + 65, 220, 20}, "SIGNALS"); if(GuiButton((Rectangle){np.x + 20, np.y + 90, 220, 20}, "ADD SIGNAL")){ sm->addSignalAtNode(n); @@ -132,66 +130,66 @@ namespace VISEQ::APP::UI{ GuiCheckBox((Rectangle){np.x + 20, np.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled); i++; } - + int y_channel = y_midi + 30 + i*20; GuiCheckBox((Rectangle){np.x + 20, np.y + y_channel, 20, 20}, "NOTE", &mn->send_note); GuiCheckBox((Rectangle){np.x + 90, np.y + y_channel, 20, 20}, "CC", &mn->send_cc); GuiCheckBox((Rectangle){np.x + 160, np.y + y_channel, 20, 20}, "PITCH", &mn->send_pitch_bend); - + int y_cc_note = y_channel + 120; switch(settings->mode){ case 0:{ - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "NOTE CHANNEL"); - GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_note_channel); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE"); - float v = mn->midi_note; - GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note , 20, 20}, MIDI::Notes[(int)round(v)].c_str()); - GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_note).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); - mn->midi_note = round(v); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "VELOCITY"); - v = mn->midi_velocity; - GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_velocity).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); - mn->midi_velocity = round(v); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 120, 100, 20}, "GATE"); - v = mn->midi_gate; - GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 120, 20, 20}, std::format("{}",(float)mn->midi_gate/1000.0f).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 150, 220, 20}, "", "", &v, 0, 30000); - mn->midi_gate = round(v); - break;} + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "NOTE CHANNEL"); + GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_note_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE"); + float v = mn->midi_note; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note , 20, 20}, MIDI::Notes[(int)round(v)].c_str()); + GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_note).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); + mn->midi_note = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "VELOCITY"); + v = mn->midi_velocity; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_velocity).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); + mn->midi_velocity = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 120, 100, 20}, "GATE"); + v = mn->midi_gate; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 120, 20, 20}, std::format("{}",(float)mn->midi_gate/1000.0f).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 150, 220, 20}, "", "", &v, 0, 30000); + mn->midi_gate = round(v); + break;} case 1: - { - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "CC CHANNEL"); - GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_cc_channel); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); - float v = mn->midi_cc; - GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_cc).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); - mn->midi_cc = round(v); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "CC VALUE"); - v = mn->midi_cc_value; - GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_cc_value).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); - mn->midi_cc_value = round(v); - - break;} + { + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "CC CHANNEL"); + GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_cc_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); + float v = mn->midi_cc; + GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_cc).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); + mn->midi_cc = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "CC VALUE"); + v = mn->midi_cc_value; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_cc_value).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); + mn->midi_cc_value = round(v); + + break;} case 2: - { - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "PITCH BEND CHANNEL"); - GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_pitch_bend_channel); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); - float v = mn->midi_pitch_bend; - GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_pitch_bend).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383); - mn->midi_pitch_bend = round(v); - break;} + { + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "PITCH BEND CHANNEL"); + GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_pitch_bend_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); + float v = mn->midi_pitch_bend; + GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_pitch_bend).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383); + mn->midi_pitch_bend = round(v); + break;} } } }