Freeciv-3.1
Loading...
Searching...
No Matches
happiness.c
Go to the documentation of this file.
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.
7
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***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <gtk/gtk.h>
19
20/* utility */
21#include "fcintl.h"
22#include "log.h"
23#include "mem.h"
24#include "support.h"
25
26/* common */
27#include "city.h"
28#include "game.h"
29#include "government.h"
30
31/* client */
32#include "text.h"
33#include "tilespec.h"
34
35/* client/gui-gtk-3.0 */
36#include "graphics.h"
37#include "gui_main.h"
38#include "gui_stuff.h"
39#include "happiness.h"
40#include "mapview.h"
41
42/* semi-arbitrary number that controls the width of the happiness widget */
43#define HAPPINESS_PIX_WIDTH 30
44
45#define FEELING_WIDTH (HAPPINESS_PIX_WIDTH * tileset_small_sprite_width(tileset))
46#define FEELING_HEIGHT (tileset_small_sprite_height(tileset))
47
48#define NUM_HAPPINESS_MODIFIERS 6
49
51
53 struct city *pcity;
54 GtkWidget *win;
55 GtkWidget *shell;
56 GtkWidget *cityname_label;
60 GtkWidget *close;
61};
62
63#define SPECLIST_TAG dialog
64#define SPECLIST_TYPE struct happiness_dialog
65#include "speclist.h"
66
67#define dialog_list_iterate(dialoglist, pdialog) \
68 TYPED_LIST_ITERATE(struct happiness_dialog, dialoglist, pdialog)
69#define dialog_list_iterate_end LIST_ITERATE_END
70
71static struct dialog_list *dialog_list;
72static struct happiness_dialog *get_happiness_dialog(struct city *pcity);
74 bool low_dlg,
75 GtkWidget *win);
76static gboolean show_happiness_popup(GtkWidget *w,
77 GdkEventButton *ev,
78 gpointer data);
79static gboolean show_happiness_button_release(GtkWidget *w,
80 GdkEventButton *ev,
81 gpointer data);
82
83/**********************************************************************/
87{
88 dialog_list = dialog_list_new();
89}
90
91/**********************************************************************/
95{
96 dialog_list_destroy(dialog_list);
97}
98
99/**********************************************************************/
103{
105 if (pdialog->pcity == pcity) {
106 return pdialog;
107 }
109
110 return NULL;
111}
112
113/**********************************************************************/
116static gboolean show_happiness_popup(GtkWidget *w,
117 GdkEventButton *ev,
118 gpointer data)
119{
120 struct happiness_dialog *pdialog = g_object_get_data(G_OBJECT(w),
121 "pdialog");
122
123 if (ev->button == 1) {
124 GtkWidget *p, *label, *frame;
125 char buf[1024];
126
127 switch (GPOINTER_TO_UINT(data)) {
128 case CITIES:
129 sz_strlcpy(buf, text_happiness_cities(pdialog->pcity));
130 break;
131 case LUXURIES:
133 break;
134 case BUILDINGS:
136 break;
137 case NATIONALITY:
139 break;
140 case UNITS:
141 sz_strlcpy(buf, text_happiness_units(pdialog->pcity));
142 break;
143 case WONDERS:
145 break;
146 default:
147 return TRUE;
148 }
149
150 p = gtk_window_new(GTK_WINDOW_POPUP);
151 gtk_widget_set_name(p, "Freeciv");
152 gtk_container_set_border_width(GTK_CONTAINER(p), 2);
153 gtk_window_set_transient_for(GTK_WINDOW(p), GTK_WINDOW(pdialog->win));
154 gtk_window_set_position(GTK_WINDOW(p), GTK_WIN_POS_MOUSE);
155
156 frame = gtk_frame_new(NULL);
157 gtk_container_add(GTK_CONTAINER(p), frame);
158
159 label = gtk_label_new(buf);
160 /* FIXME: there is no font option corresponding to this style name.
161 * Remove?: */
162 gtk_widget_set_name(label, "city_happiness_label");
163 gtk_widget_set_margin_left(label, 4);
164 gtk_widget_set_margin_right(label, 4);
165 gtk_widget_set_margin_top(label, 4);
166 gtk_widget_set_margin_bottom(label, 4);
167 gtk_container_add(GTK_CONTAINER(frame), label);
168 gtk_widget_show_all(p);
169
170 gdk_device_grab(ev->device, gtk_widget_get_window(p),
171 GDK_OWNERSHIP_NONE, TRUE, GDK_BUTTON_RELEASE_MASK, NULL,
172 ev->time);
173 gtk_grab_add(p);
174
175 g_signal_connect_after(p, "button_release_event",
176 G_CALLBACK(show_happiness_button_release), NULL);
177 }
178
179 return TRUE;
180}
181
182/**********************************************************************/
185static gboolean show_happiness_button_release(GtkWidget *w,
186 GdkEventButton *ev,
187 gpointer data)
188{
189 gtk_grab_remove(w);
190 gdk_device_ungrab(ev->device, ev->time);
191 gtk_widget_destroy(w);
192 return FALSE;
193}
194
195/**********************************************************************/
199 bool low_dlg,
200 GtkWidget *win)
201{
202 int i;
203 struct happiness_dialog *pdialog;
204 GtkWidget *ebox, *label, *table;
205 char buf[700];
206
207 static const char *happiness_label_str[NUM_HAPPINESS_MODIFIERS] = {
208 N_("Cities:"),
209 N_("Luxuries:"),
210 N_("Buildings:"),
211 N_("Nationality:"),
212 N_("Units:"),
213 N_("Wonders:"),
214 };
215 static bool happiness_label_str_done;
216
217 pdialog = fc_malloc(sizeof(struct happiness_dialog));
218 pdialog->pcity = pcity;
219
220 pdialog->shell = gtk_grid_new();
221 gtk_orientable_set_orientation(GTK_ORIENTABLE(pdialog->shell),
222 GTK_ORIENTATION_VERTICAL);
223
224 pdialog->cityname_label = gtk_frame_new(_("Happiness"));
225 gtk_container_add(GTK_CONTAINER(pdialog->shell), pdialog->cityname_label);
226
227 table = gtk_grid_new();
228 g_object_set(table, "margin", 4, NULL);
229 gtk_grid_set_row_spacing(GTK_GRID(table), 10);
230
231 intl_slist(ARRAY_SIZE(happiness_label_str), happiness_label_str,
232 &happiness_label_str_done);
233
234 gtk_container_add(GTK_CONTAINER(pdialog->cityname_label), table);
235
236 for (i = 0; i < NUM_HAPPINESS_MODIFIERS; i++) {
237 GtkWidget *img;
238
239 /* set spacing between lines of citizens*/
240
241 /* happiness labels */
242 label = gtk_label_new(happiness_label_str[i]);
243 pdialog->happiness_label[i] = label;
244 gtk_widget_set_name(label, "city_label");
245 gtk_widget_set_halign(label, GTK_ALIGN_START);
246 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
247
248 gtk_grid_attach(GTK_GRID(table), label, 0, i, 1, 1);
249
250 /* list of citizens */
251 ebox = gtk_event_box_new();
252 gtk_widget_set_margin_left(ebox, 5);
253 gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
254 g_object_set_data(G_OBJECT(ebox), "pdialog", pdialog);
255 g_signal_connect(ebox, "button_press_event",
256 G_CALLBACK(show_happiness_popup), GUINT_TO_POINTER(i));
257 pdialog->happiness_ebox[i] = ebox;
258
259 pdialog->feeling_surfaces[i] = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
261 img = gtk_image_new_from_surface(pdialog->feeling_surfaces[i]);
262 gtk_container_add(GTK_CONTAINER(ebox), img);
263 gtk_widget_set_halign(img, GTK_ALIGN_START);
264 gtk_widget_set_valign(img, GTK_ALIGN_START);
265
266 gtk_grid_attach(GTK_GRID(table), ebox, 1, i, 1, 1);
267 }
268
269 /* TRANS: the width of this text defines the width of the city dialog.
270 * '%s' is either space or newline depending on screen real estate. */
271 fc_snprintf(buf, sizeof(buf),
272 _("Additional information is available%svia left "
273 "click on the citizens."), low_dlg ? "\n" : " ");
274 label = gtk_label_new(buf);
275 gtk_widget_set_name(label, "city_label");
276 gtk_widget_set_halign(label, GTK_ALIGN_START);
277 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
278 gtk_grid_attach(GTK_GRID(table), label, 0, NUM_HAPPINESS_MODIFIERS, 2, 1);
279
280 gtk_widget_show_all(pdialog->shell);
281 dialog_list_prepend(dialog_list, pdialog);
283
284 pdialog->win = win;
285
286 return pdialog;
287}
288
289/**********************************************************************/
292static void refresh_feeling_surface(cairo_surface_t *dst, struct city *pcity,
293 enum citizen_feeling index)
294{
295 enum citizen_category categories[MAX_CITY_SIZE];
296 int i;
297 int num_citizens = get_city_citizen_types(pcity, index, categories);
298 int offset = MIN(tileset_small_sprite_width(tileset), FEELING_WIDTH / num_citizens);
299 cairo_t *cr;
300
301 cr = cairo_create(dst);
302
303 for (i = 0; i < num_citizens; i++) {
304 cairo_set_source_surface(cr,
305 get_citizen_sprite(tileset, categories[i], i, pcity)->surface,
306 i * offset, 0);
307 cairo_rectangle(cr, i * offset, 0, offset, FEELING_HEIGHT);
308 cairo_fill(cr);
309 }
310
311 cairo_destroy(cr);
312}
313
314/**********************************************************************/
318{
319 int i;
321
322 for (i = 0; i < FEELING_LAST; i++) {
323 refresh_feeling_surface(pdialog->feeling_surfaces[i], pdialog->pcity, i);
324 }
325}
326
327/**********************************************************************/
331{
333 int i;
334
335 if (pdialog == NULL) {
336 /* City which is being investigated doesn't contain happiness tab */
337 return;
338 }
339
340 gtk_widget_hide(pdialog->shell);
341
342 dialog_list_remove(dialog_list, pdialog);
343
344 gtk_widget_destroy(pdialog->shell);
345
346 for (i = 0; i < NUM_HAPPINESS_MODIFIERS; i++) {
347 cairo_surface_destroy(pdialog->feeling_surfaces[i]);
348 }
349
350 free(pdialog);
351}
352
353/**********************************************************************/
356GtkWidget *get_top_happiness_display(struct city *pcity, bool low_dlg,
357 GtkWidget *win)
358{
359 return create_happiness_dialog(pcity, low_dlg, win)->shell;
360}
citizen_category
Definition city.h:259
#define MAX_CITY_SIZE
Definition city.h:98
citizen_feeling
Definition city.h:270
@ FEELING_LAST
Definition city.h:277
int get_city_citizen_types(struct city *pcity, enum citizen_feeling idx, enum citizen_category *categories)
#define _(String)
Definition fcintl.h:67
#define N_(String)
Definition fcintl.h:69
void intl_slist(int n, const char **s, bool *done)
Definition gui_stuff.c:105
void happiness_dialog_init(void)
Definition happiness.c:86
#define FEELING_WIDTH
Definition happiness.c:45
void close_happiness_dialog(struct city *pcity)
Definition happiness.c:330
static struct happiness_dialog * get_happiness_dialog(struct city *pcity)
Definition happiness.c:102
void happiness_dialog_done(void)
Definition happiness.c:94
#define FEELING_HEIGHT
Definition happiness.c:46
static struct happiness_dialog * create_happiness_dialog(struct city *pcity, bool low_dlg, GtkWidget *win)
Definition happiness.c:198
#define dialog_list_iterate_end
Definition happiness.c:69
static gboolean show_happiness_popup(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition happiness.c:116
void refresh_happiness_dialog(struct city *pcity)
Definition happiness.c:317
static gboolean show_happiness_button_release(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition happiness.c:185
#define dialog_list_iterate(dialoglist, pdialog)
Definition happiness.c:67
static struct dialog_list * dialog_list
Definition happiness.c:71
@ NATIONALITY
Definition happiness.c:50
@ UNITS
Definition happiness.c:50
@ BUILDINGS
Definition happiness.c:50
@ WONDERS
Definition happiness.c:50
@ CITIES
Definition happiness.c:50
@ LUXURIES
Definition happiness.c:50
GtkWidget * get_top_happiness_display(struct city *pcity, bool low_dlg, GtkWidget *win)
Definition happiness.c:356
static void refresh_feeling_surface(cairo_surface_t *dst, struct city *pcity, enum citizen_feeling index)
Definition happiness.c:292
#define NUM_HAPPINESS_MODIFIERS
Definition happiness.c:48
#define NUM_HAPPINESS_MODIFIERS
Definition happiness.c:48
#define fc_malloc(sz)
Definition mem.h:34
const char * text_happiness_cities(const struct city *pcity)
Definition text.c:1931
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MIN(x, y)
Definition shared.h:55
Definition city.h:309
GtkWidget * happiness_ebox[NUM_HAPPINESS_MODIFIERS]
Definition happiness.c:58
GtkWidget * win
Definition happiness.c:54
GtkWidget * cityname_label
Definition happiness.c:56
struct city * pcity
Definition happiness.c:53
GtkWidget * happiness_label[NUM_HAPPINESS_MODIFIERS]
Definition happiness.c:59
GtkWidget * shell
Definition happiness.c:55
cairo_surface_t * feeling_surfaces[NUM_HAPPINESS_MODIFIERS]
Definition happiness.c:57
GtkWidget * close
Definition happiness.c:60
Definition mapimg.c:367
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
#define sz_strlcpy(dest, src)
Definition support.h:167
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
const char * text_happiness_nationality(const struct city *pcity)
Definition text.c:1859
const char * text_happiness_wonders(const struct city *pcity)
Definition text.c:1901
const char * text_happiness_units(const struct city *pcity)
Definition text.c:2065
const char * text_happiness_luxuries(const struct city *pcity)
Definition text.c:2103
const char * text_happiness_buildings(const struct city *pcity)
Definition text.c:1831
int tileset_small_sprite_width(const struct tileset *t)
Definition tilespec.c:864
struct sprite * get_citizen_sprite(const struct tileset *t, enum citizen_category type, int citizen_index, const struct city *pcity)
Definition tilespec.c:6437