1 /**********************************************************************
2 *
3 * FreeDoko a Doppelkopf-Game
4 *
5 * Copyright (C) 2001 – 2018 by Diether Knof and Borg Enders
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You can find this license in the file 'gpl.txt'.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 * Contact:
24 * Diether Knof dknof@posteo.de
25 *
26 *********************************************************************/
27
28 #include "constants.h"
29
30 #ifdef USE_UI_GTKMM
31
32 #include "gameplay_actions.h"
33
34 #include "ui.h"
35
36 #include "../../party/party.h"
37
38 #include "../../utils/string.h"
39
40 #include <gtkmm/treeview.h>
41
42 namespace UI_GTKMM_NS {
43
44 /** constructor
45 **
46 ** @param parent parent object
47 **/
GameplayActions(Base * const parent)48 GameplayActions::GameplayActions(Base* const parent) :
49 Base(parent),
50 Gtk::TreeView()
51 {
52 this->init();
53 } // GameplayActions::GameplayActions(Base* parent)
54
55 /** destruktor
56 **/
57 GameplayActions::~GameplayActions() = default;
58
59 /** create all subelements
60 **/
61 void
init()62 GameplayActions::init()
63 {
64 this->list = Gtk::ListStore::create(this->model);
65 this->set_model(this->list);
66
67 this->get_selection()->set_mode(Gtk::SELECTION_NONE);
68
69 this->append_column(_("type"), this->model.type);
70 this->append_column(_("player"), this->model.player);
71 this->get_column_cell_renderer(1)->set_property("xalign", 0.5);
72 this->append_column(_("data"), this->model.data);
73
74 for (auto c : this->get_columns()) {
75 c->set_cell_data_func(*c->get_first_cell(),
76 sigc::mem_fun(*this, &GameplayActions::set_cell_color));
77 }
78 this->show_all_children();
79
80 if (this->get_realized())
81 this->update();
82 else
83 this->signal_realize().connect(sigc::mem_fun(*this, &GameplayActions::update));
84 } // void GameplayActions::init()
85
86 /** update (rewrite) all information
87 **
88 ** @todo mark the winner gray
89 ** @todo if there is no 'player_of' don't show the column
90 **/
91 void
update()92 GameplayActions::update()
93 {
94 if (!this->get_realized())
95 return ;
96
97 this->list->clear();
98
99 if (this->actions) {
100 unsigned trickno = 0;
101 for (unsigned a = 0; a < this->actions->size(); ++a) {
102 auto const& action = *((*this->actions)[a]);
103 auto row = *this->list->append();
104 row[this->model.type] = ::gettext(action.type());
105 unsigned const player = ::GameplayActions::player(action);
106 if (player == UINT_MAX)
107 row[this->model.player] = "";
108 else
109 #ifdef WORKAROUND
110 // in 'party_open()' 'BugReportReplay' first gets the party and then the ui
111 row[this->model.player]
112 = ::party->players()[player].name();
113 #else
114 row[this->model.player]
115 = this->ui->party().players()[player].name();
116 #endif
117 if (action.type() == ::GameplayActions::Type::trick_full) {
118 trickno += 1;
119 row[this->model.data]
120 = (String::to_string(trickno) + ": "
121 + action.data_translation());
122 } else {
123 row[this->model.data] = action.data_translation();
124 }
125 row[this->model.action] = &action;
126 row[this->model.no] = a;
127 } // for (a < this->actsion->size())
128 } // if (this->actions)
129 } // void GameplayActions::update()
130
131 /** sets the actions
132 **
133 ** @param actions actions to display
134 **/
135 void
set_actions(vector<unique_ptr<::GameplayAction>> const & actions)136 GameplayActions::set_actions(vector<unique_ptr<::GameplayAction>> const& actions)
137 {
138 this->actions = &actions;
139 this->update();
140 } // void GameplayActions::set_actions(vector<unique_ptr<::GameplayAction>> actions)
141
142 /** sets the discrepancy
143 **
144 ** @param discrepancies discrepancies of the actions to the gameplay
145 **/
146 void
set_discrepancies(vector<::GameplayActions::Discrepancy> const & discrepancies)147 GameplayActions::set_discrepancies(vector<::GameplayActions::Discrepancy>
148 const& discrepancies)
149 {
150 this->discrepancies = &discrepancies;
151 this->update();
152 } // void GameplayActions::set_discrepancies(vector<GameplayAction::Discrepancy> discrepancies)
153
154 /** removes the actions
155 **/
156 void
remove_actions()157 GameplayActions::remove_actions()
158 {
159 this->actions = nullptr;
160 this->discrepancies = nullptr;
161 this->update();
162 } // void GameplayActions::remove_actions()
163
164 /** sets the number of the current action
165 **
166 ** @param current_action_no new number
167 **/
168 void
set_current_action_no(unsigned const current_action_no)169 GameplayActions::set_current_action_no(unsigned const current_action_no)
170 {
171 this->current_action_no = current_action_no;
172
173 if (!this->get_realized())
174 return ;
175
176 // the redrawing is needed, so that the colors are updated
177 this->queue_draw();
178
179 // just scroll to the current row (I do not know a simplier way)
180 if (this->current_action_no < this->get_model()->children().size())
181 this->scroll_to_row(this->get_model()->get_path(*(this->get_model()->get_iter(String::to_string(current_action_no)))));
182 } // void GameplayActions::set_current_action_no(unsigned current_action_no)
183
184 /** the name of 'player' has changed
185 **
186 ** @param player the player with the changed name
187 **/
188 void
name_changed(Player const & player)189 GameplayActions::name_changed(Player const& player)
190 {
191 if (!this->get_realized())
192 return ;
193
194 this->update();
195 } // void GameplayActions::name_changed(Player player)
196
197 /** changes the color of the cell at 'iterator'
198 **
199 ** @param cell_renderer cell renderer to change
200 ** @param iterator row
201 **/
202 void
set_cell_color(Gtk::CellRenderer * const cell_renderer,Gtk::TreeModel::iterator const & iterator)203 GameplayActions::set_cell_color(Gtk::CellRenderer* const cell_renderer,
204 Gtk::TreeModel::iterator const& iterator)
205 {
206 auto const row = *iterator;
207 GameplayAction const* const action = row[this->model.action];
208 auto const action_no = row[this->model.no];
209
210 pair<string, string> colors;
211 if (this->discrepancies) {
212 if (row[this->model.no] < this->discrepancies->size())
213 colors = GameplayActions::colors(action->type(),
214 (*this->discrepancies)[action_no]);
215 else
216 colors = GameplayActions::colors(action->type(),
217 ::GameplayActions::Discrepancy::future);
218
219 } else { // if !(this->discrepancies)
220 colors = GameplayActions::colors(action->type(),
221 ::GameplayActions::Discrepancy::none);
222 } // if !(this->discrepancies)
223
224 cell_renderer->set_property("foreground", colors.first);
225 cell_renderer->set_property("background", colors.second);
226 cell_renderer->set_property("cell_background", colors.second);
227 } // void GameplayActions::set_cell_color(Gtk::CellRenderer* cell_renderer, Gtk::TreeModel::iterator iterator)
228
229 /** -> result
230 **
231 ** @param action_type the action type
232 ** @param discrepancy the discrepancy to the action
233 **
234 ** @return pair of colors (foreground, background)
235 **/
236 pair<string, string>
colors(::GameplayActions::Type const action_type,::GameplayActions::Discrepancy const discrepancy)237 GameplayActions::colors(::GameplayActions::Type const action_type,
238 ::GameplayActions::Discrepancy const discrepancy)
239 {
240 switch (action_type) {
241 case ::GameplayActions::Type::poverty_shift:
242 case ::GameplayActions::Type::poverty_accepted:
243 case ::GameplayActions::Type::poverty_returned:
244 case ::GameplayActions::Type::poverty_denied:
245 case ::GameplayActions::Type::poverty_denied_by_all:
246 case ::GameplayActions::Type::announcement:
247 case ::GameplayActions::Type::swines:
248 case ::GameplayActions::Type::hyperswines:
249 case ::GameplayActions::Type::marriage:
250 case ::GameplayActions::Type::genscher:
251 switch (discrepancy) {
252 case ::GameplayActions::Discrepancy::future:
253 return std::make_pair("black", "white");
254 case ::GameplayActions::Discrepancy::none:
255 return std::make_pair("black", "lightgreen");
256 case ::GameplayActions::Discrepancy::skipped:
257 case ::GameplayActions::Discrepancy::player:
258 case ::GameplayActions::Discrepancy::card:
259 case ::GameplayActions::Discrepancy::other:
260 return std::make_pair("black", "red");
261 } // switch (discrepancy)
262 break;
263
264 case ::GameplayActions::Type::reservation:
265 case ::GameplayActions::Type::trick_open:
266 case ::GameplayActions::Type::trick_full:
267 case ::GameplayActions::Type::trick_taken:
268 switch (discrepancy) {
269 case ::GameplayActions::Discrepancy::future:
270 return std::make_pair("black", "lightgray");
271 case ::GameplayActions::Discrepancy::none:
272 return std::make_pair("white", "darkgreen");
273 case ::GameplayActions::Discrepancy::skipped:
274 case ::GameplayActions::Discrepancy::player:
275 case ::GameplayActions::Discrepancy::card:
276 case ::GameplayActions::Discrepancy::other:
277 return std::make_pair("white", "darkred");
278 } // switch (discrepancy)
279 break;
280
281 case ::GameplayActions::Type::card_played:
282 switch (discrepancy) {
283 case ::GameplayActions::Discrepancy::future:
284 return std::make_pair("black", "white");
285 case ::GameplayActions::Discrepancy::none:
286 return std::make_pair("black", "green");
287 case ::GameplayActions::Discrepancy::skipped:
288 case ::GameplayActions::Discrepancy::player:
289 case ::GameplayActions::Discrepancy::card:
290 case ::GameplayActions::Discrepancy::other:
291 return std::make_pair("black", "red");
292 } // switch (discrepancy)
293 break;
294
295 case ::GameplayActions::Type::check:
296 return std::make_pair("red", "blue");
297 case ::GameplayActions::Type::print:
298 return std::make_pair("black", "blue");
299 case ::GameplayActions::Type::quit:
300 return std::make_pair("red", "white");
301 }; // switch (action_type)
302
303 return std::make_pair("black", "white");
304 } // static pair<string, string> GameplayActions::colors(GameplayActions::Type action_type, GameplayActions::Discrepancy discrepancy)
305
306 } // namespace UI_GTKMM_NS
307
308 #endif // #ifdef USE_UI_GTKMM
309