1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Jochen Becher
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "defaultstyleengine.h"
27 
28 #include "defaultstyle.h"
29 #include "objectvisuals.h"
30 #include "styledobject.h"
31 #include "styledrelation.h"
32 
33 #include "qmt/diagram/dclass.h"
34 #include "qmt/diagram/dpackage.h"
35 #include "qmt/diagram/dcomponent.h"
36 #include "qmt/diagram/ditem.h"
37 #include "qmt/diagram/dannotation.h"
38 #include "qmt/infrastructure/qmtassert.h"
39 
40 #include <utils/algorithm.h>
41 
42 #include <QSet>
43 
44 namespace {
45 
46 class DepthProperties
47 {
48 public:
49     DepthProperties() = default;
DepthProperties(qmt::DefaultStyleEngine::ElementType elementType,qmt::DObject::VisualPrimaryRole visualPrimaryRole,qmt::DObject::VisualSecondaryRole visualSecondaryRole)50     DepthProperties(qmt::DefaultStyleEngine::ElementType elementType,
51                     qmt::DObject::VisualPrimaryRole visualPrimaryRole,
52                     qmt::DObject::VisualSecondaryRole visualSecondaryRole)
53         : m_elementType(elementType),
54           m_visualPrimaryRole(visualPrimaryRole),
55           m_visualSecondaryRole(visualSecondaryRole)
56     {
57     }
58 
59     qmt::DefaultStyleEngine::ElementType m_elementType = qmt::DefaultStyleEngine::TypeOther;
60     qmt::DObject::VisualPrimaryRole m_visualPrimaryRole = qmt::DObject::PrimaryRoleNormal;
61     qmt::DObject::VisualSecondaryRole m_visualSecondaryRole = qmt::DObject::SecondaryRoleNone;
62 };
63 
64 } // namespace
65 
66 namespace qmt {
67 
68 // TODO use tuple instead of these 4 explicit key classes
69 
70 class ObjectStyleKey
71 {
72 public:
73     ObjectStyleKey() = default;
74 
ObjectStyleKey(StyleEngine::ElementType elementType,const ObjectVisuals & objectVisuals)75     ObjectStyleKey(StyleEngine::ElementType elementType, const ObjectVisuals &objectVisuals)
76         : m_elementType(elementType),
77           m_objectVisuals(objectVisuals)
78     {
79     }
80 
81     StyleEngine::ElementType m_elementType = StyleEngine::TypeOther;
82     ObjectVisuals m_objectVisuals;
83 };
84 
qHash(const ObjectStyleKey & styleKey)85 uint qHash(const ObjectStyleKey &styleKey)
86 {
87     return ::qHash(styleKey.m_elementType) ^ qHash(styleKey.m_objectVisuals);
88 }
89 
operator ==(const ObjectStyleKey & lhs,const ObjectStyleKey & rhs)90 bool operator==(const ObjectStyleKey &lhs, const ObjectStyleKey &rhs)
91 {
92     return lhs.m_elementType == rhs.m_elementType && lhs.m_objectVisuals == rhs.m_objectVisuals;
93 }
94 
95 class RelationStyleKey
96 {
97 public:
RelationStyleKey(StyleEngine::ElementType elementType=StyleEngine::TypeOther,DObject::VisualPrimaryRole visualPrimaryRole=DObject::PrimaryRoleNormal)98     RelationStyleKey(StyleEngine::ElementType elementType = StyleEngine::TypeOther,
99                      DObject::VisualPrimaryRole visualPrimaryRole = DObject::PrimaryRoleNormal)
100         : m_elementType(elementType),
101           m_visualPrimaryRole(visualPrimaryRole)
102     {
103     }
104 
105     StyleEngine::ElementType m_elementType = StyleEngine::TypeOther;
106     DObject::VisualPrimaryRole m_visualPrimaryRole = DObject::PrimaryRoleNormal;
107 };
108 
qHash(const RelationStyleKey & styleKey)109 uint qHash(const RelationStyleKey &styleKey)
110 {
111     return ::qHash(styleKey.m_elementType) ^ ::qHash(styleKey.m_visualPrimaryRole);
112 }
113 
operator ==(const RelationStyleKey & lhs,const RelationStyleKey & rhs)114 bool operator==(const RelationStyleKey &lhs, const RelationStyleKey &rhs)
115 {
116     return lhs.m_elementType == rhs.m_elementType && lhs.m_visualPrimaryRole == rhs.m_visualPrimaryRole;
117 }
118 
119 class AnnotationStyleKey
120 {
121 public:
AnnotationStyleKey(DAnnotation::VisualRole visualRole=DAnnotation::RoleNormal)122     AnnotationStyleKey(DAnnotation::VisualRole visualRole = DAnnotation::RoleNormal)
123         : m_visualRole(visualRole)
124     {
125     }
126 
127     DAnnotation::VisualRole m_visualRole = DAnnotation::RoleNormal;
128 };
129 
qHash(const AnnotationStyleKey & styleKey)130 uint qHash(const AnnotationStyleKey &styleKey)
131 {
132     return ::qHash(styleKey.m_visualRole);
133 }
134 
operator ==(const AnnotationStyleKey & lhs,const AnnotationStyleKey & rhs)135 bool operator==(const AnnotationStyleKey &lhs, const AnnotationStyleKey &rhs)
136 {
137     return lhs.m_visualRole == rhs.m_visualRole;
138 }
139 
140 // TODO remove class if no attributes needed even with future extensions
141 class BoundaryStyleKey
142 {
143 };
144 
qHash(const BoundaryStyleKey & styleKey)145 uint qHash(const BoundaryStyleKey &styleKey)
146 {
147     Q_UNUSED(styleKey)
148 
149     return 1;
150 }
151 
operator ==(const BoundaryStyleKey & lhs,const BoundaryStyleKey & rhs)152 bool operator==(const BoundaryStyleKey &lhs, const BoundaryStyleKey &rhs)
153 {
154     Q_UNUSED(lhs)
155     Q_UNUSED(rhs)
156 
157     return true;
158 }
159 
160 // TODO remove class if no attributes needed even with future extensions
161 class SwimlaneStyleKey
162 {
163 };
164 
qHash(const SwimlaneStyleKey & styleKey)165 uint qHash(const SwimlaneStyleKey &styleKey)
166 {
167     Q_UNUSED(styleKey)
168 
169     return 1;
170 }
171 
operator ==(const SwimlaneStyleKey & lhs,const SwimlaneStyleKey & rhs)172 bool operator==(const SwimlaneStyleKey &lhs, const SwimlaneStyleKey &rhs)
173 {
174     Q_UNUSED(lhs)
175     Q_UNUSED(rhs)
176 
177     return true;
178 }
179 
DefaultStyleEngine()180 DefaultStyleEngine::DefaultStyleEngine()
181 {
182 }
183 
~DefaultStyleEngine()184 DefaultStyleEngine::~DefaultStyleEngine()
185 {
186     qDeleteAll(m_objectStyleMap);
187     qDeleteAll(m_relationStyleMap);
188     qDeleteAll(m_annotationStyleMap);
189     qDeleteAll(m_boundaryStyleMap);
190 }
191 
applyStyle(const Style * baseStyle,StyleEngine::ElementType elementType,const StyleEngine::Parameters * parameters)192 const Style *DefaultStyleEngine::applyStyle(const Style *baseStyle, StyleEngine::ElementType elementType,
193                                             const StyleEngine::Parameters *parameters)
194 {
195     switch (elementType) {
196     case TypeAnnotation:
197         return applyAnnotationStyle(baseStyle, DAnnotation::RoleNormal, parameters);
198     case TypeBoundary:
199         return applyBoundaryStyle(baseStyle, parameters);
200     case TypeRelation:
201         break;
202     case TypeClass:
203     case TypeComponent:
204     case TypeItem:
205     case TypePackage:
206         return applyObjectStyle(
207                     baseStyle, elementType,
208                     ObjectVisuals(DObject::PrimaryRoleNormal, DObject::SecondaryRoleNone, false, QColor(), 0),
209                     parameters);
210     case TypeOther:
211         break;
212     case TypeSwimlane:
213         return applySwimlaneStyle(baseStyle, parameters);
214     }
215     return baseStyle;
216 }
217 
applyObjectStyle(const Style * baseStyle,StyleEngine::ElementType elementType,const ObjectVisuals & objectVisuals,const StyleEngine::Parameters * parameters)218 const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, StyleEngine::ElementType elementType,
219                                                   const ObjectVisuals &objectVisuals,
220                                                   const StyleEngine::Parameters *parameters)
221 {
222     ObjectStyleKey key(elementType, objectVisuals);
223     const Style *derivedStyle = m_objectStyleMap.value(key);
224     if (!derivedStyle) {
225         int lineWidth = 1;
226 
227         QColor fillColor = DefaultStyleEngine::fillColor(elementType, objectVisuals);
228         QColor lineColor = DefaultStyleEngine::lineColor(elementType, objectVisuals);
229         QColor textColor = DefaultStyleEngine::textColor(elementType, objectVisuals);
230 
231         QFont normalFont = baseStyle->normalFont();
232         QFont headerFont = baseStyle->normalFont();
233         if (objectVisuals.isEmphasized()) {
234             lineWidth = 2;
235             headerFont.setBold(true);
236         }
237 
238         auto style = new Style(baseStyle->type());
239         QPen linePen = baseStyle->linePen();
240         linePen.setColor(lineColor);
241         linePen.setWidth(lineWidth);
242         style->setLinePen(linePen);
243         style->setInnerLinePen(linePen);
244         style->setOuterLinePen(linePen);
245         style->setExtraLinePen(linePen);
246         style->setTextBrush(QBrush(textColor));
247         if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleOutline) {
248             style->setFillBrush(QBrush(Qt::white));
249         } else if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleFlat) {
250             style->setFillBrush(QBrush(fillColor));
251         } else {
252             if (!parameters->suppressGradients()) {
253                 QLinearGradient fillGradient(0.0, 0.0, 0.0, 1.0);
254                 fillGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
255                 fillGradient.setColorAt(0.0, fillColor.lighter(110));
256                 fillGradient.setColorAt(1.0, fillColor.darker(110));
257                 style->setFillBrush(QBrush(fillGradient));
258             } else {
259                 style->setFillBrush(QBrush(fillColor));
260             }
261         }
262         if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleOutline)
263             style->setExtraFillBrush(QBrush(Qt::white));
264         else if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleFlat)
265             style->setExtraFillBrush(QBrush(fillColor));
266         else
267             style->setExtraFillBrush(QBrush(fillColor.darker(120)));
268         style->setNormalFont(normalFont);
269         style->setSmallFont(baseStyle->smallFont());
270         style->setHeaderFont(headerFont);
271         m_objectStyleMap.insert(key, style);
272         derivedStyle = style;
273     }
274 
275     return derivedStyle;
276 }
277 
applyObjectStyle(const Style * baseStyle,const StyledObject & styledObject,const Parameters * parameters)278 const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const StyledObject &styledObject,
279                                                   const Parameters *parameters)
280 {
281     ElementType elementType = objectType(styledObject.object());
282 
283     // find colliding elements which best match visual appearance of styled object
284     DObject::VisualPrimaryRole styledVisualPrimaryRole = styledObject.objectVisuals().visualPrimaryRole();
285     DObject::VisualSecondaryRole styledVisualSecondaryRole = styledObject.objectVisuals().visualSecondaryRole();
286     QHash<int, DepthProperties> depths;
287     foreach (const DObject *collidingObject, styledObject.collidingObjects()) {
288         int collidingDepth = collidingObject->depth();
289         if (collidingDepth < styledObject.object()->depth()) {
290             ElementType collidingElementType = objectType(collidingObject);
291             DObject::VisualPrimaryRole collidingVisualPrimaryRole = collidingObject->visualPrimaryRole();
292             DObject::VisualSecondaryRole collidingVisualSecondaryRole = collidingObject->visualSecondaryRole();
293             if (!depths.contains(collidingDepth)) {
294                 depths.insert(collidingDepth, DepthProperties(collidingElementType, collidingVisualPrimaryRole,
295                                                               collidingVisualSecondaryRole));
296             } else {
297                 bool updateProperties = false;
298                 DepthProperties properties = depths.value(collidingDepth);
299                 if (properties.m_elementType != elementType && collidingElementType == elementType) {
300                     properties.m_elementType = collidingElementType;
301                     properties.m_visualPrimaryRole = collidingVisualPrimaryRole;
302                     properties.m_visualSecondaryRole = collidingVisualSecondaryRole;
303                     updateProperties = true;
304                 } else if (properties.m_elementType == elementType && collidingElementType == elementType) {
305                     if ((properties.m_visualPrimaryRole != styledVisualPrimaryRole
306                          || properties.m_visualSecondaryRole != styledVisualSecondaryRole)
307                             && collidingVisualPrimaryRole == styledVisualPrimaryRole
308                             && collidingVisualSecondaryRole == styledVisualSecondaryRole) {
309                         properties.m_visualPrimaryRole = collidingVisualPrimaryRole;
310                         properties.m_visualSecondaryRole = collidingVisualSecondaryRole;
311                         updateProperties = true;
312                     }
313                 }
314                 if (updateProperties)
315                     depths.insert(collidingDepth, properties);
316             }
317         }
318     }
319     int depth = 0;
320     if (!depths.isEmpty()) {
321         QList<int> keys = depths.keys();
322         Utils::sort(keys);
323         foreach (int d, keys) {
324             DepthProperties properties = depths.value(d);
325             if (properties.m_elementType == elementType
326                     && areStackingRoles(properties.m_visualPrimaryRole, properties.m_visualSecondaryRole,
327                                         styledVisualPrimaryRole, styledVisualSecondaryRole)) {
328                 ++depth;
329             } else {
330                 depth = 0;
331             }
332         }
333     }
334 
335     return applyObjectStyle(baseStyle, elementType,
336                             ObjectVisuals(styledVisualPrimaryRole,
337                                           styledVisualSecondaryRole,
338                                           styledObject.objectVisuals().isEmphasized(),
339                                           styledObject.objectVisuals().baseColor(),
340                                           depth),
341                             parameters);
342 }
343 
applyRelationStyle(const Style * baseStyle,const StyledRelation & styledRelation,const Parameters * parameters)344 const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, const StyledRelation &styledRelation,
345                                                     const Parameters *parameters)
346 {
347     Q_UNUSED(parameters)
348 
349     ElementType elementType = objectType(styledRelation.endA());
350     RelationStyleKey key(elementType, styledRelation.endA() ? styledRelation.endA()->visualPrimaryRole() : DObject::PrimaryRoleNormal);
351     const Style *derivedStyle = m_relationStyleMap.value(key);
352     if (!derivedStyle) {
353         auto style = new Style(baseStyle->type());
354 
355         const DObject *object = styledRelation.endA();
356         ObjectVisuals objectVisuals(object ? object->visualPrimaryRole() : DObject::PrimaryRoleNormal,
357                                      object ? object->visualSecondaryRole() : DObject::SecondaryRoleNone,
358                                      object ? object->isVisualEmphasized() : false,
359                                      Qt::black, // TODO STyledRelation should get an EndAObjectVisuals
360                                      object ? object->depth() : 0);
361         QColor lineColor = DefaultStyleEngine::lineColor(objectType(object), objectVisuals);
362         QColor fillColor = lineColor;
363 
364         QPen linePen = baseStyle->linePen();
365         linePen.setWidth(1);
366         linePen.setColor(lineColor);
367         style->setLinePen(linePen);
368         QBrush textBrush = baseStyle->textBrush();
369         textBrush.setColor(QColor("black"));
370         style->setTextBrush(textBrush);
371         QBrush brush = baseStyle->fillBrush();
372         brush.setColor(fillColor);
373         brush.setStyle(Qt::SolidPattern);
374         style->setFillBrush(brush);
375         style->setNormalFont(baseStyle->normalFont());
376         style->setSmallFont(baseStyle->smallFont());
377         style->setHeaderFont(baseStyle->headerFont());
378         m_relationStyleMap.insert(key, style);
379         derivedStyle = style;
380     }
381     return derivedStyle;
382 }
383 
applyAnnotationStyle(const Style * baseStyle,const DAnnotation * annotation,const Parameters * parameters)384 const Style *DefaultStyleEngine::applyAnnotationStyle(const Style *baseStyle, const DAnnotation *annotation,
385                                                       const Parameters *parameters)
386 {
387     DAnnotation::VisualRole visualRole = annotation ? annotation->visualRole() : DAnnotation::RoleNormal;
388     return applyAnnotationStyle(baseStyle, visualRole, parameters);
389 }
390 
applyBoundaryStyle(const Style * baseStyle,const DBoundary * boundary,const Parameters * parameters)391 const Style *DefaultStyleEngine::applyBoundaryStyle(const Style *baseStyle, const DBoundary *boundary,
392                                                     const Parameters *parameters)
393 {
394     Q_UNUSED(boundary)
395 
396     return applyBoundaryStyle(baseStyle, parameters);
397 }
398 
applySwimlaneStyle(const Style * baseStyle,const DSwimlane * swimlane,const StyleEngine::Parameters * parameters)399 const Style *DefaultStyleEngine::applySwimlaneStyle(const Style *baseStyle, const DSwimlane *swimlane, const StyleEngine::Parameters *parameters)
400 {
401     Q_UNUSED(swimlane)
402 
403     return applySwimlaneStyle(baseStyle, parameters);
404 }
405 
applyAnnotationStyle(const Style * baseStyle,DAnnotation::VisualRole visualRole,const StyleEngine::Parameters * parameters)406 const Style *DefaultStyleEngine::applyAnnotationStyle(const Style *baseStyle, DAnnotation::VisualRole visualRole,
407                                                       const StyleEngine::Parameters *parameters)
408 {
409     Q_UNUSED(parameters)
410 
411     AnnotationStyleKey key(visualRole);
412     const Style *derivedStyle = m_annotationStyleMap.value(key);
413     if (!derivedStyle) {
414         auto style = new Style(baseStyle->type());
415         QFont normalFont;
416         QBrush textBrush = baseStyle->textBrush();
417         switch (visualRole) {
418         case DAnnotation::RoleNormal:
419             normalFont = baseStyle->normalFont();
420             break;
421         case DAnnotation::RoleTitle:
422             normalFont = baseStyle->headerFont();
423             break;
424         case DAnnotation::RoleSubtitle:
425             normalFont = baseStyle->normalFont();
426             normalFont.setItalic(true);
427             break;
428         case DAnnotation::RoleEmphasized:
429             normalFont = baseStyle->normalFont();
430             normalFont.setBold(true);
431             break;
432         case DAnnotation::RoleSoften:
433             normalFont = baseStyle->normalFont();
434             textBrush.setColor(Qt::gray);
435             break;
436         case DAnnotation::RoleFootnote:
437             normalFont = baseStyle->smallFont();
438             break;
439         }
440         style->setNormalFont(normalFont);
441         style->setTextBrush(textBrush);
442         m_annotationStyleMap.insert(key, style);
443         derivedStyle = style;
444     }
445     return derivedStyle;
446 }
447 
applyBoundaryStyle(const Style * baseStyle,const StyleEngine::Parameters * parameters)448 const Style *DefaultStyleEngine::applyBoundaryStyle(const Style *baseStyle, const StyleEngine::Parameters *parameters)
449 {
450     Q_UNUSED(parameters)
451 
452     BoundaryStyleKey key;
453     const Style *derivedStyle = m_boundaryStyleMap.value(key);
454     if (!derivedStyle) {
455         auto style = new Style(baseStyle->type());
456         style->setNormalFont(baseStyle->normalFont());
457         style->setTextBrush(baseStyle->textBrush());
458         m_boundaryStyleMap.insert(key, style);
459         derivedStyle = style;
460     }
461     return derivedStyle;
462 }
463 
applySwimlaneStyle(const Style * baseStyle,const StyleEngine::Parameters * parameters)464 const Style *DefaultStyleEngine::applySwimlaneStyle(const Style *baseStyle, const StyleEngine::Parameters *parameters)
465 {
466     Q_UNUSED(parameters)
467 
468     SwimlaneStyleKey key;
469     const Style *derivedStyle = m_swimlaneStyleMap.value(key);
470     if (!derivedStyle) {
471         auto style = new Style(baseStyle->type());
472         style->setNormalFont(baseStyle->normalFont());
473         style->setTextBrush(baseStyle->textBrush());
474         m_swimlaneStyleMap.insert(key, style);
475         derivedStyle = style;
476     }
477     return derivedStyle;
478 }
479 
objectType(const DObject * object)480 DefaultStyleEngine::ElementType DefaultStyleEngine::objectType(const DObject *object)
481 {
482     ElementType elementType;
483     if (dynamic_cast<const DPackage *>(object))
484         elementType = TypePackage;
485     else if (dynamic_cast<const DComponent *>(object))
486         elementType = TypeComponent;
487     else if (dynamic_cast<const DClass *>(object))
488         elementType = TypeClass;
489     else if (dynamic_cast<const DItem *>(object))
490         elementType = TypeItem;
491     else
492         elementType = TypeOther;
493     return elementType;
494 }
495 
areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole,DObject::VisualSecondaryRole rhsSecondaryRole,DObject::VisualPrimaryRole lhsPrimaryRole,DObject::VisualSecondaryRole lhsSecondaryRols)496 bool DefaultStyleEngine::areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole,
497                                           DObject::VisualSecondaryRole rhsSecondaryRole,
498                                           DObject::VisualPrimaryRole lhsPrimaryRole,
499                                           DObject::VisualSecondaryRole lhsSecondaryRols)
500 {
501     switch (rhsSecondaryRole) {
502     case DObject::SecondaryRoleNone:
503     case DObject::SecondaryRoleLighter:
504     case DObject::SecondaryRoleDarker:
505     case DObject::SecondaryRoleFlat:
506         switch (lhsSecondaryRols) {
507         case DObject::SecondaryRoleNone:
508         case DObject::SecondaryRoleLighter:
509         case DObject::SecondaryRoleDarker:
510         case DObject::SecondaryRoleFlat:
511             return lhsPrimaryRole == rhsPrimaryRole;
512         case DObject::SecondaryRoleSoften:
513         case DObject::SecondaryRoleOutline:
514             return false;
515         }
516         break;
517     case DObject::SecondaryRoleSoften:
518     case DObject::SecondaryRoleOutline:
519         return false;
520     }
521     return true;
522 }
523 
baseColor(ElementType elementType,ObjectVisuals objectVisuals)524 QColor DefaultStyleEngine::baseColor(ElementType elementType, ObjectVisuals objectVisuals)
525 {
526     if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleOutline)
527         return QColor(0xFF, 0xFF, 0xFF);
528 
529     QColor baseColor;
530 
531     if (objectVisuals.visualPrimaryRole() == DObject::PrimaryRoleNormal) {
532         if (objectVisuals.baseColor().isValid()) {
533             baseColor = objectVisuals.baseColor();
534         } else {
535             switch (elementType) {
536             case TypePackage:
537                 baseColor = QColor(0x7C, 0x98, 0xAD);
538                 break;
539             case TypeComponent:
540                 baseColor = QColor(0xA0, 0xA8, 0x91);
541                 break;
542             case TypeClass:
543                 baseColor = QColor(0xE5, 0xA8, 0x58);
544                 break;
545             case TypeItem:
546                 baseColor = QColor(0xB9, 0x95, 0xC6);
547                 break;
548             case TypeRelation:
549             case TypeAnnotation:
550             case TypeBoundary:
551             case TypeSwimlane:
552             case TypeOther:
553                 baseColor = QColor(0xBF, 0x7D, 0x65);
554                 break;
555             }
556         }
557     } else {
558         static QColor customColors[] = {
559             QColor(0xEE, 0x8E, 0x99).darker(110),  // ROLE_CUSTOM1,
560             QColor(0x80, 0xAF, 0x47).lighter(130), // ROLE_CUSTOM2,
561             QColor(0xFF, 0xA1, 0x5B).lighter(100), // ROLE_CUSTOM3,
562             QColor(0x55, 0xC4, 0xCF).lighter(120), // ROLE_CUSTOM4,
563             QColor(0xFF, 0xE1, 0x4B)               // ROLE_CUSTOM5,
564         };
565 
566         int index = static_cast<int>(objectVisuals.visualPrimaryRole()) - static_cast<int>(DObject::PrimaryRoleCustom1);
567         QMT_ASSERT(index >= 0 && index <= 4, return baseColor);
568         baseColor = customColors[index];
569     }
570 
571     switch (objectVisuals.visualSecondaryRole()) {
572     case DObject::SecondaryRoleNone:
573         break;
574     case DObject::SecondaryRoleLighter:
575         baseColor = baseColor.lighter(110);
576         break;
577     case DObject::SecondaryRoleDarker:
578         baseColor = baseColor.darker(120);
579         break;
580     case DObject::SecondaryRoleSoften:
581         baseColor = baseColor.lighter(300);
582         break;
583     case DObject::SecondaryRoleOutline:
584         QMT_CHECK(false);
585         break;
586     case DObject::SecondaryRoleFlat:
587         break;
588     }
589 
590     return baseColor;
591 }
592 
lineColor(ElementType elementType,const ObjectVisuals & objectVisuals)593 QColor DefaultStyleEngine::lineColor(ElementType elementType, const ObjectVisuals &objectVisuals)
594 {
595     QColor lineColor;
596     if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleOutline)
597         lineColor = Qt::black;
598     else if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleSoften)
599         lineColor = Qt::gray;
600     else
601         lineColor = baseColor(elementType, objectVisuals).darker(200).lighter(150).darker(100 + objectVisuals.depth() * 10);
602     return lineColor;
603 }
604 
fillColor(ElementType elementType,const ObjectVisuals & objectVisuals)605 QColor DefaultStyleEngine::fillColor(ElementType elementType, const ObjectVisuals &objectVisuals)
606 {
607     QColor fillColor;
608     if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleOutline)
609         fillColor = Qt::white;
610     else
611         fillColor = baseColor(elementType, objectVisuals).lighter(150).darker(100 + objectVisuals.depth() * 10);
612     return fillColor;
613 }
614 
textColor(const DObject * object,int depth)615 QColor DefaultStyleEngine::textColor(const DObject *object, int depth)
616 {
617     Q_UNUSED(depth)
618 
619     QColor textColor;
620     DObject::VisualPrimaryRole visualRole = object ? object->visualPrimaryRole() : DObject::PrimaryRoleNormal;
621     if (visualRole == DObject::DeprecatedPrimaryRoleSoften)
622         textColor = Qt::gray;
623     else
624         textColor = Qt::black;
625     return textColor;
626 }
627 
textColor(ElementType elementType,const ObjectVisuals & objectVisuals)628 QColor DefaultStyleEngine::textColor(ElementType elementType, const ObjectVisuals &objectVisuals)
629 {
630     Q_UNUSED(elementType)
631 
632     QColor textColor;
633     if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleSoften)
634         textColor = Qt::gray;
635     else
636         textColor = Qt::black;
637     return textColor;
638 }
639 
640 } // namespace qmt
641