#include "component_display.h" #include "schema_display.h" #include "application.h" #include "attribute_dialog.h" #include "single_automatic_dialog.h" #include #include #include namespace display { Schema::Schema() { this->selectedBrush.setColor(QColor::fromRgb(20, 20, 125)); this->selectedPen.setColor(QColor::fromRgb(20, 20, 125)); schema = nullptr; library = std::nullopt; this->setScene(&scene); this->setAcceptDrops(true); } void Schema::refreshContent() { schema = Application::instance()->getSchema(); library = Application::instance()->getLibrary(); components.clear(); buses.clear(); scene.clear(); busConnections.clear(); if (schema != nullptr) { for (auto &instance: schema->componentInstances) { auto group = new display::ComponentGroup(instance); for (auto pin: group->getPins()) { display::Pin *p = pin; domain::ConnectionComponent connection{instance->name, p->getPin().getName()}; pins.insert(std::make_pair(connection, p)); } components.insert(std::make_pair(instance->name, group)); scene.addItem(group); } for (auto &instance: schema->busInstances) { if (instance->bus.getDisplayBus().has_value()) { auto group = new display::BusGroup(instance); buses.insert(std::make_pair(instance->name, group)); scene.addItem(group); } } for (auto &connection: schema->connections) { auto busInstance = dynamic_cast(connection.get()); if (busInstance != nullptr) { auto con = new display::BusConnection(busInstance, components[busInstance->instance->name], buses[busInstance->bus->name]); busConnections.push_back(con); scene.addItem(con); } auto directInstance = dynamic_cast(connection.get()); if (directInstance != nullptr) { auto con = new display::DirectConnection(directInstance, components[directInstance->instance->name], components[directInstance->secondInstance->name]); directConnections.push_back(con); scene.addItem(con); } } } } void Schema::updateConnections() { if (schema != nullptr) { for (auto conn: busConnections) { conn->updateConnection(); } for (auto conn: directConnections) { conn->updateConnection(); } } } void Schema::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("comdel/component") || event->mimeData()->hasFormat("comdel/bus")) { event->acceptProposedAction(); } } void Schema::dropEvent(QDropEvent *event) { if (event->mimeData()->hasFormat("comdel/component")) { auto component = library->getComponent(event->mimeData()->data("comdel/component").toStdString()); auto attributes = populateAttributes(component.getAttributes()); if(attributes.size() != component.getAttributes().size()) { return; } auto currentPos = this->mapToScene(event->pos()).toPoint(); auto instance = Application::instance()->addComponent(component, attributes, currentPos.x(), currentPos.y()); auto group = new display::ComponentGroup(instance); scene.addItem(group); for (auto pin: group->getPins()) { display::Pin *p = pin; domain::ConnectionComponent connection{instance->name, p->getPin().getName()}; pins.insert(std::make_pair(connection, p)); } components[instance->name] = group; event->acceptProposedAction(); } if (event->mimeData()->hasFormat("comdel/bus")) { auto bus = library->getBus(event->mimeData()->data("comdel/bus").toStdString()); auto currentPos = this->mapToScene(event->pos()).toPoint(); auto instance = Application::instance()->addBus(bus, currentPos.x(), currentPos.y()); auto group = new display::BusGroup(instance); scene.addItem(group); buses[instance->name] = group; event->acceptProposedAction(); } } void Schema::dragMoveEvent(QDragMoveEvent *event) { event->acceptProposedAction(); } void Schema::removeConnectable(QPointF endPoint) { auto instance = context.pin->getComponentInstance(); auto &pin = context.pin->getPin(); auto busInstances = getAvailableConnectionBusses(instance, pin); for (auto &bus: busInstances) { if(buses[bus->name] == nullptr) { continue; } auto rect = buses[bus->name]->boundingRect(); rect = QRectF(buses[bus->name]->x(), buses[bus->name]->y(), rect.width(), rect.height()); if (rect.contains(endPoint)) { auto con = library->getConnection({instance->component.getName(), pin.getName()}, bus->bus.getName()); if (con.has_value()) { auto attributes = populateAttributes(con->getAttributes()); if(attributes.size() != con->getAttributes().size()) { return; } auto conInstance = std::make_shared(instance, attributes, bus, *con); schema->connections.push_back(conInstance); if (conInstance != nullptr) { auto c = new display::BusConnection(conInstance.get(), components[conInstance->instance->name], buses[conInstance->bus->name]); busConnections.push_back(c); scene.addItem(c); } break; } } } auto pinInstances = getAvailableConnectionPins(instance, pin); for (auto &pinInstance: pinInstances) { auto rect = pins[pinInstance]->boundingRect(); rect.setX(pins[pinInstance]->scenePos().x()); rect.setY(pins[pinInstance]->scenePos().y()); if (rect.contains(endPoint)) { auto name = components[pinInstance.component]->getComponentInstance()->component.getName(); auto con = library->getConnection({instance->component.getName(), pin.getName()}, {name, pinInstance.pin}); if (con.has_value()) { auto busInstance = Application::instance()->addBus(library->getBus(con->getBus()), 0, 0); std::vector attributes; if(library->getBus(con->getBus()).getType() == domain::Bus::SINGLE_AUTOMATIC) { attributes = populateSingleAutomaticConnection(*con); } else { attributes = populateAttributes(con->getAttributes()); } if(attributes.size() != con->getAttributes().size()) { return; } auto conInstance = std::make_shared(instance, components[pinInstance.component]->getComponentInstance().get(), attributes, busInstance.get(), *con); schema->connections.push_back(conInstance); if (conInstance != nullptr) { auto c = new display::DirectConnection(conInstance.get(), components[conInstance->instance->name], components[conInstance->secondInstance->name]); directConnections.push_back(c); scene.addItem(c); } break; } } } updateConnections(); for (auto &item: this->context.selectable) { this->scene.removeItem(item); delete item; } this->context.selectable.clear(); } void Schema::showConnectable(Pin *domainPin) { auto &pin = domainPin->getPin(); auto busInstances = getAvailableConnectionBusses(domainPin->getComponentInstance(), domainPin->getPin()); for (auto bus: busInstances) { auto &group = buses[bus->name]; if(group == nullptr) { continue; } auto rect = new QGraphicsRectItem(group->boundingRect()); rect->setPen(selectedPen); rect->setPos(group->scenePos()); auto _rect = rect->rect(); _rect.setWidth(_rect.width() + 1); _rect.setHeight(_rect.height() + 1); rect->setRect(_rect); context.selectable.push_back(rect); scene.addItem(rect); } std::vector pinInstances = getAvailableConnectionPins( domainPin->getComponentInstance(), domainPin->getPin()); for (auto &pinInstance: pinInstances) { auto &instance = pins[pinInstance]; auto rect = new QGraphicsRectItem(instance->boundingRect()); rect->setPen(selectedPen); rect->setPos(instance->scenePos()); auto _rect = rect->rect(); _rect.setWidth(_rect.width() + 1); _rect.setHeight(_rect.height() + 1); rect->setRect(_rect); context.selectable.push_back(rect); scene.addItem(rect); } } std::vector Schema::getAvailableConnectionBusses(domain::ComponentInstance *instance, domain::Pin &pin) { std::vector instances; for (const auto &bus: schema->busInstances) { if (library->hasConnection(domain::ConnectionComponent{instance->component.getName(), pin.getName()}, bus->bus.getName())) { instances.push_back(bus.get()); } } return instances; } std::vector Schema::getAvailableConnectionPins(domain::ComponentInstance *instance, domain::Pin &pin) { std::vector instances; domain::ConnectionComponent source{instance->component.getName(), pin.getName()}; for (const auto &entry: pins) { std::string name = components[entry.first.component]->getComponentInstance()->component.getName(); if (library->hasConnection(source, domain::ConnectionComponent{name, entry.first.pin})) { instances.push_back(entry.first); } } return instances; } std::vector Schema::populateAttributes(std::vector& attributes) { std::vector instanceAttributes; for (auto attr: attributes) { domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr); if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) { if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) { auto dialog = new MemoryDialog(&attribute, schema->componentInstances); if(dialog->exec() == QDialog::Rejected) { // if any dialog isn't set, whole creation is rejected return {}; } } else { auto dialog = new AttributeDialog(&attribute); if(dialog->exec() == QDialog::Rejected) { // if any dialog isn't set, whole creation is rejected return {}; } } } instanceAttributes.push_back(attribute); } return instanceAttributes; } std::vector Schema::populateSingleAutomaticConnection(domain::Connection connection) { std::vector instanceAttributes; for (auto attr: connection.getAttributes()) { instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr); } auto dialog = new display::SingleAutomaticDialog(instanceAttributes); if(dialog->exec() == QDialog::Rejected) { // if dialog is rejected, whole creation is rejected return {}; } return instanceAttributes; } } // namespace display