Compare commits

..

3 Commits

Author SHA1 Message Date
Borna Rajković 1100a9f0b9 Added connection display 2022-05-19 21:08:00 +02:00
Borna Rajković f11551fef6 Added connection display 2022-05-18 00:14:33 +02:00
Borna Rajković 281926cb8b Added movement storing 2022-05-17 21:31:32 +02:00
12 changed files with 363 additions and 52 deletions

View File

@ -5,7 +5,6 @@
#include <QMenu> #include <QMenu>
#include <QGraphicsSceneContextMenuEvent> #include <QGraphicsSceneContextMenuEvent>
#include <QGraphicsScene>
#include <iostream> #include <iostream>
namespace display { namespace display {
@ -46,4 +45,66 @@ void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
menu.exec(event->screenPos()); menu.exec(event->screenPos());
} }
QVariant BusGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) {
if (change == ItemPositionChange && scene()) {
// value is the new position.
QPointF newPos = value.toPointF();
busInstance->position.first = newPos.x();
busInstance->position.second = newPos.y();
auto view = dynamic_cast<Schema*>(scene()->views()[0]);
view->updateConnections();
}
return QGraphicsItem::itemChange(change, value);
}
QVariant ComponentGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) {
if (change == ItemPositionChange && scene()) {
// value is the new position.
QPointF newPos = value.toPointF();
componentInstance->position.first = newPos.x();
componentInstance->position.second = newPos.y();
auto view = dynamic_cast<Schema*>(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; i<this->connection->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]() {
auto dialog = new AttributeDialog(attr);
dialog->exec();
});
action->setEnabled(enabled);
}
menu.exec(event->screenPos());
}
void DirectConnection::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QMenu menu;
menu.addAction("Ukloni poveznicu", [this](){});
menu.addSeparator();
for(int i=0; i<this->connection->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]() {
auto dialog = new AttributeDialog(attr);
dialog->exec();
});
action->setEnabled(enabled);
}
menu.exec(event->screenPos());
}
} // namespace display } // namespace display

View File

@ -5,6 +5,7 @@
#include <comdel/domain/wireinstance.h> #include <comdel/domain/wireinstance.h>
#include <QGraphicsItemGroup> #include <QGraphicsItemGroup>
#include "comdel/domain/connectioninstance.h"
namespace display { namespace display {
@ -14,7 +15,7 @@ private:
domain::Pin pin; domain::Pin pin;
public: public:
Pin(domain::Pin pin): pin(pin) { Pin(domain::Pin pin): pin(pin) {
pin.getDisplay().render(this); pin.getDisplayPin().render(this);
} }
}; };
@ -24,9 +25,12 @@ private:
std::shared_ptr<domain::ComponentInstance> instance; std::shared_ptr<domain::ComponentInstance> instance;
public: public:
Component(const std::shared_ptr<domain::ComponentInstance>& instance): instance(instance) { Component(const std::shared_ptr<domain::ComponentInstance>& instance): instance(instance) {
setFlag(ItemSendsGeometryChanges, true);
instance->component.getDisplay().render(this); instance->component.getDisplay().render(this);
} }
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
}; };
class Bus: public QGraphicsItemGroup class Bus: public QGraphicsItemGroup
@ -37,6 +41,7 @@ public:
instance->bus.getDisplay()->render(this); instance->bus.getDisplay()->render(this);
} }
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
}; };
class ComponentGroup: public QGraphicsItemGroup class ComponentGroup: public QGraphicsItemGroup
@ -47,6 +52,8 @@ private:
public: public:
explicit ComponentGroup(const std::shared_ptr<domain::ComponentInstance>& instance): componentInstance(instance) { explicit ComponentGroup(const std::shared_ptr<domain::ComponentInstance>& instance): componentInstance(instance) {
setFlag(ItemIsMovable, true); setFlag(ItemIsMovable, true);
setFlag(ItemSendsGeometryChanges, true);
setHandlesChildEvents(false); setHandlesChildEvents(false);
addToGroup(new display::Component(instance)); addToGroup(new display::Component(instance));
@ -57,6 +64,10 @@ public:
setPos(instance->position.first, instance->position.second); setPos(instance->position.first, instance->position.second);
} }
protected:
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);
}; };
class BusGroup: public QGraphicsItemGroup class BusGroup: public QGraphicsItemGroup
@ -67,14 +78,70 @@ private:
public: public:
explicit BusGroup(const std::shared_ptr<domain::BusInstance>& instance): busInstance(instance) { explicit BusGroup(const std::shared_ptr<domain::BusInstance>& instance): busInstance(instance) {
setFlag(ItemIsMovable, true); setFlag(ItemIsMovable, true);
setFlag(ItemSendsGeometryChanges, true);
setHandlesChildEvents(false); setHandlesChildEvents(false);
addToGroup(new display::Bus(instance)); addToGroup(new display::Bus(instance));
setPos(instance->position.first, instance->position.second); setPos(instance->position.first, instance->position.second);
} }
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;
};
class DirectConnection: public QGraphicsLineItem
{
private:
domain::DirectConnectionInstance* connection;
ComponentGroup* first;
ComponentGroup* second;
BusGroup* bus;
public:
DirectConnection(domain::DirectConnectionInstance* connection, ComponentGroup *first, ComponentGroup *second, BusGroup *bus): connection(connection), first(first), second(second), bus(bus) {
updateConnection();
setHandlesChildEvents(false);
}
void updateConnection() {
auto pin1 = connection->instance->component.getPin(connection->connection.getComponent().pin).getDisplayPin();
auto pin2 = connection->secondInstance->component.getPin(connection->connection.getSecondComponent()->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());
}
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
};
} // namespace display } // namespace display
#endif // DISPLAY_COMPONENT_H #endif // DISPLAY_COMPONENT_H

View File

@ -11,18 +11,42 @@ Schema::Schema()
void Schema::setSchema(domain::Schema* _schema) void Schema::setSchema(domain::Schema* _schema)
{ {
std::map<std::string, display::ComponentGroup*> components;
std::map<std::string, display::BusGroup*> buses;
scene.clear(); scene.clear();
connections.clear();
this->schema = _schema; this->schema = _schema;
if(schema != nullptr) { if(schema != nullptr) {
for(auto &instance: schema->componentInstances) { 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) { for(auto &instance: schema->busInstances) {
if(instance->bus.getDisplay().has_value()) { 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<domain::BusConnectionInstance*>(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 } // namespace display

View File

@ -9,13 +9,19 @@
namespace display { namespace display {
class BusConnection;
class Schema: public QGraphicsView class Schema: public QGraphicsView
{ {
public: public:
Schema(); Schema();
std::vector<BusConnection*> connections;
void setSchema(domain::Schema* schema); void setSchema(domain::Schema* schema);
void updateConnections();
private: private:
QGraphicsScene scene; QGraphicsScene scene;

View File

@ -61,10 +61,90 @@ public:
PinType pinType; PinType pinType;
int x, y, w, h; 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) { 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<ui::Item>& getItems() {return items;}
private: private:
std::vector<ui::Item> items; std::vector<ui::Item> items;
}; };

View File

@ -14,8 +14,8 @@ std::string PinConnection::getMessage() {
} }
Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional<std::vector<Value>> wires) Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin, std::optional<std::vector<Value>> wires)
: name(name), type(type), tooltip(tooltip), connection(connection), display(display), wires(wires) : name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires)
{} {}
std::string &Pin::getName() { std::string &Pin::getName() {
@ -27,8 +27,8 @@ Pin::PinType Pin::getType() {
std::string Pin::getTooltip() { std::string Pin::getTooltip() {
return tooltip; return tooltip;
} }
Display &Pin::getDisplay() { ui::Pin &Pin::getDisplayPin() {
return display; return displayPin;
} }
PinConnection &Pin::getConnection() { PinConnection &Pin::getConnection() {
return connection; return connection;

View File

@ -43,17 +43,17 @@ private:
PinType type; PinType type;
std::string tooltip; std::string tooltip;
PinConnection connection; PinConnection connection;
Display display; domain::ui::Pin displayPin;
std::optional<std::vector<Value>> wires; std::optional<std::vector<Value>> wires;
public: public:
Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional<std::vector<Value>> wires); Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin, std::optional<std::vector<Value>> wires);
std::string &getName(); std::string &getName();
PinType getType(); PinType getType();
std::string getTooltip(); std::string getTooltip();
Display &getDisplay(); ui::Pin &getDisplayPin();
PinConnection &getConnection(); PinConnection &getConnection();
std::optional<std::vector<Value>> &getWires(); std::optional<std::vector<Value>> &getWires();
}; };

View File

@ -542,6 +542,12 @@ optional<Pin> SchemaCreator::loadPin(PinNode node)
if(!display) { if(!display) {
return nullopt; 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) { if(!node.connection) {
errors.emplace_back(node.span, "missing @connection"); errors.emplace_back(node.span, "missing @connection");
@ -565,16 +571,7 @@ optional<Pin> SchemaCreator::loadPin(PinNode node)
wiresOpt = wires; wiresOpt = wires;
} }
return Pin(name, type, tooltip, connection, *display, wiresOpt); return Pin(name, type, tooltip, connection, displayPin, 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();
} }
std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node) std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node)
@ -584,26 +581,53 @@ std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node)
ui::Item displayItem; ui::Item displayItem;
std::string type = item.type.value; std::string type = item.type.value;
if(type == "rect") { if(type == "rect") {
int x, y, w, h; long long int x, y, w, h;
x = getIntProperty(item, "x"); x = item.asInt(&errors, "x");
y = getIntProperty(item, "y"); y = item.asInt(&errors, "y");
w = getIntProperty(item, "w"); w = item.asInt(&errors, "w");
h = getIntProperty(item, "h"); h = item.asInt(&errors, "h");
displayItem.rect = ui::Rect(x, y, w, h); displayItem.rect = ui::Rect(x, y, w, h);
} else if(type == "line") { } else if(type == "line") {
int x1, y1, x2, y2; long long int x1, y1, x2, y2;
x1 = getIntProperty(item, "x1"); x1 = item.asInt(&errors, "x1");
y1 = getIntProperty(item, "y1"); y1 = item.asInt(&errors, "y1");
x2 = getIntProperty(item, "x2"); x2 = item.asInt(&errors, "x2");
y2 = getIntProperty(item, "y2"); y2 = item.asInt(&errors, "y2");
displayItem.line = ui::Line(x1, y1, x2, y2); displayItem.line = ui::Line(x1, y1, x2, y2);
} else if(type == "pin") { } else if(type == "pin") {
int x, y, w, h; long long int x, y, w, h;
x = getIntProperty(item, "x"); x = item.asInt(&errors, "x");
y = getIntProperty(item, "y"); y = item.asInt(&errors, "y");
w = getIntProperty(item, "w"); w = item.asInt(&errors, "w");
h = getIntProperty(item, "h"); h = item.asInt(&errors, "h");
displayItem.pin = ui::Pin(x, y, w, 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 { } else {
errors.emplace_back(item.type.span, "unsupported display type"); errors.emplace_back(item.type.span, "unsupported display type");
} }
@ -946,7 +970,7 @@ vector<Enumeration> SchemaCreator::createWireEnumeration(vector<Value> wireValue
} }
std::optional<Attribute> SchemaCreator::createMemoryAttribute() { std::optional<Attribute> SchemaCreator::createMemoryAttribute() {
return Attribute("_memory", Value::fromMemoryReference(nullopt), createMemoryPopup()); return Attribute("_memory", Value::fromMemoryReference(std::nullopt), createMemoryPopup());
} }
std::optional<Popup> SchemaCreator::createMemoryPopup() { std::optional<Popup> SchemaCreator::createMemoryPopup() {

View File

@ -162,10 +162,10 @@ std::string Value::stringify() {
case ATTRIBUTE_REFERENCE: case ATTRIBUTE_REFERENCE:
return reference; return reference;
case MEMORY_REFERENCE: case MEMORY_REFERENCE:
if(memoryReference->empty()) { if(memoryReference.has_value()) {
return "null";
} else {
return memoryReference.value(); return memoryReference.value();
} else {
return "null";
} }
default: default:
throw std::exception(); throw std::exception();

View File

@ -29,22 +29,20 @@ public:
}; };
private: private:
long long intValue; long long intValue = 0;
std::string stringValue; std::string stringValue;
bool boolValue; bool boolValue = false;
std::optional<AddressSpace> addressSpace; std::optional<AddressSpace> addressSpace = std::nullopt;
std::string reference; std::string reference;
domain::ComponentInstance *memory; domain::ComponentInstance *memory = nullptr;
std::optional<std::string> memoryReference; std::optional<std::string> memoryReference = std::nullopt;
ValueType type; ValueType type = UNDEFINED;
public: public:
Value() { Value() {}
this->type = UNDEFINED;
}
bool equals(Value value) { bool equals(Value value) {
if(value.getType() == type) { if(value.getType() == type) {

View File

@ -2,6 +2,7 @@
#define AST_NODE_H #define AST_NODE_H
#include "token.h" #include "token.h"
#include "sourceerror.h"
#include <optional> #include <optional>
#include <vector> #include <vector>
@ -173,6 +174,52 @@ struct DisplayItemNode: public AstNode
{ {
IdentifierNode type; IdentifierNode type;
std::vector<PropertyNode> values; std::vector<PropertyNode> values;
long long int asInt(std::vector<SourceError>* 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<SourceError>* 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<SourceError>* 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 struct DisplayNode: public AstNode

View File

@ -193,6 +193,8 @@ void MainWindow::onValidateSchema(bool /*toggled*/) {
return; return;
} }
log->clear();
this->validationErrors.clear(); this->validationErrors.clear();
domain::ComdelValidator validator{validators}; domain::ComdelValidator validator{validators};