@@ -14,6 +14,9 @@ namespace app { | |||||
/** Manages an engine::Module in the rack. */ | /** Manages an engine::Module in the rack. */ | ||||
struct ModuleWidget : widget::OpaqueWidget { | struct ModuleWidget : widget::OpaqueWidget { | ||||
struct Internal; | |||||
Internal* internal; | |||||
plugin::Model* model = NULL; | plugin::Model* model = NULL; | ||||
/** Owned. */ | /** Owned. */ | ||||
engine::Module* module = NULL; | engine::Module* module = NULL; | ||||
@@ -24,9 +27,6 @@ struct ModuleWidget : widget::OpaqueWidget { | |||||
std::vector<ParamWidget*> params; | std::vector<ParamWidget*> params; | ||||
std::vector<PortWidget*> inputs; | std::vector<PortWidget*> inputs; | ||||
std::vector<PortWidget*> outputs; | std::vector<PortWidget*> outputs; | ||||
/** For RackWidget dragging */ | |||||
math::Vec dragPos; | |||||
math::Vec oldPos; | |||||
ModuleWidget(); | ModuleWidget(); | ||||
DEPRECATED ModuleWidget(engine::Module* module) : 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. | It is recommended to add a blank ui::MenuEntry first for spacing. | ||||
*/ | */ | ||||
virtual void appendContextMenu(ui::Menu* menu) {} | 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 */ | /** The last mouse position in the RackWidget */ | ||||
math::Vec mousePos; | math::Vec mousePos; | ||||
ParamWidget* touchedParam = NULL; | ParamWidget* touchedParam = NULL; | ||||
std::map<int, math::Vec> moduleDragPositions; | |||||
int nextCableColorId = 0; | int nextCableColorId = 0; | ||||
RackWidget(); | RackWidget(); | ||||
@@ -59,7 +58,7 @@ struct RackWidget : widget::OpaqueWidget { | |||||
void setModulePosForce(ModuleWidget* mw, math::Vec pos); | void setModulePosForce(ModuleWidget* mw, math::Vec pos); | ||||
ModuleWidget* getModule(int moduleId); | ModuleWidget* getModule(int moduleId); | ||||
bool isEmpty(); | bool isEmpty(); | ||||
void updateModuleDragPositions(); | |||||
void updateModuleOldPositions(); | |||||
history::ComplexAction* getModuleDragAction(); | history::ComplexAction* getModuleDragAction(); | ||||
// Cable methods | // Cable methods | ||||
@@ -224,6 +224,10 @@ struct ModelBox : widget::OpaqueWidget { | |||||
// Pretend the moduleWidget was clicked so it can be dragged in the RackWidget | // Pretend the moduleWidget was clicked so it can be dragged in the RackWidget | ||||
e.consume(mw); | 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() { | ModuleWidget::ModuleWidget() { | ||||
internal = new Internal; | |||||
box.size = math::Vec(0, RACK_GRID_HEIGHT); | box.size = math::Vec(0, RACK_GRID_HEIGHT); | ||||
} | } | ||||
ModuleWidget::~ModuleWidget() { | ModuleWidget::~ModuleWidget() { | ||||
clearChildren(); | clearChildren(); | ||||
setModule(NULL); | setModule(NULL); | ||||
delete internal; | |||||
} | } | ||||
void ModuleWidget::draw(const DrawArgs& args) { | void ModuleWidget::draw(const DrawArgs& args) { | ||||
@@ -384,36 +398,30 @@ void ModuleWidget::onHoverKey(const event::HoverKey& e) { | |||||
} | } | ||||
void ModuleWidget::onDragStart(const event::DragStart& 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) { | 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) { | 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 app | ||||
} // namespace rack | } // namespace rack |
@@ -276,7 +276,10 @@ void PortWidget::onDragDrop(const event::DragDrop& e) { | |||||
} | } | ||||
void PortWidget::onDragEnter(const event::DragEnter& 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) | if (e.button != GLFW_MOUSE_BUTTON_LEFT) | ||||
return; | return; | ||||
@@ -521,12 +521,12 @@ bool RackWidget::isEmpty() { | |||||
return moduleContainer->children.empty(); | 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) { | for (widget::Widget* w : moduleContainer->children) { | ||||
ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w); | ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w); | ||||
assert(mw); | 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) { | for (widget::Widget* w : moduleContainer->children) { | ||||
ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w); | ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w); | ||||
assert(mw); | 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. | // 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; | history::ModuleMove* mmh = new history::ModuleMove; | ||||
mmh->moduleId = mw->module->id; | mmh->moduleId = mw->module->id; | ||||
mmh->oldPos = pos; | |||||
mmh->oldPos = oldPos; | |||||
mmh->newPos = mw->box.pos; | mmh->newPos = mw->box.pos; | ||||
h->push(mmh); | h->push(mmh); | ||||
} | } | ||||
} | } | ||||
if (h->isEmpty()) { | |||||
delete h; | |||||
return NULL; | |||||
} | |||||
return h; | return h; | ||||
} | } | ||||