1 /***************************************************************************
2 imagemap.cpp - description
3 -------------------
4 begin : Wed Apr 4 2001
5 copyright : (C) 2001 by Jan Schäfer
6 email : j_schaef@informatik.uni-kl.de
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 "imagemap.h"
19 #include "kimagemapeditor.h"
20
21 #include <QBitmap>
22 #include <QMouseEvent>
23 #include <QPainter>
24 #include <QPixmap>
25 #include <QResizeEvent>
26
round(double d)27 int round(double d) {
28 if ( (d-((int) d)) < 0.5 )
29 return (int) d;
30 else
31 return ((int) d)+1;
32 }
33
ImageMap(QWidget * parent,KImageMapEditor * _imageMapEditor)34 ImageMap::ImageMap(QWidget *parent,KImageMapEditor* _imageMapEditor)
35 : QScrollArea(parent)
36 {
37 imageMapEditor=_imageMapEditor;
38 // setPicture(QImage());
39 currentAction=None;
40 currentArea=0L;
41 eraseOldArea=false;
42 oldArea=0L;
43 _zoom=1;
44 widget()->setMouseTracking(true);
45
46
47 }
48
~ImageMap()49 ImageMap::~ImageMap(){
50 }
51
setPicture(const QImage & _image)52 void ImageMap::setPicture(const QImage &_image) {
53 image=_image;
54 zoomedImage.convertFromImage(image);
55 setZoom(_zoom);
56 }
57
setZoom(double z)58 void ImageMap::setZoom(double z) {
59 _zoom=z;
60 imageRect.setHeight(image.height()*_zoom);
61 imageRect.setWidth(image.width()*_zoom);
62 zoomedImage=QPixmap(imageRect.width(),imageRect.height());
63 QPainter p(&zoomedImage);
64 p.scale(z,z);
65 QPixmap pix;
66 pix.convertFromImage(image);
67 // if the picture has transparent areas,
68 // fill them with Gimp like background
69 if (pix.mask()) {
70 QPixmap backPix(32,32);
71 QPainter p2(&backPix);
72 p2.fillRect(0,0,32,32,QColor(156,149,156));
73 p2.fillRect(0,16,16,16,QColor(98,105,98));
74 p2.fillRect(16,0,16,16,QColor(98,105,98));
75 p2.flush();
76 p.setPen(QPen());
77 p.fillRect(imageRect.left(),imageRect.top(),imageRect.width(),imageRect.height(),QBrush(QColor("black"),backPix));
78 }
79 p.drawPixmap(imageRect.left(),imageRect.top(),pix);
80 p.flush();
81 resizeContents(visibleWidth()>imageRect.width() ? visibleWidth() : imageRect.width(),
82 visibleHeight()>imageRect.height() ? visibleHeight() : imageRect.height());
83 repaintContents(0,0,contentsWidth(),contentsHeight(),true);
84 }
85
translateFromZoom(const QPoint & p) const86 QPoint ImageMap::translateFromZoom(const QPoint & p) const {
87 return QPoint(p.x()/_zoom,p.y()/_zoom);
88 }
89
translateToZoom(const QPoint & p) const90 QPoint ImageMap::translateToZoom(const QPoint & p) const {
91 return QPoint(round(p.x()*_zoom),round(p.y()*_zoom));
92 }
93
translateToZoom(const QRect & r) const94 QRect ImageMap::translateToZoom(const QRect & r) const {
95 return QRect(round(r.x()*_zoom),round(r.y()*_zoom),
96 round(r.width()*_zoom),round(r.height()*_zoom));
97 }
98
mouseDoubleClickEvent(QMouseEvent * e)99 void ImageMap::mouseDoubleClickEvent(QMouseEvent* e) {
100 QPoint point=e->pos();
101 point-=imageRect.topLeft();
102 point=translateFromZoom(point);
103 if ( currentAction==None &&
104 (currentArea=imageMapEditor->onArea(point)))
105 imageMapEditor->showTagEditor(currentArea);
106
107 }
108
mousePressEvent(QMouseEvent * e)109 void ImageMap::mousePressEvent(QMouseEvent* e) {
110 drawStart=e->pos();
111 // Check if it's on picture if not
112 // move it to the picture's border
113 if (!imageRect.contains(drawStart)) {
114 if (drawStart.x()>imageRect.right())
115 drawStart.setX(imageRect.right());
116 if (drawStart.x()<imageRect.left())
117 drawStart.setX(imageRect.left());
118 if (drawStart.y()>imageRect.bottom())
119 drawStart.setY(imageRect.bottom());
120 if (drawStart.y()<imageRect.top())
121 drawStart.setY(imageRect.top());
122 }
123
124 // Translate it to picture coordinates
125 drawStart-=imageRect.topLeft();
126 drawStart=translateFromZoom(drawStart);
127 if (currentArea)
128 oldArea=new Area(*currentArea);
129
130 if ( currentAction==None ) {
131 if (e->button()==Qt::RightButton) {
132 currentArea=imageMapEditor->onArea(drawStart);
133 imageMapEditor->select(currentArea);
134 imageMapEditor->slotShowPopupMenu(e->globalPos());
135 } else
136 if ((currentArea=imageMapEditor->selected()) &&
137 (currentSelectionPoint=currentArea->onSelectionPoint(drawStart)))
138 {
139 currentAction=MoveSelectionPoint;
140 } else
141 if ((currentArea=imageMapEditor->onArea(drawStart))) {
142 currentAction=MoveArea;
143 imageMapEditor->select(currentArea);
144 } else
145 if (imageMapEditor->currentShapeType()!=Area::None) {
146 currentArea=new Area(imageMapEditor->currentShapeType());
147 currentArea->setRect(QRect(drawStart,drawStart));
148 currentArea->setSelected(false);
149 if (imageMapEditor->selected())
150 imageMapEditor->selected()->setSelected(false);
151 switch (currentArea->type()) {
152 case Area::Rectangle : currentAction=DrawRectangle; break;
153 case Area::Circle : currentAction=DrawCircle; break;
154 case Area::Polygon :
155 currentAction=DrawPolygon;
156 currentArea->addCoord(drawStart);
157 currentSelectionPoint=currentArea->selectionPoints()->last();
158
159 break;
160 default: break;
161 }
162 }
163 // Clicked with the arrow at an areafree position
164 else {
165 currentArea=0L;
166 imageMapEditor->deselectAll();
167 }
168 } else
169 if ( currentAction==DrawPolygon) {
170
171 }
172
173 QRect r;
174 if (oldArea)
175 r=oldArea->selectionRect();
176 if (currentArea) {
177 r= r | currentArea->selectionRect();
178 repaintContents(translateToZoom(r),false);
179 }
180
181 }
182
mouseReleaseEvent(QMouseEvent * e)183 void ImageMap::mouseReleaseEvent(QMouseEvent *e) {
184 drawEnd=e->pos();
185
186 // Check if it's on picture if not
187 // move it to the picture's border
188 if (!imageRect.contains(drawEnd)) {
189 if (drawEnd.x()>imageRect.right())
190 drawEnd.setX(imageRect.right());
191 if (drawEnd.x()<imageRect.left())
192 drawEnd.setX(imageRect.left());
193 if (drawEnd.y()>imageRect.bottom())
194 drawEnd.setY(imageRect.bottom());
195 if (drawEnd.y()<imageRect.top())
196 drawEnd.setY(imageRect.top());
197 }
198 // Translate it to picture coordinates
199 drawEnd-=imageRect.topLeft();
200 drawEnd=translateFromZoom(drawEnd);
201
202 if (currentAction==DrawCircle || currentAction==DrawRectangle) {
203 imageMapEditor->addArea(currentArea);
204 imageMapEditor->select(currentArea);
205 //imageMapEditor->slotAreaChanged(currentArea);
206 currentAction=None;
207 } else
208 if (currentAction==DrawPolygon) {
209 // If the number of Polygonpoints is more than 2
210 // and clicked on the first PolygonPoint or
211 // the right Button was pressed the Polygon is finished
212 if ((currentArea->selectionPoints()->count()>2)
213 && (currentArea->selectionPoints()->first()->contains(drawEnd)
214 || (e->button()==Qt::RightButton)))
215 {
216 currentArea->setFinished(true);
217 imageMapEditor->addArea(currentArea);
218 currentAction=None;
219 } else
220 {
221 currentArea->addCoord(drawEnd);
222 currentSelectionPoint=currentArea->selectionPoints()->last();
223 }
224
225 // currentArea->addCoord(drawEnd);
226 // currentSelectionPoint=currentArea->selectionPoints()->last();
227 } else
228 if (currentAction==MoveArea || currentAction==MoveSelectionPoint) {
229 imageMapEditor->slotAreaChanged(currentArea);
230 currentAction=None;
231 }
232 else {
233 currentAction=None;
234 }
235 imageMapEditor->slotChangeStatusCoords(drawEnd.x(),drawEnd.y());
236 imageMapEditor->slotUpdateSelectionCoords();
237
238 if (currentArea)
239 repaintArea(*currentArea);
240 // repaintContents(0,0,contentsWidth(),contentsHeight(),false);
241 }
242
243
mouseMoveEvent(QMouseEvent * e)244 void ImageMap::mouseMoveEvent(QMouseEvent *e) {
245 drawCurrent=e->pos();
246
247 // If outside the image
248 // set it to the border
249 if (!imageRect.contains(drawCurrent)) {
250 if (drawCurrent.x()>imageRect.right())
251 drawCurrent.setX(imageRect.right());
252 if (drawCurrent.x()<imageRect.left())
253 drawCurrent.setX(imageRect.left());
254 if (drawCurrent.y()>imageRect.bottom())
255 drawCurrent.setY(imageRect.bottom());
256 if (drawCurrent.y()<imageRect.top())
257 drawCurrent.setY(imageRect.top());
258 }
259
260 // Translate to image coordinates
261 drawCurrent-=imageRect.topLeft();
262 drawCurrent=translateFromZoom(drawCurrent);
263
264 if (currentAction==DrawRectangle) {
265 // To avoid flicker, only repaint the minimum rect
266 QRect oldRect=translateToZoom(currentArea->rect());
267 currentArea->setRect(QRect(drawStart,drawCurrent).normalize());
268 QRect newRect=translateToZoom(currentArea->rect());
269 QRect r=oldRect | newRect;
270 repaintContents(r,false);
271 imageMapEditor->slotUpdateSelectionCoords(currentArea->rect());
272 } else
273 if (currentAction==DrawCircle) {
274 QRect oldRect=translateToZoom(currentArea->rect());
275 currentArea->setRect(QRect(drawStart,drawCurrent).normalize());
276 QRect newRect=translateToZoom(currentArea->rect());
277 QRect r=oldRect | newRect;
278 repaintContents(r,false);
279 imageMapEditor->slotUpdateSelectionCoords(currentArea->rect());
280 } else
281 if ( currentAction==DrawPolygon ) {
282 QRect oldRect=translateToZoom(currentArea->rect());
283 currentArea->moveSelectionPoint(currentSelectionPoint,drawCurrent);
284 QRect newRect=translateToZoom(currentArea->rect());
285 QRect r=oldRect | newRect;
286 repaintContents(r,false);
287 imageMapEditor->slotUpdateSelectionCoords(currentArea->rect());
288 } else
289 if ( currentAction==MoveArea ) {
290 QRect oldRect=translateToZoom(currentArea->selectionRect());
291 currentArea->translate((drawCurrent-drawStart).x(),(drawCurrent-drawStart).y());
292 QRect newRect=translateToZoom(currentArea->selectionRect());
293 QRect r=oldRect | newRect;
294 repaintContents(r,false);
295 drawStart=drawCurrent;
296 imageMapEditor->slotUpdateSelectionCoords();
297 } else
298 if ( currentAction==MoveSelectionPoint ) {
299 QRect oldRect=translateToZoom(currentArea->selectionRect());
300 currentArea->moveSelectionPoint(currentSelectionPoint,drawCurrent);
301 QRect newRect=translateToZoom(currentArea->selectionRect());
302 QRect r=oldRect | newRect;
303 repaintContents(r,false);
304 imageMapEditor->slotUpdateSelectionCoords();
305 }
306 imageMapEditor->slotChangeStatusCoords(drawCurrent.x(),drawCurrent.y());
307 }
308
resizeEvent(QResizeEvent * e)309 void ImageMap::resizeEvent(QResizeEvent* e) {
310 QScrollArea::resizeEvent(e);
311 int width=(int) (image.width()*_zoom);
312 int height=(int) (image.height()*_zoom);
313 if (visibleWidth()>width)
314 width=visibleWidth();
315 if (visibleHeight()>height)
316 height=visibleHeight();
317
318 resizeContents(width,height);
319
320 imageRect.setLeft(0);
321 imageRect.setTop(0);
322 imageRect.setHeight(image.height()*_zoom);
323 imageRect.setWidth(image.width()*_zoom);
324
325 }
326
repaintArea(const Area & a)327 void ImageMap::repaintArea(const Area & a) {
328 repaintContents(translateToZoom(a.selectionRect()),false);
329 }
330
drawContents(QPainter * p,int clipx,int clipy,int clipw,int cliph)331 void ImageMap::drawContents(QPainter* p,int clipx,int clipy,int clipw,int cliph) {
332 // qCDebug(KIMAGEMAPEDITOR_LOG) << "drawing\n";
333 // p.scale(rect.width()*2,rect.height()*2);
334 // if (e->rect()!=rect()) {
335 // p.setClipping(true);
336 // p.setClipRect(e->rect());
337 // } else
338 /* if (currentAction==DrawRectangle) {
339 p->setClipping(true);
340 QRect r(currentArea->rect());
341 r.translate(imageRect.left()-5,imageRect.top()-5);
342 r.setSize(r.size()+QSize(10,10));
343 p->setClipRegion(r);
344 }
345 */
346
347 QRect updateRect(clipx,clipy,clipw,cliph);
348 QPixmap doubleBuffer(updateRect.size()); // Pixmap for double-buffering
349 QPainter p2(&doubleBuffer);
350 p2.drawPixmap(0,0,zoomedImage,clipx,clipy,clipw,cliph);
351 p2.translate(-updateRect.x(), -updateRect.y());
352 p2.scale(_zoom,_zoom);
353
354 AreaList *list=imageMapEditor->areaList();
355 for (Area* s=list->first();s != 0L; s=list->next())
356 s->draw(p2);
357
358 // Draw the current drawing Area
359 if (currentAction != MoveArea &&
360 currentAction != MoveSelectionPoint &&
361 currentAction != None)
362 {
363 currentArea->draw(p2);
364 }
365
366 p2.end();
367
368 // Copy the double buffer into the widget
369 p->drawPixmap(clipx,clipy,doubleBuffer);
370 // Erase background without flicker
371 QRegion region(contentsX(),contentsY(),visibleWidth(),visibleHeight());
372 region=region.subtract(QRegion(imageRect));
373 for (int i=0;i<region.rects().count();i++) {
374 p->eraseRect(region.rects()[i]);
375 }
376
377
378 // Draw our picture
379 // p->drawPixmap(imageRect.left(),imageRect.top(),zoomedImage);
380 //
381 //
382 // p->scale(_zoom,_zoom);
383 // p->translate(imageRect.left(),imageRect.top());
384 //
385 // AreaList *list=imageMapEditor->areaList();
386 // for (Area* s=list->first();s != 0L; s=list->next())
387 // s->draw(*p);
388 //
389 // // Draw the current drawing Area
390 // if (currentAction != MoveArea &&
391 // currentAction != MoveSelectionPoint &&
392 // currentAction != None)
393 // {
394 // currentArea->draw(*p);
395 // }
396
397
398 }
399