File indexing completed on 2024-03-24 04:07:36
0001 /* 0002 SPDX-FileCopyrightText: 2006 Matthew Williams <matt@milliams.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "gameboardscene.h" 0008 0009 #include "highlightanimation.h" 0010 0011 #include <cmath> 0012 0013 #include <QGraphicsSceneMouseEvent> 0014 #include <QGraphicsEllipseItem> 0015 0016 #include <QDebug> 0017 0018 //generated 0019 #include "settings.h" 0020 0021 GameBoardScene::GameBoardScene(int newWidth, int newHeight, QObject *parent) : QGraphicsScene(parent), width(newWidth), height(newHeight), acceptEvents(true) 0022 { 0023 ////qDebug() << "GameBoardScene::GameBoardScene()"; 0024 0025 for (int i = 0; i < (2 * width * height + width + height); i++) { 0026 lineList.append(false); //simply fill array with 'false's 0027 } 0028 0029 spacing = 40; //this hard coding doesn't matter since auto-resizing exists :) 0030 for (int iWidth = 0; iWidth <= width; iWidth++) { 0031 for (int iHeight = 0; iHeight <= height; iHeight++) { 0032 int x = iWidth * spacing; 0033 int y = iHeight * spacing; 0034 auto dot = new QGraphicsEllipseItem(QRectF(-2, -2, 4, 4)); 0035 dot->moveBy(x, y); 0036 dot->setBrush(QBrush(Settings::centerDotColor(), Qt::SolidPattern)); 0037 dot->setZValue(20); // set the elevation, the dot's are on top 0038 addItem(dot); 0039 } 0040 } 0041 QPen feintPen(Qt::DotLine); //for the guidelines between dots 0042 feintPen.setWidth(1); 0043 feintPen.setColor(Settings::feintLineColor()); 0044 for (int iWidth = 0; iWidth <= width; iWidth++) { 0045 addLine(QLineF(spacing * iWidth, 0, spacing * iWidth, spacing * height), feintPen); 0046 } 0047 for (int iHeight = 0; iHeight <= height; iHeight++) { 0048 addLine(QLineF(0, spacing * iHeight, spacing * width, spacing * iHeight), feintPen); 0049 } 0050 0051 setBackgroundBrush(QBrush(Settings::backgroundColor())); 0052 0053 indicatorLine = new QGraphicsLineItem(1, 1, 1, 1); 0054 indicatorLine->setZValue(10); 0055 indicatorLine->setPen(QPen(QBrush(Settings::indicatorLineColor()), 2.5)); 0056 indicatorLine->hide(); 0057 addItem(indicatorLine); 0058 0059 QGraphicsEllipseItem tempItem; 0060 QGraphicsEllipseItemType = tempItem.type(); 0061 0062 qreal border = 10; 0063 QRectF rect = sceneRect(); 0064 rect.setLeft(rect.left() - border); 0065 rect.setRight(rect.right() + border); 0066 rect.setTop(rect.top() - border); 0067 rect.setBottom(rect.bottom() + border); 0068 setSceneRect(rect); 0069 } 0070 0071 GameBoardScene::~GameBoardScene() 0072 { 0073 //qDebug() << "GameBoardScene::~GameBoardScene()"; 0074 delete indicatorLine; 0075 } 0076 0077 void GameBoardScene::drawLine(int index, const QColor &colour) 0078 { 0079 auto line = new QGraphicsLineItem(lineFromIndex(index)); 0080 line->setZValue(10); 0081 line->setPen(QPen(QBrush(colour), 2.5)); 0082 addItem(line); // draw new line 0083 lineList[index] = true; // keep this table in sync 0084 indicatorLine->hide(); 0085 update(line->boundingRect()); 0086 } 0087 0088 void GameBoardScene::highlightLine(int index) 0089 { 0090 auto anim = new HighlightAnimation(lineFromIndex(index)); 0091 anim->setZValue(9); 0092 addItem(anim); 0093 } 0094 0095 void GameBoardScene::drawSquare(int index, const QColor &colour) 0096 { 0097 QBrush brush(colour, Qt::SolidPattern); 0098 0099 addRect(QRectF(qreal((index % width)*spacing), qreal((index / width)*spacing), qreal(spacing), qreal(spacing)), QPen(), brush)->setZValue(-1); 0100 } 0101 0102 int GameBoardScene::indexFromPointPair(const QList<QGraphicsEllipseItem *> &pointPair) const 0103 { 0104 0105 if (pointPair.size() != 2) { 0106 return -1; // if it isn't a pair 0107 } 0108 0109 qreal pointOneX = pointPair.at(0)->scenePos().x() / spacing; 0110 qreal pointOneY = pointPair.at(0)->scenePos().y() / spacing; 0111 qreal pointTwoX = pointPair.at(1)->scenePos().x() / spacing; 0112 qreal pointTwoY = pointPair.at(1)->scenePos().y() / spacing; 0113 0114 //this int conversion could go bad but SHOULD be safe 0115 qreal refX; // these two will be the grid-coord of the 0116 qreal refY; // to and left most point of the two 0117 0118 int index = -1; 0119 if (pointOneX == pointTwoX) { 0120 //dir = VERTICAL; 0121 refX = pointOneX; 0122 if (pointTwoY < pointOneY) { //want the topmost point as reference 0123 refY = pointTwoY; 0124 } else { 0125 refY = pointOneY; 0126 } 0127 index = static_cast<int>(refY * ((2 * width) + 1) + refX + width); 0128 } 0129 0130 else if (pointOneY == pointTwoY) { 0131 //dir = HORIZONTAL; 0132 refY = pointOneY; 0133 if (pointOneX < pointTwoX) { //want the leftmost point as reference 0134 refX = pointOneX; 0135 } else { 0136 refX = pointTwoX; 0137 } 0138 index = static_cast<int>(refY * ((2 * width) + 1) + refX); 0139 } 0140 return index; 0141 } 0142 0143 QLineF GameBoardScene::lineFromIndex(int index) const 0144 { 0145 int index2 = index % ((2 * width) + 1); 0146 enum {HORIZONTAL, VERTICAL} dir; 0147 if (index2 < width) { 0148 dir = HORIZONTAL; 0149 } else { 0150 dir = VERTICAL; 0151 } 0152 0153 int yCoordStart = (index / ((2 * width) + 1)) * spacing; 0154 int xCoordStart = 0; 0155 int yCoordEnd = 0; 0156 int xCoordEnd = 0; 0157 switch (dir) { 0158 case HORIZONTAL: 0159 xCoordStart = index2 * spacing; 0160 yCoordEnd = yCoordStart; 0161 xCoordEnd = xCoordStart + spacing; 0162 break; 0163 case VERTICAL: 0164 xCoordStart = (index2 - width) * spacing; 0165 yCoordEnd = yCoordStart + spacing; 0166 xCoordEnd = xCoordStart; 0167 break; 0168 } 0169 return QLineF(xCoordStart, yCoordStart, xCoordEnd, yCoordEnd); 0170 } 0171 0172 bool GameBoardScene::isLineAlready(const QList<QGraphicsEllipseItem *> &pointPair) const //TODO does this work? 0173 { 0174 int index = indexFromPointPair(pointPair); 0175 if (index == -1) { 0176 return true; 0177 } 0178 0179 return lineList.at(index); 0180 } 0181 0182 void GameBoardScene::addLineToIndex(const QList<QGraphicsEllipseItem *> &pointPair) 0183 { 0184 int index = indexFromPointPair(pointPair); 0185 if (index == -1) { //not a valid line since no two unique ends 0186 return; 0187 } 0188 0189 Q_EMIT lineDrawn(index); //addLineToIndex(index); 0190 } 0191 0192 QList<QGraphicsEllipseItem *> GameBoardScene::getTwoNearestPoints(const QPointF &pos) const 0193 { 0194 QList<QGraphicsItem *> itemList = items(); 0195 QList<QGraphicsEllipseItem *> connectList; 0196 for (int i = 0; i < itemList.size(); ++i) { 0197 if (itemList.at(i)->type() == QGraphicsEllipseItemType) { 0198 //cout << "itemList.at(i)->scenePos():" << qgraphicsitem_cast<QGraphicsEllipseItem*>(itemList.at(i))->scenePos().x() << "," << qgraphicsitem_cast<QGraphicsEllipseItem*>(itemList.at(i))->scenePos().y() << endl; 0199 QPointF dist(pos - itemList.at(i)->scenePos()); 0200 qreal distMod = sqrt(dist.x() * dist.x() + dist.y() * dist.y()); 0201 //if (distMod < (spacing*0.7071)) //there will only ever be either 1 or 2 items that fulfil this [0.7071 ~ 2^(-0.5)] 0202 if (distMod < spacing - 5) { 0203 connectList << qgraphicsitem_cast<QGraphicsEllipseItem *>(itemList.at(i)); 0204 } 0205 } 0206 } 0207 return connectList; 0208 } 0209 0210 const QSize GameBoardScene::minimumSizeHint() const 0211 { 0212 return QSize((width * spacing) + 10, (height * spacing) + 10); // the +10 is to provide padding and to avoid scrollbars 0213 } 0214 0215 /*void GameBoardScene::mousePressEvent (QGraphicsSceneMouseEvent* mouseEvent) 0216 { 0217 if (!acceptEvents) return; 0218 QGraphicsScene::mousePressEvent(mouseEvent); 0219 }*/ 0220 0221 void GameBoardScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) 0222 { 0223 if (!acceptEvents) { 0224 QGraphicsScene::mouseReleaseEvent(mouseEvent); 0225 return; 0226 } 0227 0228 //cout << "GameBoardScene::mouseReleaseEvent" << endl; 0229 if (mouseEvent->button() == Qt::LeftButton) { 0230 QList<QGraphicsEllipseItem *> connectList = getTwoNearestPoints(mouseEvent->scenePos()); 0231 if (connectList.size() == 2) { 0232 addLineToIndex(connectList); 0233 } 0234 } 0235 0236 QGraphicsScene::mouseReleaseEvent(mouseEvent); 0237 } 0238 0239 void GameBoardScene::acknowledgeMove(int x1, int y1, int x2, int y2) 0240 { 0241 QPoint calculatedpos(((x1 + x2) / 2.0) * spacing, ((y1 + y2) / 2.0) * spacing); 0242 QList<QGraphicsEllipseItem *> connectList = getTwoNearestPoints(calculatedpos); 0243 addLineToIndex(connectList); 0244 } 0245 0246 void GameBoardScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) 0247 { 0248 if (!acceptEvents) { 0249 return; 0250 } 0251 //indicatorLine = 0; 0252 0253 ////qDebug() << "GameBoardScene::mouseMoveEvent"; 0254 ////qDebug() << "mouseEvent->scenePos():" << mouseEvent->scenePos().x() << "," << mouseEvent->scenePos().y(); 0255 0256 QList<QGraphicsEllipseItem *> connectList = getTwoNearestPoints(mouseEvent->scenePos()); 0257 0258 if (connectList.size() == 2 && !isLineAlready(connectList)) { 0259 //if there are two nearest points and there isn't already a line 0260 indicatorLine->setLine(QLineF(connectList.at(0)->scenePos(), connectList.at(1)->scenePos())); //where 0261 indicatorLine->show(); 0262 } else { 0263 indicatorLine->hide(); 0264 } 0265 0266 QGraphicsScene::mouseMoveEvent(mouseEvent); 0267 } 0268 0269 #include "moc_gameboardscene.cpp"