File indexing completed on 2023-10-01 04:14:06

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