#include "component_display.h" #include "comdel/display/dialog/attribute_dialog.h" #include "comdel/display/dialog/name_dialog.h" #include "mainwindow.h" #include "application.h" #include "comdel/display/dialog/single_automatic_dialog.h" #include "comdel/display/dialog/memory_dialog.h" #include "message_source.h" #include #include #include #include #include namespace display { QPen connectionPen(QColor::fromRgb(150, 150, 250)); Component::Component(const std::shared_ptr &instance): instance(instance) { setFlag(ItemSendsGeometryChanges, true); setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName())); instance->component.getDisplay().render(this, domain::ui::DisplayContext(instance.get())); } void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu menu; menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() { std::set names; for(const auto &component: Application::instance()->getSchema()->componentInstances) { names.insert(component->name); } auto dialog = new NameDialog(this->instance->name, names); dialog->exec(); auto currentName = this->instance->name; auto newName = dialog->getName(); Application::instance()->renameComponent(currentName, newName); setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName())); }); menu.addSeparator(); for (int i = 0; i < this->instance->attributes.size(); i++) { auto *attr = &this->instance->attributes[i]; bool enabled = attr->attribute.getPopup().has_value(); if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) { menu.addAction(QMESSAGE("msg_dialog_memory_update"), [attr]() { auto dialog = new MemoryDialog(MESSAGE("msg_dialog_memory_update"), MESSAGE("msg_dialog_actions_update"), attr, Application::instance()->getSchema()->componentInstances); dialog->exec(); }); } else { std::map params = {{"attribute", attr->attribute.getDisplayName()}}; auto action = menu.addAction(QMESSAGE_PARAM("msg_dialog_attribute_update", params), [attr]() { std::map params = {{"attribute", attr->attribute.getDisplayName()}}; auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_update", params), "msg_dialog_actions_update", attr); dialog->exec(); }); action->setEnabled(enabled); } } menu.addSeparator(); std::map params = {{"name", instance->name}}; menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() { Application::instance()->removeComponent(this->instance->name); auto view = dynamic_cast(this->scene()->views()[0]); view->refreshContent(); }); menu.exec(event->screenPos()); } void Pin::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu menu; auto pinConnections = Application::instance()->getSchema()->getConnections(componentInstance->name, pin.getName()); if(isSingleAutomatic(pinConnections)) { auto *update = menu.addMenu(QMESSAGE("msg_pin_update")); auto *remove = menu.addMenu(QMESSAGE("msg_pin_remove")); for (auto pinConnection: pinConnections) { // this always must be true as only directConnections can be connected multiple times if (auto directConnection = dynamic_cast(pinConnection)) { if (directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC) { auto params = MessageSource::instance()->map( {{"wire1", directConnection->attributes[0].value}, {"wire2", directConnection->attributes[1].value}} ); update->addAction(QMESSAGE_PARAM("msg_sa_pin_update_title", params), [directConnection]() { auto params = MessageSource::instance()->map( {{"wire1", directConnection->attributes[0].value}, {"wire2", directConnection->attributes[1].value}} ); auto dialog = new SingleAutomaticDialog(MESSAGE_PARAM("msg_sa_pin_update_title", params), MESSAGE("msg_pin_update_action"), directConnection->attributes); dialog->exec(); }); remove->addAction(QMESSAGE_PARAM("msg_sa_pin_remove_title", params), [this, directConnection]() { Application::instance()->removeConnection(directConnection); auto view = dynamic_cast(this->scene()->views()[0]); view->refreshContent(); }); } } } } else if(!pinConnections.empty()) { auto pinConnection = pinConnections[0]; if(auto busConnection = dynamic_cast(pinConnection)) { menu.addSection(QString::fromStdString(busConnection->bus->name)); } else if(auto directConnection = dynamic_cast(pinConnection)) { if(directConnection->instance == componentInstance.get()) { menu.addSection(QString::fromStdString(directConnection->secondInstance->name + "." + directConnection->connection.getSecondComponent()->pin)); } else { menu.addSection(QString::fromStdString(directConnection->instance->name + "." + directConnection->connection.getComponent().pin)); } } for (int i = 0; i < pinConnection->attributes.size(); i++) { auto *attr = &pinConnection->attributes[i]; std::map params = {{"name", attr->attribute.getDisplayName()}}; menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_update_named", params), [attr]() { std::map params = {{"name", attr->attribute.getDisplayName()}}; auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_actions_update_named", params), "msg_pin_update_action", attr); dialog->exec(); }); } menu.addAction(QMESSAGE("msg_pin_remove_action"), [this, pinConnection]() { Application::instance()->removeConnection(pinConnection); auto view = dynamic_cast(this->scene()->views()[0]); view->refreshContent(); }); } menu.exec(event->screenPos()); } void Pin::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::MouseButton::LeftButton) { auto view = dynamic_cast(this->scene()->views()[0]); view->state = Schema::CREATING_CONNECTION; view->context.pin = this; view->context.startingPoint = dynamic_cast(this->parentItem())->pos() + QPointF(pin.getDisplayPin().getConnectionX(), pin.getDisplayPin().getConnectionY()); view->context.line = new QGraphicsLineItem(QLineF(view->context.startingPoint, event->scenePos())); view->context.line->setPen(QPen(QColor::fromRgb(100, 100, 250), 1, Qt::PenStyle::DashLine)); view->context.line->setZValue(1000); this->scene()->addItem(view->context.line); view->showConnectable(this); } } void Pin::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { auto view = dynamic_cast(this->scene()->views()[0]); if (view->state == Schema::CREATING_CONNECTION) { auto line = view->context.line->line(); line.setP2(event->scenePos()); view->context.line->setLine(line); } } void Pin::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::MouseButton::LeftButton) { auto view = dynamic_cast(this->scene()->views()[0]); view->state = Schema::DEFAULT; this->scene()->removeItem(view->context.line); delete view->context.line; view->removeConnectable(event->scenePos()); } } domain::Pin &Pin::getPin() { return pin; } domain::ComponentInstance *Pin::getComponentInstance() { return componentInstance.get(); } bool Pin::isSingleAutomatic(std::vector pinConnections) { if(pinConnections.empty()) { return false; } auto pinConnection = pinConnections[0]; if(auto directConnection = dynamic_cast(pinConnection)) { return directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC; } else { return false; } } Bus::Bus(const std::shared_ptr &instance): busInstance(instance) { instance->bus.getDisplayBus()->render(this, instance->size); setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getName())); } void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu menu; menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() { std::set names; for(const auto &component: Application::instance()->getSchema()->busInstances) { names.insert(component->name); } auto dialog = new NameDialog(this->busInstance->name, names); dialog->exec(); auto currentName = this->busInstance->name; auto newName = dialog->getName(); Application::instance()->renameBus(currentName, newName); setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getDisplayName())); }); menu.addSeparator(); std::map params = {{"name", busInstance->name}}; menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() { Application::instance()->removeBus(this->busInstance->name); auto view = dynamic_cast(this->scene()->views()[0]); view->refreshContent(); }); menu.exec(event->screenPos()); } QVariant BusGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if (change == ItemPositionChange && scene()) { // value is the new position. QPoint newPos = value.toPointF().toPoint(); busInstance->position.first = newPos.x(); busInstance->position.second = newPos.y(); auto view = dynamic_cast(scene()->views()[0]); view->updateConnections(); } return QGraphicsItem::itemChange(change, value); } BusGroup::BusGroup(const std::shared_ptr &instance) : busInstance(instance) { setFlag(ItemIsMovable, true); setFlag(ItemSendsGeometryChanges, true); setHandlesChildEvents(false); bus = new display::Bus(instance); addToGroup(bus); setPos(instance->position.first, instance->position.second); } QVariant ComponentGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if (change == ItemPositionChange && scene()) { // value is the new position. QPoint newPos = value.toPointF().toPoint(); componentInstance->position.first = newPos.x(); componentInstance->position.second = newPos.y(); auto view = dynamic_cast(scene()->views()[0]); view->updateConnections(); } return QGraphicsItem::itemChange(change, value); } std::shared_ptr ComponentGroup::getComponentInstance() { return componentInstance; } std::vector &ComponentGroup::getPins() { return pins; } ComponentGroup::ComponentGroup(const std::shared_ptr &instance): componentInstance( instance) { setFlag(ItemIsMovable, true); setFlag(ItemSendsGeometryChanges, true); setHandlesChildEvents(false); addToGroup(new display::Component(instance)); for (auto &pin: instance->component.getPins()) { pins.push_back(new display::Pin(pin, componentInstance)); addToGroup(pins.back()); } setPos(instance->position.first, instance->position.second); } BusConnection::BusConnection(domain::BusConnectionInstance *connection, ComponentGroup *component, BusGroup *bus): connection( connection), component(component), bus(bus) { updateConnection(); setPen(connectionPen); setZValue(-1); setHandlesChildEvents(false); } void BusConnection::updateConnection() { auto busPosition = bus->boundingRect(); auto pin = connection->instance->component.getPin( connection->connection.getComponent().pin).getDisplayPin(); setLine(connection->instance->position.first + pin.getConnectionX(), connection->instance->position.second + pin.getConnectionY(), connection->bus->position.first + busPosition.width() / 2, connection->bus->position.second + busPosition.height() / 2); connection->start.first = connection->instance->position.first + pin.getConnectionX(); connection->start.second = connection->instance->position.second + pin.getConnectionY(); connection->end.first = connection->bus->position.first + busPosition.width() / 2; connection->end.second = connection->bus->position.second + busPosition.height() / 2; } DirectConnection::DirectConnection(domain::DirectConnectionInstance *connection, ComponentGroup *first, ComponentGroup *second): connection(connection), first(first), second(second) { updateConnection(); setPen(connectionPen); setZValue(-1); setHandlesChildEvents(false); } void DirectConnection::updateConnection() { domain::ui::Pin pin1, pin2; if(connection->connection.getComponent().component == connection->instance->component.getName()) { pin1 = connection->instance->component.getPin( connection->connection.getComponent().pin).getDisplayPin(); pin2 = connection->secondInstance->component.getPin( connection->connection.getSecondComponent()->pin).getDisplayPin(); } else { pin1 = connection->instance->component.getPin( connection->connection.getSecondComponent()->pin).getDisplayPin(); pin2 = connection->secondInstance->component.getPin( connection->connection.getComponent().pin).getDisplayPin(); } setLine(connection->instance->position.first + pin1.getConnectionX(), connection->instance->position.second + pin1.getConnectionY(), connection->secondInstance->position.first + pin2.getConnectionX(), connection->secondInstance->position.second + pin2.getConnectionY()); connection->start.first = connection->instance->position.first + pin1.getConnectionX(); connection->start.second = connection->instance->position.second + pin1.getConnectionY(); connection->end.first = connection->secondInstance->position.first + pin2.getConnectionX(); connection->end.second = connection->secondInstance->position.second + pin2.getConnectionY(); } } // namespace display