Freeciv-3.1
Loading...
Searching...
No Matches
optiondlg.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 <stdlib.h>
19
20#include <gtk/gtk.h>
21
22/* utility */
23#include "log.h"
24#include "mem.h"
25#include "string_vector.h"
26
27/* client */
28#include "options.h"
29
30/* client/gui-gtk-4.0 */
31#include "colors.h"
32#include "dialogs.h"
33#include "gui_main.h"
34#include "gui_stuff.h"
35#include "pages.h"
36
37#include "optiondlg.h"
38
39
40/* The option dialog data. */
41struct option_dialog {
42 const struct option_set *poptset; /* The option set. */
43 GtkWidget *shell; /* The main widget. */
44 GtkWidget *notebook; /* The notebook. */
45 GtkWidget **vboxes; /* Category boxes. */
46 int *box_children; /* The number of children for
47 * each category. */
48};
49
50#define SPECLIST_TAG option_dialog
51#define SPECLIST_TYPE struct option_dialog
52#include "speclist.h"
53#define option_dialogs_iterate(pdialog) \
54 TYPED_LIST_ITERATE(struct option_dialog, option_dialogs, pdialog)
55#define option_dialogs_iterate_end LIST_ITERATE_END
56
57/* All option dialog are set on this list. */
58static struct option_dialog_list *option_dialogs = NULL;
59
60enum {
67};
68
69static GtkWidget *opt_popover = NULL;
70
71
72/* Option dialog main functions. */
73static struct option_dialog *
75static struct option_dialog *
76option_dialog_new(const char *name, const struct option_set *poptset);
77static void option_dialog_destroy(struct option_dialog *pdialog);
78
79static void option_dialog_reorder_notebook(struct option_dialog *pdialog);
80static inline void option_dialog_foreach(struct option_dialog *pdialog,
81 void (*option_action)
82 (struct option *));
83
84/* Option dialog option-specific functions. */
85static void option_dialog_option_add(struct option_dialog *pdialog,
86 struct option *poption,
87 bool reorder_notebook);
88static void option_dialog_option_remove(struct option_dialog *pdialog,
89 struct option *poption);
90
91static void option_dialog_option_refresh(struct option *poption);
92static void option_dialog_option_reset(struct option *poption);
93static void option_dialog_option_apply(struct option *poption);
94
95
96/************************************************************************/
99static void option_dialog_reponse_callback(GtkDialog *dialog,
100 gint response_id, gpointer data)
101{
102 struct option_dialog *pdialog = (struct option_dialog *) data;
103
104 switch (response_id) {
105 case RESPONSE_CANCEL:
106 gtk_window_destroy(GTK_WINDOW(dialog));
107 break;
108 case RESPONSE_OK:
110 gtk_window_destroy(GTK_WINDOW(dialog));
111 break;
112 case RESPONSE_APPLY:
114 break;
115 case RESPONSE_RESET:
117 break;
118 case RESPONSE_REFRESH:
120 break;
121 case RESPONSE_SAVE:
123 options_save(NULL);
124 break;
125 }
126}
127
128/************************************************************************/
131static void option_dialog_destroy_callback(GtkWidget *object, gpointer data)
132{
133 struct option_dialog *pdialog = (struct option_dialog *) data;
134
135 if (NULL != pdialog->shell) {
136 /* Mark as destroyed, see also option_dialog_destroy(). */
137 pdialog->shell = NULL;
138 option_dialog_destroy(pdialog);
139 }
140}
141
142/************************************************************************/
145static void option_refresh_callback(GSimpleAction *action, GVariant *parameter,
146 gpointer data)
147{
148 struct option *poption = (struct option *)data;
149 struct option_dialog *pdialog = option_dialog_get(option_optset(poption));
150
151 if (NULL != pdialog) {
153 }
154
155 gtk_widget_unparent(opt_popover);
156 g_object_unref(opt_popover);
157}
158
159/************************************************************************/
162static void option_reset_callback(GSimpleAction *action, GVariant *parameter,
163 gpointer data)
164{
165 struct option *poption = (struct option *) data;
166 struct option_dialog *pdialog = option_dialog_get(option_optset(poption));
167
168 if (NULL != pdialog) {
170 }
171
172 gtk_widget_unparent(opt_popover);
173 g_object_unref(opt_popover);
174}
175
176/************************************************************************/
179static void option_apply_callback(GSimpleAction *action, GVariant *parameter,
180 gpointer data)
181{
182 struct option *poption = (struct option *) data;
183 struct option_dialog *pdialog = option_dialog_get(option_optset(poption));
184
185 if (NULL != pdialog) {
187 }
188
189 gtk_widget_unparent(opt_popover);
190 g_object_unref(opt_popover);
191}
192
193/************************************************************************/
196static gboolean option_button_press_callback(GtkGestureClick *gesture,
197 int n_press,
198 double x, double y,
199 gpointer data)
200{
201 struct option *poption = (struct option *) data;
202 GtkEventController *controller = GTK_EVENT_CONTROLLER(gesture);
203 GtkWidget *parent = gtk_event_controller_get_widget(controller);
204 GMenu *menu;
205 GActionGroup *group;
206 GSimpleAction *act;
207 GdkRectangle rect = { .x = x, .y = y, .width = 1, .height = 1};
208
209 if (!option_is_changeable(poption)) {
210 return FALSE;
211 }
212
213 group = G_ACTION_GROUP(g_simple_action_group_new());
214
215 menu = g_menu_new();
216
217 act = g_simple_action_new("refresh", NULL);
218 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
219 g_signal_connect(act, "activate", G_CALLBACK(option_refresh_callback), poption);
220 menu_item_append_unref(menu, g_menu_item_new(_("Refresh this option"),
221 "win.refresh"));
222
223 act = g_simple_action_new("unit_reset", NULL);
224 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
225 g_signal_connect(act, "activate", G_CALLBACK(option_reset_callback), poption);
226 menu_item_append_unref(menu, g_menu_item_new(_("Reset this option"),
227 "win.unit_reset"));
228
229 act = g_simple_action_new("units_apply", NULL);
230 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
231 g_signal_connect(act, "activate", G_CALLBACK(option_apply_callback), poption);
233 g_menu_item_new(_("Apply the changes for this option"),
234 "win.units_apply"));
235
236 opt_popover = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
237 g_object_ref(opt_popover);
238 gtk_widget_insert_action_group(opt_popover, "win", group);
239
240 gtk_widget_set_parent(opt_popover, parent);
241 gtk_popover_set_pointing_to(GTK_POPOVER(opt_popover), &rect);
242
243 gtk_popover_popup(GTK_POPOVER(opt_popover));
244
245 return TRUE;
246}
247
248/************************************************************************/
251static struct option_dialog *
253{
254 if (NULL != option_dialogs) {
255 option_dialogs_iterate(pdialog) {
256 if (pdialog->poptset == poptset) {
257 return pdialog;
258 }
260 }
261 return NULL;
262}
263
264/************************************************************************/
267static void option_color_destroy_notify(gpointer data)
268{
269 GdkRGBA *color = (GdkRGBA *) data;
270
271 if (NULL != color) {
272 gdk_rgba_free(color);
273 }
274}
275
276/************************************************************************/
279static void option_color_set_button_color(GtkButton *button,
280 const GdkRGBA *new_color)
281{
282 GdkRGBA *current_color = g_object_get_data(G_OBJECT(button), "color");
283 GtkWidget *child;
284
285 if (NULL == new_color) {
286 if (NULL != current_color) {
287 g_object_set_data(G_OBJECT(button), "color", NULL);
288 gtk_button_set_child(button, NULL);
289 }
290 } else {
291 GdkPixbuf *pixbuf;
292
293 /* Apply the new color. */
294 if (NULL != current_color) {
295 /* We already have a GdkRGBA pointer. */
296 *current_color = *new_color;
297 } else {
298 /* We need to make a GdkRGBA pointer. */
299 current_color = gdk_rgba_copy(new_color);
300 g_object_set_data_full(G_OBJECT(button), "color", current_color,
302 }
303 gtk_button_set_child(button, NULL);
304
305 /* Update the button. */
306 {
307 cairo_surface_t *surface = cairo_image_surface_create(
308 CAIRO_FORMAT_RGB24, 16, 16);
309 cairo_t *cr = cairo_create(surface);
310 gdk_cairo_set_source_rgba(cr, current_color);
311 cairo_paint(cr);
312 cairo_destroy(cr);
313 pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, 16, 16);
314 cairo_surface_destroy(surface);
315 }
316 child = gtk_image_new_from_pixbuf(pixbuf);
317 gtk_button_set_child(GTK_BUTTON(button), child);
318 gtk_widget_show(child);
319 g_object_unref(G_OBJECT(pixbuf));
320 }
321}
322
323/************************************************************************/
326static void color_selector_response_callback(GtkDialog *dialog,
327 gint res, gpointer data)
328{
329 if (res == GTK_RESPONSE_REJECT) {
330 /* Clears the current color. */
331 option_color_set_button_color(GTK_BUTTON(data), NULL);
332 } else if (res == GTK_RESPONSE_OK) {
333 /* Apply the new color. */
334 GtkColorChooser *chooser =
335 GTK_COLOR_CHOOSER(g_object_get_data(G_OBJECT(dialog), "chooser"));
336 GdkRGBA new_color;
337
338 gtk_color_chooser_get_rgba(chooser, &new_color);
339 option_color_set_button_color(GTK_BUTTON(data), &new_color);
340 }
341
342 gtk_window_destroy(GTK_WINDOW(dialog));
343}
344
345/************************************************************************/
348static void option_color_select_callback(GtkButton *button, gpointer data)
349{
350 GtkWidget *dialog, *chooser;
351 GdkRGBA *current_color = g_object_get_data(G_OBJECT(button), "color");
352
353 dialog = gtk_dialog_new_with_buttons(_("Select a color"), NULL,
354 GTK_DIALOG_MODAL,
355 _("_Cancel"), GTK_RESPONSE_CANCEL,
356 _("C_lear"), GTK_RESPONSE_REJECT,
357 _("_OK"), GTK_RESPONSE_OK, NULL);
358 setup_dialog(dialog, toplevel);
359 g_signal_connect(dialog, "response",
360 G_CALLBACK(color_selector_response_callback), button);
361
362 chooser = gtk_color_chooser_widget_new();
363 g_object_set_data(G_OBJECT(dialog), "chooser", chooser);
364 gtk_box_insert_child_after(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
365 chooser, NULL);
366 if (current_color) {
367 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(chooser), current_color);
368 }
369
370 gtk_widget_show(dialog);
371}
372
373/************************************************************************/
376static struct option_dialog *
377option_dialog_new(const char *name, const struct option_set *poptset)
378{
379 struct option_dialog *pdialog;
380 const int CATEGORY_NUM = optset_category_number(poptset);
381
382 /* Create the dialog structure. */
383 pdialog = fc_malloc(sizeof(*pdialog));
384 pdialog->poptset = poptset;
385 pdialog->shell = gtk_dialog_new_with_buttons(name, NULL, 0,
386 _("_Cancel"), RESPONSE_CANCEL,
387 _("_Save"), RESPONSE_SAVE,
388 _("_Refresh"), RESPONSE_REFRESH,
389 _("Reset"), RESPONSE_RESET,
390 _("_Apply"), RESPONSE_APPLY,
391 _("_OK"), RESPONSE_OK, NULL);
392 pdialog->notebook = gtk_notebook_new();
393 pdialog->vboxes = fc_calloc(CATEGORY_NUM, sizeof(*pdialog->vboxes));
394 pdialog->box_children = fc_calloc(CATEGORY_NUM,
395 sizeof(*pdialog->box_children));
396
397 /* Append to the option dialog list. */
398 if (NULL == option_dialogs) {
399 option_dialogs = option_dialog_list_new();
400 }
401 option_dialog_list_append(option_dialogs, pdialog);
402
403 /* Shell */
404 setup_dialog(pdialog->shell, toplevel);
405 gtk_window_set_default_size(GTK_WINDOW(pdialog->shell), -1, 480);
406 g_signal_connect(pdialog->shell, "response",
407 G_CALLBACK(option_dialog_reponse_callback), pdialog);
408 g_signal_connect(pdialog->shell, "destroy",
409 G_CALLBACK(option_dialog_destroy_callback), pdialog);
410
411 gtk_box_insert_child_after(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(pdialog->shell))),
412 pdialog->notebook, NULL);
413
414 /* Add the options. */
415 options_iterate(poptset, poption) {
416 option_dialog_option_add(pdialog, poption, FALSE);
418
420
421 /* Show the widgets. */
422 gtk_widget_show(pdialog->shell);
423
424 return pdialog;
425}
426
427/************************************************************************/
430static void option_dialog_destroy(struct option_dialog *pdialog)
431{
432 GtkWidget *shell = pdialog->shell;
433
434 if (NULL != option_dialogs) {
435 option_dialog_list_remove(option_dialogs, pdialog);
436 }
437
438 options_iterate(pdialog->poptset, poption) {
439 option_set_gui_data(poption, NULL);
441
442 if (NULL != shell) {
443 /* Maybe already destroyed, see also option_dialog_destroy_callback(). */
444 pdialog->shell = NULL;
445 gtk_window_destroy(GTK_WINDOW(shell));
446 }
447
448 free(pdialog->vboxes);
449 free(pdialog->box_children);
450 free(pdialog);
451}
452
453/************************************************************************/
456static int option_dialog_pages_sort_func(const void *w1, const void *w2)
457{
458 GObject *obj1 = G_OBJECT(*(GtkWidget **) w1);
459 GObject *obj2 = G_OBJECT(*(GtkWidget **) w2);
460
461 return (GPOINTER_TO_INT(g_object_get_data(obj1, "category"))
462 - GPOINTER_TO_INT(g_object_get_data(obj2, "category")));
463}
464
465/************************************************************************/
469{
470 GtkNotebook *notebook = GTK_NOTEBOOK(pdialog->notebook);
471 const int pages_num = gtk_notebook_get_n_pages(notebook);
472
473 if (0 < pages_num) {
474 GtkWidget *pages[pages_num];
475 int i;
476
477 for (i = 0; i < pages_num; i++) {
478 pages[i] = gtk_notebook_get_nth_page(notebook, i);
479 }
480 qsort(pages, pages_num, sizeof(*pages), option_dialog_pages_sort_func);
481 for (i = 0; i < pages_num; i++) {
482 gtk_notebook_reorder_child(notebook, pages[i], i);
483 }
484 }
485}
486
487/************************************************************************/
490static inline void option_dialog_foreach(struct option_dialog *pdialog,
491 void (*option_action)
492 (struct option *))
493{
494 fc_assert_ret(NULL != pdialog);
495
496 options_iterate(pdialog->poptset, poption) {
497 option_action(poption);
499}
500
501/************************************************************************/
504static void option_dialog_option_add(struct option_dialog *pdialog,
505 struct option *poption,
506 bool reorder_notebook)
507{
508 const int category = option_category(poption);
509 GtkWidget *main_hbox, *label, *w = NULL;
510 int main_col = 0;
511 GtkGesture *gesture;
512 GtkEventController *controller;
513
514 fc_assert(NULL == option_get_gui_data(poption));
515
516 /* Add category if needed. */
517 if (NULL == pdialog->vboxes[category]) {
518 GtkWidget *sw;
519
520 sw = gtk_scrolled_window_new();
521 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
522 GTK_POLICY_NEVER,
523 GTK_POLICY_AUTOMATIC);
524 gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(sw), TRUE);
525 g_object_set_data(G_OBJECT(sw), "category", GINT_TO_POINTER(category));
526 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog->notebook), sw,
527 gtk_label_new_with_mnemonic
528 (option_category_name(poption)));
529
530 if (reorder_notebook) {
532 }
533
534 pdialog->vboxes[category] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
535 gtk_widget_set_margin_bottom(pdialog->vboxes[category], 8);
536 gtk_widget_set_margin_end(pdialog->vboxes[category], 8);
537 gtk_widget_set_margin_start(pdialog->vboxes[category], 8);
538 gtk_widget_set_margin_top(pdialog->vboxes[category], 8);
539 gtk_widget_set_hexpand(pdialog->vboxes[category], TRUE);
540 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), pdialog->vboxes[category]);
541
542 gtk_widget_show(sw);
543 }
544 pdialog->box_children[category]++;
545
546 main_hbox = gtk_grid_new();
547 label = gtk_label_new(option_description(poption));
548 gtk_widget_set_margin_bottom(label, 2);
549 gtk_widget_set_margin_end(label, 2);
550 gtk_widget_set_margin_start(label, 2);
551 gtk_widget_set_margin_top(label, 2);
552 gtk_grid_attach(GTK_GRID(main_hbox), label, main_col++, 0, 1, 1);
553 gtk_widget_set_tooltip_text(main_hbox, option_help_text(poption));
554 gesture = gtk_gesture_click_new();
555 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
556 controller = GTK_EVENT_CONTROLLER(gesture);
557 g_signal_connect(controller, "pressed",
558 G_CALLBACK(option_button_press_callback), poption);
559 gtk_widget_add_controller(main_hbox, controller);
560 gtk_box_append(GTK_BOX(pdialog->vboxes[category]), main_hbox);
561
562 switch (option_type(poption)) {
563 case OT_BOOLEAN:
564 w = gtk_check_button_new();
565 break;
566
567 case OT_INTEGER:
568 {
569 int min = option_int_min(poption), max = option_int_max(poption);
570
571 w = gtk_spin_button_new_with_range(min, max, MAX((max - min) / 50, 1));
572 }
573 break;
574
575 case OT_STRING:
576 {
577 const struct strvec *values = option_str_values(poption);
578
579 if (NULL != values) {
580 w = gtk_combo_box_text_new_with_entry();
581 strvec_iterate(values, value) {
582 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w), value);
584 } else {
585 w = gtk_entry_new();
586 }
587 }
588 break;
589
590 case OT_ENUM:
591 {
592 int i;
593 const char *str;
594 GtkListStore *model;
595 GtkCellRenderer *renderer;
596 GtkTreeIter iter;
597
598 /* 0: enum index, 1: translated enum name. */
599 model = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
600 w = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
601 g_object_unref(model);
602
603 renderer = gtk_cell_renderer_text_new();
604 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w), renderer, FALSE);
605 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(w), renderer,
606 "text", 1, NULL);
607 for (i = 0; (str = option_enum_int_to_str(poption, i)); i++) {
608 gtk_list_store_append(model, &iter);
609 gtk_list_store_set(model, &iter, 0, i, 1, _(str), -1);
610 }
611 }
612 break;
613
614 case OT_BITWISE:
615 {
616 GList *list = NULL;
617 GtkWidget *grid, *check;
618 const struct strvec *values = option_bitwise_values(poption);
619 int i;
620
621 w = gtk_frame_new(NULL);
622 grid = gtk_grid_new();
623 gtk_grid_set_column_spacing(GTK_GRID(grid), 4);
624 gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE);
625 gtk_frame_set_child(GTK_FRAME(w), grid);
626 for (i = 0; i < strvec_size(values); i++) {
627 check = gtk_check_button_new();
628 gtk_grid_attach(GTK_GRID(grid), check, 0, i, 1, 1);
629 label = gtk_label_new(_(strvec_get(values, i)));
630 gtk_grid_attach(GTK_GRID(grid), label, 1, i, 1, 1);
631 list = g_list_append(list, check);
632 }
633 g_object_set_data_full(G_OBJECT(w), "check_buttons", list,
634 (GDestroyNotify) g_list_free);
635 }
636 break;
637
638 case OT_FONT:
639 w = gtk_font_button_new();
640 g_object_set(G_OBJECT(w), "use-font", TRUE, NULL);
641 break;
642
643 case OT_COLOR:
644 {
645 GtkWidget *button;
646 int grid_col = 0;
647
648 w = gtk_grid_new();
649 gtk_grid_set_column_spacing(GTK_GRID(w), 4);
650 gtk_grid_set_row_homogeneous(GTK_GRID(w), TRUE);
651
652 /* Foreground color selector button. */
653 button = gtk_button_new();
654 gtk_grid_attach(GTK_GRID(w), button, grid_col++, 0, 1, 1);
655 gtk_widget_set_tooltip_text(GTK_WIDGET(button),
656 _("Select the text color"));
657 g_object_set_data(G_OBJECT(w), "fg_button", button);
658 g_signal_connect(button, "clicked",
659 G_CALLBACK(option_color_select_callback), NULL);
660
661 /* Background color selector button. */
662 button = gtk_button_new();
663 gtk_grid_attach(GTK_GRID(w), button, grid_col++, 0, 1, 1);
664 gtk_widget_set_tooltip_text(GTK_WIDGET(button),
665 _("Select the background color"));
666 g_object_set_data(G_OBJECT(w), "bg_button", button);
667 g_signal_connect(button, "clicked",
668 G_CALLBACK(option_color_select_callback), NULL);
669 }
670 break;
671
672 case OT_VIDEO_MODE:
673 log_error("Option type %s (%d) not supported yet.",
674 option_type_name(option_type(poption)),
675 option_type(poption));
676 break;
677 }
678
679 option_set_gui_data(poption, w);
680 if (NULL == w) {
681 log_error("Failed to create a widget for option %d \"%s\".",
682 option_number(poption), option_name(poption));
683 } else {
684 g_object_set_data(G_OBJECT(w), "main_widget", main_hbox);
685 g_object_set_data(G_OBJECT(w), "parent_of_main", pdialog->vboxes[category]);
686 gtk_widget_set_hexpand(w, TRUE);
687 gtk_widget_set_halign(w, GTK_ALIGN_END);
688 gtk_grid_attach(GTK_GRID(main_hbox), w, main_col++, 0, 1, 1);
689 }
690
691 gtk_widget_show(main_hbox);
692
693 /* Set as current value. */
695}
696
697/************************************************************************/
700static void option_dialog_option_remove(struct option_dialog *pdialog,
701 struct option *poption)
702{
703 GObject *object = G_OBJECT(option_get_gui_data(poption));
704
705 if (NULL != object) {
706 const int category = option_category(poption);
707
708 option_set_gui_data(poption, NULL);
709 gtk_box_remove(GTK_BOX(g_object_get_data(object, "parent_of_main")),
710 GTK_WIDGET(g_object_get_data(object, "main_widget")));
711
712 /* Remove category if needed. */
713 if (0 == --pdialog->box_children[category]) {
714 gtk_notebook_remove_page(GTK_NOTEBOOK(pdialog->notebook), category);
715 pdialog->vboxes[category] = NULL;
716 }
717 }
718}
719
720/************************************************************************/
723static inline void option_dialog_option_bool_set(struct option *poption,
724 bool value)
725{
726 gtk_check_button_set_active(GTK_CHECK_BUTTON
727 (option_get_gui_data(poption)),
728 value);
729}
730
731/************************************************************************/
734static inline void option_dialog_option_int_set(struct option *poption,
735 int value)
736{
737 gtk_spin_button_set_value(GTK_SPIN_BUTTON(option_get_gui_data(poption)),
738 value);
739}
740
741/************************************************************************/
744static inline void option_dialog_option_str_set(struct option *poption,
745 const char *string)
746{
747 GtkWidget *wdg = option_get_gui_data(poption);
748
749 if (NULL != option_str_values(poption)) {
750 GtkWidget *child = gtk_combo_box_get_child(GTK_COMBO_BOX(wdg));
751
752 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(child)), string, -1);
753 } else {
754 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(wdg)), string, -1);
755 }
756}
757
758/************************************************************************/
761static inline void option_dialog_option_enum_set(struct option *poption,
762 int value)
763{
764 GtkComboBox *combo = GTK_COMBO_BOX(option_get_gui_data(poption));
765 GtkTreeModel *model = gtk_combo_box_get_model(combo);
766 GtkTreeIter iter;
767 int i;
768
769 if (gtk_tree_model_get_iter_first(model, &iter)) {
770 do {
771 gtk_tree_model_get(model, &iter, 0, &i, -1);
772 if (i == value) {
773 gtk_combo_box_set_active_iter(combo, &iter);
774 return;
775 }
776 } while (gtk_tree_model_iter_next(model, &iter));
777 }
778
779 log_error("Didn't find the value %d for option \"%s\" (nb %d).",
780 value, option_name(poption), option_number(poption));
781}
782
783/************************************************************************/
786static inline void option_dialog_option_bitwise_set(struct option *poption,
787 unsigned value)
788{
789 GObject *data = option_get_gui_data(poption);
790 GList *iter = g_object_get_data(data, "check_buttons");
791 int bit;
792
793 for (bit = 0; NULL != iter; iter = g_list_next(iter), bit++) {
794 gtk_check_button_set_active(GTK_CHECK_BUTTON(iter->data),
795 value & (1 << bit));
796 }
797}
798
799/************************************************************************/
802static inline void option_dialog_option_font_set(struct option *poption,
803 const char *font)
804{
805 gtk_font_chooser_set_font(GTK_FONT_CHOOSER
806 (option_get_gui_data(poption)), font);
807}
808
809/************************************************************************/
812static inline void option_dialog_option_color_set(struct option *poption,
813 struct ft_color color)
814{
815 GtkWidget *w = option_get_gui_data(poption);
816 GdkRGBA gdk_color;
817
818 /* Update the foreground button. */
819 if (NULL != color.foreground
820 && '\0' != color.foreground[0]
821 && gdk_rgba_parse(&gdk_color, color.foreground)) {
822 option_color_set_button_color(g_object_get_data(G_OBJECT(w),
823 "fg_button"),
824 &gdk_color);
825 } else {
826 option_color_set_button_color(g_object_get_data(G_OBJECT(w),
827 "fg_button"), NULL);
828 }
829
830 /* Update the background button. */
831 if (NULL != color.background
832 && '\0' != color.background[0]
833 && gdk_rgba_parse(&gdk_color, color.background)) {
834 option_color_set_button_color(g_object_get_data(G_OBJECT(w),
835 "bg_button"),
836 &gdk_color);
837 } else {
838 option_color_set_button_color(g_object_get_data(G_OBJECT(w),
839 "bg_button"), NULL);
840 }
841}
842
843/************************************************************************/
846static void option_dialog_option_refresh(struct option *poption)
847{
848 switch (option_type(poption)) {
849 case OT_BOOLEAN:
851 break;
852 case OT_INTEGER:
854 break;
855 case OT_STRING:
857 break;
858 case OT_ENUM:
860 break;
861 case OT_BITWISE:
863 break;
864 case OT_FONT:
866 break;
867 case OT_COLOR:
869 break;
870 case OT_VIDEO_MODE:
871 log_error("Option type %s (%d) not supported yet.",
872 option_type_name(option_type(poption)),
873 option_type(poption));
874 break;
875 }
876
877 gtk_widget_set_sensitive(option_get_gui_data(poption),
878 option_is_changeable(poption));
879}
880
881/************************************************************************/
884static void option_dialog_option_reset(struct option *poption)
885{
886 switch (option_type(poption)) {
887 case OT_BOOLEAN:
889 break;
890 case OT_INTEGER:
892 break;
893 case OT_STRING:
895 break;
896 case OT_ENUM:
898 break;
899 case OT_BITWISE:
901 break;
902 case OT_FONT:
904 break;
905 case OT_COLOR:
907 break;
908 case OT_VIDEO_MODE:
909 log_error("Option type %s (%d) not supported yet.",
910 option_type_name(option_type(poption)),
911 option_type(poption));
912 break;
913 }
914}
915
916/************************************************************************/
919static void option_dialog_option_apply(struct option *poption)
920{
921 GtkWidget *w = GTK_WIDGET(option_get_gui_data(poption));
922
923 switch (option_type(poption)) {
924 case OT_BOOLEAN:
925 (void) option_bool_set(poption, gtk_check_button_get_active
926 (GTK_CHECK_BUTTON(w)));
927 break;
928
929 case OT_INTEGER:
930 (void) option_int_set(poption, gtk_spin_button_get_value_as_int
931 (GTK_SPIN_BUTTON(w)));
932 break;
933
934 case OT_STRING:
935 if (NULL != option_str_values(poption)) {
936 (void) option_str_set(poption,
937 gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w)));
938 } else {
939 (void) option_str_set(poption, gtk_entry_buffer_get_text(
940 gtk_entry_get_buffer(GTK_ENTRY(w))));
941 }
942 break;
943
944 case OT_ENUM:
945 {
946 GtkTreeIter iter;
947 int value;
948
949 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w), &iter)) {
950 break;
951 }
952
953 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(w)),
954 &iter, 0, &value, -1);
955 (void) option_enum_set_int(poption, value);
956 }
957 break;
958
959 case OT_BITWISE:
960 {
961 GList *iter = g_object_get_data(G_OBJECT(w), "check_buttons");
962 unsigned value = 0;
963 int bit;
964
965 for (bit = 0; NULL != iter; iter = g_list_next(iter), bit++) {
966 if (gtk_check_button_get_active(GTK_CHECK_BUTTON(iter->data))) {
967 value |= 1 << bit;
968 }
969 }
970 (void) option_bitwise_set(poption, value);
971 }
972 break;
973
974 case OT_FONT:
975 (void) option_font_set(poption, gtk_font_chooser_get_font
976 (GTK_FONT_CHOOSER(w)));
977 break;
978
979 case OT_COLOR:
980 {
981 gchar *fg_color_text = NULL, *bg_color_text = NULL;
982 GObject *button;
983 GdkRGBA *color;
984
985 /* Get foreground color. */
986 button = g_object_get_data(G_OBJECT(w), "fg_button");
987 color = g_object_get_data(button, "color");
988 if (color) fg_color_text = gdk_rgba_to_string(color);
989
990 /* Get background color. */
991 button = g_object_get_data(G_OBJECT(w), "bg_button");
992 color = g_object_get_data(button, "color");
993 if (color) bg_color_text = gdk_rgba_to_string(color);
994
995 (void) option_color_set(poption,
996 ft_color_construct(fg_color_text, bg_color_text));
997 g_free(fg_color_text);
998 g_free(bg_color_text);
999 }
1000 break;
1001
1002 case OT_VIDEO_MODE:
1003 log_error("Option type %s (%d) not supported yet.",
1004 option_type_name(option_type(poption)),
1005 option_type(poption));
1006 break;
1007 }
1008}
1009
1010/************************************************************************/
1013void option_dialog_popup(const char *name, const struct option_set *poptset)
1014{
1015 struct option_dialog *pdialog = option_dialog_get(poptset);
1016
1017 if (NULL != pdialog) {
1019 } else {
1021 }
1022}
1023
1024/************************************************************************/
1028{
1029 struct option_dialog *pdialog = option_dialog_get(poptset);
1030
1031 if (NULL != pdialog) {
1032 option_dialog_destroy(pdialog);
1033 }
1034}
1035
1036/************************************************************************/
1040static void option_gui_update_extra(struct option *poption)
1041{
1042 if (option_optset(poption) == server_optset) {
1043 if (strcmp(option_name(poption), "aifill") == 0) {
1045 } else if (strcmp(option_name(poption), "nationset") == 0) {
1047 }
1048 }
1049}
1050
1051/************************************************************************/
1054void option_gui_update(struct option *poption)
1055{
1056 struct option_dialog *pdialog = option_dialog_get(option_optset(poption));
1057
1058 if (NULL != pdialog) {
1060 }
1061
1062 option_gui_update_extra(poption);
1063}
1064
1065/************************************************************************/
1068void option_gui_add(struct option *poption)
1069{
1070 struct option_dialog *pdialog = option_dialog_get(option_optset(poption));
1071
1072 if (NULL != pdialog) {
1073 option_dialog_option_add(pdialog, poption, TRUE);
1074 }
1075
1076 option_gui_update_extra(poption);
1077}
1078
1079/************************************************************************/
1082void option_gui_remove(struct option *poption)
1083{
1084 struct option_dialog *pdialog = option_dialog_get(option_optset(poption));
1085
1086 if (NULL != pdialog) {
1087 option_dialog_option_remove(pdialog, poption);
1088 }
1089}
#define str
Definition astring.c:76
static struct fc_sockaddr_list * list
Definition clinet.c:102
#define _(String)
Definition fcintl.h:67
static struct ft_color ft_color_construct(const char *foreground, const char *background)
void nationset_sync_to_server(const char *nationset)
Definition dialogs.c:809
GtkWidget * toplevel
Definition gui_main.c:124
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:281
static struct gui_dialog * shell
Definition messagedlg.c:39
static void option_dialog_destroy_callback(GtkWidget *object, gpointer data)
Definition optiondlg.c:129
static void color_selector_response_callback(GtkDialog *dialog, gint res, gpointer data)
Definition optiondlg.c:306
static struct option_dialog * option_dialog_get(const struct option_set *poptset)
Definition optiondlg.c:228
void option_gui_remove(struct option *poption)
Definition optiondlg.c:1048
static void option_dialog_option_refresh(struct option *poption)
Definition optiondlg.c:813
void option_dialog_popdown(const struct option_set *poptset)
Definition optiondlg.c:993
static void option_dialog_option_color_set(struct option *poption, struct ft_color color)
Definition optiondlg.c:779
static void option_color_set_button_color(GtkButton *button, const GdkRGBA *new_color)
Definition optiondlg.c:255
static void option_dialog_option_add(struct option_dialog *pdialog, struct option *poption, bool reorder_notebook)
Definition optiondlg.c:486
#define option_dialogs_iterate_end
Definition optiondlg.c:55
static void option_dialog_option_bitwise_set(struct option *poption, unsigned value)
Definition optiondlg.c:753
static void option_dialog_destroy(struct option_dialog *pdialog)
Definition optiondlg.c:412
static void option_dialog_option_bool_set(struct option *poption, bool value)
Definition optiondlg.c:693
static void option_dialog_option_remove(struct option_dialog *pdialog, struct option *poption)
Definition optiondlg.c:671
void option_gui_add(struct option *poption)
Definition optiondlg.c:1034
static void option_color_select_callback(GtkButton *button, gpointer data)
Definition optiondlg.c:328
static void option_dialog_option_int_set(struct option *poption, int value)
Definition optiondlg.c:704
static void option_dialog_reponse_callback(GtkDialog *dialog, gint response_id, gpointer data)
Definition optiondlg.c:97
#define option_dialogs_iterate(pdialog)
Definition optiondlg.c:53
static void option_gui_update_extra(struct option *poption)
Definition optiondlg.c:1006
static void option_apply_callback(GtkMenuItem *menuitem, gpointer data)
Definition optiondlg.c:169
static void option_color_destroy_notify(gpointer data)
Definition optiondlg.c:243
static void option_dialog_option_font_set(struct option *poption, const char *font)
Definition optiondlg.c:769
void option_gui_update(struct option *poption)
Definition optiondlg.c:1020
static int option_dialog_pages_sort_func(const void *w1, const void *w2)
Definition optiondlg.c:438
void option_dialog_popup(const char *name, const struct option_set *poptset)
Definition optiondlg.c:979
static void option_dialog_reorder_notebook(struct option_dialog *pdialog)
Definition optiondlg.c:450
static void option_dialog_option_apply(struct option *poption)
Definition optiondlg.c:886
static gboolean option_button_press_callback(GtkWidget *widget, GdkEventButton *event, gpointer data)
Definition optiondlg.c:182
@ RESPONSE_SAVE
Definition optiondlg.c:66
@ RESPONSE_APPLY
Definition optiondlg.c:63
@ RESPONSE_CANCEL
Definition optiondlg.c:61
@ RESPONSE_OK
Definition optiondlg.c:62
@ RESPONSE_RESET
Definition optiondlg.c:64
@ RESPONSE_REFRESH
Definition optiondlg.c:65
static void option_dialog_option_reset(struct option *poption)
Definition optiondlg.c:851
static void option_reset_callback(GtkMenuItem *menuitem, gpointer data)
Definition optiondlg.c:156
static void option_dialog_foreach(struct option_dialog *pdialog, void(*option_action)(struct option *))
Definition optiondlg.c:472
static void option_dialog_option_str_set(struct option *poption, const char *string)
Definition optiondlg.c:714
static struct option_dialog_list * option_dialogs
Definition optiondlg.c:58
static void option_dialog_option_enum_set(struct option *poption, int value)
Definition optiondlg.c:728
static void option_refresh_callback(GtkMenuItem *menuitem, gpointer data)
Definition optiondlg.c:143
void ai_fill_changed_by_server(int aifill)
Definition pages.c:1651
#define menu_item_append_unref(menu, item)
Definition gui_stuff.h:149
static GtkWidget * opt_popover
Definition optiondlg.c:69
static struct option_dialog * option_dialog_new(void)
Definition optiondlg.c:788
const char * name
Definition inputfile.c:127
#define fc_assert_ret(condition)
Definition log.h:191
#define fc_assert(condition)
Definition log.h:176
#define log_error(message,...)
Definition log.h:103
#define fc_calloc(n, esz)
Definition mem.h:38
#define fc_malloc(sz)
Definition mem.h:34
const struct strvec * option_str_values(const struct option *poption)
Definition options.c:890
unsigned option_bitwise_def(const struct option *poption)
Definition options.c:1060
int option_int_min(const struct option *poption)
Definition options.c:831
bool option_bool_def(const struct option *poption)
Definition options.c:783
const char * option_font_def(const struct option *poption)
Definition options.c:1127
const struct option_set * server_optset
Definition options.c:4009
const char * option_description(const struct option *poption)
Definition options.c:613
const char * option_help_text(const struct option *poption)
Definition options.c:623
struct ft_color option_color_get(const struct option *poption)
Definition options.c:1165
int option_enum_get_int(const struct option *poption)
Definition options.c:955
int option_number(const struct option *poption)
Definition options.c:593
int option_category(const struct option *poption)
Definition options.c:643
bool option_str_set(struct option *poption, const char *str)
Definition options.c:901
const char * option_name(const struct option *poption)
Definition options.c:603
int option_int_get(const struct option *poption)
Definition options.c:809
bool option_color_set(struct option *poption, struct ft_color color)
Definition options.c:1188
bool option_bool_set(struct option *poption, bool val)
Definition options.c:794
bool option_is_changeable(const struct option *poption)
Definition options.c:664
void option_set_gui_data(struct option *poption, void *data)
Definition options.c:742
const char * option_str_get(const struct option *poption)
Definition options.c:868
void * option_get_gui_data(const struct option *poption)
Definition options.c:752
bool option_enum_set_int(struct option *poption, int val)
Definition options.c:1015
bool option_bool_get(const struct option *poption)
Definition options.c:772
int optset_category_number(const struct option_set *poptset)
Definition options.c:432
enum option_type option_type(const struct option *poption)
Definition options.c:633
const char * option_enum_int_to_str(const struct option *poption, int val)
Definition options.c:940
const struct option_set * option_optset(const struct option *poption)
Definition options.c:583
const char * option_str_def(const struct option *poption)
Definition options.c:879
int option_int_max(const struct option *poption)
Definition options.c:842
bool option_font_set(struct option *poption, const char *font)
Definition options.c:1149
void options_save(option_save_log_callback log_cb)
Definition options.c:6053
const struct strvec * option_bitwise_values(const struct option *poption)
Definition options.c:1088
bool option_bitwise_set(struct option *poption, unsigned val)
Definition options.c:1099
const char * option_font_get(const struct option *poption)
Definition options.c:1116
void desired_settable_options_update(void)
Definition options.c:5531
struct ft_color option_color_def(const struct option *poption)
Definition options.c:1176
unsigned option_bitwise_get(const struct option *poption)
Definition options.c:1049
int option_enum_def_int(const struct option *poption)
Definition options.c:979
bool option_int_set(struct option *poption, int val)
Definition options.c:853
const char * option_category_name(const struct option *poption)
Definition options.c:653
int option_int_def(const struct option *poption)
Definition options.c:820
#define options_iterate(poptset, poption)
Definition options.h:527
#define options_iterate_end
Definition options.h:532
#define MAX(x, y)
Definition shared.h:54
const char * strvec_get(const struct strvec *psv, size_t svindex)
size_t strvec_size(const struct strvec *psv)
#define strvec_iterate(psv, str)
#define strvec_iterate_end
Definition colors.h:20
int * box_children
Definition optiondlg.c:46
GtkWidget ** vboxes
Definition optiondlg.c:45
GtkWidget * shell
Definition optiondlg.c:43
const struct option_set * poptset
Definition optiondlg.c:42
GtkWidget * notebook
Definition optiondlg.c:44
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47