Do not return NULL as boolean from wonder_is_lost() nor wonder_is_built()
[freeciv.git] / client / gui-gtk-2.0 / happiness.c
blob0d4b31a0938cf525f7799ac6db0139dec994c0f0
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)
6 any later version.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <gtk/gtk.h>
20 /* utility */
21 #include "fcintl.h"
22 #include "log.h"
23 #include "mem.h"
24 #include "support.h"
26 /* common */
27 #include "city.h"
28 #include "game.h"
29 #include "government.h"
31 /* client */
32 #include "text.h"
33 #include "tilespec.h"
35 /* client/gui-gtk-2.0 */
36 #include "graphics.h"
37 #include "gui_main.h"
38 #include "gui_stuff.h"
39 #include "happiness.h"
40 #include "mapview.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 {
53 struct city *pcity;
54 GtkWidget *shell;
55 GtkWidget *cityname_label;
56 GtkWidget *hpixmaps[NUM_HAPPINESS_MODIFIERS];
57 GtkWidget *happiness_ebox[NUM_HAPPINESS_MODIFIERS];
58 GtkWidget *happiness_label[NUM_HAPPINESS_MODIFIERS];
59 GtkWidget *close;
62 #define SPECLIST_TAG dialog
63 #define SPECLIST_TYPE struct happiness_dialog
64 #include "speclist.h"
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,
74 GdkEventButton *ev,
75 gpointer data);
76 static gboolean show_happiness_button_release(GtkWidget *w,
77 GdkEventButton *ev,
78 gpointer data);
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) {
103 return pdialog;
105 } dialog_list_iterate_end;
107 return NULL;
110 /****************************************************************
111 Popup for the happiness display.
112 *****************************************************************/
113 static gboolean show_happiness_popup(GtkWidget *w,
114 GdkEventButton *ev,
115 gpointer data)
117 struct happiness_dialog *pdialog = g_object_get_data(G_OBJECT(w),
118 "pdialog");
120 if (ev->button == 1) {
121 GtkWidget *p, *label, *frame;
122 char buf[1024];
124 switch (GPOINTER_TO_UINT(data)) {
125 case CITIES:
126 sz_strlcpy(buf, text_happiness_cities(pdialog->pcity));
127 break;
128 case LUXURIES:
129 sz_strlcpy(buf, text_happiness_luxuries(pdialog->pcity));
130 break;
131 case BUILDINGS:
132 sz_strlcpy(buf, text_happiness_buildings(pdialog->pcity));
133 break;
134 case NATIONALITY:
135 sz_strlcpy(buf, text_happiness_nationality(pdialog->pcity));
136 break;
137 case UNITS:
138 sz_strlcpy(buf, text_happiness_units(pdialog->pcity));
139 break;
140 case WONDERS:
141 sz_strlcpy(buf, text_happiness_wonders(pdialog->pcity));
142 break;
143 default:
144 return TRUE;
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);
163 gtk_grab_add(p);
165 g_signal_connect_after(p, "button_release_event",
166 G_CALLBACK(show_happiness_button_release), NULL);
169 return TRUE;
172 /**************************************************************************
173 Clear the happiness popup.
174 **************************************************************************/
175 static gboolean show_happiness_button_release(GtkWidget *w,
176 GdkEventButton *ev,
177 gpointer data)
179 gtk_grab_remove(w);
180 gdk_pointer_ungrab(GDK_CURRENT_TIME);
181 gtk_widget_destroy(w);
182 return FALSE;
185 /**************************************************************************
186 Create the happiness notebook page.
187 **************************************************************************/
188 static struct happiness_dialog *create_happiness_dialog(struct city *pcity)
190 int i;
191 struct happiness_dialog *pdialog;
192 GtkWidget *hbox, *ebox, *cbox, *label, *table;
194 static const char *happiness_label_str[NUM_HAPPINESS_MODIFIERS] = {
195 N_("Cities:"),
196 N_("Luxuries:"),
197 N_("Buildings:"),
198 N_("Nationality:"),
199 N_("Units:"),
200 N_("Wonders:"),
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);
267 return pdialog;
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];
277 int i;
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),
286 i * offset, 0);
289 gtk_pixcomm_thaw(dst);
292 /**************************************************************************
293 Refresh whole happiness dialog
294 **************************************************************************/
295 void refresh_happiness_dialog(struct city *pcity)
297 int i;
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 */
313 return;
316 gtk_widget_hide(pdialog->shell);
318 dialog_list_remove(dialog_list, pdialog);
320 gtk_widget_destroy(pdialog->shell);
321 free(pdialog);
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;