Browse Source

Implement RackWidget::copyClipboardSelectedModules(). Clean up RackWidget API.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
aaf98bb16d
8 changed files with 163 additions and 104 deletions
  1. +1
    -0
      include/app/CableWidget.hpp
  2. +7
    -7
      include/app/RackWidget.hpp
  3. +4
    -0
      src/app/CableWidget.cpp
  4. +34
    -45
      src/app/ModuleWidget.cpp
  5. +1
    -2
      src/app/PortWidget.cpp
  6. +81
    -29
      src/app/RackWidget.cpp
  7. +35
    -19
      src/app/Scene.cpp
  8. +0
    -2
      src/engine/Engine.cpp

+ 1
- 0
include/app/CableWidget.hpp View File

@@ -39,6 +39,7 @@ struct CableWidget : widget::Widget {
Adopts ownership.
*/
void setCable(engine::Cable* cable);
engine::Cable* getCable();
math::Vec getInputPos();
math::Vec getOutputPos();
json_t* toJson();


+ 7
- 7
include/app/RackWidget.hpp View File

@@ -1,6 +1,4 @@
#pragma once
#include <map>

#include <app/common.hpp>
#include <widget/OpaqueWidget.hpp>
#include <widget/FramebufferWidget.hpp>
@@ -49,7 +47,7 @@ struct RackWidget : widget::OpaqueWidget {
void clear();
void mergeJson(json_t* rootJ);
void fromJson(json_t* rootJ);
void pastePresetClipboardAction();
void pasteClipboardAction();

// Module methods

@@ -66,7 +64,7 @@ struct RackWidget : widget::OpaqueWidget {
void setModulePosNearest(ModuleWidget* mw, math::Vec pos);
void setModulePosForce(ModuleWidget* mw, math::Vec pos);
ModuleWidget* getModule(int64_t moduleId);
std::list<ModuleWidget*> getModules();
std::vector<ModuleWidget*> getModules();
bool hasModules();
void updateModuleOldPositions();
history::ComplexAction* getModuleDragAction();
@@ -78,13 +76,15 @@ struct RackWidget : widget::OpaqueWidget {
void selectAllModules();
bool hasSelectedModules();
int getNumSelectedModules();
std::list<ModuleWidget*> getSelectedModules();
std::vector<ModuleWidget*> getSelectedModules();
json_t* selectedModulesToJson();
void resetSelectedModulesAction();
void randomizeSelectedModulesAction();
void disconnectSelectedModulesAction();
void cloneSelectedModulesAction();
void bypassSelectedModulesAction(bool bypassed);
bool areSelectedModulesBypassed();
void copyClipboardSelectedModules();
void deleteSelectedModulesAction();
bool requestSelectedModulePos(math::Vec delta);
void setSelectedModulesPosNearest(math::Vec delta);
@@ -108,9 +108,9 @@ struct RackWidget : widget::OpaqueWidget {
/** Returns the most recently added complete cable connected to the given Port, i.e. the top of the stack. */
CableWidget* getTopCable(PortWidget* port);
CableWidget* getCable(int64_t cableId);
std::list<CableWidget*> getCompleteCables();
std::vector<CableWidget*> getCompleteCables();
/** Returns all cables attached to port, complete or not. */
std::list<CableWidget*> getCablesOnPort(PortWidget* port);
std::vector<CableWidget*> getCablesOnPort(PortWidget* port);
};




+ 4
- 0
src/app/CableWidget.cpp View File

@@ -185,6 +185,10 @@ void CableWidget::setCable(engine::Cable* cable) {
}
}

engine::Cable* CableWidget::getCable() {
return cable;
}

math::Vec CableWidget::getInputPos() {
if (inputPort) {
return inputPort->getRelativeOffset(inputPort->box.zeroPos().getCenter(), APP->scene->rack);


+ 34
- 45
src/app/ModuleWidget.cpp View File

@@ -318,24 +318,7 @@ void ModuleWidget::onHover(const HoverEvent& e) {
}

void ModuleWidget::onHoverKey(const HoverKeyEvent& e) {
OpaqueWidget::onHoverKey(e);
if (e.isConsumed())
return;

if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
if (e.keyName == "i" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
// Don't handle key commands if modules are selected, since it will interfere with Scene's module selection key commands
if (!APP->scene->rack->hasSelectedModules()) {
resetAction();
e.consume(this);
}
}
if (e.keyName == "r" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (!APP->scene->rack->hasSelectedModules()) {
randomizeAction();
e.consume(this);
}
}
if (e.keyName == "c" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
copyClipboard();
e.consume(this);
@@ -345,40 +328,42 @@ void ModuleWidget::onHoverKey(const HoverKeyEvent& e) {
e.consume(this);
}
if (e.keyName == "d" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (!APP->scene->rack->hasSelectedModules()) {
cloneAction();
e.consume(this);
}
cloneAction();
e.consume(this);
}
if ((e.key == GLFW_KEY_DELETE || e.key == GLFW_KEY_BACKSPACE) && (e.mods & RACK_MOD_MASK) == 0) {
removeAction();
e.consume(this);
}
if (e.keyName == "i" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
resetAction();
e.consume(this);
}
if (e.keyName == "r" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
randomizeAction();
e.consume(this);
}
if (e.keyName == "u" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (!APP->scene->rack->hasSelectedModules()) {
disconnectAction();
e.consume(this);
}
disconnectAction();
e.consume(this);
}
if (e.keyName == "e" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (!APP->scene->rack->hasSelectedModules()) {
bypassAction(!module->isBypassed());
e.consume(this);
}
}
if ((e.key == GLFW_KEY_DELETE || e.key == GLFW_KEY_BACKSPACE) && (e.mods & RACK_MOD_MASK) == 0) {
if (!APP->scene->rack->hasSelectedModules()) {
removeAction();
e.consume(this);
}
bypassAction(!module->isBypassed());
e.consume(this);
}
}

if (e.action == RACK_HELD) {
// Also handle Delete/Backspace when holding the key while hovering
if ((e.key == GLFW_KEY_DELETE || e.key == GLFW_KEY_BACKSPACE) && (e.mods & RACK_MOD_MASK) == 0) {
if (!APP->scene->rack->hasSelectedModules()) {
removeAction();
e.consume(NULL);
}
removeAction();
e.consume(NULL);
}
}

if (e.isConsumed())
return;
OpaqueWidget::onHoverKey(e);
}

void ModuleWidget::onButton(const ButtonEvent& e) {
@@ -1077,18 +1062,14 @@ void ModuleWidget::createContextMenu() {
weakThis->randomizeAction();
}));

// Disconnect cables
menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [=]() {
if (!weakThis)
return;
weakThis->disconnectAction();
}));

menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() {
if (!weakThis)
return;
weakThis->cloneAction();
}));

// Bypass
std::string bypassText = RACK_MOD_CTRL_NAME "+E";
bool bypassed = module && module->isBypassed();
if (bypassed)
@@ -1099,6 +1080,14 @@ void ModuleWidget::createContextMenu() {
weakThis->bypassAction(!bypassed);
}));

// Duplicate
menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() {
if (!weakThis)
return;
weakThis->cloneAction();
}));

// Delete
menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() {
if (!weakThis)
return;


+ 1
- 2
src/app/PortWidget.cpp View File

@@ -39,8 +39,7 @@ struct PortTooltip : ui::Tooltip {
text += string::f("% .3fV", math::normalizeZero(v));
}
// Connected to
std::list<CableWidget*> cables = APP->scene->rack->getCablesOnPort(portWidget);
for (CableWidget* cable : cables) {
for (CableWidget* cable : APP->scene->rack->getCablesOnPort(portWidget)) {
PortWidget* otherPw = (portWidget->type == engine::Port::INPUT) ? cable->outputPort : cable->inputPort;
if (!otherPw)
continue;


+ 81
- 29
src/app/RackWidget.cpp View File

@@ -138,15 +138,6 @@ void RackWidget::onHover(const HoverEvent& e) {

void RackWidget::onHoverKey(const HoverKeyEvent& e) {
OpaqueWidget::onHoverKey(e);
if (e.isConsumed())
return;

if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
pastePresetClipboardAction();
e.consume(this);
}
}
}

void RackWidget::onButton(const ButtonEvent& e) {
@@ -268,8 +259,8 @@ void RackWidget::mergeJson(json_t* rootJ) {
continue;
}

// Merge CableWidget JSON
json_t* cwJ = cw->toJson();
// Merge cable JSON object
json_object_update(cableJ, cwJ);
json_decref(cwJ);
}
@@ -368,7 +359,7 @@ void RackWidget::fromJson(json_t* rootJ) {
}
}

void RackWidget::pastePresetClipboardAction() {
void RackWidget::pasteClipboardAction() {
const char* moduleJson = glfwGetClipboardString(APP->window->win);
if (!moduleJson) {
WARN("Could not get text from clipboard.");
@@ -614,8 +605,8 @@ ModuleWidget* RackWidget::getModule(int64_t moduleId) {
return NULL;
}

std::list<ModuleWidget*> RackWidget::getModules() {
std::list<ModuleWidget*> mws;
std::vector<ModuleWidget*> RackWidget::getModules() {
std::vector<ModuleWidget*> mws;
for (widget::Widget* w : internal->moduleContainer->children) {
ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
assert(mw);
@@ -694,8 +685,8 @@ int RackWidget::getNumSelectedModules() {
return count;
}

std::list<ModuleWidget*> RackWidget::getSelectedModules() {
std::list<ModuleWidget*> mws;
std::vector<ModuleWidget*> RackWidget::getSelectedModules() {
std::vector<ModuleWidget*> mws;
for (widget::Widget* w : internal->moduleContainer->children) {
ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
assert(mw);
@@ -705,6 +696,49 @@ std::list<ModuleWidget*> RackWidget::getSelectedModules() {
return mws;
}

json_t* RackWidget::selectedModulesToJson() {
json_t* rootJ = json_object();

std::set<engine::Module*> modules;

// modules
json_t* modulesJ = json_array();
for (ModuleWidget* mw : getSelectedModules()) {
json_t* moduleJ = mw->toJson();
json_array_append_new(modulesJ, moduleJ);

modules.insert(mw->getModule());
}
json_object_set_new(rootJ, "modules", modulesJ);

// cables
json_t* cablesJ = json_array();
for (CableWidget* cw : getCompleteCables()) {
// Only add cables attached on both ends to selected modules
engine::Cable* cable = cw->getCable();
if (!cable || !cable->inputModule || !cable->outputModule)
continue;
const auto inputIt = modules.find(cable->inputModule);
if (inputIt == modules.end())
continue;
const auto outputIt = modules.find(cable->outputModule);
if (outputIt == modules.end())
continue;

json_t* cableJ = cable->toJson();

// Merge CableWidget JSON
json_t* cwJ = cw->toJson();
json_object_update(cableJ, cwJ);
json_decref(cwJ);

json_array_append_new(cablesJ, cableJ);
}
json_object_set_new(rootJ, "cables", cablesJ);

return rootJ;
}

void RackWidget::resetSelectedModulesAction() {
history::ComplexAction* complexAction = new history::ComplexAction;
complexAction->name = "reset modules";
@@ -797,6 +831,14 @@ bool RackWidget::areSelectedModulesBypassed() {
return true;
}

void RackWidget::copyClipboardSelectedModules() {
json_t* rootJ = selectedModulesToJson();
DEFER({json_decref(rootJ);});
char* moduleJson = json_dumps(rootJ, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
DEFER({std::free(moduleJson);});
glfwSetClipboardString(APP->window->win, moduleJson);
}

void RackWidget::deleteSelectedModulesAction() {
history::ComplexAction* complexAction = new history::ComplexAction;
complexAction->name = "remove modules";
@@ -866,6 +908,26 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
deselectModules();
}, n == 0));

// Copy
menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [=]() {
copyClipboardSelectedModules();
}, n == 0));

// Paste
menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [=]() {
pasteClipboardAction();
}));

// Duplicate
menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() {
cloneSelectedModulesAction();
}, n == 0));

// Delete
menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() {
deleteSelectedModulesAction();
}, n == 0));

// Initialize
menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [=]() {
resetSelectedModulesAction();
@@ -881,11 +943,6 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
disconnectSelectedModulesAction();
}, n == 0));

// Duplicate
menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() {
cloneSelectedModulesAction();
}, n == 0));

// Bypass
std::string bypassText = RACK_MOD_CTRL_NAME "+E";
bool bypassed = (n > 0) && areSelectedModulesBypassed();
@@ -894,11 +951,6 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {
menu->addChild(createMenuItem("Bypass", bypassText, [=]() {
bypassSelectedModulesAction(!bypassed);
}, n == 0));

// Delete
menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() {
deleteSelectedModulesAction();
}, n == 0));
}

void RackWidget::clearCables() {
@@ -994,8 +1046,8 @@ CableWidget* RackWidget::getCable(int64_t cableId) {
return NULL;
}

std::list<CableWidget*> RackWidget::getCompleteCables() {
std::list<CableWidget*> cws;
std::vector<CableWidget*> RackWidget::getCompleteCables() {
std::vector<CableWidget*> cws;
for (widget::Widget* w : internal->cableContainer->children) {
CableWidget* cw = dynamic_cast<CableWidget*>(w);
assert(cw);
@@ -1005,9 +1057,9 @@ std::list<CableWidget*> RackWidget::getCompleteCables() {
return cws;
}

std::list<CableWidget*> RackWidget::getCablesOnPort(PortWidget* port) {
std::vector<CableWidget*> RackWidget::getCablesOnPort(PortWidget* port) {
assert(port);
std::list<CableWidget*> cws;
std::vector<CableWidget*> cws;
for (widget::Widget* w : internal->cableContainer->children) {
CableWidget* cw = dynamic_cast<CableWidget*>(w);
assert(cw);


+ 35
- 19
src/app/Scene.cpp View File

@@ -125,10 +125,6 @@ void Scene::onDragHover(const DragHoverEvent& e) {
}

void Scene::onHoverKey(const HoverKeyEvent& e) {
OpaqueWidget::onHoverKey(e);
if (e.isConsumed())
return;

if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
// DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str());
if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
@@ -220,35 +216,51 @@ void Scene::onHoverKey(const HoverKeyEvent& e) {
rack->deselectModules();
e.consume(this);
}
if (e.keyName == "c" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (rack->hasSelectedModules()) {
rack->copyClipboardSelectedModules();
e.consume(this);
}
}
if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
rack->pasteClipboardAction();
e.consume(this);
}
if (e.keyName == "i" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (rack->hasSelectedModules())
if (rack->hasSelectedModules()) {
rack->resetSelectedModulesAction();
e.consume(this);
e.consume(this);
}
}
if (e.keyName == "r" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (rack->hasSelectedModules())
if (rack->hasSelectedModules()) {
rack->randomizeSelectedModulesAction();
e.consume(this);
}
if (e.keyName == "d" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (rack->hasSelectedModules())
rack->cloneSelectedModulesAction();
e.consume(this);
e.consume(this);
}
}
if (e.keyName == "u" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (rack->hasSelectedModules())
if (rack->hasSelectedModules()) {
rack->disconnectSelectedModulesAction();
e.consume(this);
e.consume(this);
}
}
if (e.keyName == "e" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (rack->hasSelectedModules())
if (rack->hasSelectedModules()) {
rack->bypassSelectedModulesAction(!rack->areSelectedModulesBypassed());
e.consume(this);
e.consume(this);
}
}
if (e.keyName == "d" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
if (rack->hasSelectedModules()) {
rack->cloneSelectedModulesAction();
e.consume(this);
}
}
if ((e.key == GLFW_KEY_DELETE || e.key == GLFW_KEY_BACKSPACE) && (e.mods & RACK_MOD_MASK) == 0) {
if (rack->hasSelectedModules())
if (rack->hasSelectedModules()) {
rack->deleteSelectedModulesAction();
e.consume(this);
e.consume(this);
}
}
}

@@ -279,6 +291,10 @@ void Scene::onHoverKey(const HoverKeyEvent& e) {
e.consume(this);
}
}

if (e.isConsumed())
return;
OpaqueWidget::onHoverKey(e);
}

void Scene::onPathDrop(const PathDropEvent& e) {


+ 0
- 2
src/engine/Engine.cpp View File

@@ -1171,7 +1171,6 @@ json_t* Engine::toJson() {
// modules
json_t* modulesJ = json_array();
for (Module* module : internal->modules) {
// module
json_t* moduleJ = module->toJson();
json_array_append_new(modulesJ, moduleJ);
}
@@ -1180,7 +1179,6 @@ json_t* Engine::toJson() {
// cables
json_t* cablesJ = json_array();
for (Cable* cable : internal->cables) {
// cable
json_t* cableJ = cable->toJson();
json_array_append_new(cablesJ, cableJ);
}


Loading…
Cancel
Save