1 #include <QAction>
2 #include <QDebug>
3 #include <QPainter>
4 #include <QPen>
5 #include <QTimer>
6 #include <cmath>
7 #ifdef _WIN32
8 #include "round.h"
9 #endif /* _WIN32 */
10 #include "pb/command_draw_cards.pb.h"
11 #include "pb/command_next_turn.pb.h"
12 #include "pb/command_set_active_phase.pb.h"
13 #include "pb/command_set_card_attr.pb.h"
14 #include "phasestoolbar.h"
15 #include "pixmapgenerator.h"
16
PhaseButton(const QString & _name,QGraphicsItem * parent,QAction * _doubleClickAction,bool _highlightable)17 PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_doubleClickAction, bool _highlightable)
18 : QObject(), QGraphicsItem(parent), name(_name), active(false), highlightable(_highlightable),
19 activeAnimationCounter(0), doubleClickAction(_doubleClickAction), width(50)
20 {
21 if (highlightable) {
22 activeAnimationTimer = new QTimer(this);
23 connect(activeAnimationTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));
24 activeAnimationTimer->setSingleShot(false);
25 } else
26 activeAnimationCounter = 9;
27
28 setCacheMode(DeviceCoordinateCache);
29 }
30
boundingRect() const31 QRectF PhaseButton::boundingRect() const
32 {
33 return {0, 0, width, width};
34 }
35
paint(QPainter * painter,const QStyleOptionGraphicsItem *,QWidget *)36 void PhaseButton::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
37 {
38 QRectF iconRect = boundingRect().adjusted(3, 3, -3, -3);
39 QRectF translatedIconRect = painter->combinedTransform().mapRect(iconRect);
40 qreal scaleFactor = translatedIconRect.width() / iconRect.width();
41 QPixmap iconPixmap =
42 PhasePixmapGenerator::generatePixmap(static_cast<int>(round(translatedIconRect.height())), name);
43
44 painter->setBrush(QColor(static_cast<int>(220 * (activeAnimationCounter / 10.0)),
45 static_cast<int>(220 * (activeAnimationCounter / 10.0)),
46 static_cast<int>(220 * (activeAnimationCounter / 10.0))));
47 painter->setPen(Qt::gray);
48 painter->drawRect(0, 0, static_cast<int>(width - 1), static_cast<int>(width - 1));
49 painter->save();
50 resetPainterTransform(painter);
51 painter->drawPixmap(iconPixmap.rect().translated(static_cast<int>(round(3 * scaleFactor)),
52 static_cast<int>(round(3 * scaleFactor))),
53 iconPixmap, iconPixmap.rect());
54 painter->restore();
55
56 painter->setBrush(QColor(0, 0, 0, static_cast<int>(255 * ((10 - activeAnimationCounter) / 15.0))));
57 painter->setPen(Qt::gray);
58 painter->drawRect(0, 0, static_cast<int>(width - 1), static_cast<int>(width - 1));
59 }
60
setWidth(double _width)61 void PhaseButton::setWidth(double _width)
62 {
63 prepareGeometryChange();
64 width = _width;
65 }
66
setActive(bool _active)67 void PhaseButton::setActive(bool _active)
68 {
69 if ((active == _active) || !highlightable)
70 return;
71
72 active = _active;
73 activeAnimationTimer->start(25);
74 }
75
updateAnimation()76 void PhaseButton::updateAnimation()
77 {
78 if (!highlightable)
79 return;
80
81 if (active) {
82 if (++activeAnimationCounter >= 10)
83 activeAnimationTimer->stop();
84 } else {
85 if (--activeAnimationCounter <= 0)
86 activeAnimationTimer->stop();
87 }
88 update();
89 }
90
mousePressEvent(QGraphicsSceneMouseEvent *)91 void PhaseButton::mousePressEvent(QGraphicsSceneMouseEvent * /*event*/)
92 {
93 emit clicked();
94 }
95
mouseDoubleClickEvent(QGraphicsSceneMouseEvent *)96 void PhaseButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/)
97 {
98 triggerDoubleClickAction();
99 }
100
triggerDoubleClickAction()101 void PhaseButton::triggerDoubleClickAction()
102 {
103 if (doubleClickAction)
104 doubleClickAction->trigger();
105 }
106
PhasesToolbar(QGraphicsItem * parent)107 PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
108 : QGraphicsItem(parent), width(100), height(100), ySpacing(1), symbolSize(8)
109 {
110 auto *aUntapAll = new QAction(this);
111 connect(aUntapAll, SIGNAL(triggered()), this, SLOT(actUntapAll()));
112 auto *aDrawCard = new QAction(this);
113 connect(aDrawCard, SIGNAL(triggered()), this, SLOT(actDrawCard()));
114
115 PhaseButton *untapButton = new PhaseButton("untap", this, aUntapAll);
116 PhaseButton *upkeepButton = new PhaseButton("upkeep", this);
117 PhaseButton *drawButton = new PhaseButton("draw", this, aDrawCard);
118 PhaseButton *main1Button = new PhaseButton("main1", this);
119 PhaseButton *combatStartButton = new PhaseButton("combat_start", this);
120 PhaseButton *combatAttackersButton = new PhaseButton("combat_attackers", this);
121 PhaseButton *combatBlockersButton = new PhaseButton("combat_blockers", this);
122 PhaseButton *combatDamageButton = new PhaseButton("combat_damage", this);
123 PhaseButton *combatEndButton = new PhaseButton("combat_end", this);
124 PhaseButton *main2Button = new PhaseButton("main2", this);
125 PhaseButton *cleanupButton = new PhaseButton("cleanup", this);
126
127 buttonList << untapButton << upkeepButton << drawButton << main1Button << combatStartButton << combatAttackersButton
128 << combatBlockersButton << combatDamageButton << combatEndButton << main2Button << cleanupButton;
129
130 for (auto &i : buttonList)
131 connect(i, SIGNAL(clicked()), this, SLOT(phaseButtonClicked()));
132
133 nextTurnButton = new PhaseButton("nextturn", this, nullptr, false);
134 connect(nextTurnButton, SIGNAL(clicked()), this, SLOT(actNextTurn()));
135
136 rearrangeButtons();
137
138 retranslateUi();
139 }
140
boundingRect() const141 QRectF PhasesToolbar::boundingRect() const
142 {
143 return {0, 0, width, height};
144 }
145
retranslateUi()146 void PhasesToolbar::retranslateUi()
147 {
148 for (int i = 0; i < buttonList.size(); ++i)
149 buttonList[i]->setToolTip(getLongPhaseName(i));
150 }
151
getLongPhaseName(int phase) const152 QString PhasesToolbar::getLongPhaseName(int phase) const
153 {
154 switch (phase) {
155 case 0:
156 return tr("Untap step");
157 case 1:
158 return tr("Upkeep step");
159 case 2:
160 return tr("Draw step");
161 case 3:
162 return tr("First main phase");
163 case 4:
164 return tr("Beginning of combat step");
165 case 5:
166 return tr("Declare attackers step");
167 case 6:
168 return tr("Declare blockers step");
169 case 7:
170 return tr("Combat damage step");
171 case 8:
172 return tr("End of combat step");
173 case 9:
174 return tr("Second main phase");
175 case 10:
176 return tr("End of turn step");
177 default:
178 return QString();
179 }
180 }
181
paint(QPainter * painter,const QStyleOptionGraphicsItem *,QWidget *)182 void PhasesToolbar::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
183 {
184 painter->fillRect(boundingRect(), QColor(50, 50, 50));
185 }
186
187 const double PhasesToolbar::marginSize = 3;
188
rearrangeButtons()189 void PhasesToolbar::rearrangeButtons()
190 {
191 for (auto &i : buttonList)
192 i->setWidth(symbolSize);
193 nextTurnButton->setWidth(symbolSize);
194
195 double y = marginSize;
196 buttonList[0]->setPos(marginSize, y);
197 buttonList[1]->setPos(marginSize, y += symbolSize);
198 buttonList[2]->setPos(marginSize, y += symbolSize);
199 y += ySpacing;
200 buttonList[3]->setPos(marginSize, y += symbolSize);
201 y += ySpacing;
202 buttonList[4]->setPos(marginSize, y += symbolSize);
203 buttonList[5]->setPos(marginSize, y += symbolSize);
204 buttonList[6]->setPos(marginSize, y += symbolSize);
205 buttonList[7]->setPos(marginSize, y += symbolSize);
206 buttonList[8]->setPos(marginSize, y += symbolSize);
207 y += ySpacing;
208 buttonList[9]->setPos(marginSize, y += symbolSize);
209 y += ySpacing;
210 buttonList[10]->setPos(marginSize, y += symbolSize);
211 y += ySpacing;
212 y += ySpacing;
213 nextTurnButton->setPos(marginSize, y + symbolSize);
214 }
215
setHeight(double _height)216 void PhasesToolbar::setHeight(double _height)
217 {
218 prepareGeometryChange();
219
220 height = _height;
221 ySpacing = (height - 2 * marginSize) / (buttonCount * 5 + spaceCount);
222 symbolSize = ySpacing * 5;
223 width = symbolSize + 2 * marginSize;
224
225 rearrangeButtons();
226 }
227
setActivePhase(int phase)228 void PhasesToolbar::setActivePhase(int phase)
229 {
230 if (phase >= buttonList.size())
231 return;
232
233 for (int i = 0; i < buttonList.size(); ++i)
234 buttonList[i]->setActive(i == phase);
235 }
236
triggerPhaseAction(int phase)237 void PhasesToolbar::triggerPhaseAction(int phase)
238 {
239 if (0 <= phase && phase < buttonList.size()) {
240 buttonList[phase]->triggerDoubleClickAction();
241 }
242 }
243
phaseButtonClicked()244 void PhasesToolbar::phaseButtonClicked()
245 {
246 auto *button = qobject_cast<PhaseButton *>(sender());
247 if (button->getActive())
248 button->triggerDoubleClickAction();
249
250 Command_SetActivePhase cmd;
251 cmd.set_phase(static_cast<google::protobuf::uint32>(buttonList.indexOf(button)));
252
253 emit sendGameCommand(cmd, -1);
254 }
255
actNextTurn()256 void PhasesToolbar::actNextTurn()
257 {
258 emit sendGameCommand(Command_NextTurn(), -1);
259 }
260
actUntapAll()261 void PhasesToolbar::actUntapAll()
262 {
263 Command_SetCardAttr cmd;
264 cmd.set_zone("table");
265 cmd.set_attribute(AttrTapped);
266 cmd.set_attr_value("0");
267
268 emit sendGameCommand(cmd, -1);
269 }
270
actDrawCard()271 void PhasesToolbar::actDrawCard()
272 {
273 Command_DrawCards cmd;
274 cmd.set_number(1);
275
276 emit sendGameCommand(cmd, -1);
277 }
278