diff --git a/comdel/display/component_display.cpp b/comdel/display/component_display.cpp index d9a89e0..14e856a 100644 --- a/comdel/display/component_display.cpp +++ b/comdel/display/component_display.cpp @@ -51,6 +51,9 @@ void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QPointF newPos = value.toPointF(); busInstance->position.first = newPos.x(); busInstance->position.second = newPos.y(); + + auto view = dynamic_cast(scene()->views()[0]); + view->updateConnections(); } return QGraphicsItem::itemChange(change, value); } @@ -62,7 +65,33 @@ void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QPointF newPos = value.toPointF(); componentInstance->position.first = newPos.x(); componentInstance->position.second = newPos.y(); + + auto view = dynamic_cast(scene()->views()[0]); + view->updateConnections(); } return QGraphicsItem::itemChange(change, value); } + + void BusConnection::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { + QMenu menu; + menu.addAction("Ukloni poveznicu", [this](){}); + menu.addSeparator(); + for(int i=0; iconnection->attributes.size(); i++) { + auto* attr = &this->connection->attributes[i]; + bool enabled = attr->attribute.getPopup().has_value(); + + auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name), + [attr]() { + if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) { + auto dialog = new MemoryDialog(attr, MainWindow::getSchema()->componentInstances); + dialog->exec(); + } else { + auto dialog = new AttributeDialog(attr); + dialog->exec(); + } + }); + action->setEnabled(enabled); + } + menu.exec(event->screenPos()); + } } // namespace display diff --git a/comdel/display/component_display.h b/comdel/display/component_display.h index 1fbe5e1..548eec5 100644 --- a/comdel/display/component_display.h +++ b/comdel/display/component_display.h @@ -5,6 +5,7 @@ #include #include +#include "comdel/domain/connectioninstance.h" namespace display { @@ -14,7 +15,7 @@ private: domain::Pin pin; public: Pin(domain::Pin pin): pin(pin) { - pin.getDisplay().render(this); + pin.getDisplayPin().render(this); } }; @@ -90,6 +91,29 @@ protected: virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); }; +class BusConnection: public QGraphicsLineItem +{ +private: + domain::BusConnectionInstance* connection; + ComponentGroup* component; + BusGroup* bus; + +public: + BusConnection(domain::BusConnectionInstance* connection, ComponentGroup *component, BusGroup *bus): connection(connection), component(component), bus(bus) { + updateConnection(); + + setHandlesChildEvents(false); + } + + void 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); + } + + void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; +}; } // namespace display diff --git a/comdel/display/schema_display.cpp b/comdel/display/schema_display.cpp index 7ff29c3..dd546a3 100644 --- a/comdel/display/schema_display.cpp +++ b/comdel/display/schema_display.cpp @@ -11,18 +11,42 @@ Schema::Schema() void Schema::setSchema(domain::Schema* _schema) { + std::map components; + std::map buses; + scene.clear(); + connections.clear(); this->schema = _schema; if(schema != nullptr) { for(auto &instance: schema->componentInstances) { - scene.addItem(new display::ComponentGroup(instance)); + auto group = new display::ComponentGroup(instance); + components.insert(std::make_pair(instance->name, group)); + scene.addItem(group); } for(auto &instance: schema->busInstances) { if(instance->bus.getDisplay().has_value()) { - scene.addItem(new display::BusGroup(instance)); + 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]); + connections.push_back(con); + scene.addItem(con); } } } } +void Schema::updateConnections() { + if(schema != nullptr) { + for(auto conn: connections) { + conn->updateConnection(); + } + } +} + } // namespace display diff --git a/comdel/display/schema_display.h b/comdel/display/schema_display.h index 06a4a86..db7ad98 100644 --- a/comdel/display/schema_display.h +++ b/comdel/display/schema_display.h @@ -9,13 +9,19 @@ namespace display { + class BusConnection; + class Schema: public QGraphicsView { public: Schema(); + std::vector connections; + void setSchema(domain::Schema* schema); + void updateConnections(); + private: QGraphicsScene scene; diff --git a/comdel/domain/display.h b/comdel/domain/display.h index 4278e99..cc46f8f 100644 --- a/comdel/domain/display.h +++ b/comdel/domain/display.h @@ -61,10 +61,90 @@ public: PinType pinType; int x, y, w, h; - Pin(int x, int y, int w, int h): x(x), y(y), w(w), h(h) {} + Pin(int x, int y, int w, int h, Orientation orientation, PinType pinType): x(x), y(y), w(w), h(h), orientation(orientation), pinType(pinType) {} + + void renderIn(QGraphicsItemGroup *group) { + QPolygon polygon; + + switch (orientation) { + case Orientation::TOP: + polygon << QPoint(x, y) << QPoint(x, y+h) << QPoint(x+w, y+h) << QPoint(x+w, y) << QPoint(x+w/2, y+h/2); + break; + case Orientation::BOTTOM: + polygon << QPoint(x, y) << QPoint(x, y+h) << QPoint(x+w/2, y+h/2) << QPoint(x+w, y+h) << QPoint(x+w, y); + break; + case Orientation::LEFT: + polygon << QPoint(x, y) << QPoint(x+w/2, y+h/2) << QPoint(x, y+h) << QPoint(x+w, y+h) << QPoint(x+w, y); + break; + case Orientation::RIGHT: + polygon << QPoint(x, y) << QPoint(x, y+h) << QPoint(x+w, y+h) << QPoint(x+w/2, y+h/2) << QPoint(x+w, y); + break; + } + group->addToGroup(new QGraphicsPolygonItem(polygon)); + } + + void renderOut(QGraphicsItemGroup *group) { + QPolygon polygon; + + switch (orientation) { + case Orientation::TOP: + polygon << QPoint(x, y+h/2) << QPoint(x, y+h) << QPoint(x+w, y+h) << QPoint(x+w, y+h/2) << QPoint(x+w/2, y); + break; + case Orientation::BOTTOM: + polygon << QPoint(x, y) << QPoint(x, y+h/2) << QPoint(x+w/2, y+h) << QPoint(x+w, y+h/2) << QPoint(x+w, y); + break; + case Orientation::LEFT: + polygon << QPoint(x+w, y) << QPoint(x+w/2, y) << QPoint(x, y+h/2) << QPoint(x+w/2, y+h) << QPoint(x+w, y+w); + break; + case Orientation::RIGHT: + polygon << QPoint(x, y) << QPoint(x, y+h) << QPoint(x+w/2, y+h) << QPoint(x+w, y+h/2) << QPoint(x+w/2, y); + break; + } + group->addToGroup(new QGraphicsPolygonItem(polygon)); + } + + void renderInOut(QGraphicsItemGroup *group) { + group->addToGroup(new QGraphicsRectItem(x, y ,w, h)); + } void render(QGraphicsItemGroup *group) { - group->addToGroup(new QGraphicsRectItem(x,y,w,h)); + switch (pinType) { + case PinType::IN: + renderIn(group); + break; + case PinType::OUT: + renderOut(group); + break; + case PinType::IN_OUT: + renderInOut(group); + break; + } + } + + int getConnectionX() { + switch (orientation) { + case ui::Orientation::TOP: + case ui::Orientation::BOTTOM: + return x+w/2; + case ui::Orientation::LEFT: + return x; + case ui::Orientation::RIGHT: + return x+w; + } + return 0; + } + + int getConnectionY() { + switch (orientation) { + case ui::Orientation::LEFT: + case ui::Orientation::RIGHT: + return y+h/2; + case ui::Orientation::TOP: + return y; + case ui::Orientation::BOTTOM: + return y+h; + } + return 0; } }; @@ -109,6 +189,8 @@ public: } } + std::vector& getItems() {return items;} + private: std::vector items; }; diff --git a/comdel/domain/pin.cpp b/comdel/domain/pin.cpp index 183e8b6..c6ede24 100644 --- a/comdel/domain/pin.cpp +++ b/comdel/domain/pin.cpp @@ -14,8 +14,8 @@ std::string PinConnection::getMessage() { } -Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional> wires) - : name(name), type(type), tooltip(tooltip), connection(connection), display(display), wires(wires) +Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin, std::optional> wires) + : name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires) {} std::string &Pin::getName() { @@ -27,8 +27,8 @@ Pin::PinType Pin::getType() { std::string Pin::getTooltip() { return tooltip; } -Display &Pin::getDisplay() { - return display; +ui::Pin &Pin::getDisplayPin() { + return displayPin; } PinConnection &Pin::getConnection() { return connection; diff --git a/comdel/domain/pin.h b/comdel/domain/pin.h index 843d7b4..87dbe33 100644 --- a/comdel/domain/pin.h +++ b/comdel/domain/pin.h @@ -43,17 +43,17 @@ private: PinType type; std::string tooltip; PinConnection connection; - Display display; + domain::ui::Pin displayPin; std::optional> wires; public: - Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional> wires); + Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin, std::optional> wires); std::string &getName(); PinType getType(); std::string getTooltip(); - Display &getDisplay(); + ui::Pin &getDisplayPin(); PinConnection &getConnection(); std::optional> &getWires(); }; diff --git a/comdel/domain/schemacreator.cpp b/comdel/domain/schemacreator.cpp index aa14599..1d5d68c 100644 --- a/comdel/domain/schemacreator.cpp +++ b/comdel/domain/schemacreator.cpp @@ -542,6 +542,12 @@ optional SchemaCreator::loadPin(PinNode node) if(!display) { return nullopt; } + if(display->getItems().size() != 1 || !display->getItems()[0].pin.has_value()) { + errors.emplace_back(node.span, "@display must contain only exactly one pin definition"); + return nullopt; + } + ui::Pin displayPin = *display->getItems()[0].pin; + if(!node.connection) { errors.emplace_back(node.span, "missing @connection"); @@ -565,16 +571,7 @@ optional SchemaCreator::loadPin(PinNode node) wiresOpt = wires; } - return Pin(name, type, tooltip, connection, *display, wiresOpt); -} - -int getIntProperty(DisplayItemNode &node, std::string property) { - for(auto& prop: node.values) { - if(prop.key.value == property) { - return prop.value.asInt(); - } - } - throw std::exception(); + return Pin(name, type, tooltip, connection, displayPin, wiresOpt); } std::optional SchemaCreator::loadDisplay(DisplayNode node) @@ -584,26 +581,53 @@ std::optional SchemaCreator::loadDisplay(DisplayNode node) ui::Item displayItem; std::string type = item.type.value; if(type == "rect") { - int x, y, w, h; - x = getIntProperty(item, "x"); - y = getIntProperty(item, "y"); - w = getIntProperty(item, "w"); - h = getIntProperty(item, "h"); + long long int x, y, w, h; + x = item.asInt(&errors, "x"); + y = item.asInt(&errors, "y"); + w = item.asInt(&errors, "w"); + h = item.asInt(&errors, "h"); displayItem.rect = ui::Rect(x, y, w, h); } else if(type == "line") { - int x1, y1, x2, y2; - x1 = getIntProperty(item, "x1"); - y1 = getIntProperty(item, "y1"); - x2 = getIntProperty(item, "x2"); - y2 = getIntProperty(item, "y2"); + long long int x1, y1, x2, y2; + x1 = item.asInt(&errors, "x1"); + y1 = item.asInt(&errors, "y1"); + x2 = item.asInt(&errors, "x2"); + y2 = item.asInt(&errors, "y2"); displayItem.line = ui::Line(x1, y1, x2, y2); } else if(type == "pin") { - int x, y, w, h; - x = getIntProperty(item, "x"); - y = getIntProperty(item, "y"); - w = getIntProperty(item, "w"); - h = getIntProperty(item, "h"); - displayItem.pin = ui::Pin(x, y, w, h); + long long int x, y, w, h; + x = item.asInt(&errors, "x"); + y = item.asInt(&errors, "y"); + w = item.asInt(&errors, "w"); + h = item.asInt(&errors, "h"); + std::string _orientation = item.asString(&errors, "orientation", "bottom"); + std::string _pinType = item.asString(&errors, "type", "out"); + + ui::Orientation orientation; + if(_orientation == "left") { + orientation = ui::Orientation::LEFT; + } else if(_orientation == "right") { + orientation = ui::Orientation::RIGHT; + } else if(_orientation == "top") { + orientation = ui::Orientation::TOP; + } else if(_orientation == "bottom") { + orientation = ui::Orientation::BOTTOM; + } else { + errors.emplace_back(item.span, "unknown orientation type '" + _orientation + "'"); + } + + ui::PinType pinType; + if(_pinType == "in") { + pinType = ui::PinType::IN; + } else if(_pinType == "out") { + pinType = ui::PinType::OUT; + } else if(_pinType == "in_out") { + pinType = ui::PinType::IN_OUT; + } else { + errors.emplace_back(item.span, "unknown pin type '" + _pinType + "'"); + } + + displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType); } else { errors.emplace_back(item.type.span, "unsupported display type"); } diff --git a/comdel/parser/astnode.h b/comdel/parser/astnode.h index b0c8df8..54cd2be 100644 --- a/comdel/parser/astnode.h +++ b/comdel/parser/astnode.h @@ -2,6 +2,7 @@ #define AST_NODE_H #include "token.h" +#include "sourceerror.h" #include #include @@ -173,6 +174,52 @@ struct DisplayItemNode: public AstNode { IdentifierNode type; std::vector values; + + long long int asInt(std::vector* errors, const std::string& property, long long int _default = 0) { + for(auto& prop: values) { + if(prop.key.value == property) { + if(prop.value.is(ValueNode::INT)) { + return prop.value.asInt(); + } else { + if(errors != nullptr) { + errors->emplace_back(prop.value.span, "expected number"); + } + } + } + } + return _default; + } + + std::string asIdentifier(std::vector* errors, const std::string& property, std::string _default = "") { + for(auto& prop: values) { + if(prop.key.value == property) { + if(prop.value.is(ValueNode::IDENTIFIER)) { + return prop.value.asIdentifier(); + } else { + if(errors != nullptr) { + errors->emplace_back(prop.value.span, "expected identifier"); + } + } + } + } + return _default; + } + + + std::string asString(std::vector* errors, const std::string& property, std::string _default = "") { + for(auto& prop: values) { + if(prop.key.value == property) { + if(prop.value.is(ValueNode::STRING)) { + return prop.value.asString(); + } else { + if(errors != nullptr) { + errors->emplace_back(prop.value.span, "expected string"); + } + } + } + } + return _default; + } }; struct DisplayNode: public AstNode