File indexing completed on 2024-04-14 04:00:18

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"