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-3.22 */
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/**********************************************************************/
60void set_relative_window_position(GtkWindow *ref, GtkWindow *w, int px, int py)
61{
62 gint x, y, width, height;
63
64 gtk_window_get_position(ref, &x, &y);
65 gtk_window_get_size(ref, &width, &height);
66
67 x += px * width / 100;
68 y += py * height / 100;
69
70 gtk_window_move(w, x, y);
71}
72
73/**********************************************************************/
76GtkWidget *icon_label_button_new(const gchar *icon_name,
77 const gchar *label_text)
78{
79 GtkWidget *button;
80 GtkWidget *image;
81
82 button = gtk_button_new_with_mnemonic(label_text);
83
84 if (icon_name != NULL) {
85 image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON);
86 gtk_button_set_image(GTK_BUTTON(button), image);
87 }
88
89 return button;
90}
91
92/**********************************************************************/
96void gtk_stockbutton_set_label(GtkWidget *button, const gchar *label_text)
97{
98 gtk_button_set_label(GTK_BUTTON(button), label_text);
99}
100
101/**********************************************************************/
111void intl_slist(int n, const char **s, bool *done)
112{
113 int i;
114
115 if (!*done) {
116 for (i = 0; i < n; i++) {
117 s[i] = Q_(s[i]);
118 }
119
120 *done = TRUE;
121 }
122}
123
124/**********************************************************************/
127void itree_begin(GtkTreeModel *model, ITree *it)
128{
129 it->model = model;
130 it->end = !gtk_tree_model_get_iter_first(it->model, &it->it);
131}
132
133/**********************************************************************/
136gboolean itree_end(ITree *it)
137{
138 return it->end;
139}
140
141/**********************************************************************/
145{
146 it->end = !gtk_tree_model_iter_next(it->model, &it->it);
147}
148
149/**********************************************************************/
152void itree_set(ITree *it, ...)
153{
154 va_list ap;
155
156 va_start(ap, it);
157 gtk_tree_store_set_valist(GTK_TREE_STORE(it->model), &it->it, ap);
158 va_end(ap);
159}
160
161/**********************************************************************/
164void itree_get(ITree *it, ...)
165{
166 va_list ap;
167
168 va_start(ap, it);
169 gtk_tree_model_get_valist(it->model, &it->it, ap);
170 va_end(ap);
171}
172
173/**********************************************************************/
176void tstore_append(GtkTreeStore *store, ITree *it, ITree *parent)
177{
178 it->model = GTK_TREE_MODEL(store);
179 if (parent) {
180 gtk_tree_store_append(GTK_TREE_STORE(it->model), &it->it, &parent->it);
181 } else {
182 gtk_tree_store_append(GTK_TREE_STORE(it->model), &it->it, NULL);
183 }
184 it->end = FALSE;
185}
186
187/**********************************************************************/
190gboolean itree_is_selected(GtkTreeSelection *selection, ITree *it)
191{
192 return gtk_tree_selection_iter_is_selected(selection, &it->it);
193}
194
195/**********************************************************************/
198void itree_select(GtkTreeSelection *selection, ITree *it)
199{
200 gtk_tree_selection_select_iter(selection, &it->it);
201}
202
203/**********************************************************************/
206void itree_unselect(GtkTreeSelection *selection, ITree *it)
207{
208 gtk_tree_selection_unselect_iter(selection, &it->it);
209}
210
211/**********************************************************************/
215gint gtk_tree_selection_get_row(GtkTreeSelection *selection)
216{
217 GtkTreeModel *model;
218 GtkTreeIter it;
219 gint row = -1;
220
221 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
222 GtkTreePath *path;
223 gint *idx;
224
225 path = gtk_tree_model_get_path(model, &it);
226 idx = gtk_tree_path_get_indices(path);
227 row = idx[0];
228 gtk_tree_path_free(path);
229 }
230 return row;
231}
232
233/**********************************************************************/
236void gtk_tree_view_focus(GtkTreeView *view)
237{
238 GtkTreeModel *model;
239 GtkTreePath *path;
240 GtkTreeIter iter;
241
242 if ((model = gtk_tree_view_get_model(view))
243 && gtk_tree_model_get_iter_first(model, &iter)
244 && (path = gtk_tree_model_get_path(model, &iter))) {
245 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
246 gtk_tree_path_free(path);
247 gtk_widget_grab_focus(GTK_WIDGET(view));
248 }
249}
250
251/**********************************************************************/
255GtkWidget *gtk_aux_menu_bar_new(void)
256{
257 GtkWidget *menubar = gtk_menu_bar_new();
258
259 /*
260 * Ubuntu Linux's Ayatana/Unity desktop environment likes to steal the
261 * application's main menu bar from its window and put it at the top of
262 * the screen. It needs a hint in order not to steal menu bars other
263 * than the main one. Gory details at
264 * https://bugs.launchpad.net/ubuntu/+source/freeciv/+bug/743265
265 */
266 if (g_object_class_find_property(
267 G_OBJECT_CLASS(GTK_MENU_BAR_GET_CLASS(menubar)), "ubuntu-local")) {
268 g_object_set(G_OBJECT(menubar), "ubuntu-local", TRUE, NULL);
269 }
270
271 return menubar;
272}
273
274/**********************************************************************/
277static void close_callback(GtkDialog *dialog, gpointer data)
278{
279 gtk_widget_destroy(GTK_WIDGET(dialog));
280}
281
282/**********************************************************************/
287void setup_dialog(GtkWidget *shell, GtkWidget *parent)
288{
289 if (GUI_GTK_OPTION(dialogs_on_top) || GUI_GTK_OPTION(fullscreen)) {
290 gtk_window_set_transient_for(GTK_WINDOW(shell),
291 GTK_WINDOW(parent));
292 gtk_window_set_type_hint(GTK_WINDOW(shell),
293 GDK_WINDOW_TYPE_HINT_DIALOG);
294 } else {
295 gtk_window_set_type_hint(GTK_WINDOW(shell),
296 GDK_WINDOW_TYPE_HINT_NORMAL);
297 }
298
299 /* Close dialog window on Escape keypress. */
300 if (GTK_IS_DIALOG(shell)) {
301 g_signal_connect_after(shell, "close", G_CALLBACK(close_callback), shell);
302 }
303}
304
305/**********************************************************************/
308static void gui_dialog_response(struct gui_dialog *dlg, int response)
309{
310 if (dlg->response_callback) {
311 (*dlg->response_callback)(dlg, response, dlg->user_data);
312 }
313}
314
315/**********************************************************************/
318static void gui_dialog_destroyed(struct gui_dialog *dlg, int response,
319 gpointer data)
320{
322}
323
324/**********************************************************************/
327static void gui_dialog_destroy_handler(GtkWidget *w, struct gui_dialog *dlg)
328{
329 if (dlg->type == GUI_DIALOG_TAB) {
330 GtkWidget *notebook = dlg->v.tab.notebook;
331 gulong handler_id = dlg->v.tab.handler_id;
332
333 g_signal_handler_disconnect(notebook, handler_id);
334 }
335
336 g_object_unref(dlg->gui_button);
337
338 if (*(dlg->source)) {
339 *(dlg->source) = NULL;
340 }
341
342 dialog_list = g_list_remove(dialog_list, dlg);
343
344 /* Raise the return dialog set by gui_dialog_set_return_dialog() */
345 if (dlg->return_dialog_id != -1) {
346 GList *it;
347
348 for (it = dialog_list; it; it = g_list_next(it)) {
349 struct gui_dialog * adialog = (struct gui_dialog *)it->data;
350
351 if (adialog->id == dlg->return_dialog_id) {
352 gui_dialog_raise(adialog);
353 break;
354 }
355 }
356 }
357
358 if (dlg->title) {
359 free(dlg->title);
360 }
361
362 free(dlg);
363}
364
365/**********************************************************************/
370static gint gui_dialog_delete_handler(GtkWidget *widget,
371 GdkEventAny *ev, gpointer data)
372{
373 struct gui_dialog *dlg = data;
374
375 /* emit response signal. */
376 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
377
378 /* do the destroy by default. */
379 return FALSE;
380}
381
382/**********************************************************************/
388{
389 GtkWidget* notebook;
390 int n;
391
392 notebook = dlg->v.tab.notebook;
393 n = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
394 if (gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), n)
395 != dlg->v.tab.child) {
397 }
398
399 /* emit response signal. */
400 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
401
402 /* do the destroy by default. */
403 return FALSE;
404}
405
406/**********************************************************************/
409static gboolean gui_dialog_key_press_handler(GtkWidget *w, GdkEventKey *ev,
410 gpointer data)
411{
412 struct gui_dialog *dlg = data;
413
414 if (ev->keyval == GDK_KEY_Escape
415 || ((ev->state & GDK_CONTROL_MASK) && ev->keyval == GDK_KEY_w)) {
416 /* emit response signal. */
417 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
418 }
419
420 /* propagate event further. */
421 return FALSE;
422}
423
424/**********************************************************************/
428 GtkWidget *page,
429 guint num,
430 struct gui_dialog *dlg)
431{
432 gint n;
433
434 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->vbox);
435
436 if (n == num) {
437 GtkStyleContext *context = gtk_widget_get_style_context(dlg->v.tab.label);
438
439 gtk_style_context_remove_class(context, "alert");
440 gtk_style_context_remove_class(context, "notice");
441 }
442}
443
444/**********************************************************************/
447static void gui_dialog_detach(struct gui_dialog* dlg)
448{
449 gint n;
450 GtkWidget *window, *notebook;
451 gulong handler_id;
452
453 if (dlg->type != GUI_DIALOG_TAB) {
454 return;
455 }
456 dlg->type = GUI_DIALOG_WINDOW;
457
458 /* Create a new reference to the main widget, so it won't be
459 * destroyed in gtk_notebook_remove_page() */
460 g_object_ref(dlg->vbox);
461
462 /* Remove widget from the notebook */
463 notebook = dlg->v.tab.notebook;
464 handler_id = dlg->v.tab.handler_id;
465 g_signal_handler_disconnect(notebook, handler_id);
466
467 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->vbox);
468 gtk_notebook_remove_page(GTK_NOTEBOOK(dlg->v.tab.notebook), n);
469
470
471 /* Create window and put the widget inside */
472 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
473 gtk_window_set_title(GTK_WINDOW(window), dlg->title);
475
476 gtk_container_add(GTK_CONTAINER(window), dlg->vbox);
477 dlg->v.window = window;
478 g_signal_connect(window, "delete_event",
479 G_CALLBACK(gui_dialog_delete_handler), dlg);
480
481 gtk_window_set_default_size(GTK_WINDOW(dlg->v.window),
482 dlg->default_width,
483 dlg->default_height);
484 gtk_widget_show_all(window);
485}
486
487/**********************************************************************/
490static gboolean click_on_tab_callback(GtkWidget *w,
491 GdkEventButton* button,
492 gpointer data)
493{
494 if (button->type != GDK_2BUTTON_PRESS) {
495 return FALSE;
496 }
497 if (button->button != 1) {
498 return FALSE;
499 }
500 gui_dialog_detach((struct gui_dialog*) data);
501 return TRUE;
502}
503
504
505/**********************************************************************/
513void gui_dialog_new(struct gui_dialog **pdlg, GtkNotebook *notebook,
514 gpointer user_data, bool check_top)
515{
516 struct gui_dialog *dlg;
517 GtkWidget *vbox, *action_area;
518 static int dialog_id_counter;
519
520 dlg = fc_malloc(sizeof(*dlg));
521 dialog_list = g_list_prepend(dialog_list, dlg);
522
523 dlg->source = pdlg;
524 *pdlg = dlg;
525 dlg->user_data = user_data;
526 dlg->title = NULL;
527
528 dlg->default_width = 200;
529 dlg->default_height = 300;
530
531 if (GUI_GTK_OPTION(enable_tabs)) {
532 dlg->type = GUI_DIALOG_TAB;
533 } else {
534 dlg->type = GUI_DIALOG_WINDOW;
535 }
536
537 if (!gui_action) {
538 gui_action = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL);
539 }
540 dlg->gui_button = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
541
542 vbox = gtk_grid_new();
543 action_area = gtk_grid_new();
544 gtk_grid_set_row_spacing(GTK_GRID(action_area), 4);
545 gtk_grid_set_column_spacing(GTK_GRID(action_area), 4);
546 if (GUI_GTK_OPTION(enable_tabs)
547 && (check_top && notebook != GTK_NOTEBOOK(top_notebook))
548 && !GUI_GTK_OPTION(small_display_layout)) {
549 /* We expect this to be short (as opposed to tall); maximise usable
550 * height by putting buttons down the right hand side */
551 gtk_orientable_set_orientation(GTK_ORIENTABLE(action_area),
552 GTK_ORIENTATION_VERTICAL);
553 } else {
554 /* We expect this to be reasonably tall; maximise usable width by
555 * putting buttons along the bottom */
556 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
557 GTK_ORIENTATION_VERTICAL);
558 }
559
560 gtk_widget_show(vbox);
561 gtk_container_add(GTK_CONTAINER(vbox), action_area);
562 gtk_widget_show(action_area);
563
564 gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
565 gtk_container_set_border_width(GTK_CONTAINER(action_area), 2);
566
567 switch (dlg->type) {
569 {
570 GtkWidget *window;
571
572 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
573 gtk_widget_set_name(window, "Freeciv");
574 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);
576
577 gtk_container_add(GTK_CONTAINER(window), vbox);
578 dlg->v.window = window;
579 g_signal_connect(window, "delete_event",
580 G_CALLBACK(gui_dialog_delete_handler), dlg);
581
582 }
583 break;
584 case GUI_DIALOG_TAB:
585 {
586 GtkWidget *hbox, *label, *image, *button, *event_box;
587 gchar *buf;
588
589 hbox = gtk_grid_new();
590
591 label = gtk_label_new(NULL);
592 gtk_widget_set_halign(label, GTK_ALIGN_START);
593 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
594 gtk_widget_set_margin_start(label, 4);
595 gtk_widget_set_margin_end(label, 4);
596 gtk_widget_set_margin_top(label, 0);
597 gtk_widget_set_margin_bottom(label, 0);
598 gtk_container_add(GTK_CONTAINER(hbox), label);
599
600 button = gtk_button_new();
601 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
602 g_signal_connect_swapped(button, "clicked",
603 G_CALLBACK(gui_dialog_delete_tab_handler), dlg);
604
605 buf = g_strdup_printf(_("Close Tab:\n%s"), _("Ctrl+W"));
606 gtk_widget_set_tooltip_text(button, buf);
607 g_free(buf);
608
609 image = gtk_image_new_from_icon_name("window-close", GTK_ICON_SIZE_MENU);
610 gtk_widget_set_margin_start(image, 0);
611 gtk_widget_set_margin_end(image, 0);
612 gtk_widget_set_margin_top(image, 0);
613 gtk_widget_set_margin_bottom(image, 0);
614 gtk_button_set_image(GTK_BUTTON(button), image);
615
616 gtk_container_add(GTK_CONTAINER(hbox), button);
617
618 gtk_widget_show_all(hbox);
619
620 event_box = gtk_event_box_new();
621 gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box), FALSE);
622 gtk_container_add(GTK_CONTAINER(event_box), hbox);
623
624 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, event_box);
625 dlg->v.tab.handler_id =
626 g_signal_connect(notebook, "switch-page",
627 G_CALLBACK(gui_dialog_switch_page_handler), dlg);
628 dlg->v.tab.child = vbox;
629
630 gtk_style_context_add_provider(gtk_widget_get_style_context(label),
631 GTK_STYLE_PROVIDER(dlg_tab_provider),
632 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
633 dlg->v.tab.label = label;
634 dlg->v.tab.notebook = GTK_WIDGET(notebook);
635
636 gtk_widget_add_events(event_box, GDK_BUTTON2_MOTION_MASK);
637 g_signal_connect(event_box, "button-press-event",
638 G_CALLBACK(click_on_tab_callback), dlg);
639 }
640 break;
641 }
642
643 dlg->vbox = vbox;
645
647
648 dlg->id = dialog_id_counter;
649 dialog_id_counter++;
650 dlg->return_dialog_id = -1;
651
652 g_signal_connect(vbox, "destroy",
653 G_CALLBACK(gui_dialog_destroy_handler), dlg);
654 g_signal_connect(vbox, "key_press_event",
655 G_CALLBACK(gui_dialog_key_press_handler), dlg);
656
657 g_object_set_data(G_OBJECT(vbox), "gui-dialog-data", dlg);
658}
659
660/**********************************************************************/
663static void action_widget_activated(GtkWidget *button, GtkWidget *vbox)
664{
665 struct gui_dialog *dlg =
666 g_object_get_data(G_OBJECT(vbox), "gui-dialog-data");
667 gpointer arg2 =
668 g_object_get_data(G_OBJECT(button), "gui-dialog-response-data");
669
670 gui_dialog_response(dlg, GPOINTER_TO_INT(arg2));
671}
672
673/**********************************************************************/
676static void gui_dialog_pack_button(struct gui_dialog *dlg, GtkWidget *button,
677 int response)
678{
679 gint signal_id;
680
681 fc_assert_ret(GTK_IS_BUTTON(button));
682
683 g_object_set_data(G_OBJECT(button), "gui-dialog-response-data",
684 GINT_TO_POINTER(response));
685
686 if ((signal_id = g_signal_lookup("clicked", GTK_TYPE_BUTTON))) {
687 GClosure *closure;
688
689 closure = g_cclosure_new_object(G_CALLBACK(action_widget_activated),
690 G_OBJECT(dlg->vbox));
691 g_signal_connect_closure_by_id(button, signal_id, 0, closure, FALSE);
692 }
693
694 gtk_container_add(GTK_CONTAINER(dlg->action_area), button);
695 gtk_size_group_add_widget(gui_action, button);
696 gtk_size_group_add_widget(dlg->gui_button, button);
697}
698
699/**********************************************************************/
702GtkWidget *gui_dialog_add_button(struct gui_dialog *dlg,
703 const char *icon_name,
704 const char *text, int response)
705{
706 GtkWidget *button;
707
708 button = icon_label_button_new(icon_name, text);
709 gtk_widget_set_can_default(button, TRUE);
710 gui_dialog_pack_button(dlg, button, response);
711
712 return button;
713}
714
715/**********************************************************************/
718GtkWidget *gui_dialog_add_widget(struct gui_dialog *dlg,
719 GtkWidget *widget)
720{
721 gtk_container_add(GTK_CONTAINER(dlg->action_area), widget);
722 gtk_size_group_add_widget(gui_action, widget);
723
724 return widget;
725}
726
727/**********************************************************************/
730void gui_dialog_set_default_response(struct gui_dialog *dlg, int response)
731{
732 GList *children;
733 GList *list;
734
735 children = gtk_container_get_children(GTK_CONTAINER(dlg->action_area));
736
737 for (list = children; list; list = g_list_next(list)) {
738 GtkWidget *button = list->data;
739
740 if (GTK_IS_BUTTON(button)) {
741 gpointer data = g_object_get_data(G_OBJECT(button),
742 "gui-dialog-response-data");
743
744 if (response == GPOINTER_TO_INT(data)) {
745 gtk_widget_grab_default(button);
746 }
747 }
748 }
749
750 g_list_free(children);
751}
752
753/**********************************************************************/
757 int response, bool setting)
758{
759 GList *children;
760 GList *list;
761
762 children = gtk_container_get_children(GTK_CONTAINER(dlg->action_area));
763
764 for (list = children; list; list = g_list_next(list)) {
765 GtkWidget *button = list->data;
766
767 if (GTK_IS_BUTTON(button)) {
768 gpointer data = g_object_get_data(G_OBJECT(button),
769 "gui-dialog-response-data");
770
771 if (response == GPOINTER_TO_INT(data)) {
772 gtk_widget_set_sensitive(button, setting);
773 }
774 }
775 }
776
777 g_list_free(children);
778}
779
780/**********************************************************************/
783GtkWidget *gui_dialog_get_toplevel(struct gui_dialog *dlg)
784{
785 return gtk_widget_get_toplevel(dlg->vbox);
786}
787
788/**********************************************************************/
792{
793 gtk_widget_show_all(dlg->vbox);
794
795 if (dlg->type == GUI_DIALOG_TAB) {
796 GList *children;
797 GList *list;
798 gint num_visible = 0;
799
800 children = gtk_container_get_children(GTK_CONTAINER(dlg->action_area));
801
802 for (list = children; list; list = g_list_next(list)) {
803 GtkWidget *button = list->data;
804
805 if (!GTK_IS_BUTTON(button)) {
806 num_visible++;
807 } else {
808 gpointer data = g_object_get_data(G_OBJECT(button),
809 "gui-dialog-response-data");
810 int response = GPOINTER_TO_INT(data);
811
812 if (response != GTK_RESPONSE_CLOSE
813 && response != GTK_RESPONSE_CANCEL) {
814 num_visible++;
815 } else {
816 gtk_widget_hide(button);
817 }
818 }
819 }
820 g_list_free(children);
821
822 if (num_visible == 0) {
823 gtk_widget_hide(dlg->action_area);
824 }
825 }
826}
827
828/**********************************************************************/
832{
833 fc_assert_ret(NULL != dlg);
834
835 switch (dlg->type) {
837 gtk_widget_show(dlg->v.window);
838 break;
839 case GUI_DIALOG_TAB:
840 {
841 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
842 gint current, n;
843
844 current = gtk_notebook_get_current_page(notebook);
845 n = gtk_notebook_page_num(notebook, dlg->vbox);
846
847 if (current != n) {
848 GtkWidget *label = dlg->v.tab.label;
849
850 gtk_style_context_add_class(gtk_widget_get_style_context(label),
851 "notice");
852 }
853 }
854 break;
855 }
856}
857
858/**********************************************************************/
862{
863 fc_assert_ret(NULL != dlg);
864
865 switch (dlg->type) {
867 gtk_window_present(GTK_WINDOW(dlg->v.window));
868 break;
869 case GUI_DIALOG_TAB:
870 {
871 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
872 gint n;
873
874 n = gtk_notebook_page_num(notebook, dlg->vbox);
875 gtk_notebook_set_current_page(notebook, n);
876 }
877 break;
878 }
879}
880
881/**********************************************************************/
885{
886 fc_assert_ret(NULL != dlg);
887
888 switch (dlg->type) {
890 break;
891 case GUI_DIALOG_TAB:
892 {
893 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
894 gint current, n;
895
896 current = gtk_notebook_get_current_page(notebook);
897 n = gtk_notebook_page_num(notebook, dlg->vbox);
898
899 if (current != n) {
900 GtkWidget *label = dlg->v.tab.label;
901 GtkStyleContext *context = gtk_widget_get_style_context(label);
902
903 /* Have only alert - remove notice if it exist. */
904 gtk_style_context_remove_class(context, "notice");
905 gtk_style_context_add_class(context, "alert");
906 }
907 }
908 break;
909 }
910}
911
912/**********************************************************************/
916{
917 dlg->default_width = width;
918 dlg->default_height = height;
919 switch (dlg->type) {
921 gtk_window_set_default_size(GTK_WINDOW(dlg->v.window), width, height);
922 break;
923 case GUI_DIALOG_TAB:
924 break;
925 }
926}
927
928/**********************************************************************/
931void gui_dialog_set_title(struct gui_dialog *dlg, const char *title)
932{
933 if (dlg->title) {
934 free(dlg->title);
935 }
936 dlg->title = fc_strdup(title);
937 switch (dlg->type) {
939 gtk_window_set_title(GTK_WINDOW(dlg->v.window), title);
940 break;
941 case GUI_DIALOG_TAB:
942 gtk_label_set_text_with_mnemonic(GTK_LABEL(dlg->v.tab.label), title);
943 break;
944 }
945}
946
947/**********************************************************************/
951{
952 switch (dlg->type) {
954 gtk_widget_destroy(dlg->v.window);
955 break;
956 case GUI_DIALOG_TAB:
957 {
958 gint n;
959
960 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->vbox);
961 gtk_notebook_remove_page(GTK_NOTEBOOK(dlg->v.tab.notebook), n);
962 }
963 break;
964 }
965}
966
967/**********************************************************************/
971{
972 GList *it, *it_next;
973
974 for (it = dialog_list; it; it = it_next) {
975 it_next = g_list_next(it);
976
977 gui_dialog_destroy((struct gui_dialog *)it->data);
978 }
979}
980
981/**********************************************************************/
989
990/**********************************************************************/
994 struct gui_dialog *return_dialog)
995{
996 if (return_dialog == NULL) {
997 dlg->return_dialog_id = -1;
998 } else {
999 dlg->return_dialog_id = return_dialog->id;
1000 }
1001}
1002
1003/**********************************************************************/
1006void gui_update_font(const char *font_name, const char *font_value)
1007{
1008 char *str;
1009 GtkCssProvider *provider;
1010 PangoFontDescription *desc;
1011 int size;
1012 const char *fam;
1013 const char *style;
1014 const char *weight;
1015
1016 desc = pango_font_description_from_string(font_value);
1017
1018 if (desc == NULL) {
1019 return;
1020 }
1021
1022 fam = pango_font_description_get_family(desc);
1023
1024 if (fam == NULL) {
1025 return;
1026 }
1027
1028 if (pango_font_description_get_style(desc) == PANGO_STYLE_ITALIC) {
1029 style = "\n font-style: italic;";
1030 } else {
1031 style = "";
1032 }
1033
1034 if (pango_font_description_get_weight(desc) >= 700) {
1035 weight = "\n font-weight: bold;";
1036 } else {
1037 weight = "";
1038 }
1039
1040 size = pango_font_description_get_size(desc);
1041
1042 if (size != 0) {
1043 if (pango_font_description_get_size_is_absolute(desc)) {
1044 str = g_strdup_printf("#Freeciv #%s { font-family: %s; font-size: %dpx;%s%s}",
1045 font_name, fam, size / PANGO_SCALE, style, weight);
1046 } else {
1047 str = g_strdup_printf("#Freeciv #%s { font-family: %s; font-size: %dpt;%s%s}",
1048 font_name, fam, size / PANGO_SCALE, style, weight);
1049 }
1050 } else {
1051 str = g_strdup_printf("#Freeciv #%s { font-family: %s;%s%s}",
1052 font_name, fam, style, weight);
1053 }
1054
1055 pango_font_description_free(desc);
1056
1057 provider = gtk_css_provider_new();
1058 gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
1059 str, -1, NULL);
1060 gtk_style_context_add_provider_for_screen(
1061 gtk_widget_get_screen(toplevel), GTK_STYLE_PROVIDER(provider),
1062 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1063 g_free(str);
1064}
1065
1066/**********************************************************************/
1069void gui_update_font_full(const char *font_name, const char *font_value,
1070 PangoFontDescription **font_desc)
1071{
1072 PangoFontDescription *f_desc;
1073
1074 gui_update_font(font_name, font_value);
1075
1076 f_desc = pango_font_description_from_string(font_value);
1077 pango_font_description_free(*font_desc);
1078
1079 *font_desc = f_desc;
1080}
1081
1082/**********************************************************************/
1086void disable_gobject_callback(GObject *obj, GCallback cb)
1087{
1088 gulong hid;
1089
1090 if (!obj || !cb) {
1091 return;
1092 }
1093
1094 hid = g_signal_handler_find(obj, G_SIGNAL_MATCH_FUNC,
1095 0, 0, NULL, cb, NULL);
1096 g_signal_handler_block(obj, hid);
1097}
1098
1099/**********************************************************************/
1102void enable_gobject_callback(GObject *obj, GCallback cb)
1103{
1104 gulong hid;
1105
1106 if (!obj || !cb) {
1107 return;
1108 }
1109
1110 hid = g_signal_handler_find(obj, G_SIGNAL_MATCH_FUNC,
1111 0, 0, NULL, cb, NULL);
1112 g_signal_handler_unblock(obj, hid);
1113}
1114
1115/**********************************************************************/
1119GtkTreeViewColumn *add_treeview_column(GtkWidget *view, const char *title,
1120 GType gtype, int model_index)
1121{
1122 GtkTreeViewColumn *col;
1123 GtkCellRenderer *rend;
1124 const char *attr;
1125
1126 fc_assert_ret_val(view != NULL, NULL);
1127 fc_assert_ret_val(GTK_IS_TREE_VIEW(view), NULL);
1128 fc_assert_ret_val(title != NULL, NULL);
1129
1130 if (gtype == G_TYPE_BOOLEAN) {
1131 rend = gtk_cell_renderer_toggle_new();
1132 attr = "active";
1133 } else if (gtype == GDK_TYPE_PIXBUF) {
1134 rend = gtk_cell_renderer_pixbuf_new();
1135 attr = "pixbuf";
1136 } else {
1137 rend = gtk_cell_renderer_text_new();
1138 attr = "text";
1139 }
1140
1141 col = gtk_tree_view_column_new_with_attributes(title, rend, attr,
1142 model_index, NULL);
1143 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1144
1145 return col;
1146}
1147
1148/**********************************************************************/
1152{
1153 dlg_tab_provider = gtk_css_provider_new();
1154
1155 gtk_css_provider_load_from_data(dlg_tab_provider,
1156 ".alert {\n"
1157 "color: rgba(255, 0, 0, 255);\n"
1158 "}\n"
1159 ".notice {\n"
1160 "color: rgba(0, 0, 255, 255);\n"
1161 "}\n",
1162 -1, NULL);
1163}
#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
static struct fc_sockaddr_list * list
Definition clinet.c:102
#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 gui_dialog_set_default_response(struct gui_dialog *dlg, int response)
Definition gui_stuff.c:733
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
GtkWidget * gui_dialog_add_widget(struct gui_dialog *dlg, GtkWidget *widget)
Definition gui_stuff.c:721
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 set_relative_window_position(GtkWindow *ref, GtkWindow *w, int px, int py)
Definition gui_stuff.c:58
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
GtkWidget * gtk_aux_menu_bar_new(void)
Definition gui_stuff.c:249
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
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_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 * action_area
Definition gui_stuff.h:72
union gui_dialog::@149 v
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