new 4475edb243ed4627f4c5f2c470ca40b3def034d4
[tagua/yd.git] / src / graphicalgame.cpp
bloba05517d7436947b3ae666474a166c0f6718e4c33
1 /*
2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@gmail.com>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 */
11 #include <core/color.h>
12 #include <core/moveserializer.h>
13 #include <core/state.h>
14 #include <core/validator.h>
16 #include "variant.h"
17 #include "components.h"
18 #include "graphicalgame.h"
20 #include <KDebug>
22 #include "game.h"
23 #include "game_p.h"
24 #include "mastersettings.h"
25 #include "graphicalsystem.h"
26 #include "movelist_table.h"
27 #include "decoratedmove.h"
28 #include "entities/userentity.h"
30 using namespace GamePrivate; // is this ok?
32 template <typename Enum>
33 inline void setFlag(QFlags<Enum>& flag, Enum e, bool value) {
34 if (value)
35 flag |= e;
36 else
37 flag &= ~e;
41 class CtrlAction {
42 Game* m_game;
43 bool m_done;
44 Index m_index;
45 public:
46 CtrlAction(Game* game)
47 : m_game(game)
48 , m_index(game->index()) {
49 m_done = m_game->back();
52 void forfait() { m_done = false; }
54 ~CtrlAction() {
55 if (m_done) m_game->goTo(m_index);
59 GraphicalGame::GraphicalGame(GraphicalSystem* graphical,
60 MoveList::Table* m)
61 : Game(graphical->components())
62 , m_graphical(graphical)
63 , m_movelist(m)
64 , m_anim_sequence(false) {
65 m_action_state = 0;
66 m_decorator = graphical->components()->moveSerializer("decorated");
68 if(m_movelist) {
69 m_movelist->reset();
70 // FIXME restore move list layout
71 m_movelist->setLayoutStyle(0 /*graphical->m_variant->moveListLayout()*/);
72 m_movelist->setNotifier( static_cast<MoveList::Notifier*>(this) );
73 m_movelist->show();
75 settings().onChange(this, "settingsChanged", "Loader::Theme");
76 settingsChanged();
79 GraphicalGame::~GraphicalGame() {
80 if(m_movelist) {
81 Q_ASSERT(m_movelist->getNotifier() == static_cast<MoveList::Notifier*>(this));
83 m_movelist->setNotifier(NULL, false);
87 void GraphicalGame::settingsChanged() {
88 m_anim_sequence = settings().flag("animations", true)
89 && settings()("animations").flag("sequence", true);
90 m_anim_sequence_max = settings()("animations")("sequence")[QString("max")] | 10;
93 void GraphicalGame::onAdded(const Index& ix) {
94 onAddedInternal(ix);
95 updateActionState();
98 void GraphicalGame::onAddedInternal(const Index& ix, bool confirm_promotion) {
99 if(!m_movelist)
100 return;
102 int at;
103 History *vec = fetchRef(ix, &at);
104 if(!vec) {
105 kError() << "invalid index " << ix;
106 return;
109 m_movelist->remove(ix, confirm_promotion); //clear existing, if any
111 Index index = ix;
112 for(int i=at;i<(int)vec->size();i++) {
113 Entry* e = &(*vec)[i];
114 StatePtr prev = position(index.prev());
115 DecoratedMove mv(
116 (e->move != Move() && prev) ?
117 m_decorator->serialize(e->move, prev.get()) :
118 (e->position ? "(-)" : "???"));
120 int turn = prev ? prev->turn()->index() : (index.totalNumMoves()+1)%2;
122 //mv += " " + QString::number(turn);
123 m_movelist->setMove(index, turn, mv, e->comment, confirm_promotion);
125 for (Variations::const_iterator it = e->variations.begin();
126 it != e->variations.end(); ++it)
127 onAddedInternal(index.next(it->first), confirm_promotion);
128 for (VComments::const_iterator it = e->vcomments.begin();
129 it != e->vcomments.end(); ++it)
130 m_movelist->setVComment(index, it->first, it->second, confirm_promotion);
132 index = index.next();
136 void GraphicalGame::onEntryChanged(const Index& at, int propagate) {
137 if(at <= Index(0)) {
138 Entry* e = fetch(at);
139 if(!e)
140 return;
141 if(at == current && e->position)
142 m_graphical->warp(e->move, e->position);
143 return;
146 if(m_movelist) {
147 Entry* e = fetch(at);
148 if(!e)
149 return;
151 Entry* pe = fetch(at.prev());
153 StatePtr last_pos;
154 if (pe) last_pos = pe->position;
156 DecoratedMove mv(
157 (e->move != Move() && last_pos) ?
158 m_decorator->serialize(e->move, last_pos.get()) :
159 (e->position ? "(-)" : "???"));
161 int turn = last_pos ?
162 last_pos->turn()->index() :
163 (at.totalNumMoves()+1)%2;
165 m_movelist->setMove(at, turn, mv, e->comment);
166 if(at == current && e->position)
167 m_graphical->warp(e->move, e->position);
169 // when an entry changes, chances are that we get some more information about the
170 // next ones as well
171 if(propagate) {
172 onEntryChanged(at.next(), propagate-1);
173 for (Variations::const_iterator it = e->variations.begin();
174 it != e->variations.end(); ++it)
175 onEntryChanged(at.next(it->first), propagate-1);
180 void GraphicalGame::onRemoved(const Index& i) {
181 if(m_movelist)
182 m_movelist->remove(i);
183 updateActionState();
186 void GraphicalGame::onPromoteVariation(const Index& i, int v) {
187 if(m_movelist) {
188 m_movelist->promoteVariation(i,v);
189 onAddedInternal(i.next(), true);
190 onAddedInternal(i.next(v), true);
191 VComments vc = fetch(i)->vcomments;
192 VComments::const_iterator it = vc.find(v);
193 if(it != vc.end())
194 m_movelist->setVComment(i, v, it->second, true);
195 m_movelist->select(current, true);
197 updateActionState();
200 void GraphicalGame::onSetComment(const Index& i, const QString& s) {
201 if(m_movelist)
202 m_movelist->setComment(i, s);
205 void GraphicalGame::onSetVComment(const Index& i, int v, const QString& s) {
206 if(m_movelist)
207 m_movelist->setVComment(i, v, s);
210 void GraphicalGame::updateActionState() {
211 ActionState old_state = m_action_state;
212 setFlag(m_action_state, BACK, current != 0);
213 setFlag(m_action_state, BEGIN, current != 0);
214 Entry* next_entry = fetch(current.next());
215 setFlag(m_action_state, FORWARD, next_entry);
216 setFlag(m_action_state, END, next_entry);
217 if (old_state != m_action_state)
218 onActionStateChange();
221 void GraphicalGame::onCurrentIndexChanged(const Index& old_c) {
222 if (m_ctrl) m_ctrl->forfait();
224 if(m_movelist)
225 m_movelist->select(current);
227 updateActionState();
229 Entry *oe = fetch(old_c);
230 Entry *e = fetch(current);
231 std::pair<int, int> steps = old_c.stepsTo(current);
233 if(!e || !e->position)
234 return;
236 if(!oe || !oe->position) {
237 m_graphical->warp(move(), position());
238 return;
241 bool can_animate = (steps.first+steps.second <= 1) || (m_anim_sequence
242 && (steps.first+steps.second <= m_anim_sequence_max));
244 if(can_animate)
245 for(int i=1;i<=steps.first;i++)
246 if( move(old_c.prev(i-1)) == Move() ||
247 !position(old_c.prev(i))) {
248 can_animate = false;
249 break;
252 if(can_animate)
253 for(int i=steps.second-1;i>=0;i--)
254 if( move(current.prev(i)) == Move() ||
255 !position(current.prev(i))) {
256 can_animate = false;
257 break;
260 if(can_animate) {
261 for(int i=1;i<=steps.first;i++)
262 m_graphical->back( move(old_c.prev(i)), move(old_c.prev(i-1)), position(old_c.prev(i)));
263 for(int i=steps.second-1;i>=0;i--)
264 m_graphical->forward( move(current.prev(i)), position(current.prev(i)));
266 else
267 m_graphical->warp( move(), position());
269 // set m_action_state
273 void GraphicalGame::onAvailableUndo(bool e) {
274 setFlag(m_action_state, UNDO, e);
275 onActionStateChange();
278 void GraphicalGame::onAvailableRedo(bool e) {
279 setFlag(m_action_state, REDO, e);
280 onActionStateChange();
283 void GraphicalGame::onUserSelectMove(const Index& i) {
284 if (boost::shared_ptr<UserEntity> entity = m_listener_entity.lock())
285 if (entity->goTo(i))
286 return;
288 // fallback
289 goTo(i);
292 void GraphicalGame::onUserSetComment(const Index& i, QString s) {
293 setComment(i, s);
296 void GraphicalGame::onUserSetVComment(const Index& i, int v, QString s) {
297 setVComment(i, v, s);
300 void GraphicalGame::onUserClearVariations(const Index& i) {
301 clearVariations(i);
304 void GraphicalGame::onUserTruncate(const Index& i) {
305 if (i == index())
306 if (boost::shared_ptr<UserEntity> entity = m_listener_entity.lock())
307 if (entity->truncate())
308 return;
310 // fallback
311 truncate(i);
314 void GraphicalGame::onUserPromoteVariation(const Index& i) {
315 if (i == index())
316 if (boost::shared_ptr<UserEntity> entity = m_listener_entity.lock())
317 if (entity->promoteVariation())
318 return;
320 // fallback
321 promoteVariation(i);
324 void GraphicalGame::onUserRemoveVariation(const Index& i) {
325 removeVariation(i);
328 void GraphicalGame::onUserUndo() {
329 if (boost::shared_ptr<UserEntity> entity = m_listener_entity.lock())
330 if (entity->undo())
331 return;
333 // fallback
334 undo();
337 void GraphicalGame::onUserRedo() {
338 if (boost::shared_ptr<UserEntity> entity = m_listener_entity.lock())
339 if (entity->redo())
340 return;
342 // fallback
343 redo();
346 void GraphicalGame::onDetachNotifier() {
347 Q_ASSERT(m_movelist->getNotifier() == static_cast<MoveList::Notifier*>(this));
349 m_movelist = NULL;
352 void GraphicalGame::createCtrlAction() {
353 m_ctrl = boost::shared_ptr<CtrlAction>(new CtrlAction(this));
356 void GraphicalGame::destroyCtrlAction() {
357 m_ctrl.reset();
360 void GraphicalGame::setActionStateObserver(
361 const boost::shared_ptr<ActionStateObserver>& obs) {
362 m_action_state_observer = obs;
365 void GraphicalGame::onActionStateChange() {
366 m_action_state_observer->notifyActionStateChange(m_action_state);
369 ActionStateObserver::~ActionStateObserver() { }