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