| @@ -14,6 +14,9 @@ namespace app { | |||
| /** Manages an engine::Module in the rack. */ | |||
| struct ModuleWidget : widget::OpaqueWidget { | |||
| struct Internal; | |||
| Internal* internal; | |||
| plugin::Model* model = NULL; | |||
| /** Owned. */ | |||
| engine::Module* module = NULL; | |||
| @@ -24,9 +27,6 @@ struct ModuleWidget : widget::OpaqueWidget { | |||
| std::vector<ParamWidget*> params; | |||
| std::vector<PortWidget*> inputs; | |||
| std::vector<PortWidget*> outputs; | |||
| /** For RackWidget dragging */ | |||
| math::Vec dragPos; | |||
| math::Vec oldPos; | |||
| ModuleWidget(); | |||
| DEPRECATED ModuleWidget(engine::Module* module) : ModuleWidget() { | |||
| @@ -90,6 +90,9 @@ struct ModuleWidget : widget::OpaqueWidget { | |||
| It is recommended to add a blank ui::MenuEntry first for spacing. | |||
| */ | |||
| virtual void appendContextMenu(ui::Menu* menu) {} | |||
| math::Vec& dragPos(); | |||
| math::Vec& oldPos(); | |||
| }; | |||
| @@ -23,7 +23,6 @@ struct RackWidget : widget::OpaqueWidget { | |||
| /** The last mouse position in the RackWidget */ | |||
| math::Vec mousePos; | |||
| ParamWidget* touchedParam = NULL; | |||
| std::map<int, math::Vec> moduleDragPositions; | |||
| int nextCableColorId = 0; | |||
| RackWidget(); | |||
| @@ -59,7 +58,7 @@ struct RackWidget : widget::OpaqueWidget { | |||
| void setModulePosForce(ModuleWidget* mw, math::Vec pos); | |||
| ModuleWidget* getModule(int moduleId); | |||
| bool isEmpty(); | |||
| void updateModuleDragPositions(); | |||
| void updateModuleOldPositions(); | |||
| history::ComplexAction* getModuleDragAction(); | |||
| // Cable methods | |||
| @@ -224,6 +224,10 @@ struct ModelBox : widget::OpaqueWidget { | |||
| // Pretend the moduleWidget was clicked so it can be dragged in the RackWidget | |||
| e.consume(mw); | |||
| // Set the drag position at the center of the module | |||
| // TODO This doesn't work because ModuleWidget::onDragStart, which is called afterwards, overwrites this. | |||
| // mw->dragPos() = mw->box.size.div(2); | |||
| } | |||
| } | |||
| @@ -241,13 +241,27 @@ struct ModuleDeleteItem : ui::MenuItem { | |||
| }; | |||
| struct ModuleWidget::Internal { | |||
| /** The position the user clicked on the module to start dragging in the RackWidget. | |||
| */ | |||
| math::Vec dragPos; | |||
| /** The position in the RackWidget when dragging began. | |||
| Used for history::ModuleMove. | |||
| Set by RackWidget::updateModuleOldPositions() when *any* module begins dragging, since force-dragging can move other modules around. | |||
| */ | |||
| math::Vec oldPos; | |||
| }; | |||
| ModuleWidget::ModuleWidget() { | |||
| internal = new Internal; | |||
| box.size = math::Vec(0, RACK_GRID_HEIGHT); | |||
| } | |||
| ModuleWidget::~ModuleWidget() { | |||
| clearChildren(); | |||
| setModule(NULL); | |||
| delete internal; | |||
| } | |||
| void ModuleWidget::draw(const DrawArgs& args) { | |||
| @@ -384,36 +398,30 @@ void ModuleWidget::onHoverKey(const event::HoverKey& e) { | |||
| } | |||
| void ModuleWidget::onDragStart(const event::DragStart& e) { | |||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||
| return; | |||
| oldPos = box.pos; | |||
| dragPos = APP->scene->rack->mousePos.minus(box.pos); | |||
| APP->scene->rack->updateModuleDragPositions(); | |||
| if (e.button == GLFW_MOUSE_BUTTON_LEFT) { | |||
| internal->dragPos = APP->scene->rack->mousePos.minus(box.pos); | |||
| APP->scene->rack->updateModuleOldPositions(); | |||
| } | |||
| } | |||
| void ModuleWidget::onDragEnd(const event::DragEnd& e) { | |||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||
| return; | |||
| history::ComplexAction* h = APP->scene->rack->getModuleDragAction(); | |||
| if (!h) { | |||
| delete h; | |||
| return; | |||
| if (e.button == GLFW_MOUSE_BUTTON_LEFT) { | |||
| history::ComplexAction* h = APP->scene->rack->getModuleDragAction(); | |||
| if (!h) | |||
| return; | |||
| APP->history->push(h); | |||
| } | |||
| APP->history->push(h); | |||
| } | |||
| void ModuleWidget::onDragMove(const event::DragMove& e) { | |||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||
| return; | |||
| if (!settings::lockModules) { | |||
| math::Vec pos = APP->scene->rack->mousePos.minus(dragPos); | |||
| if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) | |||
| APP->scene->rack->setModulePosForce(this, pos); | |||
| else | |||
| APP->scene->rack->setModulePosNearest(this, pos); | |||
| if (e.button == GLFW_MOUSE_BUTTON_LEFT) { | |||
| if (!settings::lockModules) { | |||
| math::Vec pos = APP->scene->rack->mousePos.minus(internal->dragPos); | |||
| if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) | |||
| APP->scene->rack->setModulePosForce(this, pos); | |||
| else | |||
| APP->scene->rack->setModulePosNearest(this, pos); | |||
| } | |||
| } | |||
| } | |||
| @@ -836,5 +844,14 @@ void ModuleWidget::createContextMenu() { | |||
| } | |||
| math::Vec& ModuleWidget::dragPos() { | |||
| return internal->dragPos; | |||
| } | |||
| math::Vec& ModuleWidget::oldPos() { | |||
| return internal->oldPos; | |||
| } | |||
| } // namespace app | |||
| } // namespace rack | |||
| @@ -276,7 +276,10 @@ void PortWidget::onDragDrop(const event::DragDrop& e) { | |||
| } | |||
| void PortWidget::onDragEnter(const event::DragEnter& e) { | |||
| createTooltip(); | |||
| PortWidget* pw = dynamic_cast<PortWidget*>(e.origin); | |||
| if (pw) { | |||
| createTooltip(); | |||
| } | |||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||
| return; | |||
| @@ -521,12 +521,12 @@ bool RackWidget::isEmpty() { | |||
| return moduleContainer->children.empty(); | |||
| } | |||
| void RackWidget::updateModuleDragPositions() { | |||
| moduleDragPositions.clear(); | |||
| void RackWidget::updateModuleOldPositions() { | |||
| // Set all modules' oldPos field from their current position. | |||
| for (widget::Widget* w : moduleContainer->children) { | |||
| ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w); | |||
| assert(mw); | |||
| moduleDragPositions[mw->module->id] = mw->box.pos; | |||
| mw->oldPos() = mw->box.pos; | |||
| } | |||
| } | |||
| @@ -536,20 +536,21 @@ history::ComplexAction* RackWidget::getModuleDragAction() { | |||
| for (widget::Widget* w : moduleContainer->children) { | |||
| ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w); | |||
| assert(mw); | |||
| // It is possible to add modules to the rack while dragging, so ignore modules that don't exist. | |||
| auto it = moduleDragPositions.find(mw->module->id); | |||
| if (it == moduleDragPositions.end()) | |||
| continue; | |||
| // Create ModuleMove action if the module was moved. | |||
| math::Vec pos = it->second; | |||
| if (!pos.isEqual(mw->box.pos)) { | |||
| math::Vec oldPos = mw->oldPos(); | |||
| if (!oldPos.isEqual(mw->box.pos)) { | |||
| history::ModuleMove* mmh = new history::ModuleMove; | |||
| mmh->moduleId = mw->module->id; | |||
| mmh->oldPos = pos; | |||
| mmh->oldPos = oldPos; | |||
| mmh->newPos = mw->box.pos; | |||
| h->push(mmh); | |||
| } | |||
| } | |||
| if (h->isEmpty()) { | |||
| delete h; | |||
| return NULL; | |||
| } | |||
| return h; | |||
| } | |||