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>
23 #include <gdk/gdkkeysyms.h>
28 #include "string_vector.h"
34 #include "government.h"
35 #include "multipliers.h"
38 #include "client_main.h"
41 /* client/gui-gtk-3.0 */
46 #include "gui_stuff.h"
51 /******************************************************************/
52 static GtkWidget
*rates_dialog_shell
;
53 static GtkWidget
*rates_gov_label
;
54 static GtkWidget
*rates_tax_toggle
, *rates_lux_toggle
, *rates_sci_toggle
;
55 static GtkWidget
*rates_tax_label
, *rates_lux_label
, *rates_sci_label
;
56 static GtkWidget
*rates_tax_scale
, *rates_lux_scale
, *rates_sci_scale
;
58 static GtkWidget
*multiplier_dialog_shell
;
59 static GtkWidget
*multipliers_scale
[MAX_NUM_MULTIPLIERS
];
61 static gulong rates_tax_sig
, rates_lux_sig
, rates_sci_sig
;
62 /******************************************************************/
64 static int rates_tax_value
, rates_lux_value
, rates_sci_value
;
66 static void rates_changed_callback(GtkWidget
*range
);
68 /**************************************************************************
69 Set tax values to display
70 **************************************************************************/
71 static void rates_set_values(int tax
, int no_tax_scroll
,
72 int lux
, int no_lux_scroll
,
73 int sci
, int no_sci_scroll
)
76 int tax_lock
, lux_lock
, sci_lock
;
79 tax_lock
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rates_tax_toggle
));
80 lux_lock
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rates_lux_toggle
));
81 sci_lock
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rates_sci_toggle
));
83 if (NULL
!= client
.conn
.playing
) {
84 maxrate
= get_player_bonus(client
.conn
.playing
, EFT_MAX_RATES
);
89 /* This's quite a simple-minded "double check".. */
90 tax
= MIN(tax
, maxrate
);
91 lux
= MIN(lux
, maxrate
);
92 sci
= MIN(sci
, maxrate
);
94 if (tax
+ sci
+ lux
!= 100) {
95 if (tax
!= rates_tax_value
) {
97 lux
= MIN(MAX(100 - tax
- sci
, 0), maxrate
);
100 sci
= MIN(MAX(100 - tax
- lux
, 0), maxrate
);
102 } else if (lux
!= rates_lux_value
) {
104 tax
= MIN(MAX(100 - lux
- sci
, 0), maxrate
);
107 sci
= MIN(MAX(100 - lux
- tax
, 0), maxrate
);
109 } else if (sci
!= rates_sci_value
) {
111 lux
= MIN(MAX(100 - tax
- sci
, 0), maxrate
);
114 tax
= MIN(MAX(100 - lux
- sci
, 0), maxrate
);
118 if (tax
+ sci
+ lux
!= 100) {
119 tax
= rates_tax_value
;
120 lux
= rates_lux_value
;
121 sci
= rates_sci_value
;
123 rates_tax_value
= -1;
124 rates_lux_value
= -1;
125 rates_sci_value
= -1;
133 if (tax
!= rates_tax_value
) {
134 fc_snprintf(buf
, sizeof(buf
), "%3d%%", tax
);
136 if (strcmp(buf
, gtk_label_get_text(GTK_LABEL(rates_tax_label
))) != 0) {
137 gtk_label_set_text(GTK_LABEL(rates_tax_label
), buf
);
139 if (!no_tax_scroll
) {
140 g_signal_handler_block(rates_tax_scale
, rates_tax_sig
);
141 gtk_range_set_value(GTK_RANGE(rates_tax_scale
), tax
/ 10);
142 g_signal_handler_unblock(rates_tax_scale
, rates_tax_sig
);
144 rates_tax_value
= tax
;
147 if (lux
!= rates_lux_value
) {
148 fc_snprintf(buf
, sizeof(buf
), "%3d%%", lux
);
150 if (strcmp(buf
, gtk_label_get_text(GTK_LABEL(rates_lux_label
))) != 0) {
151 gtk_label_set_text(GTK_LABEL(rates_lux_label
), buf
);
153 if (!no_lux_scroll
) {
154 g_signal_handler_block(rates_lux_scale
, rates_lux_sig
);
155 gtk_range_set_value(GTK_RANGE(rates_lux_scale
), lux
/ 10);
156 g_signal_handler_unblock(rates_lux_scale
, rates_lux_sig
);
158 rates_lux_value
= lux
;
161 if (sci
!= rates_sci_value
) {
162 fc_snprintf(buf
, sizeof(buf
), "%3d%%", sci
);
164 if (strcmp(buf
, gtk_label_get_text(GTK_LABEL(rates_sci_label
))) != 0) {
165 gtk_label_set_text(GTK_LABEL(rates_sci_label
), buf
);
167 if (!no_sci_scroll
) {
168 g_signal_handler_block(rates_sci_scale
, rates_sci_sig
);
169 gtk_range_set_value(GTK_RANGE(rates_sci_scale
), sci
/ 10);
170 g_signal_handler_unblock(rates_sci_scale
, rates_sci_sig
);
172 rates_sci_value
= sci
;
176 /**************************************************************************
178 **************************************************************************/
179 static void rates_changed_callback(GtkWidget
*range
)
181 int percent
= gtk_range_get_value(GTK_RANGE(range
));
183 if (range
== rates_tax_scale
) {
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 } else if (range
== rates_lux_scale
) {
192 lux_value
= 10 * percent
;
193 lux_value
= MIN(lux_value
, 100);
194 rates_set_values(rates_tax_value
, 0, lux_value
, 1, rates_sci_value
, 0);
198 sci_value
= 10 * percent
;
199 sci_value
= MIN(sci_value
, 100);
200 rates_set_values(rates_tax_value
, 0, rates_lux_value
, 0, sci_value
, 1);
204 /**************************************************************************
205 User has responded to rates dialog
206 **************************************************************************/
207 static void rates_command_callback(GtkWidget
*w
, gint response_id
)
209 if (response_id
== GTK_RESPONSE_OK
) {
210 dsend_packet_player_rates(&client
.conn
, rates_tax_value
, rates_lux_value
,
213 gtk_widget_destroy(rates_dialog_shell
);
216 /**************************************************************************
217 Convert real multiplier display value to scale value
218 **************************************************************************/
219 static int mult_to_scale(const struct multiplier
*pmul
, int val
)
221 return (val
- pmul
->start
) / pmul
->step
;
224 /**************************************************************************
225 Convert scale units to real multiplier display value
226 **************************************************************************/
227 static int scale_to_mult(const struct multiplier
*pmul
, int scale
)
229 return scale
* pmul
->step
+ pmul
->start
;
232 /**************************************************************************
233 Format value for multiplier scales
234 **************************************************************************/
235 static gchar
*multiplier_value_callback(GtkScale
*scale
, gdouble value
,
238 const struct multiplier
*pmul
= udata
;
240 return g_strdup_printf("%d", scale_to_mult(pmul
, value
));
243 /**************************************************************************
244 User has responded to multipliers dialog
245 **************************************************************************/
246 static void multipliers_command_callback(GtkWidget
*w
, gint response_id
)
248 struct packet_player_multiplier mul
;
250 if (response_id
== GTK_RESPONSE_OK
&& can_client_issue_orders()) {
251 multipliers_iterate(m
) {
252 Multiplier_type_id i
= multiplier_index(m
);
253 int value
= gtk_range_get_value(GTK_RANGE(multipliers_scale
[i
]));
255 mul
.multipliers
[i
] = scale_to_mult(m
, value
);
256 } multipliers_iterate_end
;
257 mul
.count
= multiplier_count();
258 send_packet_player_multiplier(&client
.conn
, &mul
);
260 gtk_widget_destroy(multiplier_dialog_shell
);
263 /**************************************************************************
264 Update values in multipliers dialog
265 **************************************************************************/
266 static void multiplier_dialog_update_values(bool set_positions
)
268 multipliers_iterate(pmul
) {
269 Multiplier_type_id multiplier
= multiplier_index(pmul
);
270 int val
= player_multiplier_value(client_player(), pmul
);
271 int target
= player_multiplier_target_value(client_player(), pmul
);
273 fc_assert(multiplier
< ARRAY_SIZE(multipliers_scale
));
274 fc_assert(scale_to_mult(pmul
, mult_to_scale(pmul
, val
)) == val
);
275 fc_assert(scale_to_mult(pmul
, mult_to_scale(pmul
, target
)) == target
);
277 gtk_scale_clear_marks(GTK_SCALE(multipliers_scale
[multiplier
]));
278 gtk_scale_add_mark(GTK_SCALE(multipliers_scale
[multiplier
]),
279 mult_to_scale(pmul
, val
), GTK_POS_BOTTOM
,
280 /* TRANS: current value of policy in force */
281 Q_("?multiplier:Cur"));
284 gtk_range_set_value(GTK_RANGE(multipliers_scale
[multiplier
]),
285 mult_to_scale(pmul
, target
));
287 } multipliers_iterate_end
;
290 /**************************************************************************
291 Callback when server indicates multiplier values have changed
292 **************************************************************************/
293 void real_multipliers_dialog_update(void)
295 if (!multiplier_dialog_shell
) {
299 /* If dialog belongs to a player rather than an observer, we don't
300 * want to lose any local changes made by the player.
301 * This dialog should be the only way the values can change, anyway. */
302 multiplier_dialog_update_values(!can_client_issue_orders());
305 /****************************************************************
306 Create multipliers dialog
307 ****************************************************************/
308 static GtkWidget
*create_multiplier_dialog(void)
310 GtkWidget
*shell
, *content
;
311 GtkWidget
*label
, *scale
;
313 if (can_client_issue_orders()) {
314 shell
= gtk_dialog_new_with_buttons(_("Change policies"),
323 shell
= gtk_dialog_new_with_buttons(_("Policies"),
330 setup_dialog(shell
, toplevel
);
332 gtk_window_set_position(GTK_WINDOW(shell
), GTK_WIN_POS_MOUSE
);
333 content
= gtk_dialog_get_content_area(GTK_DIALOG(shell
));
335 if (can_client_issue_orders()) {
336 label
= gtk_label_new(_("Changes will not take effect until next turn."));
337 gtk_box_pack_start( GTK_BOX( content
), label
, FALSE
, FALSE
, 0);
340 multipliers_iterate(pmul
) {
341 Multiplier_type_id multiplier
= multiplier_index(pmul
);
343 fc_assert(multiplier
< ARRAY_SIZE(multipliers_scale
));
344 label
= gtk_label_new(multiplier_name_translation(pmul
));
345 /* Map each multiplier step to a single step on the UI, to enforce
347 scale
= gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL
,
348 mult_to_scale(pmul
, pmul
->start
),
349 mult_to_scale(pmul
, pmul
->stop
), 1);
350 multipliers_scale
[multiplier
] = scale
;
351 gtk_range_set_increments(GTK_RANGE(multipliers_scale
[multiplier
]),
352 1, MAX(2, mult_to_scale(pmul
, pmul
->stop
) / 10));
353 g_signal_connect(multipliers_scale
[multiplier
], "format-value",
354 G_CALLBACK(multiplier_value_callback
), pmul
);
355 g_signal_connect(multipliers_scale
[multiplier
], "destroy",
356 G_CALLBACK(gtk_widget_destroyed
),
357 &multipliers_scale
[multiplier
]);
358 gtk_box_pack_start( GTK_BOX( content
), label
, TRUE
, TRUE
, 5 );
359 gtk_box_pack_start( GTK_BOX( content
), scale
, TRUE
, TRUE
, 5 );
360 gtk_widget_set_sensitive(multipliers_scale
[multiplier
],
361 can_client_issue_orders());
362 } multipliers_iterate_end
;
364 multiplier_dialog_update_values(TRUE
);
366 g_signal_connect(shell
, "destroy",
367 G_CALLBACK(gtk_widget_destroyed
), &multiplier_dialog_shell
);
369 g_signal_connect(shell
, "response",
370 G_CALLBACK(multipliers_command_callback
), NULL
);
372 gtk_widget_show_all(content
);
377 /****************************************************************
378 Popup multipliers dialog
379 *****************************************************************/
380 void popup_multiplier_dialog(void)
382 if (!multiplier_dialog_shell
) {
383 multiplier_dialog_shell
= create_multiplier_dialog();
386 if (!multiplier_dialog_shell
) {
390 gtk_window_present(GTK_WINDOW(multiplier_dialog_shell
));
393 /****************************************************************
395 *****************************************************************/
396 static GtkWidget
*create_rates_dialog(void)
398 GtkWidget
*shell
, *content
;
399 GtkWidget
*frame
, *hgrid
;
402 if (!can_client_issue_orders()) {
406 shell
= gtk_dialog_new_with_buttons(_("Select tax, luxury and science rates"),
414 setup_dialog(shell
, toplevel
);
415 gtk_dialog_set_default_response(GTK_DIALOG(shell
), GTK_RESPONSE_OK
);
416 gtk_window_set_position(GTK_WINDOW(shell
), GTK_WIN_POS_MOUSE
);
417 content
= gtk_dialog_get_content_area(GTK_DIALOG(shell
));
419 rates_gov_label
= gtk_label_new("");
420 gtk_box_pack_start( GTK_BOX( content
), rates_gov_label
, TRUE
, TRUE
, 5 );
422 frame
= gtk_frame_new( _("Tax") );
423 gtk_box_pack_start( GTK_BOX( content
), frame
, TRUE
, TRUE
, 5 );
425 hgrid
= gtk_grid_new();
426 gtk_grid_set_column_spacing(GTK_GRID(hgrid
), 10);
427 gtk_container_add(GTK_CONTAINER(frame
), hgrid
);
430 gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL
, 0, 10, 1);
431 gtk_range_set_increments(GTK_RANGE(rates_tax_scale
), 1, 1);
432 for (i
= 0; i
<= 10; i
++) {
433 gtk_scale_add_mark(GTK_SCALE(rates_tax_scale
), i
, GTK_POS_TOP
, NULL
);
435 gtk_widget_set_size_request(rates_tax_scale
, 300, 40);
436 gtk_scale_set_digits(GTK_SCALE(rates_tax_scale
), 0);
437 gtk_scale_set_draw_value(GTK_SCALE(rates_tax_scale
), FALSE
);
438 gtk_container_add(GTK_CONTAINER(hgrid
), rates_tax_scale
);
440 rates_tax_label
= gtk_label_new(" 0%");
441 gtk_container_add(GTK_CONTAINER(hgrid
), rates_tax_label
);
442 gtk_widget_set_size_request(rates_tax_label
, 40, -1);
444 rates_tax_toggle
= gtk_check_button_new_with_label( _("Lock") );
445 gtk_container_add(GTK_CONTAINER(hgrid
), rates_tax_toggle
);
447 frame
= gtk_frame_new( _("Luxury") );
448 gtk_box_pack_start( GTK_BOX( content
), frame
, TRUE
, TRUE
, 5 );
450 hgrid
= gtk_grid_new();
451 gtk_grid_set_column_spacing(GTK_GRID(hgrid
), 10);
452 gtk_container_add(GTK_CONTAINER(frame
), hgrid
);
455 gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL
, 0, 10, 1);
456 gtk_range_set_increments(GTK_RANGE(rates_lux_scale
), 1, 1);
457 for (i
= 0; i
<= 10; i
++) {
458 gtk_scale_add_mark(GTK_SCALE(rates_lux_scale
), i
, GTK_POS_TOP
, NULL
);
460 gtk_widget_set_size_request(rates_lux_scale
, 300, 40);
461 gtk_scale_set_digits(GTK_SCALE(rates_lux_scale
), 0);
462 gtk_scale_set_draw_value(GTK_SCALE(rates_lux_scale
), FALSE
);
463 gtk_container_add(GTK_CONTAINER(hgrid
), rates_lux_scale
);
465 rates_lux_label
= gtk_label_new(" 0%");
466 gtk_container_add(GTK_CONTAINER(hgrid
), rates_lux_label
);
467 gtk_widget_set_size_request(rates_lux_label
, 40, -1);
469 rates_lux_toggle
= gtk_check_button_new_with_label( _("Lock") );
470 gtk_container_add(GTK_CONTAINER(hgrid
), rates_lux_toggle
);
472 frame
= gtk_frame_new( _("Science") );
473 gtk_box_pack_start( GTK_BOX( content
), frame
, TRUE
, TRUE
, 5 );
475 hgrid
= gtk_grid_new();
476 gtk_grid_set_column_spacing(GTK_GRID(hgrid
), 10);
477 gtk_container_add(GTK_CONTAINER(frame
), hgrid
);
480 gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL
, 0, 10, 1);
481 gtk_range_set_increments(GTK_RANGE(rates_sci_scale
), 1, 1);
482 for (i
= 0; i
<= 10; i
++) {
483 gtk_scale_add_mark(GTK_SCALE(rates_sci_scale
), i
, GTK_POS_TOP
, NULL
);
485 gtk_widget_set_size_request(rates_sci_scale
, 300, 40);
486 gtk_scale_set_digits(GTK_SCALE(rates_sci_scale
), 0);
487 gtk_scale_set_draw_value(GTK_SCALE(rates_sci_scale
), FALSE
);
488 gtk_container_add(GTK_CONTAINER(hgrid
), rates_sci_scale
);
490 rates_sci_label
= gtk_label_new(" 0%");
491 gtk_container_add(GTK_CONTAINER(hgrid
), rates_sci_label
);
492 gtk_widget_set_size_request(rates_sci_label
, 40, -1);
494 rates_sci_toggle
= gtk_check_button_new_with_label( _("Lock") );
495 gtk_container_add(GTK_CONTAINER(hgrid
), rates_sci_toggle
);
498 g_signal_connect(shell
, "response",
499 G_CALLBACK(rates_command_callback
), NULL
);
500 g_signal_connect(shell
, "destroy",
501 G_CALLBACK(gtk_widget_destroyed
), &rates_dialog_shell
);
503 gtk_widget_show_all(shell
);
510 g_signal_connect_after(rates_tax_scale
, "value-changed",
511 G_CALLBACK(rates_changed_callback
), NULL
);
514 g_signal_connect_after(rates_lux_scale
, "value-changed",
515 G_CALLBACK(rates_changed_callback
), NULL
);
518 g_signal_connect_after(rates_sci_scale
, "value-changed",
519 G_CALLBACK(rates_changed_callback
), NULL
);
521 rates_set_values(client
.conn
.playing
->economic
.tax
, 0,
522 client
.conn
.playing
->economic
.luxury
, 0,
523 client
.conn
.playing
->economic
.science
, 0);
528 /****************************************************************
530 *****************************************************************/
531 void popup_rates_dialog(void)
533 if (!can_client_issue_orders()) {
537 if (!rates_dialog_shell
) {
538 rates_dialog_shell
= create_rates_dialog();
540 if (!rates_dialog_shell
) {
544 gchar
*buf
= g_strdup_printf(_("%s max rate: %d%%"),
545 government_name_for_player(client
.conn
.playing
),
546 get_player_bonus(client
.conn
.playing
, EFT_MAX_RATES
));
547 gtk_label_set_text(GTK_LABEL(rates_gov_label
), buf
);
549 gtk_range_set_fill_level(GTK_RANGE(rates_tax_scale
),
550 get_player_bonus(client
.conn
.playing
,
552 gtk_range_set_fill_level(GTK_RANGE(rates_lux_scale
),
553 get_player_bonus(client
.conn
.playing
,
555 gtk_range_set_fill_level(GTK_RANGE(rates_sci_scale
),
556 get_player_bonus(client
.conn
.playing
,
559 gtk_window_present(GTK_WINDOW(rates_dialog_shell
));