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