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