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