File indexing completed on 2024-12-01 06:51:42
0001 /****************************************************************f*********** 0002 cmapelement.cpp 0003 ------------------- 0004 begin : Sat Mar 10 2001 0005 copyright : (C) 2001 by Kmud Developer Team 0006 email : kmud-devel@kmud.de 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 #include "cmapelement.h" 0019 0020 #include <QDebug> 0021 0022 #include <KLocalizedString> 0023 #include <kconfiggroup.h> 0024 0025 #include "cmaplevel.h" 0026 #include "cmapmanager.h" 0027 #include "cmapcmdelementproperties.h" 0028 #include "cmapview.h" 0029 0030 #define RESIZE_SIZE 10 0031 #define RESIZE_SIZE_HALF 5 0032 0033 CMapElement::CMapElement(CMapManager *manager,QRect rect,CMapLevel *level) : QObject (nullptr) 0034 { 0035 mapManager = manager; 0036 position = rect; 0037 mapLevel = level; 0038 selected = false; 0039 editing = false; 0040 doPaint = true; 0041 0042 if (mapManager->getZone(true)) 0043 mapManager->addedElement(this); 0044 0045 connect(this,SIGNAL(deleteElement(CMapElement *,bool)),manager,SLOT(deleteElement(CMapElement *,bool))); 0046 } 0047 0048 CMapElement::CMapElement(CMapManager *manager,CMapLevel *level) 0049 { 0050 mapManager = manager; 0051 mapLevel = level; 0052 selected = false; 0053 editing = false; 0054 doPaint = true; 0055 0056 mapManager->addedElement(this); 0057 } 0058 0059 CMapElement::~CMapElement() 0060 { 0061 if (mapLevel) 0062 mapManager->getActiveView()->deletedElement(mapLevel); 0063 } 0064 0065 /** This method is used to get the level that the element is in */ 0066 CMapLevel *CMapElement::getLevel(void) 0067 { 0068 return mapLevel; 0069 } 0070 0071 /** This method is used to set the level that the element is in */ 0072 void CMapElement::setLevel(CMapLevel *level) 0073 { 0074 mapLevel = level; 0075 mapManager->changedElement(this); 0076 } 0077 0078 void CMapElement::paint(QPainter *p,CMapZone *zone) 0079 { 0080 paintElementResize(p,getLowPos(),getSize(),zone); 0081 0082 // If the room is selected then draw the selection indicator 0083 if (getSelected()) 0084 { 0085 //FIXME_jp: Move this somewere else so that it's only caled when the element position changes 0086 generateResizePositions(); 0087 paintResizeHandles (p, resizePos); 0088 } 0089 } 0090 0091 /** This method is used to paint the resize handles 0092 * @param p The painter used to do the painting 0093 * @param resizePos The positions of the handles to be painted */ 0094 void CMapElement::paintResizeHandles(QPainter *p, QList<QRect> &resizePos) 0095 { 0096 p->setPen(getManager()->getMapData()->selectedColor); 0097 p->setBrush(getManager()->getMapData()->selectedColor); 0098 0099 foreach (QRect rect, resizePos) 0100 p->drawRect(rect); 0101 } 0102 0103 CMapZone *CMapElement::getZone(void) 0104 { 0105 if (mapLevel) 0106 return mapLevel->getZone(); 0107 else 0108 return nullptr; 0109 } 0110 0111 /** Used to find out if the mouse is in the element */ 0112 bool CMapElement::mouseInElement(QPoint mousePos) 0113 { 0114 QRect rect = position; 0115 0116 if (rect.left() == rect.right()) 0117 { 0118 rect.setLeft(rect.left()-5); 0119 rect.setRight(rect.right()+5); 0120 } 0121 0122 if (rect.top() == rect.bottom()) 0123 { 0124 rect.setTop(rect.top()-5); 0125 rect.setBottom(rect.bottom()+5); 0126 } 0127 0128 QRegion region(rect,QRegion::Rectangle); 0129 0130 return region.contains(mousePos); 0131 } 0132 0133 /** This method is used to set the elements edit mode state */ 0134 void CMapElement::setEditMode(bool edit) 0135 { 0136 bool oldEdit = editing; 0137 editing = edit; 0138 0139 if (oldEdit!=editing) 0140 { 0141 if (edit) 0142 editModeSetEvent(); 0143 else 0144 editModeUnsetEvent(); 0145 } 0146 } 0147 0148 /** This method is used to find out if the element is in edit mode */ 0149 bool CMapElement::getEditMode(void) 0150 { 0151 return editing; 0152 } 0153 0154 /** Used to find out if the mouse is in the resize box 0155 * @param mousePos The position of the mouse pointer 0156 * @param currentZone A pointer to the current zone 0157 * @return the ID of the resize box, or 0 if not in any */ 0158 int CMapElement::mouseInResize(QPoint mousePos,CMapZone *) 0159 { 0160 int num = 1; 0161 0162 foreach (QRect rect, resizePos) 0163 { 0164 QRegion region(rect,QRegion::Rectangle); 0165 if (region.contains(mousePos)) 0166 return num; 0167 num++; 0168 } 0169 0170 return 0; 0171 } 0172 0173 /** Used to find out if the mouse is in the resize box 0174 * @param mousePos The position of the mouse pointer 0175 * @param currentZone A pointer to the current zone 0176 * @return the ID of the resize box, or 0 if not in any */ 0177 bool CMapElement::elementIn(QRect rect,CMapZone *) 0178 { 0179 QRegion region( rect,QRegion::Rectangle); 0180 0181 return region.contains(position); 0182 } 0183 0184 /** Used to move the element relative to it's current position */ 0185 void CMapElement::moveBy(QPoint offset) 0186 { 0187 position.translate(offset.x(),offset.y()); 0188 } 0189 0190 /** This is used to paint a element while it is being resized 0191 * @param offset The offset of the mouse pointer since the start of the resize operation 0192 * @param p The painter to paint the element too 0193 * @param currentZone The current zone being viewed 0194 * @param resizeId The id of the resize handle being moved */ 0195 void CMapElement::resizePaint(QPoint offset,QPainter *p,CMapZone *currentZone,int resizeId) 0196 { 0197 signed int offsetx = offset.x(); 0198 signed int offsety = offset.y(); 0199 QPoint pos = getLowPos(); 0200 QSize size = getSize(); 0201 0202 // Calc new positions 0203 calcResizeCords(&size,&pos,&offsetx,&offsety,&offset,resizeId); 0204 0205 // Paint the element 0206 paintElementResize(p,pos,size,currentZone); 0207 0208 // Paint resize handles 0209 QList<QRect> tmpResizePos; 0210 generateResizePositions(QRect(pos,size), tmpResizePos); 0211 paintResizeHandles(p, tmpResizePos); 0212 } 0213 0214 void CMapElement::calcResizeCords(QSize *size,QPoint *pos,signed int *offsetx,signed int *offsety,QPoint *offset,int resizeId) 0215 { 0216 int gridWidth = getManager()->getMapData()->gridSize.width(); 0217 int gridHeight = getManager()->getMapData()->gridSize.height(); 0218 0219 switch (resizeId) 0220 { 0221 case 1 : if (size->height()-*offsety<=0) // NORTH 0222 { 0223 offset->setY(size->height()-gridHeight); 0224 *offsety=size->height()-gridHeight; 0225 } 0226 if (size->height()-*offsety >= gridHeight) 0227 { 0228 pos->setY(pos->y()+*offsety); 0229 if (*offsety>0) 0230 *size-=QSize(0,abs(*offsety)); 0231 else 0232 *size+=QSize(0,abs(*offsety)); 0233 } 0234 break; 0235 case 2 : if (size->height()-*offsety<=0) // NORTHEAST 0236 { 0237 offset->setY(size->height()-gridHeight); 0238 *offsety=size->height()-gridHeight; 0239 } 0240 if (size->height()-*offsety >= gridHeight) 0241 { 0242 pos->setY(pos->y()+offset->y()); 0243 if (*offsety>0) 0244 size->setHeight(size->height()-abs(*offsety)); 0245 else 0246 size->setHeight(size->height()+abs(*offsety)); 0247 } 0248 size->setWidth(size->width()+*offsetx); 0249 break; 0250 case 3 : *size+=QSize(*offsetx,0); // EAST 0251 break; 0252 case 4 : *size+=QSize(*offsetx,*offsety); // SOUTHEAST 0253 break; 0254 case 5 : *size+=QSize(0,*offsety); // SOUTH 0255 break; 0256 case 6 : *size+=QSize(0,*offsety); // SOUTHWEST 0257 if (size->width()-*offsetx<=0) 0258 { 0259 offset->setX(size->width()-gridWidth); 0260 *offsetx = size->width()-gridWidth; 0261 } 0262 if (size->width()-*offsetx >= gridWidth) 0263 { 0264 pos->setX(pos->x()+*offsetx); 0265 if (*offsetx>0) 0266 size->setWidth(size->width()-abs(*offsetx)); 0267 else 0268 size->setWidth(size->width()+abs(*offsetx)); 0269 } 0270 0271 break; 0272 case 7 : if (size->width()-*offsetx<=0) // WEST 0273 { 0274 offset->setX(size->width()-gridWidth); 0275 *offsetx = size->width()-gridWidth; 0276 } 0277 if (size->width()-*offsetx >= gridWidth) 0278 { 0279 pos->setX(pos->x()+*offsetx); 0280 if (*offsetx>0) 0281 size->setWidth(size->width()-abs(*offsetx)); 0282 else 0283 size->setWidth(size->width()+abs(*offsetx)); 0284 } 0285 break; 0286 case 8 : if (size->width()-*offsetx<=0) // NORTHWEST 0287 { 0288 offset->setX(size->width()-gridWidth); 0289 *offsetx = size->width()-gridWidth; 0290 } 0291 if (size->height()-*offsety<=0) 0292 { 0293 offset->setY(size->height()-gridHeight); 0294 *offsety=size->height()-gridHeight; 0295 } 0296 if (size->width()-*offsetx >= gridWidth && 0297 size->height()-*offsety >= gridHeight) 0298 { 0299 *pos+=*offset; 0300 if (*offsetx>0) 0301 size->setWidth(size->width()-abs(*offsetx)); 0302 else 0303 size->setWidth(size->width()+abs(*offsetx)); 0304 0305 if (*offsety>0) 0306 size->setHeight(size->height()-abs(*offsety)); 0307 else 0308 size->setHeight(size->height()+abs(*offsety)); 0309 } 0310 break; 0311 0312 default : break; 0313 } 0314 0315 if (size->width() < gridWidth) 0316 { 0317 size->setWidth(gridWidth); 0318 } 0319 0320 if (size->height() < gridHeight) 0321 { 0322 size->setHeight(gridHeight); 0323 } 0324 } 0325 0326 /** This is used to resize the element */ 0327 void CMapElement::resize(QPoint offset,int resizeId) 0328 { 0329 QSize size = getSize(); 0330 QPoint pos = getLowPos(); 0331 signed int offsetx = offset.x(); 0332 signed int offsety = offset.y(); 0333 0334 // Clac the new positions 0335 calcResizeCords(&size,&pos,&offsetx,&offsety,&offset,resizeId); 0336 0337 0338 CMapCmdElementProperties *cmd = new CMapCmdElementProperties(mapManager,i18n("Resize Element"),this); 0339 KConfigGroup grp = cmd->getOrgProperties(); 0340 grp.writeEntry("X",getX()); 0341 grp.writeEntry("Y",getY()); 0342 grp.writeEntry("Width",getWidth()); 0343 grp.writeEntry("Height",getHeight()); 0344 grp = cmd->getNewProperties(); 0345 grp.writeEntry("X",pos.x()); 0346 grp.writeEntry("Y",pos.y()); 0347 grp.writeEntry("Width",size.width()); 0348 grp.writeEntry("Height",size.height()); 0349 mapManager->addCommand(cmd); 0350 /* 0351 setLowPos(pos); 0352 setSize(size); 0353 */ 0354 } 0355 0356 /** Used to set the position of the top left of the element */ 0357 void CMapElement::setLowPos(QPoint pos) 0358 { 0359 int width = position.width(); 0360 int height = position.height(); 0361 position.setX(pos.x()); 0362 position.setY(pos.y()); 0363 position.setWidth(width); 0364 position.setHeight(height); 0365 0366 geometryChanged(); 0367 } 0368 0369 0370 /** This method is used to calculate the positions of the resize handles */ 0371 void CMapElement::generateResizePositions() 0372 { 0373 generateResizePositions(getRect(), resizePos); 0374 } 0375 0376 /** This method is used to calc the resize handle positions for a rectangle 0377 * object and add them to a list 0378 * @param rect The coridantes of the object 0379 * @param resizePos The list to add the positions too */ 0380 void CMapElement::generateResizePositions(QRect rect, QList<QRect> &resizePos) 0381 { 0382 int width = rect.width(); 0383 int height = rect.height(); 0384 int x1 = rect.left()+1; 0385 int y1 = rect.top()+1; 0386 int x2 = rect.right(); 0387 int y2 = rect.bottom(); 0388 0389 resizePos.clear(); 0390 resizePos.append(QRect(x1+(width/2)-5,y1-4,7,7)); // NORTH 0391 resizePos.append(QRect(x2-4,y1-4,7,7)); // NORTHEAST 0392 resizePos.append(QRect(x2-4,y1+(height/2)-5,7,7)); // EAST 0393 resizePos.append(QRect(x2-4,y2-4,7,7)); // SOUTHEAST 0394 resizePos.append(QRect(x1+(width/2)-5,y2-4,7,7)); // SOUTH 0395 resizePos.append(QRect(x1-4,y2-4,7,7)); // SOUTHWEST 0396 resizePos.append(QRect(x1-4,y1+(height/2)-5,7,7)); // WEST 0397 resizePos.append(QRect(x1-4,y1-4,7,7)); // NORTHWEST 0398 } 0399 0400 /** Used to load the properties of the element from a list of properties */ 0401 void CMapElement::loadProperties(KConfigGroup grp) 0402 { 0403 QPoint lowPos = getLowPos(); 0404 lowPos.setX(grp.readEntry("X",getX())); 0405 lowPos.setY(grp.readEntry("Y",getY())); 0406 setLowPos(lowPos); 0407 QSize size = getSize(); 0408 size.setWidth(grp.readEntry("Width",getWidth())); 0409 size.setHeight(grp.readEntry("Height",getHeight())); 0410 setSize(size); 0411 } 0412 0413 /** Used to save the properties of the element to a list of properties */ 0414 void CMapElement::saveProperties(KConfigGroup grp) 0415 { 0416 grp.writeEntry("Type",(int)getElementType()); 0417 grp.writeEntry("X",getX()); 0418 grp.writeEntry("Y",getY()); 0419 grp.writeEntry("Width",getWidth()); 0420 grp.writeEntry("Height",getHeight()); 0421 if (getZone()) 0422 grp.writeEntry("Zone",getZone()->getZoneID()); 0423 else 0424 grp.writeEntry("Zone",-1); 0425 0426 CMapLevel *level = getLevel(); 0427 if (level) 0428 { 0429 grp.writeEntry("Level",level->getLevelID()); 0430 } 0431 } 0432 0433 /** Used to save the element as an XML object 0434 * @param properties The XML object to save the properties too 0435 * @param doc The XML Document */ 0436 void CMapElement::saveQDomElement(QDomDocument *,QDomElement *properties) 0437 { 0438 if (properties) 0439 { 0440 properties->setAttribute("Type",(int)getElementType()); 0441 properties->setAttribute("X",getX()); 0442 properties->setAttribute("Y",getY()); 0443 properties->setAttribute("Width",getWidth()); 0444 properties->setAttribute("Height",getHeight()); 0445 } 0446 else 0447 { 0448 qDebug() << "CMapElement::saveQDomElement - properties pointer is null"; 0449 } 0450 } 0451 0452 /** Used to load the properties from a XML object */ 0453 void CMapElement::loadQDomElement(QDomElement *properties) 0454 { 0455 if (properties) 0456 { 0457 int x = properties->attribute("X",QString::number(getX())).toInt(); 0458 int y = properties->attribute("Y",QString::number(getY())).toInt(); 0459 setLowPos(QPoint (x,y)); 0460 0461 setWidth(properties->attribute("Width",QString::number(getWidth())).toInt()); 0462 setHeight(properties->attribute("Height",QString::number(getHeight())).toInt()); 0463 } 0464 } 0465 0466 /** This method is used to put a element in a selected state 0467 * @param sel The selected state to set the element too */ 0468 void CMapElement::setSelected(bool sel) 0469 { 0470 selected = sel; 0471 mapManager->changedElement(this); 0472 } 0473 0474 /** This method is used to get the selected state of the element 0475 * @return The selected state of the element */ 0476 bool CMapElement::getSelected(void) 0477 { 0478 return selected; 0479 } 0480 0481 /** 0482 * This is used to read a color value from a XML object 0483 * @param e The XML object 0484 * @param key The key of the color to read 0485 * @param defaultCol If the color is not found then this will be used 0486 * @return The Color value 0487 */ 0488 QColor CMapElement::readColor(QDomElement *e,QString key,QColor defaultCol) 0489 { 0490 if (!e) 0491 { 0492 return defaultCol; 0493 } 0494 0495 // Find Color element 0496 QDomNode n = e->namedItem(key); 0497 if (n.isNull()) 0498 { 0499 return defaultCol; 0500 } 0501 0502 QDomElement e2 = n.toElement(); 0503 if (e2.isNull() ) 0504 { 0505 return defaultCol; 0506 } 0507 0508 // Get color values 0509 QString red = e2.attribute("Red","Not Found"); 0510 QString green = e2.attribute("Green","Not Found"); 0511 QString blue = e2.attribute("Blue","Not Found"); 0512 0513 if (red=="Not Found" || green=="Not Found" || blue=="Not Found") 0514 { 0515 return defaultCol; 0516 } 0517 0518 QColor col(red.toInt(),green.toInt(),blue.toInt()); 0519 0520 return col; 0521 } 0522 0523 /** 0524 * This is used to write a color value to a XML object 0525 * @param doc The XML document 0526 * @param e The XML object 0527 * @param key The key of the color to write 0528 * @param col The color value to write 0529 */ 0530 void CMapElement::writeColor(QDomDocument *doc,QDomElement *e,QString key,QColor col) 0531 { 0532 QDomElement color = doc->createElement (key); 0533 0534 color.setAttribute("Red",col.red()); 0535 color.setAttribute("Green",col.green()); 0536 color.setAttribute("Blue",col.blue()); 0537 0538 e->appendChild(color); 0539 } 0540 0541 /** 0542 * This method is used to read a int value from a XML object 0543 * @param e The XML object 0544 * @param key The key of the int to read 0545 * @param defaultCol If the int is not found then this will be used 0546 * @return The int value 0547 */ 0548 int CMapElement::readInt(QDomElement *e,QString key,int i) 0549 { 0550 return e->attribute(key,QString::number(i)).toInt(); 0551 } 0552 0553 /** 0554 * This metod is used to write a int value to a XML object 0555 * @param doc The XML document 0556 * @param e The XML object 0557 * @param key The key of the int to write 0558 * @param i The int value to write 0559 */ 0560 void CMapElement::writeInt(QDomDocument *,QDomElement *e,QString key,int i) 0561 { 0562 e->setAttribute(key,i); 0563 } 0564 0565 0566 /** 0567 * This method is used to read a boolean value from a XML object 0568 * @param e The XML object 0569 * @param key The key of the boolean to read 0570 * @param defaultCol If the boolean is not found then this will be used 0571 * @return The boolean value 0572 */ 0573 bool CMapElement::readBool(QDomElement *e,QString key,bool b) 0574 { 0575 QString defaultStr = b ? "true" : "false"; 0576 return (e->attribute(key,defaultStr)=="true"); 0577 } 0578 0579 /** 0580 * This metod is used to write a boolean value to a XML object 0581 * @param doc The XML document 0582 * @param e The XML object 0583 * @param key The key of the boolean to write 0584 * @param b The bolean value to write 0585 */ 0586 void CMapElement::writeBool(QDomElement *e,QString key,bool b) 0587 { 0588 e->setAttribute(key, b ? "true" : "false"); 0589 } 0590 0591 #include "moc_cmapelement.cpp"