From 7f2d16932fba77fd799b036e9215dcb5a4a4d482 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 13 Dec 2024 00:30:31 +0100 Subject: [PATCH] Resize on hover taken out. ModNode introduced but needs a better ui approach. --- src/config-node.h | 2 +- src/midi-node.h | 56 ++++---- src/modifier-node.h | 315 +++++++++++++++++++++++++++++++++++++++++++ src/signal-manager.h | 2 +- src/ui.h | 2 +- 5 files changed, 346 insertions(+), 31 deletions(-) create mode 100644 src/modifier-node.h diff --git a/src/config-node.h b/src/config-node.h index 6fe3129..ab70471 100644 --- a/src/config-node.h +++ b/src/config-node.h @@ -87,7 +87,7 @@ namespace VISEQ::GRAPH::NODES { return midiPolyPressure + cPolyPressure; } - std::vector> getConnectedConfigNodes() const { + std::vector> getConnectedConfigNodes() const { // TODO: check for cyclic connections of config nodes (crashes) auto config_conns = connections | RANGE_FILTER([](EDGES::SPTR_Edge c){ return c->start.lock()->getNodeType() == NodeType::CONFIGNODE || c->end.lock()->getNodeType() == NodeType::CONFIGNODE;}) | std::ranges::to>>(); std::vector> config_nodes; for(auto e : config_conns){ diff --git a/src/midi-node.h b/src/midi-node.h index 9bdf11f..5cbd6a9 100644 --- a/src/midi-node.h +++ b/src/midi-node.h @@ -259,11 +259,11 @@ namespace VISEQ::GRAPH::NODES { void draw(Vec2Df mouse, Camera2D cam) override { Node::draw(); - if(hovering()) { - radius += radius < hover_radius ? 2 : 0; - } else { - radius -= radius > node_radius ? 2 : 0; - } + /*if(hovering()) {*/ + /* radius += radius < hover_radius ? 2 : 0;*/ + /*} else {*/ + /* radius -= radius > node_radius ? 2 : 0;*/ + /*}*/ if(hovering() || selected) interact(); @@ -304,23 +304,23 @@ namespace VISEQ::GRAPH::NODES { if(selected) DrawCircleLinesV(position, radius+8, (Color){158, 255, 210, 255}); - if(hovering()){ - for(int i = 0; i < 16; ++i){ - channelButtons.at(i).position = position.orbitAtAngle(radius - 6.0f, DEG2RAD * (360.0f/16.0f)*i); - Color col = VS_COLOR_YELLOW; - if(mode == 0 && midiNote.channel == i) col = VS_COLOR_PINK; - if(mode == 1 && midiCC.channel == i) col = VS_COLOR_PINK; - if(mode == 2 && midiPitchBend.channel == i) col = VS_COLOR_PINK; - channelButtons.at(i).color = col; - channelButtons.at(i).draw(); - if(channelButtons.at(i).hovering()) DrawCenteredText(std::format("{}", i+1), position + (Vec2Df){0,10.0f}, 8, VS_COLOR_WHITE); - if(channelButtons.at(i).clicked()) { - if(mode == 0) midiNote.channel = i; - if(mode == 1) midiCC.channel = i; - if(mode == 2) midiPitchBend.channel = i; - } - } - } + /*if(hovering()){*/ + /* for(int i = 0; i < 16; ++i){*/ + /* channelButtons.at(i).position = position.orbitAtAngle(radius - 6.0f, DEG2RAD * (360.0f/16.0f)*i);*/ + /* Color col = VS_COLOR_YELLOW;*/ + /* if(mode == 0 && midiNote.channel == i) col = VS_COLOR_PINK;*/ + /* if(mode == 1 && midiCC.channel == i) col = VS_COLOR_PINK;*/ + /* if(mode == 2 && midiPitchBend.channel == i) col = VS_COLOR_PINK;*/ + /* channelButtons.at(i).color = col;*/ + /* channelButtons.at(i).draw();*/ + /* if(channelButtons.at(i).hovering()) DrawCenteredText(std::format("{}", i+1), position + (Vec2Df){0,10.0f}, 8, VS_COLOR_WHITE);*/ + /* if(channelButtons.at(i).clicked()) {*/ + /* if(mode == 0) midiNote.channel = i;*/ + /* if(mode == 1) midiCC.channel = i;*/ + /* if(mode == 2) midiPitchBend.channel = i;*/ + /* }*/ + /* }*/ + /*}*/ if(KEYS_DOWN.alt){ float value = 0; @@ -329,32 +329,32 @@ namespace VISEQ::GRAPH::NODES { case 0: value = (float)getNotes().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, VS_COLOR_BLACK ); + DrawText(std::format("{:.2f}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); break; case 1: value = (float)getCC().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, VS_COLOR_BLACK ); + DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); break; case 2: value = (float)getPitchBend().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, VS_COLOR_BLACK ); + 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)getNotes().note].c_str(), 12); - DrawText(MIDI::Notes[getNotes().note].c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + DrawText(MIDI::Notes[getNotes().note].c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); break;} case 1:{ int offset = MeasureText(std::format("{}", getCC().control).c_str(), 12); - DrawText(std::format("{}", getCC().control).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + DrawText(std::format("{}", getCC().control).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); break;} case 2:{ int offset = MeasureText(std::format("{}", getPitchBend().value).c_str(), 12); - DrawText(std::format("{}", getPitchBend().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + DrawText(std::format("{}", getPitchBend().value).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); break;} } } diff --git a/src/modifier-node.h b/src/modifier-node.h new file mode 100644 index 0000000..236a251 --- /dev/null +++ b/src/modifier-node.h @@ -0,0 +1,315 @@ +#pragma once + +#include "datatypes.h" +#include "edge.h" +#include "node.h" +#include "raymath.h" +#include "state.h" +#include + +namespace VISEQ::GRAPH::NODES { + + class ModNode : public Node{ + + public: + ModNode() {std::cout << "ModNode Constructor std" << std::endl;} + ModNode(Vec2Df position) : Node(position) {} + + std::shared_ptr getPtr() { + return std::static_pointer_cast(shared_from_this()); + } + + NodeType nodeType = NodeType::CONFIGNODE; + + MIDI::MidiNote midiNote; + MIDI::MidiCC midiCC; + MIDI::MidiPitchBend midiPitchBend; + MIDI::MidiPolyPressure midiPolyPressure; + MIDI::MidiPC midiPC; + MIDI::MidiAftertouch midiAftertouch; + + int mode = 0; + float radius = 20.0f; + + virtual NodeType getNodeType() const override {return nodeType;} + + virtual void trigger() override {} + + virtual void setMode(int _mode) override { + mode = _mode; + } + + MIDI::MidiNote getNotes() const { + MIDI::MidiNote cNote; + for(auto cn : getConnectedModNodes()){ + cNote += cn.lock()->getNotes(); + } + return midiNote + cNote; + } + + MIDI::MidiCC getCC() const { + MIDI::MidiCC cCC; + for(auto cn : getConnectedModNodes()){ + cCC += cn.lock()->getCC(); + } + return midiCC + cCC; + } + + MIDI::MidiPC getPC() const { + MIDI::MidiPC cPC; + for(auto cn : getConnectedModNodes()){ + cPC += cn.lock()->getPC(); + } + return midiPC + cPC; + } + + MIDI::MidiPitchBend getPitchBend() const { + MIDI::MidiPitchBend cPitchBend; + for(auto cn : getConnectedModNodes()){ + cPitchBend += cn.lock()->getPitchBend(); + } + return midiPitchBend + cPitchBend; + } + + MIDI::MidiAftertouch getAftertouch() const { + MIDI::MidiAftertouch cAftertouch; + for(auto cn : getConnectedModNodes()){ + cAftertouch += cn.lock()->getAftertouch(); + } + return midiAftertouch + cAftertouch; + } + + MIDI::MidiPolyPressure getPolyPressure() const { + MIDI::MidiPolyPressure cPolyPressure; + for(auto cn : getConnectedModNodes()){ + cPolyPressure += cn.lock()->getPolyPressure(); + } + return midiPolyPressure + cPolyPressure; + } + + std::vector> getConnectedModNodes() const { // TODO: check for cyclic connections of config nodes (crashes) + auto config_conns = connections | RANGE_FILTER([](EDGES::SPTR_Edge c){ return c->start.lock()->getNodeType() == NodeType::CONFIGNODE || c->end.lock()->getNodeType() == NodeType::CONFIGNODE;}) | std::ranges::to>>(); + std::vector> config_nodes; + for(auto e : config_conns){ + if(e->start.lock().get() != this && e->start.lock()->getNodeType() == NodeType::CONFIGNODE) config_nodes.push_back(std::dynamic_pointer_cast(e->start.lock())); + //if(e->end.lock().get() != this && e->end.lock()->getNodeType() == NodeType::CONFIGNODE) config_nodes.push_back(std::dynamic_pointer_cast(e->end.lock())); + } + /*std::cout << "id: " << id << " n cn: " << config_nodes.size() << std::endl;*/ + return config_nodes; + } + + std::vector> getConnectedMidiNodes() const { + auto config_conns = connections | RANGE_FILTER([](EDGES::SPTR_Edge c){ return c->start.lock()->getNodeType() == NodeType::MIDINODE || c->end.lock()->getNodeType() == NodeType::MIDINODE;}) | std::ranges::to>>(); + std::vector> config_nodes; + for(auto e : config_conns){ + if(e->start.lock().get() != this && e->start.lock()->getNodeType() == NodeType::MIDINODE) config_nodes.push_back(std::dynamic_pointer_cast(e->start.lock())); + if(e->end.lock().get() != this && e->end.lock()->getNodeType() == NodeType::MIDINODE) config_nodes.push_back(std::dynamic_pointer_cast(e->end.lock())); + } + /*std::cout << "id: " << id << " n cn: " << config_nodes.size() << std::endl;*/ + return config_nodes; + } + + void update() override { + Node::update(); + mode = state->node_mode; + } + + void interact(){ + float wheel = GetMouseWheelMove(); + + if(KEYS_DOWN.ctrl && !KEYS_DOWN.alt){ + switch(state->node_mode){ + case 0:{ + midiNote.note += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel; + break;} + case 1:{ + midiCC.value += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel; + break;} + case 2:{ + midiPitchBend.value += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel; + break;} + }; + + if(midiNote.note < -127 ) midiNote.note = -127; + if(midiNote.note > 127 ) midiNote.note = 127; + + if(midiCC.value < -127 ) midiCC.value = -127; + if(midiCC.value > 127 ) midiCC.value = 127; + + if(midiPitchBend.value < -16383 ) midiPitchBend.value = -16383; + if(midiPitchBend.value > 16383 ) midiPitchBend.value = 16383; + + } else if(KEYS_DOWN.alt) { + switch(state->node_mode){ + case 0:{ + midiNote.channel += wheel; + if(midiNote.channel < 0 ) midiNote.channel = 0; + if(midiNote.channel > 15) midiNote.channel = 15; + break;} + case 1:{ + midiCC.channel += wheel; + if(midiCC.channel < 0 ) midiCC.channel = 0; + if(midiCC.channel > 15 ) midiCC.channel = 15; + break;} + case 2:{ + midiPitchBend.channel += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 100 : wheel; + if(midiPitchBend.channel < 0 ) midiPitchBend.channel = 0; + if(midiPitchBend.channel > 15 ) midiPitchBend.channel = 15; + break;} + }; + } + } + + void draw(Vec2Df mouse, Camera2D cam) override { + Node::draw(); + if(hovering() || selected) interact(); + + DrawRing(position, radius, radius+4, 0, 360, 24, (Color){60, 60, 60, 255}); + DrawCircleLinesV(position, radius + 4, (Color){100, 100, 100, 255}); + + Color gate_color = VS_COLOR_GREEN; + + switch(mode){ + case 0:{ + gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){180, 210, 115 + 70, (unsigned char)Clamp(255, 0, 255)}, WHITE); + break;} + case 1:{ + gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){229, 181, 103 + 70, (unsigned char)Clamp(255, 0, 255)}, WHITE); + break;} + case 2:{ + gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){232, 125, 62 + 70, (unsigned char)Clamp(255, 0, 255)}, WHITE); + break;} + } + if(!picked_up && !selected && !in_selection_rect && !hovering()) DrawCircle(position.x, position.y, radius, gate_color); + if(picked_up || in_selection_rect || hovering()) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); + if(selected) DrawCircle(position.x, position.y, radius, (Color){255, 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(KEYS_DOWN.alt){ + float value = 0; + int offset_gate = 0; + switch(mode){ + case 0: + value = (float)getNotes().channel; + 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, VS_COLOR_BLACK ); + break; + case 1: + value = (float)getCC().channel; + 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, VS_COLOR_BLACK ); + break; + case 2: + value = (float)getPC().channel; + 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, VS_COLOR_BLACK ); + break; + case 3: + value = (float)getPitchBend().channel; + 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, VS_COLOR_BLACK ); + break; + case 4: + value = (float)getAftertouch().channel; + 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, VS_COLOR_BLACK ); + break; + case 5: + value = (float)getPolyPressure().channel; + 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, VS_COLOR_BLACK ); + break; + } + } else { + switch(mode){ + case 0:{ + int offset = MeasureText(std::format("{:+}", getNotes().note).c_str(), 12); + DrawText(std::format("{:+}", getNotes().note).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + break;} + case 1:{ + int offset = MeasureText(std::format("{:+}", getCC().value).c_str(), 12); + DrawText(std::format("{:+}", getCC().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + break;} + case 2:{ + int offset = MeasureText(std::format("{:+}", getPC().value).c_str(), 12); + DrawText(std::format("{:+}", getPC().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + break;} + case 3:{ + int offset = MeasureText(std::format("{:+}", getPitchBend().value).c_str(), 12); + DrawText(std::format("{:+}", getPitchBend().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + break;} + case 4:{ + int offset = MeasureText(std::format("{:+}", getAftertouch().value).c_str(), 12); + DrawText(std::format("{:+}", getAftertouch().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + break;} + case 5:{ + int offset = MeasureText(std::format("{:+}", getPolyPressure().value).c_str(), 12); + DrawText(std::format("{:+}", getPolyPressure().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); + break;} + } + } + + if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200}); + //DrawText(std::format("{}", id).c_str(), position.x + 20.0f, position.y + 20.0f, 10, WHITE); + } + + friend void to_json(json& j, const ModNode& N){ + std::vector conns; + std::ranges::transform(N.connections.begin(), N.connections.end(), std::back_inserter(conns), [](VISEQ::GRAPH::EDGES::SPTR_Edge e){ return e->id;}); + + j = json{ + {"id", N.id}, + {"position", N.position}, + {"distributionMode", N.distributionMode}, + {"nodeType", N.nodeType}, + {"midi_note_channel",N.midiNote.channel}, + {"midi_note_note",N.midiNote.note}, + {"midi_note_velocity",N.midiNote.velocity}, + {"midi_note_gate",N.midiNote.gate}, + {"midi_cc_channel",N.midiCC.channel}, + {"midi_cc_control",N.midiCC.control}, + {"midi_cc_value",N.midiCC.value}, + {"midi_pc_channel",N.midiPC.channel}, + {"midi_pc_program",N.midiPC.program}, + {"midi_pc_value",N.midiPC.value}, + {"midi_pitch_bend_channel",N.midiPitchBend.channel}, + {"midi_pitch_bend_value",N.midiPitchBend.value}, + {"midi_aftertouch_channel",N.midiAftertouch.channel}, + {"midi_aftertouch_value",N.midiAftertouch.value}, + {"midi_polypressure_channel",N.midiPolyPressure.channel}, + {"midi_polypressure_value",N.midiPolyPressure.value}, + {"connections",conns}}; + } + + friend void from_json(const json& j, ModNode& N){ + std::cout << "configNode from_json" << std::endl; + + j.at("id").get_to(N.id); + j.at("position").get_to(N.position); + j.at("distributionMode").get_to(N.distributionMode); + j.at("nodeType").get_to(N.nodeType); + j.at("midi_note_channel").get_to(N.midiNote.channel); + j.at("midi_note_note").get_to(N.midiNote.note); + j.at("midi_note_velocity").get_to(N.midiNote.velocity); + j.at("midi_note_gate").get_to(N.midiNote.gate); + j.at("midi_cc_channel").get_to(N.midiCC.channel); + j.at("midi_cc_control").get_to(N.midiCC.control); + j.at("midi_cc_value").get_to(N.midiCC.value); + j.at("midi_pc_channel").get_to(N.midiPC.channel); + j.at("midi_pc_program").get_to(N.midiPC.program); + j.at("midi_pc_value").get_to(N.midiPC.value); + j.at("midi_pitch_bend_channel").get_to(N.midiPitchBend.channel); + j.at("midi_pitch_bend_value").get_to(N.midiPitchBend.value); + j.at("midi_aftertouch_channel").get_to(N.midiAftertouch.channel); + j.at("midi_aftertouch_value").get_to(N.midiAftertouch.value); + j.at("midi_polypressure_channel").get_to(N.midiPolyPressure.channel); + j.at("midi_polypressure_value").get_to(N.midiPolyPressure.value); + + //j.at("connections").get_to(N.connections); + } + }; +} diff --git a/src/signal-manager.h b/src/signal-manager.h index bb0e6e7..92aa129 100644 --- a/src/signal-manager.h +++ b/src/signal-manager.h @@ -73,7 +73,7 @@ namespace VISEQ::SIGNAL { void addSignalAtNode(WPTR_Node node){ Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200}; - signals.emplace_back(std::make_shared(node.lock()->position + Vec2Df{0.5f, 0.5f}, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea! + signals.emplace_back(std::make_shared(node.lock()->position + Vec2Df{0.5f, 0.5f}, 8.0f, 480, c)); // position + 1 or else it does not render. why? no idea! signals.back()->next = node; signals.back()->last = node; signals.back()->start = node; diff --git a/src/ui.h b/src/ui.h index 61c0300..910c604 100644 --- a/src/ui.h +++ b/src/ui.h @@ -103,7 +103,7 @@ namespace VISEQ::APP::UI{ if(state->node_mode == i) col = VS_COLOR_SUN; Vec2Df pos = {state->settings.width - (6.0f*75.0f) + i*75.0f, state->settings.height - 75.0f}; DrawCircleV(pos, 30.0f, col); - DrawCenteredText(shorts[i], pos, 20, VS_COLOR_BLACK); + DrawCenteredText(shorts[i], pos, 20, WHITE); } }