| @@ -10,6 +10,9 @@ namespace rack { | |||
| namespace app { | |||
| struct CableWidget; | |||
| struct PlugWidget : widget::Widget { | |||
| struct Internal; | |||
| Internal* internal; | |||
| @@ -19,8 +22,9 @@ struct PlugWidget : widget::Widget { | |||
| void step() override; | |||
| PRIVATE void setColor(NVGcolor color); | |||
| PRIVATE void setAngle(float angle); | |||
| PRIVATE void setPortWidget(PortWidget* portWidget); | |||
| PRIVATE void setTop(bool top); | |||
| CableWidget* getCable(); | |||
| engine::Port::Type getType(); | |||
| }; | |||
| @@ -41,6 +45,7 @@ struct CableWidget : widget::Widget { | |||
| CableWidget(); | |||
| ~CableWidget(); | |||
| /** Returns whether cable is connected to 2 ports. */ | |||
| bool isComplete(); | |||
| /** Based on the input/output ports, re-creates the cable and removes/adds it to the Engine. */ | |||
| void updateCable(); | |||
| @@ -50,6 +55,15 @@ struct CableWidget : widget::Widget { | |||
| */ | |||
| void setCable(engine::Cable* cable); | |||
| engine::Cable* getCable(); | |||
| PlugWidget*& getPlug(engine::Port::Type type) { | |||
| return type == engine::Port::INPUT ? inputPlug : outputPlug; | |||
| } | |||
| PortWidget*& getPort(engine::Port::Type type) { | |||
| return type == engine::Port::INPUT ? inputPort : outputPort; | |||
| } | |||
| PortWidget*& getHoveredPort(engine::Port::Type type) { | |||
| return type == engine::Port::INPUT ? hoveredInputPort : hoveredOutputPort; | |||
| } | |||
| math::Vec getInputPos(); | |||
| math::Vec getOutputPos(); | |||
| void mergeJson(json_t* rootJ); | |||
| @@ -115,23 +115,29 @@ struct RackWidget : widget::OpaqueWidget { | |||
| void clearCablesAction(); | |||
| /** Removes all cables connected to the port */ | |||
| void clearCablesOnPort(PortWidget* port); | |||
| /** Adds a complete cable and adopts ownership. | |||
| /** Adds a cable and adopts ownership. | |||
| */ | |||
| void addCable(CableWidget* cw); | |||
| /** Removes cable and releases ownership to caller. | |||
| */ | |||
| void removeCable(CableWidget* cw); | |||
| CableWidget* getIncompleteCable(); | |||
| /** Takes ownership of `cw` and adds it as a child if it isn't already. */ | |||
| void setIncompleteCable(CableWidget* cw); | |||
| CableWidget* releaseIncompleteCable(); | |||
| /** Returns the most recently added complete cable connected to the given Port, i.e. the top of the stack. */ | |||
| /** Returns the top incomplete cable. Use getIncompleteCables() instead. */ | |||
| DEPRECATED CableWidget* getIncompleteCable(); | |||
| /** Returns the topmost plug stacked on the port. */ | |||
| PlugWidget* getTopPlug(PortWidget* port); | |||
| /** Returns the cable with the topmost plug stacked on the port. */ | |||
| CableWidget* getTopCable(PortWidget* port); | |||
| CableWidget* getCable(int64_t cableId); | |||
| CableWidget* getCable(PortWidget* outputPort, PortWidget* inputPort); | |||
| /** Returns all cables, complete and incomplete. */ | |||
| std::vector<CableWidget*> getCables(); | |||
| /** Returns all cables attached to 2 ports. */ | |||
| std::vector<CableWidget*> getCompleteCables(); | |||
| /** Returns all cables attached to port, complete or not. */ | |||
| /** Returns all cables attached to less than 2 ports. */ | |||
| std::vector<CableWidget*> getIncompleteCables(); | |||
| /** Returns all cables attached to the port, complete or not. */ | |||
| std::vector<CableWidget*> getCablesOnPort(PortWidget* port); | |||
| /** Returns all complete cables attached to the port. */ | |||
| std::vector<CableWidget*> getCompleteCablesOnPort(PortWidget* port); | |||
| /** Returns but does not advance the next cable color. */ | |||
| int getNextCableColorId(); | |||
| @@ -34,17 +34,17 @@ struct PlugLight : componentlibrary::TRedGreenBlueLight<app::MultiLightWidget> { | |||
| struct PlugWidget::Internal { | |||
| CableWidget* cableWidget; | |||
| engine::Port::Type type; | |||
| /** Initially pointing upward. */ | |||
| float angle = 0.5f * M_PI; | |||
| PortWidget* portWidget = NULL; | |||
| widget::FramebufferWidget* fb; | |||
| widget::TransformWidget* plugTransform; | |||
| TintWidget* plugTint; | |||
| widget::SvgWidget* plug; | |||
| widget::SvgWidget* plugPort; | |||
| app::MultiLightWidget* plugLight; | |||
| }; | |||
| @@ -87,8 +87,10 @@ PlugWidget::~PlugWidget() { | |||
| void PlugWidget::step() { | |||
| std::vector<float> values(3); | |||
| if (internal->portWidget && internal->plugLight->isVisible()) { | |||
| engine::Port* port = internal->portWidget->getPort(); | |||
| PortWidget* pw = internal->cableWidget->getPort(internal->type); | |||
| if (pw && internal->plugLight->isVisible()) { | |||
| engine::Port* port = pw->getPort(); | |||
| if (port) { | |||
| for (int i = 0; i < 3; i++) { | |||
| values[i] = port->plugLights[i].getBrightness(); | |||
| @@ -116,14 +118,18 @@ void PlugWidget::setAngle(float angle) { | |||
| internal->fb->setDirty(); | |||
| } | |||
| void PlugWidget::setPortWidget(PortWidget* portWidget) { | |||
| internal->portWidget = portWidget; | |||
| } | |||
| void PlugWidget::setTop(bool top) { | |||
| internal->plugLight->setVisible(top); | |||
| } | |||
| CableWidget* PlugWidget::getCable() { | |||
| return internal->cableWidget; | |||
| } | |||
| engine::Port::Type PlugWidget::getType() { | |||
| return internal->type; | |||
| } | |||
| struct CableWidget::Internal { | |||
| }; | |||
| @@ -134,7 +140,12 @@ CableWidget::CableWidget() { | |||
| color = color::BLACK_TRANSPARENT; | |||
| outputPlug = new PlugWidget; | |||
| outputPlug->internal->cableWidget = this; | |||
| outputPlug->internal->type = engine::Port::OUTPUT; | |||
| inputPlug = new PlugWidget; | |||
| inputPlug->internal->cableWidget = this; | |||
| inputPlug->internal->type = engine::Port::INPUT; | |||
| } | |||
| @@ -267,20 +278,18 @@ void CableWidget::step() { | |||
| colorOpaque.a = 1.f; | |||
| // Draw output plug | |||
| bool outputTop = !isComplete() || APP->scene->rack->getTopCable(outputPort) == this; | |||
| outputPlug->setPosition(outputPos); | |||
| outputPlug->setTop(outputTop); | |||
| // bool outputTop = isComplete() && APP->scene->rack->getTopCable(outputPort) == this; | |||
| // outputPlug->setTop(outputTop); | |||
| outputPlug->setAngle(slump.minus(outputPos).arg()); | |||
| outputPlug->setColor(colorOpaque); | |||
| outputPlug->setPortWidget(outputPort); | |||
| // Draw input plug | |||
| bool inputTop = !isComplete() || APP->scene->rack->getTopCable(inputPort) == this; | |||
| inputPlug->setPosition(inputPos); | |||
| inputPlug->setTop(inputTop); | |||
| // bool inputTop = isComplete() && APP->scene->rack->getTopCable(inputPort) == this; | |||
| // inputPlug->setTop(inputTop); | |||
| inputPlug->setAngle(slump.minus(inputPos).arg()); | |||
| inputPlug->setColor(colorOpaque); | |||
| inputPlug->setPortWidget(inputPort); | |||
| Widget::step(); | |||
| } | |||
| @@ -329,8 +338,9 @@ void CableWidget::drawLayer(const DrawArgs& args, int layer) { | |||
| // The endpoints are off-center | |||
| math::Vec slump = getSlumpPos(outputPos, inputPos); | |||
| outputPos = outputPos.plus(slump.minus(outputPos).normalize().mult(13.0)); | |||
| inputPos = inputPos.plus(slump.minus(inputPos).normalize().mult(13.0)); | |||
| float dist = 14.f; | |||
| outputPos = outputPos.plus(slump.minus(outputPos).normalize().mult(dist)); | |||
| inputPos = inputPos.plus(slump.minus(inputPos).normalize().mult(dist)); | |||
| nvgLineCap(args.vg, NVG_ROUND); | |||
| // Avoids glitches when cable is bent | |||
| @@ -48,7 +48,7 @@ struct PortTooltip : ui::Tooltip { | |||
| text += string::f("%d: ", i + 1); | |||
| text += string::f("% .3fV", math::normalizeZero(v)); | |||
| } | |||
| // Connected to | |||
| // From/To | |||
| std::vector<CableWidget*> cables = APP->scene->rack->getCompleteCablesOnPort(portWidget); | |||
| for (auto it = cables.rbegin(); it != cables.rend(); it++) { | |||
| CableWidget* cable = *it; | |||
| @@ -136,6 +136,8 @@ struct PortCableItem : ui::ColorDotMenuItem { | |||
| ui::Menu* createChildMenu() override { | |||
| ui::Menu* menu = new ui::Menu; | |||
| // menu->addChild(createMenuLabel(string::f("ID: %ld", cw->cable->id))); | |||
| for (NVGcolor color : settings::cableColors) { | |||
| // Include extra leading spaces for the color circle | |||
| CableColorItem* item = createMenuItem<CableColorItem>("Set color"); | |||
| @@ -342,6 +344,12 @@ void PortWidget::step() { | |||
| void PortWidget::draw(const DrawArgs& args) { | |||
| PortWidget* draggedPw = dynamic_cast<PortWidget*>(APP->event->getDraggedWidget()); | |||
| if (draggedPw) { | |||
| // TODO | |||
| } | |||
| // TODO Reimplement this | |||
| #if 0 | |||
| CableWidget* cw = APP->scene->rack->getIncompleteCable(); | |||
| if (cw) { | |||
| // Dim the PortWidget if the active cable cannot plug into this PortWidget | |||
| @@ -349,6 +357,7 @@ void PortWidget::draw(const DrawArgs& args) { | |||
| nvgTint(args.vg, nvgRGBf(0.33, 0.33, 0.33)); | |||
| } | |||
| } | |||
| #endif | |||
| Widget::draw(args); | |||
| } | |||
| @@ -426,32 +435,35 @@ void PortWidget::onDragStart(const DragStartEvent& e) { | |||
| h->setCable(cw); | |||
| APP->history->push(h); | |||
| // Disconnect and reuse existing cable | |||
| APP->scene->rack->removeCable(cw); | |||
| if (type == engine::Port::OUTPUT) | |||
| cw->outputPort = NULL; | |||
| else | |||
| cw->inputPort = NULL; | |||
| // Reuse existing cable | |||
| cw->getPort(type) = NULL; | |||
| cw->updateCable(); | |||
| } | |||
| } | |||
| // If not using existing cable, create new cable | |||
| if (!cw) { | |||
| // Create a new cable | |||
| cw = new CableWidget; | |||
| // Set color | |||
| cw->color = APP->scene->rack->getNextCableColor(); | |||
| // Set port | |||
| if (type == engine::Port::OUTPUT) | |||
| cw->outputPort = this; | |||
| else | |||
| cw->inputPort = this; | |||
| cw->getPort(type) = this; | |||
| cw->updateCable(); | |||
| } | |||
| APP->scene->rack->setIncompleteCable(cw); | |||
| // Add cable to rack if not already added | |||
| if (!cw->getParent()) { | |||
| APP->scene->rack->addCable(cw); | |||
| } | |||
| else { | |||
| // Move grabbed plug to top of stack | |||
| PlugWidget* plug = cw->getPlug(type); | |||
| assert(plug); | |||
| APP->scene->rack->getPlugContainer()->removeChild(plug); | |||
| APP->scene->rack->getPlugContainer()->addChild(plug); | |||
| } | |||
| } | |||
| @@ -459,20 +471,31 @@ void PortWidget::onDragEnd(const DragEndEvent& e) { | |||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||
| return; | |||
| CableWidget* cw = APP->scene->rack->releaseIncompleteCable(); | |||
| if (!cw) | |||
| std::vector<CableWidget*> cws = APP->scene->rack->getIncompleteCables(); | |||
| if (cws.empty()) | |||
| return; | |||
| if (cw->isComplete()) { | |||
| APP->scene->rack->addCable(cw); | |||
| history::ComplexAction* h = new history::ComplexAction; | |||
| // history::CableAdd | |||
| history::CableAdd* h = new history::CableAdd; | |||
| h->setCable(cw); | |||
| APP->history->push(h); | |||
| for (CableWidget* cw : cws) { | |||
| if (cw->isComplete()) { | |||
| // history::CableAdd | |||
| history::CableAdd* hAdd = new history::CableAdd; | |||
| hAdd->setCable(cw); | |||
| h->push(hAdd); | |||
| } | |||
| else { | |||
| APP->scene->rack->removeCable(cw); | |||
| delete cw; | |||
| } | |||
| } | |||
| // Push history | |||
| if (h->isEmpty()) { | |||
| delete h; | |||
| } | |||
| else { | |||
| delete cw; | |||
| APP->history->push(h); | |||
| } | |||
| } | |||
| @@ -481,18 +504,28 @@ void PortWidget::onDragDrop(const DragDropEvent& e) { | |||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||
| return; | |||
| PortWidget* pwOrigin = dynamic_cast<PortWidget*>(e.origin); | |||
| if (!pwOrigin) | |||
| return; | |||
| // HACK: Only delete tooltip if we're not (normal) dragging it. | |||
| if (e.origin == this) | |||
| if (pwOrigin == this) { | |||
| createTooltip(); | |||
| } | |||
| CableWidget* cw = APP->scene->rack->getIncompleteCable(); | |||
| if (cw) { | |||
| cw->hoveredOutputPort = cw->hoveredInputPort = NULL; | |||
| if (type == engine::Port::OUTPUT && cw->inputPort && !APP->scene->rack->getCable(this, cw->inputPort)) { | |||
| cw->outputPort = this; | |||
| for (CableWidget* cw : APP->scene->rack->getIncompleteCables()) { | |||
| cw->hoveredOutputPort = NULL; | |||
| cw->hoveredInputPort = NULL; | |||
| if (type == engine::Port::OUTPUT) { | |||
| // Check that similar cable doesn't exist | |||
| if (cw->inputPort && !APP->scene->rack->getCable(this, cw->inputPort)) { | |||
| cw->outputPort = this; | |||
| } | |||
| } | |||
| if (type == engine::Port::INPUT && cw->outputPort && !APP->scene->rack->getCable(cw->outputPort, this)) { | |||
| cw->inputPort = this; | |||
| else { | |||
| if (cw->outputPort && !APP->scene->rack->getCable(cw->outputPort, this)) { | |||
| cw->inputPort = this; | |||
| } | |||
| } | |||
| cw->updateCable(); | |||
| } | |||
| @@ -503,18 +536,25 @@ void PortWidget::onDragEnter(const DragEnterEvent& e) { | |||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||
| return; | |||
| PortWidget* pw = dynamic_cast<PortWidget*>(e.origin); | |||
| if (pw) { | |||
| createTooltip(); | |||
| } | |||
| // Check if dragging from another port, which implies that a cable is being dragged | |||
| PortWidget* pwOrigin = dynamic_cast<PortWidget*>(e.origin); | |||
| if (!pwOrigin) | |||
| return; | |||
| CableWidget* cw = APP->scene->rack->getIncompleteCable(); | |||
| if (cw) { | |||
| if (type == engine::Port::OUTPUT && cw->inputPort && !APP->scene->rack->getCable(this, cw->inputPort)) { | |||
| cw->hoveredOutputPort = this; | |||
| createTooltip(); | |||
| // Make all incomplete cables hover this port | |||
| for (CableWidget* cw : APP->scene->rack->getIncompleteCables()) { | |||
| if (type == engine::Port::OUTPUT) { | |||
| // Check that similar cable doesn't exist | |||
| if (cw->inputPort && !APP->scene->rack->getCable(this, cw->inputPort)) { | |||
| cw->hoveredOutputPort = this; | |||
| } | |||
| } | |||
| if (type == engine::Port::INPUT && cw->outputPort && !APP->scene->rack->getCable(cw->outputPort, this)) { | |||
| cw->hoveredInputPort = this; | |||
| else { | |||
| if (cw->outputPort && !APP->scene->rack->getCable(cw->outputPort, this)) { | |||
| cw->hoveredInputPort = this; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -526,16 +566,12 @@ void PortWidget::onDragLeave(const DragLeaveEvent& e) { | |||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||
| return; | |||
| PortWidget* originPort = dynamic_cast<PortWidget*>(e.origin); | |||
| if (!originPort) | |||
| PortWidget* pwOrigin = dynamic_cast<PortWidget*>(e.origin); | |||
| if (!pwOrigin) | |||
| return; | |||
| CableWidget* cw = APP->scene->rack->getIncompleteCable(); | |||
| if (cw) { | |||
| if (type == engine::Port::OUTPUT) | |||
| cw->hoveredOutputPort = NULL; | |||
| if (type == engine::Port::INPUT) | |||
| cw->hoveredInputPort = NULL; | |||
| for (CableWidget* cw : APP->scene->rack->getIncompleteCables()) { | |||
| cw->getHoveredPort(type) = NULL; | |||
| } | |||
| } | |||
| @@ -28,7 +28,6 @@ struct RackWidget::Internal { | |||
| widget::Widget* moduleContainer = NULL; | |||
| widget::Widget* plugContainer = NULL; | |||
| widget::Widget* cableContainer = NULL; | |||
| CableWidget* incompleteCable = NULL; | |||
| int nextCableColorId = 0; | |||
| /** The last mouse position in the RackWidget */ | |||
| math::Vec mousePos; | |||
| @@ -289,6 +288,13 @@ void RackWidget::mergeJson(json_t* rootJ) { | |||
| json_object_set_new(moduleJ, "pos", posJ); | |||
| } | |||
| // Calculate plug orders | |||
| std::map<Widget*, int> plugOrders; | |||
| int plugOrder = 1; | |||
| for (Widget* w : internal->plugContainer->children) { | |||
| plugOrders[w] = plugOrder++; | |||
| } | |||
| // cables | |||
| json_t* cablesJ = json_object_get(rootJ, "cables"); | |||
| if (!cablesJ) | |||
| @@ -308,6 +314,20 @@ void RackWidget::mergeJson(json_t* rootJ) { | |||
| } | |||
| cw->mergeJson(cableJ); | |||
| // inputPlugOrder | |||
| auto plugOrderIt = plugOrders.find(cw->inputPlug); | |||
| if (plugOrderIt != plugOrders.end()) { | |||
| int inputPlugOrder = plugOrderIt->second; | |||
| json_object_set_new(cableJ, "inputPlugOrder", json_integer(inputPlugOrder)); | |||
| } | |||
| // outputPlugOrder | |||
| plugOrderIt = plugOrders.find(cw->outputPlug); | |||
| if (plugOrderIt != plugOrders.end()) { | |||
| int outputPlugOrder = plugOrderIt->second; | |||
| json_object_set_new(cableJ, "outputPlugOrder", json_integer(outputPlugOrder)); | |||
| } | |||
| } | |||
| } | |||
| @@ -369,6 +389,8 @@ void RackWidget::fromJson(json_t* rootJ) { | |||
| updateExpanders(); | |||
| std::map<Widget*, int> plugOrders; | |||
| // cables | |||
| json_t* cablesJ = json_object_get(rootJ, "cables"); | |||
| // In <=v0.6, cables were called wires | |||
| @@ -409,7 +431,24 @@ void RackWidget::fromJson(json_t* rootJ) { | |||
| continue; | |||
| } | |||
| addCable(cw); | |||
| // inputPlugOrder | |||
| json_t* inputPlugOrderJ = json_object_get(cableJ, "inputPlugOrder"); | |||
| if (inputPlugOrderJ) { | |||
| plugOrders[cw->inputPlug] = json_integer_value(inputPlugOrderJ); | |||
| } | |||
| // outputPlugOrder | |||
| json_t* outputPlugOrderJ = json_object_get(cableJ, "outputPlugOrder"); | |||
| if (outputPlugOrderJ) { | |||
| plugOrders[cw->outputPlug] = json_integer_value(outputPlugOrderJ); | |||
| } | |||
| } | |||
| // Reorder plugs, approximately O(n log(n) log(n)) | |||
| internal->plugContainer->children.sort([&](Widget* w1, Widget* w2) { | |||
| return get(plugOrders, w1, 0) < get(plugOrders, w2, 0); | |||
| }); | |||
| } | |||
| struct PasteJsonResult { | |||
| @@ -680,7 +719,6 @@ std::vector<ModuleWidget*> RackWidget::getModules() { | |||
| assert(mw); | |||
| mws.push_back(mw); | |||
| } | |||
| mws.shrink_to_fit(); | |||
| return mws; | |||
| } | |||
| @@ -1010,8 +1048,8 @@ json_t* RackWidget::selectionToJson(bool cables) { | |||
| if (cables) { | |||
| // cables | |||
| json_t* cablesJ = json_array(); | |||
| // Only add complete cables to JSON | |||
| 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; | |||
| @@ -1394,8 +1432,7 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) { | |||
| } | |||
| void RackWidget::clearCables() { | |||
| internal->incompleteCable = NULL; | |||
| // Since cables manage plugs, all plugs are removed from plugContainer | |||
| // Since cables manage plugs, all plugs will be removed from plugContainer | |||
| internal->cableContainer->clearChildren(); | |||
| } | |||
| @@ -1421,61 +1458,46 @@ void RackWidget::clearCablesAction() { | |||
| void RackWidget::clearCablesOnPort(PortWidget* port) { | |||
| for (CableWidget* cw : getCablesOnPort(port)) { | |||
| // Check if cable is connected to port | |||
| if (cw == internal->incompleteCable) { | |||
| internal->incompleteCable = NULL; | |||
| internal->cableContainer->removeChild(cw); | |||
| } | |||
| else { | |||
| removeCable(cw); | |||
| } | |||
| removeCable(cw); | |||
| delete cw; | |||
| } | |||
| } | |||
| void RackWidget::addCable(CableWidget* cw) { | |||
| assert(cw->isComplete()); | |||
| internal->cableContainer->addChild(cw); | |||
| } | |||
| void RackWidget::removeCable(CableWidget* cw) { | |||
| assert(cw->isComplete()); | |||
| internal->cableContainer->removeChild(cw); | |||
| } | |||
| CableWidget* RackWidget::getIncompleteCable() { | |||
| return internal->incompleteCable; | |||
| } | |||
| void RackWidget::setIncompleteCable(CableWidget* cw) { | |||
| if (internal->incompleteCable) { | |||
| internal->cableContainer->removeChild(internal->incompleteCable); | |||
| delete internal->incompleteCable; | |||
| internal->incompleteCable = NULL; | |||
| } | |||
| if (cw) { | |||
| internal->cableContainer->addChild(cw); | |||
| internal->incompleteCable = cw; | |||
| for (auto it = internal->cableContainer->children.rbegin(); it != internal->cableContainer->children.rend(); it++) { | |||
| CableWidget* cw = dynamic_cast<CableWidget*>(*it); | |||
| assert(cw); | |||
| if (!cw->isComplete()) | |||
| return cw; | |||
| } | |||
| return NULL; | |||
| } | |||
| CableWidget* RackWidget::releaseIncompleteCable() { | |||
| if (!internal->incompleteCable) | |||
| return NULL; | |||
| CableWidget* cw = internal->incompleteCable; | |||
| internal->cableContainer->removeChild(internal->incompleteCable); | |||
| internal->incompleteCable = NULL; | |||
| return cw; | |||
| PlugWidget* RackWidget::getTopPlug(PortWidget* port) { | |||
| assert(port); | |||
| for (auto it = internal->plugContainer->children.rbegin(); it != internal->plugContainer->children.rend(); it++) { | |||
| PlugWidget* plug = dynamic_cast<PlugWidget*>(*it); | |||
| assert(plug); | |||
| CableWidget* cw = plug->getCable(); | |||
| PortWidget* port2 = cw->getPort(plug->getType()); | |||
| if (port2 == port) | |||
| return plug; | |||
| } | |||
| return NULL; | |||
| } | |||
| CableWidget* RackWidget::getTopCable(PortWidget* port) { | |||
| for (auto it = internal->cableContainer->children.rbegin(); it != internal->cableContainer->children.rend(); it++) { | |||
| CableWidget* cw = dynamic_cast<CableWidget*>(*it); | |||
| assert(cw); | |||
| if (cw->inputPort == port || cw->outputPort == port) | |||
| return cw; | |||
| } | |||
| PlugWidget* plug = getTopPlug(port); | |||
| if (plug) | |||
| return plug->getCable(); | |||
| return NULL; | |||
| } | |||
| @@ -1501,8 +1523,20 @@ CableWidget* RackWidget::getCable(PortWidget* outputPort, PortWidget* inputPort) | |||
| return NULL; | |||
| } | |||
| std::vector<CableWidget*> RackWidget::getCables() { | |||
| std::vector<CableWidget*> cws; | |||
| cws.reserve(internal->cableContainer->children.size()); | |||
| for (widget::Widget* w : internal->cableContainer->children) { | |||
| CableWidget* cw = dynamic_cast<CableWidget*>(w); | |||
| assert(cw); | |||
| cws.push_back(cw); | |||
| } | |||
| return cws; | |||
| } | |||
| std::vector<CableWidget*> RackWidget::getCompleteCables() { | |||
| std::vector<CableWidget*> cws; | |||
| // Assume that most cables are complete, so pre-allocate and shrink vector. | |||
| cws.reserve(internal->cableContainer->children.size()); | |||
| for (widget::Widget* w : internal->cableContainer->children) { | |||
| CableWidget* cw = dynamic_cast<CableWidget*>(w); | |||
| @@ -1514,15 +1548,27 @@ std::vector<CableWidget*> RackWidget::getCompleteCables() { | |||
| return cws; | |||
| } | |||
| std::vector<CableWidget*> RackWidget::getCablesOnPort(PortWidget* port) { | |||
| assert(port); | |||
| std::vector<CableWidget*> RackWidget::getIncompleteCables() { | |||
| std::vector<CableWidget*> cws; | |||
| for (widget::Widget* w : internal->cableContainer->children) { | |||
| CableWidget* cw = dynamic_cast<CableWidget*>(w); | |||
| assert(cw); | |||
| if (cw->inputPort == port || cw->outputPort == port) { | |||
| if (!cw->isComplete()) | |||
| cws.push_back(cw); | |||
| } | |||
| return cws; | |||
| } | |||
| std::vector<CableWidget*> RackWidget::getCablesOnPort(PortWidget* port) { | |||
| assert(port); | |||
| std::vector<CableWidget*> cws; | |||
| for (widget::Widget* w : internal->plugContainer->children) { | |||
| PlugWidget* plug = dynamic_cast<PlugWidget*>(w); | |||
| assert(plug); | |||
| CableWidget* cw = plug->getCable(); | |||
| PortWidget* port2 = cw->getPort(plug->getType()); | |||
| if (port2 == port) | |||
| cws.push_back(cw); | |||
| } | |||
| } | |||
| return cws; | |||
| } | |||
| @@ -1530,14 +1576,15 @@ std::vector<CableWidget*> RackWidget::getCablesOnPort(PortWidget* port) { | |||
| std::vector<CableWidget*> RackWidget::getCompleteCablesOnPort(PortWidget* port) { | |||
| assert(port); | |||
| std::vector<CableWidget*> cws; | |||
| for (widget::Widget* w : internal->cableContainer->children) { | |||
| CableWidget* cw = dynamic_cast<CableWidget*>(w); | |||
| assert(cw); | |||
| for (widget::Widget* w : internal->plugContainer->children) { | |||
| PlugWidget* plug = dynamic_cast<PlugWidget*>(w); | |||
| assert(plug); | |||
| CableWidget* cw = plug->getCable(); | |||
| if (!cw->isComplete()) | |||
| continue; | |||
| if (cw->inputPort == port || cw->outputPort == port) { | |||
| PortWidget* port2 = cw->getPort(plug->getType()); | |||
| if (port2 == port) | |||
| cws.push_back(cw); | |||
| } | |||
| } | |||
| return cws; | |||
| } | |||