File indexing completed on 2024-06-02 04:05:33

0001 /***************************************************************************
0002                                cmaptoolselect.cpp
0003                              -------------------
0004     begin                : Tue May 1 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 "cmaptoolselect.h"
0019 
0020 #include "../../../cmapmanager.h"
0021 #include "../../../cmapelement.h"
0022 #include "../../../cmapview.h"
0023 #include "../../../cmaplevel.h"
0024 #include "../../../cmappath.h"
0025 #include "../cmapcmdmoveelements.h"
0026 
0027 #include <QCursor>
0028 #include <QApplication>
0029 
0030 #include <KLocalizedString>
0031 
0032 CMapToolSelect::CMapToolSelect(KActionCollection *actionCollection,CMapManager *manager)
0033         : CMapToolBase(actionCollection,
0034                        i18n("Select"),
0035                        QIcon::fromTheme("kmud_select.png"),
0036                        manager,"toolsSelect",nullptr)
0037 {
0038 
0039     bDragging = false;
0040     connect (&mouseDownTimer ,SIGNAL(timeout()),SLOT(slotStartDraging()));
0041 }
0042 
0043 CMapToolSelect::~CMapToolSelect()
0044 {
0045 }
0046 
0047 void CMapToolSelect::paint(QPainter *p)
0048 {
0049   if (!bDragging) return;
0050 
0051   int gridWidth = mapManager->getMapData()->gridSize.width();
0052   int gridHeight = mapManager->getMapData()->gridSize.height();
0053 
0054   CMapLevel *currentLevel = mapManager->getActiveView()->getCurrentlyViewedLevel();
0055   QList<CMapElement *> lst = currentLevel->getAllElements();
0056   if (moveDrag)
0057   {
0058     // This is a element move/drag operation
0059     p->setPen(Qt::black);
0060 
0061     QPoint offset;
0062 
0063     offset.setX((((int)(lastDrag.x() / gridWidth)) * gridWidth) - (((int)(mouseDrag.x()/gridWidth))*gridWidth));
0064     offset.setY((((int)(lastDrag.y() / gridHeight)) * gridHeight) - (((int)(mouseDrag.y()/gridHeight))*gridHeight));
0065 
0066     foreach (CMapElement *element, lst)
0067       if (element->getSelected())
0068         element->dragPaint(offset,p,currentLevel->getZone());
0069   }
0070   else if (resizeDrag > 0)
0071   {
0072     QPoint offset;
0073 
0074     offset.setX(((((int)(lastDrag.x() / gridWidth)) * gridWidth) - (((int)((mouseDrag.x()-6)/gridWidth))*gridWidth))-gridWidth);
0075     offset.setY(((((int)(lastDrag.y() / gridHeight)) * gridHeight) - (((int)((mouseDrag.y()-6)/gridHeight))*gridHeight))-gridHeight);           
0076 
0077     foreach (CMapElement *element, lst)
0078       if (element->getSelected())
0079         element->resizePaint(offset,p,currentLevel->getZone(),resizeDrag);
0080   }
0081   else if (m_editDrag > 0)
0082   {
0083     foreach (CMapElement *element, lst)
0084       if (element->getElementType()==PATH && element->getEditMode())
0085         ((CMapPath *)element)->editPaint(lastDrag,p,currentLevel->getZone(),m_editDrag);
0086   }
0087   else
0088   {
0089     // This is a element move/drag operation
0090     p->setPen(QColor(128, 128, 128, 64));
0091     p->setBrush(QColor(0, 128, 255, 32));
0092     p->drawRect(mouseDrag.x(),mouseDrag.y(),lastDrag.x()-mouseDrag.x(),lastDrag.y()-mouseDrag.y());
0093   }
0094 }
0095 
0096 /** Called when the tool recives a mouse press event */
0097 void CMapToolSelect::mousePressEvent(QPoint mousePos, QMouseEvent *, CMapLevel *currentLevel)
0098 {
0099   moveDrag = false;
0100   resizeDrag = 0;
0101   m_editDrag = 0;
0102 
0103   QList<CMapElement *> lst = currentLevel->getAllElements();
0104 
0105   // Check to see if the mouse was pressed in an element
0106   foreach (CMapElement *element, lst)
0107   {
0108     // Is a edit drag in operation
0109     if (element->getElementType()==PATH && element->getEditMode())
0110     {
0111       CMapPath *path = (CMapPath *)element;
0112       m_editDrag = path->mouseInEditBox(mousePos,currentLevel->getZone());
0113 
0114       if (m_editDrag > 0)
0115       {
0116         break;
0117       }
0118     }
0119 
0120     // Is a resize drag in operation
0121     resizeDrag = element->mouseInResize(mousePos,currentLevel->getZone());
0122     if (resizeDrag > 0 && element->getSelected())
0123     {
0124       break;
0125     }
0126     else
0127     {
0128       resizeDrag = 0;
0129       if (element->mouseInElement(mousePos))
0130       {
0131         moveDrag = true;
0132       }
0133     }
0134   }
0135 
0136   if (resizeDrag > 0 || m_editDrag > 0)
0137   {
0138     // Repaint the map without the elements being resized
0139     foreach (CMapElement *element, lst)
0140     {
0141       if (element->getSelected())
0142       {
0143         element->setDoPaint(false);
0144       }
0145 
0146       if (element->getEditMode() && element->getElementType()==PATH)
0147       {
0148         ((CMapPath *)element)->setDontPaintBend(m_editDrag);
0149       }
0150     }
0151 
0152     mapManager->redrawAllViews();
0153   }
0154 
0155   if (moveDrag || resizeDrag > 0 || m_editDrag > 0)
0156   {
0157     // The mouse was pressed in an element so this is a element move/drag operation
0158     mouseDrag =  mousePos;
0159     lastDrag = QPoint (-100,-100);
0160   }
0161   else
0162   {
0163     // The mouse was not pressed in a element so this is a rectangle drag selection operation
0164     mouseDrag = lastDrag = mousePos;
0165   }
0166 
0167   mapManager->levelChanged(currentLevel);
0168 
0169   mouseDownTimer.start(150);
0170 }
0171 
0172 QPoint CMapToolSelect::alignToGrid(QPoint offset)
0173 {
0174   int gridWidth = mapManager->getMapData()->gridSize.width();
0175   int gridHeight = mapManager->getMapData()->gridSize.height();
0176 
0177   offset.setX(offset.x() - offset.x() % gridWidth);
0178   offset.setY(offset.y() - offset.y() % gridHeight);
0179 
0180   return offset;
0181 }
0182 
0183 /** Called when the tool recives a mouse release event */
0184 void CMapToolSelect::mouseReleaseEvent(QPoint mousePos, QMouseEvent *e, CMapLevel *currentLevel)
0185 {
0186   QList<CMapElement *> lst = currentLevel->getAllElements();
0187 
0188   mouseDownTimer.stop();
0189 
0190   // Was a drag operation performed
0191   if (bDragging)
0192   {
0193     // Yes a drag is in action
0194     if (moveDrag)
0195     {
0196       // An element was draged to a new position so move it
0197       moveElement(alignToGrid(mousePos) - alignToGrid(mouseDrag), currentLevel);
0198     }
0199     else if (resizeDrag > 0)
0200     {
0201       // An element was resized so change it's size
0202       resizeElements(mousePos,currentLevel);
0203     }
0204     else if (m_editDrag > 0)
0205     {
0206       foreach (CMapElement *element, lst)
0207       {
0208         if (element->getElementType()==PATH && element->getEditMode())
0209         {
0210           mapManager->openCommandGroup(i18n("Move Bend"));
0211           CMapPath *path = (CMapPath *) element;
0212 
0213           path->setDontPaintBend(0);
0214           path->moveBendWithUndo(m_editDrag,mousePos);
0215           if (path->getOpsitePath())
0216           {
0217             path->getOpsitePath()->moveBendWithUndo(m_editDrag,mousePos);
0218           }
0219           mapManager->closeCommandGroup();
0220           break;
0221         }
0222       }
0223     }
0224     else
0225     {
0226       bool found = false;
0227 
0228       // A rectangle selection operation was performed
0229       if (!(QApplication::keyboardModifiers() & Qt::ControlModifier))
0230       {             
0231         //FIXME_jp: unselectElements should return a bool like in kmud1
0232         mapManager->unselectElements(currentLevel);
0233         found = true;
0234       }
0235 
0236       int x1 = mouseDrag.x() < lastDrag.x() ? mouseDrag.x() : lastDrag.x();
0237       int y1 = mouseDrag.y() < lastDrag.y() ? mouseDrag.y() : lastDrag.y();
0238       int x2 = mouseDrag.x() >= lastDrag.x() ? mouseDrag.x() : lastDrag.x();
0239       int y2 = mouseDrag.y() >= lastDrag.y() ? mouseDrag.y() : lastDrag.y();
0240       QRect area = QRect(QPoint(x1,y1),QPoint(x2,y2));
0241 
0242       // Select the elements in the rectangle               
0243       foreach (CMapElement *element, lst)
0244       {
0245         if (element->elementIn(area,currentLevel->getZone()))
0246         {
0247           element->setSelected(true);
0248           found = true;
0249         }
0250       }
0251       if (found)
0252       {
0253         mapManager->levelChanged(currentLevel);
0254       }
0255     }
0256 
0257     bDragging = false;
0258     return;
0259   }
0260 
0261   // If we are shift-clicking, toggle whatever is clicked on. Otherwise unselect everything, then select what got clicked on.
0262   bool shift = e->modifiers() & Qt::ShiftModifier;
0263 
0264   if (!shift)
0265     mapManager->unselectElements(currentLevel);
0266 
0267   foreach (CMapElement *element, lst)
0268   {
0269     if (!element->mouseInElement(mousePos)) continue;
0270     bool sel = shift ? (!element->getSelected()) : true;
0271     element->setSelected(sel);
0272     break;
0273   }
0274 
0275   mapManager->getActiveView()->changed();
0276 }
0277 
0278 void CMapToolSelect::mouseDoubleClickEvent(QPoint mousePos, QMouseEvent *, CMapLevel *currentLevel)
0279 {
0280   // If we double-click on something that is not a room, do nothing
0281   QList<CMapElement *> elements = currentLevel->elementsUnderMouse(mousePos);
0282   CMapRoom *room = nullptr;
0283   foreach (CMapElement *el, elements) {
0284     room = dynamic_cast<CMapRoom *>(el);
0285     if (room) break;
0286   }
0287   if (!room) return;
0288 
0289   // If we do not have a current room, set this room as one.
0290   if (!mapManager->getCurrentRoom()) {
0291     mapManager->setCurrentRoom(room);
0292     return;
0293   }
0294 
0295   // If we do, speedwalk from there to this room.
0296   mapManager->walkPlayerTo(room);
0297 }
0298 
0299 
0300 /** Called when the tool recives a mouse move event */
0301 void CMapToolSelect::mouseMoveEvent(QPoint mousePos, Qt::KeyboardModifiers, Qt::MouseButtons, CMapLevel *)
0302 {
0303   // If a drag operation is not in progress then return
0304   if (!bDragging) return;
0305 
0306   // Make sure this is not the same position as the last one
0307   if (lastDrag!=mousePos)
0308   {
0309     lastDrag=mousePos;
0310     mapManager->getActiveView()->requestPaint();
0311   }
0312 }
0313 
0314 /** This is called when a key is pressed */
0315 void CMapToolSelect::keyPressEvent(QKeyEvent *e)
0316 {
0317   int x = 0, y = 0;
0318   if (e->key() == Qt::Key_Left) x = -1;
0319   else if (e->key() == Qt::Key_Right) x = 1;
0320   else if (e->key() == Qt::Key_Up) y = -1;
0321   else if (e->key() == Qt::Key_Down) y = 1;
0322   else return;
0323 
0324   int gridWidth = mapManager->getMapData()->gridSize.width();
0325   int gridHeight = mapManager->getMapData()->gridSize.height();
0326 
0327   QPoint offset(gridWidth * x, gridHeight * y);
0328   moveElement(offset, mapManager->getActiveView()->getCurrentlyViewedLevel());
0329 }
0330 
0331 /** This function called when a tool is selected */
0332 void CMapToolSelect::toolSelected(void)
0333 {
0334     CMapView *view = mapManager->getActiveView();
0335     if (view)
0336     {
0337         view->setMouseTracking(false);
0338         view->setCursor(Qt::ArrowCursor);
0339     }
0340 }
0341 
0342 /** This function is called when a tool is unselected */
0343 void CMapToolSelect::toolUnselected(void)
0344 {
0345     CMapView *view = mapManager->getActiveView();
0346     if (view)
0347         mapManager->unselectElements(view->getCurrentlyViewedLevel());
0348 }
0349 
0350 /** Used to move elements */
0351 void CMapToolSelect::moveElement(QPoint offset, CMapLevel *currentLevel)
0352 {
0353   moveDrag = false;
0354 
0355   offset = alignToGrid(offset);
0356 
0357   CMapCmdMoveElements *cmd = new CMapCmdMoveElements(mapManager, offset);
0358 
0359   bool found = false;
0360   QList<CMapElement *> lst = currentLevel->getAllElements();
0361   foreach (CMapElement *element, lst)
0362     if (element->getSelected()) {
0363       cmd->addElement(element);
0364       found = true;
0365     }
0366 
0367   if (found)
0368     mapManager->addCommand(cmd);
0369   else
0370     delete cmd;
0371 }
0372 
0373 /** Used to resize the selected elements */
0374 void CMapToolSelect::resizeElements(QPoint mousePos,CMapLevel *currentLevel)
0375 {
0376   int gridWidth = mapManager->getMapData()->gridSize.width();
0377   int gridHeight = mapManager->getMapData()->gridSize.height();
0378 
0379   QPoint offset;
0380   offset.setX(((((int)(mousePos.x() / gridWidth)) * gridWidth) - (((int)((mouseDrag.x()-6)/gridWidth))*gridWidth))-gridWidth);
0381   offset.setY(((((int)(mousePos.y() / gridHeight)) * gridHeight) - (((int)((mouseDrag.y()-6)/gridHeight))*gridHeight))-gridHeight);
0382 
0383   QList<CMapElement *> lst = currentLevel->getAllElements();
0384   foreach (CMapElement *element, lst)
0385     if (element->getSelected())
0386     {
0387       element->resize(offset,resizeDrag);
0388       element->setDoPaint(true);
0389     }
0390 
0391   resizeDrag = 0;
0392   mapManager->levelChanged(currentLevel);
0393 }
0394 
0395 ///////////////////////////////////// SLOTS /////////////////////////////////////////////////
0396 
0397 /** Called when a rectange drag opertion is performed */
0398 void CMapToolSelect::slotStartDraging(void)
0399 {
0400   bDragging = true;
0401   mouseDownTimer.stop();
0402 
0403   CMapView *view =  mapManager->getActiveView();    
0404   CMapLevel *currentLevel = view->getCurrentlyViewedLevel();
0405 
0406   if (!currentLevel) return;
0407 
0408   QList<CMapElement *> lst = currentLevel->elementsUnderMouse(mouseDrag);
0409   foreach (CMapElement *element, lst)
0410     element->setSelected(true);
0411 }
0412 
0413 #include "moc_cmaptoolselect.cpp"