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