/*************************************************************************** * Copyright (C) 2008-2013 by Heiko Koehn - KoehnHeiko@googlemail.com * * Copyright (C) 2013-2016 by Stephen Lyons - slysven@virginmedia.com * * Copyright (C) 2014 by Ahmed Charles - acharles@outlook.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "T2DMap.h" #include "Host.h" #include "TArea.h" #include "TConsole.h" #include "TEvent.h" #include "TMap.h" #include "TRoom.h" #include "TRoomDB.h" #include "dlgMapper.h" #include "dlgRoomExits.h" #include "pre_guard.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "post_guard.h" T2DMap::T2DMap(QWidget* parent) : QWidget(parent) , mDialogLock(false) , mMultiSelectionListWidget(this) , mMultiSelectionHighlightRoomId(-1) , mIsSelectionSorting(true) , mIsSelectionSortByNames(false) , mIsSelectionUsingNames(false) , mpMap() , _rx() , _ry() , mTX() , mTY() , mChosenRoomColor() , xspan() , yspan() , mMultiSelection() , mPopupMenu() , mRID() , mAID() , mOx() , mOy() , mOz() , arealist_combobox() , mpCurrentLineStyle() , mpCurrentLineColor() , mpCurrentLineArrow() , mCurrentLineArrow() , mShowGrid() { mMultiSelectionListWidget.setColumnCount(2); mMultiSelectionListWidget.hideColumn(1); QStringList headerLabels; headerLabels << tr("Room Id") << tr("Room Name"); mMultiSelectionListWidget.setHeaderLabels(headerLabels); mMultiSelectionListWidget.setToolTip( tr("

Click on a line to select or deselect that room number (with the given name if the rooms are named) to add or remove the room from the selection. Click on the " "relevant header to sort by that method. Note that the name column willl only show if at least one of the rooms has a name.

")); mMultiSelectionListWidget.setUniformRowHeights(true); mMultiSelectionListWidget.setItemsExpandable(false); mMultiSelectionListWidget.setSelectionMode(QAbstractItemView::MultiSelection); // Was ExtendedSelection mMultiSelectionListWidget.setRootIsDecorated(false); QSizePolicy multiSelectionSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); mMultiSelectionListWidget.setSizePolicy(multiSelectionSizePolicy); mMultiSelectionListWidget.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); mMultiSelectionListWidget.setFrameShape(QFrame::NoFrame); mMultiSelectionListWidget.setFrameShadow(QFrame::Plain); mMultiSelectionListWidget.header()->setProperty("showSortIndicator", QVariant(true)); mMultiSelectionListWidget.header()->setSectionsMovable(false); mMultiSelectionListWidget.header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); mMultiSelectionListWidget.header()->setStretchLastSection(true); mMultiSelectionListWidget.setSortingEnabled(mIsSelectionSorting); mMultiSelectionListWidget.resize(120, 100); mMultiSelectionListWidget.move(0, 0); mMultiSelectionListWidget.hide(); connect(&mMultiSelectionListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(slot_roomSelectionChanged())); mMoveLabel = false; mLabelHilite = false; xzoom = 20; yzoom = 20; gzoom = 20; mPick = false; mTarget = 0; //mRoomSelection = 0; mStartSpeedWalk = false; mRoomBeingMoved = false; mPHighlightMove = QPoint(width() / 2, height() / 2); mNewMoveAction = false; mFontHeight = 20; mShowRoomID = false; rSize = 0.5; eSize = 3.0; mShiftMode = false; mShowInfo = true; mBubbleMode = false; mMapperUseAntiAlias = true; mMoveLabel = false; mCustomLineSelectedRoom = 0; mCustomLineSelectedExit = ""; mCustomLineSelectedPoint = -1; mCustomLinesRoomFrom = 0; mCustomLinesRoomTo = 0; mSizeLabel = false; gridMapSizeChange = true; isCenterViewCall = false; mCurrentLineColor = QColor(255, 255, 100); //setFocusPolicy( Qt::ClickFocus); } void T2DMap::init() { isCenterViewCall = false; QTime _time; _time.start(); //setFocusPolicy( Qt::ClickFocus); if (!mpMap) { return; } gridMapSizeChange = false; eSize = mpMap->mpHost->mLineSize; rSize = mpMap->mpHost->mRoomSize; mMapperUseAntiAlias = mpHost->mMapperUseAntiAlias; mPixMap.clear(); QFont f = QFont(QFont("Bitstream Vera Sans Mono", 20, QFont::Normal)); //( QFont("Monospace", 10, QFont::Courier) ); f.setPointSize(gzoom); f.setBold(true); int j = 0; for (int k = 1; k < 17; k++) { for (int i = 1; i < 255; i++) { j++; QPixmap b(gzoom, gzoom); b.fill(Qt::transparent); QPainter p(&b); QColor c = _getColor(k); p.setPen(c); p.setFont(f); QRect r(0, 0, gzoom, gzoom); p.drawText(r, Qt::AlignHCenter | Qt::AlignVCenter, QChar(i)); mPixMap[j] = b; } } mCurrentLineArrow = true; mCurrentLineColor = QColor("red"); mCurrentLineStyle = QString("solid line"); // Configure custom line drawing starting points here } QColor T2DMap::_getColor(int id) { QColor c; switch (id) { case 1: c = mpHost->mRed_2; break; case 2: c = mpHost->mGreen_2; break; case 3: c = mpHost->mYellow_2; break; case 4: c = mpHost->mBlue_2; break; case 5: c = mpHost->mMagenta_2; break; case 6: c = mpHost->mCyan_2; break; case 7: c = mpHost->mWhite_2; break; case 8: c = mpHost->mBlack_2; break; case 9: c = mpHost->mLightRed_2; break; case 10: c = mpHost->mLightGreen_2; break; case 11: c = mpHost->mLightYellow_2; break; case 12: c = mpHost->mLightBlue_2; break; case 13: c = mpHost->mLightMagenta_2; break; case 14: c = mpHost->mLightCyan_2; break; case 15: c = mpHost->mLightWhite_2; break; case 16: c = mpHost->mLightBlack_2; } return c; } QColor T2DMap::getColor(int id) { QColor c; TRoom* pR = mpMap->mpRoomDB->getRoom(id); if (!pR) { return c; } int env = pR->environment; if (mpMap->envColors.contains(env)) { env = mpMap->envColors[env]; } else { if (!mpMap->customEnvColors.contains(env)) { env = 1; } } switch (env) { case 1: c = mpHost->mRed_2; break; case 2: c = mpHost->mGreen_2; break; case 3: c = mpHost->mYellow_2; break; case 4: c = mpHost->mBlue_2; break; case 5: c = mpHost->mMagenta_2; break; case 6: c = mpHost->mCyan_2; break; case 7: c = mpHost->mWhite_2; break; case 8: c = mpHost->mBlack_2; break; case 9: c = mpHost->mLightRed_2; break; case 10: c = mpHost->mLightGreen_2; break; case 11: c = mpHost->mLightYellow_2; break; case 12: c = mpHost->mLightBlue_2; break; case 13: c = mpHost->mLightMagenta_2; break; case 14: c = mpHost->mLightCyan_2; break; case 15: c = mpHost->mLightWhite_2; break; case 16: c = mpHost->mLightBlack_2; break; default: //user defined room color if (!mpMap->customEnvColors.contains(env)) { break; } c = mpMap->customEnvColors[env]; } return c; } void T2DMap::shiftDown() { mShiftMode = true; mOy--; update(); } void T2DMap::toggleShiftMode() { mShiftMode = !mShiftMode; update(); } void T2DMap::shiftUp() { mShiftMode = true; mOy++; update(); } void T2DMap::shiftLeft() { mShiftMode = true; mOx--; update(); } void T2DMap::shiftRight() { mShiftMode = true; mOx++; update(); } void T2DMap::shiftZup() { mShiftMode = true; mOz++; update(); } void T2DMap::shiftZdown() { mShiftMode = true; mOz--; update(); } void T2DMap::slot_switchArea(QString name) { Host* pHost = mpHost; if (!pHost || !mpMap) { return; } int playerRoomId = mpMap->mRoomIdHash.value(pHost->getName()); TRoom* pPlayerRoom = mpMap->mpRoomDB->getRoom(playerRoomId); int playerAreaId = -2; // Cannot be valid (but -1 can be)! if (pPlayerRoom) { playerAreaId = pPlayerRoom->getArea(); } QMapIterator it(mpMap->mpRoomDB->getAreaNamesMap()); while (it.hasNext()) { it.next(); int areaID = it.key(); QString _n = it.value(); TArea* pA = mpMap->mpRoomDB->getArea(areaID); if (name == _n && pA) { mAID = areaID; mShiftMode = true; pA->calcSpan(); if (areaID == playerAreaId) { // We are switching back to the area that has the player in it // recenter view on that room! mOx = pPlayerRoom->x; mOy = -pPlayerRoom->y; // Map y coordinates are reversed on 2D map! mOz = pPlayerRoom->z; repaint(); mpMap->set3DViewCenter(mAID, mOx, -mOy, mOz); // Pass the coordinates to the TMap instance to pass to the 3D mapper return; // escape early } bool isAValidRoomFound = false; if (!pA->ebenen.contains(mOz)) { // If the current map z-coordinate value is NOT one that is used // for this then get the FIRST room in the area and goto the // mathmatical midpoint of all the rooms on the same // z-coordinate. QSetIterator itRoom(pA->getAreaRooms()); QMap roomsCountLevelMap; // key is z-coordinate, value is count of rooms on that level while (itRoom.hasNext()) { int checkRoomId = itRoom.next(); TRoom* pR = mpMap->mpRoomDB->getRoom(checkRoomId); if (pR) { isAValidRoomFound = true; if (roomsCountLevelMap.contains(pR->z)) { ++roomsCountLevelMap[pR->z]; } else { roomsCountLevelMap[pR->z] = 1; } } } if (isAValidRoomFound) { QMapIterator itRoomsCount(roomsCountLevelMap); itRoomsCount.toBack(); // Start at highest value and work down itRoomsCount.previous(); // This will be Okay as we KNOW there is at least one entry int maxRoomCountOnLevel = 0; int minLevelWithMaxRoomCount = itRoomsCount.key(); // Initalisation value, will get overwritten itRoomsCount.next(); // Return to the back so the previous() in the do loop works correctly do { itRoomsCount.previous(); if (maxRoomCountOnLevel < itRoomsCount.value()) { maxRoomCountOnLevel = itRoomsCount.value(); minLevelWithMaxRoomCount = itRoomsCount.key(); } } while (itRoomsCount.hasPrevious()); // We now have lowest level with the highest number of rooms // Now find the geometry center of the rooms on THAT level // In a similar manner to the getCenterSelection() method itRoom.toFront(); float mean_x = 0.0; float mean_y = 0.0; uint processedRoomCount = 0; QSet pSRoom; // Hold on to relevent rooms for // following step while (itRoom.hasNext()) { TRoom* pR = mpMap->mpRoomDB->getRoom(itRoom.next()); if (!pR || pR->z != minLevelWithMaxRoomCount) { continue; } pSRoom.insert(pR); mean_x += (static_cast(pR->x - mean_x)) / ++processedRoomCount; mean_y += (static_cast(pR->y - mean_y)) / processedRoomCount; } // We now have the position that is the "centre" of the // rooms on this level - just need to find the room nearest // to that: QSetIterator itpRoom(pSRoom); float closestSquareDistance = -1.0; TRoom* pClosestRoom = 0; while (itpRoom.hasNext()) { TRoom* pR = itpRoom.next(); QVector2D meanToRoom(static_cast(pR->x) - mean_x, static_cast(pR->y) - mean_y); if (closestSquareDistance < -0.5) { // Test for first time around loop - for initalisation // Don't use an equality to zero test, we are using floats so // need to allow for a little bit of fuzzzyness! closestSquareDistance = meanToRoom.lengthSquared(); pClosestRoom = pR; } else { float currentRoomSquareDistance = meanToRoom.lengthSquared(); if (closestSquareDistance > currentRoomSquareDistance) { closestSquareDistance = currentRoomSquareDistance; pClosestRoom = pR; } } } mOx = pClosestRoom->x; mOy = -pClosestRoom->y; // Map y coordinates are reversed on 2D map! mOz = pClosestRoom->z; } if (!isAValidRoomFound) { //no rooms, go to 0,0,0 mOx = 0; mOy = 0; mOz = 0; } } else { // Else the selected area DOES have rooms on the same z-coordinate // Now find the geometry center of the rooms on the given level // In a similar manner to the getCenterSelection() method float mean_x = 0.0; float mean_y = 0.0; uint processedRoomCount = 0; QSet pSRoom; // Hold on to relevent rooms for // following step QSetIterator itRoom(pA->getAreaRooms()); while (itRoom.hasNext()) { TRoom* pR = mpMap->mpRoomDB->getRoom(itRoom.next()); if (!pR || pR->z != mOz) { continue; } pSRoom.insert(pR); mean_x += (static_cast(pR->x - mean_x)) / ++processedRoomCount; mean_y += (static_cast(pR->y - mean_y)) / processedRoomCount; } // We now have the position that is the "centre" of the // rooms on this level - just need to find the room nearest // to that: QSetIterator itpRoom(pSRoom); float closestSquareDistance = -1.0; TRoom* pClosestRoom = 0; while (itpRoom.hasNext()) { TRoom* pR = itpRoom.next(); QVector2D meanToRoom(static_cast(pR->x) - mean_x, static_cast(pR->y) - mean_y); if (closestSquareDistance < -0.5) { // Test for first time around loop - for initalisation // Don't use an equality to zero test, we are using floats so // need to allow for a little bit of fuzzzyness! closestSquareDistance = meanToRoom.lengthSquared(); pClosestRoom = pR; } else { float currentRoomSquareDistance = meanToRoom.lengthSquared(); if (closestSquareDistance > currentRoomSquareDistance) { closestSquareDistance = currentRoomSquareDistance; pClosestRoom = pR; } } } if (pClosestRoom) { mOx = pClosestRoom->x; mOy = -pClosestRoom->y; // Map y coordinates are reversed on 2D map! } } repaint(); mpMap->set3DViewCenter(mAID, mOx, -mOy, mOz); // Pass the coordinates to the TMap instance to pass to the 3D mapper return; } } } void T2DMap::paintEvent(QPaintEvent* e) { if (!mpMap) { return; } bool __Pick = mPick; QElapsedTimer __time; __time.start(); QPainter p(this); if (!p.isActive()) { return; } mAreaExitList.clear(); float _w = width(); float _h = height(); if (_w < 10 || _h < 10) { return; } if (_w > _h) { xspan = xzoom * (_w / _h); yspan = xzoom; } else { xspan = yzoom; yspan = yzoom * (_h / _w); } float tx = _w / xspan; float ty = _h / yspan; mTX = tx; mTY = ty; int px, py; QList exitList; QList oneWayExits; TRoom* pPlayerRoom = mpMap->mpRoomDB->getRoom(mpMap->mRoomIdHash.value(mpHost->getName())); if (!pPlayerRoom) { p.drawText(_w / 2, _h / 2, "No map or no valid position."); return; } int ox, oy; // N/U: oz; if (mRID != mpMap->mRoomIdHash.value(mpHost->getName()) && mShiftMode) { mShiftMode = false; } TArea* pAID; TRoom* pRID; int playerArea = pPlayerRoom->getArea(); if ((!__Pick && !mShiftMode) || mpMap->mNewMove) { mShiftMode = true; mpMap->mNewMove = false; // das ist nur hier von Interesse, weil es nur hier einen map editor gibt -> map wird unter Umstaenden nicht geupdated, deshalb force ich mit mNewRoom ein map update bei centerview() if (!mpMap->mpRoomDB->getArea(playerArea)) { return; } mRID = mpMap->mRoomIdHash.value(mpHost->getName()); pRID = mpMap->mpRoomDB->getRoom(mRID); mAID = pRID->getArea(); pAID = mpMap->mpRoomDB->getArea(mAID); if (!pRID || !pAID) { return; } ox = pRID->x; oy = pRID->y * -1; mOx = ox; mOy = oy; mOz = pRID->z; } else { pRID = mpMap->mpRoomDB->getRoom(mRID); pAID = mpMap->mpRoomDB->getArea(mAID); if (!pRID || !pAID) { return; } ox = mOx; oy = mOy; } if (ox * tx > xspan / 2 * tx) { _rx = -(tx * ox - xspan / 2 * tx); } else { _rx = xspan / 2 * tx - tx * ox; } if (oy * ty > yspan / 2 * ty) { _ry = -(ty * oy - yspan / 2 * ty); } else { _ry = yspan / 2 * ty - ty * oy; } px = ox * tx + _rx; py = oy * ty + _ry; TArea* pArea = pAID; int zEbene; zEbene = mOz; float wegBreite = 1 / eSize * tx * rSize; p.fillRect(0, 0, width(), height(), mpHost->mBgColor_2); QPen pen; pen = p.pen(); pen.setColor(mpHost->mFgColor_2); pen.setWidthF(wegBreite); if (mMapperUseAntiAlias) { p.setRenderHint(QPainter::Antialiasing); } else { p.setRenderHint(QPainter::NonCosmeticDefaultPen); } p.setPen(pen); if (mpMap->mapLabels.contains(mAID)) { QMapIterator it(mpMap->mapLabels[mAID]); while (it.hasNext()) { it.next(); if (it.value().pos.z() != mOz) { continue; } if (it.value().text.length() < 1) { mpMap->mapLabels[mAID][it.key()].text = "no text"; } QPointF lpos; int _lx = it.value().pos.x() * tx + _rx; int _ly = it.value().pos.y() * ty * -1 + _ry; lpos.setX(_lx); lpos.setY(_ly); int _lw = abs(it.value().size.width()) * tx; int _lh = abs(it.value().size.height()) * ty; if (!((0 < _lx || 0 < _lx + _lw) && (_w > _lx || _w > _lx + _lw))) { continue; } if (!((0 < _ly || 0 < _ly + _lh) && (_h > _ly || _h > _ly + _lh))) { continue; } QRectF _drawRect = QRect(it.value().pos.x() * tx + _rx, it.value().pos.y() * ty * -1 + _ry, _lw, _lh); if (!it.value().showOnTop) { if (!it.value().noScaling) { p.drawPixmap(lpos, it.value().pix.scaled(_drawRect.size().toSize())); mpMap->mapLabels[mAID][it.key()].clickSize.setWidth(_drawRect.width()); mpMap->mapLabels[mAID][it.key()].clickSize.setHeight(_drawRect.height()); } else { p.drawPixmap(lpos, it.value().pix); mpMap->mapLabels[mAID][it.key()].clickSize.setWidth(it.value().pix.width()); mpMap->mapLabels[mAID][it.key()].clickSize.setHeight(it.value().pix.height()); } } if (it.value().hilite) { _drawRect.setSize(it.value().clickSize); p.fillRect(_drawRect, QColor(255, 155, 55, 190)); } } } if (!pArea->gridMode) { int customLineDestinationTarget = 0; if (mCustomLinesRoomTo > 0) { customLineDestinationTarget = mCustomLinesRoomTo; } else if (mCustomLineSelectedRoom > 0 && !mCustomLineSelectedExit.isEmpty()) { TRoom* pSR = mpMap->mpRoomDB->getRoom(mCustomLineSelectedRoom); if (pSR) { if (mCustomLineSelectedExit == "NW" || mCustomLineSelectedExit == "nw") { customLineDestinationTarget = pSR->getNorthwest(); } else if (mCustomLineSelectedExit == "N" || mCustomLineSelectedExit == "n") { customLineDestinationTarget = pSR->getNorth(); } else if (mCustomLineSelectedExit == "NE" || mCustomLineSelectedExit == "ne") { customLineDestinationTarget = pSR->getNortheast(); } else if (mCustomLineSelectedExit == "UP" || mCustomLineSelectedExit == "up") { customLineDestinationTarget = pSR->getUp(); } else if (mCustomLineSelectedExit == "W" || mCustomLineSelectedExit == "w") { customLineDestinationTarget = pSR->getWest(); } else if (mCustomLineSelectedExit == "E" || mCustomLineSelectedExit == "e") { customLineDestinationTarget = pSR->getEast(); } else if (mCustomLineSelectedExit == "DOWN" || mCustomLineSelectedExit == "down") { customLineDestinationTarget = pSR->getDown(); } else if (mCustomLineSelectedExit == "SW" || mCustomLineSelectedExit == "sw") { customLineDestinationTarget = pSR->getSouthwest(); } else if (mCustomLineSelectedExit == "S" || mCustomLineSelectedExit == "s") { customLineDestinationTarget = pSR->getSouth(); } else if (mCustomLineSelectedExit == "SE" || mCustomLineSelectedExit == "se") { customLineDestinationTarget = pSR->getSoutheast(); } else if (mCustomLineSelectedExit == "IN" || mCustomLineSelectedExit == "in") { customLineDestinationTarget = pSR->getIn(); } else if (mCustomLineSelectedExit == "OUT" || mCustomLineSelectedExit == "out") { customLineDestinationTarget = pSR->getOut(); } else { QMultiMap otherExits = pSR->getOtherMap(); QMapIterator otherExitIt = otherExits; while (otherExitIt.hasNext()) { otherExitIt.next(); if (otherExitIt.value().startsWith("0") || otherExitIt.value().startsWith("1")) { if (otherExitIt.value().mid(1) == mCustomLineSelectedExit) { customLineDestinationTarget = otherExitIt.key(); break; } } else if (otherExitIt.value() == mCustomLineSelectedExit) { customLineDestinationTarget = otherExitIt.key(); break; } } } } } QSetIterator itRoom2(pArea->getAreaRooms()); while (itRoom2.hasNext()) { int _id = itRoom2.next(); TRoom* pR = mpMap->mpRoomDB->getRoom(_id); if (!pR) { continue; } float rx = pR->x * tx + _rx; float ry = pR->y * -1 * ty + _ry; int rz = pR->z; if (rz != zEbene) { continue; } if (pR->customLines.size() == 0) { if (rx < 0 || ry < 0 || rx > _w || ry > _h) { continue; } } else { float miny = pR->min_y * -1 * ty + (float)_ry; float maxy = pR->max_y * -1 * ty + (float)_ry; float minx = pR->min_x * tx + (float)_rx; float maxx = pR->max_x * tx + (float)_rx; if (!((minx > 0.0 || maxx > 0.0) && ((float)_w > minx || (float)_w > maxx))) { continue; } if (!((miny > 0.0 || maxy > 0.0) && ((float)_h > miny || (float)_h > maxy))) { continue; } } pR->rendered = true; exitList.clear(); oneWayExits.clear(); if (pR->customLines.size() > 0) { if (!pR->customLines.contains("N")) { exitList.push_back(pR->getNorth()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getNorth()); if (pER) { if (pER->getSouth() != _id) { oneWayExits.push_back(pR->getNorth()); } } } if (!pR->customLines.contains("NW")) { exitList.push_back(pR->getNorthwest()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getNorthwest()); if (pER) { if (pER->getSoutheast() != _id) { oneWayExits.push_back(pR->getNorthwest()); } } } if (!pR->customLines.contains("E")) { exitList.push_back(pR->getEast()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getEast()); if (pER) { if (pER->getWest() != _id) { oneWayExits.push_back(pR->getEast()); } } } if (!pR->customLines.contains("SE")) { exitList.push_back(pR->getSoutheast()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getSoutheast()); if (pER) { if (pER->getNorthwest() != _id) { oneWayExits.push_back(pR->getSoutheast()); } } } if (!pR->customLines.contains("S")) { exitList.push_back(pR->getSouth()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getSouth()); if (pER) { if (pER->getNorth() != _id) { oneWayExits.push_back(pR->getSouth()); } } } if (!pR->customLines.contains("SW")) { exitList.push_back(pR->getSouthwest()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getSouthwest()); if (pER) { if (pER->getNortheast() != _id) { oneWayExits.push_back(pR->getSouthwest()); } } } if (!pR->customLines.contains("W")) { exitList.push_back(pR->getWest()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getWest()); if (pER) { if (pER->getEast() != _id) { oneWayExits.push_back(pR->getWest()); } } } if (!pR->customLines.contains("NE")) { exitList.push_back(pR->getNortheast()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getNortheast()); if (pER) { if (pER->getSouthwest() != _id) { oneWayExits.push_back(pR->getNortheast()); } } } } else { if (pR->getNorth() > 0) { exitList.push_back(pR->getNorth()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getNorth()); if (pER) { if (pER->getSouth() != _id) { oneWayExits.push_back(pR->getNorth()); } } } if (pR->getNorthwest() > 0) { exitList.push_back(pR->getNorthwest()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getNorthwest()); if (pER) { if (pER->getSoutheast() != _id) { oneWayExits.push_back(pR->getNorthwest()); } } } if (pR->getEast() > 0) { exitList.push_back(pR->getEast()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getEast()); if (pER) { if (pER->getWest() != _id) { oneWayExits.push_back(pR->getEast()); } } } if (pR->getSoutheast() > 0) { exitList.push_back(pR->getSoutheast()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getSoutheast()); if (pER) { if (pER->getNorthwest() != _id) { oneWayExits.push_back(pR->getSoutheast()); } } } if (pR->getSouth() > 0) { exitList.push_back(pR->getSouth()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getSouth()); if (pER) { if (pER->getNorth() != _id) { oneWayExits.push_back(pR->getSouth()); } } } if (pR->getSouthwest() > 0) { exitList.push_back(pR->getSouthwest()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getSouthwest()); if (pER) { if (pER->getNortheast() != _id) { oneWayExits.push_back(pR->getSouthwest()); } } } if (pR->getWest() > 0) { exitList.push_back(pR->getWest()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getWest()); if (pER) { if (pER->getEast() != _id) { oneWayExits.push_back(pR->getWest()); } } } if (pR->getNortheast() > 0) { exitList.push_back(pR->getNortheast()); TRoom* pER = mpMap->mpRoomDB->getRoom(pR->getNortheast()); if (pER) { if (pER->getSouthwest() != _id) { oneWayExits.push_back(pR->getNortheast()); } } } } if (pR->customLines.size() > 0) { QPen oldPen = p.pen(); QMapIterator> itk(pR->customLines); while (itk.hasNext()) { itk.next(); QColor _color; if (_id == mCustomLineSelectedRoom && itk.key() == mCustomLineSelectedExit) { _color.setRed(255); _color.setGreen(155); _color.setBlue(55); } else if (pR->customLinesColor[itk.key()].size() == 3) { _color.setRed(pR->customLinesColor[itk.key()][0]); _color.setGreen(pR->customLinesColor[itk.key()][1]); _color.setBlue(pR->customLinesColor[itk.key()][2]); } else { _color = QColor(Qt::red); } bool _arrow = pR->customLinesArrow[itk.key()]; QString _style = pR->customLinesStyle[itk.key()]; QPointF _cstartP; float ex = pR->x * tx + _rx; float ey = pR->y * ty * -1 + _ry; if (itk.key() == "N") { _cstartP = QPoint(ex, ey - ty / 2); } else if (itk.key() == "NW") { _cstartP = QPoint(ex - tx / 2, ey - ty / 2); } else if (itk.key() == "NE") { _cstartP = QPoint(ex + tx / 2, ey - ty / 2); } else if (itk.key() == "S") { _cstartP = QPoint(ex, ey + ty / 2); } else if (itk.key() == "SW") { _cstartP = QPoint(ex - tx / 2, ey + ty / 2); } else if (itk.key() == "SE") { _cstartP = QPoint(ex + tx / 2, ey + ty / 2); } else if (itk.key() == "W") { _cstartP = QPoint(ex - tx / 2, ey); } else if (itk.key() == "E") { _cstartP = QPoint(ex + tx / 2, ey); } else { _cstartP = QPointF(ex, ey); } QPointF ursprung = QPointF(ex, ey); QPen customLinePen = p.pen(); customLinePen.setCosmetic(mMapperUseAntiAlias); customLinePen.setColor(_color); customLinePen.setCapStyle(Qt::RoundCap); customLinePen.setJoinStyle(Qt::RoundJoin); if (_style == "solid line") { customLinePen.setStyle(Qt::SolidLine); } else if (_style == "dot line") { customLinePen.setStyle(Qt::DotLine); } else if (_style == "dash line") { customLinePen.setStyle(Qt::DashLine); } else if (_style == "dash dot line") { customLinePen.setStyle(Qt::DashDotLine); } else { customLinePen.setStyle(Qt::DashDotDotLine); } QList _pL = itk.value(); if (_pL.size() > 0) { p.setPen(customLinePen); p.drawLine(ursprung, _cstartP); } for (int pk = 0; pk < _pL.size(); pk++) { QPointF _cendP; _cendP.setX(_pL[pk].x() * tx + _rx); _cendP.setY(_pL[pk].y() * ty * -1 + _ry); p.drawLine(_cstartP, _cendP); if (_id == mCustomLineSelectedRoom && itk.key() == mCustomLineSelectedExit) { QPen _savedPen = p.pen(); QPen _pen; QBrush _brush = p.brush(); if (pk == mCustomLineSelectedPoint) { _pen = QPen(QColor(255, 255, 55), _savedPen.width(), Qt::SolidLine, Qt::FlatCap, _savedPen.joinStyle()); // Draw the selected point in yellow not orange. } else { _pen = QPen(_savedPen.color(), _savedPen.width(), Qt::SolidLine, Qt::FlatCap, _savedPen.joinStyle()); } p.setBrush(Qt::NoBrush); // Draw hollow circles not default filled ones! p.setPen(_pen); p.drawEllipse(_cendP, mTX / 4, mTX / 4); p.setPen(_savedPen); p.setBrush(_brush); } if (pk == _pL.size() - 1 && _arrow) { QLineF l0 = QLineF(_cendP, _cstartP); l0.setLength(wegBreite * 5); QPointF _p1 = l0.p1(); QPointF _p2 = l0.p2(); QLineF l1 = QLineF(l0); qreal w1 = l1.angle() - 90.0; QLineF l2; l2.setP1(_p2); l2.setAngle(w1); l2.setLength(wegBreite * 2); QPointF _p3 = l2.p2(); l2.setAngle(l2.angle() + 180.0); QPointF _p4 = l2.p2(); QPolygonF _poly; _poly.append(_p1); _poly.append(_p3); _poly.append(_p4); QBrush brush = p.brush(); brush.setColor(_color); brush.setStyle(Qt::SolidPattern); QPen arrowPen = p.pen(); arrowPen.setCosmetic(mMapperUseAntiAlias); arrowPen.setStyle(Qt::SolidLine); p.setPen(arrowPen); p.setBrush(brush); p.drawPolygon(_poly); } _cstartP = _cendP; } } p.setPen(oldPen); } // N/U: int e = pR->z; // draw exit stubs QMap unitVectors = mpMap->unitVectors; for (int direction : pR->exitStubs) { QVector3D uDirection = unitVectors[direction]; p.drawLine(rx + rSize * (int)uDirection.x() / 2, ry + rSize * (int)uDirection.y(), rx + (int)uDirection.x() * (rSize * 3 / 4 * tx), ry + uDirection.y() * (rSize * 3 / 4 * ty)); } QPen __pen; for (int& k : exitList) { int rID = k; if (rID <= 0) { continue; } bool areaExit; TRoom* pE = mpMap->mpRoomDB->getRoom(rID); if (!pE) { continue; } if (pE->getArea() != mAID) { areaExit = true; } else { areaExit = false; } float ex = pE->x * tx + _rx; float ey = pE->y * ty * -1 + _ry; int ez = pE->z; QVector3D p1(ex, ey, ez); QVector3D p2(rx, ry, rz); QLine _line; if (!areaExit) { // one way exit or 2 way exit? if (!oneWayExits.contains(rID)) { p.drawLine((int)p1.x(), (int)p1.y(), (int)p2.x(), (int)p2.y()); } else { // one way exit draw arrow QLineF l0 = QLineF(p2.x(), p2.y(), p1.x(), p1.y()); QLineF k0 = l0; k0.setLength((l0.length() - wegBreite * 5) * 0.5); qreal dx = k0.dx(); qreal dy = k0.dy(); QPen _tp = p.pen(); QPen _tp2 = _tp; _tp2.setStyle(Qt::DotLine); p.setPen(_tp2); p.drawLine(l0); p.setPen(_tp); l0.setLength(wegBreite * 5); QPointF _p1 = l0.p2(); QPointF _p2 = l0.p1(); QLineF l1 = QLineF(l0); qreal w1 = l1.angle() - 90.0; QLineF l2; l2.setP1(_p2); l2.setAngle(w1); l2.setLength(wegBreite * 2); QPointF _p3 = l2.p2(); l2.setAngle(l2.angle() + 180.0); QPointF _p4 = l2.p2(); QPolygonF _poly; _poly.append(_p1); _poly.append(_p3); _poly.append(_p4); QBrush brush = p.brush(); brush.setColor(QColor(255, 100, 100)); brush.setStyle(Qt::SolidPattern); QPen arrowPen = p.pen(); arrowPen.setCosmetic(mMapperUseAntiAlias); arrowPen.setStyle(Qt::SolidLine); p.setPen(arrowPen); p.setBrush(brush); p.drawPolygon(_poly.translated(dx, dy)); } } else { __pen = p.pen(); QPoint _p; pen = p.pen(); pen.setWidthF(wegBreite); pen.setCosmetic(mMapperUseAntiAlias); pen.setColor(getColor(k)); p.setPen(pen); if (pR->getSouth() == rID) { _line = QLine(p2.x(), p2.y() + ty, p2.x(), p2.y()); _p = QPoint(p2.x(), p2.y() + ty / 2); } else if (pR->getNorth() == rID) { _line = QLine(p2.x(), p2.y() - ty, p2.x(), p2.y()); _p = QPoint(p2.x(), p2.y() - ty / 2); } else if (pR->getWest() == rID) { _line = QLine(p2.x() - tx, p2.y(), p2.x(), p2.y()); _p = QPoint(p2.x() - tx / 2, p2.y()); } else if (pR->getEast() == rID) { _line = QLine(p2.x() + tx, p2.y(), p2.x(), p2.y()); _p = QPoint(p2.x() + tx / 2, p2.y()); } else if (pR->getNorthwest() == rID) { _line = QLine(p2.x() - tx, p2.y() - ty, p2.x(), p2.y()); _p = QPoint(p2.x() - tx / 2, p2.y() - ty / 2); } else if (pR->getNortheast() == rID) { _line = QLine(p2.x() + tx, p2.y() - ty, p2.x(), p2.y()); _p = QPoint(p2.x() + tx / 2, p2.y() - ty / 2); } else if (pR->getSoutheast() == rID) { _line = QLine(p2.x() + tx, p2.y() + ty, p2.x(), p2.y()); _p = QPoint(p2.x() + tx / 2, p2.y() + ty / 2); } else if (pR->getSouthwest() == rID) { _line = QLine(p2.x() - tx, p2.y() + ty, p2.x(), p2.y()); _p = QPoint(p2.x() - tx / 2, p2.y() + ty / 2); } p.drawLine(_line); mAreaExitList[k] = _p; QLineF l0 = QLineF(_line); l0.setLength(wegBreite * 5); QPointF _p1 = l0.p1(); QPointF _p2 = l0.p2(); QLineF l1 = QLineF(l0); qreal w1 = l1.angle() - 90.0; QLineF l2; l2.setP1(_p2); l2.setAngle(w1); l2.setLength(wegBreite * 2); QPointF _p3 = l2.p2(); l2.setAngle(l2.angle() + 180.0); QPointF _p4 = l2.p2(); QPolygonF _poly; _poly.append(_p1); _poly.append(_p3); _poly.append(_p4); QBrush brush = p.brush(); brush.setColor(getColor(k)); brush.setStyle(Qt::SolidPattern); QPen arrowPen = p.pen(); arrowPen.setCosmetic(mMapperUseAntiAlias); p.setPen(arrowPen); p.setBrush(brush); p.drawPolygon(_poly); p.setPen(__pen); } // doors if (pR->doors.size() > 0) { int doorStatus = 0; if (pR->getSouth() == rID && pR->doors.contains("s")) { doorStatus = pR->doors["s"]; } else if (pR->getNorth() == rID && pR->doors.contains("n")) { doorStatus = pR->doors["n"]; } else if (pR->getSouthwest() == rID && pR->doors.contains("sw")) { doorStatus = pR->doors["sw"]; } else if (pR->getSoutheast() == rID && pR->doors.contains("se")) { doorStatus = pR->doors["se"]; } else if (pR->getNortheast() == rID && pR->doors.contains("ne")) { doorStatus = pR->doors["ne"]; } else if (pR->getNorthwest() == rID && pR->doors.contains("nw")) { doorStatus = pR->doors["nw"]; } else if (pR->getWest() == rID && pR->doors.contains("w")) { doorStatus = pR->doors["w"]; } else if (pR->getEast() == rID && pR->doors.contains("e")) { doorStatus = pR->doors["e"]; } if (doorStatus > 0) { QLineF k0; QRectF rect; rect.setWidth(0.25 * mTX); rect.setHeight(0.25 * mTY); if (areaExit) { k0 = QLineF(_line); } else { k0 = QLineF(p2.x(), p2.y(), p1.x(), p1.y()); } k0.setLength((k0.length()) * 0.5); rect.moveCenter(k0.p2()); QPen arrowPen = p.pen(); QPen _tp = p.pen(); arrowPen.setCosmetic(mMapperUseAntiAlias); arrowPen.setStyle(Qt::SolidLine); if (doorStatus == 1) { //open door arrowPen.setColor(QColor(10, 155, 10)); } else if (doorStatus == 2) { //closed door arrowPen.setColor(QColor(155, 155, 10)); } else { //locked door arrowPen.setColor(QColor(155, 10, 10)); } QBrush brush; QBrush oldBrush; p.setPen(arrowPen); p.setBrush(brush); p.drawRect(rect); p.setBrush(oldBrush); p.setPen(_tp); } } } // End of for( exitList ) // Indicate destination for custom exit line drawing - double size // target yellow hollow circle // Similar code is now also used to indicate center target of // multiple selected rooms but that must be done after all the rooms // have been drawn otherwise later drawn rooms will overwrite the // mark, especially on areas in gridmode. if (customLineDestinationTarget > 0 && customLineDestinationTarget == _id) { QPen savePen = p.pen(); QBrush saveBrush = p.brush(); float _radius = tx * 1.2; float _diagonal = tx * 1.2; QPointF _center = QPointF(rx, ry); QPen myPen(QColor(255, 255, 50, 192)); // Quarter opaque yellow pen myPen.setWidth(tx * 0.1); QPainterPath myPath; p.setPen(myPen); p.setBrush(Qt::NoBrush); myPath.addEllipse(_center, _radius, _radius); myPath.addEllipse(_center, _radius / 2.0, _radius / 2.0); myPath.moveTo(rx - _diagonal, ry - _diagonal); myPath.lineTo(rx + _diagonal, ry + _diagonal); myPath.moveTo(rx + _diagonal, ry - _diagonal); myPath.lineTo(rx - _diagonal, ry + _diagonal); p.drawPath(myPath); p.setPen(savePen); p.setBrush(saveBrush); } } // End of for( area Rooms ) } // End of NOT area gridmode // Draw label sizing or group selection box if (mSizeLabel) { p.fillRect(mMultiRect, QColor(250, 190, 0, 190)); } else { p.fillRect(mMultiRect, QColor(190, 190, 190, 60)); } QSetIterator itRoom(pArea->getAreaRooms()); while (itRoom.hasNext()) { int currentAreaRoom = itRoom.next(); TRoom* pR = mpMap->mpRoomDB->getRoom(currentAreaRoom); if (!pR) { continue; // Was missing this safety step to skip missing rooms } float rx = pR->x * tx + _rx; float ry = pR->y * -1 * ty + _ry; int rz = pR->z; if (rz != zEbene) { continue; } if (rx < 0 || ry < 0 || rx > _w || ry > _h) { continue; } pR->rendered = false; QRectF dr; if (pArea->gridMode) { dr = QRectF(rx - tx / 2, ry - ty / 2, tx, ty); } else { dr = QRectF(rx - (tx * rSize) / 2, ry - (ty * rSize) / 2, tx * rSize, ty * rSize); } QColor c; int env = pR->environment; if (mpMap->envColors.contains(env)) { env = mpMap->envColors[env]; } else { if (!mpMap->customEnvColors.contains(env)) { env = 1; } } switch (env) { case 1: c = mpHost->mRed_2; break; case 2: c = mpHost->mGreen_2; break; case 3: c = mpHost->mYellow_2; break; case 4: c = mpHost->mBlue_2; break; case 5: c = mpHost->mMagenta_2; break; case 6: c = mpHost->mCyan_2; break; case 7: c = mpHost->mWhite_2; break; case 8: c = mpHost->mBlack_2; break; case 9: c = mpHost->mLightRed_2; break; case 10: c = mpHost->mLightGreen_2; break; case 11: c = mpHost->mLightYellow_2; break; case 12: c = mpHost->mLightBlue_2; break; case 13: c = mpHost->mLightMagenta_2; break; case 14: c = mpHost->mLightCyan_2; break; case 15: c = mpHost->mLightWhite_2; break; case 16: c = mpHost->mLightBlack_2; break; default: //user defined room color if (mpMap->customEnvColors.contains(env)) { c = mpMap->customEnvColors[env]; } } if (((mPick || __Pick) && mPHighlight.x() >= dr.x() - (tx * rSize) && mPHighlight.x() <= dr.x() + (tx * rSize) && mPHighlight.y() >= dr.y() - (ty * rSize) && mPHighlight.y() <= dr.y() + (ty * rSize)) || mMultiSelectionSet.contains(currentAreaRoom)) { p.fillRect(dr, QColor(255, 155, 55)); mPick = false; if (mStartSpeedWalk) { mStartSpeedWalk = false; float _radius = (0.8 * tx) / 2; QPointF _center = QPointF(rx, ry); QRadialGradient _gradient(_center, _radius); _gradient.setColorAt(0.95, QColor(255, 0, 0, 150)); _gradient.setColorAt(0.80, QColor(150, 100, 100, 150)); _gradient.setColorAt(0.799, QColor(150, 100, 100, 100)); _gradient.setColorAt(0.7, QColor(255, 0, 0, 200)); _gradient.setColorAt(0, QColor(255, 255, 255, 255)); QPen myPen(Qt::transparent); QPainterPath myPath; p.setBrush(_gradient); p.setPen(myPen); myPath.addEllipse(_center, _radius, _radius); p.drawPath(myPath); mTarget = currentAreaRoom; if (mpMap->mpRoomDB->getRoom(mTarget)) { mpMap->mTargetID = mTarget; if (mpMap->findPath(mpMap->mRoomIdHash.value(mpHost->getName()), mpMap->mTargetID)) { mpHost->startSpeedWalk(); } else { QString msg = "Mapper: Cannot find a path to this room using known exits.\n"; mpHost->mpConsole->printSystemMessage(msg); } } } } else { char _ch = pR->c; if (_ch >= 33 /* && _ch < 255 seems that _ch is a signed char so will always be less than 255 */) { int _color = (265 - 257) * 254 + _ch; //(mpMap->rooms[pArea->rooms[i]]->environment - 257 ) * 254 + _ch; if (c.red() + c.green() + c.blue() > 260) { _color = (7) * 254 + _ch; } else { _color = (6) * 254 + _ch; } p.fillRect(dr, c); if (mPixMap.contains(_color)) { QPixmap pix = mPixMap[_color].scaled(dr.width(), dr.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); p.drawPixmap(dr.topLeft(), pix); } } else { if (mBubbleMode) { float _radius = (rSize * tx) / 2; QPointF _center = QPointF(rx, ry); QRadialGradient _gradient(_center, _radius); _gradient.setColorAt(0.85, c); _gradient.setColorAt(0, QColor(255, 255, 255, 255)); QPen myPen(Qt::transparent); QPainterPath myPath; p.setBrush(_gradient); p.setPen(myPen); myPath.addEllipse(_center, _radius, _radius); p.drawPath(myPath); } else { p.fillRect(dr, c); } } if (pR->highlight) { float _radius = (pR->highlightRadius * tx) / 2; QPointF _center = QPointF(rx, ry); QRadialGradient _gradient(_center, _radius); _gradient.setColorAt(0.85, pR->highlightColor); _gradient.setColorAt(0, pR->highlightColor2); QPen myPen(Qt::transparent); QPainterPath myPath; p.setBrush(_gradient); p.setPen(myPen); myPath.addEllipse(_center, _radius, _radius); p.drawPath(myPath); } if (mShowRoomID) { QPen __pen = p.pen(); QColor lc; if (c.red() + c.green() + c.blue() > 200) { lc = QColor(Qt::black); } else { lc = QColor(Qt::white); } p.setPen(QPen(lc)); p.drawText(dr, Qt::AlignHCenter | Qt::AlignVCenter, QString::number(currentAreaRoom)); p.setPen(__pen); } if (mShiftMode && currentAreaRoom == mpMap->mRoomIdHash.value(mpHost->getName())) { float _radius = (1.2 * tx) / 2; QPointF _center = QPointF(rx, ry); QRadialGradient _gradient(_center, _radius); _gradient.setColorAt(0.95, QColor(255, 0, 0, 150)); _gradient.setColorAt(0.80, QColor(150, 100, 100, 150)); _gradient.setColorAt(0.799, QColor(150, 100, 100, 100)); _gradient.setColorAt(0.7, QColor(255, 0, 0, 200)); _gradient.setColorAt(0, QColor(255, 255, 255, 255)); QPen myPen(Qt::transparent); QPainterPath myPath; p.setBrush(_gradient); p.setPen(myPen); myPath.addEllipse(_center, _radius, _radius); p.drawPath(myPath); } } QColor lc; if (c.red() + c.green() + c.blue() > 200) { lc = QColor(Qt::black); } else { lc = QColor(Qt::white); } pen = p.pen(); pen.setColor(lc); pen.setWidthF(0); //wegBreite?); pen.setCosmetic(mMapperUseAntiAlias); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); p.setPen(pen); //FIXME: redo exit stubs here since the room will draw over up/down stubs -- its repetitive though QMap unitVectors = mpMap->unitVectors; for (int k = 0; k < pR->exitStubs.size(); k++) { int direction = pR->exitStubs[k]; QVector3D uDirection = unitVectors[direction]; if (direction > 8) { float rx = pR->x * tx + _rx; float ry = pR->y * -1 * ty + _ry; QPolygonF _poly; QPointF _pt; _pt = QPointF(rx, ry + (ty * rSize) * uDirection.z() / 20); _poly.append(_pt); _pt = QPointF(rx + (tx * rSize) / 3.1, ry + (ty * rSize) * uDirection.z() / 3.1); _poly.append(_pt); _pt = QPointF(rx - (tx * rSize) / 3.1, ry + (ty * rSize) * uDirection.z() / 3.1); _poly.append(_pt); QBrush brush = p.brush(); brush.setColor(Qt::black); brush.setStyle(Qt::NoBrush); p.setBrush(brush); p.drawPolygon(_poly); } } if (pR->getUp() > 0) { QPolygonF _poly; QPointF _pt; _pt = QPointF(rx, ry + (ty * rSize) / 20); _poly.append(_pt); _pt = QPointF(rx - (tx * rSize) / 3.1, ry + (ty * rSize) / 3.1); _poly.append(_pt); _pt = QPointF(rx + (tx * rSize) / 3.1, ry + (ty * rSize) / 3.1); _poly.append(_pt); QBrush brush = p.brush(); brush.setColor(Qt::black); brush.setStyle(Qt::SolidPattern); p.setBrush(brush); p.drawPolygon(_poly); } if (pR->getDown() > 0) { QPolygonF _poly; QPointF _pt; _pt = QPointF(rx, ry - (ty * rSize) / 20); _poly.append(_pt); _pt = QPointF(rx - (tx * rSize) / 3.1, ry - (ty * rSize) / 3.1); _poly.append(_pt); _pt = QPointF(rx + (tx * rSize) / 3.1, ry - (ty * rSize) / 3.1); _poly.append(_pt); QBrush brush = p.brush(); brush.setColor(Qt::black); brush.setStyle(Qt::SolidPattern); p.setBrush(brush); p.drawPolygon(_poly); } if (pR->getIn() > 0) { QPolygonF _poly; QPointF _pt; _pt = QPointF(rx + (tx * rSize) / 20, ry); _poly.append(_pt); _pt = QPointF(rx - (tx * rSize) / 3.1, ry - (ty * rSize) / 3.1); _poly.append(_pt); _pt = QPointF(rx - (tx * rSize) / 3.1, ry + (ty * rSize) / 3.1); _poly.append(_pt); QBrush brush = p.brush(); brush.setColor(Qt::black); brush.setStyle(Qt::SolidPattern); p.setBrush(brush); p.drawPolygon(_poly); } if (pR->getOut() > 0) { QPolygonF _poly; QPointF _pt; _pt = QPointF(rx - (tx * rSize) / 20, ry); _poly.append(_pt); _pt = QPointF(rx + (tx * rSize) / 3.1, ry - (ty * rSize) / 3.1); _poly.append(_pt); _pt = QPointF(rx + (tx * rSize) / 3.1, ry + (ty * rSize) / 3.1); _poly.append(_pt); QBrush brush = p.brush(); brush.setColor(Qt::black); brush.setStyle(Qt::SolidPattern); p.setBrush(brush); p.drawPolygon(_poly); } if (pArea->gridMode) { QMapIterator it(mAreaExitList); while (it.hasNext()) { it.next(); QPoint P = it.value(); int rx = P.x(); int ry = P.y(); QRectF dr = QRectF(rx - tx / 2, ry - ty / 2, tx, ty); if (((mPick || __Pick) && mPHighlight.x() >= dr.x() - tx / 2 && mPHighlight.x() <= dr.x() + tx / 2 && mPHighlight.y() >= dr.y() - ty / 2 && mPHighlight.y() <= dr.y() + ty / 2) || mMultiSelectionSet.contains(currentAreaRoom)) { p.fillRect(dr, QColor(50, 255, 50)); mPick = false; mTarget = it.key(); if (mpMap->mpRoomDB->getRoom(mTarget)) { mpMap->mTargetID = mTarget; if (mpMap->findPath(mpMap->mRoomIdHash.value(mpHost->getName()), mpMap->mTargetID)) { mpHost->startSpeedWalk(); } else { QString msg = "Mapper: Cannot find a path to this room using known exits.\n"; mpHost->mpConsole->printSystemMessage(msg); } } } } } else { QMapIterator it(mAreaExitList); while (it.hasNext()) { it.next(); QPoint P = it.value(); int rx = P.x(); int ry = P.y(); QRectF dr = QRectF(rx, ry, tx * rSize, ty * rSize); //rx-(tx*rSize)/2,ry-(ty*rSize)/2,tx*rSize,ty*rSize); if (((mPick || __Pick) && mPHighlight.x() >= dr.x() - tx / 3 && mPHighlight.x() <= dr.x() + tx / 3 && mPHighlight.y() >= dr.y() - ty / 3 && mPHighlight.y() <= dr.y() + ty / 3) && mStartSpeedWalk) { mStartSpeedWalk = false; float _radius = (0.8 * tx) / 2; QPointF _center = QPointF(rx, ry); QRadialGradient _gradient(_center, _radius); _gradient.setColorAt(0.95, QColor(255, 0, 0, 150)); _gradient.setColorAt(0.80, QColor(150, 100, 100, 150)); _gradient.setColorAt(0.799, QColor(150, 100, 100, 100)); _gradient.setColorAt(0.7, QColor(255, 0, 0, 200)); _gradient.setColorAt(0, QColor(255, 255, 255, 255)); QPen myPen(Qt::transparent); QPainterPath myPath; p.setBrush(_gradient); p.setPen(myPen); myPath.addEllipse(_center, _radius, _radius); p.drawPath(myPath); mPick = false; mTarget = it.key(); if (mpMap->mpRoomDB->getRoom(mTarget)) { mpMap->mTargetID = mTarget; if (mpMap->findPath(mpMap->mRoomIdHash.value(mpHost->getName()), mpMap->mTargetID)) { mpMap->mpHost->startSpeedWalk(); } else { QString msg = "Mapper: Cannot find a path to this room using known exits.\n"; mpHost->mpConsole->printSystemMessage(msg); } } } } } } if (mpMap->mapLabels.contains(mAID)) { QMapIterator it(mpMap->mapLabels[mAID]); while (it.hasNext()) { it.next(); if (it.value().pos.z() != mOz) { continue; } if (it.value().text.length() < 1) { mpMap->mapLabels[mAID][it.key()].text = "no text"; } QPointF lpos; int _lx = it.value().pos.x() * tx + _rx; int _ly = it.value().pos.y() * ty * -1 + _ry; lpos.setX(_lx); lpos.setY(_ly); int _lw = abs(it.value().size.width()) * tx; int _lh = abs(it.value().size.height()) * ty; if (!((0 < _lx || 0 < _lx + _lw) && (_w > _lx || _w > _lx + _lw))) { continue; } if (!((0 < _ly || 0 < _ly + _lh) && (_h > _ly || _h > _ly + _lh))) { continue; } QRectF _drawRect = QRect(it.value().pos.x() * tx + _rx, it.value().pos.y() * ty * -1 + _ry, _lw, _lh); if (it.value().showOnTop) { if (!it.value().noScaling) { p.drawPixmap(lpos, it.value().pix.scaled(_drawRect.size().toSize())); mpMap->mapLabels[mAID][it.key()].clickSize.setWidth(_drawRect.width()); mpMap->mapLabels[mAID][it.key()].clickSize.setHeight(_drawRect.height()); } else { p.drawPixmap(lpos, it.value().pix); mpMap->mapLabels[mAID][it.key()].clickSize.setWidth(it.value().pix.width()); mpMap->mapLabels[mAID][it.key()].clickSize.setHeight(it.value().pix.height()); } } if (it.value().hilite) { _drawRect.setSize(it.value().clickSize); p.fillRect(_drawRect, QColor(255, 155, 55, 190)); } } } // Similar code was used to indicate target of custom exit line selected for // editing but this could not be done there because gridmode areas don't hit // that bit of code and later rooms would overwrite the target... if (mMultiSelectionHighlightRoomId > 0 && mMultiSelectionSet.size() > 1) { TRoom* pR_multiSelectionHighlight = mpMap->mpRoomDB->getRoom(mMultiSelectionHighlightRoomId); if (pR_multiSelectionHighlight) { float r_mSx = pR_multiSelectionHighlight->x * tx + _rx; float r_mSy = pR_multiSelectionHighlight->y * -1 * ty + _ry; QPen savePen = p.pen(); QBrush saveBrush = p.brush(); float _radius = tx * 1.2; float _diagonal = tx * 1.2; QPointF _center = QPointF(r_mSx, r_mSy); QPen myPen(QColor(255, 255, 50, 192)); // Quarter opaque yellow pen myPen.setWidth(tx * 0.1); QPainterPath myPath; p.setPen(myPen); p.setBrush(Qt::NoBrush); myPath.addEllipse(_center, _radius, _radius); myPath.addEllipse(_center, _radius / 2.0, _radius / 2.0); myPath.moveTo(r_mSx - _diagonal, r_mSy - _diagonal); myPath.lineTo(r_mSx + _diagonal, r_mSy + _diagonal); myPath.moveTo(r_mSx + _diagonal, r_mSy - _diagonal); myPath.lineTo(r_mSx - _diagonal, r_mSy + _diagonal); p.drawPath(myPath); p.setPen(savePen); p.setBrush(saveBrush); } } QColor infoColor; if (mpHost->mBgColor_2.lightness() > 127) { infoColor = QColor(Qt::black); } else { infoColor = QColor(Qt::white); } // Draw central red circle: if (!mShiftMode) { p.save(); QPen myPen(Qt::transparent); QPainterPath myPath; if (mpHost->mMapStrongHighlight) { // Never set, no means to except via XMLImport, as dlgMapper class's // slot_toggleStrongHighlight is not wired up to anything QRectF dr = QRectF(px - (tx * rSize) / 2, py - (ty * rSize) / 2, tx * rSize, ty * rSize); p.fillRect(dr, QColor(255, 0, 0, 150)); float _radius = (1.9 * tx) / 2; QPointF _center = QPointF(px, py); QRadialGradient _gradient(_center, _radius); _gradient.setColorAt(0.95, QColor(255, 0, 0, 150)); _gradient.setColorAt(0.80, QColor(150, 100, 100, 150)); _gradient.setColorAt(0.799, QColor(150, 100, 100, 100)); _gradient.setColorAt(0.7, QColor(255, 0, 0, 200)); _gradient.setColorAt(0, QColor(255, 255, 255, 255)); p.setBrush(_gradient); p.setPen(myPen); myPath.addEllipse(_center, _radius, _radius); } else { float _radius = (1.9 * tx) / 2; QPointF _center = QPointF(px, py); QRadialGradient _gradient(_center, _radius); _gradient.setColorAt(0.95, QColor(255, 0, 0, 150)); _gradient.setColorAt(0.80, QColor(150, 100, 100, 150)); _gradient.setColorAt(0.799, QColor(150, 100, 100, 100)); _gradient.setColorAt(0.3, QColor(150, 150, 150, 100)); _gradient.setColorAt(0.1, QColor(255, 255, 255, 100)); _gradient.setColorAt(0, QColor(255, 255, 255, 255)); p.setBrush(_gradient); p.setPen(myPen); myPath.addEllipse(_center, _radius, _radius); } p.drawPath(myPath); p.restore(); } // Work out text for information box, need to offset if room selection widget is present if (mShowInfo) { QString infoText; int __rid = mRID; if (!isCenterViewCall && mMultiSelectionSet.size()) { if (mpMap->mpRoomDB->getRoom(*(mMultiSelectionSet.constBegin()))) { __rid = mMultiSelectionHighlightRoomId; } } p.save(); // Save painter state QFont f = p.font(); TRoom* _prid = mpMap->mpRoomDB->getRoom(__rid); if (_prid) { int _iaid = _prid->getArea(); TArea* _paid = mpMap->mpRoomDB->getArea(_iaid); QString _paid_name = mpMap->mpRoomDB->getAreaNamesMap().value(_iaid); if (_paid) { infoText = tr("Area: %1 ID:%2 x:%3 <-> %4 y:%5 <-> %6 z:%7 <-> %8\n") .arg(_paid_name, QString::number(_iaid), QString::number(_paid->min_x), QString::number(_paid->max_x), QString::number(_paid->min_y), QString::number(_paid->max_y), QString::number(_paid->min_z), QString::number((_paid->max_z))); } else { infoText = QStringLiteral("\n"); } if (!_prid->name.isEmpty()) { infoText.append(tr("Room Name: %1\n").arg(_prid->name)); } uint selectionSize = mMultiSelectionSet.size(); // Italicise the text if the current display area {mAID} is not the // same as the displayed text information - which happens when NO // room is selected AND the current area is NOT the one the player // is in (to emphasis that the displayed data is {mostly} not about // the CURRENTLY VISIBLE area)... make it bold if the player room IS // in the displayed map // If one or more rooms are selected - make the text slightly orange. switch (selectionSize) { case 0: infoText.append(tr("Room ID: %1 (Current) Position on Map: (%2,%3,%4)\n").arg(QString::number(__rid), QString::number(_prid->x), QString::number(_prid->y), QString::number(_prid->z))); if (playerArea != mAID) { f.setItalic(true); } else { f.setBold(true); } break; case 1: infoText.append( tr("Room ID: %1 (Selected) Position on Map: (%2,%3,%4)\n").arg(QString::number(__rid), QString::number(_prid->x), QString::number(_prid->y), QString::number(_prid->z))); f.setBold(true); if (infoColor.lightness() > 127) { infoColor = QColor(255, 223, 191); // Slightly orange white } else { infoColor = QColor(96, 48, 0); // Dark, slightly orange grey } break; default: infoText.append(tr("Room ID: %1 (%5 Selected) Position on Map: (%2,%3,%4)\n") .arg(QString::number(__rid), QString::number(_prid->x), QString::number(_prid->y), QString::number(_prid->z), QString::number(selectionSize))); f.setBold(true); if (infoColor.lightness() > 127) { infoColor = QColor(255, 223, 191); // Slightly orange white } else { infoColor = QColor(96, 48, 0); // Dark, slightly orange grey } break; } } infoText.append(tr("render time: %1S mO: (%2,%3,%4)").arg(__time.nsecsElapsed() * 1.0e-9, 0, 'f', 3).arg(QString::number(mOx), QString::number(mOy), QString::number(mOz))); uint infoLeftSideAvoid = 10; // Left margin for info widget if (mMultiSelectionListWidget.isVisible()) { // Room Selection Widget showing, so increase margin to avoid infoLeftSideAvoid += mMultiSelectionListWidget.x() + mMultiSelectionListWidget.rect().width(); } uint infoHeight = 5 + mFontHeight; // Account for first iteration QRect testRect; // infoRect has a 10 margin on either side and on top to widget frame. mMapInfoRect = QRect(infoLeftSideAvoid, 10, width() - 10 - infoLeftSideAvoid, infoHeight); do { infoHeight += mFontHeight; mMapInfoRect.setHeight(infoHeight); // Test in a rectangle that is 10 less on all sides: testRect = p.boundingRect(mMapInfoRect.left() + 10, mMapInfoRect.top() + 10, mMapInfoRect.width() - 20, mMapInfoRect.height() - 20, Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop, infoText); } while ((testRect.height() > mMapInfoRect.height() - 20 || testRect.width() > mMapInfoRect.width() - 20) && infoHeight < height()); // Last term is needed to prevent runaway under "odd" conditions p.fillRect(mMapInfoRect, QColor(150, 150, 150, 80)); // Restore Grey translucent background, was useful for debugging! p.setPen(infoColor); p.setFont(f); p.drawText(mMapInfoRect.left() + 10, mMapInfoRect.top() + 10, mMapInfoRect.width() - 20, mMapInfoRect.height() - 20, Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop, infoText); p.restore(); //forget about font size changing and bolding/italicisation } static bool isAreaWidgetValid = true; // Remember between uses QFont _f = mpMap->mpMapper->showArea->font(); if (isAreaWidgetValid) { if (mAID == -1 // * the map being shown is the "default" area && !mpMap->mpMapper->getDefaultAreaShown()) { // * the area widget is not showing the "default" area isAreaWidgetValid = false; // So the widget CANNOT indicate the correct area // Set the area widget to indicate the area widget is NOT // showing valid text - so make it italic and crossed out _f.setItalic(true); _f.setUnderline(true); _f.setStrikeOut(true); _f.setOverline(true); } } else { if (!(mAID == -1 && !mpMap->mpMapper->getDefaultAreaShown())) { isAreaWidgetValid = true; // So the widget CAN now indicate the correct area // Reset to normal _f.setItalic(false); _f.setUnderline(false); _f.setStrikeOut(false); _f.setOverline(false); } } mpMap->mpMapper->showArea->setFont(_f); if (mHelpMsg.size() > 0) { p.setPen(QColor(255, 155, 50)); QFont _f = p.font(); QFont _f2 = _f; _f.setPointSize(12); // 20 was a little large _f.setBold(true); p.setFont(_f); QRect _r = QRect(0, 0, _w, _h); p.drawText(_r, Qt::AlignHCenter | Qt::AlignBottom | Qt::TextWordWrap, mHelpMsg); // Now draw text centered at bottom, so it does not clash with info window p.setFont(_f2); } } void T2DMap::mouseDoubleClickEvent(QMouseEvent* event) { if (mDialogLock) { return; } int x = event->x(); int y = event->y(); mPHighlight = QPoint(x, y); mPick = true; mStartSpeedWalk = true; repaint(); } void T2DMap::createLabel(QRectF labelRect) { // N/U: QRectF selectedRegion = labelRect; TMapLabel label; QFont _font; QString t = "no text"; QString imagePath; mHelpMsg.clear(); QMessageBox msgBox; msgBox.setText("Text label or image label?"); QPushButton* textButton = msgBox.addButton(tr("Text Label"), QMessageBox::ActionRole); QPushButton* imageButton = msgBox.addButton(tr("Image Label"), QMessageBox::ActionRole); msgBox.setStandardButtons(QMessageBox::Cancel); msgBox.exec(); if (msgBox.clickedButton() == textButton) { QString title = "Enter label text."; _font = QFontDialog::getFont(0); t = QInputDialog::getText(0, title, title); if (t.length() < 1) { t = "no text"; } label.text = t; label.bgColor = QColorDialog::getColor(QColor(50, 50, 150, 100), 0, "Background color"); label.fgColor = QColorDialog::getColor(QColor(255, 255, 50, 255), 0, "Foreground color"); } else if (msgBox.clickedButton() == imageButton) { label.bgColor = QColor(50, 50, 150, 100); label.fgColor = QColor(255, 255, 50, 255); label.text = ""; imagePath = QFileDialog::getOpenFileName(0, "Select image"); } else { return; } QMessageBox msgBox2; msgBox2.setStandardButtons(QMessageBox::Cancel); msgBox2.setText("Draw label as background or on top of everything?"); QPushButton* textButton2 = msgBox2.addButton(tr("Background"), QMessageBox::ActionRole); QPushButton* imageButton2 = msgBox2.addButton(tr("Foreground"), QMessageBox::ActionRole); msgBox2.exec(); bool showOnTop = false; if (msgBox2.clickedButton() == textButton2) { showOnTop = false; } else if (msgBox2.clickedButton() == imageButton2) { showOnTop = true; } else { return; } label.showOnTop = showOnTop; QPixmap pix(abs(labelRect.width()), abs(labelRect.height())); QRect drawRect = labelRect.normalized().toRect(); drawRect.moveTo(0, 0); //pix.fill(QColor(0,255,0,0)); QPainter lp(&pix); QPen lpen; lp.setFont(_font); lpen.setColor(label.fgColor); lp.setPen(lpen); lp.fillRect(drawRect, label.bgColor); if (msgBox.clickedButton() == textButton) { lp.drawText(drawRect, Qt::AlignHCenter | Qt::AlignCenter, t, 0); } else { QPixmap imagePixmap = QPixmap(imagePath); lp.drawPixmap(QPoint(0, 0), imagePixmap.scaled(drawRect.size())); } label.pix = pix.copy(drawRect); labelRect = labelRect.normalized(); float mx = labelRect.topLeft().x() / mTX + mOx; float my = labelRect.topLeft().y() / mTY + mOy; mx = mx - xspan / 2; my = yspan / 2 - my; float mx2 = labelRect.bottomRight().x() / mTX + mOx; float my2 = labelRect.bottomRight().y() / mTY + mOy; mx2 = mx2 - xspan / 2; my2 = yspan / 2 - my2; label.pos = QVector3D(mx, my, mOz); label.size = QRectF(QPointF(mx, my), QPointF(mx2, my2)).normalized().size(); if (!mpMap->mpRoomDB->getArea(mAID)) { return; } int labelID; if (!mpMap->mapLabels.contains(mAID)) { QMap m; m[0] = label; mpMap->mapLabels[mAID] = m; } else { labelID = mpMap->createMapLabelID(mAID); mpMap->mapLabels[mAID].insert(labelID, label); } update(); } void T2DMap::mouseReleaseEvent(QMouseEvent* e) { if (mMoveLabel) { mMoveLabel = false; } //move map with left mouse button + ALT (-> if (mpMap->mLeftDown) { mpMap->mLeftDown = false; } if (e->button() & Qt::LeftButton) { mMultiSelection = false; // End drag-to-select rectangle resizing mHelpMsg.clear(); if (mSizeLabel) { mSizeLabel = false; QRectF labelRect = mMultiRect; createLabel(labelRect); } mMultiRect = QRect(0, 0, 0, 0); update(); } } bool T2DMap::event(QEvent* event) { //NOTE: key events aren't being forwarded to T2DMap because the widget currently never has focus because it's more comfortable for the user to always have focus on the command line // If this were to be changed some day the setFocusPolicy() calls in the constructor need to be uncommented if (event->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast(event); qDebug() << "modifier=" << ke->modifiers() << " key=" << ke->key(); // if( ke->key() == Qt::Key_Delete ) // { // if( mCustomLineSelectedRoom != 0 ) // { // if( mpMap->rooms.contains(mCustomLineSelectedRoom) ) // { // TRoom * pR = mpMap->rooms[mCustomLineSelectedRoom]; // if( pR->customLines.contains( mCustomLineSelectedExit) ) // { // pR->customLines.remove(mCustomLineSelectedExit); // repaint(); // mCustomLineSelectedRoom = 0; // mCustomLineSelectedExit = ""; // mCustomLineSelectedPoint = -1; // return QWidget::event(event); // } // } // } // } } else if (event->type() == QEvent::Resize) { // Tweak the room selection widget to fit resizeMultiSelectionWidget(); } return QWidget::event(event); } void T2DMap::mousePressEvent(QMouseEvent* event) { mNewMoveAction = true; if (event->buttons() & Qt::LeftButton) { // move map with left mouse button + ALT if (event->modifiers().testFlag(Qt::AltModifier)) { mpMap->mLeftDown = true; } // drawing new custom exit line if (mCustomLinesRoomFrom > 0) { if (mDialogLock) { return; // Prevent any line drawing until ready } TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLinesRoomFrom); if (pR) { float mx = event->pos().x() / mTX + mOx; float my = event->pos().y() / mTY + mOy; mx = mx - xspan / 2; my = yspan / 2 - my; // might be useful to have a snap to grid type option pR->customLines[mCustomLinesRoomExit].push_back(QPointF(mx, my)); pR->calcRoomDimensions(); repaint(); return; } } // check click on custom exit lines if (mMultiSelectionSet.isEmpty()) { // But NOT if got one or more rooms already selected! TArea* pA = mpMap->mpRoomDB->getArea(mAID); if (pA) { TArea* pArea = pA; float mx = event->pos().x() / mTX + mOx; float my = event->pos().y() / mTY + mOy; mx = mx - xspan / 2; my = yspan / 2 - my; QPointF pc = QPointF(mx, my); QSetIterator itRoom = pArea->rooms; while (itRoom.hasNext()) { int currentRoomId = itRoom.next(); TRoom* pR = mpMap->mpRoomDB->getRoom(currentRoomId); if (!pR) { continue; } QMapIterator> it(pR->customLines); while (it.hasNext()) { it.next(); const QList& _pL = it.value(); if (_pL.size()) { // The way this code is structured means that EARLIER // points are selected in preference to later ones! // This might not be intuative to the users... float olx, oly, lx, ly; for (int j = 0; j < _pL.size(); j++) { if (j == 0) { // First segment of a custom line // start it at the centre of the room olx = pR->x; oly = pR->y; //FIXME: exit richtung beachten, um den Linienanfangspunkt zu berechnen lx = _pL[0].x(); ly = _pL[0].y(); } else { // Not the first segment of a custom line // so start it at the end of the previous one olx = lx; oly = ly; lx = _pL[j].x(); ly = _pL[j].y(); } // End of each custom line segment is given // click auf einen edit - punkt if (mCustomLineSelectedRoom != 0) { // We have already choosen a line to edit if (abs(mx - lx) <= 0.25 && abs(my - ly) <= 0.25) { // And this looks close enough to a point that we should edit it mCustomLineSelectedPoint = j; return; } } // We have not previously choosen a line to edit QLineF line = QLineF(olx, oly, lx, ly); QLineF normal = line.normalVector(); QLineF tl; tl.setP1(pc); tl.setAngle(normal.angle()); tl.setLength(0.1); QLineF tl2; tl2.setP1(pc); tl2.setAngle(normal.angle()); tl2.setLength(-0.1); QPointF pi; if ((line.intersect(tl, &pi) == QLineF::BoundedIntersection) || (line.intersect(tl2, &pi) == QLineF::BoundedIntersection)) { // Choose THIS line to edit as we have clicked close enough to it... mCustomLineSelectedRoom = pR->getId(); mCustomLineSelectedExit = it.key(); repaint(); return; } } } } } } mCustomLineSelectedRoom = 0; mCustomLineSelectedExit = ""; } if (mRoomBeingMoved) // Moving rooms so end that { mPHighlightMove = event->pos(); mPick = true; setMouseTracking(false); mRoomBeingMoved = false; } else if (!mPopupMenu) // Not in a context menu, so start selection mode - including drag to select { mMultiSelection = true; mMultiRect = QRect(event->pos(), event->pos()); int _roomID = mRID; if (!mpMap->mpRoomDB->getRoom(_roomID)) { return; } int _areaID = mAID; TArea* pArea = mpMap->mpRoomDB->getArea(_areaID); if (!pArea) { return; } float _rx = xspan / 2 * mTX - mTX * mOx; float _ry = yspan / 2 * mTY - mTY * mOy; if (!event->modifiers().testFlag(Qt::ControlModifier)) { // If control key NOT down then clear selection, and put up helpful text mHelpMsg = tr("Drag to select multiple rooms or labels, release to finish..."); mMultiSelectionSet.clear(); } QSetIterator itRoom(pArea->getAreaRooms()); while (itRoom.hasNext()) { // Scan to find rooms in selection int currentAreaRoom = itRoom.next(); TRoom* pR = mpMap->mpRoomDB->getRoom(currentAreaRoom); if (!pR) { continue; } int rx = pR->x * mTX + _rx; int ry = pR->y * -1 * mTY + _ry; int rz = pR->z; int mx = event->pos().x(); int my = event->pos().y(); int mz = mOz; if ((abs(mx - rx) < mTX * rSize / 2) && (abs(my - ry) < mTY * rSize / 2) && (mz == rz)) { if (mMultiSelectionSet.contains(currentAreaRoom) && event->modifiers().testFlag(Qt::ControlModifier)) { mMultiSelectionSet.remove(currentAreaRoom); } else { mMultiSelectionSet.insert(currentAreaRoom); } if (mMultiSelectionSet.size() > 0) { mMultiSelection = false; } } } switch (mMultiSelectionSet.size()) { case 0: mMultiSelectionHighlightRoomId = -1; break; case 1: mMultiSelection = false; // OK, found one room so stop mMultiSelectionHighlightRoomId = mMultiSelectionSet.toList().first(); mHelpMsg.clear(); break; default: mMultiSelection = false; // OK, found more than one room so stop mHelpMsg.clear(); getCenterSelection(); } // select labels if (mpMap->mapLabels.contains(mAID)) { QMapIterator it(mpMap->mapLabels[mAID]); while (it.hasNext()) { it.next(); if (it.value().pos.z() != mOz) { continue; } QPointF lpos; float _lx = it.value().pos.x() * mTX + _rx; float _ly = it.value().pos.y() * mTY * -1 + _ry; lpos.setX(_lx); lpos.setY(_ly); int mx = event->pos().x(); int my = event->pos().y(); // N/U: int mz = mOz; QPoint click = QPoint(mx, my); QRectF br = QRect(_lx, _ly, it.value().clickSize.width(), it.value().clickSize.height()); if (br.contains(click)) { if (!it.value().hilite) { mLabelHilite = true; mpMap->mapLabels[mAID][it.key()].hilite = true; } else { mpMap->mapLabels[mAID][it.key()].hilite = false; mLabelHilite = false; } update(); return; } } } mLabelHilite = false; update(); if (mMultiSelection && mMultiSelectionSet.size() > 0 && (event->modifiers().testFlag(Qt::ControlModifier))) { // We were dagging multi-selection rectange, we had selected at // least one room and the user has -clicked with the mouse // so switch off the dragging mMultiSelection = false; mHelpMsg.clear(); } } else { // In popup menu, so end that mPopupMenu = false; } // display room selection list widget if more than 1 room has been selected // -> user can manually change current selection if rooms are overlapping if (mMultiSelectionSet.size() > 1) { mMultiSelectionListWidget.blockSignals(true); // We don't want to cause calls to slot_roomSelectionChanged() here! mIsSelectionSorting = mMultiSelectionListWidget.isSortingEnabled(); mIsSelectionSortByNames = (mMultiSelectionListWidget.sortColumn() == 1); mMultiSelectionListWidget.clear(); mMultiSelectionListWidget.setSortingEnabled(false); // Do NOT sort whilst inserting items! QSetIterator itRoom = mMultiSelectionSet; mIsSelectionUsingNames = false; while (itRoom.hasNext()) { auto _item = new QTreeWidgetItem; int multiSelectionRoomId = itRoom.next(); _item->setText(0, QStringLiteral("%1").arg(multiSelectionRoomId, 7)); // Pad with spaces so sorting works _item->setTextAlignment(0, Qt::AlignRight); TRoom* pR_multiSelection = mpMap->mpRoomDB->getRoom(multiSelectionRoomId); if (pR_multiSelection) { QString multiSelectionRoomName = pR_multiSelection->name; if (!multiSelectionRoomName.isEmpty()) { _item->setText(1, multiSelectionRoomName); _item->setTextAlignment(1, Qt::AlignLeft); mIsSelectionUsingNames = true; } } mMultiSelectionListWidget.addTopLevelItem(_item); } mMultiSelectionListWidget.setColumnHidden(1, !mIsSelectionUsingNames); // Can't sort if nothing to sort on, switch to sorting by room number if ((!mIsSelectionUsingNames) && mIsSelectionSortByNames && mIsSelectionSorting) { mIsSelectionSortByNames = false; } mMultiSelectionListWidget.sortByColumn(mIsSelectionSortByNames ? 1 : 0); mMultiSelectionListWidget.setSortingEnabled(mIsSelectionSorting); resizeMultiSelectionWidget(); mMultiSelectionListWidget.selectAll(); mMultiSelectionListWidget.blockSignals(false); mMultiSelectionListWidget.show(); update(); } else { mMultiSelectionListWidget.hide(); } } if (event->buttons() & Qt::RightButton) { auto popup = new QMenu(this); if (mCustomLinesRoomFrom > 0) { if (mDialogLock) { return; } TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLinesRoomFrom); if (pR) { QAction* action = new QAction("undo", this); action->setStatusTip(tr("undo last point")); if (pR->customLines.value(mCustomLinesRoomExit).count() > 1) { connect(action, SIGNAL(triggered()), this, SLOT(slot_undoCustomLineLastPoint())); } else { action->setEnabled(false); } QAction* action2 = new QAction("properties", this); action2->setText("properties..."); action2->setStatusTip(tr("change the properties of this line")); connect(action2, SIGNAL(triggered()), this, SLOT(slot_customLineProperties())); QAction* action3 = new QAction("finish", this); action3->setStatusTip(tr("finish drawing this line")); connect(action3, SIGNAL(triggered()), this, SLOT(slot_doneCustomLine())); mPopupMenu = true; pR->calcRoomDimensions(); popup->addAction(action); popup->addAction(action2); popup->addAction(action3); popup->popup(mapToGlobal(event->pos())); update(); return; } } if (!mLabelHilite && mCustomLineSelectedRoom == 0) { QAction* action = new QAction("move", this); action->setStatusTip(tr("move room")); connect(action, SIGNAL(triggered()), this, SLOT(slot_moveRoom())); QAction* action2 = new QAction("delete", this); action2->setStatusTip(tr("delete room")); connect(action2, SIGNAL(triggered()), this, SLOT(slot_deleteRoom())); QAction* action3 = new QAction("color", this); action3->setStatusTip(tr("change room color")); connect(action3, SIGNAL(triggered()), this, SLOT(slot_changeColor())); QAction* action4 = new QAction("spread", this); action4->setStatusTip(tr("increase map X-Y spacing for the selected group of rooms")); connect(action4, SIGNAL(triggered()), this, SLOT(slot_spread())); QAction* action9 = new QAction("shrink", this); action9->setStatusTip(tr("decrease map X-Y spacing for the selected group of rooms")); connect(action9, SIGNAL(triggered()), this, SLOT(slot_shrink())); //QAction * action5 = new QAction("user data", this ); //action5->setStatusTip(tr("set user data")); //connect( action5, SIGNAL(triggered()), this, SLOT(slot_setUserData())); QAction* action6 = new QAction("lock", this); action6->setStatusTip(tr("lock room for speed walks")); connect(action6, SIGNAL(triggered()), this, SLOT(slot_lockRoom())); QAction* action17 = new QAction("unlock", this); action17->setStatusTip(tr("unlock room for speed walks")); connect(action17, SIGNAL(triggered()), this, SLOT(slot_unlockRoom())); QAction* action7 = new QAction("weight", this); action7->setStatusTip(tr("set room weight")); connect(action7, SIGNAL(triggered()), this, SLOT(slot_setRoomWeight())); QAction* action8 = new QAction("exits", this); action8->setStatusTip(tr("set room exits")); connect(action8, SIGNAL(triggered()), this, SLOT(slot_setExits())); QAction* action10 = new QAction("letter", this); action10->setStatusTip(tr("set a letter to mark special rooms")); connect(action10, SIGNAL(triggered()), this, SLOT(slot_setCharacter())); // QAction * action11 = new QAction("image", this ); // action11->setStatusTip(tr("set an image to mark special rooms")); // connect( action11, SIGNAL(triggered()), this, SLOT(slot_setImage())); QAction* action12 = new QAction("move to", this); action12->setStatusTip(tr("move selected group to a given position")); connect(action12, SIGNAL(triggered()), this, SLOT(slot_movePosition())); QAction* action13 = new QAction("area", this); action13->setStatusTip(tr("set room area ID")); connect(action13, SIGNAL(triggered()), this, SLOT(slot_setArea())); QAction* action14 = new QAction("custom exit lines", this); TArea* pArea = mpMap->mpRoomDB->getArea(mAID); if (!pArea) { return; } if (pArea->gridMode) { // Disable custom exit lines in grid mode as they aren't visible anyway action14->setStatusTip(tr("custom exit lines are not shown and are not editable in grid mode")); action14->setEnabled(false); } else { action14->setStatusTip(tr("replace an exit line with a custom line")); connect(action14, SIGNAL(triggered()), this, SLOT(slot_setCustomLine())); } QAction* action15 = new QAction("create Label", this); action15->setStatusTip(tr("Create labels to show text or images.")); connect(action15, SIGNAL(triggered()), this, SLOT(slot_createLabel())); QAction* action16 = new QAction("set location", this); if (mMultiSelectionSet.size() == 1) { // Only enable if ONE room is highlighted action16->setStatusTip(tr("set player current location to here")); connect(action16, SIGNAL(triggered()), this, SLOT(slot_setPlayerLocation())); } else { action16->setEnabled(false); action16->setStatusTip(tr("cannot set location when not exactly one room selected")); } mPopupMenu = true; // QMenu * popup = new QMenu( this ); popup->addAction(action); popup->addAction(action8); popup->addAction(action14); popup->addAction(action3); popup->addAction(action10); //popup->addAction( action11 ); popup->addAction(action4); popup->addAction(action9); //popup->addAction( action5 ); popup->addAction(action6); popup->addAction(action17); popup->addAction(action7); popup->addAction(action2); popup->addAction(action12); popup->addAction(action13); popup->addAction(action15); popup->addAction(action16); popup->popup(mapToGlobal(event->pos())); } else if (mLabelHilite) { QAction* action = new QAction("move", this); action->setStatusTip(tr("move label")); connect(action, SIGNAL(triggered()), this, SLOT(slot_moveLabel())); QAction* action2 = new QAction("delete", this); action2->setStatusTip(tr("delete label")); connect(action2, SIGNAL(triggered()), this, SLOT(slot_deleteLabel())); mPopupMenu = true; popup->addAction(action); popup->addAction(action2); popup->popup(mapToGlobal(event->pos())); } else { // seems that if we get here then we have right clicked on a selected custom line? // qDebug("T2DMap::mousePressEvent(): reached else case, mCustomLineSelectedRoom=%i, Exit=%s, Point=%i", // mCustomLineSelectedRoom, // qPrintable(mCustomLineSelectedExit), // mCustomLineSelectedPoint); if (mCustomLineSelectedRoom > 0) { TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLineSelectedRoom); if (pR) { QAction* action = new QAction("add point", this); if (mCustomLineSelectedPoint > -1) // The first user manipulable point IS zero - line is // drawn to it from a point around room symbol dependent // on the exit direction - and we can now add even to it { connect(action, SIGNAL(triggered()), this, SLOT(slot_customLineAddPoint())); action->setStatusTip(tr("divide segment by adding a new point mid-way along")); } else { action->setEnabled(false); action->setStatusTip(tr("select a point first, then add a new point mid-way along the segment towards room")); } QAction* action2 = new QAction("remove point", this); // Permit this to be enabled if the current point is 0 or greater, but not if there is no others if (mCustomLineSelectedPoint > -1) { if (pR->customLines.value(mCustomLineSelectedExit).count() > 1) { connect(action2, SIGNAL(triggered()), this, SLOT(slot_customLineRemovePoint())); if ((mCustomLineSelectedPoint + 1) < pR->customLines.value(mCustomLineSelectedExit).count()) { action2->setStatusTip(tr("merge pair of segments by removing this point")); } else { action2->setStatusTip(tr("remove last segment by removing this point")); } } else { action2->setEnabled(false); action2->setStatusTip(tr(R"(use "delete line" to remove the only segment ending in an editable point)")); } } else { action2->setEnabled(false); action2->setStatusTip(tr("select a point first, then remove it")); } QAction* action3 = new QAction("properties", this); action3->setText("properties..."); action3->setStatusTip(tr("change the properties of this custom line")); connect(action3, SIGNAL(triggered()), this, SLOT(slot_customLineProperties())); QAction* action4 = new QAction("delete line", this); action4->setStatusTip(tr("delete all of this custom line")); connect(action4, SIGNAL(triggered()), this, SLOT(slot_deleteCustomExitLine())); mPopupMenu = true; popup->addAction(action); popup->addAction(action2); popup->addAction(action3); popup->addAction(action4); popup->popup(mapToGlobal(event->pos())); } } } //this is placed at the end since it is likely someone will want to hook anywhere QMap userMenus; QMapIterator it(mUserMenus); while (it.hasNext()) { it.next(); QStringList menuInfo = it.value(); QString displayName = menuInfo[1]; auto userMenu = new QMenu(displayName, this); userMenus.insert(it.key(), userMenu); } it.toFront(); while (it.hasNext()) { //take care of nested menus now since they're all made it.next(); QStringList menuInfo = it.value(); QString menuParent = menuInfo[0]; if (menuParent == "") { //parentless popup->addMenu(userMenus[it.key()]); } else { //has a parent userMenus[menuParent]->addMenu(userMenus[it.key()]); } } //add our actions QMapIterator it2(mUserActions); auto mapper = new QSignalMapper(this); while (it2.hasNext()) { it2.next(); QStringList actionInfo = it2.value(); auto action = new QAction(actionInfo[2], this); if (actionInfo[1] == "") { //no parent popup->addAction(action); } else if (userMenus.contains(actionInfo[1])) { userMenus[actionInfo[1]]->addAction(action); } else { continue; } mapper->setMapping(action, it2.key()); connect(action, SIGNAL(triggered()), mapper, SLOT(map())); } connect(mapper, SIGNAL(mapped(QString)), this, SLOT(slot_userAction(QString))); mLastMouseClick = event->localPos(); } update(); } // Used both by "properties..." context menu item for existing lines AND // during drawing new ones. void T2DMap::slot_customLineProperties() { QString exit; TRoom* pR; if (mCustomLineSelectedRoom > 0) { pR = mpMap->mpRoomDB->getRoom(mCustomLineSelectedRoom); exit = mCustomLineSelectedExit; } else { pR = mpMap->mpRoomDB->getRoom(mCustomLinesRoomFrom); exit = mCustomLinesRoomExit; } if (pR) { if (exit.isEmpty()) { qDebug("T2DMap::slot_customLineProperties() called but no exit is selected..."); return; } if (pR->customLines.contains(exit)) { QUiLoader loader; QFile file(":/ui/custom_lines_properties.ui"); file.open(QFile::ReadOnly); QDialog* d = qobject_cast(loader.load(&file, this)); file.close(); if (!d) { qWarning("T2DMap::slot_customLineProperties() ERROR: failed to create the dialog!"); return; } d->setWindowIcon(QIcon(QStringLiteral(":/icons/mudlet_custom_exit_properties.png"))); QLineEdit* le_toId = d->findChild("toId"); QLineEdit* le_fromId = d->findChild("fromId"); QLineEdit* le_cmd = d->findChild("cmd"); mpCurrentLineStyle = d->findChild("lineStyle"); mpCurrentLineColor = d->findChild("lineColor"); mpCurrentLineArrow = d->findChild("arrow"); if (!le_toId || !le_cmd || !le_fromId || !mpCurrentLineStyle || !mpCurrentLineColor || !mpCurrentLineArrow) { qWarning("T2DMap::slot_customLineProperties() ERROR: failed to find an element in the dialog!"); return; } le_cmd->setText(exit); le_fromId->setText(QString::number(pR->getId())); if (exit == "NW") { le_toId->setText(QString::number(pR->getNorthwest())); } else if (exit == "N") { le_toId->setText(QString::number(pR->getNorth())); } else if (exit == "NE") { le_toId->setText(QString::number(pR->getNortheast())); } else if (exit == "UP") { le_toId->setText(QString::number(pR->getUp())); } else if (exit == "W") { le_toId->setText(QString::number(pR->getWest())); } else if (exit == "E") { le_toId->setText(QString::number(pR->getEast())); } else if (exit == "DOWN") { le_toId->setText(QString::number(pR->getDown())); } else if (exit == "SW") { le_toId->setText(QString::number(pR->getSouthwest())); } else if (exit == "S") { le_toId->setText(QString::number(pR->getSouth())); } else if (exit == "SE") { le_toId->setText(QString::number(pR->getSoutheast())); } else if (exit == "IN") { le_toId->setText(QString::number(pR->getIn())); } else if (exit == "OUT") { le_toId->setText(QString::number(pR->getOut())); } else { bool isFound = false; QMultiMap otherExits = pR->getOtherMap(); QMapIterator otherExitIt = otherExits; while (otherExitIt.hasNext()) { otherExitIt.next(); if (otherExitIt.value().startsWith("0") || otherExitIt.value().startsWith("1")) { if (otherExitIt.value().mid(1) == exit) { le_toId->setText(QString::number(otherExitIt.key())); isFound = true; break; } } else if (otherExitIt.value() == exit) { le_toId->setText(QString::number(otherExitIt.key())); isFound = true; break; } } if (!isFound) { qWarning(R"(T2DMap::slot_customLineProperties() - WARNING: missing command "%s" from custom lines for room id %i)", qPrintable(exit), pR->getId()); } } QStringList _lineStyles; _lineStyles << "solid line" << "dot line" << "dash line" << "dash dot line" << "dash dot dot line"; mpCurrentLineStyle->addItems(_lineStyles); QString _lineStyle = pR->customLinesStyle.value(exit); mpCurrentLineStyle->setCurrentIndex(mpCurrentLineStyle->findText(_lineStyle)); mpCurrentLineArrow->setChecked(pR->customLinesArrow.value(exit)); mCurrentLineColor.setRed(pR->customLinesColor.value(exit).at(0)); mCurrentLineColor.setGreen(pR->customLinesColor.value(exit).at(1)); mCurrentLineColor.setBlue(pR->customLinesColor.value(exit).at(2)); QString _styleSheet = QString("background-color:" + mCurrentLineColor.name()); mpCurrentLineColor->setStyleSheet(_styleSheet); connect(mpCurrentLineColor, SIGNAL(clicked()), this, SLOT(slot_customLineColor())); if (d->exec() == QDialog::Accepted) { // Make the changes pR->customLinesStyle[exit] = mpCurrentLineStyle->currentText(); mCurrentLineStyle = mpCurrentLineStyle->currentText(); pR->customLinesColor[exit][0] = mCurrentLineColor.red(); pR->customLinesColor[exit][1] = mCurrentLineColor.green(); pR->customLinesColor[exit][2] = mCurrentLineColor.blue(); pR->customLinesArrow[exit] = mpCurrentLineArrow->checkState(); mCurrentLineArrow = mpCurrentLineArrow->checkState(); } } repaint(); } else { qDebug("T2DMap::slot_customLineProperties() called but no line is selected..."); } } void T2DMap::slot_customLineAddPoint() { TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLineSelectedRoom); if (!pR) { return; } if (mCustomLineSelectedPoint > 0) { QLineF segment = QLineF(pR->customLines.value(mCustomLineSelectedExit).at(mCustomLineSelectedPoint - 1), pR->customLines.value(mCustomLineSelectedExit).at(mCustomLineSelectedPoint)); segment.setLength(segment.length() / 2.0); pR->customLines[mCustomLineSelectedExit].insert(mCustomLineSelectedPoint, segment.p2()); mCustomLineSelectedPoint++; repaint(); } else if (mCustomLineSelectedPoint == 0) { // The first user manipulable point IS zero - line is drawn to it from a // point around room symbol dependent on the exit direction // The first segment of custom line stick out half of the distance // between two rooms at a map unit vector distance apart. so an added // point inserted before the first must be placed halfway between // the offset point and the previosu first point QPointF customLineStartPoint; if (mCustomLineSelectedExit == "N") { customLineStartPoint = QPointF(pR->x, pR->y + 0.5); } else if (mCustomLineSelectedExit == "S") { customLineStartPoint = QPointF(pR->x, pR->y - 0.5); } else if (mCustomLineSelectedExit == "E") { customLineStartPoint = QPointF(pR->x + 0.5, pR->y); } else if (mCustomLineSelectedExit == "W") { customLineStartPoint = QPointF(pR->x - 0.5, pR->y); } else if (mCustomLineSelectedExit == "NE") { customLineStartPoint = QPointF(pR->x + 0.5, pR->y + 0.5); } else if (mCustomLineSelectedExit == "NW") { customLineStartPoint = QPointF(pR->x - 0.5, pR->y + 0.5); } else if (mCustomLineSelectedExit == "SE") { customLineStartPoint = QPointF(pR->x + 0.5, pR->y - 0.5); } else if (mCustomLineSelectedExit == "SW") { customLineStartPoint = QPointF(pR->x - 0.5, pR->y - 0.5); } else { customLineStartPoint = QPointF(pR->x, pR->y); } QLineF segment = QLineF(customLineStartPoint, pR->customLines.value(mCustomLineSelectedExit).at(0)); segment.setLength(segment.length() / 2.0); pR->customLines[mCustomLineSelectedExit].insert(mCustomLineSelectedPoint, segment.p2()); mCustomLineSelectedPoint++; repaint(); } } void T2DMap::slot_customLineRemovePoint() { TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLineSelectedRoom); if (!pR) { return; } if (mCustomLineSelectedPoint > 0) { pR->customLines[mCustomLineSelectedExit].removeAt(mCustomLineSelectedPoint); mCustomLineSelectedPoint--; repaint(); } else if (mCustomLineSelectedPoint == 0 && pR->customLines.value(mCustomLineSelectedExit).count() > 1) { // The first user manipulable point IS zero - line is drawn to it from a // point around room symbol dependent on the exit direction. We can only // allow it's deletion if there is at least another one left. pR->customLines[mCustomLineSelectedExit].removeAt(mCustomLineSelectedPoint); repaint(); } } void T2DMap::slot_undoCustomLineLastPoint() { if (mCustomLinesRoomFrom > 0) { TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLinesRoomFrom); if (pR) { if (pR->customLines.value(mCustomLinesRoomExit).count() > 0) { pR->customLines[mCustomLinesRoomExit].pop_back(); } pR->calcRoomDimensions(); } repaint(); } } void T2DMap::slot_doneCustomLine() { if (mpCustomLinesDialog) { mpCustomLinesDialog->accept(); mpCustomLinesDialog = 0; } mHelpMsg = ""; mCustomLinesRoomFrom = 0; mCustomLinesRoomTo = 0; mCustomLinesRoomExit.clear(); if (mMultiSelectionSet.size() > 0) { TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLineSelectedRoom); if (pR) { pR->calcRoomDimensions(); } } update(); } void T2DMap::slot_deleteCustomExitLine() { if (mCustomLineSelectedRoom > 0) { TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLineSelectedRoom); if (pR) { pR->customLinesArrow.remove(mCustomLineSelectedExit); pR->customLinesColor.remove(mCustomLineSelectedExit); pR->customLinesStyle.remove(mCustomLineSelectedExit); pR->customLines.remove(mCustomLineSelectedExit); mCustomLineSelectedRoom = 0; mCustomLineSelectedExit = ""; mCustomLineSelectedPoint = -1; repaint(); pR->calcRoomDimensions(); TArea* pA = mpMap->mpRoomDB->getArea(pR->getArea()); if (pA) { pA->calcSpan(); } } } } void T2DMap::slot_moveLabel() { mMoveLabel = true; } void T2DMap::slot_deleteLabel() { if (mpMap->mapLabels.contains(mAID)) { QList deleteList; QMapIterator it(mpMap->mapLabels[mAID]); while (it.hasNext()) { it.next(); int _zlevel = static_cast(it.value().pos.z()); if (_zlevel != mOz) { continue; } if (it.value().hilite) { deleteList.push_back(it.key()); } } for (int& i : deleteList) { mpMap->mapLabels[mAID].remove(i); } } update(); } void T2DMap::slot_editLabel() { } void T2DMap::slot_setPlayerLocation() { if (mMultiSelectionSet.size() != 1) { return; // Was <= 1 but that can't be right, and >1 doesn't seem right either } int _newRoomId = *(mMultiSelectionSet.constBegin()); if (mpMap->mpRoomDB->getRoom(_newRoomId)) { // No need to check it is a DIFFERENT room - that is taken care of by en/dis-abling the control mpMap->mRoomIdHash[mpHost->getName()] = _newRoomId; mpMap->mNewMove = true; TEvent manualSetEvent; manualSetEvent.mArgumentList.append(QLatin1String("sysManualLocationSetEvent")); manualSetEvent.mArgumentTypeList.append(ARGUMENT_TYPE_STRING); manualSetEvent.mArgumentList.append(QString::number(_newRoomId)); manualSetEvent.mArgumentTypeList.append(ARGUMENT_TYPE_NUMBER); mpHost->raiseEvent(manualSetEvent); update(); } } void T2DMap::slot_userAction(QString uniqueName) { TEvent event; QStringList userEvent = mUserActions[uniqueName]; event.mArgumentList.append(userEvent[0]); event.mArgumentTypeList.append(ARGUMENT_TYPE_STRING); event.mArgumentList.append(uniqueName); event.mArgumentTypeList.append(ARGUMENT_TYPE_STRING); QSetIterator itRoom(mMultiSelectionSet); if (itRoom.hasNext()) { while (itRoom.hasNext()) { event.mArgumentList.append(QString::number(itRoom.next())); event.mArgumentTypeList.append(ARGUMENT_TYPE_NUMBER); } mpHost->raiseEvent(event); } // Unreachable code as had effectively the same test as the previous "if" // mMultiSelectionList is now mMultiSelectionSet: // else if( mMultiSelectionList.size() > 0 ) // { // event.mArgumentList.append(QString::number(mMultiSelectionList[0])); // event.mArgumentTypeList.append(ARGUMENT_TYPE_NUMBER); // mpHost->raiseEvent( & event ); // } else { event.mArgumentList.append(uniqueName); event.mArgumentTypeList.append(ARGUMENT_TYPE_STRING); for (int i = 0; i < userEvent.size(); i++) { event.mArgumentList.append(userEvent[i]); event.mArgumentTypeList.append(ARGUMENT_TYPE_STRING); } mpHost->raiseEvent(event); } } void T2DMap::slot_movePosition() { if (!getCenterSelection()) { return; } TRoom* pR_start = mpMap->mpRoomDB->getRoom(mMultiSelectionHighlightRoomId); // pR has already been validated by getCenterSelection() auto pD = new QDialog(this); auto pL = new QGridLayout; pD->setLayout(pL); pD->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); pD->setContentsMargins(0, 0, 0, 0); auto pLEx = new QLineEdit(pD); auto pLEy = new QLineEdit(pD); auto pLEz = new QLineEdit(pD); pLEx->setText(QString::number(pR_start->x)); pLEy->setText(QString::number(pR_start->y)); pLEz->setText(QString::number(pR_start->z)); QLabel* pLa0 = new QLabel(tr("Move the selection, centered on\nthe highlighted room (%1) to:").arg(mMultiSelectionHighlightRoomId)); // Record the starting coordinates - can be a help when working out how to move a block of rooms! QLabel* pLa1 = new QLabel(tr("x coordinate (was %1):").arg(pR_start->x)); QLabel* pLa2 = new QLabel(tr("y coordinate (was %1):").arg(pR_start->y)); QLabel* pLa3 = new QLabel(tr("z coordinate (was %1):").arg(pR_start->z)); pL->addWidget(pLa0, 0, 0, 1, 2, Qt::AlignCenter); pL->addWidget(pLa1, 1, 0, Qt::AlignVCenter | Qt::AlignRight); pL->addWidget(pLEx, 1, 1, Qt::AlignVCenter | Qt::AlignLeft); pL->addWidget(pLa2, 2, 0, Qt::AlignVCenter | Qt::AlignRight); pL->addWidget(pLEy, 2, 1, Qt::AlignVCenter | Qt::AlignLeft); pL->addWidget(pLa3, 3, 0, Qt::AlignVCenter | Qt::AlignRight); pL->addWidget(pLEz, 3, 1, Qt::AlignVCenter | Qt::AlignLeft); auto pButtonBar = new QWidget(pD); auto pL2 = new QHBoxLayout; pButtonBar->setLayout(pL2); pButtonBar->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); auto pB_ok = new QPushButton(pButtonBar); pB_ok->setText("Ok"); pL2->addWidget(pB_ok); connect(pB_ok, SIGNAL(clicked()), pD, SLOT(accept())); auto pB_abort = new QPushButton(pButtonBar); pB_abort->setText("Cancel"); connect(pB_abort, SIGNAL(clicked()), pD, SLOT(reject())); pL2->addWidget(pB_abort); pL->addWidget(pButtonBar, 4, 0, 1, 2, Qt::AlignCenter); if (pD->exec() == QDialog::Accepted) { int dx = pLEx->text().toInt() - pR_start->x; int dy = pLEy->text().toInt() - pR_start->y; int dz = pLEz->text().toInt() - pR_start->z; mMultiRect = QRect(0, 0, 0, 0); QSetIterator itRoom = mMultiSelectionSet; while (itRoom.hasNext()) { TRoom* pR = mpMap->mpRoomDB->getRoom(itRoom.next()); if (!pR) { continue; } pR->x += dx; pR->y += dy; pR->z += dz; } } repaint(); } void T2DMap::slot_moveRoom() { mRoomBeingMoved = true; setMouseTracking(true); mNewMoveAction = true; } // TODO: Convert pR->c (a single ASCII character) to pR->symbol (a single Unicode Grapheme, possibly containing several QChars - as a QString) void T2DMap::slot_setCharacter() { // Now analysises and reports the existing letters used in ALL the selected // rooms if more than once (and sorts by their frequency) // Also allows the existing letters to be deleted (by clearing all the displayed // letters) as previous code DID NOT - and the Cancel option works as well! if (mMultiSelectionSet.size() < 1) { return; } // First scan and count all the different letters used QMap usedLetters; QSetIterator itRoom = mMultiSelectionSet; TRoom* pR; while (itRoom.hasNext()) { pR = mpMap->mpRoomDB->getRoom(itRoom.next()); if (!pR) { continue; } if (pR->c) { QString thisLetter = QString(pR->c); if (!thisLetter.isEmpty()) { if (usedLetters.contains(thisLetter)) { usedLetters[thisLetter] += 1; } else { usedLetters[thisLetter] = 1; } } } } QString newLetterText; bool isOk = false; // Choose most appropriate text depending on number of rooms selected and // how many of them have letters already: if (mMultiSelectionSet.size() == 1) { if (usedLetters.isEmpty()) { newLetterText = QInputDialog::getText(this, // QWidget * parent tr("Enter room marker"), // const QString & title tr("Enter new (not space)\n" "marker letter:"), // const QString & label QLineEdit::Normal, // QLineEdit::EchoMode mode = QLineEdit::Normal QString(), // const QString & text = QString() &isOk, // bool * ok = 0 0, // Qt::WindowFlags flags = 0 Qt::ImhLatinOnly); // Qt::InputMethodHints inputMethodHints = Qt::ImhNone } else { newLetterText = QInputDialog::getText(this, tr("Enter rooom marker"), tr("Delete the existing, or\n" "enter a new (non-space),\n" "marker letter:"), QLineEdit::Normal, usedLetters.keys().first(), &isOk, 0, Qt::ImhLatinOnly); } } else { if (usedLetters.isEmpty()) { newLetterText = QInputDialog::getText(this, tr("Enter room marker"), tr("Enter new (not space)\n" "marker letter:"), QLineEdit::Normal, QString(), &isOk, 0, Qt::ImhLatinOnly); } else if (usedLetters.size() == 1) { newLetterText = QInputDialog::getText(this, tr("Enter room marker"), tr("Delete the (only)\n" "existing (in some rooms),\n" "or enter a new (not\n" "space) marker letter for\n" "all selected rooms:"), QLineEdit::Normal, usedLetters.keys().first(), &isOk, 0, Qt::ImhLatinOnly); } else { QMapIterator itSymbolUsed = usedLetters; QSet symbolCountsSet; while (itSymbolUsed.hasNext()) { itSymbolUsed.next(); symbolCountsSet.insert(itSymbolUsed.value()); } QList symbolCountsList = symbolCountsSet.toList(); if (symbolCountsList.size() > 1) { std::sort(symbolCountsList.begin(), symbolCountsList.end()); } QStringList displayStrings; for (int i = symbolCountsList.size() - 1; i >= 0; --i) { itSymbolUsed.toFront(); while (itSymbolUsed.hasNext()) { itSymbolUsed.next(); if (itSymbolUsed.value() == symbolCountsList.at(i)) { displayStrings.append(tr("%1 {count:%2}").arg(itSymbolUsed.key(), itSymbolUsed.value())); } } } newLetterText = QInputDialog::getItem(this, // QWidget * parent tr("Enter room marker"), // const QString & title tr("Choose an existing marker\n" "letter) from the list\n" "(sorted by most commonly\n" "used first) or enter a\n" "new single ASCII\n" "character (not space) for\n" "all selected rooms:", // Intentional comment to separate two strings! "Use line feeds to format text into a reasonable rectangle."), // const QString & label displayStrings, // QStringList & items 0, // int current = 0 true, // bool editable = true &isOk, // bool * ok = 0 0, // Qt::WindowFlags flags = 0 Qt::ImhLatinOnly); // Qt::InputMethodHints inputMethodHints = Qt::ImhNone, // to change when I rework the room symbols for any Unicode Grapheme! } } QString newLetter; if (isOk) { // Don't proceed if cancel was pressed, will need revision to extract the // first grapheme when we support all printable unicode characters as room symbols! if (newLetterText.isEmpty()) { newLetter = QStringLiteral(" "); } else if (!newLetterText.at(0).isHighSurrogate()) { // The first QChar of the QString is NOT the start of a Unicode character beyond the BMP! if (newLetterText.at(0).row() == 0) { // The first QChar of the QString has a zero high byte if (newLetterText.at(0).cell() < 128) { // The first QChar of the QString has a low byte within the range for ASCII newLetter = newLetterText.at(0); } else { isOk = false; // Prevent any change if the value is not reasonable } } else { isOk = false; // Prevent any change if the value is not reasonable } } else { isOk = false; // Prevent any change if the value is not reasonable } } if (isOk) { itRoom.toFront(); while (itRoom.hasNext()) { pR = mpMap->mpRoomDB->getRoom(itRoom.next()); if (!pR) { continue; } if (newLetter.at(0) == QStringLiteral(" ")) { if (pR->c) { pR->c = 0; } } else { pR->c = newLetter.at(0).toLatin1(); } } } } void T2DMap::slot_setImage() { } void T2DMap::slot_deleteRoom() { mpMap->mpRoomDB->removeRoom(mMultiSelectionSet); // mMultiSelectionSet gets cleared as rooms are removed by // TRoomDB::removeRoom() so no need to clear it here! mMultiRect = QRect(0, 0, 0, 0); mMultiSelectionListWidget.clear(); mMultiSelectionListWidget.hide(); repaint(); } void T2DMap::slot_selectRoomColor(QListWidgetItem* pI) { mChosenRoomColor = pI->text().toInt(); } void T2DMap::slot_defineNewColor() { auto color = QColorDialog::getColor(mpHost->mRed, this); if (color.isValid()) { mpMap->customEnvColors[mpMap->customEnvColors.size() + 257 + 16] = color; slot_changeColor(); } repaint(); } void T2DMap::slot_changeColor() { mChosenRoomColor = 5; auto pD = new QDialog(this); auto pL = new QVBoxLayout; pD->setLayout(pL); pD->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); pD->setContentsMargins(0, 0, 0, 0); auto pLW = new QListWidget(pD); pLW->setViewMode(QListView::IconMode); connect(pLW, SIGNAL(itemDoubleClicked(QListWidgetItem*)), pD, SLOT(accept())); connect(pLW, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slot_selectRoomColor(QListWidgetItem*))); pL->addWidget(pLW); auto pButtonBar = new QWidget(pD); auto pL2 = new QHBoxLayout; pButtonBar->setLayout(pL2); pButtonBar->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); auto pB_newColor = new QPushButton(pButtonBar); pB_newColor->setText("define new color"); connect(pB_newColor, SIGNAL(clicked()), pD, SLOT(reject())); connect(pB_newColor, SIGNAL(clicked()), this, SLOT(slot_defineNewColor())); pL2->addWidget(pB_newColor); auto pB_ok = new QPushButton(pButtonBar); pB_ok->setText("ok"); pL2->addWidget(pB_ok); connect(pB_ok, SIGNAL(clicked()), pD, SLOT(accept())); auto pB_abort = new QPushButton(pButtonBar); pB_abort->setText("abort"); connect(pB_abort, SIGNAL(clicked()), pD, SLOT(reject())); pL2->addWidget(pB_abort); pL->addWidget(pButtonBar); QMapIterator it(mpMap->customEnvColors); while (it.hasNext()) { it.next(); QColor c; c = it.value(); auto pI = new QListWidgetItem(pLW); QPixmap pix = QPixmap(50, 50); pix.fill(c); QIcon mi(pix); pI->setIcon(mi); pI->setText(QString::number(it.key())); pLW->addItem(pI); } if (pD->exec() == QDialog::Accepted && mpMap->customEnvColors.contains(mChosenRoomColor)) { // Only proceed if OK - "abort" now prevents change AND check for a valid // color here rather than inside the room change loop as before (only test // once rather than for each room) mMultiRect = QRect(0, 0, 0, 0); QSetIterator itSelectedRoom(mMultiSelectionSet); while (itSelectedRoom.hasNext()) { TRoom* pR = mpMap->mpRoomDB->getRoom(itSelectedRoom.next()); if (pR) { pR->environment = mChosenRoomColor; } } update(); } } void T2DMap::slot_spread() { if (mMultiSelectionSet.size() < 2) { // nothing to do! return; } TRoom* pR_centerRoom = mpMap->mpRoomDB->getRoom(mMultiSelectionHighlightRoomId); if (!pR_centerRoom) { return; } // Move the dialog down to here so it doesn't fire up for some already // determined to be null (no change) case, also handle "Cancel" being pressed bool isOk = false; int spread = QInputDialog::getInt(this, tr("Spread out rooms"), tr("Increase the spacing of\n" "the selected rooms,\n" "centered on the\n" "highlighted room by a\n" "factor of:"), 5, // Initial value 1, // Minimum value 2147483647, // Maximum value 1, // Step &isOk); if (spread == 1 || !isOk) { return; } mMultiRect = QRect(0, 0, 0, 0); int dx = pR_centerRoom->x * (1 - spread); int dy = pR_centerRoom->y * (1 - spread); QSetIterator itSelectionRoom = mMultiSelectionSet; while (itSelectionRoom.hasNext()) { TRoom* pMovingR = mpMap->mpRoomDB->getRoom(itSelectionRoom.next()); if (!pMovingR) { continue; } pMovingR->x *= spread; pMovingR->y *= spread; pMovingR->x += dx; pMovingR->y += dy; QMapIterator> itCustomLine(pMovingR->customLines); QMap> newCustomLinePointsMap; while (itCustomLine.hasNext()) { itCustomLine.next(); QList customLinePoints = itCustomLine.value(); for (auto& customLinePoint : customLinePoints) { QPointF movingPoint = customLinePoint; customLinePoint.setX((float)(movingPoint.x() * spread + dx)); customLinePoint.setY((float)(movingPoint.y() * spread + dy)); } newCustomLinePointsMap.insert(itCustomLine.key(), customLinePoints); } pMovingR->customLines = newCustomLinePointsMap; pMovingR->calcRoomDimensions(); } repaint(); } void T2DMap::slot_shrink() { if (mMultiSelectionSet.size() < 2) { // nothing to do! return; } TRoom* pR_centerRoom = mpMap->mpRoomDB->getRoom(mMultiSelectionHighlightRoomId); if (!pR_centerRoom) { return; } // Move the dialog down to here so it doesn't fire up for some already // determined to be null (no change) case, also handle "Cancel" being pressed bool isOk = false; int spread = QInputDialog::getInt(this, tr("Shrink in rooms"), tr("Decrease the spacing of\n" "the selected rooms,\n" "centered on the\n" "highlighted room by a\n" "factor of:"), 5, // Initial value 1, // Minimum value 2147483647, // Maximum value 1, // Step &isOk); if (spread == 1 || !isOk) { return; } mMultiRect = QRect(0, 0, 0, 0); int dx = pR_centerRoom->x * (1 - 1 / spread); int dy = pR_centerRoom->y * (1 - 1 / spread); QSetIterator itSelectionRoom(mMultiSelectionSet); while (itSelectionRoom.hasNext()) { TRoom* pMovingR = mpMap->mpRoomDB->getRoom(itSelectionRoom.next()); if (!pMovingR) { continue; } pMovingR->x /= spread; pMovingR->y /= spread; pMovingR->x += dx; pMovingR->y += dy; QMapIterator> itCustomLine(pMovingR->customLines); QMap> newCustomLinePointsMap; while (itCustomLine.hasNext()) { itCustomLine.next(); QList customLinePoints = itCustomLine.value(); for (auto& customLinePoint : customLinePoints) { QPointF movingPoint = customLinePoint; customLinePoint.setX((float)(movingPoint.x() / spread + dx)); customLinePoint.setY((float)(movingPoint.y() / spread + dy)); } newCustomLinePointsMap.insert(itCustomLine.key(), customLinePoints); } pMovingR->customLines = newCustomLinePointsMap; pMovingR->calcRoomDimensions(); } repaint(); } void T2DMap::slot_setExits() { if (mMultiSelectionSet.size() < 1) { return; } if (mpMap->mpRoomDB->getRoom(mMultiSelectionHighlightRoomId)) { auto pD = new dlgRoomExits(mpHost, this); pD->init(mMultiSelectionHighlightRoomId); pD->show(); pD->raise(); } } void T2DMap::slot_setUserData() { } void T2DMap::slot_lockRoom() { if (mMultiSelectionSet.size() < 1) { return; } mMultiRect = QRect(0, 0, 0, 0); QSetIterator itSelectedRoom(mMultiSelectionSet); while (itSelectedRoom.hasNext()) { TRoom* pR = mpMap->mpRoomDB->getRoom(itSelectedRoom.next()); if (pR) { pR->isLocked = true; mpMap->mMapGraphNeedsUpdate = true; } } } void T2DMap::slot_unlockRoom() { if (mMultiSelectionSet.size() < 1) { return; } mMultiRect = QRect(0, 0, 0, 0); QSetIterator itSelectedRoom(mMultiSelectionSet); while (itSelectedRoom.hasNext()) { TRoom* pR = mpMap->mpRoomDB->getRoom(itSelectedRoom.next()); if (pR) { pR->isLocked = false; mpMap->mMapGraphNeedsUpdate = true; } } } void T2DMap::slot_setRoomWeight() { if (mMultiSelectionSet.isEmpty()) { return; } // First scan and count all the different weights used QMap usedWeights; // key is weight, value is count of uses QSetIterator itSelectedRoom = mMultiSelectionSet; TRoom* pR; while (itSelectedRoom.hasNext()) { pR = mpMap->mpRoomDB->getRoom(itSelectedRoom.next()); if (!pR) { continue; } int w = pR->getWeight(); if (w > 0) { if (usedWeights.contains(w)) { usedWeights[w] += 1; } else { usedWeights[w] = 1; } } } int newWeight = 1; bool isOk = false; // Choose most appropriate weight dialog on number of rooms selected and // how many of them have different weights already: if (mMultiSelectionSet.size() == 1) { // Just one room selected newWeight = QInputDialog::getInt(this, tr("Enter room weight"), tr("Enter new roomweight\n" "(= travel time), mimimum\n" "(and default) is 1:", "Use line feeds to format text into a reasonable rectangle."), usedWeights.keys().first(), 1, 2147483647, 1, &isOk); } else { // More than one room selected if (usedWeights.size() == 1) { newWeight = QInputDialog::getInt(this, tr("Enter room weight"), tr("Enter new roomweight\n" "(= travel time) for all\n" "selected rooms, mimimum\n" "(and default) is 1 and\n" "the only current value\n" "used is:", "Use line feeds to format text into a reasonable rectangle."), usedWeights.keys().first(), 1, 2147483647, 1, &isOk); } else { QMapIterator itWeightsUsed = usedWeights; // Obtain a set of "used" weights QSet weightCountsSet; while (itWeightsUsed.hasNext()) { itWeightsUsed.next(); weightCountsSet.insert(itWeightsUsed.value()); } // Obtains a list of those weights sorted in ascending count of used QList weightCountsList = weightCountsSet.toList(); if (weightCountsList.size() > 1) { std::sort(weightCountsList.begin(), weightCountsList.end()); } // Build a list of the "used" weights in decending count of use QStringList displayStrings; for (int i = weightCountsList.size() - 1; i >= 0; --i) { itWeightsUsed.toFront(); while (itWeightsUsed.hasNext()) { itWeightsUsed.next(); if (itWeightsUsed.value() == weightCountsList.at(i)) { if (itWeightsUsed.key() == 1) { // Indicate the "default" value which is unity weight displayStrings.append(tr("%1 {count:%2, default}").arg(itWeightsUsed.key(), itWeightsUsed.value())); } else { displayStrings.append(tr("%1 {count:%2}").arg(itWeightsUsed.key(), itWeightsUsed.value())); } } } } if (!usedWeights.contains(1)) { // If unity weight was not used insert it at end of list displayStrings.append(tr("1 {count 0, default}")); } QString newWeightText = QInputDialog::getItem(this, // QWidget * parent tr("Enter room weight"), // const QString & title tr("Choose an existing\n" "roomweight (= travel\n" "time) from the list\n" "(sorted by most commonly\n" "used first) or enter a\n" "new (positive) integer\n" "value for all selected\n" "rooms:", "Use line feeds to format text into a reasonable rectangle."), // const QString & label displayStrings, // QStringList & items 0, // int current = 0, last value in list true, // bool editable = true &isOk, // bool * ok = 0 0, // Qt::WindowFlags flags = 0 Qt::ImhDigitsOnly); // Qt::InputMethodHints inputMethodHints = Qt::ImhNone newWeight = 1; if (isOk) { // Don't do anything if cancel was pressed if (newWeightText.toInt() > 0) { newWeight = newWeightText.toInt(); } else { isOk = false; // Prevent any change if the value is not reasonable } } } } if (isOk && newWeight > 0) { // Don't proceed if cancel was pressed or the value is not valid itSelectedRoom.toFront(); while (itSelectedRoom.hasNext()) { pR = mpMap->mpRoomDB->getRoom(itSelectedRoom.next()); if (!pR) { continue; } pR->setWeight(newWeight); } mpMap->mMapGraphNeedsUpdate = true; repaint(); } } void T2DMap::slot_setArea() { QUiLoader loader; QFile file(":/ui/set_room_area.ui"); file.open(QFile::ReadOnly); QDialog* set_room_area_dialog = dynamic_cast(loader.load(&file, this)); file.close(); if (!set_room_area_dialog) { return; } arealist_combobox = set_room_area_dialog->findChild("arealist_combobox"); if (!arealist_combobox) { return; } QMapIterator it(mpMap->mpRoomDB->getAreaNamesMap()); while (it.hasNext()) { it.next(); int areaID = it.key(); if (areaID > 0) { arealist_combobox->addItem(QStringLiteral("%1 (%2)").arg(it.value(), QString::number(areaID)), QVariant(areaID)); } } if (set_room_area_dialog->exec() == QDialog::Rejected) { // Don't proceed if "cancel" was pressed return; } int newAreaId = arealist_combobox->itemData(arealist_combobox->currentIndex()).toInt(); mMultiRect = QRect(0, 0, 0, 0); QSetIterator itSelectedRoom = mMultiSelectionSet; while (itSelectedRoom.hasNext()) { int currentRoomId = itSelectedRoom.next(); if (itSelectedRoom.hasNext()) { // NOT the last room in set - so defer some area related recalculations mpMap->setRoomArea(currentRoomId, newAreaId, true); } else { // Is the LAST room, so be careful to do all that is needed to clean // up the affected areas (triggered by last "false" argument in next // line)... if (!(mpMap->setRoomArea(currentRoomId, newAreaId, false))) { // Failed on the last of multiple room area move so do the missed // out recalculations for the dirtied areas QSetIterator itpArea = mpMap->mpRoomDB->getAreaPtrList().toSet(); while (itpArea.hasNext()) { TArea* pArea = itpArea.next(); if (pArea->mIsDirty) { pArea->determineAreaExits(); pArea->calcSpan(); pArea->mIsDirty = false; } } } } } repaint(); } void T2DMap::mouseMoveEvent(QMouseEvent* event) { if (mpMap->mLeftDown && !mpMap->m2DPanMode && event->modifiers().testFlag(Qt::AltModifier)) { mpMap->m2DPanXStart = event->x(); mpMap->m2DPanYStart = event->y(); mpMap->m2DPanMode = true; } if (mpMap->m2DPanMode && !event->modifiers().testFlag(Qt::AltModifier)) { mpMap->m2DPanMode = false; mpMap->mLeftDown = false; } if (mpMap->m2DPanMode) { int x = event->x(); int y = height() - event->y(); if ((mpMap->m2DPanXStart - x) > 1) { shiftRight(); mpMap->m2DPanXStart = x; } else if ((mpMap->m2DPanXStart - x) < -1) { shiftLeft(); mpMap->m2DPanXStart = x; } if ((mpMap->m2DPanYStart - y) > 1) { shiftDown(); mpMap->m2DPanYStart = y; } else if ((mpMap->m2DPanYStart - y) < -1) { shiftUp(); mpMap->m2DPanYStart = y; } return; } if (mCustomLineSelectedRoom != 0 && mCustomLineSelectedPoint >= 0) { TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLineSelectedRoom); if (pR) { if (pR->customLines.contains(mCustomLineSelectedExit)) { if (pR->customLines[mCustomLineSelectedExit].size() > mCustomLineSelectedPoint) { float mx = event->pos().x() / mTX + mOx; float my = event->pos().y() / mTY + mOy; mx = mx - xspan / 2; my = yspan / 2 - my; QPointF pc = QPointF(mx, my); pR->customLines[mCustomLineSelectedExit][mCustomLineSelectedPoint] = pc; pR->calcRoomDimensions(); repaint(); return; } } } } mCustomLineSelectedPoint = -1; //FIXME: if (mLabelHilite) //mMoveLabel )//&& mLabelHilite ) { if (mpMap->mapLabels.contains(mAID)) { QMapIterator it(mpMap->mapLabels[mAID]); while (it.hasNext()) { it.next(); if (it.value().pos.z() != mOz) { continue; } if (!it.value().hilite) { continue; } int mx = event->pos().x() / mTX + mOx; int my = event->pos().y() / mTY + mOy; mx = mx - xspan / 2; my = yspan / 2 - my; QVector3D p = QVector3D(mx, my, mOz); mpMap->mapLabels[mAID][it.key()].pos = p; } } update(); } else { mMoveLabel = false; } if ((mMultiSelection && !mRoomBeingMoved) || mSizeLabel) { // (The drag to select (or size) rectangle is being actively resized and rooms are not being moved) // OR (We are sizing up a label) if (mNewMoveAction) { mMultiRect = QRect(event->pos(), event->pos()); mNewMoveAction = false; } else { mMultiRect.setBottomLeft(event->pos()); } int _roomID = mRID; if (!mpMap->mpRoomDB->getRoom(_roomID)) { return; } int _areaID = mAID; TArea* pArea = mpMap->mpRoomDB->getArea(_areaID); if (!pArea) { return; } float _rx = xspan / 2 * mTX - mTX * mOx; float _ry = yspan / 2 * mTY - mTY * mOy; if (!mSizeLabel) { // NOT sizing a label mMultiSelectionSet.clear(); QSetIterator itSelectedRoom(pArea->getAreaRooms()); while (itSelectedRoom.hasNext()) { int currentRoomId = itSelectedRoom.next(); TRoom* pR = mpMap->mpRoomDB->getRoom(currentRoomId); if (!pR) { continue; } int rx = pR->x * mTX + _rx; int ry = pR->y * -1 * mTY + _ry; int rz = pR->z; // copy rooms on all z-levels if the shift key is being pressed // CHECK: Consider adding z-level to multi-selection Widget? if (rz != mOz && !(event->modifiers().testFlag(Qt::ShiftModifier))) { continue; } QRectF dr; if (pArea->gridMode) { dr = QRectF(rx - mTX / 2, ry - mTY / 2, mTX, mTY); } else { dr = QRectF(rx - (mTX * rSize) / 2, ry - (mTY * rSize) / 2, mTX * rSize, mTY * rSize); } if (mMultiRect.contains(dr)) { mMultiSelectionSet.insert(currentRoomId); } } switch (mMultiSelectionSet.size()) { case 0: mMultiSelectionHighlightRoomId = -1; break; case 1: mMultiSelectionHighlightRoomId = mMultiSelectionSet.toList().first(); break; default: getCenterSelection(); // Sets mMultiSelectionHighlightRoomId to (a) central room } int mx = event->pos().x() / mTX; int my = event->pos().y() / mTY; mx = mx - xspan / 2 + 1; my = yspan / 2 - my - 1; TRoom* pR = mpMap->mpRoomDB->getRoom(mRID); if (pR) { mx += pR->x; my += pR->y; mOldMousePos = QPoint(mx, my); } if (mMultiSelectionSet.size() > 1) { mMultiSelectionListWidget.blockSignals(true); // We don't want to cause calls to slot_roomSelectionChanged() here! mIsSelectionSorting = mMultiSelectionListWidget.isSortingEnabled(); // Save sorting state before we switch it off mIsSelectionSortByNames = (mMultiSelectionListWidget.sortColumn() == 1); mMultiSelectionListWidget.clear(); mMultiSelectionListWidget.setSortingEnabled(false); // Do NOT sort whilst inserting items! QSetIterator itRoom = mMultiSelectionSet; mIsSelectionUsingNames = false; while (itRoom.hasNext()) { auto _item = new QTreeWidgetItem; int multiSelectionRoomId = itRoom.next(); _item->setText(0, QStringLiteral("%1").arg(multiSelectionRoomId, 7)); _item->setTextAlignment(0, Qt::AlignRight); TRoom* pR_multiSelection = mpMap->mpRoomDB->getRoom(multiSelectionRoomId); if (pR_multiSelection) { QString multiSelectionRoomName = pR_multiSelection->name; if (!multiSelectionRoomName.isEmpty()) { _item->setText(1, multiSelectionRoomName); _item->setTextAlignment(1, Qt::AlignLeft); mIsSelectionUsingNames = true; } } mMultiSelectionListWidget.addTopLevelItem(_item); } mMultiSelectionListWidget.setColumnHidden(1, !mIsSelectionUsingNames); // Can't sort if nothing to sort on, switch to sorting by room number if ((!mIsSelectionUsingNames) && mIsSelectionSortByNames && mIsSelectionSorting) { mIsSelectionSortByNames = false; } mMultiSelectionListWidget.sortByColumn(mIsSelectionSortByNames ? 1 : 0); mMultiSelectionListWidget.setSortingEnabled(mIsSelectionSorting); resizeMultiSelectionWidget(); mMultiSelectionListWidget.selectAll(); mMultiSelectionListWidget.blockSignals(false); mMultiSelectionListWidget.show(); } else { mMultiSelectionListWidget.hide(); } } update(); return; } if (mRoomBeingMoved && !mSizeLabel && !mMultiSelectionSet.isEmpty()) { mMultiRect = QRect(0, 0, 0, 0); int _roomID = mRID; if (!mpMap->mpRoomDB->getRoom(_roomID)) { return; } int _areaID = mAID; TArea* pArea = mpMap->mpRoomDB->getArea(_areaID); if (!pArea) { return; } // N/U: int ox = mOx; // N/U: int oy = mOy; // N/U: float _rx; // N/U: float _ry; // These tests are pointless - both branches produce the same results // if( ox*mTX > xspan/2*mTX ) // _rx = -(mTX*ox-xspan/2*mTX); // else // _rx = xspan/2*mTX-mTX*ox; // if( oy*mTY > yspan/2*mTY ) // _ry = -(mTY*oy-yspan/2*mTY); // else // _ry = yspan/2*mTY-mTY*oy; int mx = event->pos().x() / mTX + mOx; int my = event->pos().y() / mTY + mOy; mx = mx - xspan / 2 + 1; my = yspan / 2 - my - 1; int dx, dy; if (!getCenterSelection()) { return; } TRoom* pR = mpMap->mpRoomDB->getRoom(mMultiSelectionHighlightRoomId); if (!pR) { return; } dx = mx - pR->x; dy = my - pR->y; QSetIterator itRoom = mMultiSelectionSet; while (itRoom.hasNext()) { pR = mpMap->mpRoomDB->getRoom(itRoom.next()); if (pR) { pR->x += dx; pR->y += dy; pR->z = mOz; // allow groups to be moved to a different z-level with the map editor QMapIterator> itk(pR->customLines); QMap> newMap; while (itk.hasNext()) { itk.next(); QList _pL = itk.value(); for (auto& point : _pL) { QPointF op = point; point.setX((float)(op.x() + dx)); point.setY((float)(op.y() + dy)); } newMap.insert(itk.key(), _pL); } pR->customLines = newMap; pR->calcRoomDimensions(); } } repaint(); } } // Replacement for getTopLeftCenter - determines a room closest to geometrical // mean of all the room selected, the result is stored in the class member // mMultiSelectionHighlightRoomId and this returns true on successfully finding // such a room bool T2DMap::getCenterSelection() { mMultiSelectionHighlightRoomId = -1; if (mMultiSelectionSet.isEmpty()) { return false; } QSetIterator itRoom = mMultiSelectionSet; float mean_x = 0.0; float mean_y = 0.0; float mean_z = 0.0; uint processedRoomCount = 0; while (itRoom.hasNext()) { int currentRoomId = itRoom.next(); TRoom* pR = mpMap->mpRoomDB->getRoom(currentRoomId); if (!pR) { continue; } mean_x += (static_cast(pR->x - mean_x)) / ++processedRoomCount; mean_y += (static_cast(pR->y - mean_y)) / processedRoomCount; mean_z += (static_cast(pR->z - mean_z)) / processedRoomCount; } if (processedRoomCount) { itRoom.toFront(); float closestSquareDistance = -1.0; while (itRoom.hasNext()) { int currentRoomId = itRoom.next(); TRoom* pR = mpMap->mpRoomDB->getRoom(currentRoomId); if (!pR) { continue; } QVector3D meanToRoom(static_cast(pR->x) - mean_x, static_cast(pR->y) - mean_y, static_cast(pR->z) - mean_z); if (closestSquareDistance < -0.5) { // Don't use an equality to zero test, we are using floats so // need to allow for a little bit of fuzzzyness! closestSquareDistance = meanToRoom.lengthSquared(); mMultiSelectionHighlightRoomId = currentRoomId; } else { float currentRoomSquareDistance = meanToRoom.lengthSquared(); if (closestSquareDistance > currentRoomSquareDistance) { closestSquareDistance = currentRoomSquareDistance; mMultiSelectionHighlightRoomId = currentRoomId; } } } return true; } else { return false; } } void T2DMap::exportAreaImage(int id) { paintMap(); } void T2DMap::wheelEvent(QWheelEvent* e) { // If the mouse wheel is scrolling up and down through the // mMultiSelectionListWidget the wheelevents from that get passed up to here // when the end of the list is reached (i.e when it rejects those events) // - so that the mapper window doesn't THEN zoom in or out, swallow the // events, i.e. accept() them and return before hitting the zoom altering // code that follows. // However the event "pos()" depends on the widget it came from so we have // to use "globalPos()" instead and see how it lies in relation to the child // widget: QRect selectionListWidgetGlobalRect = QRect(mapToGlobal(mMultiSelectionListWidget.frameRect().topLeft()), mapToGlobal(mMultiSelectionListWidget.frameRect().bottomRight())); if (mMultiSelectionListWidget.isVisible() && selectionListWidgetGlobalRect.contains(e->globalPos())) { e->accept(); return; } if (!(mpMap->mpRoomDB->getRoom(mRID) && mpMap->mpRoomDB->getArea(mAID))) { return; } // int delta = e->delta() / 8 / 15; // Deprecated in Qt 5.x ...! int delta = e->angleDelta().y() / (8 * 15); if (e->modifiers() & Qt::ControlModifier) { // Increase rate 10-fold if control key down - it makes scrolling through // a large nuber of items in a listwidget's contents easier AND this make it // easier to zoom in and out on LARGE area maps delta *= 10; } if (delta != 0) { mPick = false; xzoom += delta; yzoom += delta; if (yzoom < 3) { // At present xzoom and yzoom alway will be the same I think yzoom = 3; } if (xzoom < 3) { xzoom = 3; } update(); e->accept(); return; } e->ignore(); return; } void T2DMap::setMapZoom(int zoom) { xzoom = zoom; yzoom = zoom; if (yzoom < 3 || xzoom < 3) { xzoom = 3; yzoom = 3; } } void T2DMap::setRoomSize(double f) { rSize = f; if (mpHost) { mpHost->mRoomSize = f; } } void T2DMap::setExitSize(double f) { eSize = f; if (mpHost) { mpHost->mLineSize = f; } } void T2DMap::slot_setCustomLine() { if (mMultiSelectionSet.isEmpty()) { return; } TRoom* pR = mpMap->mpRoomDB->getRoom(mMultiSelectionHighlightRoomId); if (!pR) { return; } if (mpCustomLinesDialog) { // Refuse to create another instance if one is already present! // Just show it... mpCustomLinesDialog->raise(); return; } QUiLoader loader; QFile file(":/ui/custom_lines.ui"); file.open(QFile::ReadOnly); QDialog* d = dynamic_cast(loader.load(&file, this)); file.close(); if (!d) { return; } d->setWindowIcon(QIcon(QStringLiteral(":/icons/mudlet_custom_exit.png"))); mCustomLinesRoomFrom = mMultiSelectionHighlightRoomId; mCustomLinesRoomTo = 0; mCustomLinesRoomExit = ""; QPushButton* b_ = d->findChild("nw"); QTreeWidget* specialExits = d->findChild("specialExits"); mpCurrentLineStyle = d->findChild("lineStyle"); mpCurrentLineColor = d->findChild("lineColor"); mpCurrentLineArrow = d->findChild("arrow"); if (!b_ || !specialExits || !mpCurrentLineColor || !mpCurrentLineStyle || !mpCurrentLineArrow) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "nw" exit line button or another element of the dialog!)"); return; } else if (pR->getNorthwest() <= 0) { b_->setCheckable(false); b_->setDisabled(true); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("NW") || pR->customLines.contains("nw")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("n"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "n" exit line button!)"); return; } else if (pR->getNorth() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("N") || pR->customLines.contains("n")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("ne"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "ne" exit line button!)"); return; } else if (pR->getNortheast() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("NE") || pR->customLines.contains("ne")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("up"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "up" exit line button!)"); return; } else if (pR->getUp() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("UP") || pR->customLines.contains("up")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("w"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "w" exit line button!)"); return; } else if (pR->getWest() <= 0) { b_->setCheckable(false); b_->setDisabled(true); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("W") || pR->customLines.contains("w")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("e"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "e" exit line button!)"); return; } else if (pR->getEast() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("E") || pR->customLines.contains("e")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("down"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "down" exit line button!)"); return; } else if (pR->getDown() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("DOWN") || pR->customLines.contains("down")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("sw"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "sw" exit line button!)"); return; } else if (pR->getSouthwest() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("SW") || pR->customLines.contains("sw")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("s"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "s" exit line button!)"); return; } else if (pR->getSouth() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("S") || pR->customLines.contains("s")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("se"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "se" exit line button!)"); return; } else if (pR->getSoutheast() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("SE") || pR->customLines.contains("se")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("in"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "in" exit line button!)"); return; } else if (pR->getIn() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("IN") || pR->customLines.contains("in")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } b_ = d->findChild("out"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "out" exit line button!)"); return; } else if (pR->getOut() <= 0) { b_->setDisabled(true); b_->setCheckable(false); } else { b_->setCheckable(true); b_->setChecked(pR->customLines.contains("OUT") || pR->customLines.contains("out")); connect(b_, SIGNAL(clicked()), this, SLOT(slot_setCustomLine2())); } QMapIterator it(pR->getOtherMap()); while (it.hasNext()) { it.next(); int id_to = it.key(); QString dir = it.value(); if (dir.size() > 1) { if (dir.startsWith('0') || dir.startsWith('1')) { dir = dir.mid(1); } } auto pI = new QTreeWidgetItem(specialExits); if (pR->customLines.contains(dir)) { pI->setCheckState(0, Qt::Checked); } else { pI->setCheckState(0, Qt::Unchecked); } pI->setTextAlignment(0, Qt::AlignHCenter); pI->setText(1, QString::number(id_to)); pI->setTextAlignment(1, Qt::AlignRight); pI->setText(2, dir); pI->setTextAlignment(2, Qt::AlignLeft); } b_ = d->findChild("button_cancel"); if (!b_) { qWarning(R"(T2DMap::slot_setCustomLine() ERROR: failed to find "cancel" button!)"); return; } connect(b_, SIGNAL(clicked()), d, SLOT(reject())); connect(d, SIGNAL(rejected()), this, SLOT(slot_cancelCustomLineDialog())); QStringList _lineStyles; _lineStyles << "solid line" << "dot line" << "dash line" << "dash dot line" << "dash dot dot line"; mpCurrentLineStyle->addItems(_lineStyles); mpCurrentLineStyle->setCurrentText(mCurrentLineStyle); mpCurrentLineArrow->setChecked(mCurrentLineArrow); mpCurrentLineColor->setStyleSheet("background-color:" + mCurrentLineColor.name()); connect(specialExits, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slot_setCustomLine2B(QTreeWidgetItem*, int))); connect(mpCurrentLineColor, SIGNAL(clicked()), this, SLOT(slot_customLineColor())); mpCustomLinesDialog = d; // Don't assign the pointer value to the class memeber until ready to go mpCustomLinesDialog->show(); mpCustomLinesDialog->raise(); mDialogLock = true; // Prevent any line drawing until dialog has been used } void T2DMap::slot_customLineColor() { QColor color; if (mCurrentLineColor.isValid()) { color = QColorDialog::getColor(mCurrentLineColor, this); } else { color = QColorDialog::getColor(mpHost->mFgColor_2, this); } if (color.isValid()) { mCurrentLineColor = color; QString styleSheet = QString("background-color:" + color.name()); mpCurrentLineColor->setStyleSheet(styleSheet); } } // Called by dialog's reject event which is caused at least by "X" button on // title bar and by ESC keypress... void T2DMap::slot_cancelCustomLineDialog() { mpCustomLinesDialog->deleteLater(); mpCustomLinesDialog = 0; mCustomLinesRoomFrom = 0; mCustomLinesRoomTo = 0; mCustomLinesRoomExit.clear(); mDialogLock = false; } void T2DMap::slot_setCustomLine2() { QPushButton* pB = qobject_cast(sender()); if (!pB) { if (mpCustomLinesDialog) { mpCustomLinesDialog->reject(); } else { // This is needed to escape from custom line exit drawing mode if // the dialog has disappeared, not likely I think/hope mCustomLinesRoomFrom = 0; mCustomLinesRoomTo = 0; mCustomLinesRoomExit.clear(); mDialogLock = false; } return; } QString exit = pB->text(); mpCustomLinesDialog->hide(); // Hide but don't delete until done the custom line mCustomLinesRoomExit = exit; mDialogLock = false; TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLinesRoomFrom); if (!pR) { return; } if (exit == "NW") { mCustomLinesRoomTo = pR->getNorthwest(); // mCustomLinesRoomTo - wasn't being set! } else if (exit == "N") { mCustomLinesRoomTo = pR->getNorth(); } else if (exit == "NE") { mCustomLinesRoomTo = pR->getNortheast(); } else if (exit == "UP") { mCustomLinesRoomTo = pR->getUp(); } else if (exit == "W") { mCustomLinesRoomTo = pR->getWest(); } else if (exit == "E") { mCustomLinesRoomTo = pR->getEast(); } else if (exit == "DOWN") { mCustomLinesRoomTo = pR->getDown(); } else if (exit == "SW") { mCustomLinesRoomTo = pR->getSouthwest(); } else if (exit == "S") { mCustomLinesRoomTo = pR->getSouth(); } else if (exit == "SE") { mCustomLinesRoomTo = pR->getSoutheast(); } else if (exit == "IN") { mCustomLinesRoomTo = pR->getIn(); } else if (exit == "OUT") { mCustomLinesRoomTo = pR->getOut(); } else { qWarning(R"(T2DMap::slot_setCustomLine2(): unable to identify exit "%s"to use!)", qPrintable(exit)); return; } QList _list; pR->customLines[exit] = _list; QList _colorList; // qDebug("T2DMap::slot_setCustomLine2() NORMAL EXIT: %s", qPrintable(exit)); _colorList << mCurrentLineColor.red() << mCurrentLineColor.green() << mCurrentLineColor.blue(); pR->customLinesColor[exit] = _colorList; /* * qDebug(" COLOR(r,g,b): %i,%i,%i", * mCurrentLineColor.red(), * mCurrentLineColor.green(), * mCurrentLineColor.blue() ); */ pR->customLinesStyle[exit] = mCurrentLineStyle; // qDebug(" LINE STYLE: %s", qPrintable(mCurrentLineStyle) ); pR->customLinesArrow[exit] = mCurrentLineArrow; // qDebug(" ARROW: %s", mCurrentLineArrow ? "Yes" : "No"); mHelpMsg = tr("Left-click to add point, right-click to undo/change/finish..."); // This message was previously being put up AFTER first click to set first segment was made.... update(); } void T2DMap::slot_setCustomLine2B(QTreeWidgetItem* special_exit, int column) { Q_UNUSED(column); if (!special_exit) { return; } QString exit = special_exit->text(2); mpCustomLinesDialog->hide(); // Hide but don't delete until done the custom line mCustomLinesRoomExit = exit; mCustomLinesRoomTo = special_exit->text(1).toInt(); // Wasn't being set ! mDialogLock = false; TRoom* pR = mpMap->mpRoomDB->getRoom(mCustomLinesRoomFrom); if (!pR) { return; } QList _list; pR->customLines[exit] = _list; QList _colorList; _colorList << mCurrentLineColor.red() << mCurrentLineColor.green() << mCurrentLineColor.blue(); // qDebug("T2DMap::slot_setCustomLine2B() SPECIAL EXIT: %s", qPrintable(exit)); pR->customLinesColor[exit] = _colorList; /* * qDebug(" COLOR(r,g,b): %i,%i,%i", * mCurrentLineColor.red(), * mCurrentLineColor.green(), * mCurrentLineColor.blue() ); */ pR->customLinesStyle[exit] = mCurrentLineStyle; // qDebug(" LINE STYLE: %s", qPrintable(mCurrentLineStyle) ); pR->customLinesArrow[exit] = mCurrentLineArrow; // qDebug(" ARROW: %s", mCurrentLineArrow ? "Yes" : "No"); mHelpMsg = tr("Left-click to add point, right-click to undo/change/finish..."); // This message was previously being put up AFTER first click to set first segment was made.... update(); } void T2DMap::slot_createLabel() { if (!mpMap->mpRoomDB->getArea(mAID)) { return; } mHelpMsg = tr("Left-click and drag a square for the size and position of your label"); mSizeLabel = true; mMultiSelection = true; update(); } void T2DMap::slot_roomSelectionChanged() { QList _sl = mMultiSelectionListWidget.selectedItems(); mMultiSelectionSet.clear(); for (auto treeWidgetItem : _sl) { int currentRoomId = treeWidgetItem->text(0).toInt(); mMultiSelectionSet.insert(currentRoomId); } switch (mMultiSelectionSet.size()) { case 0: mMultiSelectionHighlightRoomId = -1; break; case 1: mMultiSelectionHighlightRoomId = *(mMultiSelectionSet.constBegin()); break; default: getCenterSelection(); } update(); } void T2DMap::paintMap() { // if( !mpMap ) return; // bool __Pick = mPick; // QTime __time; __time.start(); // mAreaExitList.clear(); // int px,py; // QList exitList; // QList oneWayExits; // int ox, oy, oz; // if( !mpMap ) return; // if( !mpMap->areas.contains(mAID)) return; // mpMap->areas[mAID]->calcSpan(); // int x_min; // int y_min; // int x_max; // int y_max; // if( ! mpMap->areas[mAID]->xminEbene.contains(mOz) ) // { // ox = 0; // oy = 0; // oz = 0; // } // else // { // x_min = mpMap->areas[mAID]->xminEbene[mOz]; // y_min = mpMap->areas[mAID]->yminEbene[mOz]; // x_max = mpMap->areas[mAID]->xmaxEbene[mOz]; // y_max = mpMap->areas[mAID]->ymaxEbene[mOz]; // ox = x_min + ( abs( x_max - x_min ) / 2 ); // oy = ( y_min + ( abs( y_max - y_min ) / 2 ) ) * -1; // oz = 0; // } // int sizex, sizey; // if( x_max < 0 ) sizex = abs(abs(x_min)-abs(x_max)); // if( x_max > 0 && x_min > 0 ) sizex = x_max-x_min; // if( x_max >= 0 && x_min <= 0 ) sizex = abs(x_max+abs(x_min)); // if( y_max < 0 ) sizey = abs(abs(y_min)-abs(y_max)); // if( y_max > 0 && y_min > 0 ) sizey = y_max-y_min; // if( y_max >= 0 && y_min <= 0 ) sizey = abs(y_max+abs(y_min)); // sizex += 10; // sizey += 10; // if( sizex > sizey ) // sizey = sizex; // else // sizex = sizey; // xzoom = 30; // yzoom = 30; // // Qt png limits // //if( sizex*xzoom >= 32768 ) // xzoom = 10000/sizex; // //if( sizey*yzoom >= 32768 ) // yzoom = 10000/sizey; // if(xzoom > yzoom) // xzoom = yzoom; // else // yzoom = xzoom; // xspan = xzoom; // yspan = yzoom; // float _w = sizex*xspan; // float _h = sizey*yspan; // float tx = xspan; // float ty = yspan; // mTX = tx; // mTY = ty; // oy *= -1; // if( ox*tx > (sizex/2)*tx ) // _rx = -(tx*ox-(sizex/2)*tx); // else // _rx = (sizex/2)*tx-tx*ox; // if( oy*ty > (sizey/2)*ty ) // _ry = -(ty*oy-(sizey/2)*ty); // else // _ry = (sizey/2)*ty-ty*oy; // px = ox*tx+_rx; // py = oy*ty+_ry; // TArea * pArea = mpMap->areas[mAID]; // if( ! pArea ) return; // int zEbene; // zEbene = mOz; // if( ! mpMap ) return; // if( ! mpMap->rooms.contains( mRID ) ) return; // float wegBreite = 1/eSize * tx * rSize; // if( ! mpMap->areas.contains(mAID) ) return; // TArea * pA = mpMap->areas[mAID]; // if( pA->rooms.size() < 1 ) return; // QPixmap pix = QPixmap(sizex*xspan, sizey*yspan); // QPainter p( &pix ); // if( !p.isActive() ) // { // cout << "ERROR: no active painter"<mBgColor_2 ); // QPen pen; // pen = p.pen(); // pen.setColor( mpHost->mFgColor_2 ); // pen.setWidthF(wegBreite); // if(mMapperUseAntiAlias) // p.setRenderHint(QPainter::Antialiasing); // else // p.setRenderHint(QPainter::NonCosmeticDefaultPen); // p.setPen( pen ); // if( mpMap->mapLabels.contains( mAID ) ) // { // QMapIterator it(mpMap->mapLabels[mAID]); // while( it.hasNext() ) // { // it.next(); // if( it.value().pos.z() != mOz ) continue; // if( it.value().text.length() < 1 ) // { // mpMap->mapLabels[mAID][it.key()].text = "no text"; // } // QPointF lpos; // int _lx = it.value().pos.x()*tx+_rx; // int _ly = it.value().pos.y()*ty*-1+_ry; // lpos.setX( _lx ); // lpos.setY( _ly ); // int _lw = abs(it.value().size.width())*tx; // int _lh = abs(it.value().size.height())*ty; // QRectF _drawRect = QRect(it.value().pos.x()*tx+_rx, it.value().pos.y()*ty*-1+_ry, _lw, _lh); // if ( !it.value().pix.isNull() ) // { // p.drawPixmap( lpos, it.value().pix.scaled(_drawRect.size().toSize()) ); // } // else // { // if( it.value().text.length() < 1 ) // { // mpMap->mapLabels[mAID][it.key()].text = "no text"; // } // QRectF lr = QRectF( 0, 0, 1000, 100 ); // QPixmap pix( lr.size().toSize() ); // pix.fill(Qt::transparent); // QPainter lp( &pix ); // if( it.value().hilite ) // { // lp.fillRect( lr, QColor(255,155,55) ); // } // else // { // lp.fillRect( lr, it.value().bgColor ); // } // QPen lpen; // lpen.setColor( it.value().fgColor ); // lp.setPen( lpen ); // QRectF br; // lp.drawText( lr, Qt::AlignLeft, it.value().text, &br ); // QPointF lpos; // lpos.setX( it.value().pos.x()*tx+_rx ); // lpos.setY( it.value().pos.y()*ty*-1+_ry ); // p.drawPixmap( lpos, pix, br.toRect() ); // } // if( it.value().hilite ) // { // p.fillRect(_drawRect, QColor(255, 155, 55, 190)); // } // } // } // if( ! pArea->gridMode ) // { // for( int i=0; irooms.size(); i++ ) // { // TRoom * pR = mpMap->rooms[pArea->rooms[i]]; // int trID = pArea->rooms[i]; // float rx = pR->x*tx+_rx; // float ry = pR->y*-1*ty+_ry; // int rz = pR->z; // if( rz != zEbene && !mMultiSelectionList.contains(i)) continue; // pR->rendered = true; // exitList.clear(); // oneWayExits.clear(); // if( pR->customLines.size() > 0 ) // { // if( ! pR->customLines.contains("N") ) // { // exitList.push_back( pR->north ); // if( mpMap->rooms.contains(pR->north) ) // { // TRoom * pER = mpMap->rooms[pR->north]; // if( pER->south != pR->id ) // { // oneWayExits.push_back( pR->north ); // } // } // } // if( !pR->customLines.contains("NW") ) // { // exitList.push_back( pR->northwest ); // if( mpMap->rooms.contains(pR->northwest) ) // { // TRoom * pER = mpMap->rooms[pR->northwest]; // if( pER->southeast != pR->id ) // { // oneWayExits.push_back( pR->northwest ); // } // } // } // if( !pR->customLines.contains("E") ) // { // exitList.push_back( pR->east ); // if( mpMap->rooms.contains(pR->east) ) // { // TRoom * pER = mpMap->rooms[pR->east]; // if( pER->west != pR->id ) // { // oneWayExits.push_back( pR->east ); // } // } // } // if( !pR->customLines.contains("SE") ) // { // exitList.push_back( pR->southeast ); // if( mpMap->rooms.contains(pR->southeast) ) // { // TRoom * pER = mpMap->rooms[pR->southeast]; // if( pER->northwest != pR->id ) // { // oneWayExits.push_back( pR->southeast ); // } // } // } // if( !pR->customLines.contains("S") ) // { // exitList.push_back( pR->south ); // if( mpMap->rooms.contains(pR->south) ) // { // TRoom * pER = mpMap->rooms[pR->south]; // if( pER->north != pR->id ) // { // oneWayExits.push_back( pR->south ); // } // } // } // if( !pR->customLines.contains("SW") ) // { // exitList.push_back( pR->southwest ); // if( mpMap->rooms.contains(pR->southwest) ) // { // TRoom * pER = mpMap->rooms[pR->southwest]; // if( pER->northeast != pR->id ) // { // oneWayExits.push_back( pR->southwest ); // } // } // } // if( !pR->customLines.contains("W") ) // { // exitList.push_back( pR->west ); // if( mpMap->rooms.contains(pR->west) ) // { // TRoom * pER = mpMap->rooms[pR->west]; // if( pER->east != pR->id ) // { // oneWayExits.push_back( pR->west ); // } // } // } // if( !pR->customLines.contains("NE") ) // { // exitList.push_back( pR->northeast ); // if( mpMap->rooms.contains(pR->northeast) ) // { // TRoom * pER = mpMap->rooms[pR->northeast]; // if( pER->southwest != pR->id ) // { // oneWayExits.push_back( pR->northeast ); // } // } // } // } // else // { // if( pR->north > 0 ) // { // exitList.push_back( pR->north ); // if( mpMap->rooms.contains(pR->north) ) // { // TRoom * pER = mpMap->rooms[pR->north]; // if( pER->south != pR->id ) // { // oneWayExits.push_back( pR->north ); // } // } // } // if( pR->northwest > 0 ) // { // exitList.push_back( pR->northwest ); // if( mpMap->rooms.contains(pR->northwest) ) // { // TRoom * pER = mpMap->rooms[pR->northwest]; // if( pER->southeast != pR->id ) // { // oneWayExits.push_back( pR->northwest ); // } // } // } // if( pR->east > 0 ) // { // exitList.push_back( pR->east ); // if( mpMap->rooms.contains(pR->east) ) // { // TRoom * pER = mpMap->rooms[pR->east]; // if( pER->west != pR->id ) // { // oneWayExits.push_back( pR->east ); // } // } // } // if( pR->southeast > 0 ) // { // exitList.push_back( pR->southeast ); // if( mpMap->rooms.contains(pR->southeast) ) // { // TRoom * pER = mpMap->rooms[pR->southeast]; // if( pER->northwest != pR->id ) // { // oneWayExits.push_back( pR->southeast ); // } // } // } // if( pR->south > 0 ) // { // exitList.push_back( pR->south ); // if( mpMap->rooms.contains(pR->south) ) // { // TRoom * pER = mpMap->rooms[pR->south]; // if( pER->north != pR->id ) // { // oneWayExits.push_back( pR->south ); // } // } // } // if( pR->southwest > 0 ) // { // exitList.push_back( pR->southwest ); // if( mpMap->rooms.contains(pR->southwest) ) // { // TRoom * pER = mpMap->rooms[pR->southwest]; // if( pER->northeast != pR->id ) // { // oneWayExits.push_back( pR->southwest ); // } // } // } // if( pR->west > 0 ) // { // exitList.push_back( pR->west ); // if( mpMap->rooms.contains(pR->west) ) // { // TRoom * pER = mpMap->rooms[pR->west]; // if( pER->east != pR->id ) // { // oneWayExits.push_back( pR->west ); // } // } // } // if( pR->northeast > 0 ) // { // exitList.push_back( pR->northeast ); // if( mpMap->rooms.contains(pR->northeast) ) // { // TRoom * pER = mpMap->rooms[pR->northeast]; // if( pER->southwest != pR->id ) // { // oneWayExits.push_back( pR->northeast ); // } // } // } // } // if( pR->customLines.size() > 0 ) // { // QPen oldPen = p.pen(); // QMapIterator > itk(pR->customLines); // while( itk.hasNext() ) // { // itk.next(); // QColor _color; // if( pR->id == mCustomLineSelectedRoom && itk.key()== mCustomLineSelectedExit ) // { // _color.setRed( 255 ); // _color.setGreen( 155 ); // _color.setBlue( 55 ); // } // else if( pR->customLinesColor[itk.key()].size() == 3 ) // { // _color.setRed( mpMap->rooms[pArea->rooms[i]]->customLinesColor[itk.key()][0] ); // _color.setGreen( mpMap->rooms[pArea->rooms[i]]->customLinesColor[itk.key()][1] ); // _color.setBlue( mpMap->rooms[pArea->rooms[i]]->customLinesColor[itk.key()][2] ); // } // else // _color = QColor(Qt::red); // bool _arrow = pR->customLinesArrow[itk.key()]; // QString _style = pR->customLinesStyle[itk.key()]; // QPointF _cstartP; // float ex = pR->x*tx+_rx; // float ey = pR->y*ty*-1+_ry; // if( itk.key() == "N" ) // _cstartP = QPoint(ex,ey-ty/2); // else if( itk.key() == "NW" ) // _cstartP = QPoint(ex-tx/2,ey-ty/2); // else if( itk.key() == "NE" ) // _cstartP = QPoint(ex+tx/2,ey-ty/2); // else if( itk.key() == "S" ) // _cstartP = QPoint(ex,ey+ty/2); // else if( itk.key() == "SW" ) // _cstartP = QPoint(ex-tx/2,ey+ty/2); // else if( itk.key() == "SE" ) // _cstartP = QPoint(ex+tx/2,ey+ty/2); // else if( itk.key() == "W" ) // _cstartP = QPoint(ex-tx/2, ey); // else if( itk.key() == "E" ) // _cstartP = QPoint(ex+tx/2, ey); // else // _cstartP = QPointF(ex, ey); // QPointF ursprung = QPointF(ex,ey); // QPen customLinePen = p.pen(); // customLinePen.setCosmetic(mMapperUseAntiAlias); // customLinePen.setColor( _color ); // customLinePen.setCapStyle( Qt::RoundCap ); // customLinePen.setJoinStyle( Qt::RoundJoin ); // if( _style == "solid line" ) // customLinePen.setStyle( Qt::SolidLine ); // else if( _style == "dot line" ) // customLinePen.setStyle( Qt::DotLine ); // else if( _style == "dash line" ) // customLinePen.setStyle( Qt::DashLine ); // else // customLinePen.setStyle( Qt::DashDotDotLine ); // QList _pL = itk.value(); // if( _pL.size() > 0 ) // { // p.setPen(customLinePen); // p.drawLine( ursprung, _cstartP ); // } // for( int pk=0; pk<_pL.size(); pk++ ) // { // QPointF _cendP; // _cendP.setX( _pL[pk].x()*tx+_rx ); // _cendP.setY( _pL[pk].y()*ty*-1+_ry ); // p.drawLine( _cstartP, _cendP ); // if( pR->id == mCustomLineSelectedRoom && itk.key()== mCustomLineSelectedExit ) // { // QBrush _brush = p.brush(); // p.setBrush(QColor(255,155,55)); // p.drawEllipse( _cendP, mTX/4, mTX/4 ); // p.setBrush(_brush); // } // if( pk == _pL.size()-1 && _arrow ) // { // QLineF l0 = QLineF( _cendP, _cstartP ); // l0.setLength(wegBreite*5); // QPointF _p1 = l0.p1(); // QPointF _p2 = l0.p2(); // QLineF l1 = QLineF( l0 ); // qreal w1 = l1.angle()-90.0; // QLineF l2; // l2.setP1(_p2); // l2.setAngle(w1); // l2.setLength(wegBreite*2); // QPointF _p3 = l2.p2(); // l2.setAngle( l2.angle()+180.0 ); // QPointF _p4 = l2.p2(); // QPolygonF _poly; // _poly.append( _p1 ); // _poly.append( _p3 ); // _poly.append( _p4 ); // QBrush brush = p.brush(); // brush.setColor( _color ); // brush.setStyle( Qt::SolidPattern ); // QPen arrowPen = p.pen(); // arrowPen.setCosmetic( mMapperUseAntiAlias ); // arrowPen.setStyle(Qt::SolidLine); // p.setPen( arrowPen ); // p.setBrush( brush ); // p.drawPolygon(_poly); // } // _cstartP = _cendP; // } // } // p.setPen(oldPen); // } // int e = pR->z; // // draw exit stubs // QMap unitVectors = mpMap->unitVectors; // for( int k=0; kexitStubs.size(); k++ ) // { // int direction = pR->exitStubs[k]; // QVector3D uDirection = unitVectors[direction]; // p.drawLine(rx+rSize*(int)uDirection.x()/2, ry+rSize*(int)uDirection.y(),rx+(int)uDirection.x()*(rSize*3/4*tx), ry+uDirection.y()*(rSize*3/4*ty)); // } // QPen __pen; // for( int k=0; krooms[rID]; // if( pE->area != mAID ) // { // areaExit = true; // } // else // areaExit = false; // float ex = pE->x*tx+_rx; // float ey = pE->y*ty*-1+_ry; // int ez = pE->z; // QVector3D p1( ex, ey, ez ); // QVector3D p2( rx, ry, rz ); // QLine _line; // if( ! areaExit ) // { // // one way exit or 2 way exit? // if( ! oneWayExits.contains( rID ) ) // { // p.drawLine( (int)p1.x(), (int)p1.y(), (int)p2.x(), (int)p2.y() ); // } // else // { // // one way exit draw arrow // QLineF l0 = QLineF( p2.x(), p2.y(), p1.x(), p1.y() ); // QLineF k0 = l0; // k0.setLength( (l0.length()-wegBreite*5)*0.5 ); // qreal dx = k0.dx(); qreal dy = k0.dy(); // QPen _tp = p.pen(); // QPen _tp2 = _tp; // _tp2.setStyle(Qt::DotLine); // p.setPen(_tp2); // p.drawLine( l0 ); // p.setPen(_tp); // l0.setLength(wegBreite*5); // QPointF _p1 = l0.p2(); // QPointF _p2 = l0.p1(); // QLineF l1 = QLineF( l0 ); // qreal w1 = l1.angle()-90.0; // QLineF l2; // l2.setP1(_p2); // l2.setAngle(w1); // l2.setLength(wegBreite*2); // QPointF _p3 = l2.p2(); // l2.setAngle( l2.angle()+180.0 ); // QPointF _p4 = l2.p2(); // QPolygonF _poly; // _poly.append( _p1 ); // _poly.append( _p3 ); // _poly.append( _p4 ); // QBrush brush = p.brush(); // brush.setColor( QColor(255,100,100) ); // brush.setStyle( Qt::SolidPattern ); // QPen arrowPen = p.pen(); // arrowPen.setCosmetic( mMapperUseAntiAlias ); // arrowPen.setStyle(Qt::SolidLine); // p.setPen( arrowPen ); // p.setBrush( brush ); // p.drawPolygon(_poly.translated(dx,dy)); // } // } // else // { // __pen = p.pen(); // QLine _line; // if( pR->south == rID ) // { // pen = p.pen(); // pen.setWidthF(wegBreite); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setColor(getColor(exitList[k])); // p.setPen( pen ); // _line = QLine( p2.x(), p2.y()+ty,p2.x(), p2.y() ); // p.drawLine( _line ); // QPoint _p = QPoint(p2.x(), p2.y()+ty/2); // mAreaExitList[exitList[k]] = _p; // } // else if( pR->north == rID ) // { // pen = p.pen(); // pen.setWidthF(wegBreite); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setColor(getColor(exitList[k])); // p.setPen( pen ); // _line = QLine( p2.x(), p2.y()-ty, p2.x(), p2.y() ); // p.drawLine( _line ); // QPoint _p = QPoint(p2.x(), p2.y()-ty/2); // mAreaExitList[exitList[k]] = _p; // } // else if( pR->west == rID ) // { // pen = p.pen(); // pen.setWidthF(wegBreite); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setColor(getColor(exitList[k])); // p.setPen( pen ); // _line = QLine(p2.x()-tx, p2.y(),p2.x(), p2.y() ); // p.drawLine( _line ); // QPoint _p = QPoint(p2.x()-tx/2, p2.y()); // mAreaExitList[exitList[k]] = _p; // } // else if( pR->east == rID ) // { // pen = p.pen(); // pen.setWidthF(wegBreite); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setColor(getColor(exitList[k])); // p.setPen( pen ); // _line = QLine(p2.x()+tx, p2.y(),p2.x(), p2.y() ); // p.drawLine( _line ); // QPoint _p = QPoint(p2.x()+tx/2, p2.y()); // mAreaExitList[exitList[k]] = _p; // } // else if( pR->northwest == rID ) // { // pen = p.pen(); // pen.setWidthF(wegBreite); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setColor(getColor(exitList[k])); // p.setPen( pen ); // _line = QLine(p2.x()-tx, p2.y()-ty,p2.x(), p2.y() ); // p.drawLine( _line ); // QPoint _p = QPoint(p2.x()-tx/2, p2.y()-ty/2); // mAreaExitList[exitList[k]] = _p; // } // else if( pR->northeast == rID ) // { // pen = p.pen(); // pen.setWidthF(wegBreite); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setColor(getColor(exitList[k])); // p.setPen( pen ); // _line = QLine(p2.x()+tx, p2.y()-ty,p2.x(), p2.y()); // p.drawLine( _line ); // QPoint _p = QPoint(p2.x()+tx/2, p2.y()-ty/2); // mAreaExitList[exitList[k]] = _p; // } // else if( pR->southeast == rID ) // { // pen = p.pen(); // pen.setWidthF(wegBreite); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setColor(getColor(exitList[k])); // p.setPen( pen ); // _line = QLine(p2.x()+tx, p2.y()+ty, p2.x(), p2.y()); // p.drawLine( _line ); // QPoint _p = QPoint(p2.x()+tx/2, p2.y()+ty/2); // mAreaExitList[exitList[k]] = _p; // } // else if( pR->southwest == rID ) // { // pen = p.pen(); // pen.setWidthF(wegBreite); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setColor(getColor(exitList[k])); // p.setPen( pen ); // _line = QLine(p2.x()-tx, p2.y()+ty, p2.x(), p2.y()); // p.drawLine( _line ); // QPoint _p = QPoint(p2.x()-tx/2, p2.y()+ty/2); // mAreaExitList[exitList[k]] = _p; // } // QLineF l0 = QLineF( _line ); // l0.setLength(wegBreite*5); // QPointF _p1 = l0.p1(); // QPointF _p2 = l0.p2(); // QLineF l1 = QLineF( l0 ); // qreal w1 = l1.angle()-90.0; // QLineF l2; // l2.setP1(_p2); // l2.setAngle(w1); // l2.setLength(wegBreite*2); // QPointF _p3 = l2.p2(); // l2.setAngle( l2.angle()+180.0 ); // QPointF _p4 = l2.p2(); // QPolygonF _poly; // _poly.append( _p1 ); // _poly.append( _p3 ); // _poly.append( _p4 ); // QBrush brush = p.brush(); // brush.setColor( getColor(exitList[k]) ); // brush.setStyle( Qt::SolidPattern ); // QPen arrowPen = p.pen(); // arrowPen.setCosmetic( mMapperUseAntiAlias ); // p.setPen( arrowPen ); // p.setBrush( brush ); // p.drawPolygon(_poly); // p.setPen( __pen ); // } // if( pR->doors.size() > 0 ) // { // int doorStatus = 0; // if( pR->south == rID && pR->doors.contains("s") ) // { // doorStatus = pR->doors["s"]; // } // else if( pR->north == rID && pR->doors.contains("n") ) // { // doorStatus = pR->doors["n"]; // } // else if( pR->southwest == rID && pR->doors.contains("sw") ) // { // doorStatus = pR->doors["sw"]; // } // else if( pR->southeast == rID && pR->doors.contains("se") ) // { // doorStatus = pR->doors["se"]; // } // else if( pR->northeast == rID && pR->doors.contains("ne") ) // { // doorStatus = pR->doors["ne"]; // } // else if( pR->northwest == rID && pR->doors.contains("nw") ) // { // doorStatus = pR->doors["nw"]; // } // else if( pR->west == rID && pR->doors.contains("w") ) // { // doorStatus = pR->doors["w"]; // } // else if( pR->east == rID && pR->doors.contains("e") ) // { // doorStatus = pR->doors["e"]; // } // if( doorStatus > 0 ) // { // QLineF k0; // QRectF rect; // rect.setWidth(0.25*mTX); // rect.setHeight(0.25*mTY); // if ( areaExit ) // k0 = QLineF(_line); // else // k0 = QLineF( p2.x(), p2.y(), p1.x(), p1.y() ); // k0.setLength( (k0.length())*0.5 ); // rect.moveCenter(k0.p2()); // QPen arrowPen = p.pen(); // QPen _tp = p.pen(); // arrowPen.setCosmetic( mMapperUseAntiAlias ); // arrowPen.setStyle(Qt::SolidLine); // if( doorStatus == 1 ) //open door // arrowPen.setColor(QColor(10,155,10)); // else if( doorStatus == 2 ) //closed door // arrowPen.setColor(QColor(155,155,10)); // else //locked door // arrowPen.setColor(QColor(155,10,10)); // QBrush brush; // QBrush oldBrush; // p.setPen( arrowPen ); // p.setBrush(brush); // p.drawRect(rect); // p.setBrush(oldBrush); // p.setPen(_tp); // } // } // } // } // } // // draw group selection box // if( mSizeLabel ) // p.fillRect(mMultiRect,QColor(250,190,0,190)); // else // p.fillRect(mMultiRect,QColor(190,190,190,60)); // for( int i=0; irooms.size(); i++ ) // { // TRoom * pR = mpMap->rooms[pArea->rooms[i]]; // float rx = pR->x*tx+_rx; // float ry = pR->y*-1*ty+_ry; // int rz = pR->z; // if( rz != zEbene ) continue; // //if( rx < 0 || ry < 0 || rx > _w || ry > _h ) continue; // pR->rendered = false; // QRectF dr; // if( pArea->gridMode ) // { // dr = QRectF(rx-tx/2, ry-ty/2,tx,ty); // } // else // { // dr = QRectF(rx-(tx*rSize)/2,ry-(ty*rSize)/2,tx*rSize,ty*rSize); // } // QColor c; // int env = pR->environment; // if( mpMap->envColors.contains(env) ) // env = mpMap->envColors[env]; // else // { // if( ! mpMap->customEnvColors.contains(env)) // { // env = 1; // } // } // switch( env ) // { // case 1: // c = mpHost->mRed_2; // break; // case 2: // c = mpHost->mGreen_2; // break; // case 3: // c = mpHost->mYellow_2; // break; // case 4: // c = mpHost->mBlue_2; // break; // case 5: // c = mpHost->mMagenta_2; // break; // case 6: // c = mpHost->mCyan_2; // break; // case 7: // c = mpHost->mWhite_2; // break; // case 8: // c = mpHost->mBlack_2; // break; // case 9: // c = mpHost->mLightRed_2; // break; // case 10: // c = mpHost->mLightGreen_2; // break; // case 11: // c = mpHost->mLightYellow_2; // break; // case 12: // c = mpHost->mLightBlue_2; // break; // case 13: // c = mpHost->mLightMagenta_2; // break; // case 14: // c = mpHost->mLightCyan_2; // break; // case 15: // c = mpHost->mLightWhite_2; // break; // case 16: // c = mpHost->mLightBlack_2; // default: //user defined room color // if( ! mpMap->customEnvColors.contains(env) ) break; // c = mpMap->customEnvColors[env]; // } // if( ( mPick || __Pick ) && mPHighlight.x() >= dr.x()-(tx*rSize) && mPHighlight.x() <= dr.x()+(tx*rSize) && mPHighlight.y() >= dr.y()-(ty*rSize) && mPHighlight.y() <= dr.y()+(ty*rSize) // || mMultiSelectionList.contains(pArea->rooms[i]) ) // { // p.fillRect(dr,QColor(255,155,55)); // mPick = false; // if( mStartSpeedWalk ) // { // mStartSpeedWalk = false; // float _radius = (0.8*tx)/2; // QPointF _center = QPointF(rx,ry); // QRadialGradient _gradient(_center,_radius); // _gradient.setColorAt(0.95, QColor(255,0,0,150)); // _gradient.setColorAt(0.80, QColor(150,100,100,150)); // _gradient.setColorAt(0.799,QColor(150,100,100,100)); // _gradient.setColorAt(0.7, QColor(255,0,0,200)); // _gradient.setColorAt(0, QColor(255,255,255,255)); // QPen myPen(Qt::transparent); // QPainterPath myPath; // p.setBrush(_gradient); // p.setPen(myPen); // myPath.addEllipse(_center,_radius,_radius); // p.drawPath(myPath); // mTarget = pArea->rooms[i]; // if( mpMap->rooms.contains(mTarget) ) // { // mpMap->mTargetID = mTarget; // if( mpMap->findPath( mpMap->mRoomId, mpMap->mTargetID) ) // { // mpMap->mpHost->startSpeedWalk(); // } // else // { // QString msg = "Mapper: Cannot find a path to this room using known exits.\n"; // mpHost->mpConsole->printSystemMessage(msg); // } // } // } // } // else // { // char _ch = pR->c; // if( _ch >= 33 && _ch < 255 ) // { // int _color = ( 265 - 257 ) * 254 + _ch;//(mpMap->rooms[pArea->rooms[i]]->environment - 257 ) * 254 + _ch; // if( c.red()+c.green()+c.blue() > 260 ) // _color = ( 7 ) * 254 + _ch; // else // _color = ( 6 ) * 254 + _ch; // p.fillRect( dr, c ); // if( mPixMap.contains( _color ) ) // { // QPixmap pix = mPixMap[_color].scaled(dr.width(), dr.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); // p.drawPixmap(dr.topLeft(), pix); // } // } // else // { // if( mBubbleMode ) // { // float _radius = (rSize*tx)/2; // QPointF _center = QPointF(rx,ry); // QRadialGradient _gradient(_center,_radius); // _gradient.setColorAt(0.85, c); // _gradient.setColorAt(0, QColor(255,255,255,255)); // QPen myPen(Qt::transparent); // QPainterPath myPath; // p.setBrush(_gradient); // p.setPen(myPen); // myPath.addEllipse(_center,_radius,_radius); // p.drawPath(myPath); // } // else // p.fillRect(dr,c); // } // if( pR->highlight ) // { // float _radius = (mpMap->rooms[pArea->rooms[i]]->highlightRadius*tx)/2; // QPointF _center = QPointF(rx,ry); // QRadialGradient _gradient(_center,_radius); // _gradient.setColorAt(0.85, mpMap->rooms[pArea->rooms[i]]->highlightColor); // _gradient.setColorAt(0, mpMap->rooms[pArea->rooms[i]]->highlightColor2 ); // QPen myPen(Qt::transparent); // QPainterPath myPath; // p.setBrush(_gradient); // p.setPen(myPen); // myPath.addEllipse(_center,_radius,_radius); // p.drawPath(myPath); // } // if( mShowRoomID ) // { // QPen __pen = p.pen(); // QColor lc; // if( c.red()+c.green()+c.blue() > 200 ) // lc=QColor(Qt::black); // else // lc=QColor(Qt::white); // p.setPen(QPen(lc)); // p.drawText(dr, Qt::AlignHCenter|Qt::AlignVCenter,QString::number(pArea->rooms[i])); // p.setPen(__pen); // } // if( mShiftMode && pArea->rooms[i] == mpMap->mRoomId ) // { // float _radius = (1.2*tx)/2; // QPointF _center = QPointF(rx,ry); // QRadialGradient _gradient(_center,_radius); // _gradient.setColorAt(0.95, QColor(255,0,0,150)); // _gradient.setColorAt(0.80, QColor(150,100,100,150)); // _gradient.setColorAt(0.799,QColor(150,100,100,100)); // _gradient.setColorAt(0.7, QColor(255,0,0,200)); // _gradient.setColorAt(0, QColor(255,255,255,255)); // QPen myPen(Qt::transparent); // QPainterPath myPath; // p.setBrush(_gradient); // p.setPen(myPen); // myPath.addEllipse(_center,_radius,_radius); // p.drawPath(myPath); // } // } // QColor lc; // if( c.red()+c.green()+c.blue() > 200 ) // lc=QColor(Qt::black); // else // lc=QColor(Qt::white); // pen = p.pen(); // pen.setColor( lc ); // pen.setWidthF(0);//wegBreite?); // pen.setCosmetic( mMapperUseAntiAlias ); // pen.setCapStyle( Qt::RoundCap ); // pen.setJoinStyle( Qt::RoundJoin ); // p.setPen( pen ); // //FIXME: redo exit stubs here since the room will draw over up/down stubs -- its repetitive though // QMap unitVectors = mpMap->unitVectors; // for( int k=0; kexitStubs.size(); k++ ) // { // int direction = pR->exitStubs[k]; // QVector3D uDirection = unitVectors[direction]; // if (direction > 8) // { // float rx = pR->x*tx+_rx; // float ry = pR->y*-1*ty+_ry; // QPolygonF _poly; // QPointF _pt; // _pt = QPointF( rx, ry+(ty*rSize)*uDirection.z()/20 ); // _poly.append( _pt ); // _pt = QPointF( rx+(tx*rSize)/3.1, ry+(ty*rSize)*uDirection.z()/3.1); // _poly.append(_pt); // _pt = QPointF( rx-(tx*rSize)/3.1, ry+(ty*rSize)*uDirection.z()/3.1 ); // _poly.append( _pt ); // QBrush brush = p.brush(); // brush.setColor( QColor(Qt::black) ); // brush.setStyle( Qt::NoBrush ); // p.setBrush( brush ); // p.drawPolygon(_poly); // } // } // if( pR->up > 0 ) // { // QPolygonF _poly; // QPointF _pt; // _pt = QPointF( rx, ry+(ty*rSize)/20 ); // _poly.append( _pt ); // _pt = QPointF( rx-(tx*rSize)/3.1, ry+(ty*rSize)/3.1 ); // _poly.append( _pt ); // _pt = QPointF( rx+(tx*rSize)/3.1, ry+(ty*rSize)/3.1); // _poly.append(_pt); // QBrush brush = p.brush(); // brush.setColor( QColor(Qt::black) ); // brush.setStyle( Qt::SolidPattern ); // p.setBrush( brush ); // p.drawPolygon(_poly); // } // if( pR->down > 0 ) // { // QPolygonF _poly; // QPointF _pt; // _pt = QPointF( rx, ry-(ty*rSize)/20 ); // _poly.append( _pt ); // _pt = QPointF( rx-(tx*rSize)/3.1, ry-(ty*rSize)/3.1 ); // _poly.append( _pt ); // _pt = QPointF( rx+(tx*rSize)/3.1, ry-(ty*rSize)/3.1); // _poly.append(_pt); // QBrush brush = p.brush(); // brush.setColor( QColor(Qt::black) ); // brush.setStyle( Qt::SolidPattern ); // p.setBrush( brush ); // p.drawPolygon(_poly); // } // if( pR->in > 0 ) // { // QPolygonF _poly; // QPointF _pt; // _pt = QPointF( rx+(tx*rSize)/20, ry ); // _poly.append( _pt ); // _pt = QPointF( rx-(tx*rSize)/3.1, ry-(ty*rSize)/3.1 ); // _poly.append( _pt ); // _pt = QPointF( rx-(tx*rSize)/3.1, ry+(ty*rSize)/3.1); // _poly.append(_pt); // QBrush brush = p.brush(); // brush.setColor( QColor(Qt::black) ); // brush.setStyle( Qt::SolidPattern ); // p.setBrush( brush ); // p.drawPolygon(_poly); // } // if( pR->out > 0 ) // { // QPolygonF _poly; // QPointF _pt; // _pt = QPointF( rx-(tx*rSize)/20, ry); // _poly.append( _pt ); // _pt = QPointF( rx+(tx*rSize)/3.1, ry-(ty*rSize)/3.1 ); // _poly.append( _pt ); // _pt = QPointF( rx+(tx*rSize)/3.1, ry+(ty*rSize)/3.1); // _poly.append(_pt); // QBrush brush = p.brush(); // brush.setColor( QColor(Qt::black) ); // brush.setStyle( Qt::SolidPattern ); // p.setBrush( brush ); // p.drawPolygon(_poly); // } // } // QString _zeit = QTime().currentTime().toString("hh-mm-ss"); // QString home = QDir::homePath(); // home.append( "/.config/mudlet/profiles/" ); // QString name = mpHost->getName(); // home.append( name ); // QString name2 = "/mapOfAreaID_"+QString::number(mAID)+"_"+_zeit+".PNG"; // home.append( name2 ); // QString erg = QDir::toNativeSeparators( home ); // pix.save(erg); } void T2DMap::resizeMultiSelectionWidget() { int _newWidth; if (mIsSelectionUsingNames) { if (width() <= 300) { // 0 - 300 => 0 - 200 _newWidth = 2 * width() / 3; } else if (width() <= 600) { // 300 - 600 => 200 - 300 _newWidth = 100 + width() / 3; } else { // 600+ => 300 _newWidth = 300; } } else { if (width() <= 300) { // 0 - 300 => 0 - 120 _newWidth = 2 * width() / 3; } else { // 300+ => 120 _newWidth = 120; } } int _newHeight = 300; if (mMultiSelectionListWidget.topLevelItemCount() > 0) { QTreeWidgetItem* rowItem = mMultiSelectionListWidget.topLevelItem(1); // The following factors are tweaks to ensure that the widget shows all // the rows, as the header seems biggger than the value returned, statics // used to enable values to be change by debugger at runtime! static float headerFactor = 1.2; static float rowFactor = 1.0; _newHeight = headerFactor * mMultiSelectionListWidget.header()->height(); if (rowItem) { // Have some data rows - and we have forced them to be the same height: _newHeight += rowFactor * mMultiSelectionListWidget.topLevelItemCount() * mMultiSelectionListWidget.visualItemRect(rowItem).height(); } // qDebug() << "Row count:" << mMultiSelectionListWidget.topLevelItemCount() << "header height:" << mMultiSelectionListWidget.header()->height() << "row height:" << mMultiSelectionListWidget.visualItemRect(rowItem).height(); } if (_newHeight < height()) { mMultiSelectionListWidget.resize(_newWidth, _newHeight); } else { mMultiSelectionListWidget.resize(_newWidth, height()); } }