From af54306f821bc98c6bd3e3224050ee9c0fb79ef7 Mon Sep 17 00:00:00 2001 From: Jochen Becher Date: Mon, 1 Apr 2024 16:50:42 +0200 Subject: Add more visual attributes for relations Change-Id: I56af6a367c144e22c8113f69a2938080ddb2e750 Reviewed-by: Alessandro Portale Reviewed-by: --- src/libs/modelinglib/CMakeLists.txt | 1 + src/libs/modelinglib/modelinglib.qbs | 2 + .../qmt/config/stereotypedefinitionparser.cpp | 133 ++++++++++++-- .../qmt/config/stereotypedefinitionparser.h | 3 +- src/libs/modelinglib/qmt/diagram/drelation.cpp | 25 +++ src/libs/modelinglib/qmt/diagram/drelation.h | 32 ++++ .../diagram_controller/dflatassignmentvisitor.cpp | 2 + .../qmt/diagram_controller/dupdatevisitor.cpp | 2 +- .../qmt/diagram_scene/items/relationitem.cpp | 8 +- .../qmt/diagram_scene/parts/arrowitem.cpp | 24 +-- .../qmt/model_widgets_ui/propertiesviewmview.cpp | 153 +++++++++++++++- .../qmt/model_widgets_ui/propertiesviewmview.h | 16 ++ .../qmt/serializer/diagramserializer.cpp | 3 + .../modelinglib/qmt/serializer/diagramserializer.h | 3 + .../modelinglib/qmt/stereotype/customrelation.cpp | 5 + .../modelinglib/qmt/stereotype/customrelation.h | 8 +- src/libs/modelinglib/qmt/stereotype/shapevalue.cpp | 2 +- .../qmt/stereotype/stereotypecontroller.cpp | 9 + .../qmt/stereotype/stereotypecontroller.h | 1 + .../modelinglib/qmt/stereotype/stereotypeicon.cpp | 15 ++ .../modelinglib/qmt/stereotype/stereotypeicon.h | 25 ++- .../modelinglib/qmt/style/defaultstyleengine.cpp | 201 ++++++++++++++++----- .../modelinglib/qmt/style/defaultstyleengine.h | 8 + src/libs/modelinglib/qmt/style/relationvisuals.cpp | 58 ++++++ src/libs/modelinglib/qmt/style/relationvisuals.h | 42 +++++ src/libs/modelinglib/qmt/style/stylecontroller.cpp | 6 + src/libs/modelinglib/qmt/style/stylecontroller.h | 4 +- src/libs/modelinglib/qmt/style/styledrelation.cpp | 6 +- src/libs/modelinglib/qmt/style/styledrelation.h | 6 +- src/libs/modelinglib/qmt/style/styleengine.h | 4 + 30 files changed, 725 insertions(+), 82 deletions(-) create mode 100644 src/libs/modelinglib/qmt/style/relationvisuals.cpp create mode 100644 src/libs/modelinglib/qmt/style/relationvisuals.h (limited to 'src/libs/modelinglib') diff --git a/src/libs/modelinglib/CMakeLists.txt b/src/libs/modelinglib/CMakeLists.txt index 27801f479a4..dcc810eb211 100644 --- a/src/libs/modelinglib/CMakeLists.txt +++ b/src/libs/modelinglib/CMakeLists.txt @@ -158,6 +158,7 @@ add_qtc_library(Modeling qmt/style/defaultstyle.h qmt/style/objectvisuals.cpp qmt/style/objectvisuals.h qmt/style/relationstarterstyle.cpp qmt/style/relationstarterstyle.h + qmt/style/relationvisuals.cpp qmt/style/relationvisuals.h qmt/style/stylecontroller.cpp qmt/style/stylecontroller.h qmt/style/style.cpp qmt/style/styledobject.cpp qmt/style/styledobject.h diff --git a/src/libs/modelinglib/modelinglib.qbs b/src/libs/modelinglib/modelinglib.qbs index 90fc1d0d982..409928d3cbf 100644 --- a/src/libs/modelinglib/modelinglib.qbs +++ b/src/libs/modelinglib/modelinglib.qbs @@ -295,6 +295,8 @@ QtcLibrary { "style/objectvisuals.h", "style/relationstarterstyle.cpp", "style/relationstarterstyle.h", + "style/relationvisuals.cpp", + "style/relationvisuals.h", "style/style.cpp", "style/style.h", "style/stylecontroller.cpp", diff --git a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp index b3caebb1645..981641e0ad0 100644 --- a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp +++ b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp @@ -28,12 +28,15 @@ static const int KEYWORD_WIDTH = 6; static const int KEYWORD_HEIGHT = 7; static const int KEYWORD_MINWIDTH = 8; static const int KEYWORD_MINHEIGHT = 9; -static const int KEYWORD_LOCK_SIZE = 10; -static const int KEYWORD_DISPLAY = 11; -static const int KEYWORD_TEXTALIGN = 12; -static const int KEYWORD_BASECOLOR = 13; -static const int KEYWORD_SHAPE = 14; -static const int KEYWORD_OUTLINE = 15; +static const int KEYWORD_ICONWIDTH = 10; +static const int KEYWORD_ICONHEIGHT = 11; +static const int KEYWORD_LOCK_SIZE = 12; +static const int KEYWORD_DISPLAY = 13; +static const int KEYWORD_TEXTALIGN = 14; +static const int KEYWORD_BASECOLOR = 15; +static const int KEYWORD_SHAPE = 16; +static const int KEYWORD_OUTLINE = 17; +static const int KEYWORD_Z = 18; // Shape items static const int KEYWORD_CIRCLE = 30; @@ -102,8 +105,18 @@ static const int KEYWORD_DASH = 136; static const int KEYWORD_DASHDOT = 137; static const int KEYWORD_DASHDOTDOT = 138; static const int KEYWORD_COLOR = 139; - -// Operatoren +static const int KEYWORD_EMPHASIZED = 140; + +// Shape Value Units and Origin +static const int KEYWORD_ABS = 150; +static const int KEYWORD_FIX = 151; +static const int KEYWORD_SCALE = 152; +static const int KEYWORD_FRACT = 153; +static const int KEYWORD_ORIGIN = 154; +static const int KEYWORD_CENTER = 155; +static const int KEYWORD_SIZE = 156; + +// Operators static const int OPERATOR_SEMICOLON = 1; static const int OPERATOR_BRACE_OPEN = 2; static const int OPERATOR_BRACE_CLOSE = 3; @@ -111,6 +124,7 @@ static const int OPERATOR_COLON = 4; static const int OPERATOR_COMMA = 5; static const int OPERATOR_PERIOD = 6; static const int OPERATOR_MINUS = 7; +static const int OPERATOR_PERCENTAGE = 8; template QHash operator<<(QHash hash, QPair pair) { @@ -213,12 +227,15 @@ void StereotypeDefinitionParser::parse(ITextSource *source) {"height", KEYWORD_HEIGHT}, {"minwidth", KEYWORD_MINWIDTH}, {"minheight", KEYWORD_MINHEIGHT}, + {"iconwidth", KEYWORD_ICONWIDTH}, + {"iconheight", KEYWORD_ICONHEIGHT}, {"locksize", KEYWORD_LOCK_SIZE}, {"display", KEYWORD_DISPLAY}, {"textalignment", KEYWORD_TEXTALIGN}, {"basecolor", KEYWORD_BASECOLOR}, {"shape", KEYWORD_SHAPE}, {"outline", KEYWORD_OUTLINE}, + {"z", KEYWORD_Z}, {"circle", KEYWORD_CIRCLE}, {"ellipse", KEYWORD_ELLIPSE}, {"line", KEYWORD_LINE}, @@ -276,7 +293,15 @@ void StereotypeDefinitionParser::parse(ITextSource *source) {"dash", KEYWORD_DASH}, {"dashdot", KEYWORD_DASHDOT}, {"dashdotdot", KEYWORD_DASHDOTDOT}, - {"color", KEYWORD_COLOR}}); + {"color", KEYWORD_COLOR}, + {"emphasized", KEYWORD_EMPHASIZED}, + {"abs", KEYWORD_ABS}, + {"fix", KEYWORD_FIX}, + {"scale", KEYWORD_SCALE}, + {"fract", KEYWORD_FRACT}, + {"origin", KEYWORD_ORIGIN}, + {"center", KEYWORD_CENTER}, + {"size", KEYWORD_SIZE}}); textScanner.setOperators({{";", OPERATOR_SEMICOLON}, {"{", OPERATOR_BRACE_OPEN}, @@ -284,7 +309,8 @@ void StereotypeDefinitionParser::parse(ITextSource *source) {":", OPERATOR_COLON}, {",", OPERATOR_COMMA}, {".", OPERATOR_PERIOD}, - {"-", OPERATOR_MINUS}}); + {"-", OPERATOR_MINUS}, + {"%", OPERATOR_PERCENTAGE}}); textScanner.setSource(source); @@ -364,6 +390,23 @@ void StereotypeDefinitionParser::parseIcon() case KEYWORD_MINHEIGHT: stereotypeIcon.setMinHeight(parseFloatProperty()); break; + case KEYWORD_ICONWIDTH: + stereotypeIcon.setIconWith(parseFloatProperty()); + break; + case KEYWORD_ICONHEIGHT: + stereotypeIcon.setIconHeight(parseFloatProperty()); + break; + case KEYWORD_Z: + { + const static QHash zNames = QHash() + << qMakePair(QString("behinditems"), StereotypeIcon::DepthBehindItems) + << qMakePair(QString("amongitems"), StereotypeIcon::DepthAmongItems) + << qMakePair(QString("beforeitems"), StereotypeIcon::DepthBeforeItems); + parseEnum( + parseIdentifierProperty(), zNames, token.sourcePos(), + [&](StereotypeIcon::DepthLayer layer) { stereotypeIcon.setDepthLayer(layer); }); + break; + } case KEYWORD_LOCK_SIZE: { const static QHash lockNames @@ -577,7 +620,7 @@ QHash StereotypeDefinitio throw StereotypeDefinitionParserError("Property given twice.", token.sourcePos()); IconCommandParameter parameter = parameters.value(token.subtype()); if (parameter.type() == IconCommandParameter::ShapeValue) - parameter.setShapeValue(ShapeValueF(parseFloatProperty(), parameter.unit(), parameter.origin())); + parameter.setShapeValue(parseShapeValueProperty(parameter.unit(), parameter.origin())); else if (parameter.type() == IconCommandParameter::Boolean) parameter.setBoolean(parseBoolProperty()); else @@ -650,8 +693,6 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element) } case KEYWORD_COLOR: { - if (element != CustomRelation::Element::Relation) - throwUnknownPropertyError(token); Value expression = parseProperty(); if (expression.type() == Color) { relation.setColorType(CustomRelation::ColorType::Custom); @@ -663,6 +704,10 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element) relation.setColorType(CustomRelation::ColorType::EndA); } else if (colorName == "b") { relation.setColorType(CustomRelation::ColorType::EndB); + } else if (colorName == "warning") { + relation.setColorType(CustomRelation::ColorType::Warning); + } else if (colorName == "error") { + relation.setColorType(CustomRelation::ColorType::Error); } else if (QColor::isValidColor(colorName)) { relation.setColorType(CustomRelation::ColorType::Custom); relation.setColor(QColor(colorName)); @@ -674,6 +719,9 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element) } break; } + case KEYWORD_EMPHASIZED: + relation.setEmphasized(parseBoolProperty()); + break; case KEYWORD_END: parseRelationEnd(&relation); break; @@ -976,6 +1024,65 @@ StereotypeDefinitionParser::Value StereotypeDefinitionParser::parseProperty() return parseExpression(); } +ShapeValueF StereotypeDefinitionParser::parseShapeValueProperty(ShapeValueF::Unit unit, ShapeValueF::Origin origin) +{ + expectColon(); + qreal value = parseFloatExpression(); + // unit + Token token = d->m_scanner->read(); + if (token.type() == Token::TokenOperator) { + switch (token.subtype()) { + case OPERATOR_PERCENTAGE: + unit = ShapeValueF::UnitPercentage; + break; + default: + d->m_scanner->unread(token); + break; + } + } else if (token.type() == Token::TokenKeyword) { + switch (token.subtype()) { + case KEYWORD_ABS: + unit = ShapeValueF::UnitAbsolute; + break; + case KEYWORD_FIX: + unit = ShapeValueF::UnitRelative; + break; + case KEYWORD_SCALE: + unit = ShapeValueF::UnitScaled; + break; + case KEYWORD_FRACT: + unit = ShapeValueF::UnitPercentage; + break; + default: + d->m_scanner->unread(token); + break; + } + } else { + d->m_scanner->unread(token); + } + // origin + token = d->m_scanner->read(); + if (token.type() == Token::TokenKeyword) { + switch (token.subtype()) { + case KEYWORD_ORIGIN: + origin = ShapeValueF::OriginTopOrLeft; + break; + case KEYWORD_CENTER: + origin = ShapeValueF::OriginCenter; + break; + case KEYWORD_SIZE: + origin = ShapeValueF::OriginBottomOrRight; + break; + default: + d->m_scanner->unread(token); + break; + } + } else { + d->m_scanner->unread(token); + } + return ShapeValueF(value, unit, origin); +} + QString StereotypeDefinitionParser::parseStringExpression() { Token token = d->m_scanner->read(); diff --git a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h index e32126c7302..97b14211cac 100644 --- a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h +++ b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h @@ -6,6 +6,7 @@ #include #include "qmt/infrastructure/exceptions.h" #include "qmt/stereotype/customrelation.h" +#include "qmt/stereotype/shapevalue.h" #include "qmt/stereotype/toolbar.h" #include "sourcepos.h" @@ -20,7 +21,6 @@ class ITextSource; class Token; class StereotypeIcon; class Toolbar; -class ShapeValueF; class QMT_EXPORT StereotypeDefinitionParserError : public Exception { @@ -97,6 +97,7 @@ private: bool parseBoolProperty(); QColor parseColorProperty(); Value parseProperty(); + ShapeValueF parseShapeValueProperty(ShapeValueF::Unit unit, ShapeValueF::Origin origin); QString parseStringExpression(); qreal parseFloatExpression(); diff --git a/src/libs/modelinglib/qmt/diagram/drelation.cpp b/src/libs/modelinglib/qmt/diagram/drelation.cpp index a21f61c7078..890bd275e4f 100644 --- a/src/libs/modelinglib/qmt/diagram/drelation.cpp +++ b/src/libs/modelinglib/qmt/diagram/drelation.cpp @@ -65,6 +65,31 @@ void DRelation::setIntermediatePoints(const QList m_intermediatePoints = intermediatePoints; } +void DRelation::setVisualPrimaryRole(VisualPrimaryRole visualPrimaryRole) +{ + m_visualPrimaryRole = visualPrimaryRole; +} + +void DRelation::setVisualSecondaryRole(VisualSecondaryRole visualSecondaryRole) +{ + m_visualSecondaryRole = visualSecondaryRole; +} + +void DRelation::setVisualEmphasized(bool visualEmphasized) +{ + m_isVisualEmphasized = visualEmphasized; +} + +void DRelation::setColor(const QColor &color) +{ + m_color = color; +} + +void DRelation::setThickness(qreal thickness) +{ + m_thickness = thickness; +} + void DRelation::accept(DVisitor *visitor) { visitor->visitDRelation(this); diff --git a/src/libs/modelinglib/qmt/diagram/drelation.h b/src/libs/modelinglib/qmt/diagram/drelation.h index 34bdaf1986d..ed5624ad9f0 100644 --- a/src/libs/modelinglib/qmt/diagram/drelation.h +++ b/src/libs/modelinglib/qmt/diagram/drelation.h @@ -5,6 +5,7 @@ #include "delement.h" +#include #include #include @@ -15,6 +16,22 @@ class DObject; class QMT_EXPORT DRelation : public DElement { public: + enum VisualPrimaryRole { + PrimaryRoleNormal, + PrimaryRoleCustom1, + PrimaryRoleCustom2, + PrimaryRoleCustom3, + PrimaryRoleCustom4, + PrimaryRoleCustom5 + }; + + enum VisualSecondaryRole { + SecondaryRoleNone, + SecondaryRoleWarning, + SecondaryRoleError, + SecondaryRoleSoften + }; + class IntermediatePoint { public: @@ -42,6 +59,16 @@ public: void setName(const QString &name); const QList intermediatePoints() const { return m_intermediatePoints; } void setIntermediatePoints(const QList &intermediatePoints); + VisualPrimaryRole visualPrimaryRole() const { return m_visualPrimaryRole; } + void setVisualPrimaryRole(VisualPrimaryRole visualPrimaryRole); + VisualSecondaryRole visualSecondaryRole() const { return m_visualSecondaryRole; } + void setVisualSecondaryRole(VisualSecondaryRole visualSecondaryRole); + bool isVisualEmphasized() const { return m_isVisualEmphasized; } + void setVisualEmphasized(bool visualEmphasized); + QColor color() const { return m_color; } + void setColor(const QColor &color); + qreal thickness() const { return m_thickness; } + void setThickness(qreal thickness); void accept(DVisitor *visitor) override; void accept(DConstVisitor *visitor) const override; @@ -53,6 +80,11 @@ private: Uid m_endBUid; QString m_name; QList m_intermediatePoints; + VisualPrimaryRole m_visualPrimaryRole = PrimaryRoleNormal; + VisualSecondaryRole m_visualSecondaryRole = SecondaryRoleNone; + bool m_isVisualEmphasized = false; + QColor m_color; + qreal m_thickness = 0; }; bool operator==(const DRelation::IntermediatePoint &lhs, const DRelation::IntermediatePoint &rhs); diff --git a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp index 5e881758127..205c8fbb4db 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp +++ b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp @@ -100,6 +100,8 @@ void DFlatAssignmentVisitor::visitDRelation(const DRelation *relation) QMT_ASSERT(target, return); target->setStereotypes(relation->stereotypes()); target->setIntermediatePoints(relation->intermediatePoints()); + target->setVisualPrimaryRole(relation->visualPrimaryRole()); + target->setThickness(relation->thickness()); } void DFlatAssignmentVisitor::visitDInheritance(const DInheritance *inheritance) diff --git a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp index 91a95438ad5..0866e6d9f5d 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp +++ b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp @@ -71,7 +71,7 @@ void DUpdateVisitor::visitMObject(const MObject *object) const MObject *owner = object->owner(); while (owner) { owner = owner->owner(); - depth += 1; + depth += 3; } if (isUpdating(depth != dobject->depth())) dobject->setDepth(depth); diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp index a2f444f59e2..142955f8658 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp @@ -507,9 +507,11 @@ void RelationItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) const Style *RelationItem::adaptedStyle() { - DObject *endAObject = m_diagramSceneModel->diagramController()->findElement(m_relation->endAUid(), m_diagramSceneModel->diagram()); - DObject *endBObject = m_diagramSceneModel->diagramController()->findElement(m_relation->endBUid(), m_diagramSceneModel->diagram()); - StyledRelation styledRelation(m_relation, endAObject, endBObject); + const DObject *endAObject = m_diagramSceneModel->diagramController()->findElement(m_relation->endAUid(), m_diagramSceneModel->diagram()); + const DObject *endBObject = m_diagramSceneModel->diagramController()->findElement(m_relation->endBUid(), m_diagramSceneModel->diagram()); + const CustomRelation customRelation = m_diagramSceneModel->stereotypeController() + ->findCustomRelationByStereotype(m_relation->stereotypes().value(0)); + StyledRelation styledRelation(m_relation, endAObject, endBObject, &customRelation); return m_diagramSceneModel->styleController()->adaptRelationStyle(styledRelation); } diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp index 3a14eb10d99..632da76f05a 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp @@ -384,27 +384,29 @@ void ArrowItem::updateShaft(const Style *style) QMT_ASSERT(m_shaftItem, return); QPen pen(style->linePen()); + pen.setCapStyle(Qt::FlatCap); + + auto scale = [&pen](qreal v) { + return v / ((pen.widthF() - 1.0) / 2.0 + 1.0); + }; + switch (m_shaft) { case ShaftSolid: break; case ShaftDashed: - pen.setDashPattern(QVector() - << (4.0 / pen.widthF()) << (4.0 / pen.widthF())); + pen.setDashPattern(QVector() << scale(5.0) << scale(3.0)); break; case ShaftDot: - pen.setDashPattern(QVector() - << (2.0 / pen.widthF()) << (2.0 / pen.widthF())); + pen.setDashPattern(QVector() << scale(3.0) << scale(3.0)); break; case ShaftDashDot: - pen.setDashPattern(QVector() - << (4.0 / pen.widthF()) << (2.0 / pen.widthF()) - << (2.0 / pen.widthF()) << (2.0 / pen.widthF())); + pen.setDashPattern(QVector() << scale(5.0) << scale(3.0) + << scale(3.0) << scale(3.0)); break; case ShaftDashDotDot: - pen.setDashPattern(QVector() - << (4.0 / pen.widthF()) << (2.0 / pen.widthF()) - << (2.0 / pen.widthF()) << (2.0 / pen.widthF()) - << (2.0 / pen.widthF()) << (2.0 / pen.widthF())); + pen.setDashPattern(QVector() << scale(5.0) << scale(3.0) + << scale(3.0) << scale(3.0) + << scale(3.0) << scale(3.0)); break; } m_shaftItem->setPen(pen); diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp index 969313ca33f..28566d07ce3 100644 --- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp +++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp @@ -43,6 +43,7 @@ #include "qmt/diagram_scene/items/stereotypedisplayvisitor.h" #include "qmt/stereotype/stereotypecontroller.h" #include "qmt/stereotype/customrelation.h" +#include "qmt/style/relationvisuals.h" #include "qmt/style/stylecontroller.h" #include "qmt/style/style.h" #include "qmt/style/objectvisuals.h" @@ -237,6 +238,61 @@ static DClass::TemplateDisplay translateIndexToTemplateDisplay(int index) return map[index]; } +static int translateRelationVisualPrimaryRoleToIndex(DRelation::VisualPrimaryRole visualRole) +{ + switch (visualRole) { + case DRelation::PrimaryRoleNormal: + return 0; + case DRelation::PrimaryRoleCustom1: + return 1; + case DRelation::PrimaryRoleCustom2: + return 2; + case DRelation::PrimaryRoleCustom3: + return 3; + case DRelation::PrimaryRoleCustom4: + return 4; + case DRelation::PrimaryRoleCustom5: + return 5; + } + return 0; +} + +static DRelation::VisualPrimaryRole translateIndexToRelationVisualPrimaryRole(int index) +{ + static const DRelation::VisualPrimaryRole map[] = { + DRelation::PrimaryRoleNormal, + DRelation::PrimaryRoleCustom1, DRelation::PrimaryRoleCustom2, DRelation::PrimaryRoleCustom3, + DRelation::PrimaryRoleCustom4, DRelation::PrimaryRoleCustom5 + }; + QMT_ASSERT(index >= 0 && index <= 5, return DRelation::PrimaryRoleNormal); + return map[index]; +} + +static int translateRelationVisualSecondaryRoleToIndex(DRelation::VisualSecondaryRole visualRole) +{ + switch (visualRole) { + case DRelation::SecondaryRoleNone: + return 0; + case DRelation::SecondaryRoleWarning: + return 1; + case DRelation::SecondaryRoleError: + return 2; + case DRelation::SecondaryRoleSoften: + return 3; + } + return 0; +} + +static DRelation::VisualSecondaryRole translateIndexToRelationVisualSecondaryRole(int index) +{ + static const DRelation::VisualSecondaryRole map[] = { + DRelation::SecondaryRoleNone, + DRelation::SecondaryRoleWarning, DRelation::SecondaryRoleError, DRelation::SecondaryRoleSoften + }; + QMT_ASSERT(index >= 0 && index <= 5, return DRelation::SecondaryRoleNone); + return map[index]; +} + static int translateAnnotationVisualRoleToIndex(DAnnotation::VisualRole visualRole) { switch (visualRole) { @@ -1057,6 +1113,52 @@ void PropertiesView::MView::visitDItem(const DItem *item) void PropertiesView::MView::visitDRelation(const DRelation *relation) { visitDElement(relation); + if (!m_relationVisualPrimaryRoleSelector) { + m_relationVisualPrimaryRoleSelector = new PaletteBox(m_topWidget); + setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleNormal); + setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom1); + setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom2); + setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom3); + setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom4); + setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom5); + addRow(Tr::tr("Color:"), m_relationVisualPrimaryRoleSelector, "color"); + connect(m_relationVisualPrimaryRoleSelector, &PaletteBox::activated, + this, &PropertiesView::MView::onRelationVisualPrimaryRoleChanged); + } + if (!m_relationVisualPrimaryRoleSelector->hasFocus()) { + DRelation::VisualPrimaryRole visualPrimaryRole; + if (haveSameValue(m_diagramElements, &DRelation::visualPrimaryRole, &visualPrimaryRole)) + m_relationVisualPrimaryRoleSelector->setCurrentIndex(translateRelationVisualPrimaryRoleToIndex(visualPrimaryRole)); + else + m_relationVisualPrimaryRoleSelector->setCurrentIndex(-1); + } + if (!m_relationVisualSecondaryRoleSelector) { + m_relationVisualSecondaryRoleSelector = new QComboBox(m_topWidget); + m_relationVisualSecondaryRoleSelector->addItems({ Tr::tr("Normal"), Tr::tr("Warning"), Tr::tr("Error"), Tr::tr("Soften") }); + addRow(Tr::tr("Role:"), m_relationVisualSecondaryRoleSelector, "role"); + connect(m_relationVisualSecondaryRoleSelector, QOverload::of(&QComboBox::activated), + this, &PropertiesView::MView::onRelationVisualSecondaryRoleChanged); + } + if (!m_relationVisualSecondaryRoleSelector->hasFocus()) { + DRelation::VisualSecondaryRole visualSecondaryRole; + if (haveSameValue(m_diagramElements, &DRelation::visualSecondaryRole, &visualSecondaryRole)) + m_relationVisualSecondaryRoleSelector->setCurrentIndex(translateRelationVisualSecondaryRoleToIndex(visualSecondaryRole)); + else + m_relationVisualSecondaryRoleSelector->setCurrentIndex(-1); + } + if (!m_relationVisualEmphasizedCheckbox) { + m_relationVisualEmphasizedCheckbox = new QCheckBox(Tr::tr("Emphasized"), m_topWidget); + addRow(QString(), m_relationVisualEmphasizedCheckbox, "emphasized"); + connect(m_relationVisualEmphasizedCheckbox, &QAbstractButton::clicked, + this, &PropertiesView::MView::onRelationVisualEmphasizedChanged); + } + if (!m_relationVisualEmphasizedCheckbox->hasFocus()) { + bool emphasized; + if (haveSameValue(m_diagramElements, &DRelation::isVisualEmphasized, &emphasized)) + m_relationVisualEmphasizedCheckbox->setChecked(emphasized); + else + m_relationVisualEmphasizedCheckbox->setChecked(false); + } #ifdef SHOW_DEBUG_PROPERTIES if (!m_pointsLabel) { m_pointsLabel = new QLabel(m_topWidget); @@ -1392,7 +1494,42 @@ void PropertiesView::MView::onAnnotationVisualRoleChanged(int visualRoleIndex) { DAnnotation::VisualRole visualRole = translateIndexToAnnotationVisualRole((visualRoleIndex)); assignModelElement( - m_diagramElements, SelectionMulti, visualRole, &DAnnotation::visualRole, &DAnnotation::setVisualRole); + m_diagramElements, SelectionMulti, visualRole, &DAnnotation::visualRole, &DAnnotation::setVisualRole); +} + + +void PropertiesView::MView::onRelationVisualPrimaryRoleChanged(int visualRoleIndex) +{ + DRelation::VisualPrimaryRole visualRole = translateIndexToRelationVisualPrimaryRole(visualRoleIndex); + assignModelElement( + m_diagramElements, SelectionMulti, visualRole, + &DRelation::visualPrimaryRole, &DRelation::setVisualPrimaryRole); +} + +void PropertiesView::MView::onRelationVisualSecondaryRoleChanged(int visualRoleIndex) +{ + DRelation::VisualSecondaryRole visualRole = translateIndexToRelationVisualSecondaryRole(visualRoleIndex); + assignModelElement( + m_diagramElements, SelectionMulti, visualRole, + &DRelation::visualSecondaryRole, &DRelation::setVisualSecondaryRole); +} + +void PropertiesView::MView::onRelationVisualEmphasizedChanged(bool visualEmphasized) +{ + assignModelElement(m_diagramElements, SelectionMulti, visualEmphasized, + &DRelation::isVisualEmphasized, &DRelation::setVisualEmphasized); +} + +void PropertiesView::MView::onRelationColorChanged(const QColor &color) +{ + assignModelElement(m_diagramElements, SelectionMulti, color, + &DRelation::color, &DRelation::setColor); +} + +void PropertiesView::MView::onRelationThicknessChanged(qreal thickness) +{ + assignModelElement(m_diagramElements, SelectionMulti, thickness, + &DRelation::thickness, &DRelation::setThickness); } void PropertiesView::MView::prepare() @@ -1553,7 +1690,8 @@ void PropertiesView::MView::setPrimaryRolePalette(StyleEngine::ElementType eleme DObject::VisualPrimaryRole visualPrimaryRole, const QColor &baseColor) { int index = translateVisualPrimaryRoleToIndex(visualPrimaryRole); - const Style *style = m_propertiesView->styleController()->adaptObjectStyle(elementType, ObjectVisuals(visualPrimaryRole, DObject::SecondaryRoleNone, false, baseColor, 0)); + const Style *style = m_propertiesView->styleController()->adaptObjectStyle( + elementType, ObjectVisuals(visualPrimaryRole, DObject::SecondaryRoleNone, false, baseColor, 0)); m_visualPrimaryRoleSelector->setBrush(index, style->fillBrush()); m_visualPrimaryRoleSelector->setLinePen(index, style->linePen()); } @@ -1595,6 +1733,17 @@ QString PropertiesView::MView::formatTemplateParameters(const QList &te return templateParamters; } +void PropertiesView::MView::setRelationPrimaryRolePalette(StyleEngine::ElementType elementType, + DRelation::VisualPrimaryRole visualPrimaryRole) +{ + int index = translateRelationVisualPrimaryRoleToIndex(visualPrimaryRole); + const Style *style = m_propertiesView->styleController()->adaptRelationStyle( + elementType, RelationVisuals(DObject::PrimaryRoleNormal, visualPrimaryRole, + DRelation::SecondaryRoleNone, false)); + m_relationVisualPrimaryRoleSelector->setBrush(index, style->fillBrush()); + m_relationVisualPrimaryRoleSelector->setLinePen(index, style->linePen()); +} + template QList PropertiesView::MView::filter(const QList &elements) { diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h index 4762803a209..026f4f68578 100644 --- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h +++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h @@ -8,6 +8,8 @@ #include "qmt/model/mconstvisitor.h" #include "qmt/diagram/dconstvisitor.h" #include "qmt/diagram/dobject.h" +#include "qmt/diagram/drelation.h" +#include "qmt/infrastructure/qmtassert.h" #include "qmt/stereotype/stereotypeicon.h" #include "qmt/style/styleengine.h" @@ -110,6 +112,11 @@ protected: void onPlainShapeChanged(bool plainShape); void onItemShapeChanged(const QString &shape); void onAutoWidthChanged(bool autoWidthed); + void onRelationVisualPrimaryRoleChanged(int visualRoleIndex); + void onRelationVisualSecondaryRoleChanged(int visualRoleIndex); + void onRelationVisualEmphasizedChanged(bool visualEmphasized); + void onRelationColorChanged(const QColor &color); + void onRelationThicknessChanged(qreal thickness); void onAnnotationVisualRoleChanged(int visualRoleIndex); void prepare(); @@ -139,6 +146,9 @@ protected: QList splitTemplateParameters(const QString &templateParameters); QString formatTemplateParameters(const QList &templateParametersList); + void setRelationPrimaryRolePalette(StyleEngine::ElementType elementType, + DRelation::VisualPrimaryRole visualPrimaryRole); + enum SelectionType { SelectionSingle, SelectionMulti @@ -149,6 +159,9 @@ protected: template bool haveSameValue(const QList &baseElements, V (T::*getter)() const, V *value); template + bool isValueChanged(const QList &baseElements, SelectionType selectionType, + const V &value, V (T::*getter)() const); + template void assignModelElement(const QList &baseElements, SelectionType selectionType, const V &value, V (T::*getter)() const, void (T::*setter)(const V &)); template @@ -232,6 +245,9 @@ protected: QCheckBox *m_annotationAutoWidthCheckbox = nullptr; QComboBox *m_annotationVisualRoleSelector = nullptr; // DRelation + PaletteBox *m_relationVisualPrimaryRoleSelector = nullptr; + QComboBox *m_relationVisualSecondaryRoleSelector = nullptr; + QCheckBox *m_relationVisualEmphasizedCheckbox = nullptr; QLabel *m_pointsLabel = nullptr; }; diff --git a/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp b/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp index 5170d4fdc7e..5121a51f3d2 100644 --- a/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp +++ b/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp @@ -220,6 +220,9 @@ inline void Access::serialize(Archive &archive, DRelation &r || attr("b", relation, &DRelation::endBUid, &DRelation::setEndBUid) || attr("name", relation, &DRelation::name, &DRelation::setName) || attr("points", relation, &DRelation::intermediatePoints, &DRelation::setIntermediatePoints) + || attr("visualPrimaryRole", relation, &DRelation::visualPrimaryRole, &DRelation::setVisualPrimaryRole) + || attr("visualSecondaryRole", relation, &DRelation::visualSecondaryRole, &DRelation::setVisualSecondaryRole) + || attr("thickness", relation, &DRelation::thickness, &DRelation::setThickness) || end; } diff --git a/src/libs/modelinglib/qmt/serializer/diagramserializer.h b/src/libs/modelinglib/qmt/serializer/diagramserializer.h index a571ff94ef2..aa5d1adb526 100644 --- a/src/libs/modelinglib/qmt/serializer/diagramserializer.h +++ b/src/libs/modelinglib/qmt/serializer/diagramserializer.h @@ -6,6 +6,7 @@ #include "qmt/diagram/dannotation.h" #include "qmt/diagram/dobject.h" #include "qmt/diagram/dclass.h" +#include "qmt/diagram/drelation.h" #include "qark/serialize_enum.h" @@ -16,5 +17,7 @@ QARK_SERIALIZE_ENUM(qmt::DObject::VisualSecondaryRole) QARK_SERIALIZE_ENUM(qmt::DObject::StereotypeDisplay) QARK_SERIALIZE_ENUM(qmt::DClass::TemplateDisplay) QARK_SERIALIZE_ENUM(qmt::DAnnotation::VisualRole) +QARK_SERIALIZE_ENUM(qmt::DRelation::VisualPrimaryRole) +QARK_SERIALIZE_ENUM(qmt::DRelation::VisualSecondaryRole) } // namespace qark diff --git a/src/libs/modelinglib/qmt/stereotype/customrelation.cpp b/src/libs/modelinglib/qmt/stereotype/customrelation.cpp index fa9c80a1a0f..cc80da1b800 100644 --- a/src/libs/modelinglib/qmt/stereotype/customrelation.cpp +++ b/src/libs/modelinglib/qmt/stereotype/customrelation.cpp @@ -114,4 +114,9 @@ void CustomRelation::setColor(const QColor &color) m_color = color; } +void CustomRelation::setEmphasized(bool emphasized) +{ + m_emphasized = emphasized; +} + } // namespace qmt diff --git a/src/libs/modelinglib/qmt/stereotype/customrelation.h b/src/libs/modelinglib/qmt/stereotype/customrelation.h index 7125865aded..dd32c542c0c 100644 --- a/src/libs/modelinglib/qmt/stereotype/customrelation.h +++ b/src/libs/modelinglib/qmt/stereotype/customrelation.h @@ -55,7 +55,10 @@ public: enum class ColorType { EndA, EndB, - Custom + Custom, + Warning, + Error, + Soften, }; class End { @@ -113,6 +116,8 @@ public: void setColorType(ColorType colorType); QColor color() const { return m_color; } void setColor(const QColor &color); + bool emphasized() const { return m_emphasized; } + void setEmphasized(bool emphasized); friend auto qHash(CustomRelation::Relationship relationship) { return ::qHash(static_cast(relationship)); @@ -139,6 +144,7 @@ private: ShaftPattern m_shaftPattern = ShaftPattern::Solid; ColorType m_colorType = ColorType::EndA; QColor m_color; + bool m_emphasized = false; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp b/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp index 9e1ee46c156..cf8ea5ef65b 100644 --- a/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp +++ b/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp @@ -29,7 +29,7 @@ qreal ShapeValueF::mapScaledTo(qreal scaledOrigin, qreal originalSize, qreal bas v = originalSize != 0 ? (m_value * actualSize / originalSize) : m_value; break; case UnitPercentage: - v = m_value * actualSize; + v = m_value * actualSize / 100.0; break; } switch (m_origin) { diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp index 030c9e12a51..f557e80c4b7 100644 --- a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp +++ b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp @@ -68,6 +68,7 @@ public: QHash, QString> m_stereotypeToIconIdMap; QHash m_iconIdToStereotypeIconsMap; QHash m_relationIdToCustomRelationMap; + QHash m_stereotypeToCustomRelationMap; QList m_toolbars; QList m_elementToolbars; QHash m_iconMap; @@ -150,6 +151,11 @@ CustomRelation StereotypeController::findCustomRelation(const QString &customRel return d->m_relationIdToCustomRelationMap.value(customRelationId); } +CustomRelation StereotypeController::findCustomRelationByStereotype(const QString &steoreotype) const +{ + return d->m_stereotypeToCustomRelationMap.value(steoreotype); +} + QIcon StereotypeController::createIcon(StereotypeIcon::Element element, const QList &stereotypes, const QString &defaultIconPath, const Style *style, const QSize &size, const QMarginsF &margins, qreal lineWidth) @@ -251,6 +257,9 @@ void StereotypeController::addStereotypeIcon(const StereotypeIcon &stereotypeIco void StereotypeController::addCustomRelation(const CustomRelation &customRelation) { d->m_relationIdToCustomRelationMap.insert(customRelation.id(), customRelation); + QString stereotype = Utils::toList(customRelation.stereotypes()).value(0); + if (!stereotype.isEmpty()) + d->m_stereotypeToCustomRelationMap.insert(stereotype, customRelation); } void StereotypeController::addToolbar(const Toolbar &toolbar) diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h index 676f9a275a5..45bc3bbd18f 100644 --- a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h +++ b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h @@ -33,6 +33,7 @@ public: const QList &stereotypes) const; StereotypeIcon findStereotypeIcon(const QString &stereotypeIconId) const; CustomRelation findCustomRelation(const QString &customRelationId) const; + CustomRelation findCustomRelationByStereotype(const QString &steoreotype) const; QIcon createIcon(StereotypeIcon::Element element, const QList &stereotypes, const QString &defaultIconPath, const Style *style, const QSize &size, const QMarginsF &margins, qreal lineWidth); diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp index 8bcf5df170d..19e466c509c 100644 --- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp +++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp @@ -62,6 +62,21 @@ void StereotypeIcon::setMinHeight(qreal minHeight) m_minHeight = minHeight; } +void StereotypeIcon::setIconWith(qreal iconWidth) +{ + m_iconWidth = iconWidth; +} + +void StereotypeIcon::setIconHeight(qreal iconHeight) +{ + m_iconHeight = iconHeight; +} + +void StereotypeIcon::setDepthLayer(DepthLayer depthLayer) +{ + m_depthLayer = depthLayer; +} + void StereotypeIcon::setSizeLock(StereotypeIcon::SizeLock sizeLock) { m_sizeLock = sizeLock; diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h index be45245da5d..fcb5f1a15cd 100644 --- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h +++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h @@ -31,6 +31,12 @@ public: DisplaySmart }; + enum DepthLayer { + DepthBehindItems, + DepthAmongItems, + DepthBeforeItems, + }; + enum SizeLock { LockNone, LockWidth, @@ -62,12 +68,20 @@ public: void setWidth(qreal width); qreal height() const { return m_height; } void setHeight(qreal height); - bool hasMinWidth() const { return m_minWidth > 0; } + bool hasMinWidth() const { return m_minWidth > 0.0; } qreal minWidth() const { return m_minWidth; } void setMinWidth(qreal minWidth); - bool hasMinHeight() const { return m_minHeight > 0; } + bool hasMinHeight() const { return m_minHeight > 0.0; } qreal minHeight() const { return m_minHeight; } void setMinHeight(qreal minHeight); + bool hasIconWidth() const { return m_iconWidth > 0.0; } + qreal iconWidth() const { return m_iconWidth; } + void setIconWith(qreal iconWidth); + bool hasIconHeight() const { return m_iconHeight > 0.0; } + qreal iconHeight() const { return m_iconHeight; } + void setIconHeight(qreal iconHeight); + DepthLayer depthLayer() const { return m_depthLayer; } + void setDepthLayer(DepthLayer depthLayer); SizeLock sizeLock() const { return m_sizeLock; } void setSizeLock(SizeLock sizeLock); Display display() const { return m_display; } @@ -90,8 +104,11 @@ private: QString m_name; qreal m_width = 100.0; qreal m_height = 100.0; - qreal m_minWidth = -1; - qreal m_minHeight = -1; + qreal m_minWidth = -1.0; + qreal m_minHeight = -1.0; + qreal m_iconWidth = -1.0; + qreal m_iconHeight = -1.0; + DepthLayer m_depthLayer = DepthAmongItems; SizeLock m_sizeLock = LockNone; Display m_display = DisplaySmart; TextAlignment m_textAlignment = TextalignBelow; diff --git a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp index 74e91837dc9..bce1804892d 100644 --- a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp +++ b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp @@ -5,6 +5,7 @@ #include "defaultstyle.h" #include "objectvisuals.h" +#include "relationvisuals.h" #include "styledobject.h" #include "styledrelation.h" @@ -14,6 +15,7 @@ #include "qmt/diagram/ditem.h" #include "qmt/diagram/dannotation.h" #include "qmt/infrastructure/qmtassert.h" +#include "qmt/stereotype/customrelation.h" #include @@ -73,25 +75,29 @@ bool operator==(const ObjectStyleKey &lhs, const ObjectStyleKey &rhs) class RelationStyleKey { public: - RelationStyleKey(StyleEngine::ElementType elementType = StyleEngine::TypeOther, - DObject::VisualPrimaryRole visualPrimaryRole = DObject::PrimaryRoleNormal) + RelationStyleKey(StyleEngine::ElementType elementType, const RelationVisuals &relationVisuals, + bool withObject = false) : m_elementType(elementType), - m_visualPrimaryRole(visualPrimaryRole) + m_relationVisuals(relationVisuals), + m_withObject(withObject) { } StyleEngine::ElementType m_elementType = StyleEngine::TypeOther; - DObject::VisualPrimaryRole m_visualPrimaryRole = DObject::PrimaryRoleNormal; + RelationVisuals m_relationVisuals; + bool m_withObject = false; }; size_t qHash(const RelationStyleKey &styleKey) { - return ::qHash(styleKey.m_elementType) ^ ::qHash(styleKey.m_visualPrimaryRole); + return ::qHash(styleKey.m_elementType) ^ qHash(styleKey.m_relationVisuals); } bool operator==(const RelationStyleKey &lhs, const RelationStyleKey &rhs) { - return lhs.m_elementType == rhs.m_elementType && lhs.m_visualPrimaryRole == rhs.m_visualPrimaryRole; + return lhs.m_elementType == rhs.m_elementType + && lhs.m_relationVisuals == rhs.m_relationVisuals + && lhs.m_withObject == rhs.m_withObject; } class AnnotationStyleKey @@ -253,34 +259,6 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, StyleE return derivedStyle; } -static bool areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole, - DObject::VisualSecondaryRole rhsSecondaryRole, - DObject::VisualPrimaryRole lhsPrimaryRole, - DObject::VisualSecondaryRole lhsSecondaryRols) -{ - switch (rhsSecondaryRole) { - case DObject::SecondaryRoleNone: - case DObject::SecondaryRoleLighter: - case DObject::SecondaryRoleDarker: - case DObject::SecondaryRoleFlat: - switch (lhsSecondaryRols) { - case DObject::SecondaryRoleNone: - case DObject::SecondaryRoleLighter: - case DObject::SecondaryRoleDarker: - case DObject::SecondaryRoleFlat: - return lhsPrimaryRole == rhsPrimaryRole; - case DObject::SecondaryRoleSoften: - case DObject::SecondaryRoleOutline: - return false; - } - break; - case DObject::SecondaryRoleSoften: - case DObject::SecondaryRoleOutline: - return false; - } - return true; -} - const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const StyledObject &styledObject, const Parameters *parameters) { @@ -325,10 +303,12 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const } int depth = 0; if (!depths.isEmpty()) { - for (auto it = depths.cbegin(); it != depths.cend(); ++it) { - if (it->m_elementType == elementType - && areStackingRoles(it->m_visualPrimaryRole, it->m_visualSecondaryRole, - styledVisualPrimaryRole, styledVisualSecondaryRole)) { + const QList keys = Utils::sorted(depths.keys()); + for (int d : keys) { + DepthProperties properties = depths.value(d); + if (properties.m_elementType == elementType + && areStackingRoles(properties.m_visualPrimaryRole, properties.m_visualSecondaryRole, + styledVisualPrimaryRole, styledVisualSecondaryRole)) { ++depth; } else { depth = 0; @@ -345,13 +325,100 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const parameters); } +const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, ElementType elementType, const RelationVisuals &relationVisuals, const Parameters *parameters) +{ + Q_UNUSED(parameters); + + RelationStyleKey key(elementType, relationVisuals); + const Style *derivedStyle = m_relationStyleMap.value(key); + if (!derivedStyle) { + auto style = new Style(baseStyle->type()); + static QColor customColors[] = { + QColor(0xEE, 0x8E, 0x99).darker(110), // ROLE_CUSTOM1, + QColor(0x80, 0xAF, 0x47).lighter(130), // ROLE_CUSTOM2, + QColor(0xFF, 0xA1, 0x5B).lighter(100), // ROLE_CUSTOM3, + QColor(0x55, 0xC4, 0xCF).lighter(120), // ROLE_CUSTOM4, + QColor(0xFF, 0xE1, 0x4B) // ROLE_CUSTOM5, + }; + + int index = static_cast(relationVisuals.visualPrimaryRole()) - static_cast(DRelation::PrimaryRoleCustom1); + QColor lineColor = index >= 0 && index <= 4 ? customColors[index] : Qt::black; + switch (relationVisuals.visualSecondaryRole()) { + case DRelation::SecondaryRoleNone: + break; + case DRelation::SecondaryRoleWarning: + lineColor = Qt::yellow; + break; + case DRelation::SecondaryRoleError: + lineColor = Qt::red; + break; + case DRelation::SecondaryRoleSoften: + lineColor = Qt::gray; + break; + } + + QColor fillColor = lineColor == Qt::black ? Qt::darkGray : lineColor.lighter(150); + QPen linePen = baseStyle->linePen(); + linePen.setWidth(1); + linePen.setColor(lineColor); + style->setLinePen(linePen); + QBrush textBrush = baseStyle->textBrush(); + textBrush.setColor(Qt::black); + style->setTextBrush(textBrush); + QBrush brush = baseStyle->fillBrush(); + brush.setColor(fillColor); + brush.setStyle(Qt::SolidPattern); + style->setFillBrush(brush); + style->setNormalFont(baseStyle->normalFont()); + style->setSmallFont(baseStyle->smallFont()); + style->setHeaderFont(baseStyle->headerFont()); + m_relationStyleMap.insert(key, style); + derivedStyle = style; + } + return derivedStyle; +} + const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, const StyledRelation &styledRelation, const Parameters *parameters) { Q_UNUSED(parameters) ElementType elementType = objectType(styledRelation.endA()); - RelationStyleKey key(elementType, styledRelation.endA() ? styledRelation.endA()->visualPrimaryRole() : DObject::PrimaryRoleNormal); + RelationVisuals relationVisuals; + if (styledRelation.customRelation()) { + switch (styledRelation.customRelation()->colorType()) { + case CustomRelation::ColorType::EndA: + // TODO implement + break; + case CustomRelation::ColorType::EndB: + // TODO implement + break; + case CustomRelation::ColorType::Custom: + // TODO implement + break; + case CustomRelation::ColorType::Warning: + relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleWarning); + break; + case CustomRelation::ColorType::Error: + relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleError); + break; + case CustomRelation::ColorType::Soften: + relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleSoften); + break; + } + relationVisuals.setEmphasized(styledRelation.customRelation()->emphasized()); + } + if (styledRelation.endA()) + relationVisuals.setVisualObjectPrimaryRole(styledRelation.endA()->visualPrimaryRole()); + if (styledRelation.relation()) { + if (styledRelation.relation()->visualPrimaryRole() != DRelation::VisualPrimaryRole::PrimaryRoleNormal) + relationVisuals.setVisualPrimaryRole(styledRelation.relation()->visualPrimaryRole()); + if (styledRelation.relation()->visualSecondaryRole() != DRelation::VisualSecondaryRole::SecondaryRoleNone) + relationVisuals.setVisualSecondaryRole(styledRelation.relation()->visualSecondaryRole()); + if (styledRelation.relation()->isVisualEmphasized()) + relationVisuals.setEmphasized(styledRelation.relation()->isVisualEmphasized()); + } + RelationStyleKey key(elementType, relationVisuals, true); const Style *derivedStyle = m_relationStyleMap.value(key); if (!derivedStyle) { auto style = new Style(baseStyle->type()); @@ -365,12 +432,36 @@ const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, cons QColor lineColor = DefaultStyleEngine::lineColor(objectType(object), objectVisuals); QColor fillColor = lineColor; + static QColor customColors[] = { + QColor(0xEE, 0x8E, 0x99).darker(110), // ROLE_CUSTOM1, + QColor(0x80, 0xAF, 0x47).lighter(130), // ROLE_CUSTOM2, + QColor(0xFF, 0xA1, 0x5B).lighter(100), // ROLE_CUSTOM3, + QColor(0x55, 0xC4, 0xCF).lighter(120), // ROLE_CUSTOM4, + QColor(0xFF, 0xE1, 0x4B) // ROLE_CUSTOM5, + }; + + int index = static_cast(relationVisuals.visualPrimaryRole()) - static_cast(DRelation::PrimaryRoleCustom1); + lineColor = (index >= 0 && index <= 4) ? customColors[index] : lineColor; + switch (relationVisuals.visualSecondaryRole()) { + case DRelation::SecondaryRoleNone: + break; + case DRelation::SecondaryRoleWarning: + lineColor = QColor(0xffc800); + break; + case DRelation::SecondaryRoleError: + lineColor = Qt::red; + break; + case DRelation::SecondaryRoleSoften: + lineColor = Qt::gray; + break; + } + QPen linePen = baseStyle->linePen(); - linePen.setWidth(1); + linePen.setWidth(relationVisuals.isEmphasized() ? 3 : 1); linePen.setColor(lineColor); style->setLinePen(linePen); QBrush textBrush = baseStyle->textBrush(); - textBrush.setColor(QColor("black")); + textBrush.setColor(Qt::black); style->setTextBrush(textBrush); QBrush brush = baseStyle->fillBrush(); brush.setColor(fillColor); @@ -497,6 +588,34 @@ DefaultStyleEngine::ElementType DefaultStyleEngine::objectType(const DObject *ob return elementType; } +bool DefaultStyleEngine::areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole, + DObject::VisualSecondaryRole rhsSecondaryRole, + DObject::VisualPrimaryRole lhsPrimaryRole, + DObject::VisualSecondaryRole lhsSecondaryRols) +{ + switch (rhsSecondaryRole) { + case DObject::SecondaryRoleNone: + case DObject::SecondaryRoleLighter: + case DObject::SecondaryRoleDarker: + case DObject::SecondaryRoleFlat: + switch (lhsSecondaryRols) { + case DObject::SecondaryRoleNone: + case DObject::SecondaryRoleLighter: + case DObject::SecondaryRoleDarker: + case DObject::SecondaryRoleFlat: + return lhsPrimaryRole == rhsPrimaryRole; + case DObject::SecondaryRoleSoften: + case DObject::SecondaryRoleOutline: + return false; + } + break; + case DObject::SecondaryRoleSoften: + case DObject::SecondaryRoleOutline: + return false; + } + return true; +} + QColor DefaultStyleEngine::baseColor(ElementType elementType, ObjectVisuals objectVisuals) { if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleOutline) diff --git a/src/libs/modelinglib/qmt/style/defaultstyleengine.h b/src/libs/modelinglib/qmt/style/defaultstyleengine.h index 67cdf9ed857..b5ebe557e0b 100644 --- a/src/libs/modelinglib/qmt/style/defaultstyleengine.h +++ b/src/libs/modelinglib/qmt/style/defaultstyleengine.h @@ -37,6 +37,9 @@ public: const Parameters *parameters) override; const Style *applyObjectStyle(const Style *baseStyle, const StyledObject &styledObject, const Parameters *parameters) override; + const Style *applyRelationStyle(const Style *baseStyle, ElementType elementType, + const RelationVisuals &relationVisuals, + const Parameters *parameters) override; const Style *applyRelationStyle(const Style *baseStyle, const StyledRelation &styledRelation, const Parameters *parameters) override; const Style *applyAnnotationStyle(const Style *baseStyle, const DAnnotation *annotation, @@ -54,6 +57,11 @@ private: ElementType objectType(const DObject *object); + bool areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole, + DObject::VisualSecondaryRole rhsSecondaryRole, + DObject::VisualPrimaryRole lhsPrimaryRole, + DObject::VisualSecondaryRole lhsSecondaryRols); + QColor baseColor(ElementType elementType, ObjectVisuals objectVisuals); QColor lineColor(ElementType elementType, const ObjectVisuals &objectVisuals); QColor fillColor(ElementType elementType, const ObjectVisuals &objectVisuals); diff --git a/src/libs/modelinglib/qmt/style/relationvisuals.cpp b/src/libs/modelinglib/qmt/style/relationvisuals.cpp new file mode 100644 index 00000000000..d297047ae1d --- /dev/null +++ b/src/libs/modelinglib/qmt/style/relationvisuals.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2024 Jochen Becher +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "relationvisuals.h" + +namespace qmt { + +RelationVisuals::RelationVisuals() {} + +RelationVisuals::RelationVisuals(DObject::VisualPrimaryRole visualObjectPrimaryRole, + DRelation::VisualPrimaryRole visualPrimaryRole, + DRelation::VisualSecondaryRole visualSecondaryRole, + bool emphasized) + : m_visualObjectPrimaryRole(visualObjectPrimaryRole) + , m_visualPrimaryRole(visualPrimaryRole) + , m_visualSecondaryRole(visualSecondaryRole) + , m_isEmphasized(emphasized) +{} + +RelationVisuals::~RelationVisuals() {} + +void RelationVisuals::setVisualPrimaryRole(DRelation::VisualPrimaryRole VisualPrimaryRole) +{ + m_visualPrimaryRole = VisualPrimaryRole; +} + +void RelationVisuals::setVisualObjectPrimaryRole(DObject::VisualPrimaryRole visualPrimaryRole) +{ + m_visualObjectPrimaryRole = visualPrimaryRole; +} + +void RelationVisuals::setVisualSecondaryRole(DRelation::VisualSecondaryRole visualSecondaryRole) +{ + m_visualSecondaryRole = visualSecondaryRole; +} + +void RelationVisuals::setEmphasized(bool emphasized) +{ + m_isEmphasized = emphasized; +} + +bool operator==(const RelationVisuals &lhs, const RelationVisuals &rhs) +{ + return lhs.visualObjectPrimaryRole() == rhs.visualObjectPrimaryRole() + && lhs.visualPrimaryRole() == rhs.visualPrimaryRole() + && lhs.visualSecondaryRole() == rhs.visualSecondaryRole() + && lhs.isEmphasized() == rhs.isEmphasized(); +} + +size_t qHash(const RelationVisuals &relationVisuals) +{ + return ::qHash(static_cast(relationVisuals.visualObjectPrimaryRole())) + ^ ::qHash(static_cast(relationVisuals.visualPrimaryRole())) + ^ ::qHash(static_cast(relationVisuals.visualSecondaryRole())) + ^ ::qHash(relationVisuals.isEmphasized()); +} + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/style/relationvisuals.h b/src/libs/modelinglib/qmt/style/relationvisuals.h new file mode 100644 index 00000000000..be87a7d2917 --- /dev/null +++ b/src/libs/modelinglib/qmt/style/relationvisuals.h @@ -0,0 +1,42 @@ +// Copyright (C) 2024 Jochen Becher +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "qmt/diagram/drelation.h" +#include "qmt/diagram/dobject.h" + +#include + +namespace qmt { + +class QMT_EXPORT RelationVisuals +{ +public: + RelationVisuals(); + RelationVisuals(DObject::VisualPrimaryRole visualObjectPrimaryRole, + DRelation::VisualPrimaryRole visualPrimaryRole, + DRelation::VisualSecondaryRole visualSecondaryRole, + bool emphasized); + ~RelationVisuals(); + + DObject::VisualPrimaryRole visualObjectPrimaryRole() const { return m_visualObjectPrimaryRole; } + void setVisualObjectPrimaryRole(DObject::VisualPrimaryRole visualPrimaryRole); + DRelation::VisualPrimaryRole visualPrimaryRole() const { return m_visualPrimaryRole; } + void setVisualPrimaryRole(DRelation::VisualPrimaryRole visualPrimaryRole); + DRelation::VisualSecondaryRole visualSecondaryRole() const { return m_visualSecondaryRole; } + void setVisualSecondaryRole(DRelation::VisualSecondaryRole visualSecondaryRole); + bool isEmphasized() const { return m_isEmphasized; } + void setEmphasized(bool emphasized); + +private: + DObject::VisualPrimaryRole m_visualObjectPrimaryRole = DObject::PrimaryRoleNormal; + DRelation::VisualPrimaryRole m_visualPrimaryRole = DRelation::PrimaryRoleNormal; + DRelation::VisualSecondaryRole m_visualSecondaryRole = DRelation::SecondaryRoleNone; + bool m_isEmphasized = false; +}; + +bool operator==(const RelationVisuals &lhs, const RelationVisuals &rhs); +size_t qHash(const RelationVisuals &relationVisuals); + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/style/stylecontroller.cpp b/src/libs/modelinglib/qmt/style/stylecontroller.cpp index 5cd50c1738a..bbfc28622ed 100644 --- a/src/libs/modelinglib/qmt/style/stylecontroller.cpp +++ b/src/libs/modelinglib/qmt/style/stylecontroller.cpp @@ -63,6 +63,12 @@ const Style *StyleController::adaptObjectStyle(const StyledObject &object) return m_defaultStyleEngine->applyObjectStyle(m_defaultStyle.data(), object, ¶meters); } +const Style *StyleController::adaptRelationStyle(StyleEngine::ElementType elementType, const RelationVisuals &relationVisuals) +{ + Parameters parameters(this); + return m_defaultStyleEngine->applyRelationStyle(m_defaultStyle.data(), elementType, relationVisuals, ¶meters); +} + const Style *StyleController::adaptRelationStyle(const StyledRelation &relation) { Parameters parameters(this); diff --git a/src/libs/modelinglib/qmt/style/stylecontroller.h b/src/libs/modelinglib/qmt/style/stylecontroller.h index 2627bb2caa2..afa566460fc 100644 --- a/src/libs/modelinglib/qmt/style/stylecontroller.h +++ b/src/libs/modelinglib/qmt/style/stylecontroller.h @@ -4,7 +4,6 @@ #pragma once #include "styleengine.h" -#include "qmt/diagram/dobject.h" #include #include @@ -14,6 +13,7 @@ namespace qmt { class Style; class ObjectVisuals; class StyledObject; +class RelationVisuals; class StyledRelation; class DAnnotation; class DBoundary; @@ -33,6 +33,8 @@ public: const Style *adaptObjectStyle(StyleEngine::ElementType elementType, const ObjectVisuals &objectVisuals); const Style *adaptObjectStyle(const StyledObject &object); + const Style *adaptRelationStyle(StyleEngine::ElementType elementType, + const RelationVisuals &relationVisuals); const Style *adaptRelationStyle(const StyledRelation &relation); const Style *adaptAnnotationStyle(const DAnnotation *annotation); const Style *adaptBoundaryStyle(const DBoundary *boundary); diff --git a/src/libs/modelinglib/qmt/style/styledrelation.cpp b/src/libs/modelinglib/qmt/style/styledrelation.cpp index 3c78abf96df..144e5f22ac7 100644 --- a/src/libs/modelinglib/qmt/style/styledrelation.cpp +++ b/src/libs/modelinglib/qmt/style/styledrelation.cpp @@ -5,10 +5,12 @@ namespace qmt { -StyledRelation::StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB) +StyledRelation::StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB, + const CustomRelation *customRelation) : m_relation(relation), m_endA(endA), - m_endB(endB) + m_endB(endB), + m_customRelation(customRelation) { } diff --git a/src/libs/modelinglib/qmt/style/styledrelation.h b/src/libs/modelinglib/qmt/style/styledrelation.h index 422947908e2..27e8735463d 100644 --- a/src/libs/modelinglib/qmt/style/styledrelation.h +++ b/src/libs/modelinglib/qmt/style/styledrelation.h @@ -9,21 +9,25 @@ namespace qmt { class DRelation; class DObject; +class CustomRelation; class QMT_EXPORT StyledRelation { public: - StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB); + StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB, + const CustomRelation *customRelation); ~StyledRelation(); const DRelation *relation() const { return m_relation; } const DObject *endA() const { return m_endA; } const DObject *endB() const { return m_endB; } + const CustomRelation *customRelation() const { return m_customRelation; } private: const DRelation *m_relation = nullptr; const DObject *m_endA = nullptr; const DObject *m_endB = nullptr; + const CustomRelation *m_customRelation = nullptr; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/style/styleengine.h b/src/libs/modelinglib/qmt/style/styleengine.h index e78f4303d93..463a62a194d 100644 --- a/src/libs/modelinglib/qmt/style/styleengine.h +++ b/src/libs/modelinglib/qmt/style/styleengine.h @@ -14,6 +14,7 @@ namespace qmt { class Style; class ObjectVisuals; class StyledObject; +class RelationVisuals; class StyledRelation; class DAnnotation; @@ -51,6 +52,9 @@ public: const Parameters *parameters) = 0; virtual const Style *applyObjectStyle(const Style *baseStyle, const StyledObject &, const Parameters *) = 0; + virtual const Style *applyRelationStyle(const Style *baseStyle, ElementType elementType, + const RelationVisuals &relationVisuals, + const Parameters *) = 0; virtual const Style *applyRelationStyle(const Style *baseStyle, const StyledRelation &, const Parameters *) = 0; virtual const Style *applyAnnotationStyle(const Style *baseStyle, const DAnnotation *, -- cgit v1.2.3