@@ -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; | |||
} | |||