File indexing completed on 2024-07-07 07:27:07

0001 /*
0002     SPDX-FileCopyrightText: 2003 Russell Steffen <rsteffen@bayarea.net>
0003     SPDX-FileCopyrightText: 2003 Stephan Zehetner <s.zehetner@nevox.org>
0004     SPDX-FileCopyrightText: 2006 Dmitry Suzdalev <dimsuz@gmail.com>
0005     SPDX-FileCopyrightText: 2006 Inge Wallin <inge@lysator.liu.se>
0006     SPDX-FileCopyrightText: 2006 Pierre Ducroquet <pinaraf@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "mapscene.h"
0012 
0013 #include <QGraphicsItem>
0014 #include <QPainter>
0015 
0016 #include "map.h"
0017 #include "mapitems.h"
0018 #include "../sector.h"
0019 #include "../images.h"
0020 #include "../game.h"
0021 #include "../planet.h"
0022 
0023 
0024 MapScene::MapScene (Game *game)
0025   : QGraphicsScene(game),
0026     m_game(game),
0027     m_selectedPlanetItem(nullptr),
0028     m_planetInfoItem(nullptr),
0029     m_width(width()),
0030     m_height(height())
0031 {
0032     m_renderer = new QSvgRenderer(IMAGES_SVG);
0033     m_imageCache = new KImageCache(QStringLiteral("konquest-pixmaps"), 100000);
0034 }
0035 
0036 
0037 MapScene::~MapScene ()
0038 {
0039     delete m_imageCache;
0040     delete m_renderer;
0041 }
0042 
0043 
0044 void
0045 MapScene::resizeScene(const QRectF& rect)
0046 {
0047     m_width = rect.width();
0048     m_height = rect.height();
0049 
0050     setSceneRect(rect);
0051 }
0052 
0053 
0054 void
0055 MapScene::selectPlanet(Planet *planet)
0056 {
0057     unselectPlanet();
0058     for (PlanetItem *item : std::as_const(m_planetItems)) {
0059         if (item->sector() == planet->sector()) {
0060             item->select();
0061             m_selectedPlanetItem = item;
0062             break;
0063         }
0064     }
0065 }
0066 
0067 
0068 void
0069 MapScene::clearMap()
0070 {
0071     QGraphicsItem  *item;
0072     while (items().count() > 0) {
0073         item = items()[0];
0074         removeItem(item);
0075         delete item;
0076     }
0077     m_planetItems.clear();
0078     m_planetInfoItem = nullptr;
0079     m_selectedPlanetItem = nullptr;
0080 }
0081 
0082 
0083 void
0084 MapScene::mapUpdate()
0085 {
0086     Sector *sector;
0087 
0088     clearMap();
0089     if(m_game->isRunning()) {
0090         for (int i = 0 ; i < map()->rows() ; i++) {
0091             for (int j = 0 ; j < map()->columns() ; j++) {
0092                 sector = map()->sector(Coordinate(j, i));
0093                 if (sector->hasPlanet()) {
0094                     PlanetItem *item = new PlanetItem(this, sector, m_game);
0095                     connect(item, &PlanetItem::planetItemSelected, this, &MapScene::planetItemSelected);
0096                     item->setZValue(1.0);
0097                     addItem(item);
0098                     m_planetItems.append(item);
0099                 }
0100             }
0101         }
0102     }
0103 }
0104 
0105 
0106 void
0107 MapScene::unselectPlanet()
0108 {
0109     if (m_selectedPlanetItem) {
0110         m_selectedPlanetItem->unselect();
0111         m_selectedPlanetItem = nullptr;
0112     }
0113 }
0114 
0115 
0116 void
0117 MapScene::planetItemSelected (PlanetItem *item)
0118 {
0119     if (m_selectedPlanetItem)
0120         unselectPlanet();
0121     m_selectedPlanetItem = item;
0122 
0123     Q_EMIT planetSelected(item->sector()->planet());
0124 }
0125 
0126 
0127 void
0128 MapScene::drawBackground ( QPainter * painter, const QRectF & /*rect*/ )
0129 {
0130     qreal sectorSize = getSectorSize();
0131     qreal horizontalOffset = itemsHorizontalOffset();
0132     qreal verticalOffset = itemsVerticalOffset();
0133 
0134     qreal mapWidth = map()->columns()*sectorSize;
0135     qreal mapHeight = map()->rows()*sectorSize;
0136 
0137     QPen pen = painter->pen();
0138     pen.setColor(Qt::black);
0139     pen.setWidth(1);
0140     pen.setStyle(Qt::SolidLine);
0141     painter->setPen(pen);
0142     painter->fillRect(0, 0, m_width, m_height, Qt::black);
0143     m_renderer->render(painter, QStringLiteral("background"), QRectF(0, 0, m_width, m_height));
0144 
0145     m_renderer->render(painter, QStringLiteral("screen"), QRectF(horizontalOffset, verticalOffset, mapWidth, mapHeight));
0146     painter->setOpacity(0.5);
0147     qreal lastLine = mapWidth + horizontalOffset;
0148     for (qreal i = horizontalOffset ; i <= lastLine ; i += sectorSize) {
0149         painter->drawLine(QPointF(i, verticalOffset), QPointF(i, mapHeight + verticalOffset));
0150     }
0151     lastLine = mapHeight + verticalOffset;
0152     for (qreal j = verticalOffset ; j <= lastLine ; j += sectorSize) {
0153         painter->drawLine(QPointF(horizontalOffset, j), QPointF(mapWidth + horizontalOffset, j));
0154     }
0155 }
0156 
0157 
0158 void
0159 MapScene::displayPlanetInfo(Planet *planet)
0160 {
0161     if (!planet) {
0162         if (m_planetInfoItem) {
0163             m_planetInfoItem->hide();
0164         }
0165 
0166         return;
0167     }
0168 
0169     /**
0170      * @todo Figure out why coord.y and coord.x seem to be used the other way
0171      * around.
0172      */
0173 
0174     QPointF pos(
0175         planet->sector()->coord().y() * getSectorSize() + itemsHorizontalOffset(),
0176         planet->sector()->coord().x() * getSectorSize() + itemsVerticalOffset()
0177     );
0178 
0179     displayPlanetInfo(planet, pos);
0180 }
0181 
0182 
0183 void
0184 MapScene::displayPlanetInfo (Planet *planet, const QPointF &pos)
0185 {
0186     if (!planet) {
0187         if (m_planetInfoItem) {
0188             m_planetInfoItem->hide();
0189         }
0190 
0191         return;
0192     }
0193 
0194     if (!m_planetInfoItem) {
0195         m_planetInfoItem = new PlanetInfoItem(m_game);
0196         addItem(m_planetInfoItem);
0197     }
0198 
0199     m_planetInfoItem->show();
0200     m_planetInfoItem->setPlanet(planet);
0201     m_planetInfoItem->setZValue(1.5);
0202     m_planetInfoItem->moveBy(
0203         pos.x() - m_planetInfoItem->x(),
0204         pos.y() - m_planetInfoItem->y()
0205     );
0206 
0207     // Move to stay in the game field.
0208 
0209     if (pos.x() > m_width / 2) {
0210         m_planetInfoItem->moveBy(-m_planetInfoItem->boundingRect().width(), 0);
0211     }
0212 
0213     if (pos.y() > m_height / 2) {
0214         m_planetInfoItem->moveBy(0, -m_planetInfoItem->boundingRect().height());
0215     }
0216 
0217     update();
0218 }
0219 
0220 
0221 qreal
0222 MapScene::getSectorSize()
0223 {
0224     qreal s_w = m_width / map()->columns();
0225     qreal s_h = m_height / map()->rows();
0226 
0227     return qMin(s_w, s_h);
0228 }
0229 
0230 
0231 qreal
0232 MapScene::itemsHorizontalOffset()
0233 {
0234     return (m_width - map()->columns() * getSectorSize()) / 2;
0235 }
0236 
0237 
0238 qreal
0239 MapScene::itemsVerticalOffset()
0240 {
0241     return (m_height - map()->rows() * getSectorSize()) / 2;
0242 }
0243 
0244 #include "moc_mapscene.cpp"