1 /*
2 SPDX-FileCopyrightText: 2009-2014 Graeme Gott <graeme@gottcode.org>
3
4 SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7 #include "letter.h"
8
9 #include "beveled_rect.h"
10
11 #include <QBrush>
12 #include <QCursor>
13 #include <QGraphicsEllipseItem>
14 #include <QGraphicsScene>
15 #include <QGraphicsSceneMouseEvent>
16 #include <QGraphicsSimpleTextItem>
17 #include <QLinearGradient>
18 #include <QRadialGradient>
19 #include <QPainterPath>
20 #include <QPen>
21
22 #include <cmath>
23
24 //-----------------------------------------------------------------------------
25
Letter(const QFont & font,int size,const QPoint & position)26 Letter::Letter(const QFont& font, int size, const QPoint& position)
27 : m_arrow(nullptr)
28 , m_clickable(true)
29 , m_position(position)
30 {
31 QPainterPath path;
32 path.addRoundedRect(0, 0, size, size, 5, 5);
33 setPath(path);
34 setPen(Qt::NoPen);
35 setBrush(Qt::white);
36 setHandlesChildEvents(true);
37 setZValue(1);
38
39 m_face = new QGraphicsEllipseItem(0.5, 0.5, size - 1, size - 1, this);
40 m_face->setPen(QPen(Qt::white, 1));
41 m_face->setBrush(Qt::white);
42
43 m_item = new QGraphicsSimpleTextItem(this);
44 m_item->setFont(font);
45 m_item->setBrush(Qt::black);
46 setText("?");
47
48 m_cell = new BeveledRect(size + 3, this);
49 m_cell->setPos(-1.5, -1.5);
50 m_cell->setFlag(QGraphicsItem::ItemStacksBehindParent);
51 m_cell->setColor(QColor(0, 0x57, 0xae));
52 }
53
54 //-----------------------------------------------------------------------------
55
setArrow(qreal angle,int z)56 void Letter::setArrow(qreal angle, int z)
57 {
58 delete m_arrow;
59 m_arrow = nullptr;
60 if (angle < 0.0) {
61 return;
62 }
63
64 QRect rect = sceneBoundingRect().toRect();
65 switch (std::lround(angle / 45.0)) {
66 case 0: // right
67 createSideArrow();
68 m_arrow->moveBy(rect.right() - 8, rect.center().y() + 0.5);
69 break;
70
71 case 1: // top right
72 createCornerArrow();
73 m_arrow->moveBy(rect.right() - 8.5, rect.top() + 8.5);
74 m_arrow->setRotation(270);
75 break;
76
77 case 2: // top
78 createSideArrow();
79 m_arrow->moveBy(rect.center().x() + 0.5, rect.top() + 8);
80 m_arrow->setRotation(270);
81 break;
82
83 case 3: // top left
84 createCornerArrow();
85 m_arrow->moveBy(rect.left() + 8.5, rect.top() + 8.5);
86 m_arrow->setRotation(180);
87 break;
88
89 case 4: // left
90 createSideArrow();
91 m_arrow->moveBy(rect.left() + 8, rect.center().y() + 0.5);
92 m_arrow->setRotation(180);
93 break;
94
95 case 5: // bottom left
96 createCornerArrow();
97 m_arrow->moveBy(rect.left() + 8.5, rect.bottom() - 8.5);
98 m_arrow->setRotation(90);
99 break;
100
101 case 6: // bottom
102 createSideArrow();
103 m_arrow->moveBy(rect.center().x() + 0.5, rect.bottom() - 8);
104 m_arrow->setRotation(90);
105 break;
106
107 case 7: // bottom right
108 createCornerArrow();
109 m_arrow->moveBy(rect.right() - 8.5, rect.bottom() - 8.5);
110 break;
111
112 default:
113 return;
114 };
115
116 m_arrow->setZValue(z + 2);
117 }
118
119 //-----------------------------------------------------------------------------
120
setCellColor(const QColor & color)121 void Letter::setCellColor(const QColor& color)
122 {
123 if (color.isValid()) {
124 m_cell->setColor(color, false);
125 } else {
126 m_cell->setColor(QColor(0, 0x57, 0xae));
127 }
128 }
129
130 //-----------------------------------------------------------------------------
131
setColor(const QColor & color)132 void Letter::setColor(const QColor& color)
133 {
134 QColor darker = color.darker(106);
135 QColor darkest = color.darker(160);
136
137 auto height = boundingRect().height();
138
139 QLinearGradient sides(0, 0, 0, height);
140 sides.setColorAt(0, darker);
141 sides.setColorAt(1, darkest);
142 setBrush(sides);
143
144 QLinearGradient face_border(0, 0, 0, height);
145 face_border.setColorAt(0, color);
146 face_border.setColorAt(1, darker);
147 m_face->setPen(QPen(face_border, 1));
148
149 auto radius = height / 2;
150 QRadialGradient face(radius, radius, radius);
151 face.setColorAt(0, color);
152 face.setColorAt(0.5, color);
153 face.setColorAt(1, darker);
154 m_face->setBrush(face);
155 }
156
157 //-----------------------------------------------------------------------------
158
setClickable(bool clickable)159 void Letter::setClickable(bool clickable)
160 {
161 m_clickable = clickable;
162 if (m_clickable) {
163 setCursor(Qt::PointingHandCursor);
164 setColor(Qt::white);
165 } else {
166 unsetCursor();
167 setColor(QColor(0xaa, 0xaa, 0xaa));
168 }
169 }
170
171 //-----------------------------------------------------------------------------
172
setText(const QString & text)173 void Letter::setText(const QString& text)
174 {
175 m_text = text;
176 m_item->setText(m_text);
177 m_item->setPos(boundingRect().center() - m_item->boundingRect().center());
178 }
179
180 //-----------------------------------------------------------------------------
181
mousePressEvent(QGraphicsSceneMouseEvent * event)182 void Letter::mousePressEvent(QGraphicsSceneMouseEvent* event)
183 {
184 Q_UNUSED(event);
185 if (m_clickable) {
186 emit clicked(this);
187 }
188 }
189
190 //-----------------------------------------------------------------------------
191
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)192 void Letter::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
193 {
194 event->ignore();
195 }
196
197 //-----------------------------------------------------------------------------
198
createCornerArrow()199 void Letter::createCornerArrow()
200 {
201 QPainterPath path;
202 path.moveTo(0, 0);
203 path.lineTo(22, 22);
204 path.moveTo(22, 14);
205 path.lineTo(22, 22);
206 path.lineTo(14, 22);
207
208 m_arrow = scene()->addPath(path, QPen(Qt::black, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
209 QGraphicsItem* fill = scene()->addPath(path, QPen(Qt::white, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
210 fill->setParentItem(m_arrow);
211 }
212
213 //-----------------------------------------------------------------------------
214
createSideArrow()215 void Letter::createSideArrow()
216 {
217 QPainterPath path;
218 path.moveTo(0, 0);
219 path.lineTo(22, 0);
220 path.moveTo(16, -6);
221 path.lineTo(22, 0);
222 path.lineTo(16, 6);
223
224 m_arrow = scene()->addPath(path, QPen(Qt::black, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
225 QGraphicsItem* fill = scene()->addPath(path, QPen(Qt::white, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
226 fill->setParentItem(m_arrow);
227 }
228
229 //-----------------------------------------------------------------------------
230