1 /*
2 * Gyatzee: Gnomified Yahtzee game.
3 * (C) 1998 the Free Software Foundation
4 *
5 * File: clist.c
6 *
7 * Author: Scott Heavner
8 *
9 * Scoring is done using a GtkTreeView and handled in this file.
10 *
11 * Variables are exported in gyahtzee.h
12 *
13 * This file is largely based upon GTT code by Eckehard Berns.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29 #include <gtk/gtk.h>
30 #include <gdk/gdk.h>
31
32 #include <stdio.h>
33
34 #include "yahtzee.h"
35 #include "gyahtzee.h"
36
37 static gchar *row_tooltips[MAX_FIELDS];
38
39 void
update_score_cell(GtkWidget * treeview,gint row,gint col,int val)40 update_score_cell (GtkWidget * treeview, gint row, gint col, int val)
41 {
42 GtkTreeModel *model;
43 GtkTreeIter iter;
44 char *buf;
45
46 g_assert (treeview != NULL);
47
48 model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
49 gtk_tree_model_iter_nth_child (model, &iter, NULL, row);
50 if (val < 0)
51 gtk_list_store_set (GTK_LIST_STORE (model), &iter, col, "", -1);
52 else {
53 buf = g_strdup_printf ("%i", val);
54 gtk_list_store_set (GTK_LIST_STORE (model), &iter, col, buf, -1);
55 g_free (buf);
56 }
57 }
58
59 static void
set_label_bold(GtkLabel * label,gboolean make_bold)60 set_label_bold (GtkLabel * label, gboolean make_bold)
61 {
62 PangoAttrList *attrlist;
63 PangoAttribute *attr;
64
65 g_assert (label != NULL);
66
67 attrlist = gtk_label_get_attributes (label);
68 if (!attrlist)
69 attrlist = pango_attr_list_new ();
70
71 if (make_bold) {
72 attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
73 attr->start_index = 0;
74 attr->end_index = -1;
75 pango_attr_list_change (attrlist, attr);
76 } else {
77 attr = pango_attr_weight_new (PANGO_WEIGHT_NORMAL);
78 attr->start_index = 0;
79 attr->end_index = -1;
80 pango_attr_list_change (attrlist, attr);
81 }
82 gtk_label_set_attributes (label, attrlist);
83 }
84
85 /* Shows the active player by make the player name bold in the TreeView. */
86 void
ShowoffPlayer(GtkWidget * treeview,int player,int so)87 ShowoffPlayer (GtkWidget * treeview, int player, int so)
88 {
89 GtkTreeViewColumn *col;
90 GtkWidget *label;
91 GList *collist;
92
93 g_return_if_fail (treeview != NULL);
94
95 if (player < 0 || player >= MAX_NUMBER_OF_PLAYERS)
96 return;
97
98 collist = gtk_tree_view_get_columns (GTK_TREE_VIEW (treeview));
99 col = GTK_TREE_VIEW_COLUMN (g_list_nth_data (collist, player + 1));
100 g_list_free (collist);
101
102 label = gtk_tree_view_column_get_widget (col);
103 if (!label)
104 return;
105
106 g_assert (GTK_IS_LABEL (label));
107
108 set_label_bold (GTK_LABEL (label), so);
109 }
110
gtk_tree_path_to_row(GtkTreePath * path)111 static gint gtk_tree_path_to_row (GtkTreePath *path)
112 {
113 char *path_str = gtk_tree_path_to_string (path);
114 gint row;
115 if (sscanf (path_str, "%i", &row) != 1) {
116 g_warning ("%s: could not convert '%s' to integer\n",
117 G_STRFUNC, path_str);
118 g_free (path_str);
119 return -1;
120 }
121 g_free (path_str);
122 return row;
123 }
124
125 /* Convert the row of a tree into the score row */
126
score_row(GtkTreePath * path)127 static gint score_row (GtkTreePath *path)
128 {
129 gint row = gtk_tree_path_to_row (path);
130 if (row == R_UTOTAL || row == R_BONUS || row == R_BLANK1 ||
131 row == R_GTOTAL || row == R_LTOTAL)
132 return -1;
133
134 /* Adjust for Upper Total / Bonus entries */
135 if (row >= NUM_UPPER)
136 row -= 3;
137
138 if (row < 0 || row >= NUM_FIELDS)
139 return -1;
140
141 return row;
142 }
143
144 static void
row_activated_cb(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * column,gpointer user_data)145 row_activated_cb (GtkTreeView * treeview, GtkTreePath * path,
146 GtkTreeViewColumn * column, gpointer user_data)
147 {
148 int row = score_row (path);
149
150 if (players[CurrentPlayer].comp)
151 return;
152
153 if (row >= 0) {
154 if (row < NUM_FIELDS && !players[CurrentPlayer].finished) {
155 if (play_score (CurrentPlayer, row) == SLOT_USED) {
156 say (_("Already used! " "Where do you want to put that?"));
157 } else {
158 UndoScoreElement *elem = RedoHead ();
159 if (elem && elem->player == CurrentPlayer) {
160 RedoPlayer ();
161 } else {
162 NextPlayer ();
163 }
164 }
165 }
166 }
167 update_undo_sensitivity ();
168 }
169
170 static gboolean
activate_selected_row_idle_cb(gpointer data)171 activate_selected_row_idle_cb (gpointer data)
172 {
173 GtkTreeView *tree = GTK_TREE_VIEW (data);
174 GtkTreeViewColumn *column;
175 GtkTreePath *path;
176
177 path = NULL;
178 gtk_tree_view_get_cursor (tree, &path, &column);
179 if (path) {
180 if (!column)
181 column = gtk_tree_view_get_column (tree, 0);
182 gtk_tree_view_row_activated (tree, path, column);
183 }
184
185 /* Quoted from docs: "The returned GtkTreePath must be freed
186 * with gtk_tree_path_free() when you are done with it." */
187 gtk_tree_path_free (path);
188
189 return FALSE;
190 }
191
192 /* Returns: FALSE to let the GtkTreeView focus the selected row */
193 static gboolean
tree_button_press_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)194 tree_button_press_cb (GtkWidget * widget, GdkEventButton * event,
195 gpointer data)
196 {
197 GtkTreeView *tree = GTK_TREE_VIEW (data);
198
199 g_assert (widget != NULL);
200 g_assert (event != NULL);
201
202 if (event->type != GDK_BUTTON_PRESS)
203 return FALSE;
204
205 g_idle_add_full (G_PRIORITY_HIGH, activate_selected_row_idle_cb,
206 (gpointer) tree, NULL);
207
208 return FALSE;
209 }
210
211 /* Returns: TRUE to let GtkTreeView know it can show a tooltip */
212 static gboolean
tree_query_tooltip_cb(GtkWidget * widget,gint x,gint y,gboolean keyboard_mode,GtkTooltip * tooltip,gpointer data)213 tree_query_tooltip_cb (GtkWidget * widget, gint x, gint y,
214 gboolean keyboard_mode, GtkTooltip *tooltip, gpointer data)
215 {
216 GtkTreeModel *model_ptr = NULL;
217 GtkTreePath *path_ptr = NULL;
218 GtkTreeIter *iter_ptr = NULL;
219 gint rval = FALSE;
220
221 if (gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y,
222 keyboard_mode, &model_ptr, &path_ptr, iter_ptr)) {
223 if (path_ptr) {
224 gint row = score_row (path_ptr);
225 if (row >= 0) {
226 gtk_tooltip_set_text (tooltip, row_tooltips[row]);
227 rval = TRUE;
228 }
229 }
230 }
231
232 return rval;
233 }
234
235 GtkWidget *
create_score_list(void)236 create_score_list (void)
237 {
238 GtkWidget *tree;
239 GtkListStore *store;
240
241 store = gtk_list_store_new (MAX_NUMBER_OF_PLAYERS + 3,
242 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
243 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
244 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
245 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
246 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree), TRUE);
247 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (tree), FALSE);
248 gtk_widget_set_has_tooltip (GTK_WIDGET (tree), TRUE);
249
250 g_object_unref (store);
251
252 g_signal_connect (G_OBJECT (tree), "row-activated",
253 G_CALLBACK (row_activated_cb), NULL);
254 g_signal_connect (G_OBJECT (tree), "button-press-event",
255 G_CALLBACK (tree_button_press_cb), (gpointer) tree);
256 g_signal_connect (G_OBJECT (tree), "query-tooltip",
257 G_CALLBACK (tree_query_tooltip_cb), (gpointer) tree);
258
259 return tree;
260 }
261
262 static void
add_columns(GtkTreeView * tree)263 add_columns (GtkTreeView * tree)
264 {
265 GtkTreeViewColumn *column;
266 GtkCellRenderer *renderer;
267 GtkWidget *label;
268 GValue *prop_value;
269 int i;
270
271 /* Create columns */
272 renderer = gtk_cell_renderer_text_new ();
273 column = gtk_tree_view_column_new_with_attributes ("", renderer,
274 "text", 0,
275 "weight", LAST_COL,
276 NULL);
277 g_object_set (renderer, "weight-set", TRUE, NULL);
278 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
279 for (i = 0; i < MAX_NUMBER_OF_PLAYERS; i++) {
280 renderer = gtk_cell_renderer_text_new ();
281 prop_value = g_new0 (GValue, 1);
282 g_value_init (prop_value, G_TYPE_FLOAT);
283 g_value_set_float (prop_value, 1.0);
284 g_object_set_property (G_OBJECT (renderer), "xalign", prop_value);
285 g_object_set (renderer, "weight-set", TRUE, NULL);
286 g_value_unset (prop_value);
287 g_free (prop_value);
288
289 column = gtk_tree_view_column_new ();
290 gtk_tree_view_column_pack_start (column, renderer, TRUE);
291 gtk_tree_view_column_set_attributes (column, renderer,
292 "text", i + 1,
293 "weight", LAST_COL, NULL);
294 gtk_tree_view_column_set_min_width (column, 95);
295 gtk_tree_view_column_set_alignment (column, 1.0);
296 label = gtk_label_new (players[i].name);
297 gtk_tree_view_column_set_widget (column, label);
298 gtk_widget_show (label);
299 gtk_tree_view_column_set_visible (column, FALSE);
300 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
301 }
302 renderer = gtk_cell_renderer_text_new ();
303 column = gtk_tree_view_column_new_with_attributes ("", renderer, "text",
304 MAX_NUMBER_OF_PLAYERS
305 + 1, NULL);
306 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
307 }
308
309 void
score_list_set_column_title(GtkWidget * treeview,int column,const char * str)310 score_list_set_column_title (GtkWidget * treeview, int column,
311 const char *str)
312 {
313 GtkTreeViewColumn *col;
314 GtkWidget *label;
315
316 g_assert (treeview != NULL);
317
318 col = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), column);
319 label = gtk_tree_view_column_get_widget (col);
320 if (!label)
321 return;
322
323 gtk_label_set_text (GTK_LABEL (label), str);
324 }
325
326 static void
initialize_column_titles(GtkTreeView * treeview)327 initialize_column_titles (GtkTreeView * treeview)
328 {
329 GtkTreeViewColumn *col;
330 GList *collist, *node;
331 GtkWidget *label;
332 int i;
333
334 collist = gtk_tree_view_get_columns (treeview);
335 i = 0;
336 for (node = collist; node != NULL; node = g_list_next (node)) {
337 col = GTK_TREE_VIEW_COLUMN (node->data);
338 label = gtk_tree_view_column_get_widget (col);
339 if (!label)
340 continue;
341
342 gtk_tree_view_column_set_visible (col, i < NumberOfPlayers);
343 gtk_label_set_text (GTK_LABEL (label), players[i].name);
344 i++;
345 }
346 g_list_free (collist);
347 }
348
349 void
setup_score_list(GtkWidget * treeview)350 setup_score_list (GtkWidget * treeview)
351 {
352 GtkTreeModel *model;
353 GtkListStore *store;
354 GtkTreeIter iter;
355 GList *columns;
356 int i;
357
358 g_assert (treeview != NULL);
359
360 columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (treeview));
361 if (!columns) {
362 add_columns (GTK_TREE_VIEW (treeview));
363 } else {
364 initialize_column_titles (GTK_TREE_VIEW (treeview));
365 }
366
367 model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
368 store = GTK_LIST_STORE (model);
369 gtk_list_store_clear (store);
370
371 for (i = 0; i < NUM_UPPER; i++) {
372 gtk_list_store_append (store, &iter);
373 gtk_list_store_set (store, &iter, 0, _(FieldLabels[i]),
374 LAST_COL, PANGO_WEIGHT_NORMAL, -1);
375 }
376
377 gtk_list_store_append (store, &iter);
378 gtk_list_store_set (store, &iter, 0, _(FieldLabels[F_BONUS]),
379 LAST_COL, PANGO_WEIGHT_BOLD, -1);
380 gtk_list_store_append (store, &iter);
381 gtk_list_store_set (store, &iter, 0, _(FieldLabels[F_UPPERT]),
382 LAST_COL, PANGO_WEIGHT_BOLD, -1);
383 gtk_list_store_append (store, &iter);
384 gtk_list_store_set (store, &iter, 0, "", -1);
385
386 for (i = 0; i < NUM_LOWER; i++) {
387 gtk_list_store_append (store, &iter);
388 gtk_list_store_set (store, &iter,
389 0, _(FieldLabels[i + NUM_UPPER]),
390 LAST_COL, PANGO_WEIGHT_NORMAL, -1);
391 }
392
393 gtk_list_store_append (store, &iter);
394 gtk_list_store_set (store, &iter, 0, _(FieldLabels[F_LOWERT]),
395 LAST_COL, PANGO_WEIGHT_BOLD, -1);
396 gtk_list_store_append (store, &iter);
397 gtk_list_store_set (store, &iter, 0, _(FieldLabels[F_GRANDT]),
398 LAST_COL, PANGO_WEIGHT_BOLD, -1);
399 }
400
401 void
update_score_tooltips(void)402 update_score_tooltips (void)
403 {
404 gint ii;
405
406 for (ii = 0; ii < NUM_FIELDS; ii++) {
407 gint score = player_field_score (CurrentPlayer, ii);
408 if (!row_tooltips[ii]) row_tooltips[ii] = g_new0 (gchar, 100);
409
410
411 if (score >= 0)
412 sprintf (row_tooltips[ii], _("Score: %d"), score);
413 else
414 sprintf (row_tooltips[ii], _("Field used"));
415 }
416 }
417