1 /* Pioneers - Implementation of the excellent Settlers of Catan board game.
2 * Go buy a copy.
3 *
4 * Copyright (C) 1999 Dave Cole
5 * Copyright (C) 2003, 2006 Bas Wijnen <shevek@fmf.nl>
6 * Copyright (C) 2004-2008 Roland Clobus <rclobus@bigfoot.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "config.h"
24 #include <stdlib.h>
25 #include "colors.h"
26 #include "frontend.h"
27 #include "log.h"
28 #include "common_gtk.h"
29 #include "player-icon.h"
30 #include "audio.h"
31
32 static void player_show_connected_at_iter(gint player_num,
33 gboolean connected,
34 GtkTreeIter * iter);
35
36 static GdkRGBA ps_settlement = { 0.73, 0.00, 0.00, 1.0 };
37 static GdkRGBA ps_city = { 1.00, 0.00, 0.00, 1.0 };
38 static GdkRGBA ps_city_wall = { 1.00, 0.00, 0.00, 1.0 };
39 static GdkRGBA ps_largest = { 0.11, 0.71, 0.93, 1.0 };
40 static GdkRGBA ps_soldier = { 0.90, 0.56, 0.09, 1.0 };
41 static GdkRGBA ps_resource = { 0.00, 0.00, 1.00, 1.0 };
42 static GdkRGBA ps_development = { 0.78, 0.78, 0.07, 1.0 };
43 static GdkRGBA ps_building = { 0.04, 0.93, 0.54, 1.0 };
44
45 typedef struct {
46 const gchar *singular;
47 const gchar *plural;
48 GdkRGBA *textcolor;
49 } Statistic;
50
51 static Statistic statistics[] = {
52 { N_("Settlement"), N_("Settlements"), &ps_settlement },
53 { N_("City"), N_("Cities"), &ps_city },
54 { N_("City wall"), N_("City walls"), &ps_city_wall },
55 { N_("Largest army"), NULL, &ps_largest },
56 { N_("Longest road"), NULL, &ps_largest },
57 { N_("Chapel"), N_("Chapels"), &ps_building },
58 { N_("Pioneer university"), N_("Pioneer universities"),
59 &ps_building },
60 { N_("Governor's house"), N_("Governor's houses"), &ps_building },
61 { N_("Library"), N_("Libraries"), &ps_building },
62 { N_("Market"), N_("Markets"), &ps_building },
63 { N_("Soldier"), N_("Soldiers"), &ps_soldier },
64 { N_("Resource card"), N_("Resource cards"), &ps_resource },
65 { N_("Development card"), N_("Development cards"), &ps_development }
66 };
67
68 enum {
69 SUMMARY_COLUMN_PLAYER_ICON, /**< Player icon */
70 SUMMARY_COLUMN_PLAYER_NUM, /**< Internal: player number */
71 SUMMARY_COLUMN_TEXT, /**< Description of the items */
72 SUMMARY_COLUMN_TEXT_COLOUR, /**< Colour of the description */
73 SUMMARY_COLUMN_SCORE, /**< Score of the items (as string) */
74 SUMMARY_COLUMN_STATISTIC, /**< enum Statistic value+1, or 0 if not in the enum */
75 SUMMARY_COLUMN_POINTS_ID, /**< Id of points, or -1 */
76 SUMMARY_COLUMN_LAST
77 };
78
79 static GtkListStore *summary_store; /**< the player summary data */
80 static GtkWidget *summary_widget; /**< the player summary widget */
81 static gboolean summary_color_enabled = TRUE;
82
83 /** Structure to find combination of player and statistic */
84 struct Player_statistic {
85 enum TFindResult result;
86 GtkTreeIter iter;
87 gint player_num;
88 gint statistic;
89 };
90
91 /** Structure to find combination of player and points */
92 struct Player_point {
93 enum TFindResult result;
94 GtkTreeIter iter;
95 gint player_num;
96 gint point_id;
97 };
98
99 static GtkWidget *turn_area; /** turn indicator in status bar */
100 /** Width for each icon */
101 static const gint turn_area_icon_width = 28;
102 /** Separation between each icon */
103 static const gint turn_area_icon_separation = 2;
104
player_init(void)105 void player_init(void)
106 {
107 colors_init();
108 playericon_init();
109 }
110
player_color(gint player_num)111 GdkRGBA *player_color(gint player_num)
112 {
113 return colors_get_player(player_num);
114 }
115
player_or_spectator_color(gint player_num)116 GdkRGBA *player_or_spectator_color(gint player_num)
117 {
118 if (player_is_spectator(player_num)) {
119 /* spectator color is always black */
120 return &black;
121 }
122 return colors_get_player(player_num);
123 }
124
player_create_icon(gint player_num,gboolean connected)125 GdkPixbuf *player_create_icon(gint player_num, gboolean connected)
126 {
127 GdkPixbuf *pixbuf;
128 gint width;
129 gint height;
130 cairo_surface_t *surface;
131
132 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
133 surface =
134 playericon_create_icon(player_get_style(player_num),
135 player_or_spectator_color(player_num),
136 player_is_spectator(player_num),
137 connected, width, height);
138 pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, width, height);
139 cairo_surface_destroy(surface);
140 return pixbuf;
141 }
142
143 /** Locate a line suitable for the statistic */
summary_locate_statistic(GtkTreeModel * model,G_GNUC_UNUSED GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)144 static gboolean summary_locate_statistic(GtkTreeModel * model,
145 G_GNUC_UNUSED GtkTreePath * path,
146 GtkTreeIter * iter,
147 gpointer user_data)
148 {
149 struct Player_statistic *ps =
150 (struct Player_statistic *) user_data;
151 gint current_player;
152 gint current_statistic;
153 gtk_tree_model_get(model, iter,
154 SUMMARY_COLUMN_PLAYER_NUM, ¤t_player,
155 SUMMARY_COLUMN_STATISTIC, ¤t_statistic,
156 -1);
157 if (current_player > ps->player_num) {
158 ps->result = FIND_MATCH_INSERT_BEFORE;
159 ps->iter = *iter;
160 return TRUE;
161 } else if (current_player == ps->player_num) {
162 if (current_statistic > ps->statistic) {
163 ps->result = FIND_MATCH_INSERT_BEFORE;
164 ps->iter = *iter;
165 return TRUE;
166 } else if (current_statistic == ps->statistic) {
167 ps->result = FIND_MATCH_EXACT;
168 ps->iter = *iter;
169 return TRUE;
170 }
171 }
172 return FALSE;
173 }
174
175 /** Locate a line suitable for the statistic */
summary_locate_point(GtkTreeModel * model,G_GNUC_UNUSED GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)176 static gboolean summary_locate_point(GtkTreeModel * model,
177 G_GNUC_UNUSED GtkTreePath * path,
178 GtkTreeIter * iter,
179 gpointer user_data)
180 {
181 struct Player_point *pp = (struct Player_point *) user_data;
182 gint current_player;
183 gint current_point_id;
184 gint current_statistic;
185
186 gtk_tree_model_get(model, iter,
187 SUMMARY_COLUMN_PLAYER_NUM, ¤t_player,
188 SUMMARY_COLUMN_STATISTIC, ¤t_statistic,
189 SUMMARY_COLUMN_POINTS_ID, ¤t_point_id,
190 -1);
191 if (current_player > pp->player_num) {
192 pp->result = FIND_MATCH_INSERT_BEFORE;
193 pp->iter = *iter;
194 return TRUE;
195 } else if (current_player == pp->player_num) {
196 if (current_statistic >= STAT_SOLDIERS) {
197 pp->result = FIND_MATCH_INSERT_BEFORE;
198 pp->iter = *iter;
199 return TRUE;
200 }
201 if (current_point_id > pp->point_id) {
202 pp->result = FIND_MATCH_INSERT_BEFORE;
203 pp->iter = *iter;
204 return TRUE;
205 } else if (current_point_id == pp->point_id) {
206 pp->result = FIND_MATCH_EXACT;
207 pp->iter = *iter;
208 return TRUE;
209 }
210 }
211 return FALSE;
212 }
213
214 /** Function to redisplay the running point total for the indicated player */
refresh_victory_point_total(int player_num)215 static void refresh_victory_point_total(int player_num)
216 {
217 gchar points[16];
218 GtkTreeIter iter;
219 enum TFindResult found;
220
221 g_return_if_fail(player_num >= 0 && player_num < num_players());
222
223 found =
224 find_integer_in_tree(GTK_TREE_MODEL(summary_store), &iter,
225 SUMMARY_COLUMN_PLAYER_NUM, player_num);
226
227 if (found == FIND_MATCH_EXACT) {
228 snprintf(points, sizeof(points), "%d",
229 player_get_score(player_num));
230 gtk_list_store_set(summary_store, &iter,
231 SUMMARY_COLUMN_SCORE, points, -1);
232 }
233 }
234
235 /** Apply colors to the summary */
summary_apply_colors_cb(GtkTreeModel * model,G_GNUC_UNUSED GtkTreePath * path,GtkTreeIter * iter,G_GNUC_UNUSED gpointer user_data)236 static gboolean summary_apply_colors_cb(GtkTreeModel * model,
237 G_GNUC_UNUSED GtkTreePath * path,
238 GtkTreeIter * iter,
239 G_GNUC_UNUSED gpointer user_data)
240 {
241 gint current_statistic;
242 gint point_id;
243
244 gtk_tree_model_get(model, iter,
245 SUMMARY_COLUMN_STATISTIC, ¤t_statistic,
246 SUMMARY_COLUMN_POINTS_ID, &point_id, -1);
247 if (current_statistic > 0)
248 gtk_list_store_set(summary_store, iter,
249 SUMMARY_COLUMN_TEXT_COLOUR,
250 summary_color_enabled ?
251 statistics[current_statistic -
252 1].textcolor : &black, -1);
253 else if (point_id >= 0)
254 gtk_list_store_set(summary_store, iter,
255 SUMMARY_COLUMN_TEXT_COLOUR,
256 summary_color_enabled ?
257 &ps_largest : &black, -1);
258 return FALSE;
259 }
260
set_color_summary(gboolean flag)261 void set_color_summary(gboolean flag)
262 {
263 if (flag != summary_color_enabled) {
264 summary_color_enabled = flag;
265 if (summary_store)
266 gtk_tree_model_foreach(GTK_TREE_MODEL
267 (summary_store),
268 summary_apply_colors_cb,
269 NULL);
270 }
271 }
272
frontend_new_statistics(gint player_num,StatisticType type,G_GNUC_UNUSED gint num)273 void frontend_new_statistics(gint player_num, StatisticType type,
274 G_GNUC_UNUSED gint num)
275 {
276 Player *player = player_get(player_num);
277 gint value;
278 gchar points[16];
279 GtkTreeIter iter;
280 struct Player_statistic ps;
281
282 value = player->statistics[type];
283 if (stat_get_vp_value(type) > 0)
284 refresh_victory_point_total(player_num);
285
286 ps.result = FIND_NO_MATCH;
287 ps.player_num = player_num;
288 ps.statistic = type + 1;
289 gtk_tree_model_foreach(GTK_TREE_MODEL(summary_store),
290 summary_locate_statistic, &ps);
291
292 if (value == 0) {
293 if (ps.result == FIND_MATCH_EXACT)
294 gtk_list_store_remove(summary_store, &ps.iter);
295 } else {
296 gchar *desc;
297 if (value == 1) {
298 if (statistics[type].plural != NULL)
299 desc = g_strdup_printf("%d %s", value,
300 gettext(statistics
301 [type].
302 singular));
303 else
304 desc = g_strdup(gettext
305 (statistics
306 [type].singular));
307 } else
308 desc = g_strdup_printf("%d %s", value,
309 gettext(statistics
310 [type].plural));
311 if (stat_get_vp_value(type) > 0)
312 sprintf(points, "%d",
313 value * stat_get_vp_value(type));
314 else
315 strcpy(points, "");
316
317 switch (ps.result) {
318 case FIND_NO_MATCH:
319 gtk_list_store_append(summary_store, &iter);
320 break;
321 case FIND_MATCH_INSERT_BEFORE:
322 gtk_list_store_insert_before(summary_store, &iter,
323 &ps.iter);
324 break;
325 case FIND_MATCH_EXACT:
326 iter = ps.iter;
327 break;
328 default:
329 g_error("unknown case in frontend_new_statistics");
330 };
331 gtk_list_store_set(summary_store, &iter,
332 SUMMARY_COLUMN_PLAYER_NUM, player_num,
333 SUMMARY_COLUMN_TEXT, desc,
334 SUMMARY_COLUMN_TEXT_COLOUR,
335 summary_color_enabled ?
336 statistics[type].textcolor : &black,
337 SUMMARY_COLUMN_STATISTIC, type + 1,
338 SUMMARY_COLUMN_POINTS_ID, -1,
339 SUMMARY_COLUMN_SCORE, points, -1);
340 g_free(desc);
341 }
342 frontend_gui_update();
343 }
344
frontend_new_points(gint player_num,Points * points,gboolean added)345 void frontend_new_points(gint player_num, Points * points, gboolean added)
346 {
347 GtkTreeIter iter;
348 struct Player_point pp;
349 gchar score[16];
350
351 refresh_victory_point_total(player_num);
352
353 pp.result = FIND_NO_MATCH;
354 pp.player_num = player_num;
355 pp.point_id = points->id;
356 gtk_tree_model_foreach(GTK_TREE_MODEL(summary_store),
357 summary_locate_point, &pp);
358
359 if (!added) {
360 if (pp.result != FIND_MATCH_EXACT)
361 g_error("cannot remove point");
362 gtk_list_store_remove(summary_store, &pp.iter);
363 frontend_gui_update();
364 return;
365 }
366
367 switch (pp.result) {
368 case FIND_NO_MATCH:
369 gtk_list_store_append(summary_store, &iter);
370 break;
371 case FIND_MATCH_INSERT_BEFORE:
372 gtk_list_store_insert_before(summary_store, &iter,
373 &pp.iter);
374 break;
375 case FIND_MATCH_EXACT:
376 iter = pp.iter;
377 break;
378 default:
379 g_error("unknown case in frontend_new_points");
380 };
381 snprintf(score, sizeof(score), "%d", points->points);
382 gtk_list_store_set(summary_store, &iter,
383 SUMMARY_COLUMN_PLAYER_NUM, player_num,
384 SUMMARY_COLUMN_TEXT, _(points->name),
385 SUMMARY_COLUMN_TEXT_COLOUR,
386 summary_color_enabled ? &ps_largest : &black,
387 SUMMARY_COLUMN_STATISTIC, 0,
388 SUMMARY_COLUMN_POINTS_ID, points->id,
389 SUMMARY_COLUMN_SCORE, score, -1);
390 frontend_gui_update();
391 }
392
player_create_find_player(gint player_num,GtkTreeIter * iter)393 static void player_create_find_player(gint player_num, GtkTreeIter * iter)
394 {
395 GtkTreeIter found_iter;
396 enum TFindResult result;
397
398 /* Search for a place to add information about the player/spectator */
399 result =
400 find_integer_in_tree(GTK_TREE_MODEL(summary_store),
401 &found_iter, SUMMARY_COLUMN_PLAYER_NUM,
402 player_num);
403
404 switch (result) {
405 case FIND_NO_MATCH:
406 gtk_list_store_append(summary_store, iter);
407 gtk_list_store_set(summary_store, iter,
408 SUMMARY_COLUMN_PLAYER_NUM, player_num,
409 SUMMARY_COLUMN_POINTS_ID, -1, -1);
410 break;
411 case FIND_MATCH_INSERT_BEFORE:
412 gtk_list_store_insert_before(summary_store, iter,
413 &found_iter);
414 gtk_list_store_set(summary_store, iter,
415 SUMMARY_COLUMN_PLAYER_NUM, player_num,
416 SUMMARY_COLUMN_POINTS_ID, -1, -1);
417 break;
418 case FIND_MATCH_EXACT:
419 *iter = found_iter;
420 break;
421 default:
422 g_error("unknown case in player_create_find_player");
423 };
424 }
425
frontend_player_name(gint player_num,const gchar * name)426 void frontend_player_name(gint player_num, const gchar * name)
427 {
428 GtkTreeIter iter;
429
430 player_create_find_player(player_num, &iter);
431 gtk_list_store_set(summary_store, &iter,
432 SUMMARY_COLUMN_TEXT, name, -1);
433
434 player_show_connected_at_iter(player_num, TRUE, &iter);
435 if (callback_mode != MODE_INIT)
436 play_sound(SOUND_ANNOUNCE);
437
438 chat_player_name(player_num, name);
439 }
440
frontend_player_style(gint player_num,G_GNUC_UNUSED const gchar * style)441 void frontend_player_style(gint player_num,
442 G_GNUC_UNUSED const gchar * style)
443 {
444 GtkTreeIter iter;
445
446 player_create_find_player(player_num, &iter);
447 player_show_connected_at_iter(player_num, TRUE, &iter);
448 chat_player_style(player_num);
449 }
450
frontend_spectator_name(gint spectator_num,const gchar * name)451 void frontend_spectator_name(gint spectator_num, const gchar * name)
452 {
453 GtkTreeIter iter;
454
455 player_create_find_player(spectator_num, &iter);
456 gtk_list_store_set(summary_store, &iter,
457 SUMMARY_COLUMN_TEXT, name, -1);
458 if (callback_mode != MODE_INIT)
459 play_sound(SOUND_ANNOUNCE);
460
461 chat_player_name(spectator_num, name);
462 }
463
frontend_player_quit(gint player_num)464 void frontend_player_quit(gint player_num)
465 {
466 GtkTreeIter iter;
467
468 player_create_find_player(player_num, &iter);
469 player_show_connected_at_iter(player_num, FALSE, &iter);
470
471 chat_player_quit(player_num);
472 }
473
frontend_spectator_quit(gint spectator_num)474 void frontend_spectator_quit(gint spectator_num)
475 {
476 GtkTreeIter iter;
477
478 player_create_find_player(spectator_num, &iter);
479 gtk_list_store_remove(summary_store, &iter);
480
481 chat_spectator_quit(spectator_num);
482 }
483
player_show_connected_at_iter(gint player_num,gboolean connected,GtkTreeIter * iter)484 static void player_show_connected_at_iter(gint player_num,
485 gboolean connected,
486 GtkTreeIter * iter)
487 {
488 GdkPixbuf *pixbuf = player_create_icon(player_num, connected);
489
490 gtk_list_store_set(summary_store, iter,
491 SUMMARY_COLUMN_PLAYER_ICON, pixbuf, -1);
492 g_object_unref(pixbuf);
493 }
494
495 /* Get the top and bottom row for player summary and make sure player
496 * is visible
497 */
player_show_summary(gint player_num)498 static void player_show_summary(gint player_num)
499 {
500 GtkTreeIter found_iter;
501 enum TFindResult result;
502 gboolean scroll_to_end = FALSE;
503
504 result =
505 find_integer_in_tree(GTK_TREE_MODEL(summary_store),
506 &found_iter, SUMMARY_COLUMN_PLAYER_NUM,
507 player_num + 1);
508
509 if (result == FIND_NO_MATCH) {
510 scroll_to_end = TRUE;
511 } else {
512 GtkTreePath *path =
513 gtk_tree_model_get_path(GTK_TREE_MODEL(summary_store),
514 &found_iter);
515 if (gtk_tree_path_prev(path))
516 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW
517 (summary_widget),
518 path, NULL, FALSE,
519 0.0, 0.0);
520 gtk_tree_path_free(path);
521 }
522
523 result =
524 find_integer_in_tree(GTK_TREE_MODEL(summary_store),
525 &found_iter, SUMMARY_COLUMN_PLAYER_NUM,
526 player_num);
527 if (result != FIND_NO_MATCH) {
528 GtkTreePath *path =
529 gtk_tree_model_get_path(GTK_TREE_MODEL(summary_store),
530 &found_iter);
531 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(summary_widget),
532 path, NULL, scroll_to_end,
533 0.0, 0.0);
534 gtk_tree_view_set_cursor(GTK_TREE_VIEW(summary_widget),
535 path, NULL, FALSE);
536 gtk_tree_path_free(path);
537 }
538 }
539
player_build_summary(void)540 GtkWidget *player_build_summary(void)
541 {
542 GtkWidget *vbox;
543 GtkWidget *label;
544 GtkWidget *scroll_win;
545 GtkWidget *alignment;
546 GtkCellRenderer *renderer;
547 GtkTreeViewColumn *column;
548
549 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
550 gtk_widget_show(vbox);
551
552 alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
553 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 3, 3);
554 gtk_widget_show(alignment);
555 gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
556
557 label = gtk_label_new(NULL);
558 /* Caption for the overview of the points and card of other players */
559 gtk_label_set_markup(GTK_LABEL(label), _("<b>Player summary</b>"));
560 gtk_widget_show(label);
561 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
562 gtk_container_add(GTK_CONTAINER(alignment), label);
563
564 summary_store = gtk_list_store_new(SUMMARY_COLUMN_LAST, GDK_TYPE_PIXBUF, /* player icon */
565 G_TYPE_INT, /* player number */
566 G_TYPE_STRING, /* text */
567 GDK_TYPE_RGBA, /* text colour */
568 G_TYPE_STRING, /* score */
569 G_TYPE_INT, /* statistic */
570 G_TYPE_INT); /* points */
571 summary_widget =
572 gtk_tree_view_new_with_model(GTK_TREE_MODEL(summary_store));
573
574 column = gtk_tree_view_column_new_with_attributes("",
575 gtk_cell_renderer_pixbuf_new
576 (), "pixbuf",
577 SUMMARY_COLUMN_PLAYER_ICON,
578 NULL);
579 gtk_tree_view_column_set_sizing(column,
580 GTK_TREE_VIEW_COLUMN_GROW_ONLY);
581 gtk_tree_view_append_column(GTK_TREE_VIEW(summary_widget), column);
582
583 column = gtk_tree_view_column_new_with_attributes("",
584 gtk_cell_renderer_text_new
585 (), "text",
586 SUMMARY_COLUMN_TEXT,
587 "foreground-rgba",
588 SUMMARY_COLUMN_TEXT_COLOUR,
589 NULL);
590 gtk_tree_view_column_set_sizing(column,
591 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
592 gtk_tree_view_column_set_expand(column, TRUE);
593 gtk_tree_view_append_column(GTK_TREE_VIEW(summary_widget), column);
594
595 renderer = gtk_cell_renderer_text_new();
596 column = gtk_tree_view_column_new_with_attributes("",
597 renderer,
598 "text",
599 SUMMARY_COLUMN_SCORE,
600 "foreground-rgba",
601 SUMMARY_COLUMN_TEXT_COLOUR,
602 NULL);
603 g_object_set(renderer, "xalign", 1.0f, NULL);
604 gtk_tree_view_column_set_sizing(column,
605 GTK_TREE_VIEW_COLUMN_GROW_ONLY);
606 gtk_tree_view_append_column(GTK_TREE_VIEW(summary_widget), column);
607
608 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(summary_widget),
609 FALSE);
610 gtk_widget_show(summary_widget);
611
612 scroll_win = gtk_scrolled_window_new(NULL, NULL);
613 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW
614 (scroll_win), GTK_SHADOW_IN);
615 gtk_widget_show(scroll_win);
616 gtk_box_pack_start(GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0);
617 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
618 GTK_POLICY_AUTOMATIC,
619 GTK_POLICY_AUTOMATIC);
620
621 gtk_container_add(GTK_CONTAINER(scroll_win), summary_widget);
622
623 return vbox;
624 }
625
draw_turn_area_cb(GtkWidget * widget,cairo_t * cr,G_GNUC_UNUSED gpointer user_data)626 static gboolean draw_turn_area_cb(GtkWidget * widget, cairo_t * cr,
627 G_GNUC_UNUSED gpointer user_data)
628 {
629 gint offset;
630 gint idx;
631 GtkAllocation allocation;
632
633 gtk_widget_get_allocation(widget, &allocation);
634 offset = 0;
635 for (idx = 0; idx < num_players(); idx++) {
636 gdk_cairo_set_source_rgba(cr, player_color(idx));
637 cairo_rectangle(cr, offset, 0, turn_area_icon_width,
638 allocation.height);
639 cairo_fill(cr);
640
641 gdk_cairo_set_source_rgba(cr, &black);
642 if (idx == current_player()) {
643 cairo_set_line_width(cr, 3.0);
644 cairo_rectangle(cr, offset + 1.5, 1.5,
645 turn_area_icon_width - 3,
646 allocation.height - 3);
647 } else {
648 cairo_set_line_width(cr, 1.0);
649 cairo_rectangle(cr, offset + 0.5, 0.5,
650 turn_area_icon_width - 1,
651 allocation.height - 1);
652 }
653 cairo_stroke(cr);
654
655 offset += turn_area_icon_width + turn_area_icon_separation;
656 }
657 return TRUE;
658 }
659
player_build_turn_area(void)660 GtkWidget *player_build_turn_area(void)
661 {
662 turn_area = gtk_drawing_area_new();
663 g_signal_connect(G_OBJECT(turn_area), "draw",
664 G_CALLBACK(draw_turn_area_cb), NULL);
665 gtk_widget_set_size_request(turn_area,
666 turn_area_icon_width * num_players() +
667 turn_area_icon_separation *
668 (num_players() - 1), -1);
669 gtk_widget_show(turn_area);
670
671 return turn_area;
672 }
673
set_num_players(gint num)674 void set_num_players(gint num)
675 {
676 gtk_widget_set_size_request(turn_area,
677 turn_area_icon_width * num +
678 turn_area_icon_separation * (num - 1),
679 -1);
680 }
681
player_show_current(gint player_num)682 void player_show_current(gint player_num)
683 {
684 gtk_widget_queue_draw(turn_area);
685 player_show_summary(player_num);
686 }
687
player_clear_summary(void)688 void player_clear_summary(void)
689 {
690 gtk_list_store_clear(GTK_LIST_STORE(summary_store));
691 }
692