From 09991904e9adfd73d835a184f6df3e20e95fe08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borna=20Rajkovi=C4=87?= Date: Sun, 12 Jun 2022 16:02:24 +0200 Subject: [PATCH] Added dynamic color support + text display item --- CMakeLists.txt | 2 +- comdel/display/component_display.cpp | 2 +- comdel/display/name_dialog.cpp | 6 +- comdel/domain/display.cpp | 85 ++++++++++++++++--- comdel/domain/display.h | 58 +++++++++++-- comdel/domain/schema_creator.cpp | 24 ++++-- comdel/parser/ast_nodes.cpp | 30 ++++++- comdel/parser/ast_nodes.h | 31 +++++++ comdel/parser/color.cpp | 5 ++ comdel/parser/color.h | 21 +++++ comdel/parser/comdel_parser.cpp | 23 ++++- comdel/parser/comdel_parser.h | 2 + .../simplified FRISC model/frisc_library.csl | 12 +++ 13 files changed, 265 insertions(+), 36 deletions(-) create mode 100644 comdel/parser/color.cpp create mode 100644 comdel/parser/color.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aeb9af..5478eb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,5 +37,5 @@ add_executable(SchemeEditor comdel/parser/comdel_lexer.cpp main.cpp mainwindow.ui - comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/single_automatic_dialog.cpp comdel/display/single_automatic_dialog.h) + comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/single_automatic_dialog.cpp comdel/display/single_automatic_dialog.h comdel/parser/color.cpp comdel/parser/color.h) target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets) diff --git a/comdel/display/component_display.cpp b/comdel/display/component_display.cpp index ad2ed10..8e33321 100644 --- a/comdel/display/component_display.cpp +++ b/comdel/display/component_display.cpp @@ -19,7 +19,7 @@ namespace display { Component::Component(const std::shared_ptr &instance): instance(instance) { setFlag(ItemSendsGeometryChanges, true); setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getName())); - instance->component.getDisplay().render(this); + instance->component.getDisplay().render(this, domain::ui::DisplayContext(instance.get())); } void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { diff --git a/comdel/display/name_dialog.cpp b/comdel/display/name_dialog.cpp index 45837ca..539e8e1 100644 --- a/comdel/display/name_dialog.cpp +++ b/comdel/display/name_dialog.cpp @@ -20,13 +20,13 @@ display::NameDialog::NameDialog(std::string currentName, std::set & auto buttonLayout = new QHBoxLayout(this); - auto okButton = new QPushButton("Ažuriraj"); + button = new QPushButton("Ažuriraj"); auto cancelButton = new QPushButton("Odustani", this); - connect(okButton, &QPushButton::clicked, this, &NameDialog::onNameChange); + connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange); connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); - buttonLayout->addWidget(okButton); + buttonLayout->addWidget(button); buttonLayout->addWidget(cancelButton); layout->addLayout(buttonLayout); diff --git a/comdel/domain/display.cpp b/comdel/domain/display.cpp index 985edd7..7b0327d 100644 --- a/comdel/domain/display.cpp +++ b/comdel/domain/display.cpp @@ -2,17 +2,17 @@ #include #include +#include + +#include "comdel/domain/instance.h" namespace domain { - QBrush busBrush(QColor::fromRgb(200, 200, 200)); - QPen busPen(QColor::fromRgb(200, 200, 200)); - Display::Display(std::vector items) : items(items) {} - void Display::render(QGraphicsItemGroup *group) { + void Display::render(QGraphicsItemGroup *group, ui::DisplayContext context) { for (auto &item: items) { - item.render(group); + item.render(group, context); } } @@ -22,8 +22,26 @@ namespace domain { } } + void ui::Text::render(QGraphicsItemGroup *group, ui::DisplayContext context) { + auto formattedText = context.populateMessage(text); + + auto content = new QGraphicsTextItem(QString::fromStdString(formattedText)); + content->setDefaultTextColor(color); + content->setPos(x, y); + content->setFont(QFont("arial", 8)); + group->addToGroup(content); + } + + void ui::Text::comdel(std::ostream &buffer, int x, int y) { + // TODO + } + + void ui::Rect::render(QGraphicsItemGroup *group) { - group->addToGroup(new QGraphicsRectItem(x, y, w, h)); + auto rect = new QGraphicsRectItem(x, y, w, h); + rect->setPen(QPen(config.lineColor)); + rect->setBrush(QBrush(config.fillColor)); + group->addToGroup(rect); } void ui::Rect::comdel(std::ostream &buffer, int x, int y) { @@ -34,7 +52,9 @@ namespace domain { } void ui::Line::render(QGraphicsItemGroup *group) { - group->addToGroup(new QGraphicsLineItem(x1, y1, x2, y2)); + auto line = new QGraphicsLineItem(x1, y1, x2, y2); + line->setPen(QPen(config.lineColor)); + group->addToGroup(line); } void ui::Line::comdel(std::ostream &buffer, int x, int y) { @@ -52,8 +72,8 @@ namespace domain { _h = size; } auto rect = new QGraphicsRectItem(x, y, _w, _h); - rect->setBrush(busBrush); - rect->setPen(busPen); + rect->setBrush(QBrush(config.fillColor)); + rect->setPen(QPen(config.lineColor)); group->addToGroup(rect); } @@ -97,7 +117,11 @@ namespace domain { << QPoint(x + w / 2, y + h / 2) << QPoint(x + w, y); break; } - group->addToGroup(new QGraphicsPolygonItem(polygon)); + auto item = new QGraphicsPolygonItem(polygon); + item->setFillRule(Qt::OddEvenFill); + item->setBrush(QBrush(config.fillColor)); + item->setPen(QPen(config.lineColor)); + group->addToGroup(item); } void ui::Pin::renderOut(QGraphicsItemGroup *group) { @@ -121,11 +145,18 @@ namespace domain { << QPoint(x + w, y + h / 2) << QPoint(x + w / 2, y); break; } - group->addToGroup(new QGraphicsPolygonItem(polygon)); + auto item = new QGraphicsPolygonItem(polygon); + item->setFillRule(Qt::OddEvenFill); + item->setBrush(QBrush(config.fillColor)); + item->setPen(QPen(config.lineColor)); + group->addToGroup(item); } void ui::Pin::renderInOut(QGraphicsItemGroup *group) { - group->addToGroup(new QGraphicsRectItem(x, y, w, h)); + auto rect = new QGraphicsRectItem(x, y, w, h); + rect->setBrush(QBrush(config.fillColor)); + rect->setPen(QPen(config.lineColor)); + group->addToGroup(rect); } void ui::Pin::render(QGraphicsItemGroup *group) { @@ -168,11 +199,12 @@ namespace domain { return 0; } - void ui::Item::render(QGraphicsItemGroup *group, int size) { + void ui::Item::render(QGraphicsItemGroup *group, ui::DisplayContext context, int size) { if (rect) rect->render(group); if (line) line->render(group); if (pin) pin->render(group); if (bus) bus->render(group, size); + if (text) text->render(group, context); } void ui::Item::comdel(std::ostream &buffer, int x, int y, int size) { @@ -180,5 +212,32 @@ namespace domain { if (line) line->comdel(buffer, x, y); // pins aren't exported if (bus) bus->comdel(buffer, x, y, size); + // text currently isn't exported TODO + } + + ui::DisplayContext::DisplayContext(ComponentInstance *instance) { + for(auto attr: instance->attributes) { + this->values[attr.name] = attr.value; + } + this->values["instanceName"] = Value::fromString(instance->name); + } + + string replacePlaceholder(string source, string key, Value value) { + key = "{" + key + "}"; + auto placeholderValue = value.string(); + + auto found = source.find(key); + while (found != string::npos) { + source.replace(found, key.length(), placeholderValue); + found = source.find(key); + } + return source; + } + + std::string ui::DisplayContext::populateMessage(std::string source) { + for (auto &[key, value]: values) { + source = replacePlaceholder(source, key, value); + } + return source; } } // namespace domain diff --git a/comdel/domain/display.h b/comdel/domain/display.h index 38334aa..9d35269 100644 --- a/comdel/domain/display.h +++ b/comdel/domain/display.h @@ -5,16 +5,52 @@ #include #include +#include "comdel/parser/color.h" +#include "value.h" namespace domain { namespace ui { + class DisplayContext { + std::map values; + + public: + explicit DisplayContext(ComponentInstance *instance); + std::string populateMessage(std::string message); + }; + + struct DisplayConfig { + QColor lineColor; + QColor fillColor; + + DisplayConfig(Color lineColor, Color fillColor) { + this->lineColor = QColor::fromRgb(lineColor.r, lineColor.g, lineColor.b, lineColor.a); + this->fillColor = QColor::fromRgb(fillColor.r, fillColor.g, fillColor.b, fillColor.a); + } + }; + + class Text { + public: + int x, y, w, h; + QColor color; + std::string text; + + Text(int x, int y, int w, int h, std::string text, Color color) : x(x), y(y), w(w), h(h), text(text), + color(QColor::fromRgb(color.r, color.g, color.b, color.a)) {} + + void render(QGraphicsItemGroup *group, ui::DisplayContext context); + + void comdel(std::ostream &buffer, int x, int y); + + }; + class Rect { public: int x, y, w, h; + DisplayConfig config; - Rect(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) {} + Rect(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {} void render(QGraphicsItemGroup *group); @@ -25,8 +61,9 @@ namespace domain { class Line { public: int x1, y1, x2, y2; + DisplayConfig config; - Line(int x1, int y1, int x2, int y2) : x1(x1), y1(y1), x2(x2), y2(y2) {} + Line(int x1, int y1, int x2, int y2, DisplayConfig config) : x1(x1), y1(y1), x2(x2), y2(y2), config(config) {} void render(QGraphicsItemGroup *group); @@ -47,9 +84,11 @@ namespace domain { public: int x, y, w, h; BusOrientation orientation; + DisplayConfig config; - Bus(int x, int y, int w, int h, BusOrientation orientation) : x(x), y(y), w(w), h(h), - orientation(orientation) {} + Bus(int x, int y, int w, int h, BusOrientation orientation, DisplayConfig config) : x(x), y(y), w(w), h(h), + orientation(orientation), + config(config) {} void render(QGraphicsItemGroup *group, int size); @@ -64,10 +103,10 @@ namespace domain { PinOrientation orientation; PinType pinType; int x, y, w, h; + DisplayConfig config; - Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType) : x(x), y(y), w(w), h(h), - orientation(orientation), - pinType(pinType) {} + Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType, DisplayConfig config) + : x(x), y(y), w(w), h(h), orientation(orientation), pinType(pinType), config(config) {} public: void render(QGraphicsItemGroup *group); @@ -90,8 +129,9 @@ namespace domain { std::optional line = std::nullopt; std::optional pin = std::nullopt; std::optional bus = std::nullopt; + std::optional text = std::nullopt; - void render(QGraphicsItemGroup *group, int size = 0); + void render(QGraphicsItemGroup *group, ui::DisplayContext context, int size = 0); void comdel(std::ostream &buffer, int x, int y, int size = 0); }; @@ -102,7 +142,7 @@ namespace domain { Display(std::vector items); - void render(QGraphicsItemGroup *group); + void render(QGraphicsItemGroup *group, ui::DisplayContext context); void comdel(std::ostream &buffer, int x, int y, int size = 0); diff --git a/comdel/domain/schema_creator.cpp b/comdel/domain/schema_creator.cpp index aa8c1cf..c060f27 100644 --- a/comdel/domain/schema_creator.cpp +++ b/comdel/domain/schema_creator.cpp @@ -615,20 +615,34 @@ namespace domain { for (auto &item: node.items) { ui::Item displayItem; std::string type = item.type.value; - if (type == "rect") { + + auto fillColor = item.asColor(&errors, "fillColor", Color(255, 255, 255, 255)); + auto lineColor = item.asColor(&errors, "lineColor", Color(0, 0, 0, 255)); + + if (type == "text") { + long long int x, y, w, h; + std::string text; + auto color = item.asColor(&errors, "color", Color(0, 0, 0, 255)); + x = item.asInt(&errors, "x"); + y = item.asInt(&errors, "y"); + w = item.asInt(&errors, "w"); + h = item.asInt(&errors, "h"); + text = item.asString(&errors, "text"); + displayItem.text = ui::Text(x, y, w, h, text, color); + } else if (type == "rect") { 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); + displayItem.rect = ui::Rect(x, y, w, h, {lineColor, fillColor}); } else if (type == "line") { 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); + displayItem.line = ui::Line(x1, y1, x2, y2, {lineColor, fillColor}); } else if (type == "pin") { long long int x, y, w, h; x = item.asInt(&errors, "x"); @@ -662,7 +676,7 @@ namespace domain { errors.emplace_back(item.span, "unknown pin type '" + _pinType + "'"); } - displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType); + displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType, {lineColor, fillColor}); } else if (type == "bus") { long long int x, y, w, h; x = item.asInt(&errors, "x"); @@ -680,7 +694,7 @@ namespace domain { errors.emplace_back(item.span, "unknown bus orientation type '" + _orientation + "'"); } - displayItem.bus = ui::Bus(x, y, w, h, orientation); + displayItem.bus = ui::Bus(x, y, w, h, orientation, {lineColor, fillColor}); } else { errors.emplace_back(item.type.span, "unsupported display type"); } diff --git a/comdel/parser/ast_nodes.cpp b/comdel/parser/ast_nodes.cpp index 3f3edeb..b9c88c2 100644 --- a/comdel/parser/ast_nodes.cpp +++ b/comdel/parser/ast_nodes.cpp @@ -20,6 +20,19 @@ NumberNode::NumberNode(const std::string &expression) { } } +/*************************** COLOR NODE *********************************/ + +ColorNode::ColorNode(const std::string &expression) { + auto value = expression.substr(1); + color.r = std::stoul(value.substr(0, 2), nullptr, 16); + color.g = std::stoul(value.substr(2, 4), nullptr, 16); + color.b = std::stoul(value.substr(4, 6), nullptr, 16); + color.a = 255; + if(value.length() == 8) { + color.a = std::stoul(value.substr(6,8), nullptr, 16); + } +} + /*************************** STRING NODE ********************************/ std::string StringNode::asString() { @@ -49,6 +62,14 @@ std::string ValueNode::asIdentifier() { return ""; } +Color ValueNode::asColor() { + if (is(COLOR)) { + return colorValue.value(); + } + return {}; +} + + bool ValueNode::asBool() { if (is(BOOL)) { return boolValue.value(); @@ -94,6 +115,13 @@ ValueNode ValueNode::ofNull() { return value; } +ValueNode ValueNode::ofColor(Color color) { + ValueNode value; + value.type = EnumNode(COLOR); + value.colorValue = color; + return value; +} + ValueNode ValueNode::ofWire(std::optional _value) { ValueNode value; value.type = EnumNode(WIRE); @@ -106,4 +134,4 @@ ValueNode ValueNode::ofMemory(std::optional _value) { value.type = EnumNode(MEMORY); value.identifierValue = _value; return value; -} +} \ No newline at end of file diff --git a/comdel/parser/ast_nodes.h b/comdel/parser/ast_nodes.h index 38f4f30..3ae3abd 100644 --- a/comdel/parser/ast_nodes.h +++ b/comdel/parser/ast_nodes.h @@ -2,6 +2,7 @@ #define AST_NODE_H #include "token.h" +#include "color.h" #include "source_error.h" #include #include @@ -56,6 +57,14 @@ struct NumberNode : public AstNode { NumberNode() : value(0) {} }; +struct ColorNode : public AstNode { + Color color; + + explicit ColorNode(const std::string &expression); + + ColorNode() {} +}; + struct CountNode : public AstNode { NumberNode first; @@ -83,6 +92,7 @@ public: IDENTIFIER, MEMORY, NIL, + COLOR, }; private: @@ -91,6 +101,7 @@ private: std::optional stringValue; std::optional boolValue; std::optional identifierValue; + std::optional colorValue; public: ValueNode() = default; @@ -105,6 +116,8 @@ public: std::string asIdentifier(); + Color asColor(); + bool asBool(); bool is(ValueType valueType); @@ -121,7 +134,10 @@ public: static ValueNode ofNull(); + static ValueNode ofColor(Color color); + static ValueNode ofWire(std::optional _value); + }; struct ConditionNode { @@ -196,6 +212,21 @@ struct DisplayItemNode : public AstNode { return _default; } + Color asColor(std::vector *errors, const std::string &property, Color _default = Color(0, 0, 0)) { + for (auto &prop: values) { + if (prop.key.value == property) { + if (prop.value.is(ValueNode::COLOR)) { + return prop.value.asColor(); + } 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) { diff --git a/comdel/parser/color.cpp b/comdel/parser/color.cpp new file mode 100644 index 0000000..d8d0b21 --- /dev/null +++ b/comdel/parser/color.cpp @@ -0,0 +1,5 @@ +// +// Created by bbr on 12.06.22.. +// + +#include "color.h" diff --git a/comdel/parser/color.h b/comdel/parser/color.h new file mode 100644 index 0000000..d38c9da --- /dev/null +++ b/comdel/parser/color.h @@ -0,0 +1,21 @@ +// +// Created by bbr on 12.06.22.. +// + +#ifndef SCHEMEEDITOR_COLOR_H +#define SCHEMEEDITOR_COLOR_H + + +struct Color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + + Color(): r(0), g(0), b(0), a(0) {} + + Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0): r(r), g(g), b(b), a(a) {} +}; + + +#endif //SCHEMEEDITOR_COLOR_H diff --git a/comdel/parser/comdel_parser.cpp b/comdel/parser/comdel_parser.cpp index 145ae44..66f9469 100644 --- a/comdel/parser/comdel_parser.cpp +++ b/comdel/parser/comdel_parser.cpp @@ -259,9 +259,7 @@ std::optional ComdelParser::parseLibrary() { TokenType::RBRACE, std::nullopt, false, - [this] { return parseProperty( - std::optional( - TokenType::STRING)); + [this] { return parseProperty(TokenType::STRING); } )); if (!err.has_value()) { @@ -302,6 +300,23 @@ PResult ComdelParser::parseString() { } +/**************************************************************************** +* +* ColorNode := #RRGGBB[AA] +* +****************************************************************************/ +PResult ComdelParser::parseColor() { + auto spanner = getSpanner(); + if (check(TokenType::COLOR)) { + ColorNode node{current().text}; + node.span = current().span; + bump(); + return spanner(node); + } + return unexpected(); +} + + /**************************************************************************** * * IdentifierNode := IDENTIFIER @@ -1144,6 +1159,8 @@ PResult ComdelParser::parseValue() { } else if (check(TokenType::NIL)) { bump(); value = ValueNode::ofNull(); + } else if(check(TokenType::COLOR)) { + value = ValueNode::ofColor(parseColor()->color); } else { return unexpected(); } diff --git a/comdel/parser/comdel_parser.h b/comdel/parser/comdel_parser.h index f050b62..44cb555 100644 --- a/comdel/parser/comdel_parser.h +++ b/comdel/parser/comdel_parser.h @@ -66,6 +66,8 @@ private: // used to parse library and schema PResult parseString(); + PResult parseColor(); + PResult parseIdentifier(); PResult parseNumber(); diff --git a/examples/simplified FRISC model/frisc_library.csl b/examples/simplified FRISC model/frisc_library.csl index f9d64a6..41eb295 100644 --- a/examples/simplified FRISC model/frisc_library.csl +++ b/examples/simplified FRISC model/frisc_library.csl @@ -49,6 +49,14 @@ rect { x: 0; y:0; w:100; h:100; } + text { + x: 0; y: 0; w: 100; h: 100; + text: "FRISC"; + } + text { + x: 0; y: 16; w: 100; h: 100; + text: "{instanceName}"; + } } @pin glavniPin in { @tooltip "pin za spajanje na glavnu sabirnicu" @@ -283,6 +291,7 @@ */ pin { x: 100; y: 30; w: 16; h: 16; + orientation: "right"; } } } @@ -293,6 +302,7 @@ @display { pin { x: 100; y: 7; w: 16; h: 16; + orientation: "right"; } } @wires { 0, 0, null, null} @@ -317,6 +327,8 @@ h: 20; w: 100; orientation: "horizontal"; resizable: true; + lineColor: #bbbbbb; + fillColor: #bbbbbb; } } @wires {