1 /*
2 Copyright 2006-2019 The QElectroTech Team
3 This file is part of QElectroTech.
4
5 QElectroTech is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 QElectroTech is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "customelementgraphicpart.h"
19 #include "elementscene.h"
20 #include "QPropertyUndoCommand/qpropertyundocommand.h"
21
22 /**
23 * @brief CustomElementGraphicPart::CustomElementGraphicPart
24 * Default constructor.
25 * By default, item is selectable, send geometry change (Qt > 4.6),
26 * accept mouse left button and accept hover event
27 * @param editor QETElement editor that belong this.
28 */
CustomElementGraphicPart(QETElementEditor * editor,QGraphicsItem * parent)29 CustomElementGraphicPart::CustomElementGraphicPart(QETElementEditor *editor, QGraphicsItem *parent) :
30 QGraphicsObject (parent),
31 CustomElementPart(editor),
32 m_hovered (false),
33 _linestyle(NormalStyle),
34 _lineweight(NormalWeight),
35 _filling(NoneFilling),
36 _color(BlackColor),
37 _antialiased(false)
38 {
39 setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges);
40 setAcceptHoverEvents(true);
41 }
42
43 /**
44 * @brief CustomElementGraphicPart::~CustomElementGraphicPart
45 * Destructor
46 */
~CustomElementGraphicPart()47 CustomElementGraphicPart::~CustomElementGraphicPart() {}
48
49 /**
50 * @brief CustomElementGraphicPart::drawCross
51 * Draw a cross at pos center
52 * @param center : center of cross
53 * @param painter : painter to use for draw cross,
54 * the painter state is restored at end of this method.
55 */
drawCross(const QPointF & center,QPainter * painter)56 void CustomElementGraphicPart::drawCross(const QPointF ¢er, QPainter *painter)
57 {
58 painter -> save();
59 painter -> setRenderHint(QPainter::Antialiasing, false);
60 painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
61 painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
62 painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
63 painter -> restore();
64 }
65
66 /**
67 * @brief CustomElementGraphicPart::setLineStyle
68 * Set line style to ls
69 * @param ls
70 */
setLineStyle(const LineStyle ls)71 void CustomElementGraphicPart::setLineStyle(const LineStyle ls)
72 {
73 if (_linestyle == ls) return;
74 _linestyle = ls;
75 update();
76 }
77
78 /**
79 * @brief CustomElementGraphicPart::setLineWeight
80 * Set line weight to lw
81 * @param lw
82 */
setLineWeight(const LineWeight lw)83 void CustomElementGraphicPart::setLineWeight(const LineWeight lw)
84 {
85 if (_lineweight == lw) return;
86 _lineweight = lw;
87 update();
88 }
89
90 /**
91 * @brief CustomElementGraphicPart::penWeight
92 * @return the weight of pen
93 */
penWeight() const94 qreal CustomElementGraphicPart::penWeight() const
95 {
96 if (_lineweight == NoneWeight || _lineweight == ThinWeight) return 0;
97 else if (_lineweight == NormalWeight) return 1;
98 else if (_lineweight == UltraWeight) return 2;
99 else if (_lineweight == BigWeight) return 5;
100 return 1;
101 }
102
103 /**
104 * @brief CustomElementGraphicPart::setFilling
105 * Set filling to f
106 * @param f
107 */
setFilling(const Filling f)108 void CustomElementGraphicPart::setFilling(const Filling f)
109 {
110 if (_filling == f) return;
111 _filling = f;
112 update();
113 }
114
115 /**
116 * @brief CustomElementGraphicPart::setColor
117 * Set color to c
118 * @param c
119 */
setColor(const Color c)120 void CustomElementGraphicPart::setColor(const Color c)
121 {
122 if (_color == c) return;
123 _color = c;
124 update();
125 }
126
127 /**
128 * @brief CustomElementGraphicPart::setAntialiased
129 * Set antialias to b
130 * @param b
131 */
setAntialiased(const bool b)132 void CustomElementGraphicPart::setAntialiased(const bool b)
133 {
134 if (_antialiased == b) return;
135 _antialiased = b;
136 update();
137 }
138
139 /**
140 * @brief CustomElementGraphicPart::stylesToXml
141 * Write the curent style to xml element.
142 * The style are stored like this:
143 * name-of-style:value;name-of-style:value
144 * Each style separate by ; and name-style/value are separate by :
145 * @param qde : QDOmElement used to write the style.
146 */
stylesToXml(QDomElement & qde) const147 void CustomElementGraphicPart::stylesToXml(QDomElement &qde) const
148 {
149 QString css_like_styles;
150
151 css_like_styles += "line-style:";
152 if (_linestyle == DashedStyle) css_like_styles += "dashed";
153 else if (_linestyle == DottedStyle) css_like_styles += "dotted";
154 else if (_linestyle == DashdottedStyle) css_like_styles += "dashdotted";
155 else if (_linestyle == NormalStyle) css_like_styles += "normal";
156
157 css_like_styles += ";line-weight:";
158 if (_lineweight == NoneWeight) css_like_styles += "none";
159 else if (_lineweight == ThinWeight) css_like_styles += "thin";
160 else if (_lineweight == NormalWeight) css_like_styles += "normal";
161 else if (_lineweight == UltraWeight) css_like_styles += "hight";
162 else if (_lineweight == BigWeight) css_like_styles += "eleve";
163
164
165 css_like_styles += ";filling:";
166 if (_filling == NoneFilling) css_like_styles += "none";
167 else if (_filling == BlackFilling) css_like_styles += "black";
168 else if (_filling == WhiteFilling) css_like_styles += "white";
169 else if (_filling == GreenFilling) css_like_styles += "green";
170 else if (_filling == BlueFilling) css_like_styles += "blue";
171 else if (_filling == RedFilling) css_like_styles += "red";
172 else if (_filling == GrayFilling) css_like_styles += "gray";
173 else if (_filling == BrunFilling) css_like_styles += "brun";
174 else if (_filling == YellowFilling) css_like_styles += "yellow";
175 else if (_filling == CyanFilling) css_like_styles += "cyan";
176 else if (_filling == MagentaFilling) css_like_styles += "magenta";
177 else if (_filling == LightgrayFilling) css_like_styles += "lightgray";
178 else if (_filling == OrangeFilling) css_like_styles += "orange";
179 else if (_filling == PurpleFilling) css_like_styles += "purple";
180 else if (_filling == HorFilling) css_like_styles += "hor";
181 else if (_filling == VerFilling) css_like_styles += "ver";
182 else if (_filling == BdiagFilling) css_like_styles += "bdiag";
183 else if (_filling == FdiagFilling) css_like_styles += "fdiag";
184
185
186 css_like_styles += ";color:";
187 if (_color == WhiteColor) css_like_styles += "white";
188 else if (_color == BlackColor) css_like_styles += "black";
189 else if (_color == GreenColor) css_like_styles += "green";
190 else if (_color == RedColor) css_like_styles += "red";
191 else if (_color == BlueColor) css_like_styles += "blue";
192 else if (_color == GrayColor) css_like_styles += "gray";
193 else if (_color == BrunColor) css_like_styles += "brun";
194 else if (_color == YellowColor) css_like_styles += "yellow";
195 else if (_color == CyanColor) css_like_styles += "cyan";
196 else if (_color == MagentaColor) css_like_styles += "magenta";
197 else if (_color == LightgrayColor) css_like_styles += "lightgray";
198 else if (_color == OrangeColor) css_like_styles += "orange";
199 else if (_color == PurpleColor) css_like_styles += "purple";
200 else if (_color == NoneColor) css_like_styles += "none";
201
202
203 qde.setAttribute("style", css_like_styles);
204 qde.setAttribute("antialias", _antialiased ? "true" : "false");
205 }
206
207
208 /**
209 * @brief CustomElementGraphicPart::stylesFromXml
210 * Read the style used by this, from a xml element.
211 * @param qde : QDomElement used to read the style
212 */
stylesFromXml(const QDomElement & qde)213 void CustomElementGraphicPart::stylesFromXml(const QDomElement &qde)
214 {
215 resetStyles();
216
217 //Get the list of pair style/value
218 QStringList styles = qde.attribute("style").split(";", QString::SkipEmptyParts);
219
220 //Check each pair of style
221 QRegExp rx("^\\s*([a-z-]+)\\s*:\\s*([a-z-]+)\\s*$");
222 foreach (QString style, styles)
223 {
224 if (!rx.exactMatch(style)) continue;
225 QString style_name = rx.cap(1);
226 QString style_value = rx.cap(2);
227 if (style_name == "line-style")
228 {
229 if (style_value == "dashed") _linestyle = DashedStyle;
230 else if (style_value == "dotted") _linestyle = DottedStyle;
231 else if (style_value == "dashdotted") _linestyle = DashdottedStyle;
232 else if (style_value == "normal") _linestyle = NormalStyle;
233 }
234 else if (style_name == "line-weight")
235 {
236 if (style_value == "none") _lineweight = NoneWeight;
237 else if (style_value == "thin") _lineweight = ThinWeight;
238 else if (style_value == "normal") _lineweight = NormalWeight;
239 else if (style_value == "hight") _lineweight = UltraWeight;
240 else if (style_value == "eleve") _lineweight = BigWeight;
241 }
242 else if (style_name == "filling")
243 {
244 if (style_value == "white") _filling = WhiteFilling;
245 else if (style_value == "black") _filling = BlackFilling;
246 else if (style_value == "red") _filling = RedFilling;
247 else if (style_value == "green") _filling = GreenFilling;
248 else if (style_value == "blue") _filling = BlueFilling;
249 else if (style_value == "gray") _filling = GrayFilling;
250 else if (style_value == "brun") _filling = BrunFilling;
251 else if (style_value == "yellow") _filling = YellowFilling;
252 else if (style_value == "cyan") _filling = CyanFilling;
253 else if (style_value == "magenta") _filling = MagentaFilling;
254 else if (style_value == "lightgray") _filling = LightgrayFilling;
255 else if (style_value == "orange") _filling = OrangeFilling;
256 else if (style_value == "purple") _filling = PurpleFilling;
257 else if (style_value == "hor") _filling = HorFilling;
258 else if (style_value == "ver") _filling = VerFilling;
259 else if (style_value == "bdiag") _filling = BdiagFilling;
260 else if (style_value == "fdiag") _filling = FdiagFilling;
261 else if (style_value == "none") _filling = NoneFilling;
262 }
263 else if (style_name == "color")
264 {
265 if (style_value == "black") _color = BlackColor;
266 else if (style_value == "white") _color = WhiteColor;
267 else if (style_value == "green") _color = GreenColor;
268 else if (style_value == "red") _color = RedColor;
269 else if (style_value == "blue") _color = BlueColor;
270 else if (style_value == "gray") _color = GrayColor;
271 else if (style_value == "brun") _color = BrunColor;
272 else if (style_value == "yellow") _color = YellowColor;
273 else if (style_value == "cyan") _color = CyanColor;
274 else if (style_value == "magenta") _color = MagentaColor;
275 else if (style_value == "lightgray") _color = LightgrayColor;
276 else if (style_value == "orange") _color = OrangeColor;
277 else if (style_value == "purple") _color = PurpleColor;
278 else if (style_value == "none") _color = NoneColor;
279 }
280 }
281 //Get antialiasing
282 _antialiased = qde.attribute("antialias") == "true";
283 }
284
285
286 /**
287 * @brief CustomElementGraphicPart::resetStyles
288 * Reset the curent style to default,
289 * same style of default constructor
290 */
resetStyles()291 void CustomElementGraphicPart::resetStyles()
292 {
293 _linestyle = NormalStyle;
294 _lineweight = NormalWeight;
295 _filling = NoneFilling;
296 _color = BlackColor;
297 _antialiased = false;
298 }
299
300 /**
301 * @brief CustomElementGraphicPart::applyStylesToQPainter
302 * Apply the current style to the QPainter
303 * @param painter
304 */
applyStylesToQPainter(QPainter & painter) const305 void CustomElementGraphicPart::applyStylesToQPainter(QPainter &painter) const
306 {
307 //Get the pen and brush
308 QPen pen = painter.pen();
309 QBrush brush = painter.brush();
310
311 //Apply pen style
312 if (_linestyle == DashedStyle) pen.setStyle(Qt::DashLine);
313 else if (_linestyle == DashdottedStyle) pen.setStyle(Qt::DashDotLine);
314 else if (_linestyle == DottedStyle) pen.setStyle(Qt::DotLine);
315 else if (_linestyle == NormalStyle) pen.setStyle(Qt::SolidLine);
316
317 //Apply pen width
318 if (_lineweight == NoneWeight) pen.setColor(QColor(0, 0, 0, 0));
319 else if (_lineweight == ThinWeight) pen.setWidth(0);
320 else if (_lineweight == NormalWeight) pen.setWidthF(1.0);
321 else if (_lineweight == UltraWeight) pen.setWidthF(2.0);
322 else if (_lineweight == BigWeight) pen.setWidthF(5.0);
323
324 //Apply brush color
325 if (_filling == NoneFilling) brush.setStyle(Qt::NoBrush);
326 else if (_filling == HorFilling) brush.setStyle(Qt::HorPattern);
327 else if (_filling == VerFilling) brush.setStyle(Qt::VerPattern);
328 else if (_filling == BdiagFilling) brush.setStyle(Qt::BDiagPattern);
329 else if (_filling == FdiagFilling) brush.setStyle(Qt::FDiagPattern);
330 else
331 {
332 brush.setStyle(Qt::SolidPattern);
333 if (_filling == BlackFilling) brush.setColor(Qt::black);
334 else if (_filling == WhiteFilling) brush.setColor(Qt::white);
335 else if (_filling == GreenFilling) brush.setColor(Qt::green);
336 else if (_filling == RedFilling) brush.setColor(Qt::red);
337 else if (_filling == BlueFilling) brush.setColor(Qt::blue);
338 else if (_filling == GrayFilling) brush.setColor(Qt::gray);
339 else if (_filling == BrunFilling) brush.setColor(QColor(97, 44, 0));
340 else if (_filling == YellowFilling) brush.setColor(Qt::yellow);
341 else if (_filling == CyanFilling) brush.setColor(Qt::cyan);
342 else if (_filling == MagentaFilling) brush.setColor(Qt::magenta);
343 else if (_filling == LightgrayFilling) brush.setColor(Qt::lightGray);
344 else if (_filling == OrangeFilling) brush.setColor(QColor(255, 128, 0));
345 else if (_filling == PurpleFilling) brush.setColor(QColor(136, 28, 168));
346 }
347
348 //Apply pen color
349 if (_color == WhiteColor) pen.setColor(QColor(255, 255, 255, pen.color().alpha()));
350 else if (_color == BlackColor) pen.setColor(QColor( 0, 0, 0, pen.color().alpha()));
351 else if (_color == GreenColor) pen.setColor(QColor(Qt::green));
352 else if (_color == RedColor) pen.setColor(QColor(Qt::red));
353 else if (_color == BlueColor) pen.setColor(QColor(Qt::blue));
354 else if (_color == GrayColor) pen.setColor(QColor(Qt::gray));
355 else if (_color == BrunColor) pen.setColor(QColor(97, 44, 0));
356 else if (_color == YellowColor) pen.setColor(QColor(Qt::yellow));
357 else if (_color == CyanColor) pen.setColor(Qt::cyan);
358 else if (_color == MagentaColor) pen.setColor(Qt::magenta);
359 else if (_color == LightgrayColor) pen.setColor(Qt::lightGray);
360 else if (_color == OrangeColor) pen.setColor(QColor(255, 128, 0));
361 else if (_color == PurpleColor) pen.setColor(QColor(136, 28, 168));
362 else if (_color == NoneColor) pen.setBrush(Qt::transparent);
363
364 //Apply antialiasing
365 painter.setRenderHint(QPainter::Antialiasing, _antialiased);
366 painter.setRenderHint(QPainter::TextAntialiasing, _antialiased);
367 painter.setRenderHint(QPainter::SmoothPixmapTransform, _antialiased);
368
369 painter.setPen(pen);
370 painter.setBrush(brush);
371 }
372
373 /**
374 * @brief CustomElementGraphicPart::drawShadowShape
375 * Draw a transparent blue shadow arround the shape of this item.
376 * The QPainterPathStroker used to draw shadows have a width of SHADOWS_HEIGHT
377 * Be carefull if penWeight of this item is to 0 the outline of strock is bigger of 0.5
378 * @param painter : painter to use for draw this shadows
379 */
drawShadowShape(QPainter * painter)380 void CustomElementGraphicPart::drawShadowShape(QPainter *painter)
381 {
382 //@FIXME if pen weight is 0, the strock outline is SHADOWS_HEIGHT/2 + 0.5
383 //may be because shape have no line weight
384 QPainterPathStroker strock;
385 strock.setWidth(SHADOWS_HEIGHT);
386 strock.setJoinStyle(Qt::RoundJoin);
387
388 painter->save();
389 QColor color(Qt::darkBlue);
390 color.setAlpha(50);
391 painter -> setBrush (QBrush (color));
392 painter -> setPen (Qt::NoPen);
393 painter -> drawPath (strock.createStroke(shadowShape()));
394 painter -> restore ();
395 }
396
397 /**
398 * @brief CustomElementGraphicPart::itemChange
399 * Reimplemented from QGraphicsObject.
400 * If the item position change call updateCurrentPartEditor()
401 * the change is always send to QGraphicsObject
402 * @param change
403 * @param value
404 * @return the returned value of QGraphicsObject::itemChange
405 */
itemChange(GraphicsItemChange change,const QVariant & value)406 QVariant CustomElementGraphicPart::itemChange(GraphicsItemChange change, const QVariant &value)
407 {
408 if (scene())
409 if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged)
410 updateCurrentPartEditor();
411
412 return(QGraphicsObject::itemChange(change, value));
413 }
414
415 /**
416 * @brief CustomElementGraphicPart::hoverEnterEvent
417 * Reimplemented from QGraphicsObject.
418 * Set m_hovered to true
419 * @param event
420 */
hoverEnterEvent(QGraphicsSceneHoverEvent * event)421 void CustomElementGraphicPart::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
422 {
423 m_hovered = true;
424 QGraphicsObject::hoverEnterEvent(event);
425 }
426
427 /**
428 * @brief CustomElementGraphicPart::hoverLeaveEvent
429 * Reimplemented from QGraphicsObject.
430 * Set m_hovered to false
431 * @param event
432 */
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)433 void CustomElementGraphicPart::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
434 {
435 m_hovered = false;
436 QGraphicsObject::hoverLeaveEvent(event);
437 }
438
mousePressEvent(QGraphicsSceneMouseEvent * event)439 void CustomElementGraphicPart::mousePressEvent(QGraphicsSceneMouseEvent *event)
440 {
441 if(event->button() == Qt::LeftButton)
442 m_origin_pos = this->pos();
443
444 QGraphicsObject::mousePressEvent(event);
445 }
446
mouseMoveEvent(QGraphicsSceneMouseEvent * event)447 void CustomElementGraphicPart::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
448 {
449 if((event->buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable))
450 {
451 QPointF pos = event->scenePos() + (m_origin_pos - event->buttonDownScenePos(Qt::LeftButton));
452 event->modifiers() == Qt::ControlModifier ? setPos(pos) : setPos(elementScene()->snapToGrid(pos));
453 }
454 else
455 QGraphicsObject::mouseMoveEvent(event);
456 }
457
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)458 void CustomElementGraphicPart::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
459 {
460 if((event->button() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable) && m_origin_pos != pos())
461 {
462 QPropertyUndoCommand *undo = new QPropertyUndoCommand(this, "pos", QVariant(m_origin_pos), QVariant(pos()));
463 undo->setText(tr("Déplacer une primitive"));
464 undo->enableAnimation();
465 elementScene()->undoStack().push(undo);
466 }
467
468 QGraphicsObject::mouseReleaseEvent(event);
469 }
470