1 /*****************************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 *****************************************************************************/
15 #include <fc_config.h>
24 #include <gdk/gdkkeysyms.h>
31 /* client/gui-gtk-4.0 */
32 #include "gui_stuff.h"
35 #include "citizensinfo.h"
38 static struct citizens_dialog
*citizens_dialog_get(const struct city
*pcity
);
39 static struct citizens_dialog
40 *citizens_dialog_create(const struct city
*pcity
);
41 static GtkTreeStore
*citizens_dialog_store_new(void);
42 static int citizens_dialog_default_sort_column(void);
43 static void citizens_dialog_row(GtkTreeStore
*store
, GtkTreeIter
*it
,
44 const struct city
*pcity
,
45 const struct player_slot
*pslot
);
47 static const char *col_nation(const struct city
*pcity
,
48 const struct player_slot
*pslot
);
49 static const char *col_citizens(const struct city
*pcity
,
50 const struct player_slot
*pslot
);
52 /*****************************************************************************
53 The layout of the citizens display.
54 *****************************************************************************/
55 static struct citizens_column
{
57 enum player_dlg_column_type type
;
59 const char *(*func
)(const struct city
*, const struct player_slot
*);
60 /* if type = COL_*TEXT */
61 const char *tagname
; /* for save_options */
63 {TRUE
, COL_RIGHT_TEXT
, N_("#"), col_citizens
, "citizens"},
64 {TRUE
, COL_FLAG
, N_("Flag"), NULL
, "flag"},
65 {TRUE
, COL_TEXT
, N_("Nation"), col_nation
, "nation"}
67 static const int num_citizens_cols
= ARRAY_SIZE(citizens_cols
);
68 #define CITIZENS_DLG_COL_STYLE (0 + num_citizens_cols)
69 #define CITIZENS_DLG_COL_WEIGHT (1 + num_citizens_cols)
70 #define CITIZENS_DLG_COL_ID (2 + num_citizens_cols)
72 /*****************************************************************************
74 *****************************************************************************/
75 struct citizens_dialog
{
76 const struct city
*pcity
;
83 #define SPECLIST_TAG dialog
84 #define SPECLIST_TYPE struct citizens_dialog
87 #define dialog_list_iterate(dialoglist, pdialog) \
88 TYPED_LIST_ITERATE(struct citizens_dialog, dialoglist, pdialog)
89 #define dialog_list_iterate_end LIST_ITERATE_END
91 static struct dialog_list
*dialog_list
;
93 /*****************************************************************************
94 The name of the player's nation for the plrdlg.
95 *****************************************************************************/
96 static const char *col_nation(const struct city
*pcity
,
97 const struct player_slot
*pslot
)
99 return nation_adjective_for_player(player_slot_get_player(pslot
));
102 /*****************************************************************************
103 The number of citizens for the player in the city.
104 *****************************************************************************/
105 static const char *col_citizens(const struct city
*pcity
,
106 const struct player_slot
*pslot
)
108 citizens nationality
= citizens_nation_get(pcity
, pslot
);
110 if (nationality
== 0) {
115 fc_snprintf(buf
, sizeof(buf
), "%d", nationality
);
121 /****************************************************************************
122 Create a citizens dialog store.
124 FIXME: copy of players_dialog_store_new();
125 ****************************************************************************/
126 static GtkTreeStore
*citizens_dialog_store_new(void)
129 GType model_types
[num_citizens_cols
+ 3];
132 for (i
= 0; i
< num_citizens_cols
; i
++) {
133 switch (citizens_cols
[i
].type
) {
135 model_types
[i
] = GDK_TYPE_PIXBUF
;
138 model_types
[i
] = GDK_TYPE_PIXBUF
;
141 model_types
[i
] = G_TYPE_BOOLEAN
;
145 model_types
[i
] = G_TYPE_STRING
;
149 /* special (invisible rows) - Text style, weight and player id */
150 model_types
[i
++] = G_TYPE_INT
; /* CITIZENS_DLG_COL_STYLE. */
151 model_types
[i
++] = G_TYPE_INT
; /* CITIZENS_DLG_COL_WEIGHT. */
152 model_types
[i
++] = G_TYPE_INT
; /* CITIZENS_DLG_COL_ID. */
154 store
= gtk_tree_store_newv(i
, model_types
);
159 /*****************************************************************************
160 Returns column to sort by by default
161 *****************************************************************************/
162 static int citizens_dialog_default_sort_column(void) {
166 /*****************************************************************************
167 Create citizens dialog
168 *****************************************************************************/
169 static struct citizens_dialog
170 *citizens_dialog_create(const struct city
*pcity
)
172 GtkWidget
*frame
, *sw
;
173 struct citizens_dialog
*pdialog
= fc_malloc(sizeof(struct citizens_dialog
));
176 pdialog
->pcity
= pcity
;
177 pdialog
->store
= citizens_dialog_store_new();
179 = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(pdialog
->store
));
180 g_object_unref(pdialog
->store
);
182 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(pdialog
->sort
),
183 citizens_dialog_default_sort_column(),
184 GTK_SORT_DESCENDING
);
187 = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pdialog
->sort
));
188 gtk_widget_set_halign(pdialog
->list
, GTK_ALIGN_CENTER
);
189 g_object_unref(pdialog
->sort
);
191 for (i
= 0; i
< num_citizens_cols
; i
++) {
192 struct citizens_column
*pcol
;
193 GtkCellRenderer
*renderer
;
194 GtkTreeViewColumn
*col
;
196 pcol
= &citizens_cols
[i
];
199 switch (pcol
->type
) {
201 renderer
= gtk_cell_renderer_pixbuf_new();
202 col
= gtk_tree_view_column_new_with_attributes(_(pcol
->title
), renderer
,
206 renderer
= gtk_cell_renderer_text_new();
207 g_object_set(renderer
, "style-set", TRUE
, "weight-set", TRUE
, NULL
);
209 col
= gtk_tree_view_column_new_with_attributes(_(pcol
->title
), renderer
,
211 "style", CITIZENS_DLG_COL_STYLE
,
212 "weight", CITIZENS_DLG_COL_WEIGHT
,
214 gtk_tree_view_column_set_sort_column_id(col
, i
);
217 renderer
= gtk_cell_renderer_text_new();
218 g_object_set(renderer
, "style-set", TRUE
, "weight-set", TRUE
, NULL
);
220 col
= gtk_tree_view_column_new_with_attributes(_(pcol
->title
), renderer
,
222 "style", CITIZENS_DLG_COL_STYLE
,
223 "weight", CITIZENS_DLG_COL_WEIGHT
,
225 gtk_tree_view_column_set_sort_column_id(col
, i
);
226 g_object_set(renderer
, "xalign", 1.0, NULL
);
227 gtk_tree_view_column_set_alignment(col
, 1.0);
231 /* These are not used. */
232 fc_assert(pcol
->type
!= COL_COLOR
&& pcol
->type
!= COL_BOOLEAN
);
237 gtk_tree_view_append_column(GTK_TREE_VIEW(pdialog
->list
), col
);
241 gtk_widget_set_hexpand(GTK_WIDGET(pdialog
->list
), TRUE
);
242 gtk_widget_set_vexpand(GTK_WIDGET(pdialog
->list
), TRUE
);
244 sw
= gtk_scrolled_window_new(NULL
, NULL
);
245 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
246 GTK_POLICY_AUTOMATIC
,
247 GTK_POLICY_AUTOMATIC
);
248 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
),
250 gtk_container_add(GTK_CONTAINER(sw
), pdialog
->list
);
252 frame
= gtk_frame_new(_("Citizens"));
253 gtk_container_add(GTK_CONTAINER(frame
), sw
);
255 pdialog
->shell
= frame
;
257 dialog_list_prepend(dialog_list
, pdialog
);
259 citizens_dialog_refresh(pcity
);
264 /*****************************************************************************
265 Initialize citizens dialog
266 *****************************************************************************/
267 void citizens_dialog_init()
269 dialog_list
= dialog_list_new();
272 /*****************************************************************************
273 Free resources allocated for citizens dialog
274 *****************************************************************************/
275 void citizens_dialog_done()
277 dialog_list_destroy(dialog_list
);
280 /*****************************************************************************
281 Get citizen dialog of the given city
282 *****************************************************************************/
283 static struct citizens_dialog
*citizens_dialog_get(const struct city
*pcity
)
285 dialog_list_iterate(dialog_list
, pdialog
) {
286 if (pdialog
->pcity
== pcity
) {
289 } dialog_list_iterate_end
;
294 /*****************************************************************************
295 Refresh citizen dialog of the given city
296 *****************************************************************************/
297 void citizens_dialog_refresh(const struct city
*pcity
)
299 struct citizens_dialog
*pdialog
= citizens_dialog_get(pcity
);
301 if (pdialog
== NULL
) {
305 gtk_tree_store_clear(pdialog
->store
);
306 citizens_iterate(pcity
, pslot
, nationality
) {
309 gtk_tree_store_append(pdialog
->store
, &iter
, NULL
);
310 citizens_dialog_row(pdialog
->store
, &iter
, pcity
, pslot
);
311 } citizens_iterate_end
;
314 /*****************************************************************************
315 Fills the citizens list with the data for 'pslot' at the row given by 'it'.
316 *****************************************************************************/
317 static void citizens_dialog_row(GtkTreeStore
*store
, GtkTreeIter
*it
,
318 const struct city
*pcity
,
319 const struct player_slot
*pslot
)
322 int style
= PANGO_STYLE_NORMAL
, weight
= PANGO_WEIGHT_NORMAL
;
325 for (k
= 0; k
< num_citizens_cols
; k
++) {
326 struct citizens_column
*pcol
= &citizens_cols
[k
];
327 switch (pcol
->type
) {
330 gtk_tree_store_set(store
, it
, k
, pcol
->func(pcity
, pslot
), -1);
333 pixbuf
= get_flag(nation_of_player(player_slot_get_player(pslot
)));
334 if (pixbuf
!= NULL
) {
335 gtk_tree_store_set(store
, it
, k
, pixbuf
, -1);
336 g_object_unref(pixbuf
);
341 /* These are not used. */
342 fc_assert(pcol
->type
!= COL_COLOR
&& pcol
->type
!= COL_BOOLEAN
);
348 if (city_owner(pcity
)->slot
== pslot
) {
349 weight
= PANGO_WEIGHT_BOLD
;
350 style
= PANGO_STYLE_NORMAL
;
353 gtk_tree_store_set(store
, it
,
354 CITIZENS_DLG_COL_STYLE
, style
,
355 CITIZENS_DLG_COL_WEIGHT
, weight
,
356 CITIZENS_DLG_COL_ID
, player_slot_index(pslot
),
360 /*****************************************************************************
361 Close citizens dialog of one city
362 *****************************************************************************/
363 void citizens_dialog_close(const struct city
*pcity
)
365 struct citizens_dialog
*pdialog
= citizens_dialog_get(pcity
);
366 if (pdialog
== NULL
) {
370 gtk_widget_hide(pdialog
->shell
);
372 dialog_list_remove(dialog_list
, pdialog
);
374 gtk_widget_destroy(pdialog
->shell
);
378 /*****************************************************************************
379 Make citizen dialog of the city visible.
380 *****************************************************************************/
381 GtkWidget
*citizens_dialog_display(const struct city
*pcity
)
383 struct citizens_dialog
*pdialog
= citizens_dialog_get(pcity
);
386 pdialog
= citizens_dialog_create(pcity
);
389 gtk_widget_show(pdialog
->shell
);
390 citizens_dialog_refresh(pcity
);
392 return pdialog
->shell
;