2024-10-25 16:41:37 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
2024-11-01 02:38:47 +01:00
|
|
|
#include "midi-node.h"
|
2024-10-30 14:55:24 +01:00
|
|
|
#include "raylib.h"
|
2024-10-25 16:41:37 +02:00
|
|
|
#include "raygui/raygui.h"
|
|
|
|
|
#include "raygui/dark/style_dark.h"
|
|
|
|
|
|
|
|
|
|
#include "datatypes.h"
|
2024-10-30 14:55:24 +01:00
|
|
|
#include "graph-manager.h"
|
2024-10-25 16:41:37 +02:00
|
|
|
#include "signal-manager.h"
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-01 02:38:47 +01:00
|
|
|
#include <memory>
|
2024-10-25 16:41:37 +02:00
|
|
|
#include <ranges>
|
2024-11-04 01:00:59 +01:00
|
|
|
#include <set>
|
2024-10-25 16:41:37 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
namespace VISEQ::APP::UI{
|
|
|
|
|
class AppUI{
|
|
|
|
|
public:
|
|
|
|
|
AppUI() {}
|
|
|
|
|
AppUI(AppSettings *settings, SIGNAL::SignalManager *sm, GraphManager *gm) : settings(settings), gm(gm), sm(sm) {}
|
|
|
|
|
|
|
|
|
|
AppSettings *settings;
|
|
|
|
|
GraphManager *gm;
|
|
|
|
|
SIGNAL::SignalManager *sm;
|
|
|
|
|
|
2024-11-04 01:00:59 +01:00
|
|
|
bool bpm_spinner_edit_mode = false;
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void init(){
|
|
|
|
|
GuiLoadStyleDark();
|
2024-10-29 00:50:39 +01:00
|
|
|
}
|
2024-10-25 16:41:37 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void drawSideBar(){
|
|
|
|
|
|
|
|
|
|
GuiPanel((Rectangle){-1,-30,280,(float)settings->height + 31}, "");
|
|
|
|
|
const int s_controls = 25;
|
|
|
|
|
//GuiSetStyle(BUTTON, STATE_FOCUSED, 0xFF0000FF);
|
|
|
|
|
if(GuiButton((Rectangle){20, (float)s_controls, 80, 30}, "PLAY")) sm->play ? sm->pause() : sm->start();
|
|
|
|
|
if(GuiButton((Rectangle){120, (float)s_controls, 60, 30}, "STOP")) sm->stop();
|
|
|
|
|
if(GuiButton((Rectangle){200, (float)s_controls, 60, 30}, "RESET")) sm->reset();
|
|
|
|
|
|
|
|
|
|
const int s_bpm = s_controls + 45;
|
|
|
|
|
GuiLabel((Rectangle){20, (float)s_bpm, 120, 20}, "TIMING");
|
|
|
|
|
GuiLabel((Rectangle){200, (float)s_bpm, 40, 20}, std::format("{}",settings->bpm).c_str());
|
2024-11-04 01:00:59 +01:00
|
|
|
int _bpm = settings->bpm;
|
|
|
|
|
// GuiSlider((Rectangle){20, (float)s_bpm + 25, 240, 20}, "", "", &_bpm, 1, 300);
|
|
|
|
|
if(GuiSpinner((Rectangle){20, (float)s_bpm + 25, 240, 20}, "", &_bpm, 1, 300, bpm_spinner_edit_mode)) bpm_spinner_edit_mode = !bpm_spinner_edit_mode;
|
2024-11-03 03:48:49 +01:00
|
|
|
settings->bpm = _bpm;
|
|
|
|
|
|
|
|
|
|
int s_midi = s_bpm + 75;
|
|
|
|
|
GuiLabel((Rectangle){20, (float)s_midi, 240, 20}, "MIDI OUT");
|
|
|
|
|
if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate();
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
for(auto& mo : sm->midi.midi_out_ports){
|
|
|
|
|
GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, mo.port.port_name.substr(0,32).c_str(), &mo.enabled);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(GuiButton((Rectangle){20, (float)s_midi + 45 + i*20.0f, 240, 20}, "ENABLE FOR ALL")) {
|
|
|
|
|
for(auto &midis : sm->midi.midi_out_ports){
|
|
|
|
|
if(midis.enabled){
|
|
|
|
|
for(auto n : gm->nodes){
|
|
|
|
|
if(n->getNodeType() == NodeType::MIDINODE) std::dynamic_pointer_cast<MidiNode>(n)->setMidiPort(midis.number, true);
|
|
|
|
|
}
|
2024-10-25 16:41:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
int s_signal = s_midi + 100 + i*20;
|
|
|
|
|
GuiLabel((Rectangle){20, (float)s_signal, 240, 20}, "SIGNALS");
|
|
|
|
|
if(GuiButton((Rectangle){20, (float)s_signal + 35, 240, 20}, "ADD RANDOM SIGNAL")){
|
|
|
|
|
std::shared_ptr<Node> ni = gm->getRandomNode();
|
|
|
|
|
sm->addSignalAtNode(ni);
|
|
|
|
|
}
|
2024-10-25 16:41:37 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
int signal_configs = 0;
|
|
|
|
|
for(auto &s : sm->signals){
|
2024-11-04 01:00:59 +01:00
|
|
|
if(GuiButton((Rectangle){20,(float)s_signal+70 + signal_configs*20, 20, 20},"X")) sm->removeSignal(s);
|
2024-11-03 03:48:49 +01:00
|
|
|
DrawCircle(55, s_signal+80 + signal_configs*20, 6.0F, s->color);
|
2024-11-04 01:00:59 +01:00
|
|
|
float s_speed = round(s->speed);
|
|
|
|
|
s->multiplier = settings->bpm / 120.0f;
|
|
|
|
|
float signal_bpm = round(settings->bpm * s->multiplier * (s->speed / settings->speed));
|
|
|
|
|
GuiSlider((Rectangle){70, (float)s_signal+70 + signal_configs*20, 120, 20}, "", "", &s_speed, 1.0f, 16.0f * settings->grid * 4);
|
|
|
|
|
GuiLabel((Rectangle){195, (float)s_signal+70 + signal_configs*20, 30, 20}, std::format("{}",signal_bpm).c_str());
|
|
|
|
|
GuiToggle((Rectangle){240, (float)s_signal+70 + signal_configs*20, 20, 20},"P", &s->run);
|
|
|
|
|
s->speed = s_speed;
|
2024-11-03 03:48:49 +01:00
|
|
|
signal_configs++;
|
2024-10-25 16:41:37 +02:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
int s_nodes = s_signal + 70 + signal_configs*20;
|
|
|
|
|
GuiLabel((Rectangle){20, (float)s_nodes + 30, 240, 20}, "NODES");
|
|
|
|
|
if(GuiButton((Rectangle){20, (float)s_nodes + 60, 240, 20}, "ADD RANDOM NODE")){
|
|
|
|
|
gm->addMidiNode(Vec2Df{200.0f, 200.0f});
|
|
|
|
|
}
|
|
|
|
|
DrawText(std::format("{}", gm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE);
|
|
|
|
|
DrawFPS(20, settings->height - 30);
|
2024-11-05 00:51:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void drawPropertiesBar(){
|
|
|
|
|
|
|
|
|
|
float left = settings->width - 280.f;
|
|
|
|
|
|
|
|
|
|
GuiPanel((Rectangle){left,-30,280,(float)settings->height + 31}, "");
|
|
|
|
|
const int s_controls = 25;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
}
|
2024-10-25 16:41:37 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void drawPerNodeConfig(Camera2D *camera){
|
|
|
|
|
for(auto& n : gm->nodes | std::views::filter([](std::shared_ptr<Node> 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");
|
2024-10-25 16:41:37 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
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);
|
2024-11-01 02:38:47 +01:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
int y_midi = 120;
|
|
|
|
|
GuiLabel((Rectangle){np.x + 20, np.y + y_midi, 220, 20}, "MIDI OUT");
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
if(n->getNodeType() == NodeType::MIDINODE){
|
|
|
|
|
std::shared_ptr<MidiNode> mn = std::dynamic_pointer_cast<MidiNode>(n);
|
|
|
|
|
for(auto& mo : mn->midi_outs){
|
|
|
|
|
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);
|
2024-11-01 02:38:47 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
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);
|
2024-11-01 02:38:47 +01:00
|
|
|
break;}
|
2024-11-03 03:48:49 +01:00
|
|
|
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;}
|
|
|
|
|
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;}
|
|
|
|
|
}
|
2024-11-01 02:38:47 +01:00
|
|
|
}
|
2024-10-30 02:00:40 +01:00
|
|
|
}
|
2024-10-25 16:41:37 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void draw(Vec2Df *mouse_pos, Camera2D *camera){
|
|
|
|
|
drawSideBar();
|
2024-11-05 00:51:25 +01:00
|
|
|
drawPropertiesBar();
|
2024-11-03 03:48:49 +01:00
|
|
|
drawPerNodeConfig(camera);
|
|
|
|
|
}
|
2024-10-25 16:41:37 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
};
|
|
|
|
|
}
|