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 <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <gtk/gtk.h>
23 #include <gdk/gdkkeysyms.h>
24
25 /* utility */
26 #include "log.h"
27 #include "shared.h"
28 #include "string_vector.h"
29 #include "support.h"
30
31 /* common */
32 #include "events.h"
33 #include "fcintl.h"
34 #include "government.h"
35 #include "multipliers.h"
36 #include "packets.h"
37 #include "player.h"
38
39 /* client */
40 #include "client_main.h"
41 #include "options.h"
42
43 /* client/gui-gtk-2.0 */
44 #include "chatline.h"
45 #include "cityrep.h"
46 #include "dialogs.h"
47 #include "gui_main.h"
48 #include "gui_stuff.h"
49 #include "ratesdlg.h"
50
51 #include "gamedlgs.h"
52
53 /******************************************************************/
54 static GtkWidget *rates_dialog_shell;
55 static GtkWidget *rates_gov_label;
56 static GtkWidget *rates_tax_toggle, *rates_lux_toggle, *rates_sci_toggle;
57 static GtkWidget *rates_tax_label, *rates_lux_label, *rates_sci_label;
58 static GtkObject *rates_tax_adj, *rates_lux_adj, *rates_sci_adj;
59
60 static GtkWidget *multiplier_dialog_shell;
61 static GtkWidget *multipliers_scale[MAX_NUM_MULTIPLIERS];
62
63 static gulong rates_tax_sig, rates_lux_sig, rates_sci_sig;
64 /******************************************************************/
65
66 static int rates_tax_value, rates_lux_value, rates_sci_value;
67
68 static void rates_changed_callback(GtkAdjustment *adj);
69
70 /**************************************************************************
71 Set tax values to display
72 **************************************************************************/
rates_set_values(int tax,int no_tax_scroll,int lux,int no_lux_scroll,int sci,int no_sci_scroll)73 static void rates_set_values(int tax, int no_tax_scroll,
74 int lux, int no_lux_scroll,
75 int sci, int no_sci_scroll)
76 {
77 char buf[64];
78 int tax_lock, lux_lock, sci_lock;
79 int maxrate;
80
81 tax_lock = GTK_TOGGLE_BUTTON(rates_tax_toggle)->active;
82 lux_lock = GTK_TOGGLE_BUTTON(rates_lux_toggle)->active;
83 sci_lock = GTK_TOGGLE_BUTTON(rates_sci_toggle)->active;
84
85 if (NULL != client.conn.playing) {
86 maxrate = get_player_bonus(client.conn.playing, EFT_MAX_RATES);
87 } else {
88 maxrate = 100;
89 }
90 /* This's quite a simple-minded "double check".. */
91 tax=MIN(tax, maxrate);
92 lux=MIN(lux, maxrate);
93 sci=MIN(sci, maxrate);
94
95 if(tax+sci+lux!=100)
96 {
97 if((tax!=rates_tax_value))
98 {
99 if(!lux_lock)
100 lux=MIN(MAX(100-tax-sci, 0), maxrate);
101 if(!sci_lock)
102 sci=MIN(MAX(100-tax-lux, 0), maxrate);
103 }
104 else if((lux!=rates_lux_value))
105 {
106 if(!tax_lock)
107 tax=MIN(MAX(100-lux-sci, 0), maxrate);
108 if(!sci_lock)
109 sci=MIN(MAX(100-lux-tax, 0), maxrate);
110 }
111 else if((sci!=rates_sci_value))
112 {
113 if(!lux_lock)
114 lux=MIN(MAX(100-tax-sci, 0), maxrate);
115 if(!tax_lock)
116 tax=MIN(MAX(100-lux-sci, 0), maxrate);
117 }
118
119 if(tax+sci+lux!=100) {
120 tax=rates_tax_value;
121 lux=rates_lux_value;
122 sci=rates_sci_value;
123
124 rates_tax_value=-1;
125 rates_lux_value=-1;
126 rates_sci_value=-1;
127
128 no_tax_scroll=0;
129 no_lux_scroll=0;
130 no_sci_scroll=0;
131 }
132
133 }
134
135 if (tax!=rates_tax_value) {
136 fc_snprintf(buf, sizeof(buf), "%3d%%", tax);
137 if (strcmp(buf, GTK_LABEL(rates_tax_label)->label) != 0)
138 gtk_label_set_text(GTK_LABEL(rates_tax_label), buf);
139 if(!no_tax_scroll)
140 {
141 g_signal_handler_block(rates_tax_adj, rates_tax_sig);
142 gtk_adjustment_set_value(GTK_ADJUSTMENT(rates_tax_adj), tax/10 );
143 g_signal_handler_unblock(rates_tax_adj, rates_tax_sig);
144 }
145 rates_tax_value=tax;
146 }
147
148 if(lux!=rates_lux_value) {
149 fc_snprintf(buf, sizeof(buf), "%3d%%", lux);
150 if (strcmp(buf, GTK_LABEL(rates_lux_label)->label) != 0)
151 gtk_label_set_text(GTK_LABEL(rates_lux_label), buf);
152 if(!no_lux_scroll)
153 {
154 g_signal_handler_block(rates_lux_adj, rates_lux_sig);
155 gtk_adjustment_set_value(GTK_ADJUSTMENT(rates_lux_adj), lux/10 );
156 g_signal_handler_unblock(rates_lux_adj, rates_lux_sig);
157 }
158 rates_lux_value=lux;
159 }
160
161 if(sci!=rates_sci_value) {
162 fc_snprintf(buf, sizeof(buf), "%3d%%", sci);
163 if (strcmp(buf, GTK_LABEL(rates_sci_label)->label) != 0)
164 gtk_label_set_text(GTK_LABEL(rates_sci_label),buf);
165 if(!no_sci_scroll)
166 {
167 g_signal_handler_block(rates_sci_adj, rates_sci_sig);
168 gtk_adjustment_set_value(GTK_ADJUSTMENT(rates_sci_adj), sci/10 );
169 g_signal_handler_unblock(rates_sci_adj, rates_sci_sig);
170 }
171 rates_sci_value=sci;
172 }
173 }
174
175
176 /**************************************************************************
177 User changes rates
178 **************************************************************************/
rates_changed_callback(GtkAdjustment * adj)179 static void rates_changed_callback(GtkAdjustment *adj)
180 {
181 int percent=adj->value;
182
183 if(adj==GTK_ADJUSTMENT(rates_tax_adj)) {
184 int tax_value;
185
186 tax_value=10*percent;
187 tax_value=MIN(tax_value, 100);
188 rates_set_values(tax_value,1, rates_lux_value,0, rates_sci_value,0);
189 }
190 else if(adj==GTK_ADJUSTMENT(rates_lux_adj)) {
191 int lux_value;
192
193 lux_value=10*percent;
194 lux_value=MIN(lux_value, 100);
195 rates_set_values(rates_tax_value,0, lux_value,1, rates_sci_value,0);
196 }
197 else {
198 int sci_value;
199
200 sci_value=10*percent;
201 sci_value=MIN(sci_value, 100);
202 rates_set_values(rates_tax_value,0, rates_lux_value,0, sci_value,1);
203 }
204 }
205
206
207 /**************************************************************************
208 User has responded to rates dialog
209 **************************************************************************/
rates_command_callback(GtkWidget * w,gint response_id)210 static void rates_command_callback(GtkWidget *w, gint response_id)
211 {
212 if (response_id == GTK_RESPONSE_OK) {
213 dsend_packet_player_rates(&client.conn, rates_tax_value, rates_lux_value,
214 rates_sci_value);
215 }
216 gtk_widget_destroy(rates_dialog_shell);
217 }
218
219 /**************************************************************************
220 Convert real multiplier display value to scale value
221 **************************************************************************/
mult_to_scale(const struct multiplier * pmul,int val)222 static int mult_to_scale(const struct multiplier *pmul, int val)
223 {
224 return (val - pmul->start) / pmul->step;
225 }
226
227 /**************************************************************************
228 Convert scale units to real multiplier display value
229 **************************************************************************/
scale_to_mult(const struct multiplier * pmul,int scale)230 static int scale_to_mult(const struct multiplier *pmul, int scale)
231 {
232 return scale * pmul->step + pmul->start;
233 }
234
235 /**************************************************************************
236 Format value for multiplier scales
237 **************************************************************************/
multiplier_value_callback(GtkScale * scale,gdouble value,void * udata)238 static gchar *multiplier_value_callback(GtkScale *scale, gdouble value,
239 void *udata)
240 {
241 const struct multiplier *pmul = udata;
242
243 return g_strdup_printf("%d", scale_to_mult(pmul, value));
244 }
245
246 /**************************************************************************
247 User has responded to multipliers dialog
248 **************************************************************************/
multipliers_command_callback(GtkWidget * w,gint response_id)249 static void multipliers_command_callback(GtkWidget *w, gint response_id)
250 {
251 struct packet_player_multiplier mul;
252
253 if (response_id == GTK_RESPONSE_OK && can_client_issue_orders()) {
254 multipliers_iterate(m) {
255 Multiplier_type_id i = multiplier_index(m);
256 int value = gtk_range_get_value(GTK_RANGE(multipliers_scale[i]));
257
258 mul.multipliers[i] = scale_to_mult(m, value);
259 } multipliers_iterate_end;
260 mul.count = multiplier_count();
261 send_packet_player_multiplier(&client.conn, &mul);
262 }
263 gtk_widget_destroy(multiplier_dialog_shell);
264 }
265
266 /**************************************************************************
267 Update values in multipliers dialog
268 **************************************************************************/
multiplier_dialog_update_values(bool set_positions)269 static void multiplier_dialog_update_values(bool set_positions)
270 {
271 multipliers_iterate(pmul) {
272 Multiplier_type_id multiplier = multiplier_index(pmul);
273 int val = player_multiplier_value(client_player(), pmul);
274 int target = player_multiplier_target_value(client_player(), pmul);
275
276 fc_assert(multiplier < ARRAY_SIZE(multipliers_scale));
277 fc_assert(scale_to_mult(pmul, mult_to_scale(pmul, val)) == val);
278 fc_assert(scale_to_mult(pmul, mult_to_scale(pmul, target)) == target);
279
280 /* XXX: if building against ancient Gtk, manage without this bit of UI. */
281 #if GTK_CHECK_VERSION(2,16,0)
282 gtk_scale_clear_marks(GTK_SCALE(multipliers_scale[multiplier]));
283 gtk_scale_add_mark(GTK_SCALE(multipliers_scale[multiplier]),
284 mult_to_scale(pmul, val), GTK_POS_BOTTOM,
285 /* TRANS: current value of policy in force */
286 Q_("?multiplier:Now"));
287 #endif /* GTK >= 2.16 */
288
289 if (set_positions) {
290 gtk_range_set_value(GTK_RANGE(multipliers_scale[multiplier]),
291 mult_to_scale(pmul, target));
292 }
293 } multipliers_iterate_end;
294 }
295
296 /**************************************************************************
297 Callback when server indicates multiplier values have changed
298 **************************************************************************/
real_multipliers_dialog_update(void * unused)299 void real_multipliers_dialog_update(void *unused)
300 {
301 if (!multiplier_dialog_shell) {
302 return;
303 }
304
305 /* If dialog belongs to a player rather than an observer, we don't
306 * want to lose any local changes made by the player.
307 * This dialog should be the only way the values can change, anyway. */
308 multiplier_dialog_update_values(!can_client_issue_orders());
309 }
310
311 /****************************************************************
312 Create multipliers dialog
313 ****************************************************************/
create_multiplier_dialog(void)314 static GtkWidget *create_multiplier_dialog(void)
315 {
316 GtkWidget *shell, *content;
317 GtkWidget *label, *scale;
318
319 if (can_client_issue_orders()) {
320 shell = gtk_dialog_new_with_buttons(_("Change policies"),
321 NULL,
322 0,
323 GTK_STOCK_CANCEL,
324 GTK_RESPONSE_CANCEL,
325 GTK_STOCK_OK,
326 GTK_RESPONSE_OK,
327 NULL);
328 } else {
329 shell = gtk_dialog_new_with_buttons(_("Policies"),
330 NULL,
331 0,
332 GTK_STOCK_CLOSE,
333 GTK_RESPONSE_CLOSE,
334 NULL);
335 }
336 setup_dialog(shell, toplevel);
337
338 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_MOUSE);
339 content = gtk_dialog_get_content_area(GTK_DIALOG(shell));
340
341 if (can_client_issue_orders()) {
342 label = gtk_label_new(_("Changes will not take effect until next turn."));
343 gtk_box_pack_start( GTK_BOX( content ), label, FALSE, FALSE, 0);
344 }
345
346 multipliers_iterate(pmul) {
347 Multiplier_type_id multiplier = multiplier_index(pmul);
348
349 fc_assert(multiplier < ARRAY_SIZE(multipliers_scale));
350 label = gtk_label_new(multiplier_name_translation(pmul));
351 /* Map each multiplier step to a single step on the UI, to enforce
352 * the step size. */
353 scale = gtk_hscale_new_with_range(mult_to_scale(pmul, pmul->start),
354 mult_to_scale(pmul, pmul->stop), 1);
355 multipliers_scale[multiplier] = scale;
356 gtk_range_set_increments(GTK_RANGE(multipliers_scale[multiplier]),
357 1, MAX(2, mult_to_scale(pmul, pmul->stop) / 10));
358 g_signal_connect(multipliers_scale[multiplier], "format-value",
359 G_CALLBACK(multiplier_value_callback), pmul);
360 g_signal_connect(multipliers_scale[multiplier], "destroy",
361 G_CALLBACK(gtk_widget_destroyed),
362 &multipliers_scale[multiplier]);
363 gtk_box_pack_start( GTK_BOX( content ), label, TRUE, TRUE, 5 );
364 gtk_box_pack_start( GTK_BOX( content ), scale, TRUE, TRUE, 5 );
365 gtk_widget_set_sensitive(multipliers_scale[multiplier],
366 can_client_issue_orders());
367 } multipliers_iterate_end;
368
369 multiplier_dialog_update_values(TRUE);
370
371 g_signal_connect(shell, "destroy",
372 G_CALLBACK(gtk_widget_destroyed), &multiplier_dialog_shell);
373
374 g_signal_connect(shell, "response",
375 G_CALLBACK(multipliers_command_callback), NULL);
376
377 gtk_widget_show_all(content);
378
379 return shell;
380 }
381
382 /****************************************************************
383 Popup multipliers dialog
384 *****************************************************************/
popup_multiplier_dialog(void)385 void popup_multiplier_dialog(void)
386 {
387 if (!multiplier_dialog_shell) {
388 multiplier_dialog_shell = create_multiplier_dialog();
389 }
390
391 if (!multiplier_dialog_shell) {
392 return;
393 }
394
395 gtk_window_present(GTK_WINDOW(multiplier_dialog_shell));
396 }
397
398 /****************************************************************
399 Create rates dialog
400 *****************************************************************/
create_rates_dialog(void)401 static GtkWidget *create_rates_dialog(void)
402 {
403 GtkWidget *shell;
404 GtkWidget *frame, *hbox;
405
406 GtkWidget *scale;
407
408 if (!can_client_issue_orders()) {
409 return NULL;
410 }
411
412 shell = gtk_dialog_new_with_buttons(_("Select tax, luxury and science rates"),
413 NULL,
414 0,
415 GTK_STOCK_CANCEL,
416 GTK_RESPONSE_CANCEL,
417 GTK_STOCK_OK,
418 GTK_RESPONSE_OK,
419 NULL);
420 setup_dialog(shell, toplevel);
421 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_OK);
422 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_MOUSE);
423
424 rates_gov_label = gtk_label_new("");
425 gtk_box_pack_start( GTK_BOX( GTK_DIALOG( shell )->vbox ), rates_gov_label, TRUE, TRUE, 5 );
426
427 frame = gtk_frame_new( _("Tax") );
428 gtk_box_pack_start( GTK_BOX( GTK_DIALOG( shell )->vbox ), frame, TRUE, TRUE, 5 );
429
430 hbox = gtk_hbox_new( FALSE, 10 );
431 gtk_container_add( GTK_CONTAINER( frame ), hbox );
432
433 rates_tax_adj = gtk_adjustment_new( 0.0, 0.0, 11.0, 1.0, 1.0, 1.0 );
434 scale = gtk_hscale_new( GTK_ADJUSTMENT( rates_tax_adj ) );
435 gtk_widget_set_size_request(scale, 300, 40);
436 gtk_scale_set_digits( GTK_SCALE( scale ), 0 );
437 gtk_scale_set_draw_value( GTK_SCALE( scale ), FALSE );
438 gtk_box_pack_start( GTK_BOX( hbox ), scale, TRUE, TRUE, 0 );
439
440 rates_tax_label = gtk_label_new(" 0%");
441 gtk_box_pack_start( GTK_BOX( hbox ), rates_tax_label, TRUE, TRUE, 0 );
442 gtk_widget_set_size_request(rates_tax_label, 40, -1);
443
444 rates_tax_toggle = gtk_check_button_new_with_label( _("Lock") );
445 gtk_box_pack_start( GTK_BOX( hbox ), rates_tax_toggle, TRUE, TRUE, 0 );
446
447 frame = gtk_frame_new( _("Luxury") );
448 gtk_box_pack_start( GTK_BOX( GTK_DIALOG( shell )->vbox ), frame, TRUE, TRUE, 5 );
449
450 hbox = gtk_hbox_new( FALSE, 10 );
451 gtk_container_add( GTK_CONTAINER( frame ), hbox );
452
453 rates_lux_adj = gtk_adjustment_new( 0.0, 0.0, 11.0, 1.0, 1.0, 1.0 );
454 scale = gtk_hscale_new( GTK_ADJUSTMENT( rates_lux_adj ) );
455 gtk_widget_set_size_request(scale, 300, 40);
456 gtk_scale_set_digits( GTK_SCALE( scale ), 0 );
457 gtk_scale_set_draw_value( GTK_SCALE( scale ), FALSE );
458 gtk_box_pack_start( GTK_BOX( hbox ), scale, TRUE, TRUE, 0 );
459
460 rates_lux_label = gtk_label_new(" 0%");
461 gtk_box_pack_start( GTK_BOX( hbox ), rates_lux_label, TRUE, TRUE, 0 );
462 gtk_widget_set_size_request(rates_lux_label, 40, -1);
463
464 rates_lux_toggle = gtk_check_button_new_with_label( _("Lock") );
465 gtk_box_pack_start( GTK_BOX( hbox ), rates_lux_toggle, TRUE, TRUE, 0 );
466
467 frame = gtk_frame_new( _("Science") );
468 gtk_box_pack_start( GTK_BOX( GTK_DIALOG( shell )->vbox ), frame, TRUE, TRUE, 5 );
469
470 hbox = gtk_hbox_new( FALSE, 10 );
471 gtk_container_add( GTK_CONTAINER( frame ), hbox );
472
473 rates_sci_adj = gtk_adjustment_new( 0.0, 0.0, 11.0, 1.0, 1.0, 1.0 );
474 scale = gtk_hscale_new( GTK_ADJUSTMENT( rates_sci_adj ) );
475 gtk_widget_set_size_request(scale, 300, 40);
476 gtk_scale_set_digits( GTK_SCALE( scale ), 0 );
477 gtk_scale_set_draw_value( GTK_SCALE( scale ), FALSE );
478 gtk_box_pack_start( GTK_BOX( hbox ), scale, TRUE, TRUE, 0 );
479
480 rates_sci_label = gtk_label_new(" 0%");
481 gtk_box_pack_start( GTK_BOX( hbox ), rates_sci_label, TRUE, TRUE, 0 );
482 gtk_widget_set_size_request(rates_sci_label, 40, -1);
483
484 rates_sci_toggle = gtk_check_button_new_with_label( _("Lock") );
485 gtk_box_pack_start( GTK_BOX( hbox ), rates_sci_toggle, TRUE, TRUE, 0 );
486
487
488 g_signal_connect(shell, "response",
489 G_CALLBACK(rates_command_callback), NULL);
490 g_signal_connect(shell, "destroy",
491 G_CALLBACK(gtk_widget_destroyed), &rates_dialog_shell);
492
493 gtk_widget_show_all( GTK_DIALOG( shell )->vbox );
494 gtk_widget_show_all( GTK_DIALOG( shell )->action_area );
495
496 rates_tax_value=-1;
497 rates_lux_value=-1;
498 rates_sci_value=-1;
499
500 rates_tax_sig =
501 g_signal_connect_after(rates_tax_adj, "value_changed",
502 G_CALLBACK(rates_changed_callback), NULL);
503
504 rates_lux_sig =
505 g_signal_connect_after(rates_lux_adj, "value_changed",
506 G_CALLBACK(rates_changed_callback), NULL);
507
508 rates_sci_sig =
509 g_signal_connect_after(rates_sci_adj, "value_changed",
510 G_CALLBACK(rates_changed_callback), NULL);
511
512 rates_set_values(client.conn.playing->economic.tax, 0,
513 client.conn.playing->economic.luxury, 0,
514 client.conn.playing->economic.science, 0);
515 return shell;
516 }
517
518
519 /****************************************************************
520 Popup rates dialog
521 *****************************************************************/
popup_rates_dialog(void)522 void popup_rates_dialog(void)
523 {
524 if (!can_client_issue_orders()) {
525 return;
526 }
527
528 if (!rates_dialog_shell) {
529 rates_dialog_shell = create_rates_dialog();
530 }
531 if (!rates_dialog_shell) {
532 return;
533 }
534
535 gchar *buf = g_strdup_printf(_("%s max rate: %d%%"),
536 government_name_for_player(client.conn.playing),
537 get_player_bonus(client.conn.playing, EFT_MAX_RATES));
538 gtk_label_set_text(GTK_LABEL(rates_gov_label), buf);
539 g_free(buf);
540
541 gtk_window_present(GTK_WINDOW(rates_dialog_shell));
542 }
543