Browse Source

Clean up RackWidget. Use Module::id for referencing modules in patches.

tags/v1.0.0
Andrew Belt 6 years ago
parent
commit
788fe92856
7 changed files with 141 additions and 85 deletions
  1. +1
    -0
      include/engine/Engine.hpp
  2. +6
    -15
      include/engine/Module.hpp
  3. +1
    -1
      src/app/ModuleWidget.cpp
  4. +99
    -67
      src/app/RackWidget.cpp
  5. +1
    -1
      src/app/WireContainer.cpp
  6. +11
    -1
      src/engine/Engine.cpp
  7. +22
    -0
      src/engine/Module.cpp

+ 1
- 0
include/engine/Engine.hpp View File

@@ -35,6 +35,7 @@ struct Engine {
void removeWire(Wire *wire);
void setParam(Module *module, int paramId, float value);
void setParamSmooth(Module *module, int paramId, float value);
int getNextModuleId();

void setSampleRate(float sampleRate);
float getSampleRate();


+ 6
- 15
include/engine/Module.hpp View File

@@ -13,32 +13,23 @@ namespace rack {


struct Module {
int id = -1;
std::vector<Param> params;
std::vector<Input> inputs;
std::vector<Output> outputs;
std::vector<Light> lights;
/** For CPU usage meter */
/** For power meter */
float cpuTime = 0.f;

/** Constructs a Module with no params, inputs, outputs, and lights */
Module() {}
/** Constructs a Module with a fixed number of params, inputs, outputs, and lights */
Module(int numParams, int numInputs, int numOutputs, int numLights = 0) {
Module();
/** Deprecated. Use setup() instead. */
Module(int numParams, int numInputs, int numOutputs, int numLights = 0) : Module() {
setup(numParams, numInputs, numOutputs, numLights);
}
virtual ~Module() {}

void setup(int numParams, int numInputs, int numOutputs, int numLights = 0) {
params.resize(numParams);
// Create default param labels
for (int i = 0; i < numParams; i++) {
params[i].label = string::f("#%d", i + 1);
}
inputs.resize(numInputs);
outputs.resize(numOutputs);
lights.resize(numLights);
}

void setup(int numParams, int numInputs, int numOutputs, int numLights = 0);
json_t *toJson();
void fromJson(json_t *rootJ);
void reset();


+ 1
- 1
src/app/ModuleWidget.cpp View File

@@ -337,7 +337,7 @@ void ModuleWidget::onButton(event::Button &e) {
}

void ModuleWidget::onHoverKey(event::HoverKey &e) {
if (e.action == GLFW_PRESS) {
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
switch (e.key) {
case GLFW_KEY_I: {
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) {


+ 99
- 67
src/app/RackWidget.cpp View File

@@ -81,14 +81,23 @@ void RackWidget::loadDialog() {
else {
dir = string::directory(lastPath);
}

osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str());
DEFER({
osdialog_filters_free(filters);
});

char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, filters);
if (path) {
load(path);
lastPath = path;
free(path);
if (!path) {
// Fail silently
return;
}
osdialog_filters_free(filters);
DEFER({
free(path);
});

load(path);
lastPath = path;
}

void RackWidget::saveDialog() {
@@ -111,21 +120,29 @@ void RackWidget::saveAsDialog() {
dir = string::directory(lastPath);
filename = string::filename(lastPath);
}

osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str());
char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), filename.c_str(), filters);
DEFER({
osdialog_filters_free(filters);
});

if (path) {
std::string pathStr = path;
char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), filename.c_str(), filters);
if (!path) {
// Fail silently
return;
}
DEFER({
free(path);
std::string extension = string::extension(pathStr);
if (extension.empty()) {
pathStr += ".vcv";
}
});


save(pathStr);
lastPath = pathStr;
std::string pathStr = path;
if (string::extension(pathStr).empty()) {
pathStr += ".vcv";
}
osdialog_filters_free(filters);

save(pathStr);
lastPath = pathStr;
}

void RackWidget::save(std::string filename) {
@@ -133,14 +150,20 @@ void RackWidget::save(std::string filename) {
json_t *rootJ = toJson();
if (!rootJ)
return;
DEFER({
json_decref(rootJ);
});

FILE *file = fopen(filename.c_str(), "w");
if (file) {
json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
fclose(file);
if (!file) {
// Fail silently
return;
}
DEFER({
fclose(file);
});

json_decref(rootJ);
json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
}

void RackWidget::load(std::string filename) {
@@ -150,20 +173,23 @@ void RackWidget::load(std::string filename) {
// Exit silently
return;
}
DEFER({
fclose(file);
});

json_error_t error;
json_t *rootJ = json_loadf(file, 0, &error);
if (rootJ) {
clear();
fromJson(rootJ);
json_decref(rootJ);
}
else {
if (!rootJ) {
std::string message = string::f("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
return;
}
DEFER({
json_decref(rootJ);
});

fclose(file);
clear();
fromJson(rootJ);
}

void RackWidget::revert() {
@@ -178,11 +204,7 @@ void RackWidget::disconnect() {
if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "Remove all patch cables?"))
return;

for (Widget *w : moduleContainer->children) {
ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
assert(moduleWidget);
moduleWidget->disconnect();
}
wireContainer->removeAllWires(NULL);
}

json_t *RackWidget::toJson() {
@@ -195,16 +217,14 @@ json_t *RackWidget::toJson() {

// modules
json_t *modulesJ = json_array();
std::map<ModuleWidget*, int> moduleIds;
int moduleId = 0;
for (Widget *w : moduleContainer->children) {
ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
assert(moduleWidget);
moduleIds[moduleWidget] = moduleId;
moduleId++;
// module
json_t *moduleJ = moduleWidget->toJson();
{
// id
json_object_set_new(moduleJ, "id", json_integer(moduleWidget->module->id));
// pos
math::Vec pos = moduleWidget->box.pos.div(RACK_GRID_SIZE).round();
json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
@@ -219,29 +239,22 @@ json_t *RackWidget::toJson() {
for (Widget *w : wireContainer->children) {
WireWidget *wireWidget = dynamic_cast<WireWidget*>(w);
assert(wireWidget);

Port *outputPort = wireWidget->outputPort;
Port *inputPort = wireWidget->inputPort;
// Only serialize WireWidgets connected on both ends
if (!(wireWidget->outputPort && wireWidget->inputPort))
if (!(outputPort && inputPort))
continue;
// wire
json_t *wire = wireWidget->toJson();

// Get the modules at each end of the wire
ModuleWidget *outputModuleWidget = wireWidget->outputPort->getAncestorOfType<ModuleWidget>();
assert(outputModuleWidget);
int outputModuleId = moduleIds[outputModuleWidget];
assert(outputPort->module);
assert(inputPort->module);

ModuleWidget *inputModuleWidget = wireWidget->inputPort->getAncestorOfType<ModuleWidget>();
assert(inputModuleWidget);
int inputModuleId = moduleIds[inputModuleWidget];

// Get output/input ports
int outputId = wireWidget->outputPort->portId;
int inputId = wireWidget->inputPort->portId;

json_object_set_new(wire, "outputModuleId", json_integer(outputModuleId));
json_object_set_new(wire, "outputId", json_integer(outputId));
json_object_set_new(wire, "inputModuleId", json_integer(inputModuleId));
json_object_set_new(wire, "inputId", json_integer(inputId));
json_object_set_new(wire, "outputModuleId", json_integer(outputPort->module->id));
json_object_set_new(wire, "outputId", json_integer(outputPort->portId));
json_object_set_new(wire, "inputModuleId", json_integer(inputPort->module->id));
json_object_set_new(wire, "inputId", json_integer(inputPort->portId));

json_array_append_new(wires, wire);
}
@@ -256,8 +269,10 @@ void RackWidget::fromJson(json_t *rootJ) {
// version
std::string version;
json_t *versionJ = json_object_get(rootJ, "version");
if (versionJ) {
if (versionJ)
version = json_string_value(versionJ);
if (version != APP_VERSION) {
INFO("Patch made with Rack version %s, current Rack version is %s", version.c_str(), APP_VERSION.c_str());
}

// Detect old patches with ModuleWidget::params/inputs/outputs indices.
@@ -266,17 +281,21 @@ void RackWidget::fromJson(json_t *rootJ) {
if (string::startsWith(version, "0.3.") || string::startsWith(version, "0.4.") || string::startsWith(version, "0.5.") || version == "" || version == "dev") {
legacy = 1;
}
else if (string::startsWith(version, "0.6.")) {
legacy = 2;
}
if (legacy) {
INFO("Loading patch using legacy mode %d", legacy);
}

// modules
std::map<int, ModuleWidget*> moduleWidgets;
json_t *modulesJ = json_object_get(rootJ, "modules");
if (!modulesJ) return;
size_t moduleId;
if (!modulesJ)
return;
std::map<int, ModuleWidget*> moduleWidgets;
size_t moduleIndex;
json_t *moduleJ;
json_array_foreach(modulesJ, moduleId, moduleJ) {
json_array_foreach(modulesJ, moduleIndex, moduleJ) {
// Add "legacy" property if in legacy mode
if (legacy) {
json_object_set(moduleJ, "legacy", json_integer(legacy));
@@ -285,19 +304,32 @@ void RackWidget::fromJson(json_t *rootJ) {
ModuleWidget *moduleWidget = moduleFromJson(moduleJ);

if (moduleWidget) {
// id
json_t *idJ = json_object_get(moduleJ, "id");
int id = -1;
if (idJ)
id = json_integer_value(idJ);
// pos
json_t *posJ = json_object_get(moduleJ, "pos");
double x, y;
json_unpack(posJ, "[F, F]", &x, &y);
math::Vec pos = math::Vec(x, y);
if (legacy && legacy <= 1) {
// Before 0.6, positions were in pixel units
moduleWidget->box.pos = pos;
}
else {
moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
}

moduleWidgets[moduleId] = moduleWidget;
if (legacy && legacy <= 2) {
// Before 1.0, the module ID was the index in the "modules" array
moduleWidgets[moduleIndex] = moduleWidget;
}
else {
moduleWidgets[id] = moduleWidget;
}
addModule(moduleWidget);
}
else {
json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
@@ -310,10 +342,10 @@ void RackWidget::fromJson(json_t *rootJ) {

// wires
json_t *wiresJ = json_object_get(rootJ, "wires");
if (!wiresJ) return;
size_t wireId;
assert(wiresJ);
size_t wireIndex;
json_t *wireJ;
json_array_foreach(wiresJ, wireId, wireJ) {
json_array_foreach(wiresJ, wireIndex, wireJ) {
int outputModuleId = json_integer_value(json_object_get(wireJ, "outputModuleId"));
int outputId = json_integer_value(json_object_get(wireJ, "outputId"));
int inputModuleId = json_integer_value(json_object_get(wireJ, "inputModuleId"));
@@ -329,8 +361,7 @@ void RackWidget::fromJson(json_t *rootJ) {
Port *outputPort = NULL;
Port *inputPort = NULL;
if (legacy && legacy <= 1) {
// Legacy 1 mode
// The index of the "ports" array is the index of the Port in the `outputs` and `inputs` vector.
// Before 0.6, the index of the "ports" array was the index of the Port in the `outputs` and `inputs` vector.
outputPort = outputModuleWidget->outputs[outputId];
inputPort = inputModuleWidget->inputs[inputId];
}
@@ -387,7 +418,6 @@ ModuleWidget *RackWidget::moduleFromJson(json_t *moduleJ) {
ModuleWidget *moduleWidget = model->createModuleWidget();
assert(moduleWidget);
moduleWidget->fromJson(moduleJ);
moduleContainer->addChild(moduleWidget);
return moduleWidget;
}

@@ -402,12 +432,12 @@ void RackWidget::pastePresetClipboard() {
json_t *moduleJ = json_loads(moduleJson, 0, &error);
if (moduleJ) {
ModuleWidget *moduleWidget = moduleFromJson(moduleJ);
json_decref(moduleJ);
addModule(moduleWidget);
// Set moduleWidget position
math::Rect newBox = moduleWidget->box;
newBox.pos = lastMousePos.minus(newBox.size.div(2));
requestModuleBoxNearest(moduleWidget, newBox);

json_decref(moduleJ);
}
else {
WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
@@ -427,6 +457,7 @@ void RackWidget::cloneModule(ModuleWidget *m) {
json_t *moduleJ = m->toJson();
ModuleWidget *clonedModuleWidget = moduleFromJson(moduleJ);
json_decref(moduleJ);
addModule(clonedModuleWidget);
math::Rect clonedBox = clonedModuleWidget->box;
clonedBox.pos = m->box.pos;
requestModuleBoxNearest(clonedModuleWidget, clonedBox);
@@ -491,7 +522,8 @@ void RackWidget::step() {
}

// Autosave every 15 seconds
if (context()->window->frame % (60 * 15) == 0) {
int frame = context()->window->frame;
if (frame > 0 && frame % (60 * 15) == 0) {
save(asset::user("autosave.vcv"));
settings::save(asset::user("settings.json"));
}


+ 1
- 1
src/app/WireContainer.cpp View File

@@ -64,7 +64,7 @@ void WireContainer::removeAllWires(Port *port) {
for (Widget *child : children) {
WireWidget *wire = dynamic_cast<WireWidget*>(child);
assert(wire);
if (wire->inputPort == port || wire->outputPort == port) {
if (!wire || wire->inputPort == port || wire->outputPort == port) {
if (activeWire == wire) {
activeWire = NULL;
}


+ 11
- 1
src/engine/Engine.cpp View File

@@ -52,6 +52,7 @@ struct Engine::Internal {

Module *resetModule = NULL;
Module *randomizeModule = NULL;
int nextModuleId = 0;

// Parameter smoothing
Module *smoothModule = NULL;
@@ -216,6 +217,9 @@ void Engine::addModule(Module *module) {
assert(module);
VIPLock vipLock(internal->vipMutex);
std::lock_guard<std::mutex> lock(internal->mutex);
// Set ID
assert(module->id == -1);
module->id = internal->nextModuleId++;
// Check that the module is not already added
auto it = std::find(modules.begin(), modules.end(), module);
assert(it == modules.end());
@@ -238,8 +242,10 @@ void Engine::removeModule(Module *module) {
// Check that the module actually exists
auto it = std::find(modules.begin(), modules.end(), module);
assert(it != modules.end());
// Remove it
// Remove the module
modules.erase(it);
// Remove id
module->id = -1;
}

void Engine::resetModule(Module *module) {
@@ -313,6 +319,10 @@ void Engine::setParamSmooth(Module *module, int paramId, float value) {
internal->smoothModule = module;
}

int Engine::getNextModuleId() {
return internal->nextModuleId++;
}

void Engine::setSampleRate(float newSampleRate) {
internal->sampleRateRequested = newSampleRate;
}


+ 22
- 0
src/engine/Module.cpp View File

@@ -4,9 +4,26 @@
namespace rack {


Module::Module() {
}

void Module::setup(int numParams, int numInputs, int numOutputs, int numLights) {
params.resize(numParams);
// Create default param labels
for (int i = 0; i < numParams; i++) {
params[i].label = string::f("#%d", i + 1);
}
inputs.resize(numInputs);
outputs.resize(numOutputs);
lights.resize(numLights);
}

json_t *Module::toJson() {
json_t *rootJ = json_object();

// id
json_object_set_new(rootJ, "id", json_integer(id));

// params
json_t *paramsJ = json_array();
for (Param &param : params) {
@@ -25,6 +42,11 @@ json_t *Module::toJson() {
}

void Module::fromJson(json_t *rootJ) {
// id
json_t *idJ = json_object_get(rootJ, "id");
if (idJ)
id = json_integer_value(idJ);

// params
json_t *paramsJ = json_object_get(rootJ, "params");
size_t i;


Loading…
Cancel
Save