1/***************************************************************************
2 kimearea.cpp - description
3 -------------------
4 begin : Thu Jun 14 2001
5 copyright : (C) 2001 by Jan Schaefer
6 email : janschaefer@users.sourceforge.net
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include <QPolygon>
19
20#include <qbitmap.h>
21#include <qpainter.h>
22#include <qpixmap.h>
23#include <qimage.h>
24#include <qpen.h>
25#include <qbrush.h>
26#include <qpalette.h>
27#include <qcolor.h>
28
29#include <kdebug.h>
30
31#include "kimearea.h"
32#include "kimecommon.h"
33
34
35// The size of Selection Points
36
37SelectionPoint::SelectionPoint(QPoint p, QCursor c)
38{
39 point = p;
40 state = Normal;
41 _cursor = c;
42}
43
44SelectionPoint::~SelectionPoint() {
45}
46
47void SelectionPoint::setState(SelectionPoint::State s) {
48 state = s;
49}
50
51SelectionPoint::State SelectionPoint::getState() const {
52 return state;
53}
54
55void SelectionPoint::setPoint(QPoint p) {
56 point = p;
57}
58
59void SelectionPoint::translate(int dx, int dy) {
60 point += QPoint(dx,dy);
61}
62
63
64QPoint SelectionPoint::getPoint() const {
65 return point;
66}
67
68QRect SelectionPoint::getRect() const {
69 QRect r(0,0,SELSIZE,SELSIZE);
70 r.moveCenter(point);
71 return r;
72}
73
74QCursor SelectionPoint::cursor() {
75 return _cursor;
76}
77
78void SelectionPoint::setCursor(QCursor c) {
79 _cursor = c;
80}
81
82
83void SelectionPoint::draw(QPainter* p, double scalex) {
84 QColor brushColor;
85
86 switch (state) {
87 case Normal:
88 brushColor = Qt::white;
89 break;
90 case HighLighted:
91 brushColor = Qt::green;
92 break;
93 case AboutToRemove:
94 brushColor = Qt::red;
95 break;
96 case Inactive:
97 brushColor = Qt::gray;
98 break;
99 }
100
101 int d = 1;
102 if (scalex > 2)
103 d = 0;
104
105 QPoint scaledCenter((int)(point.x()*scalex),
106 (int)(point.y()*scalex));
107
108 if (state == HighLighted || state == AboutToRemove) {
109 QRect r2(0,0,SELSIZE+4,SELSIZE+4);
110
111 r2.moveCenter(scaledCenter);
112 QColor color(brushColor);
113 color.setAlpha(100);
114 p->setPen(QPen(color,4,Qt::SolidLine));
115 p->setBrush(Qt::NoBrush);
116 p->drawRect(r2);
117
118 }
119
120 // brushColor.setAlpha(230);
121 brushColor.setAlpha(200);
122 p->setBrush(QBrush(brushColor,Qt::SolidPattern));
123
124 QColor penColor = Qt::black;
125 penColor.setAlpha(120);
126 QPen pen(penColor, 2, Qt::SolidLine);
127
128 QRect r(0,0,SELSIZE,SELSIZE);
129 r.moveCenter( scaledCenter );
130
131 p->setPen(pen);
132 p->drawRect(r);
133
134
135}
136
137
138bool Area::highlightArea;
139bool Area::showAlt;
140
141
142Area::Area()
143{
144 _finished=false;
145 _isSelected=false;
146 _name=i18n("noname");
147 _listViewItem=0L;
148 currentHighlighted=-1;
149 _type=Area::None;
150}
151
152Area* Area::clone() const
153{
154 Area* areaClone = new Area();
155 areaClone->setArea( *this );
156 return areaClone;
157}
158
159QPolygon Area::coords() const {
160 return _coords;
161}
162
163QString Area::getHTMLAttributes() const
164{
165 QString retStr="";
166
167 AttributeIterator it = attributeIterator();
168 while (it.hasNext())
169 {
170 it.next();
171 retStr+=it.key()+"=\""+it.value()+"\" ";
172 }
173
174 return retStr;
175}
176
177void Area::resetSelectionPointState() {
178 setSelectionPointStates(SelectionPoint::Normal);
179}
180
181void Area::setSelectionPointStates(SelectionPoint::State st) {
182 for (int i=0;i<_selectionPoints.size();i++) {
183 _selectionPoints.at(i)->setState(st);
184 }
185}
186
187
188
189
190void Area::deleteSelectionPoints() {
191 for (int i=0;i<_selectionPoints.size();i++) {
192 delete _selectionPoints.at(i);
193 }
194 _selectionPoints.clear();
195}
196
197Area::~Area() {
198 deleteSelectionPoints();
199}
200
201bool Area::contains(const QPoint &) const {
202 return false;
203}
204
205QString Area::getHTMLCode() const {
206 return "";
207}
208
209QString Area::attribute(const QString & name) const
210{
211 return _attributes[name.toLower()];
212}
213
214void Area::setAttribute(const QString & name, const QString & value)
215{
216 _attributes.insert(name.toLower(), value);
217 if (value.isEmpty())
218 _attributes.remove(name.toLower());
219}
220
221AttributeIterator Area::attributeIterator() const
222{
223 return AttributeIterator(_attributes);
224}
225
226bool Area::setCoords(const QString &) {
227 return true;
228}
229
230void Area::moveSelectionPoint(SelectionPoint*, const QPoint &)
231{}
232
233// Default implementation; is specified by subclasses
234QString Area::coordsToString() const
235{
236 return "";
237}
238
239
240Area::ShapeType Area::type() const {
241 return _type;
242}
243
244void Area::setArea(const Area & copy)
245{
246 deleteSelectionPoints();
247 _coords.clear();
248 _coords += copy.coords();
249 currentHighlighted=-1;
250
251 SelectionPointList points = copy.selectionPoints();
252 for (int i=0; i<points.size(); i++) {
253 SelectionPoint* np =
254 new SelectionPoint(points.at(i)->getPoint(),points.at(i)->cursor());
255 _selectionPoints.append(np);
256 }
257
258 _finished=copy.finished();
259 _isSelected=copy.isSelected();
260 _rect = copy.rect();
261
262 AttributeIterator it = copy.attributeIterator();
263 while (it.hasNext()) {
264 it.next();
265 setAttribute(it.key(),it.value());
266 }
267
268 setMoving(copy.isMoving());
269}
270
271void Area::setFinished(bool b, bool ) {
272 _finished=b;
273}
274
275
276void Area::setListViewItem(QTreeWidgetItem* item) {
277 _listViewItem=item;
278}
279
280void Area::deleteListViewItem()
281{
282 delete _listViewItem;
283 _listViewItem = 0L;
284}
285
286
287void Area::setRect(const QRect & r)
288{
289 _rect=r;
290 updateSelectionPoints();
291}
292
293QRect Area::rect() const {
294 return _rect;
295}
296
297void Area::setMoving(bool b) {
298 _isMoving=b;
299}
300
301
302void Area::moveBy(int dx, int dy) {
303 _rect.translate(dx,dy);
304 _coords.translate(dx,dy);
305
306 for (int i=0;i < _selectionPoints.size(); i++) {
307 _selectionPoints.at(i)->translate(dx,dy);
308 }
309}
310
311
312void Area::moveTo(int x, int y) {
313 int dx = x-rect().left();
314 int dy = y-rect().top();
315 moveBy(dx,dy);
316}
317
318int Area::countSelectionPoints() const
319{
320 return selectionPoints().size();
321}
322
323int Area::addCoord(const QPoint & p)
324{
325 _coords.resize(_coords.size()+1);
326 _coords.setPoint(_coords.size()-1,p);
327 _selectionPoints.append(new SelectionPoint(p,QCursor(Qt::PointingHandCursor)));
328 setRect(_coords.boundingRect());
329
330 return _coords.size()-1;
331}
332
333void Area::insertCoord(int pos, const QPoint & p)
334{
335 _coords.resize(_coords.size()+1);
336
337
338 for (int i=_coords.size()-1;i>pos;i--) {
339 _coords.setPoint(i,_coords.point(i-1));
340 }
341 _coords.setPoint(pos, p);
342
343 _selectionPoints.insert(pos,new SelectionPoint(p,QCursor(Qt::PointingHandCursor)));
344 setRect(_coords.boundingRect());
345}
346
347void Area::removeCoord(int pos) {
348
349 int count =_coords.size();
350
351 if (count<4){
352 kDebug() << "Danger : trying to remove coordinate from Area with less than 4 coordinates !";
353 return;
354 }
355
356 for (int i=pos;i<(count-1);i++)
357 _coords.setPoint(i, _coords.point(i+1));
358
359 _coords.resize(count-1);
360 delete _selectionPoints.takeAt(pos);
361 setRect(_coords.boundingRect());
362}
363
364bool Area::removeSelectionPoint(SelectionPoint * p)
365{
366 if (_selectionPoints.contains(p))
367 {
368 removeCoord(_selectionPoints.indexOf(p));
369 return true;
370 }
371
372 return false;
373}
374
375
376void Area::moveCoord(int pos, const QPoint & p) {
377 _coords.setPoint(pos,p);
378 _selectionPoints.at(pos)->setPoint(p);
379 setRect(_coords.boundingRect());
380}
381
382void Area::setSelected(bool b)
383{
384 _isSelected=b;
385 if (_listViewItem) {
386 _listViewItem->setSelected(b);
387 }
388}
389
390void Area::highlightSelectionPoint(int number){
391 currentHighlighted=number;
392}
393
394QRect Area::selectionRect() const {
395 QRect r = rect();
396 r.translate(-SELSIZE*2,-SELSIZE*2);
397 r.setSize(r.size()+QSize(SELSIZE*4,SELSIZE*4));
398
399 return r;
400}
401
402void Area::setPenAndBrush(QPainter* p) {
403 QBrush brush(Qt::NoBrush);
404 if (highlightArea) {
405 QColor back = Qt::white;
406 back.setAlpha(80);
407 brush = QBrush(back,Qt::SolidPattern);
408 }
409
410 p->setBrush(brush);
411
412 QColor front = Qt::white;
413 front.setAlpha(200);
414 p->setPen(QPen(front,1));
415}
416
417
418void Area::drawAlt(QPainter* p)
419{
420 double x,y;
421
422 double scalex = p->matrix().m11();
423// double scaley = p.matrix().m12();
424
425 QMatrix oldMatrix = p->matrix();
426
427 p->setMatrix(QMatrix(1,oldMatrix.m12(), oldMatrix.m21(), 1, oldMatrix.dx(), oldMatrix.dy() ));
428
429 x = (rect().x()+rect().width()/2)*scalex;
430 y = (rect().y()+rect().height()/2)*scalex;
431
432 QFontMetrics metrics = p->fontMetrics();
433
434 int w = metrics.width(attribute("alt"));
435 x -= w/2;
436 y += metrics.height()/4;
437
438
439
440 if (highlightArea) {
441 p->setPen(Qt::black);
442 } else {
443 p->setPen(QPen(QColor("white"),1));
444 }
445
446 p->drawText(myround(x),myround(y),attribute("alt"));
447
448 p->setMatrix(oldMatrix);
449}
450
451void Area::draw(QPainter * p)
452{
453
454 // Only draw the selection points at base class
455 // the rest is done in the derived classes
456 if (_isSelected) {
457 // We do not want to have the selection points
458 // scaled, so calculate the unscaled version
459 double scalex = p->matrix().m11();
460 QMatrix oldMatrix = p->matrix();
461 p->setMatrix(QMatrix(1,oldMatrix.m12(),
462 oldMatrix.m21(), 1,
463 oldMatrix.dx(),
464 oldMatrix.dy() ));
465
466 for (int i=0; i<_selectionPoints.size(); i++) {
467 _selectionPoints.at(i)->draw(p,scalex);
468 }
469 p->setMatrix(oldMatrix);
470 }
471
472 if (showAlt) {
473 drawAlt(p);
474 }
475
476}
477
478SelectionPoint* Area::onSelectionPoint(const QPoint & p, double zoom) const
479{
480
481 for (int i=0; i<_selectionPoints.size(); i++) {
482 SelectionPoint* sp = _selectionPoints.at(i);
483
484 QRect r = sp->getRect();
485
486 r.moveCenter(sp->getPoint()*zoom);
487
488 if (r.contains(p))
489 {
490 return sp;
491 }
492 }
493
494 return 0L;
495}
496
497
498
499
500/**
501 * returns only the part of the image which is
502 * covered by the area
503 */
504QPixmap Area::cutOut(const QImage & image)
505{
506 if ( 0>=rect().width() ||
507 0>=rect().height() ||
508 !rect().intersects(image.rect()) )
509 {
510 QPixmap dummyPix(10,10);
511 dummyPix.fill();
512 return dummyPix;
513 }
514
515 // Get the mask from the subclasses
516 QBitmap mask=getMask();
517
518 // The rectangle which is part of the image
519 QRect partOfImage=rect();
520 QRect partOfMask(0,0,mask.width(),mask.height());
521
522
523 // If the area is outside of the image make the
524 // preview smaller
525 if ( (rect().x()+rect().width()) > image.width() ) {
526 partOfImage.setWidth( image.width()-rect().x() );
527 partOfMask.setWidth( image.width()-rect().x() );
528 }
529
530 if ( (rect().x() < 0) ) {
531 partOfImage.setX(0);
532 partOfMask.setX(myabs(rect().x()));
533 }
534
535 if ( (rect().y()+rect().height()) > image.height() ) {
536 partOfImage.setHeight( image.height()-rect().y() );
537 partOfMask.setHeight ( image.height()-rect().y() );
538 }
539
540 if ( (rect().y() < 0) ) {
541 partOfImage.setY(0);
542 partOfMask.setY(myabs(rect().y()));
543 }
544
545 QImage tempImage=mask.toImage().copy(partOfMask);
546 mask = QPixmap::fromImage(tempImage);
547
548// partOfImage = partOfImage.normalize();
549 QImage cut=image.copy(partOfImage);
550
551 QPixmap pix;
552
553// partOfMask = partOfMask.normalize();
554 if (!partOfMask.isValid())
555 kDebug() << "PartofMask not valid : " << partOfMask.x() << "," << partOfMask.y() << ","
556 << partOfMask.width() << "," << partOfMask.height() << "," << endl;
557
558/*
559 QBitmap mask2(partOfMask.width(), partOfMask.height());
560 QPainter p4(&mask2);
561 p4.drawPixmap( QPoint(0,0) ,mask,partOfMask);
562 p4.flush();
563 p4.end();
564*/
565
566 pix = QPixmap::fromImage(cut);
567
568 // setHighlightedPixmap(cut, mask);
569
570 QPixmap retPix(pix.width(),pix.height());
571 QPainter p3(&retPix);
572
573 // if transparent image fill the background
574 // with gimp-like rectangles
575 if (!pix.mask().isNull()) {
576 QPixmap backPix(32,32);
577
578 // Gimp like transparent rectangle
579 QPainter p2(&backPix);
580 p2.fillRect(0,0,32,32,QColor(156,149,156));
581 p2.fillRect(0,16,16,16,QColor(98,105,98));
582 p2.fillRect(16,0,16,16,QColor(98,105,98));
583
584 p3.setPen(QPen());
585 p3.fillRect(0,0,pix.width(),pix.height(),QBrush(QColor("black"),backPix));
586 }
587
588
589 p3.drawPixmap(QPoint(0,0),pix);
590 p3.end();
591 retPix.setMask(mask);
592
593 return retPix;
594}
595
596QBitmap Area::getMask() const
597{
598 QBitmap b;
599 return b;
600}
601
602/********************************************************************
603 * RECTANGLE
604 *******************************************************************/
605
606
607RectArea::RectArea()
608 : Area()
609{
610 _type=Area::Rectangle;
611 QPoint p(0,0);
612 _selectionPoints.append(new SelectionPoint(p,Qt::SizeFDiagCursor));
613 _selectionPoints.append(new SelectionPoint(p,Qt::SizeBDiagCursor));
614 _selectionPoints.append(new SelectionPoint(p,Qt::SizeBDiagCursor));
615 _selectionPoints.append(new SelectionPoint(p,Qt::SizeFDiagCursor));
616 _selectionPoints.append(new SelectionPoint(p,Qt::SizeVerCursor));
617 _selectionPoints.append(new SelectionPoint(p,Qt::SizeHorCursor));
618 _selectionPoints.append(new SelectionPoint(p,Qt::SizeVerCursor));
619 _selectionPoints.append(new SelectionPoint(p,Qt::SizeHorCursor));
620}
621
622RectArea::~RectArea() {
623}
624
625Area* RectArea::clone() const
626{
627 Area* areaClone = new RectArea();
628 areaClone->setArea( *this );
629 return areaClone;
630}
631
632void RectArea::draw(QPainter * p)
633{
634 setPenAndBrush(p);
635
636 QRect r(rect());
637 r.setWidth(r.width()+1);
638 r.setHeight(r.height()+1);
639 p->drawRect(r);
640
641 Area::draw(p);
642}
643
644QBitmap RectArea::getMask() const
645{
646 QBitmap mask(rect().width(),rect().height());
647
648 mask.fill(Qt::color0);
649 QPainter p(&mask);
650 p.setBackground(QBrush(Qt::color0));
651 p.setPen(Qt::color1);
652 p.setBrush(Qt::color1);
653 mask.fill(Qt::color1);
654 p.end();
655
656 return mask;
657}
658
659QString RectArea::coordsToString() const
660{
661 QString retStr=QString("%1,%2,%3,%4")
662 .arg(rect().left())
663 .arg(rect().top())
664 .arg(rect().right())
665 .arg(rect().bottom());
666
667 return retStr;
668}
669
670bool RectArea::contains(const QPoint & p) const{
671 return rect().contains(p);
672}
673
674void RectArea::moveSelectionPoint(SelectionPoint* selectionPoint, const QPoint & p)
675{
676 selectionPoint->setPoint(p);
677 int i = _selectionPoints.indexOf(selectionPoint);
678
679 QRect r2(_rect);
680 switch (i) {
681 case 0 :
682 _rect.setLeft(p.x());
683 _rect.setTop(p.y());
684 break;
685 case 1 :
686 _rect.setRight(p.x());
687 _rect.setTop(p.y());
688 break;
689 case 2 :
690 _rect.setLeft(p.x());
691 _rect.setBottom(p.y());
692 break;
693 case 3 :
694 _rect.setRight(p.x());
695 _rect.setBottom(p.y());
696 break;
697 case 4 : // top line
698 _rect.setTop(p.y());
699 break;
700 case 5 : // right line
701 _rect.setRight(p.x());
702 break;
703 case 6 : // bottom
704 _rect.setBottom(p.y());
705 break;
706 case 7 : // left
707 _rect.setLeft(p.x());
708 break;
709
710 }
711 if (! _rect.isValid())
712 _rect=r2;
713
714 updateSelectionPoints();
715}
716
717void RectArea::updateSelectionPoints()
718{
719 int d = 2;
720 QRect r(_rect);
721 r.adjust(0,0,1,1);
722 int xmid = r.left()+(r.width()/d);
723 int ymid = r.top()+(r.height()/d);
724
725
726 _selectionPoints[0]->setPoint(r.topLeft());
727 _selectionPoints[1]->setPoint(r.topRight());
728 _selectionPoints[2]->setPoint(r.bottomLeft());
729 _selectionPoints[3]->setPoint(r.bottomRight());
730 _selectionPoints[4]->setPoint(QPoint(xmid,r.top()));
731 _selectionPoints[5]->setPoint(QPoint(r.right(),ymid));
732 _selectionPoints[6]->setPoint(QPoint(xmid,r.bottom()));
733 _selectionPoints[7]->setPoint(QPoint(r.left(),ymid));
734}
735
736bool RectArea::setCoords(const QString & s)
737{
738 _finished=true;
739
740 const QStringList list = s.split(",");
741 QRect r;
742 bool ok=true;
743 QStringList::ConstIterator it = list.begin();
744 r.setLeft((*it).toInt(&ok,10));it++;
745 r.setTop((*it).toInt(&ok,10));it++;
746 r.setRight((*it).toInt(&ok,10));it++;
747 r.setBottom((*it).toInt(&ok,10));
748 if (ok) {
749 setRect(r);
750 return true;
751 } else {
752 return false;
753 }
754}
755
756QString RectArea::getHTMLCode() const {
757 QString retStr;
758 retStr+="<area ";
759 retStr+="shape=\"rect\" ";
760
761 retStr+=getHTMLAttributes();
762
763 retStr+="coords=\""+coordsToString()+"\" ";
764 retStr+="/>";
765 return retStr;
766
767}
768
769/********************************************************************
770 * CIRCLE
771 *******************************************************************/
772
773
774CircleArea::CircleArea()
775 : Area()
776{
777 _type = Area::Circle;
778 QPoint p(0,0);
779 _selectionPoints.append(new SelectionPoint(p,Qt::SizeFDiagCursor));
780 _selectionPoints.append(new SelectionPoint(p,Qt::SizeBDiagCursor));
781 _selectionPoints.append(new SelectionPoint(p,Qt::SizeBDiagCursor));
782 _selectionPoints.append(new SelectionPoint(p,Qt::SizeFDiagCursor));
783}
784
785CircleArea::~CircleArea() {
786}
787
788Area* CircleArea::clone() const
789{
790 Area* areaClone = new CircleArea();
791 areaClone->setArea( *this );
792 return areaClone;
793}
794
795void CircleArea::draw(QPainter * p)
796{
797 setPenAndBrush(p);
798
799 QRect r(_rect);
800 r.setWidth(r.width()+1);
801 r.setHeight(r.height()+1);
802 p->drawEllipse(r);
803
804 Area::draw(p);
805}
806
807QBitmap CircleArea::getMask() const
808{
809 QBitmap mask(_rect.width(),_rect.height());
810
811 mask.fill(Qt::color0);
812 QPainter p(&mask);
813 p.setBackground(QBrush(Qt::color0));
814 p.setPen(Qt::color1);
815 p.setBrush(Qt::color1);
816 p.drawPie(QRect(0,0,_rect.width(),_rect.height()),0,5760);
817 p.end();
818
819
820 return mask;
821
822}
823
824QString CircleArea::coordsToString() const
825{
826 QString retStr=QString("%1,%2,%3")
827 .arg(_rect.center().x())
828 .arg(_rect.center().y())
829 .arg(_rect.width()/2);
830
831 return retStr;
832}
833
834bool CircleArea::contains(const QPoint & p) const
835{
836 QRegion r(_rect,QRegion::Ellipse);
837 return r.contains(p);
838}
839
840void CircleArea::moveSelectionPoint(SelectionPoint* selectionPoint, const QPoint & p)
841{
842 selectionPoint->setPoint(p);
843
844 int i = _selectionPoints.indexOf(selectionPoint);
845
846 // The code below really sucks, but I have no better idea.
847 // it only makes sure that the circle is perfectly round
848
849 QPoint newPoint;
850 int diff=myabs(p.x()-_rect.center().x());
851 if (myabs(p.y()-_rect.center().y())>diff)
852 diff=myabs(p.y()-_rect.center().y());
853
854 newPoint.setX( p.x()-_rect.center().x()<0
855 ? _rect.center().x()-diff
856 : _rect.center().x()+diff);
857
858 newPoint.setY( p.y()-_rect.center().y()<0
859 ? _rect.center().y()-diff
860 : _rect.center().y()+diff);
861
862 switch (i) {
863 case 0 : if (newPoint.x() < _rect.center().x() &&
864 newPoint.y() < _rect.center().y())
865 {
866 _rect.setLeft(newPoint.x());
867 _rect.setTop(newPoint.y());
868 }
869 break;
870 case 1 : if (newPoint.x() > _rect.center().x() &&
871 newPoint.y() < _rect.center().y())
872 {
873 _rect.setRight(newPoint.x());
874 _rect.setTop(newPoint.y());
875 }
876 break;
877 case 2 : if (newPoint.x() < _rect.center().x() &&
878 newPoint.y() > _rect.center().y())
879 {
880 _rect.setLeft(newPoint.x());
881 _rect.setBottom(newPoint.y());
882 }
883 break;
884 case 3 : if (newPoint.x() > _rect.center().x() &&
885 newPoint.y() > _rect.center().y())
886 {
887 _rect.setRight(newPoint.x());
888 _rect.setBottom(newPoint.y());
889 }
890 break;
891 }
892
893
894
895 updateSelectionPoints();
896
897}
898
899void CircleArea::setRect(const QRect & r)
900{
901 QRect r2 = r;
902 if ( r2.height() != r2.width() )
903 r2.setHeight( r2.width() );
904
905 Area::setRect(r2);
906}
907
908
909void CircleArea::updateSelectionPoints()
910{
911 _selectionPoints[0]->setPoint(_rect.topLeft());
912 _selectionPoints[1]->setPoint(_rect.topRight());
913 _selectionPoints[2]->setPoint(_rect.bottomLeft());
914 _selectionPoints[3]->setPoint(_rect.bottomRight());
915}
916
917bool CircleArea::setCoords(const QString & s)
918{
919 _finished=true;
920 const QStringList list = s.split(",");
921 bool ok=true;
922 QStringList::ConstIterator it = list.begin();
923 int x=(*it).toInt(&ok,10);it++;
924 int y=(*it).toInt(&ok,10);it++;
925 int rad=(*it).toInt(&ok,10);
926 if (!ok) return false;
927 QRect r;
928 r.setWidth(rad*2);
929 r.setHeight(rad*2);
930 r.moveCenter(QPoint(x,y));
931 setRect(r);
932 return true;
933}
934
935QString CircleArea::getHTMLCode() const {
936 QString retStr;
937 retStr+="<area ";
938 retStr+="shape=\"circle\" ";
939
940 retStr+=getHTMLAttributes();
941
942 retStr+="coords=\""+coordsToString()+"\" ";
943 retStr+="/>";
944 return retStr;
945
946}
947
948
949/********************************************************************
950 * POLYGON
951 *******************************************************************/
952
953
954PolyArea::PolyArea()
955 : Area()
956{
957 _type = Area::Polygon;
958}
959
960PolyArea::~PolyArea() {
961}
962
963Area* PolyArea::clone() const
964{
965 Area* areaClone = new PolyArea();
966 areaClone->setArea( *this );
967 return areaClone;
968}
969
970void PolyArea::draw(QPainter * p)
971{
972 setPenAndBrush(p);
973
974 if (_finished)
975 p->drawPolygon( _coords.constData(),_coords.count());
976 else {
977 p->drawPolyline(_coords.constData(),_coords.count());
978 }
979
980 Area::draw(p);
981}
982
983QBitmap PolyArea::getMask() const
984{
985 QBitmap mask(_rect.width(),_rect.height());
986
987 mask.fill(Qt::color0);
988 QPainter p(&mask);
989 p.setBackground(QBrush(Qt::color0));
990 p.setPen(Qt::color1);
991 p.setBrush(Qt::color1);
992 p.setClipping(true);
993 QRegion r(_coords);
994 r.translate(-_rect.left(),-_rect.top());
995 p.setClipRegion(r);
996 p.fillRect(QRect(0,0,_rect.width(),_rect.height()),Qt::color1);
997 p.end();
998
999 return mask;
1000}
1001
1002QString PolyArea::coordsToString() const
1003{
1004 QString retStr;
1005
1006 for (int i=0;i<_coords.count();i++) {
1007 retStr.append(QString("%1,%2,")
1008 .arg(_coords.point(i).x())
1009 .arg(_coords.point(i).y()));
1010 }
1011
1012 retStr.remove(retStr.length()-1,1);
1013
1014 return retStr;
1015}
1016
1017int PolyArea::distance(const QPoint &p1, const QPoint &p2)
1018{
1019 QPoint temp = p1-p2;
1020 return temp.manhattanLength();
1021}
1022
1023bool PolyArea::isBetween(const QPoint &p, const QPoint &p1, const QPoint &p2)
1024{
1025 int dist = distance(p,p1)+distance(p,p2)-distance(p1,p2);
1026
1027 if (myabs(dist)<1)
1028 return true;
1029 else
1030 return false;
1031}
1032
1033void PolyArea::simplifyCoords()
1034{
1035 if (_coords.size()<4)
1036 return;
1037
1038 QPoint p = _coords.point(0) - _coords.point(1);
1039
1040 int i = 1;
1041
1042
1043 while( (i<_coords.size()) && (_coords.size() > 3) )
1044 {
1045 p = _coords.point(i-1) - _coords.point(i);
1046
1047 if (p.manhattanLength() < 3)
1048 removeCoord(i);
1049 else
1050 i++;
1051 }
1052
1053 p = _coords.point(0) - _coords.point(1);
1054
1055 double angle2;
1056 double angle1;
1057
1058 if (p.y()==0)
1059 angle1 = 1000000000;
1060 else
1061 angle1 = (double) p.x() / (double) p.y();
1062
1063 i=2;
1064
1065 while( (i<_coords.size()) && (_coords.size() > 3) )
1066 {
1067 p = _coords.point(i-1) - _coords.point(i);
1068
1069 if (p.y()==0)
1070 angle2 = 1000000000;
1071 else
1072 angle2 = (double) p.x() / (double) p.y();
1073
1074 if ( angle2==angle1 )
1075 {
1076 kDebug() << "removing " << i-1;
1077 removeCoord(i-1);
1078 }
1079 else
1080 {
1081 i++;
1082 kDebug() << "skipping " << i-1 << " cause " << angle1 << "!= " << angle2;
1083 angle1 = angle2;
1084
1085 }
1086
1087 }
1088
1089
1090
1091}
1092
1093
1094int PolyArea::addCoord(const QPoint & p)
1095{
1096 if (_coords.size()<3)
1097 {
1098 return Area::addCoord(p);
1099 }
1100
1101 if (_coords.point(_coords.size()-1) == p)
1102 {
1103 kDebug() << "equal Point added";
1104 return -1;
1105
1106 }
1107
1108 int n=_coords.size();
1109
1110// QPoint temp = p-_coords.point(0);
1111 int nearest = 0;
1112 int olddist = distance(p,_coords.point(0));
1113 int mindiff = 999999999;
1114
1115 // find the two points, which are the nearest one to the new point
1116 for (int i=1; i <= n; i++)
1117 {
1118 int dist = distance(p,_coords.point(i%n));
1119 int dist2 = distance(_coords.point(i-1),_coords.point(i%n));
1120 int diff = myabs(dist+olddist-dist2);
1121 if ( diff<mindiff )
1122 {
1123 mindiff = diff;
1124 nearest = i%n;
1125 }
1126 olddist=dist;
1127 }
1128
1129 insertCoord(nearest, p);
1130
1131 return nearest;
1132
1133}
1134
1135bool PolyArea::contains(const QPoint & p) const
1136{
1137 // A line can't contain a point
1138 if (_coords.count() >2 ) {
1139 QRegion r(_coords);
1140 return r.contains(p);
1141 }
1142 else
1143 return false;
1144}
1145
1146void PolyArea::moveSelectionPoint(SelectionPoint* selectionPoint, const QPoint & p)
1147{
1148 selectionPoint->setPoint(p);
1149
1150 int i = _selectionPoints.indexOf(selectionPoint);
1151 _coords.setPoint(i,p);
1152 _rect=_coords.boundingRect();
1153}
1154
1155void PolyArea::updateSelectionPoints()
1156{
1157 for (int i = 0; i < _selectionPoints.size(); ++i) {
1158 _selectionPoints.at(i)->setPoint(_coords.point(i));
1159 }
1160}
1161
1162bool PolyArea::setCoords(const QString & s)
1163{
1164 _finished=true;
1165 const QStringList list = s.split(",");
1166 _coords.clear();
1167 _selectionPoints.clear();
1168
1169 for (QStringList::ConstIterator it = list.begin(); it !=list.end(); ++it)
1170 {
1171 bool ok=true;
1172 int newXCoord=(*it).toInt(&ok,10);
1173 if (!ok) return false;
1174 it++;
1175 if (it==list.end()) break;
1176 int newYCoord=(*it).toInt(&ok,10);
1177 if (!ok) return false;
1178 insertCoord(_coords.size(), QPoint(newXCoord,newYCoord));
1179 }
1180
1181 return true;
1182
1183}
1184
1185QString PolyArea::getHTMLCode() const {
1186 QString retStr;
1187 retStr+="<area ";
1188 retStr+="shape=\"poly\" ";
1189
1190 retStr+=getHTMLAttributes();
1191
1192 retStr+="coords=\""+coordsToString()+"\" ";
1193 retStr+="/>";
1194 return retStr;
1195
1196}
1197
1198void PolyArea::setFinished(bool b, bool removeLast = true)
1199{
1200 // The last Point is the same as the first
1201 // so delete it
1202 if (b && removeLast) {
1203 _coords.resize(_coords.size()-1);
1204 _selectionPoints.removeLast();
1205 }
1206
1207 _finished = b;
1208}
1209
1210QRect PolyArea::selectionRect() const
1211{
1212 QRect r = _rect;
1213
1214 r.translate(-10,-10);
1215 r.setSize(r.size()+QSize(21,21));
1216
1217 return r;
1218}
1219
1220
1221
1222/********************************************************************
1223 * DEFAULT
1224 *******************************************************************/
1225
1226
1227DefaultArea::DefaultArea()
1228 : Area()
1229{
1230 _type=Area::Default;
1231}
1232
1233DefaultArea::~DefaultArea() {
1234}
1235
1236Area* DefaultArea::clone() const
1237{
1238 Area* areaClone = new DefaultArea();
1239 areaClone->setArea( *this );
1240 return areaClone;
1241}
1242
1243void DefaultArea::draw(QPainter *)
1244{}
1245
1246
1247QString DefaultArea::getHTMLCode() const {
1248 QString retStr;
1249 retStr+="<area ";
1250 retStr+="shape=\"default\" ";
1251
1252 retStr+=getHTMLAttributes();
1253
1254 retStr+="/>";
1255 return retStr;
1256
1257}
1258
1259
1260/********************************************************************
1261 * AreaSelection
1262 *******************************************************************/
1263
1264AreaSelection::AreaSelection()
1265 : Area()
1266{
1267 _areas = new AreaList();
1268 _name = "Selection";
1269 invalidate();
1270}
1271
1272AreaSelection::~AreaSelection() {
1273 delete _areas;
1274}
1275
1276Area* AreaSelection::clone() const
1277{
1278 AreaSelection* areaClone = new AreaSelection();
1279
1280 // we want a deep copy of the Areas
1281 AreaListIterator it=getAreaListIterator();
1282 while (it.hasNext()) {
1283 areaClone->add( it.next()->clone() );
1284 }
1285
1286 return areaClone;
1287}
1288
1289
1290void AreaSelection::add(Area *a)
1291{
1292 // if a selection of areas was added get the areas of it
1293 AreaSelection *selection=0L;
1294 if ( (selection = dynamic_cast <AreaSelection*> ( a ) ) ) {
1295 AreaList list = selection->getAreaList();
1296 Area* area;
1297 foreach(area,list) {
1298 if ( !_areas->contains( area )) {
1299 _areas->append( area ); // Must come before area->setSelected
1300 area->setSelected( true );
1301 }
1302 }
1303 } else {
1304 if ( !_areas->contains( a )) {
1305 _areas->append( a ); // Must come before a->setSelected
1306 a->setSelected( true );
1307 }
1308 }
1309
1310 invalidate();
1311}
1312
1313
1314void AreaSelection::setSelectionPointStates(SelectionPoint::State st) {
1315 AreaListIterator it=getAreaListIterator();
1316 while(it.hasNext()) {
1317 it.next()->setSelectionPointStates( st );
1318 }
1319}
1320
1321void AreaSelection::updateSelectionPointStates() {
1322 SelectionPoint::State st = SelectionPoint::Normal;
1323
1324 if (_areas->count() > 1)
1325 st = SelectionPoint::Inactive;
1326
1327 setSelectionPointStates(st);
1328}
1329
1330
1331void AreaSelection::remove(Area *a)
1332{
1333 if (!_areas->contains(a))
1334 return;
1335
1336 a->setSelected( false );
1337 _areas->removeAt(_areas->indexOf(a));
1338 invalidate();
1339}
1340
1341void AreaSelection::reset()
1342{
1343 AreaListIterator it=getAreaListIterator();
1344 while (it.hasNext()) {
1345 it.next()->setSelected( false );
1346 }
1347
1348 _areas->clear();
1349 invalidate();
1350}
1351
1352bool AreaSelection::contains(const QPoint & p) const
1353{
1354 AreaListIterator it=getAreaListIterator();
1355 while (it.hasNext()) {
1356 if ( it.next()->contains( p ) ) {
1357 return true;
1358 }
1359 }
1360
1361 return false;
1362}
1363
1364SelectionPoint* AreaSelection::onSelectionPoint(const QPoint & p, double zoom) const
1365{
1366
1367 if (_areas->count() != 1)
1368 return 0L;
1369
1370 return _areas->first()->onSelectionPoint(p,zoom);
1371}
1372
1373void AreaSelection::moveSelectionPoint(SelectionPoint* selectionPoint, const QPoint & p)
1374{
1375 // It's only possible to move a SelectionPoint if only one Area is selected
1376 if (_areas->count() != 1)
1377 return;
1378
1379 _areas->first()->moveSelectionPoint(selectionPoint,p);
1380
1381 invalidate();
1382}
1383
1384
1385void AreaSelection::moveBy(int dx, int dy)
1386{
1387 AreaListIterator it=getAreaListIterator();
1388 while (it.hasNext()) {
1389 it.next()->moveBy(dx,dy);
1390 }
1391
1392 Area::moveBy( dx, dy );
1393 invalidate();
1394}
1395
1396QString AreaSelection::typeString() const
1397{
1398 // if there is only one Area selected
1399 // show the name of that Area
1400 if ( _areas->count()==0 )
1401 return "";
1402 else if ( _areas->count()==1 )
1403 return _areas->first()->typeString();
1404 else
1405 return i18n("Number of Areas");
1406
1407}
1408
1409Area::ShapeType AreaSelection::type() const
1410{
1411 // if there is only one Area selected
1412 // take the type of that Area
1413 if ( _areas->count()==0 )
1414 return Area::None;
1415 else if ( _areas->count()==1 )
1416 return _areas->first()->type();
1417 else
1418 return Area::Selection;
1419}
1420
1421void AreaSelection::resetSelectionPointState() {
1422 updateSelectionPointStates();
1423}
1424
1425void AreaSelection::updateSelectionPoints()
1426{
1427 AreaListIterator it=getAreaListIterator();
1428 while (it.hasNext()) {
1429 it.next()->updateSelectionPoints();
1430 }
1431
1432 invalidate();
1433}
1434
1435
1436
1437QRect AreaSelection::selectionRect() const
1438{
1439 if (!_selectionCacheValid) {
1440 _selectionCacheValid=true;
1441 QRect r;
1442 AreaListIterator it=getAreaListIterator();
1443 while (it.hasNext()) {
1444 r = r | it.next()->selectionRect();
1445 }
1446 _cachedSelectionRect=r;
1447 }
1448
1449 return _cachedSelectionRect;
1450}
1451
1452int AreaSelection::count() const {
1453 return _areas->count();
1454}
1455
1456bool AreaSelection::isEmpty() const
1457{
1458 return _areas->isEmpty();
1459}
1460
1461
1462AreaList AreaSelection::getAreaList() const {
1463 AreaList list(*_areas);
1464 return list;
1465}
1466
1467AreaListIterator AreaSelection::getAreaListIterator() const {
1468 AreaListIterator it(*_areas);
1469 return it;
1470}
1471
1472void AreaSelection::setArea(const Area & copy)
1473{
1474 Area *area = copy.clone();
1475 AreaSelection *selection = dynamic_cast<AreaSelection*>(area);
1476 if (selection)
1477 setAreaSelection(*selection);
1478 else {
1479 Area::setArea(copy);
1480 invalidate();
1481 }
1482}
1483
1484void AreaSelection::setAreaSelection(const AreaSelection & copy)
1485{
1486 AreaList* areasCopy = copy._areas;
1487
1488 if (_areas->count() != areasCopy->count())
1489 return;
1490
1491 AreaListIterator it(*_areas);
1492 AreaListIterator it2(*areasCopy);
1493 while (it.hasNext()) {
1494 it.next()->setArea(*it2.next());
1495 }
1496
1497 Area::setArea(copy);
1498 invalidate();
1499}
1500
1501void AreaSelection::setAreaList( const AreaList & areas )
1502{
1503 delete _areas;
1504 _areas = new AreaList(areas);
1505 invalidate();
1506}
1507
1508void AreaSelection::setRect(const QRect & r)
1509{
1510 if ( _areas->count()==1 )
1511 {
1512 _areas->first()->setRect(r);
1513 }
1514
1515 invalidate();
1516 _rect=rect();
1517 updateSelectionPoints();
1518}
1519
1520QRect AreaSelection::rect() const
1521{
1522 if (!_rectCacheValid)
1523 {
1524 _rectCacheValid=true;
1525 QRect r;
1526 AreaListIterator it=getAreaListIterator();
1527
1528 while (it.hasNext()) {
1529 r = r | it.next()->rect();
1530 }
1531
1532 _cachedRect=r;
1533 }
1534
1535 return _cachedRect;
1536}
1537
1538
1539int AreaSelection::addCoord(const QPoint & p)
1540{
1541 if ( _areas->count()==1 )
1542 {
1543 return _areas->first()->addCoord(p);
1544 invalidate();
1545 }
1546
1547 return 0;
1548}
1549
1550void AreaSelection::insertCoord(int pos, const QPoint & p)
1551{
1552 if ( _areas->count()==1 )
1553 {
1554 _areas->first()->insertCoord(pos, p);
1555 invalidate();
1556 }
1557}
1558
1559void AreaSelection::removeCoord(int pos)
1560{
1561 if ( _areas->count()==1 )
1562 {
1563 _areas->first()->removeCoord(pos);
1564 invalidate();
1565 }
1566}
1567
1568bool AreaSelection::removeSelectionPoint(SelectionPoint* p)
1569{
1570 bool result=false;
1571
1572 if ( _areas->count()==1 )
1573 {
1574 result = _areas->first()->removeSelectionPoint(p);
1575 invalidate();
1576 }
1577
1578 return result;
1579}
1580
1581const SelectionPointList & AreaSelection::selectionPoints() const
1582{
1583 if ( _areas->count()==1 )
1584 {
1585 return _areas->first()->selectionPoints();
1586 }
1587
1588 return _selectionPoints;
1589}
1590
1591
1592void AreaSelection::moveCoord(int pos,const QPoint & p)
1593{
1594 if ( _areas->count()==1 )
1595 {
1596 _areas->first()->moveCoord(pos,p);
1597 invalidate();
1598 }
1599}
1600
1601void AreaSelection::highlightSelectionPoint(int i)
1602{
1603 if ( _areas->count()==1 )
1604 {
1605 _areas->first()->highlightSelectionPoint(i);
1606 invalidate();
1607 }
1608}
1609
1610
1611QPolygon AreaSelection::coords() const
1612{
1613 if ( _areas->count()==1 )
1614 {
1615 return _areas->first()->coords();
1616 }
1617
1618 return Area::coords();
1619}
1620
1621QString AreaSelection::attribute(const QString & name) const
1622{
1623 if ( _areas->count()==1 )
1624 {
1625 return _areas->first()->attribute(name);
1626 }
1627
1628 return Area::attribute(name);
1629}
1630
1631void AreaSelection::setAttribute(const QString & name, const QString & value)
1632{
1633 AreaListIterator it=getAreaListIterator();
1634
1635 while (it.hasNext()) {
1636 it.next()->setAttribute(name,value);
1637 }
1638
1639 Area::setAttribute(name,value);
1640}
1641
1642AttributeIterator AreaSelection::attributeIterator() const
1643{
1644 if ( _areas->count()==1 )
1645 {
1646 return _areas->first()->attributeIterator();
1647 }
1648
1649 return AttributeIterator(_attributes);
1650}
1651
1652void AreaSelection::setMoving(bool b)
1653{
1654 AreaListIterator it=getAreaListIterator();
1655
1656 while (it.hasNext()) {
1657 it.next()->setMoving(b);
1658 }
1659
1660 Area::setMoving(b);
1661}
1662
1663bool AreaSelection::isMoving() const
1664{
1665 if ( _areas->count()==1 )
1666 {
1667 return _areas->first()->isMoving();
1668 }
1669
1670 return Area::isMoving();
1671}
1672
1673
1674/**
1675 * Checks if an area is outside the rectangle parameter
1676 * returns false if an area has no pixel in common with the rectangle parameter
1677 **/
1678bool AreaSelection::allAreasWithin(const QRect & r) const
1679{
1680 if ( ! r.contains(rect()) )
1681 {
1682 AreaListIterator it=getAreaListIterator();
1683
1684 while (it.hasNext()) {
1685 if (!it.next()->rect().intersects(r))
1686 return false;
1687 }
1688 }
1689
1690 return true;
1691}
1692
1693
1694void AreaSelection::draw(QPainter *)
1695{}
1696
1697void AreaSelection::invalidate() {
1698 _selectionCacheValid=false;
1699 _rectCacheValid=false;
1700 updateSelectionPointStates();
1701}
1702
1703
1704