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>
29 #include "government.h"
35 /* client/gui-gtk-2.0 */
38 #include "gui_stuff.h"
39 #include "happiness.h"
42 /* semi-arbitrary number that controls the width of the happiness widget */
43 #define HAPPINESS_PIX_WIDTH 30
45 #define PIXCOMM_WIDTH (HAPPINESS_PIX_WIDTH * tileset_small_sprite_width(tileset))
46 #define PIXCOMM_HEIGHT (tileset_small_sprite_height(tileset))
48 #define NUM_HAPPINESS_MODIFIERS 6
50 enum { CITIES
, LUXURIES
, BUILDINGS
, NATIONALITY
, UNITS
, WONDERS
};
52 struct happiness_dialog
{
55 GtkWidget
*cityname_label
;
56 GtkWidget
*hpixmaps
[NUM_HAPPINESS_MODIFIERS
];
57 GtkWidget
*happiness_ebox
[NUM_HAPPINESS_MODIFIERS
];
58 GtkWidget
*happiness_label
[NUM_HAPPINESS_MODIFIERS
];
62 #define SPECLIST_TAG dialog
63 #define SPECLIST_TYPE struct happiness_dialog
66 #define dialog_list_iterate(dialoglist, pdialog) \
67 TYPED_LIST_ITERATE(struct happiness_dialog, dialoglist, pdialog)
68 #define dialog_list_iterate_end LIST_ITERATE_END
70 static struct dialog_list
*dialog_list
;
71 static struct happiness_dialog
*get_happiness_dialog(struct city
*pcity
);
72 static struct happiness_dialog
*create_happiness_dialog(struct city
*pcity
);
73 static gboolean
show_happiness_popup(GtkWidget
*w
,
76 static gboolean
show_happiness_button_release(GtkWidget
*w
,
80 /****************************************************************
81 Create happiness dialog
82 *****************************************************************/
83 void happiness_dialog_init()
85 dialog_list
= dialog_list_new();
88 /****************************************************************
89 Remove happiness dialog
90 *****************************************************************/
91 void happiness_dialog_done()
93 dialog_list_destroy(dialog_list
);
96 /****************************************************************
97 Return happiness dialog for a city
98 *****************************************************************/
99 static struct happiness_dialog
*get_happiness_dialog(struct city
*pcity
)
101 dialog_list_iterate(dialog_list
, pdialog
) {
102 if (pdialog
->pcity
== pcity
) {
105 } dialog_list_iterate_end
;
110 /****************************************************************
111 Popup for the happiness display.
112 *****************************************************************/
113 static gboolean
show_happiness_popup(GtkWidget
*w
,
117 struct happiness_dialog
*pdialog
= g_object_get_data(G_OBJECT(w
),
120 if (ev
->button
== 1) {
121 GtkWidget
*p
, *label
, *frame
;
124 switch (GPOINTER_TO_UINT(data
)) {
126 sz_strlcpy(buf
, text_happiness_cities(pdialog
->pcity
));
129 sz_strlcpy(buf
, text_happiness_luxuries(pdialog
->pcity
));
132 sz_strlcpy(buf
, text_happiness_buildings(pdialog
->pcity
));
135 sz_strlcpy(buf
, text_happiness_nationality(pdialog
->pcity
));
138 sz_strlcpy(buf
, text_happiness_units(pdialog
->pcity
));
141 sz_strlcpy(buf
, text_happiness_wonders(pdialog
->pcity
));
147 p
= gtk_window_new(GTK_WINDOW_POPUP
);
148 gtk_widget_set_name(p
, "Freeciv");
149 gtk_container_set_border_width(GTK_CONTAINER(p
), 2);
150 gtk_window_set_position(GTK_WINDOW(p
), GTK_WIN_POS_MOUSE
);
152 frame
= gtk_frame_new(NULL
);
153 gtk_container_add(GTK_CONTAINER(p
), frame
);
155 label
= gtk_label_new(buf
);
156 gtk_widget_set_name(label
, "city_happiness_label");
157 gtk_misc_set_padding(GTK_MISC(label
), 4, 4);
158 gtk_container_add(GTK_CONTAINER(frame
), label
);
159 gtk_widget_show_all(p
);
161 gdk_pointer_grab(p
->window
, TRUE
, GDK_BUTTON_RELEASE_MASK
,
162 NULL
, NULL
, ev
->time
);
165 g_signal_connect_after(p
, "button_release_event",
166 G_CALLBACK(show_happiness_button_release
), NULL
);
172 /**************************************************************************
173 Clear the happiness popup.
174 **************************************************************************/
175 static gboolean
show_happiness_button_release(GtkWidget
*w
,
180 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
181 gtk_widget_destroy(w
);
185 /**************************************************************************
186 Create the happiness notebook page.
187 **************************************************************************/
188 static struct happiness_dialog
*create_happiness_dialog(struct city
*pcity
)
191 struct happiness_dialog
*pdialog
;
192 GtkWidget
*hbox
, *ebox
, *cbox
, *label
, *table
;
194 static const char *happiness_label_str
[NUM_HAPPINESS_MODIFIERS
] = {
202 static bool happiness_label_str_done
;
204 pdialog
= fc_malloc(sizeof(struct happiness_dialog
));
205 pdialog
->pcity
= pcity
;
207 pdialog
->shell
= gtk_vbox_new(FALSE
, 0);
209 pdialog
->cityname_label
= gtk_frame_new(_("Happiness"));
210 gtk_box_pack_start(GTK_BOX(pdialog
->shell
),
211 pdialog
->cityname_label
, TRUE
, TRUE
, 0);
213 hbox
= gtk_hbox_new(TRUE
, 0);
215 table
= gtk_table_new(NUM_HAPPINESS_MODIFIERS
+ 1, 2, FALSE
);
216 gtk_table_set_col_spacing(GTK_TABLE(table
), 0, 5);
217 gtk_box_pack_start(GTK_BOX(hbox
), table
, FALSE
, FALSE
, 4);
219 intl_slist(ARRAY_SIZE(happiness_label_str
), happiness_label_str
,
220 &happiness_label_str_done
);
222 gtk_container_add(GTK_CONTAINER(pdialog
->cityname_label
), hbox
);
224 for (i
= 0; i
< NUM_HAPPINESS_MODIFIERS
; i
++) {
225 /* set spacing between lines of citizens*/
226 gtk_table_set_row_spacing(GTK_TABLE(table
), i
, 10);
228 /* happiness labels */
229 label
= gtk_label_new(happiness_label_str
[i
]);
230 pdialog
->happiness_label
[i
] = label
;
231 gtk_widget_set_name(label
, "city_label");
232 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
234 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, i
, i
+ 1,
235 GTK_FILL
, GTK_EXPAND
| GTK_SHRINK
, 0, 0);
237 /* list of citizens */
238 ebox
= gtk_event_box_new();
239 g_object_set_data(G_OBJECT(ebox
), "pdialog", pdialog
);
240 g_signal_connect(ebox
, "button_press_event",
241 G_CALLBACK(show_happiness_popup
), GUINT_TO_POINTER(i
));
242 pdialog
->happiness_ebox
[i
] = ebox
;
244 cbox
= gtk_vbox_new(FALSE
, 2);
245 pdialog
->hpixmaps
[i
] = gtk_pixcomm_new(PIXCOMM_WIDTH
, PIXCOMM_HEIGHT
);
246 gtk_box_pack_start(GTK_BOX(cbox
), pdialog
->hpixmaps
[i
], FALSE
, FALSE
, 0);
247 gtk_misc_set_alignment(GTK_MISC(pdialog
->hpixmaps
[i
]), 0, 0);
249 gtk_container_add(GTK_CONTAINER(ebox
), cbox
);
251 gtk_table_attach(GTK_TABLE(table
), ebox
, 1, 2, i
, i
+ 1,
252 GTK_FILL
, GTK_EXPAND
| GTK_SHRINK
, 0, 0);
255 /* TRANS: the width of this text defines the width of the city dialog. */
256 label
= gtk_label_new(_("Additional information is available via left "
257 "click on the citizens."));
258 gtk_widget_set_name(label
, "city_label");
259 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
260 gtk_table_attach(GTK_TABLE(table
), label
, 0, 2, NUM_HAPPINESS_MODIFIERS
,
261 NUM_HAPPINESS_MODIFIERS
+ 1, GTK_FILL
, 0, 0, 0);
263 gtk_widget_show_all(pdialog
->shell
);
264 dialog_list_prepend(dialog_list
, pdialog
);
265 refresh_happiness_dialog(pcity
);
270 /**************************************************************************
271 Refresh citizens pixcomm
272 **************************************************************************/
273 static void refresh_pixcomm(GtkPixcomm
*dst
, struct city
*pcity
,
274 enum citizen_feeling index
)
276 enum citizen_category categories
[MAX_CITY_SIZE
];
278 int num_citizens
= get_city_citizen_types(pcity
, index
, categories
);
279 int offset
= MIN(tileset_small_sprite_width(tileset
), PIXCOMM_WIDTH
/ num_citizens
);
281 gtk_pixcomm_freeze(dst
);
282 gtk_pixcomm_clear(dst
);
284 for (i
= 0; i
< num_citizens
; i
++) {
285 gtk_pixcomm_copyto(dst
, get_citizen_sprite(tileset
, categories
[i
], i
, pcity
),
289 gtk_pixcomm_thaw(dst
);
292 /**************************************************************************
293 Refresh whole happiness dialog
294 **************************************************************************/
295 void refresh_happiness_dialog(struct city
*pcity
)
298 struct happiness_dialog
*pdialog
= get_happiness_dialog(pcity
);
300 for (i
= 0; i
< FEELING_LAST
; i
++) {
301 refresh_pixcomm(GTK_PIXCOMM(pdialog
->hpixmaps
[i
]), pdialog
->pcity
, i
);
305 /**************************************************************************
306 Close happiness dialog of given city
307 **************************************************************************/
308 void close_happiness_dialog(struct city
*pcity
)
310 struct happiness_dialog
*pdialog
= get_happiness_dialog(pcity
);
311 if (pdialog
== NULL
) {
312 /* City which is being investigated doesn't contain happiness tab */
316 gtk_widget_hide(pdialog
->shell
);
318 dialog_list_remove(dialog_list
, pdialog
);
320 gtk_widget_destroy(pdialog
->shell
);
324 /**************************************************************************
325 Create happiness dialog and get its widget
326 **************************************************************************/
327 GtkWidget
*get_top_happiness_display(struct city
*pcity
)
329 return create_happiness_dialog(pcity
)->shell
;