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