Freeciv-3.1
Loading...
Searching...
No Matches
gui_stuff.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 <stdarg.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include <gtk/gtk.h>
24#include <gdk/gdkkeysyms.h>
25
26/* utility */
27#include "fcintl.h"
28#include "log.h"
29#include "mem.h"
30#include "support.h"
31
32/* client */
33#include "options.h"
34
35/* client/gui-gtk-4.0 */
36#include "colors.h"
37#include "gui_main.h"
38
39#include "gui_stuff.h"
40
41
42static GList *dialog_list;
43
44static GtkSizeGroup *gui_action;
45
46static GtkCssProvider *dlg_tab_provider = NULL;
47
48
49/**********************************************************************/
52void gtk_expose_now(GtkWidget *w)
53{
54 gtk_widget_queue_draw(w);
55}
56
57/**********************************************************************/
63GtkWidget *icon_label_button_new(const gchar *icon_name,
64 const gchar *label_text)
65{
66 GtkWidget *button;
67
68 fc_assert(icon_name != NULL || label_text != NULL);
69
70 if (label_text != NULL) {
71 button = gtk_button_new_with_mnemonic(label_text);
72 } else if (icon_name != NULL) {
73 button = gtk_button_new_from_icon_name(icon_name);
74 } else {
75 button = NULL;
76 }
77
78 return button;
79}
80
81/**********************************************************************/
85void gtk_stockbutton_set_label(GtkWidget *button, const gchar *label_text)
86{
87 gtk_button_set_label(GTK_BUTTON(button), label_text);
88}
89
90/**********************************************************************/
100void intl_slist(int n, const char **s, bool *done)
101{
102 int i;
103
104 if (!*done) {
105 for (i = 0; i < n; i++) {
106 s[i] = Q_(s[i]);
107 }
108
109 *done = TRUE;
110 }
111}
112
113/**********************************************************************/
116void itree_begin(GtkTreeModel *model, ITree *it)
117{
118 it->model = model;
119 it->end = !gtk_tree_model_get_iter_first(it->model, &it->it);
120}
121
122/**********************************************************************/
125gboolean itree_end(ITree *it)
126{
127 return it->end;
128}
129
130/**********************************************************************/
134{
135 it->end = !gtk_tree_model_iter_next(it->model, &it->it);
136}
137
138/**********************************************************************/
141void itree_set(ITree *it, ...)
142{
143 va_list ap;
144
145 va_start(ap, it);
146 gtk_tree_store_set_valist(GTK_TREE_STORE(it->model), &it->it, ap);
147 va_end(ap);
148}
149
150/**********************************************************************/
153void itree_get(ITree *it, ...)
154{
155 va_list ap;
156
157 va_start(ap, it);
158 gtk_tree_model_get_valist(it->model, &it->it, ap);
159 va_end(ap);
160}
161
162/**********************************************************************/
165void tstore_append(GtkTreeStore *store, ITree *it, ITree *parent)
166{
167 it->model = GTK_TREE_MODEL(store);
168 if (parent)
169 gtk_tree_store_append(GTK_TREE_STORE(it->model), &it->it, &parent->it);
170 else
171 gtk_tree_store_append(GTK_TREE_STORE(it->model), &it->it, NULL);
172 it->end = FALSE;
173}
174
175/**********************************************************************/
178gboolean itree_is_selected(GtkTreeSelection *selection, ITree *it)
179{
180 return gtk_tree_selection_iter_is_selected(selection, &it->it);
181}
182
183/**********************************************************************/
186void itree_select(GtkTreeSelection *selection, ITree *it)
187{
188 gtk_tree_selection_select_iter(selection, &it->it);
189}
190
191/**********************************************************************/
194void itree_unselect(GtkTreeSelection *selection, ITree *it)
195{
196 gtk_tree_selection_unselect_iter(selection, &it->it);
197}
198
199/**********************************************************************/
203gint gtk_tree_selection_get_row(GtkTreeSelection *selection)
204{
205 GtkTreeModel *model;
206 GtkTreeIter it;
207 gint row = -1;
208
209 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
210 GtkTreePath *path;
211 gint *idx;
212
213 path = gtk_tree_model_get_path(model, &it);
214 idx = gtk_tree_path_get_indices(path);
215 row = idx[0];
216 gtk_tree_path_free(path);
217 }
218 return row;
219}
220
221/**********************************************************************/
224void gtk_tree_view_focus(GtkTreeView *view)
225{
226 GtkTreeModel *model;
227 GtkTreePath *path;
228 GtkTreeIter iter;
229
230 if ((model = gtk_tree_view_get_model(view))
231 && gtk_tree_model_get_iter_first(model, &iter)
232 && (path = gtk_tree_model_get_path(model, &iter))) {
233 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
234 gtk_tree_path_free(path);
235 gtk_widget_grab_focus(GTK_WIDGET(view));
236 }
237}
238
239/**********************************************************************/
243GtkWidget *aux_menu_new(void)
244{
245 GtkWidget *menu_button = gtk_menu_button_new();
246
247 return menu_button;
248}
249
250/**********************************************************************/
253static void close_callback(GtkDialog *dialog, gpointer data)
254{
255 gtk_window_destroy(GTK_WINDOW(dialog));
256}
257
258/**********************************************************************/
263void setup_dialog(GtkWidget *shell, GtkWidget *parent)
264{
265 if (GUI_GTK_OPTION(dialogs_on_top) || GUI_GTK_OPTION(fullscreen)) {
266 gtk_window_set_transient_for(GTK_WINDOW(shell),
267 GTK_WINDOW(parent));
268 }
269
270 /* Close dialog window on Escape keypress. */
271 if (GTK_IS_DIALOG(shell)) {
272 g_signal_connect_after(shell, "close", G_CALLBACK(close_callback), shell);
273 }
274}
275
276/**********************************************************************/
279static void gui_dialog_response(struct gui_dialog *dlg, int response)
280{
281 if (dlg->response_callback) {
282 (*dlg->response_callback)(dlg, response, dlg->user_data);
283 }
284}
285
286/**********************************************************************/
289static void gui_dialog_destroyed(struct gui_dialog *dlg, int response,
290 gpointer data)
291{
293}
294
295/**********************************************************************/
298static void gui_dialog_destroy_handler(GtkWidget *w, struct gui_dialog *dlg)
299{
300 if (dlg->type == GUI_DIALOG_TAB) {
301 GtkWidget *notebook = dlg->v.tab.notebook;
302 gulong handler_id = dlg->v.tab.handler_id;
303
304 g_signal_handler_disconnect(notebook, handler_id);
305 }
306
307 g_object_unref(dlg->gui_button);
308
309 if (*(dlg->source)) {
310 *(dlg->source) = NULL;
311 }
312
313 dialog_list = g_list_remove(dialog_list, dlg);
314
315 /* Raise the return dialog set by gui_dialog_set_return_dialog() */
316 if (dlg->return_dialog_id != -1) {
317 GList *it;
318
319 for (it = dialog_list; it; it = g_list_next(it)) {
320 struct gui_dialog *adialog = (struct gui_dialog *)it->data;
321
322 if (adialog->id == dlg->return_dialog_id) {
323 gui_dialog_raise(adialog);
324 break;
325 }
326 }
327 }
328
329 if (dlg->title) {
330 free(dlg->title);
331 }
332
333 free(dlg);
334}
335
336/**********************************************************************/
341static gint gui_dialog_delete_handler(GtkWidget *widget, gpointer data)
342{
343 struct gui_dialog *dlg = data;
344
345 /* emit response signal. */
346 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
347
348 /* do the destroy by default. */
349 return FALSE;
350}
351
352/**********************************************************************/
358{
359 GtkWidget* notebook;
360 int n;
361
362 notebook = dlg->v.tab.notebook;
363 n = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
364 if (gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), n)
365 != dlg->v.tab.child) {
367 }
368
369 /* emit response signal. */
370 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
371
372 /* do the destroy by default. */
373 return FALSE;
374}
375
376
377/**********************************************************************/
380static gboolean gui_dialog_key_press_handler(GtkEventControllerKey *controller,
381 guint keyval, guint keycode,
382 GdkModifierType state,
383 gpointer data)
384{
385 struct gui_dialog *dlg = (struct gui_dialog *)data;
386
387 if (keyval == GDK_KEY_Escape
388 || ((state & GDK_CONTROL_MASK) && keyval == GDK_KEY_w)) {
389 /* Emit response signal. */
390 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
391 }
392
393 /* Propagate event further. */
394 return FALSE;
395}
396
397/**********************************************************************/
401 GtkWidget *page,
402 guint num,
403 struct gui_dialog *dlg)
404{
405 gint n;
406
407 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->grid);
408
409 if (n == num) {
410 gtk_widget_remove_css_class(dlg->v.tab.label, "alert");
411 gtk_widget_remove_css_class(dlg->v.tab.label, "notice");
412 }
413}
414
415/**********************************************************************/
418static void gui_dialog_detach(struct gui_dialog *dlg)
419{
420 gint n;
421 GtkWidget *window, *notebook;
422 gulong handler_id;
423
424 if (dlg->type != GUI_DIALOG_TAB) {
425 return;
426 }
427 dlg->type = GUI_DIALOG_WINDOW;
428
429 /* Create a new reference to the main widget, so it won't be
430 * destroyed in gtk_notebook_remove_page() */
431 g_object_ref(dlg->grid);
432
433 /* Remove widget from the notebook */
434 notebook = dlg->v.tab.notebook;
435 handler_id = dlg->v.tab.handler_id;
436 g_signal_handler_disconnect(notebook, handler_id);
437
438 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->grid);
439 gtk_notebook_remove_page(GTK_NOTEBOOK(dlg->v.tab.notebook), n);
440
441
442 /* Create window and put the widget inside */
443 window = gtk_window_new();
444 gtk_window_set_title(GTK_WINDOW(window), dlg->title);
446
447 gtk_window_set_child(GTK_WINDOW(window), dlg->grid);
448 dlg->v.window = window;
449 g_signal_connect(window, "close-request",
450 G_CALLBACK(gui_dialog_delete_handler), dlg);
451
452 gtk_window_set_default_size(GTK_WINDOW(dlg->v.window),
453 dlg->default_width,
454 dlg->default_height);
455 gtk_widget_show(window);
456}
457
458/**********************************************************************/
461static gboolean click_on_tab_callback(GtkGestureClick *gesture,
462 int n_press,
463 double x, double y, gpointer data)
464{
465 if (n_press == 2) {
466 gui_dialog_detach((struct gui_dialog *)data);
467 }
468
469 return TRUE;
470}
471
472/**********************************************************************/
480void gui_dialog_new(struct gui_dialog **pdlg, GtkNotebook *notebook,
481 gpointer user_data, bool check_top)
482{
483 struct gui_dialog *dlg;
484 GtkWidget *action_area;
485 static int dialog_id_counter;
486 GtkEventController *controller;
487
488 dlg = fc_malloc(sizeof(*dlg));
489 dialog_list = g_list_prepend(dialog_list, dlg);
490
491 dlg->source = pdlg;
492 *pdlg = dlg;
493 dlg->user_data = user_data;
494 dlg->title = NULL;
495
496 dlg->default_width = 200;
497 dlg->default_height = 300;
498
499 if (GUI_GTK_OPTION(enable_tabs)) {
500 dlg->type = GUI_DIALOG_TAB;
501 } else {
502 dlg->type = GUI_DIALOG_WINDOW;
503 }
504
505 if (!gui_action) {
506 gui_action = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL);
507 }
508 dlg->gui_button = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
509
510 dlg->grid = gtk_grid_new();
511 dlg->content_counter = 0;
512 if (GUI_GTK_OPTION(enable_tabs)
513 && (check_top && notebook != GTK_NOTEBOOK(top_notebook))
514 && !GUI_GTK_OPTION(small_display_layout)) {
515 /* We expect this to be short (as opposed to tall); maximise usable
516 * height by putting buttons down the right hand side */
517 action_area = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
518 dlg->vertical_content = FALSE;
519 } else {
520 /* We expect this to be reasonably tall; maximise usable width by
521 * putting buttons along the bottom */
522 action_area = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
523 gtk_orientable_set_orientation(GTK_ORIENTABLE(dlg->grid),
524 GTK_ORIENTATION_VERTICAL);
525 dlg->vertical_content = TRUE;
526 }
527
528 gtk_widget_show(dlg->grid);
530 gtk_widget_show(action_area);
531
532 gtk_widget_set_margin_start(dlg->grid, 2);
533 gtk_widget_set_margin_end(dlg->grid, 2);
534 gtk_widget_set_margin_top(dlg->grid, 2);
535 gtk_widget_set_margin_bottom(dlg->grid, 2);
536
537 gtk_widget_set_margin_start(action_area, 2);
538 gtk_widget_set_margin_end(action_area, 2);
539 gtk_widget_set_margin_top(action_area, 2);
540 gtk_widget_set_margin_bottom(action_area, 2);
541
542 switch (dlg->type) {
544 {
545 GtkWidget *window;
546
547 window = gtk_window_new();
548 gtk_widget_set_name(window, "Freeciv");
550
551 gtk_window_set_child(GTK_WINDOW(window), dlg->grid);
552 dlg->v.window = window;
553 g_signal_connect(window, "close-request",
554 G_CALLBACK(gui_dialog_delete_handler), dlg);
555
556 }
557 break;
558 case GUI_DIALOG_TAB:
559 {
560 GtkWidget *hbox, *label, *button;
561 gchar *buf;
562
563 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
564
565 label = gtk_label_new(NULL);
566 gtk_widget_set_halign(label, GTK_ALIGN_START);
567 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
568 gtk_widget_set_margin_start(label, 4);
569 gtk_widget_set_margin_end(label, 4);
570 gtk_widget_set_margin_top(label, 0);
571 gtk_widget_set_margin_bottom(label, 0);
572 gtk_box_append(GTK_BOX(hbox), label);
573
574 button = gtk_button_new();
575 gtk_button_set_has_frame(GTK_BUTTON(button), FALSE);
576 g_signal_connect_swapped(button, "clicked",
577 G_CALLBACK(gui_dialog_delete_tab_handler), dlg);
578
579 buf = g_strdup_printf(_("Close Tab:\n%s"), _("Ctrl+W"));
580 gtk_widget_set_tooltip_text(button, buf);
581 g_free(buf);
582
583 gtk_button_set_icon_name(GTK_BUTTON(button), "window-close");
584
585 gtk_box_append(GTK_BOX(hbox), button);
586
587 gtk_widget_show(hbox);
588
589 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dlg->grid, hbox);
590 dlg->v.tab.handler_id =
591 g_signal_connect(notebook, "switch-page",
592 G_CALLBACK(gui_dialog_switch_page_handler), dlg);
593 dlg->v.tab.child = dlg->grid;
594
595 dlg->v.tab.label = label;
596 dlg->v.tab.notebook = GTK_WIDGET(notebook);
597
598 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
599 g_signal_connect(controller, "pressed",
600 G_CALLBACK(click_on_tab_callback), dlg);
601 gtk_widget_add_controller(hbox, controller);
602 }
603 break;
604 }
605
606 dlg->actions = action_area;
607
609
610 dlg->id = dialog_id_counter;
611 dialog_id_counter++;
612 dlg->return_dialog_id = -1;
613
614 g_signal_connect(dlg->grid, "destroy",
615 G_CALLBACK(gui_dialog_destroy_handler), dlg);
616 controller = gtk_event_controller_key_new();
617 g_signal_connect(controller, "key-pressed",
618 G_CALLBACK(gui_dialog_key_press_handler), dlg);
619 gtk_widget_add_controller(dlg->grid, controller);
620
621 g_object_set_data(G_OBJECT(dlg->grid), "gui-dialog-data", dlg);
622}
623
624/**********************************************************************/
627static void action_widget_activated(GtkWidget *button, GtkWidget *vbox)
628{
629 struct gui_dialog *dlg =
630 g_object_get_data(G_OBJECT(vbox), "gui-dialog-data");
631 gpointer arg2 =
632 g_object_get_data(G_OBJECT(button), "gui-dialog-response-data");
633
634 gui_dialog_response(dlg, GPOINTER_TO_INT(arg2));
635}
636
637/**********************************************************************/
640static void gui_dialog_pack_button(struct gui_dialog *dlg, GtkWidget *button,
641 int response)
642{
643 gint signal_id;
644
645 fc_assert_ret(GTK_IS_BUTTON(button));
646
647 g_object_set_data(G_OBJECT(button), "gui-dialog-response-data",
648 GINT_TO_POINTER(response));
649
650 if ((signal_id = g_signal_lookup("clicked", GTK_TYPE_BUTTON))) {
651 GClosure *closure;
652
653 closure = g_cclosure_new_object(G_CALLBACK(action_widget_activated),
654 G_OBJECT(dlg->grid));
655 g_signal_connect_closure_by_id(button, signal_id, 0, closure, FALSE);
656 }
657
658 gui_dialog_add_action_widget(dlg, button);
659 gtk_size_group_add_widget(dlg->gui_button, button);
660}
661
662/**********************************************************************/
665GtkWidget *gui_dialog_add_button(struct gui_dialog *dlg,
666 const char *icon_name,
667 const char *text, int response)
668{
669 GtkWidget *button;
670
671 button = icon_label_button_new(icon_name, text);
672 gui_dialog_pack_button(dlg, button, response);
673
674 return button;
675}
676
677/**********************************************************************/
681 GtkWidget *widget)
682{
683 gtk_box_append(GTK_BOX(dlg->actions), widget);
684
685 gtk_size_group_add_widget(gui_action, widget);
686
687 return widget;
688}
689
690/**********************************************************************/
694 int response, bool setting)
695{
696 GtkWidget *iter;
697
698 for (iter = gtk_widget_get_first_child(dlg->actions);
699 iter != NULL;
700 iter = gtk_widget_get_next_sibling(iter)) {
701 if (GTK_IS_BUTTON(iter)) {
702 gpointer data = g_object_get_data(G_OBJECT(iter),
703 "gui-dialog-response-data");
704
705 if (response == GPOINTER_TO_INT(data)) {
706 gtk_widget_set_sensitive(iter, setting);
707 }
708 }
709 }
710}
711
712/**********************************************************************/
715GtkWidget *gui_dialog_get_toplevel(struct gui_dialog *dlg)
716{
717 return gtk_widget_get_ancestor(dlg->grid, GTK_TYPE_WINDOW);
718}
719
720/**********************************************************************/
724{
725 gtk_widget_show(dlg->grid);
726
727 if (dlg->type == GUI_DIALOG_TAB) {
728 GtkWidget *iter;
729 gint num_visible = 0;
730
731 for (iter = gtk_widget_get_first_child(dlg->actions);
732 iter != NULL;
733 iter = gtk_widget_get_next_sibling(iter)) {
734 if (!GTK_IS_BUTTON(iter)) {
735 num_visible++;
736 } else {
737 gpointer data = g_object_get_data(G_OBJECT(iter),
738 "gui-dialog-response-data");
739 int response = GPOINTER_TO_INT(data);
740
741 if (response != GTK_RESPONSE_CLOSE
742 && response != GTK_RESPONSE_CANCEL) {
743 num_visible++;
744 } else {
745 gtk_widget_hide(iter);
746 }
747 }
748 }
749
750 if (num_visible == 0) {
751 gtk_widget_hide(dlg->actions);
752 }
753 }
754}
755
756/**********************************************************************/
760{
761 fc_assert_ret(NULL != dlg);
762
763 switch (dlg->type) {
765 gtk_widget_show(dlg->v.window);
766 break;
767 case GUI_DIALOG_TAB:
768 {
769 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
770 gint current, n;
771
772 current = gtk_notebook_get_current_page(notebook);
773 n = gtk_notebook_page_num(notebook, dlg->grid);
774
775 if (current != n) {
776 gtk_widget_add_css_class(dlg->v.tab.label, "notice");
777 }
778 }
779 break;
780 }
781}
782
783/**********************************************************************/
787{
788 fc_assert_ret(NULL != dlg);
789
790 switch (dlg->type) {
792 gtk_window_present(GTK_WINDOW(dlg->v.window));
793 break;
794 case GUI_DIALOG_TAB:
795 {
796 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
797 gint n;
798
799 n = gtk_notebook_page_num(notebook, dlg->grid);
800 gtk_notebook_set_current_page(notebook, n);
801 }
802 break;
803 }
804}
805
806/**********************************************************************/
810{
811 fc_assert_ret(NULL != dlg);
812
813 switch (dlg->type) {
815 break;
816 case GUI_DIALOG_TAB:
817 {
818 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
819 gint current, n;
820
821 current = gtk_notebook_get_current_page(notebook);
822 n = gtk_notebook_page_num(notebook, dlg->grid);
823
824 if (current != n) {
825 /* Have only alert - remove notice if it exist. */
826 gtk_widget_remove_css_class(dlg->v.tab.label, "notice");
827 gtk_widget_add_css_class(dlg->v.tab.label, "alert");
828 }
829 }
830 break;
831 }
832}
833
834/**********************************************************************/
838{
839 dlg->default_width = width;
840 dlg->default_height = height;
841 switch (dlg->type) {
843 gtk_window_set_default_size(GTK_WINDOW(dlg->v.window), width, height);
844 break;
845 case GUI_DIALOG_TAB:
846 break;
847 }
848}
849
850/**********************************************************************/
853void gui_dialog_set_title(struct gui_dialog *dlg, const char *title)
854{
855 if (dlg->title) {
856 free(dlg->title);
857 }
858 dlg->title = fc_strdup(title);
859 switch (dlg->type) {
861 gtk_window_set_title(GTK_WINDOW(dlg->v.window), title);
862 break;
863 case GUI_DIALOG_TAB:
864 gtk_label_set_text_with_mnemonic(GTK_LABEL(dlg->v.tab.label), title);
865 break;
866 }
867}
868
869/**********************************************************************/
873{
874 switch (dlg->type) {
876 gtk_window_destroy(GTK_WINDOW(dlg->v.window));
877 break;
878 case GUI_DIALOG_TAB:
879 {
880 gint n;
881
882 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->grid);
883 gtk_notebook_remove_page(GTK_NOTEBOOK(dlg->v.tab.notebook), n);
884 }
885 break;
886 }
887}
888
889/**********************************************************************/
893{
894 GList *it, *it_next;
895
896 for (it = dialog_list; it; it = it_next) {
897 it_next = g_list_next(it);
898
899 gui_dialog_destroy((struct gui_dialog *)it->data);
900 }
901}
902
903/**********************************************************************/
911
912/**********************************************************************/
916 struct gui_dialog *return_dialog)
917{
918 if (return_dialog == NULL) {
919 dlg->return_dialog_id = -1;
920 } else {
921 dlg->return_dialog_id = return_dialog->id;
922 }
923}
924
925/**********************************************************************/
928void gui_update_font(const char *font_name, const char *font_value)
929{
930 char *str;
931 GtkCssProvider *provider;
932 PangoFontDescription *desc;
933 int size;
934 const char *fam;
935 const char *style;
936 const char *weight;
937
938 desc = pango_font_description_from_string(font_value);
939
940 if (desc == NULL) {
941 return;
942 }
943
944 fam = pango_font_description_get_family(desc);
945
946 if (fam == NULL) {
947 return;
948 }
949
950 if (pango_font_description_get_style(desc) == PANGO_STYLE_ITALIC) {
951 style = "\n font-style: italic;";
952 } else {
953 style = "";
954 }
955
956 if (pango_font_description_get_weight(desc) >= 700) {
957 weight = "\n font-weight: bold;";
958 } else {
959 weight = "";
960 }
961
962 size = pango_font_description_get_size(desc);
963
964 if (size != 0) {
965 if (pango_font_description_get_size_is_absolute(desc)) {
966 str = g_strdup_printf("#Freeciv #%s { font-family: %s; font-size: %dpx;%s%s}",
967 font_name, fam, size / PANGO_SCALE, style, weight);
968 } else {
969 str = g_strdup_printf("#Freeciv #%s { font-family: %s; font-size: %dpt;%s%s}",
970 font_name, fam, size / PANGO_SCALE, style, weight);
971 }
972 } else {
973 str = g_strdup_printf("#Freeciv #%s { font-family: %s;%s%s}",
974 font_name, fam, style, weight);
975 }
976
977 pango_font_description_free(desc);
978
979 provider = gtk_css_provider_new();
980 gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
981 str, -1);
982 gtk_style_context_add_provider_for_display(
983 gtk_widget_get_display(toplevel), GTK_STYLE_PROVIDER(provider),
984 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
985 g_free(str);
986}
987
988/**********************************************************************/
991void gui_update_font_full(const char *font_name, const char *font_value,
992 PangoFontDescription **font_desc)
993{
994 PangoFontDescription *f_desc;
995
996 gui_update_font(font_name, font_value);
997
998 f_desc = pango_font_description_from_string(font_value);
999 pango_font_description_free(*font_desc);
1000
1001 *font_desc = f_desc;
1002}
1003
1004/**********************************************************************/
1008void disable_gobject_callback(GObject *obj, GCallback cb)
1009{
1010 gulong hid;
1011
1012 if (!obj || !cb) {
1013 return;
1014 }
1015
1016 hid = g_signal_handler_find(obj, G_SIGNAL_MATCH_FUNC,
1017 0, 0, NULL, cb, NULL);
1018 g_signal_handler_block(obj, hid);
1019}
1020
1021/**********************************************************************/
1024void enable_gobject_callback(GObject *obj, GCallback cb)
1025{
1026 gulong hid;
1027
1028 if (!obj || !cb) {
1029 return;
1030 }
1031
1032 hid = g_signal_handler_find(obj, G_SIGNAL_MATCH_FUNC,
1033 0, 0, NULL, cb, NULL);
1034 g_signal_handler_unblock(obj, hid);
1035}
1036
1037/**********************************************************************/
1041GtkTreeViewColumn *add_treeview_column(GtkWidget *view, const char *title,
1042 GType gtype, int model_index)
1043{
1044 GtkTreeViewColumn *col;
1045 GtkCellRenderer *rend;
1046 const char *attr;
1047
1048 fc_assert_ret_val(view != NULL, NULL);
1049 fc_assert_ret_val(GTK_IS_TREE_VIEW(view), NULL);
1050 fc_assert_ret_val(title != NULL, NULL);
1051
1052 if (gtype == G_TYPE_BOOLEAN) {
1053 rend = gtk_cell_renderer_toggle_new();
1054 attr = "active";
1055 } else if (gtype == GDK_TYPE_PIXBUF) {
1056 rend = gtk_cell_renderer_pixbuf_new();
1057 attr = "pixbuf";
1058 } else {
1059 rend = gtk_cell_renderer_text_new();
1060 attr = "text";
1061 }
1062
1063 col = gtk_tree_view_column_new_with_attributes(title, rend, attr,
1064 model_index, NULL);
1065 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1066
1067 return col;
1068}
1069
1070/**********************************************************************/
1074{
1075 dlg_tab_provider = gtk_css_provider_new();
1076
1077 gtk_css_provider_load_from_data(dlg_tab_provider,
1078 ".alert {\n"
1079 "color: rgba(255, 0, 0, 255);\n"
1080 "}\n"
1081 ".notice {\n"
1082 "color: rgba(0, 0, 255, 255);\n"
1083 "}\n",
1084 -1);
1085
1086 gtk_style_context_add_provider_for_display(
1087 gtk_widget_get_display(toplevel),
1088 GTK_STYLE_PROVIDER(dlg_tab_provider),
1089 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1090}
1091
1092/**********************************************************************/
1095void gui_dialog_add_content_widget(struct gui_dialog *dlg, GtkWidget *wdg)
1096{
1097 if (dlg->vertical_content) {
1098 gtk_grid_attach(GTK_GRID(dlg->grid), wdg,
1099 0, dlg->content_counter++, 1, 1);
1100 } else {
1101 gtk_grid_attach(GTK_GRID(dlg->grid), wdg,
1102 dlg->content_counter++, 0, 1, 1);
1103 }
1104}
1105
1107 GMainLoop *loop;
1109};
1110
1111/**********************************************************************/
1114static void blocking_dialog_response(GtkWidget *dlg, gint response, void *data)
1115{
1116 struct blocking_dialog_data *bd_data = (struct blocking_dialog_data *)data;
1117
1118 bd_data->response = response;
1119
1120 g_main_loop_quit(bd_data->loop);
1121}
1122
1123/**********************************************************************/
1126gint blocking_dialog(GtkWidget *dlg)
1127{
1128 struct blocking_dialog_data data;
1129 GMainLoop *dlg_loop;
1130
1131 gtk_widget_show(dlg);
1132 dlg_loop = g_main_loop_new(NULL, FALSE);
1133 data.loop = dlg_loop;
1134 g_signal_connect(dlg, "response", G_CALLBACK(blocking_dialog_response),
1135 &data);
1136
1137 g_main_loop_run(dlg_loop);
1138
1139 return data.response;
1140}
1141
1142/**********************************************************************/
1145void widget_destroyed(GtkWidget *wdg, void *data)
1146{
1147 *(GtkWidget **)data = NULL;
1148}
1149
1150/**********************************************************************/
1154GtkWidget *widget_get_child(GtkWidget *wdg)
1155{
1156 return gtk_widget_get_first_child(wdg);
1157}
#define str
Definition astring.c:76
#define n
Definition astring.c:77
struct canvas int int struct sprite int int int int height
Definition canvas_g.h:44
struct canvas int int struct sprite int int int width
Definition canvas_g.h:44
#define Q_(String)
Definition fcintl.h:70
#define _(String)
Definition fcintl.h:67
GtkWidget * top_notebook
Definition gui_main.c:128
GtkWidget * toplevel
Definition gui_main.c:124
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
void gtk_tree_view_focus(GtkTreeView *view)
Definition gui_stuff.c:230
void gui_dialog_destroy(struct gui_dialog *dlg)
Definition gui_stuff.c:951
static void gui_dialog_pack_button(struct gui_dialog *dlg, GtkWidget *button, int response)
Definition gui_stuff.c:664
void gui_dialog_present(struct gui_dialog *dlg)
Definition gui_stuff.c:834
static void gui_dialog_switch_page_handler(GtkNotebook *notebook, GtkWidget *page, guint num, struct gui_dialog *dlg)
Definition gui_stuff.c:421
void gtk_stockbutton_set_label(GtkWidget *button, const gchar *label_text)
Definition gui_stuff.c:90
void itree_get(ITree *it,...)
Definition gui_stuff.c:158
void itree_set(ITree *it,...)
Definition gui_stuff.c:146
void gui_dialog_raise(struct gui_dialog *dlg)
Definition gui_stuff.c:864
void gui_dialog_new(struct gui_dialog **pdlg, GtkNotebook *notebook, gpointer user_data, bool check_top)
Definition gui_stuff.c:504
void disable_gobject_callback(GObject *obj, GCallback cb)
Definition gui_stuff.c:1087
gint gtk_tree_selection_get_row(GtkTreeSelection *selection)
Definition gui_stuff.c:209
void gui_dialog_set_return_dialog(struct gui_dialog *dlg, struct gui_dialog *return_dialog)
Definition gui_stuff.c:994
void gui_dialog_response_set_callback(struct gui_dialog *dlg, GUI_DIALOG_RESPONSE_FUN fun)
Definition gui_stuff.c:985
static GtkSizeGroup * gui_action
Definition gui_stuff.c:44
void itree_begin(GtkTreeModel *model, ITree *it)
Definition gui_stuff.c:121
static void gui_dialog_destroyed(struct gui_dialog *dlg, int response, gpointer data)
Definition gui_stuff.c:312
GtkWidget * gui_dialog_add_button(struct gui_dialog *dlg, const char *text, int response)
Definition gui_stuff.c:706
static void action_widget_activated(GtkWidget *button, GtkWidget *vbox)
Definition gui_stuff.c:651
void itree_unselect(GtkTreeSelection *selection, ITree *it)
Definition gui_stuff.c:200
void enable_gobject_callback(GObject *obj, GCallback cb)
Definition gui_stuff.c:1103
static void gui_dialog_detach(struct gui_dialog *dlg)
Definition gui_stuff.c:438
void gui_dialog_show_all(struct gui_dialog *dlg)
Definition gui_stuff.c:794
static gboolean gui_dialog_key_press_handler(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition gui_stuff.c:403
static gint gui_dialog_delete_handler(GtkWidget *widget, GdkEventAny *ev, gpointer data)
Definition gui_stuff.c:364
void itree_select(GtkTreeSelection *selection, ITree *it)
Definition gui_stuff.c:192
void gui_dialog_set_title(struct gui_dialog *dlg, const char *title)
Definition gui_stuff.c:932
static void close_callback(GtkDialog *dialog, gpointer data)
Definition gui_stuff.c:271
void gui_dialog_set_default_size(struct gui_dialog *dlg, int width, int height)
Definition gui_stuff.c:916
void gui_dialog_alert(struct gui_dialog *dlg)
Definition gui_stuff.c:887
GtkTreeViewColumn * add_treeview_column(GtkWidget *view, const char *title, GType gtype, int model_index)
Definition gui_stuff.c:1120
static void gui_dialog_destroy_handler(GtkWidget *w, struct gui_dialog *dlg)
Definition gui_stuff.c:321
void tstore_append(GtkTreeStore *store, ITree *it, ITree *parent)
Definition gui_stuff.c:170
static gint gui_dialog_delete_tab_handler(struct gui_dialog *dlg)
Definition gui_stuff.c:381
void itree_next(ITree *it)
Definition gui_stuff.c:138
void gui_dialog_destroy_all(void)
Definition gui_stuff.c:971
static gboolean click_on_tab_callback(GtkWidget *w, GdkEventButton *button, gpointer data)
Definition gui_stuff.c:481
gboolean itree_is_selected(GtkTreeSelection *selection, ITree *it)
Definition gui_stuff.c:184
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:281
static GList * dialog_list
Definition gui_stuff.c:42
void gui_update_font_full(const char *font_name, const char *font_value, PangoFontDescription **font_desc)
Definition gui_stuff.c:1070
void gtk_expose_now(GtkWidget *w)
Definition gui_stuff.c:50
void gui_dialog_set_response_sensitive(struct gui_dialog *dlg, int response, bool setting)
Definition gui_stuff.c:759
GtkWidget * gui_dialog_get_toplevel(struct gui_dialog *dlg)
Definition gui_stuff.c:786
void intl_slist(int n, const char **s, bool *done)
Definition gui_stuff.c:105
gboolean itree_end(ITree *it)
Definition gui_stuff.c:130
static void gui_dialog_response(struct gui_dialog *dlg, int response)
Definition gui_stuff.c:302
@ GUI_DIALOG_WINDOW
Definition gui_stuff.h:60
@ GUI_DIALOG_TAB
Definition gui_stuff.h:61
void(* GUI_DIALOG_RESPONSE_FUN)(struct gui_dialog *, int, gpointer)
Definition gui_stuff.h:66
static struct gui_dialog * shell
Definition messagedlg.c:39
const char * title
Definition repodlgs.c:1313
static GtkCssProvider * dlg_tab_provider
Definition gui_stuff.c:46
void dlg_tab_provider_prepare(void)
Definition gui_stuff.c:1151
GtkWidget * icon_label_button_new(const gchar *icon_name, const gchar *label_text)
Definition gui_stuff.c:76
gint blocking_dialog(GtkWidget *dlg)
Definition gui_stuff.c:1126
GtkWidget * aux_menu_new(void)
Definition gui_stuff.c:243
void gui_dialog_add_content_widget(struct gui_dialog *dlg, GtkWidget *wdg)
Definition gui_stuff.c:1095
GtkWidget * widget_get_child(GtkWidget *wdg)
Definition gui_stuff.c:1154
static void blocking_dialog_response(GtkWidget *dlg, gint response, void *data)
Definition gui_stuff.c:1114
GtkWidget * gui_dialog_add_action_widget(struct gui_dialog *dlg, GtkWidget *widget)
Definition gui_stuff.c:680
void widget_destroyed(GtkWidget *wdg, void *data)
Definition gui_stuff.c:1145
const char * font_name
Definition gui_main_g.h:43
gui_update_font
Definition gui_main_g.h:43
#define fc_assert_ret(condition)
Definition log.h:191
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define fc_strdup(str)
Definition mem.h:43
#define fc_malloc(sz)
Definition mem.h:34
size_t size
Definition specvec.h:72
GtkTreeModel * model
Definition gui_stuff.h:32
gboolean end
Definition gui_stuff.h:33
GtkTreeIter it
Definition gui_stuff.h:34
char * title
Definition gui_stuff.h:75
gulong handler_id
Definition gui_stuff.h:88
GtkWidget * actions
Definition gui_stuff.h:72
GtkWidget * action_area
Definition gui_stuff.h:72
union gui_dialog::@149 v
int content_counter
Definition gui_stuff.h:84
GtkWidget * grid
Definition gui_stuff.h:71
bool vertical_content
Definition gui_stuff.h:83
GtkSizeGroup * gui_button
Definition gui_stuff.h:98
GtkWidget * vbox
Definition gui_stuff.h:71
GUI_DIALOG_RESPONSE_FUN response_callback
Definition gui_stuff.h:95
GtkWidget * label
Definition gui_stuff.h:86
struct gui_dialog::@149::@150 tab
GtkWidget * notebook
Definition gui_stuff.h:87
int return_dialog_id
Definition gui_stuff.h:78
int default_height
Definition gui_stuff.h:81
struct gui_dialog ** source
Definition gui_stuff.h:93
gpointer user_data
Definition gui_stuff.h:96
GtkWidget * window
Definition gui_stuff.h:84
enum gui_dialog_type type
Definition gui_stuff.h:76
int default_width
Definition gui_stuff.h:80
GtkWidget * child
Definition gui_stuff.h:89
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47