1 #include "basegraphicitem.h"
2
3 #include "basegraphicitem.h"
4 #include "editorscene.h"
5
6 #include <QPainter>
7 #include <QMenu>
8 #include <QGraphicsScene>
9 #include <QGraphicsView>
10 #include <QGraphicsSceneMouseEvent>
11 #include <QStyleOptionGraphicsItem>
12 #include <QString>
13 #include <QDebug>
14 #include <math.h>
15
16
17
18 QString itemTypeStr[NUMITEMTYPES]=
19 {
20 "Base",
21 "Rectangle",
22 "Ellipse",
23 "Image",
24 "Line",
25 "Text",
26 "Replay",
27 "Border"
28 };
29
30 const qreal penWidthZero = qreal(0.00000001);
31
qt_graphicsItem_shapeFromPath(const QPainterPath & path,const QPen & pen) const32 QPainterPath graphItemBase::qt_graphicsItem_shapeFromPath(const QPainterPath &path, const QPen &pen) const
33 {
34 // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0
35 // if we pass a value of 0.0 to QPainterPathStroker::setWidth()
36
37
38 if (path == QPainterPath()) return path;
39 QPainterPathStroker ps;
40 ps.setCapStyle(pen.capStyle());
41 if (pen.widthF() <= 0.0) ps.setWidth(penWidthZero);
42 else ps.setWidth(pen.widthF());
43 ps.setJoinStyle(pen.joinStyle());
44 ps.setMiterLimit(pen.miterLimit());
45 QPainterPath p = ps.createStroke(path);
46 p.addPath(path);
47 return p;
48 }
49
50
graphItemBase(QMenu * cntxtMenu)51 graphItemBase::graphItemBase(QMenu *cntxtMenu)
52 {
53 param.rct = QRectF(0, 0, 100, 100);
54 m_ResizeHandles.fill(QRect(0, 0, 0, 0), 8); //initially empty handles
55 m_MousePressed = false;
56 m_IsResizing = false;
57 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges | QGraphicsItem::ItemIsSelectable);
58 param.locked=false;
59 param.modified=true;
60 param.menu=cntxtMenu;
61 param.pen.setJoinStyle(Qt::MiterJoin);
62 setAcceptHoverEvents(true);
63 selected=false;
64 markedForDeletion=false;
65
66 }
67
~graphItemBase()68 graphItemBase::~graphItemBase()
69 {
70
71 prepareGeometryChange();
72 }
73
shape() const74 QPainterPath graphItemBase::shape() const
75 {
76 QPainterPath path;
77 path.addRect(param.rct.adjusted(-2*HSIZE, -2*HSIZE, 2*HSIZE, 2*HSIZE));
78 return qt_graphicsItem_shapeFromPath(path,pen());
79 }
80
boundingRect() const81 QRectF graphItemBase::boundingRect() const
82 {
83 return shape().boundingRect();
84 }
85
86
load(QDataStream & str)87 void graphItemBase::load(QDataStream &str)
88 {
89 // str << type(); this item is already read by the loader
90 QTransform f;
91 QPointF p;
92 QRectF r;
93 QColor c;
94 QPen pn;
95 QBrush br;
96 QString t;
97 QFont fnt;
98 qreal z;
99 str >> param.rotation;
100 str >> param.hShear;
101 str >> param.vShear;
102 str >> z;
103 setZValue(z);
104 param.zValue=z;
105 str >> p;
106 setPos(p);
107 param.position=p;
108 str >> r;
109 setRect(r);
110 str >> c;
111 param.fillColor=c;
112 setBrush(c);
113 str >> pn;
114 setPen(pn);
115 str >> br;
116 QAbstractGraphicsShapeItem::setBrush(br);
117 str >> param.locked;
118 str >>param.im;
119 str >>t;
120 setText(t);
121 str >>fnt;
122 setFont(fnt);
123 str >> param.line;
124 param.gradient.load(str);
125 setTransform ();
126 getParam();
127 }
128
save(QDataStream & str)129 void graphItemBase::save(QDataStream &str)
130 {
131 str << type();
132 str << param.rotation;
133 str << param.hShear;
134 str << param.vShear;
135 str << zValue();
136 str << pos();
137 str << rect();
138 str << param.fillColor;
139 str << pen();
140 str << brush();
141 str << param.locked;
142 str << param.im;
143 str << param.txt;
144 str << param.font;
145 str << param.line;
146 param.gradient.save(str);
147 }
148
setTransform(int rot,double hs,double vs)149 void graphItemBase::setTransform(int rot, double hs, double vs)
150 {
151 param.rotation=rot;
152 param.hShear=hs;
153 param.vShear=vs;
154 setTransform ();
155 }
156
setTransform()157 void graphItemBase::setTransform ()
158 {
159 QTransform tx;
160 tx.translate(rect().x()+rect().width()/2,rect().y()+rect().height()/2);
161 tx.shear(param.hShear,param.vShear);
162 tx.rotate(param.rotation);
163 tx.translate(-rect().x()-rect().width()/2,-rect().y()-rect().height()/2);
164 QGraphicsItem::setTransform(tx,false);
165 update();
166 }
167
getParam()168 sitemParam graphItemBase::getParam()
169 {
170 param.zValue=zValue();
171 param.type=type();
172 param.pen=pen();
173 param.brush=brush();
174 param.position=pos();
175 return param;
176 }
177
setParam(sitemParam sp)178 void graphItemBase::setParam(sitemParam sp)
179 {
180 setPen(sp.pen);
181 setBrush(sp.fillColor);
182 setFont(sp.font);
183 // are used dynamically, no need to setup
184 param.txt=sp.txt;
185 param.rotation=sp.rotation;
186 param.hShear=sp.hShear;
187 param.vShear=sp.vShear;
188 setTransform (param.rotation,param.hShear,param.vShear);
189 param.im=sp.im;
190 param.gradient=sp.gradient;
191 param.rct=sp.rct;
192 param.locked=sp.locked;
193 param.line=sp.line;
194 param.modified=true;
195 param.fillColor=sp.fillColor;
196 param.menu=sp.menu;
197 }
198
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)199 void graphItemBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
200 {
201 Q_UNUSED(widget)
202 QPointF center;
203 QRectF br;
204 double scale;
205 if (option->state & QStyle::State_Selected)
206 {
207 selected=true;
208 }
209 else
210 {
211 selected=false;
212 }
213 if(!scene()) return;
214 if(scene()->views().isEmpty())
215 {
216 scale=1;
217 }
218 else
219 {
220 scale = scene()->views().at(0)->transform().m11(); //get current scale factor
221 }
222
223
224 float rectSize = RSIZE/ scale; //this is to maintain same size for resize handle rects
225 QRectF handles(0, 0, rectSize, rectSize);
226 br=boundingRect();
227 if(selected)
228 {
229
230 painter->fillRect(br, QBrush(QColor(128, 128, 255, 128)));
231 if(param.type!=LINE)
232 {
233
234 //resize handles
235 handles.moveTopLeft(br.topLeft()); //TopLeft
236 m_ResizeHandles.replace(0, handles);
237
238 handles.moveTopRight(br.topRight()); //TopRight
239 m_ResizeHandles.replace(2, handles);
240
241 handles.moveBottomRight(br.bottomRight()); //BottomRight
242 m_ResizeHandles.replace(4, handles);
243
244 handles.moveBottomLeft(br.bottomLeft()); //BottomLeft
245 m_ResizeHandles.replace(6, handles);
246
247 center= QPointF(br.center().x(), br.top()+HSIZE); //Top
248 handles.moveCenter(center);
249 m_ResizeHandles.replace(1, handles);
250
251 center = QPointF(br.center().x(), br.bottom()-HSIZE); //Bottom
252 handles.moveCenter(center);
253 m_ResizeHandles.replace(5, handles);
254 }
255
256 center = QPointF(br.right()-HSIZE, br.center().y()); //Right
257 handles.moveCenter(center);
258 m_ResizeHandles.replace(3, handles);
259
260 center = QPointF(br.left()+HSIZE, br.center().y()); //Left
261 handles.moveCenter(center);
262 m_ResizeHandles.replace(7, handles);
263
264 //arrow line
265 float size = br.width();
266 m_RotateLine.setP1(m_ResizeHandles.at(7).center());
267 m_RotateLine.setP2(QPointF(m_ResizeHandles.at(7).center().x() + (size / 4), m_ResizeHandles.at(7).center().y()));
268
269 //angle handle
270 qreal arrowSize = ARROWSIZE / scale;
271 QPointF point = m_RotateLine.p2();
272 double angle = ::acos(m_RotateLine.dx() / m_RotateLine.length());
273 if (m_RotateLine.dy() >= 0)
274 angle = (2.0 * M_PI) - angle;
275 QPointF destArrowP1 = point + QPointF(sin(angle - M_PI / 3.0) * arrowSize, cos(angle - M_PI / 3.0) * arrowSize);
276 QPointF destArrowP2 = point + QPointF(sin(angle - M_PI + M_PI / 3.0) * arrowSize , cos(angle - M_PI + M_PI / 3.0) * arrowSize);
277 // qreal points[] = { point.x(), point.y(), destArrowP1.x(), destArrowP1.y(), destArrowP2.x(), destArrowP2.y() };
278 m_AngleHandle = QPolygonF() << m_RotateLine.p2() << destArrowP1 << destArrowP2;
279 }
280 if(param.gradient.type!=sgradientParam::NONE && (param.type==ELLIPSE|| param.type==RECTANGLE))
281 {
282 setBrush(param.gradient,rect());
283 }
284 else
285 {
286 setBrush(param.fillColor);
287 }
288 painter->setBrush(brush());
289 painter->setPen(pen());
290 drawItem(painter);
291
292 QPen pens;
293 pens.setCosmetic(true); //to maintain same width of pen across zoom levels
294
295 painter->setPen(pens);
296
297 if(selected)
298 {
299 //draw arrow handle
300 QPen arrowPen;
301 arrowPen.setCosmetic(true);
302 arrowPen.setColor(Qt::yellow);
303 painter->setBrush(Qt::black);
304 painter->setPen(arrowPen);
305 painter->drawLine(m_RotateLine);
306 painter->drawPolygon(m_AngleHandle);
307 if(param.type!=TEXT)
308 {
309 //draw resize handles
310 pens.setColor(QColor(255, 255, 255));
311 painter->setBrush(Qt::black);
312 painter->setPen(pens);
313 painter->drawRects(m_ResizeHandles);
314 }
315 }
316 }
317
drawBorder(QPainter * painter)318 void graphItemBase::drawBorder(QPainter *painter)
319 {
320 QPen lpen(pen());
321 qreal pad=lpen.widthF()/2;
322 painter->setBrush(Qt::NoBrush);
323 lpen.setJoinStyle(Qt::MiterJoin);
324 painter->setPen(lpen);
325 painter->drawRect(param.rct.adjusted(pad,pad,-pad,-pad));
326 }
327
328
mousePressEvent(QGraphicsSceneMouseEvent * event)329 void graphItemBase::mousePressEvent(QGraphicsSceneMouseEvent *event)
330 {
331
332 m_MousePressed = true;
333 m_IsResizing = mousePosOnHandles(event->scenePos()); //to check event on corners or not
334 if (m_IsResizing)
335 {
336 m_ActualRect = param.rct;
337 }
338 QGraphicsItem::mousePressEvent(event);
339 }
340
mouseMoveEvent(QGraphicsSceneMouseEvent * event)341 void graphItemBase::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
342 {
343 if(param.locked) return;
344
345 QRectF m_BoundingRect(boundingRect());
346
347 bool containsAll=false;
348 bool containsNoText=false;
349 bool containsNoLineNoText=false;
350 bool changed=false;
351
352 QRectF escene=scene()->sceneRect().adjusted(-2*HSIZE,-2*HSIZE,2*HSIZE,2*HSIZE);
353 if (escene.contains(event->scenePos()))
354 {
355 containsAll=true;
356 // containsNoLine=(param.type!=LINE);
357 containsNoLineNoText=((param.type!=LINE) && (param.type!=TEXT));
358 containsNoText=(param.type!=TEXT);
359 }
360 if (m_IsResizing)
361 {
362 QPointF ptMouseMoveInItemsCoord = mapFromScene(event->scenePos());
363
364 if(m_ResizeCorner==TOP_LEFT && containsNoLineNoText)
365 {
366 changed=true;
367 m_BoundingRect.setTopLeft(ptMouseMoveInItemsCoord);
368 }
369
370
371 else if(m_ResizeCorner==TOP_RIGHT && containsNoLineNoText)
372 {
373 changed=true;
374 m_BoundingRect.setTopRight(ptMouseMoveInItemsCoord);
375 }
376
377
378 else if(m_ResizeCorner==BOTTOM_LEFT && containsNoLineNoText)
379 {
380 changed=true;
381 m_BoundingRect.setBottomLeft(ptMouseMoveInItemsCoord);
382 }
383
384
385 else if(m_ResizeCorner==BOTTOM_RIGHT && containsNoLineNoText)
386 {
387 changed=true;
388 m_BoundingRect.setBottomRight(ptMouseMoveInItemsCoord);
389 }
390
391 else if(m_ResizeCorner==TOP && containsNoLineNoText)
392 {
393 changed=true;
394 m_BoundingRect.setTop(ptMouseMoveInItemsCoord.y());
395
396 }
397
398 else if(m_ResizeCorner==BOTTOM && containsNoLineNoText)
399 {
400 changed=true;
401 m_BoundingRect.setBottom(ptMouseMoveInItemsCoord.y());
402
403 }
404
405 else if(m_ResizeCorner==LEFT && containsNoText)
406 {
407 changed=true;
408 m_BoundingRect.setLeft(ptMouseMoveInItemsCoord.x());
409 }
410
411 else if(m_ResizeCorner==RIGHT && containsNoText)
412 {
413 changed=true;
414 m_BoundingRect.setRight(ptMouseMoveInItemsCoord.x());
415 }
416
417 else if(m_ResizeCorner==ROTATE && containsAll)
418 {
419
420 changed=true;
421 QLineF line(m_BoundingRect.center(), ptMouseMoveInItemsCoord);
422 double rotations = line.angleTo(QLineF(0, 0, 1, 0));
423 if (line.dy() <= 0)
424 {
425 rotations = 180.0 - rotations;
426 }
427 else
428 {
429 rotations = rotations - 180.0;
430 }
431 m_Angle = rotations;
432 m_BoundingRect = m_BoundingRect.normalized();
433 setTransformOriginPoint(m_BoundingRect.center());
434 setRotation(rotation() + m_Angle);
435 param.rotation=round(rotation());
436 }
437 if(changed)
438 {
439 if(m_BoundingRect.width()<4*HSIZE) m_BoundingRect.setWidth(4*HSIZE);
440 if(m_BoundingRect.height()<4*HSIZE) m_BoundingRect.setHeight(4*HSIZE);
441 param.rct = m_BoundingRect.adjusted(2*HSIZE,2*HSIZE, -2*HSIZE, -2*HSIZE);
442 qreal penw=pen().widthF()/2;
443 param.rct = param.rct.adjusted(penw,penw,-penw,-penw);
444 prepareGeometryChange();
445 update();
446 }
447
448 }
449 if(!changed)
450 {
451 prepareGeometryChange();
452 update();
453 QGraphicsItem::mouseMoveEvent(event);
454 }
455 }
456
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)457 void graphItemBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
458 {
459 QRectF m_BoundingRect(param.rct.adjusted(-2*HSIZE, -2*HSIZE, 2*HSIZE, 2*HSIZE));
460 m_MousePressed = false;
461 m_IsResizing = false;
462 if (m_ActualRect != m_BoundingRect)
463 { // Rotating won't trigger this, only resizing.
464 QPointF oldScenePos = scenePos();
465 setTransformOriginPoint(m_BoundingRect.center());
466 QPointF newScenePos = scenePos();
467 QPointF oldPos = pos();
468 setPos(oldPos.x() + (oldScenePos.x() - newScenePos.x()), oldPos.y() + (oldScenePos.y() - newScenePos.y()));
469 }
470 prepareGeometryChange();
471 update();
472 QGraphicsItem::mouseReleaseEvent(event);
473 }
474
hoverEnterEvent(QGraphicsSceneHoverEvent *)475 void graphItemBase::hoverEnterEvent(QGraphicsSceneHoverEvent *)
476 {
477 }
478
hoverLeaveEvent(QGraphicsSceneHoverEvent *)479 void graphItemBase::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
480 {
481
482 }
483
hoverMoveEvent(QGraphicsSceneHoverEvent *)484 void graphItemBase::hoverMoveEvent(QGraphicsSceneHoverEvent *)
485 {
486 if(param.type==SBORDER) return;
487 if(param.locked)
488 {
489 setCursor(Qt::ForbiddenCursor);
490 }
491 else
492 {
493 setCursor(Qt::ArrowCursor);
494 }
495 }
496
mouseDoubleClickEvent(QGraphicsSceneMouseEvent *)497 void graphItemBase::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *)
498 {
499
500 }
501
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)502 void graphItemBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
503 {
504 if(param.type==SBORDER) return;
505 setSelected(true);
506 param.menu->exec(event->screenPos());
507 }
508
509
mousePosOnHandles(QPointF pos)510 bool graphItemBase::mousePosOnHandles(QPointF pos)
511 {
512 bool resizable = false;
513 int rem4Index = 8;
514
515 if(param.type!=LINE)
516 {
517 if (mapToScene(m_ResizeHandles[(0 + rem4Index) % 8]).containsPoint(pos, Qt::WindingFill))
518 {
519 m_ResizeCorner = TOP_LEFT;
520 resizable = true;
521 }
522 else if (mapToScene(m_ResizeHandles[(1 + rem4Index) % 8]).containsPoint(pos, Qt::WindingFill))
523 {
524 m_ResizeCorner = TOP;
525 resizable = true;
526 }
527 else if (mapToScene(m_ResizeHandles[(2 + rem4Index) % 8]).containsPoint(pos, Qt::WindingFill))
528 {
529 m_ResizeCorner = TOP_RIGHT;
530 resizable = true;
531 }
532
533 else if (mapToScene(m_ResizeHandles[(4 + rem4Index) % 8]).containsPoint(pos, Qt::WindingFill))
534 {
535 m_ResizeCorner = BOTTOM_RIGHT;
536 resizable = true;
537 }
538 else if (mapToScene(m_ResizeHandles[(5 + rem4Index) % 8]).containsPoint(pos, Qt::WindingFill))
539 {
540 m_ResizeCorner = BOTTOM;
541 resizable = true;
542 }
543 else if (mapToScene(m_ResizeHandles[(6 + rem4Index) % 8]).containsPoint(pos, Qt::WindingFill))
544 {
545 m_ResizeCorner = BOTTOM_LEFT;
546 resizable = true;
547 }
548 }
549 if(param.type!=TEXT)
550 {
551 if (mapToScene(m_ResizeHandles[(3 + rem4Index) % 8]).containsPoint(pos, Qt::WindingFill))
552 {
553 m_ResizeCorner = RIGHT;
554 resizable = true;
555 }
556 else if (mapToScene(m_ResizeHandles[(7 + rem4Index) % 8]).containsPoint(pos, Qt::WindingFill))
557 {
558 m_ResizeCorner = LEFT;
559 resizable = true;
560 }
561 }
562 if (mapToScene(m_AngleHandle).containsPoint(pos, Qt::WindingFill))
563 {
564 m_ResizeCorner = ROTATE;
565 resizable = true;
566 }
567 return resizable;
568 }
569