Freeciv-3.3: /fast/freeciv/nightly/main/client/gui-gtk-5.0/gui_stuff.c Source File

Freeciv-3.3

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-5.0 */
36#include "colors.h"
37#include "gui_main.h"
38
39#include "gui_stuff.h"
40
41
42 static GList *dialog_list;
43
44 static GtkSizeGroup *gui_action;
45
46 static GtkCssProvider *dlg_tab_provider = NULL;
47
48
49/**********************************************************************/
52 void gtk_expose_now(GtkWidget *w)
53{
54 gtk_widget_queue_draw(w);
55}
56
57/**********************************************************************/
63 GtkWidget *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/**********************************************************************/
85 void gtk_stockbutton_set_label(GtkWidget *button, const gchar *label_text)
86{
87 gtk_button_set_label(GTK_BUTTON(button), label_text);
88}
89
90/**********************************************************************/
100 void 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/**********************************************************************/
116 void 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/**********************************************************************/
125 gboolean itree_end(ITree *it)
126{
127 return it->end;
128}
129
130/**********************************************************************/
133 void itree_next(ITree *it)
134{
135 it->end = !gtk_tree_model_iter_next(it->model, &it->it);
136}
137
138/**********************************************************************/
141 void 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/**********************************************************************/
153 void 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/**********************************************************************/
165 void 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/**********************************************************************/
178 gboolean itree_is_selected(GtkTreeSelection *selection, ITree *it)
179{
180 return gtk_tree_selection_iter_is_selected(selection, &it->it);
181}
182
183/**********************************************************************/
186 void itree_select(GtkTreeSelection *selection, ITree *it)
187{
188 gtk_tree_selection_select_iter(selection, &it->it);
189}
190
191/**********************************************************************/
194 void itree_unselect(GtkTreeSelection *selection, ITree *it)
195{
196 gtk_tree_selection_unselect_iter(selection, &it->it);
197}
198
199/**********************************************************************/
203 gint 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
219 return row;
220}
221
222/**********************************************************************/
225 void gtk_tree_view_focus(GtkTreeView *view)
226{
227 GtkTreeModel *model;
228 GtkTreePath *path;
229 GtkTreeIter iter;
230
231 if ((model = gtk_tree_view_get_model(view))
232 && gtk_tree_model_get_iter_first(model, &iter)
233 && (path = gtk_tree_model_get_path(model, &iter))) {
234 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
235 gtk_tree_path_free(path);
236 gtk_widget_grab_focus(GTK_WIDGET(view));
237 }
238}
239
240/**********************************************************************/
244 GtkWidget *aux_menu_new(void)
245{
246 GtkWidget *menu_button = gtk_menu_button_new();
247
248 return menu_button;
249}
250
251/**********************************************************************/
254 static void close_callback(GtkDialog *dialog, gpointer data)
255{
256 gtk_window_destroy(GTK_WINDOW(dialog));
257}
258
259/**********************************************************************/
264 void setup_dialog(GtkWidget *shell, GtkWidget *parent)
265{
266 if (GTK_IS_WINDOW(shell)
267 && (GUI_GTK_OPTION(dialogs_on_top) || GUI_GTK_OPTION(fullscreen))) {
268 gtk_window_set_transient_for(GTK_WINDOW(shell),
269 GTK_WINDOW(parent));
270 }
271
272 /* Close dialog window on Escape keypress. */
273 if (GTK_IS_DIALOG(shell)) {
274 GtkEventController *controller;
275
276 controller = GTK_EVENT_CONTROLLER(gtk_event_controller_focus_new());
277 g_signal_connect(controller, "enter",
278 G_CALLBACK(fc_gained_focus), NULL);
279 g_signal_connect(controller, "leave",
280 G_CALLBACK(fc_lost_focus), NULL);
281 gtk_widget_add_controller(shell, controller);
282
283 g_signal_connect_after(shell, "close", G_CALLBACK(close_callback), shell);
284 }
285}
286
287/**********************************************************************/
290 static void gui_dialog_response(struct gui_dialog *dlg, int response)
291{
292 if (dlg->response_callback) {
293 (*dlg->response_callback)(dlg, response, dlg->user_data);
294 }
295}
296
297/**********************************************************************/
300 static void gui_dialog_destroyed(struct gui_dialog *dlg, int response,
301 gpointer data)
302{
303 gui_dialog_destroy(dlg);
304}
305
306/**********************************************************************/
309 static void gui_dialog_destroy_handler(GtkWidget *w, struct gui_dialog *dlg)
310{
311 if (dlg->type == GUI_DIALOG_TAB) {
312 GtkWidget *notebook = dlg->v.tab.notebook;
313 gulong handler_id = dlg->v.tab.handler_id;
314
315 g_signal_handler_disconnect(notebook, handler_id);
316 }
317
318 g_object_unref(dlg->gui_button);
319
320 if (*(dlg->source)) {
321 *(dlg->source) = NULL;
322 }
323
324 dialog_list = g_list_remove(dialog_list, dlg);
325
326 /* Raise the return dialog set by gui_dialog_set_return_dialog() */
327 if (dlg->return_dialog_id != -1) {
328 GList *it;
329
330 for (it = dialog_list; it; it = g_list_next(it)) {
331 struct gui_dialog *adialog = (struct gui_dialog *)it->data;
332
333 if (adialog->id == dlg->return_dialog_id) {
334 gui_dialog_raise(adialog);
335 break;
336 }
337 }
338 }
339
340 if (dlg->title) {
341 free(dlg->title);
342 }
343
344 free(dlg);
345}
346
347/**********************************************************************/
352 static gint gui_dialog_delete_handler(GtkWidget *widget, gpointer data)
353{
354 struct gui_dialog *dlg = data;
355
356 /* emit response signal. */
357 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
358
359 /* do the destroy by default. */
360 return FALSE;
361}
362
363/**********************************************************************/
368 static gint gui_dialog_delete_tab_handler(struct gui_dialog* dlg)
369{
370 GtkWidget* notebook;
371 int n;
372
373 notebook = dlg->v.tab.notebook;
374 n = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
375 if (gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), n)
376 != dlg->v.tab.child) {
377 gui_dialog_set_return_dialog(dlg, NULL);
378 }
379
380 /* Emit response signal. */
381 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
382
383 /* Do the destroy by default. */
384 return FALSE;
385}
386
387
388/**********************************************************************/
391 static gboolean gui_dialog_key_press_handler(GtkEventControllerKey *controller,
392 guint keyval, guint keycode,
393 GdkModifierType state,
394 gpointer data)
395{
396 struct gui_dialog *dlg = (struct gui_dialog *)data;
397
398 if (keyval == GDK_KEY_Escape
399 || ((state & GDK_CONTROL_MASK) && keyval == GDK_KEY_w)) {
400 /* Emit response signal. */
401 gui_dialog_response(dlg, GTK_RESPONSE_DELETE_EVENT);
402 }
403
404 /* Propagate event further. */
405 return FALSE;
406}
407
408/**********************************************************************/
411 static void gui_dialog_switch_page_handler(GtkNotebook *notebook,
412 GtkWidget *page,
413 guint num,
414 struct gui_dialog *dlg)
415{
416 gint n;
417
418 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->grid);
419
420 if (n == num) {
421 gtk_widget_remove_css_class(dlg->v.tab.label, "alert");
422 gtk_widget_remove_css_class(dlg->v.tab.label, "notice");
423 }
424}
425
426/**********************************************************************/
429 static void gui_dialog_detach(struct gui_dialog *dlg)
430{
431 gint n;
432 GtkWidget *window, *notebook;
433 gulong handler_id;
434
435 if (dlg->type != GUI_DIALOG_TAB) {
436 return;
437 }
438 dlg->type = GUI_DIALOG_WINDOW;
439
440 /* Create a new reference to the main widget, so it won't be
441 * destroyed in gtk_notebook_remove_page() */
442 g_object_ref(dlg->grid);
443
444 /* Remove widget from the notebook */
445 notebook = dlg->v.tab.notebook;
446 handler_id = dlg->v.tab.handler_id;
447 g_signal_handler_disconnect(notebook, handler_id);
448
449 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->grid);
450 gtk_notebook_remove_page(GTK_NOTEBOOK(dlg->v.tab.notebook), n);
451
452
453 /* Create window and put the widget inside */
454 window = gtk_window_new();
455 gtk_window_set_title(GTK_WINDOW(window), dlg->title);
456 setup_dialog(window, toplevel);
457
458 gtk_window_set_child(GTK_WINDOW(window), dlg->grid);
459 dlg->v.window = window;
460 g_signal_connect(window, "close-request",
461 G_CALLBACK(gui_dialog_delete_handler), dlg);
462
463 gtk_window_set_default_size(GTK_WINDOW(dlg->v.window),
464 dlg->default_width,
465 dlg->default_height);
466 gtk_widget_set_visible(window, TRUE);
467}
468
469/**********************************************************************/
472 static gboolean click_on_tab_callback(GtkGestureClick *gesture,
473 int n_press,
474 double x, double y, gpointer data)
475{
476 if (n_press == 2) {
477 gui_dialog_detach((struct gui_dialog *)data);
478 }
479
480 return TRUE;
481}
482
483/**********************************************************************/
491 void gui_dialog_new(struct gui_dialog **pdlg, GtkNotebook *notebook,
492 gpointer user_data, bool check_top)
493{
494 struct gui_dialog *dlg;
495 GtkWidget *action_area;
496 static int dialog_id_counter;
497 GtkEventController *controller;
498
499 dlg = fc_malloc(sizeof(*dlg));
500 dialog_list = g_list_prepend(dialog_list, dlg);
501
502 dlg->source = pdlg;
503 *pdlg = dlg;
504 dlg->user_data = user_data;
505 dlg->title = NULL;
506
507 dlg->default_width = 200;
508 dlg->default_height = 300;
509
510 if (GUI_GTK_OPTION(enable_tabs)) {
511 dlg->type = GUI_DIALOG_TAB;
512 } else {
513 dlg->type = GUI_DIALOG_WINDOW;
514 }
515
516 if (!gui_action) {
517 gui_action = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL);
518 }
519 dlg->gui_button = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
520
521 dlg->grid = gtk_grid_new();
522 dlg->content_counter = 0;
523 if (GUI_GTK_OPTION(enable_tabs)
524 && (check_top && notebook != GTK_NOTEBOOK(top_notebook))
525 && !GUI_GTK_OPTION(small_display_layout)) {
526 /* We expect this to be short (as opposed to tall); maximise usable
527 * height by putting buttons down the right hand side */
528 action_area = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
529 dlg->vertical_content = FALSE;
530 } else {
531 /* We expect this to be reasonably tall; maximise usable width by
532 * putting buttons along the bottom */
533 action_area = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
534 gtk_orientable_set_orientation(GTK_ORIENTABLE(dlg->grid),
535 GTK_ORIENTATION_VERTICAL);
536 dlg->vertical_content = TRUE;
537 }
538
539 gtk_widget_set_visible(dlg->grid, TRUE);
540 gui_dialog_add_content_widget(dlg, action_area);
541 gtk_widget_set_visible(action_area, TRUE);
542
543 gtk_widget_set_margin_start(dlg->grid, 2);
544 gtk_widget_set_margin_end(dlg->grid, 2);
545 gtk_widget_set_margin_top(dlg->grid, 2);
546 gtk_widget_set_margin_bottom(dlg->grid, 2);
547
548 gtk_widget_set_margin_start(action_area, 2);
549 gtk_widget_set_margin_end(action_area, 2);
550 gtk_widget_set_margin_top(action_area, 2);
551 gtk_widget_set_margin_bottom(action_area, 2);
552
553 switch (dlg->type) {
554 case GUI_DIALOG_WINDOW:
555 {
556 GtkWidget *window;
557
558 window = gtk_window_new();
559 gtk_widget_set_name(window, "Freeciv");
560 setup_dialog(window, toplevel);
561
562 gtk_window_set_child(GTK_WINDOW(window), dlg->grid);
563 dlg->v.window = window;
564 g_signal_connect(window, "close-request",
565 G_CALLBACK(gui_dialog_delete_handler), dlg);
566
567 }
568 break;
569 case GUI_DIALOG_TAB:
570 {
571 GtkWidget *hbox, *label, *button;
572 gchar *buf;
573
574 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
575
576 label = gtk_label_new(NULL);
577 gtk_widget_set_halign(label, GTK_ALIGN_START);
578 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
579 gtk_widget_set_margin_start(label, 4);
580 gtk_widget_set_margin_end(label, 4);
581 gtk_widget_set_margin_top(label, 0);
582 gtk_widget_set_margin_bottom(label, 0);
583 gtk_box_append(GTK_BOX(hbox), label);
584
585 button = gtk_button_new();
586 gtk_button_set_has_frame(GTK_BUTTON(button), FALSE);
587 g_signal_connect_swapped(button, "clicked",
588 G_CALLBACK(gui_dialog_delete_tab_handler), dlg);
589
590 buf = g_strdup_printf(_("Close Tab:\n%s"), _("Ctrl+W"));
591 gtk_widget_set_tooltip_text(button, buf);
592 g_free(buf);
593
594 gtk_button_set_icon_name(GTK_BUTTON(button), "window-close");
595
596 gtk_box_append(GTK_BOX(hbox), button);
597
598 gtk_widget_set_visible(hbox, TRUE);
599
600 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dlg->grid, hbox);
601 dlg->v.tab.handler_id
602 = g_signal_connect(notebook, "switch-page",
603 G_CALLBACK(gui_dialog_switch_page_handler), dlg);
604 dlg->v.tab.child = dlg->grid;
605
606 dlg->v.tab.label = label;
607 dlg->v.tab.notebook = GTK_WIDGET(notebook);
608
609 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
610 g_signal_connect(controller, "pressed",
611 G_CALLBACK(click_on_tab_callback), dlg);
612 gtk_widget_add_controller(hbox, controller);
613 }
614 break;
615 }
616
617 dlg->actions = action_area;
618
619 dlg->response_callback = gui_dialog_destroyed;
620
621 dlg->id = dialog_id_counter;
622 dialog_id_counter++;
623 dlg->return_dialog_id = -1;
624
625 g_signal_connect(dlg->grid, "destroy",
626 G_CALLBACK(gui_dialog_destroy_handler), dlg);
627 controller = gtk_event_controller_key_new();
628 g_signal_connect(controller, "key-pressed",
629 G_CALLBACK(gui_dialog_key_press_handler), dlg);
630 gtk_widget_add_controller(dlg->grid, controller);
631
632 g_object_set_data(G_OBJECT(dlg->grid), "gui-dialog-data", dlg);
633}
634
635/**********************************************************************/
638 static void action_widget_activated(GtkWidget *button, GtkWidget *vbox)
639{
640 struct gui_dialog *dlg =
641 g_object_get_data(G_OBJECT(vbox), "gui-dialog-data");
642 gpointer arg2 =
643 g_object_get_data(G_OBJECT(button), "gui-dialog-response-data");
644
645 gui_dialog_response(dlg, GPOINTER_TO_INT(arg2));
646}
647
648/**********************************************************************/
651 static void gui_dialog_pack_button(struct gui_dialog *dlg, GtkWidget *button,
652 int response)
653{
654 gint signal_id;
655
656 fc_assert_ret(GTK_IS_BUTTON(button));
657
658 g_object_set_data(G_OBJECT(button), "gui-dialog-response-data",
659 GINT_TO_POINTER(response));
660
661 if ((signal_id = g_signal_lookup("clicked", GTK_TYPE_BUTTON))) {
662 GClosure *closure;
663
664 closure = g_cclosure_new_object(G_CALLBACK(action_widget_activated),
665 G_OBJECT(dlg->grid));
666 g_signal_connect_closure_by_id(button, signal_id, 0, closure, FALSE);
667 }
668
669 gui_dialog_add_action_widget(dlg, button);
670 gtk_size_group_add_widget(dlg->gui_button, button);
671}
672
673/**********************************************************************/
676 GtkWidget *gui_dialog_add_button(struct gui_dialog *dlg,
677 const char *icon_name,
678 const char *text, int response)
679{
680 GtkWidget *button;
681
682 button = icon_label_button_new(icon_name, text);
683 gui_dialog_pack_button(dlg, button, response);
684
685 return button;
686}
687
688/**********************************************************************/
691 GtkWidget *gui_dialog_add_action_widget(struct gui_dialog *dlg,
692 GtkWidget *widget)
693{
694 gtk_box_append(GTK_BOX(dlg->actions), widget);
695
696 gtk_size_group_add_widget(gui_action, widget);
697
698 return widget;
699}
700
701/**********************************************************************/
704 void gui_dialog_set_response_sensitive(struct gui_dialog *dlg,
705 int response, bool setting)
706{
707 GtkWidget *iter;
708
709 for (iter = gtk_widget_get_first_child(dlg->actions);
710 iter != NULL;
711 iter = gtk_widget_get_next_sibling(iter)) {
712 if (GTK_IS_BUTTON(iter)) {
713 gpointer data = g_object_get_data(G_OBJECT(iter),
714 "gui-dialog-response-data");
715
716 if (response == GPOINTER_TO_INT(data)) {
717 gtk_widget_set_sensitive(iter, setting);
718 }
719 }
720 }
721}
722
723/**********************************************************************/
726 GtkWidget *gui_dialog_get_toplevel(struct gui_dialog *dlg)
727{
728 return gtk_widget_get_ancestor(dlg->grid, GTK_TYPE_WINDOW);
729}
730
731/**********************************************************************/
734 void gui_dialog_show_all(struct gui_dialog *dlg)
735{
736 gtk_widget_set_visible(dlg->grid, TRUE);
737
738 if (dlg->type == GUI_DIALOG_TAB) {
739 GtkWidget *iter;
740 gint num_visible = 0;
741
742 for (iter = gtk_widget_get_first_child(dlg->actions);
743 iter != NULL;
744 iter = gtk_widget_get_next_sibling(iter)) {
745 if (!GTK_IS_BUTTON(iter)) {
746 num_visible++;
747 } else {
748 gpointer data = g_object_get_data(G_OBJECT(iter),
749 "gui-dialog-response-data");
750 int response = GPOINTER_TO_INT(data);
751
752 if (response != GTK_RESPONSE_CLOSE
753 && response != GTK_RESPONSE_CANCEL) {
754 num_visible++;
755 } else {
756 gtk_widget_set_visible(iter, FALSE);
757 }
758 }
759 }
760
761 if (num_visible == 0) {
762 gtk_widget_set_visible(dlg->actions, FALSE);
763 }
764 }
765}
766
767/**********************************************************************/
770 void gui_dialog_present(struct gui_dialog *dlg)
771{
772 fc_assert_ret(nullptr != dlg);
773
774 switch (dlg->type) {
775 case GUI_DIALOG_WINDOW:
776 gtk_widget_set_visible(dlg->v.window, TRUE);
777 break;
778 case GUI_DIALOG_TAB:
779 {
780 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
781 gint current, n;
782
783 current = gtk_notebook_get_current_page(notebook);
784 n = gtk_notebook_page_num(notebook, dlg->grid);
785
786 if (current != n) {
787 gtk_widget_add_css_class(dlg->v.tab.label, "notice");
788 }
789 }
790 break;
791 }
792}
793
794/**********************************************************************/
797 void gui_dialog_raise(struct gui_dialog *dlg)
798{
799 fc_assert_ret(NULL != dlg);
800
801 switch (dlg->type) {
802 case GUI_DIALOG_WINDOW:
803 gtk_window_present(GTK_WINDOW(dlg->v.window));
804 break;
805 case GUI_DIALOG_TAB:
806 {
807 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
808 gint n;
809
810 n = gtk_notebook_page_num(notebook, dlg->grid);
811 gtk_notebook_set_current_page(notebook, n);
812 }
813 break;
814 }
815}
816
817/**********************************************************************/
820 void gui_dialog_alert(struct gui_dialog *dlg)
821{
822 fc_assert_ret(NULL != dlg);
823
824 switch (dlg->type) {
825 case GUI_DIALOG_WINDOW:
826 break;
827 case GUI_DIALOG_TAB:
828 {
829 GtkNotebook *notebook = GTK_NOTEBOOK(dlg->v.tab.notebook);
830 gint current, n;
831
832 current = gtk_notebook_get_current_page(notebook);
833 n = gtk_notebook_page_num(notebook, dlg->grid);
834
835 if (current != n) {
836 /* Have only alert - remove notice if it exist. */
837 gtk_widget_remove_css_class(dlg->v.tab.label, "notice");
838 gtk_widget_add_css_class(dlg->v.tab.label, "alert");
839 }
840 }
841 break;
842 }
843}
844
845/**********************************************************************/
848 void gui_dialog_set_default_size(struct gui_dialog *dlg, int width, int height)
849{
850 dlg->default_width = width;
851 dlg->default_height = height;
852 switch (dlg->type) {
853 case GUI_DIALOG_WINDOW:
854 gtk_window_set_default_size(GTK_WINDOW(dlg->v.window), width, height);
855 break;
856 case GUI_DIALOG_TAB:
857 break;
858 }
859}
860
861/**********************************************************************/
864 void gui_dialog_set_title(struct gui_dialog *dlg, const char *title)
865{
866 if (dlg->title) {
867 free(dlg->title);
868 }
869 dlg->title = fc_strdup(title);
870 switch (dlg->type) {
871 case GUI_DIALOG_WINDOW:
872 gtk_window_set_title(GTK_WINDOW(dlg->v.window), title);
873 break;
874 case GUI_DIALOG_TAB:
875 gtk_label_set_text_with_mnemonic(GTK_LABEL(dlg->v.tab.label), title);
876 break;
877 }
878}
879
880/**********************************************************************/
883 void gui_dialog_destroy(struct gui_dialog *dlg)
884{
885 switch (dlg->type) {
886 case GUI_DIALOG_WINDOW:
887 gtk_window_destroy(GTK_WINDOW(dlg->v.window));
888 break;
889 case GUI_DIALOG_TAB:
890 {
891 gint n;
892
893 n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->grid);
894 gtk_notebook_remove_page(GTK_NOTEBOOK(dlg->v.tab.notebook), n);
895 }
896 break;
897 }
898}
899
900/**********************************************************************/
903 void gui_dialog_destroy_all(void)
904{
905 GList *it, *it_next;
906
907 for (it = dialog_list; it; it = it_next) {
908 it_next = g_list_next(it);
909
910 gui_dialog_destroy((struct gui_dialog *)it->data);
911 }
912}
913
914/**********************************************************************/
917 void gui_dialog_response_set_callback(struct gui_dialog *dlg,
918 GUI_DIALOG_RESPONSE_FUN fun)
919{
920 dlg->response_callback = fun;
921}
922
923/**********************************************************************/
926 void gui_dialog_set_return_dialog(struct gui_dialog *dlg,
927 struct gui_dialog *return_dialog)
928{
929 if (return_dialog == NULL) {
930 dlg->return_dialog_id = -1;
931 } else {
932 dlg->return_dialog_id = return_dialog->id;
933 }
934}
935
936/**********************************************************************/
939 void gui_update_font(const char *font_name, const char *font_value)
940{
941 char *str;
942 GtkCssProvider *provider;
943 PangoFontDescription *desc;
944 int size;
945 const char *fam;
946 const char *style;
947 const char *weight;
948
949 desc = pango_font_description_from_string(font_value);
950
951 if (desc == NULL) {
952 return;
953 }
954
955 fam = pango_font_description_get_family(desc);
956
957 if (fam == NULL) {
958 return;
959 }
960
961 if (pango_font_description_get_style(desc) == PANGO_STYLE_ITALIC) {
962 style = "\n font-style: italic;";
963 } else {
964 style = "";
965 }
966
967 if (pango_font_description_get_weight(desc) >= 700) {
968 weight = "\n font-weight: bold;";
969 } else {
970 weight = "";
971 }
972
973 size = pango_font_description_get_size(desc);
974
975 if (size != 0) {
976 if (pango_font_description_get_size_is_absolute(desc)) {
977 str = g_strdup_printf("#Freeciv #%s { font-family: %s; font-size: %dpx;%s%s}",
978 font_name, fam, size / PANGO_SCALE, style, weight);
979 } else {
980 str = g_strdup_printf("#Freeciv #%s { font-family: %s; font-size: %dpt;%s%s}",
981 font_name, fam, size / PANGO_SCALE, style, weight);
982 }
983 } else {
984 str = g_strdup_printf("#Freeciv #%s { font-family: %s;%s%s}",
985 font_name, fam, style, weight);
986 }
987
988 pango_font_description_free(desc);
989
990 provider = gtk_css_provider_new();
991 gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
992 str, -1);
993 gtk_style_context_add_provider_for_display(
994 gtk_widget_get_display(toplevel), GTK_STYLE_PROVIDER(provider),
995 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
996 g_free(str);
997}
998
999/**********************************************************************/
1002 void gui_update_font_full(const char *font_name, const char *font_value,
1003 PangoFontDescription **font_desc)
1004{
1005 PangoFontDescription *f_desc;
1006
1007 gui_update_font(font_name, font_value);
1008
1009 f_desc = pango_font_description_from_string(font_value);
1010 pango_font_description_free(*font_desc);
1011
1012 *font_desc = f_desc;
1013}
1014
1015/**********************************************************************/
1019 void disable_gobject_callback(GObject *obj, GCallback cb)
1020{
1021 gulong hid;
1022
1023 if (!obj || !cb) {
1024 return;
1025 }
1026
1027 hid = g_signal_handler_find(obj, G_SIGNAL_MATCH_FUNC,
1028 0, 0, NULL, cb, NULL);
1029 g_signal_handler_block(obj, hid);
1030}
1031
1032/**********************************************************************/
1035 void enable_gobject_callback(GObject *obj, GCallback cb)
1036{
1037 gulong hid;
1038
1039 if (!obj || !cb) {
1040 return;
1041 }
1042
1043 hid = g_signal_handler_find(obj, G_SIGNAL_MATCH_FUNC,
1044 0, 0, NULL, cb, NULL);
1045 g_signal_handler_unblock(obj, hid);
1046}
1047
1048/**********************************************************************/
1052 GtkTreeViewColumn *add_treeview_column(GtkWidget *view, const char *title,
1053 GType gtype, int model_index)
1054{
1055 GtkTreeViewColumn *col;
1056 GtkCellRenderer *rend;
1057 const char *attr;
1058
1059 fc_assert_ret_val(view != NULL, NULL);
1060 fc_assert_ret_val(GTK_IS_TREE_VIEW(view), NULL);
1061 fc_assert_ret_val(title != NULL, NULL);
1062
1063 if (gtype == G_TYPE_BOOLEAN) {
1064 rend = gtk_cell_renderer_toggle_new();
1065 attr = "active";
1066 } else if (gtype == GDK_TYPE_PIXBUF) {
1067 rend = gtk_cell_renderer_pixbuf_new();
1068 attr = "pixbuf";
1069 } else {
1070 rend = gtk_cell_renderer_text_new();
1071 attr = "text";
1072 }
1073
1074 col = gtk_tree_view_column_new_with_attributes(title, rend, attr,
1075 model_index, NULL);
1076 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1077
1078 return col;
1079}
1080
1081/**********************************************************************/
1084 void dlg_tab_provider_prepare(void)
1085{
1086 dlg_tab_provider = gtk_css_provider_new();
1087
1088 gtk_css_provider_load_from_data(dlg_tab_provider,
1089 ".alert {\n"
1090 "color: rgba(255, 0, 0, 255);\n"
1091 "}\n"
1092 ".notice {\n"
1093 "color: rgba(0, 0, 255, 255);\n"
1094 "}\n",
1095 -1);
1096
1097 gtk_style_context_add_provider_for_display(
1098 gtk_widget_get_display(toplevel),
1099 GTK_STYLE_PROVIDER(dlg_tab_provider),
1100 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1101}
1102
1103/**********************************************************************/
1106 void gui_dialog_add_content_widget(struct gui_dialog *dlg, GtkWidget *wdg)
1107{
1108 if (dlg->vertical_content) {
1109 gtk_grid_attach(GTK_GRID(dlg->grid), wdg,
1110 0, dlg->content_counter++, 1, 1);
1111 } else {
1112 gtk_grid_attach(GTK_GRID(dlg->grid), wdg,
1113 dlg->content_counter++, 0, 1, 1);
1114 }
1115}
1116
1117struct blocking_dialog_data {
1118 GMainLoop *loop;
1119 gint response;
1120};
1121
1122/**********************************************************************/
1125 static void blocking_dialog_response(GtkWidget *dlg, gint response, void *data)
1126{
1127 struct blocking_dialog_data *bd_data = (struct blocking_dialog_data *)data;
1128
1129 bd_data->response = response;
1130
1131 g_main_loop_quit(bd_data->loop);
1132}
1133
1134/**********************************************************************/
1137 gint blocking_dialog(GtkWidget *dlg)
1138{
1139 struct blocking_dialog_data data;
1140 GMainLoop *dlg_loop;
1141
1142 gtk_widget_set_visible(dlg, TRUE);
1143 dlg_loop = g_main_loop_new(nullptr, FALSE);
1144 data.loop = dlg_loop;
1145 g_signal_connect(dlg, "response", G_CALLBACK(blocking_dialog_response),
1146 &data);
1147
1148 g_main_loop_run(dlg_loop);
1149
1150 return data.response;
1151}
1152
1153/**********************************************************************/
1156 void widget_destroyed(GtkWidget *wdg, void *data)
1157{
1158 *(GtkWidget **)data = NULL;
1159}
1160
1161/**********************************************************************/
1165 GtkWidget *widget_get_child(GtkWidget *wdg)
1166{
1167 return gtk_widget_get_first_child(wdg);
1168}
1169
1170/**********************************************************************/
1173 void alert_close_response(GObject *dialog, GAsyncResult *result,
1174 gpointer data)
1175{
1176 gtk_alert_dialog_choose_finish(GTK_ALERT_DIALOG(dialog), result, NULL);
1177}
str
#define str
Definition astring.c:76
n
#define n
Definition astring.c:77
height
struct canvas int int struct sprite int int int int height
Definition canvas_g.h:44
width
struct canvas int int struct sprite int int int width
Definition canvas_g.h:44
incite_cost
char * incite_cost
Definition comments.c:74
fcintl.h
Q_
#define Q_(String)
Definition fcintl.h:70
_
#define _(String)
Definition fcintl.h:67
top_notebook
GtkWidget * top_notebook
Definition gui_main.c:129
fc_lost_focus
gboolean fc_lost_focus(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition gui_main.c:758
fc_gained_focus
gboolean fc_gained_focus(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition gui_main.c:768
toplevel
GtkWidget * toplevel
Definition gui_main.c:125
GUI_GTK_OPTION
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
gtk_tree_view_focus
void gtk_tree_view_focus(GtkTreeView *view)
Definition gui_stuff.c:236
gui_dialog_destroy
void gui_dialog_destroy(struct gui_dialog *dlg)
Definition gui_stuff.c:954
gui_dialog_pack_button
static void gui_dialog_pack_button(struct gui_dialog *dlg, GtkWidget *button, int response)
Definition gui_stuff.c:680
gui_dialog_present
void gui_dialog_present(struct gui_dialog *dlg)
Definition gui_stuff.c:835
gui_dialog_switch_page_handler
static void gui_dialog_switch_page_handler(GtkNotebook *notebook, GtkWidget *page, guint num, struct gui_dialog *dlg)
Definition gui_stuff.c:431
gtk_stockbutton_set_label
void gtk_stockbutton_set_label(GtkWidget *button, const gchar *label_text)
Definition gui_stuff.c:96
dlg_tab_provider
static GtkCssProvider * dlg_tab_provider
Definition gui_stuff.c:46
itree_get
void itree_get(ITree *it,...)
Definition gui_stuff.c:164
itree_set
void itree_set(ITree *it,...)
Definition gui_stuff.c:152
gui_dialog_raise
void gui_dialog_raise(struct gui_dialog *dlg)
Definition gui_stuff.c:865
gui_dialog_new
void gui_dialog_new(struct gui_dialog **pdlg, GtkNotebook *notebook, gpointer user_data, bool check_top)
Definition gui_stuff.c:517
disable_gobject_callback
void disable_gobject_callback(GObject *obj, GCallback cb)
Definition gui_stuff.c:1090
gtk_tree_selection_get_row
gint gtk_tree_selection_get_row(GtkTreeSelection *selection)
Definition gui_stuff.c:215
gui_dialog_set_return_dialog
void gui_dialog_set_return_dialog(struct gui_dialog *dlg, struct gui_dialog *return_dialog)
Definition gui_stuff.c:997
dlg_tab_provider_prepare
void dlg_tab_provider_prepare(void)
Definition gui_stuff.c:1155
gui_dialog_response_set_callback
void gui_dialog_response_set_callback(struct gui_dialog *dlg, GUI_DIALOG_RESPONSE_FUN fun)
Definition gui_stuff.c:988
gui_action
static GtkSizeGroup * gui_action
Definition gui_stuff.c:44
itree_begin
void itree_begin(GtkTreeModel *model, ITree *it)
Definition gui_stuff.c:127
gui_dialog_destroyed
static void gui_dialog_destroyed(struct gui_dialog *dlg, int response, gpointer data)
Definition gui_stuff.c:322
action_widget_activated
static void action_widget_activated(GtkWidget *button, GtkWidget *vbox)
Definition gui_stuff.c:667
itree_unselect
void itree_unselect(GtkTreeSelection *selection, ITree *it)
Definition gui_stuff.c:206
enable_gobject_callback
void enable_gobject_callback(GObject *obj, GCallback cb)
Definition gui_stuff.c:1106
gui_dialog_detach
static void gui_dialog_detach(struct gui_dialog *dlg)
Definition gui_stuff.c:451
gui_dialog_show_all
void gui_dialog_show_all(struct gui_dialog *dlg)
Definition gui_stuff.c:795
gui_dialog_key_press_handler
static gboolean gui_dialog_key_press_handler(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition gui_stuff.c:413
gui_dialog_delete_handler
static gint gui_dialog_delete_handler(GtkWidget *widget, GdkEventAny *ev, gpointer data)
Definition gui_stuff.c:374
itree_select
void itree_select(GtkTreeSelection *selection, ITree *it)
Definition gui_stuff.c:198
gui_dialog_set_title
void gui_dialog_set_title(struct gui_dialog *dlg, const char *title)
Definition gui_stuff.c:935
close_callback
static void close_callback(GtkDialog *dialog, gpointer data)
Definition gui_stuff.c:277
gui_dialog_set_default_size
void gui_dialog_set_default_size(struct gui_dialog *dlg, int width, int height)
Definition gui_stuff.c:919
icon_label_button_new
GtkWidget * icon_label_button_new(const gchar *icon_name, const gchar *label_text)
Definition gui_stuff.c:76
gui_dialog_alert
void gui_dialog_alert(struct gui_dialog *dlg)
Definition gui_stuff.c:888
add_treeview_column
GtkTreeViewColumn * add_treeview_column(GtkWidget *view, const char *title, GType gtype, int model_index)
Definition gui_stuff.c:1123
gui_dialog_destroy_handler
static void gui_dialog_destroy_handler(GtkWidget *w, struct gui_dialog *dlg)
Definition gui_stuff.c:331
tstore_append
void tstore_append(GtkTreeStore *store, ITree *it, ITree *parent)
Definition gui_stuff.c:176
gui_dialog_delete_tab_handler
static gint gui_dialog_delete_tab_handler(struct gui_dialog *dlg)
Definition gui_stuff.c:391
itree_next
void itree_next(ITree *it)
Definition gui_stuff.c:144
gui_dialog_destroy_all
void gui_dialog_destroy_all(void)
Definition gui_stuff.c:974
click_on_tab_callback
static gboolean click_on_tab_callback(GtkWidget *w, GdkEventButton *button, gpointer data)
Definition gui_stuff.c:494
itree_is_selected
gboolean itree_is_selected(GtkTreeSelection *selection, ITree *it)
Definition gui_stuff.c:190
gui_dialog_add_button
GtkWidget * gui_dialog_add_button(struct gui_dialog *dlg, const char *icon_name, const char *text, int response)
Definition gui_stuff.c:706
setup_dialog
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:287
dialog_list
static GList * dialog_list
Definition gui_stuff.c:42
gui_update_font_full
void gui_update_font_full(const char *font_name, const char *font_value, PangoFontDescription **font_desc)
Definition gui_stuff.c:1073
gtk_expose_now
void gtk_expose_now(GtkWidget *w)
Definition gui_stuff.c:52
gui_dialog_set_response_sensitive
void gui_dialog_set_response_sensitive(struct gui_dialog *dlg, int response, bool setting)
Definition gui_stuff.c:760
gui_dialog_get_toplevel
GtkWidget * gui_dialog_get_toplevel(struct gui_dialog *dlg)
Definition gui_stuff.c:787
intl_slist
void intl_slist(int n, const char **s, bool *done)
Definition gui_stuff.c:111
itree_end
gboolean itree_end(ITree *it)
Definition gui_stuff.c:136
gui_dialog_response
static void gui_dialog_response(struct gui_dialog *dlg, int response)
Definition gui_stuff.c:312
GUI_DIALOG_WINDOW
@ GUI_DIALOG_WINDOW
Definition gui_stuff.h:61
GUI_DIALOG_TAB
@ GUI_DIALOG_TAB
Definition gui_stuff.h:62
GUI_DIALOG_RESPONSE_FUN
void(* GUI_DIALOG_RESPONSE_FUN)(struct gui_dialog *, int, gpointer)
Definition gui_stuff.h:67
shell
static struct gui_dialog * shell
Definition messagedlg.c:39
title
const char * title
Definition repodlgs.c:1314
blocking_dialog
gint blocking_dialog(GtkWidget *dlg)
Definition gui_stuff.c:1136
aux_menu_new
GtkWidget * aux_menu_new(void)
Definition gui_stuff.c:244
gui_dialog_add_content_widget
void gui_dialog_add_content_widget(struct gui_dialog *dlg, GtkWidget *wdg)
Definition gui_stuff.c:1105
widget_get_child
GtkWidget * widget_get_child(GtkWidget *wdg)
Definition gui_stuff.c:1164
blocking_dialog_response
static void blocking_dialog_response(GtkWidget *dlg, gint response, void *data)
Definition gui_stuff.c:1124
gui_dialog_add_action_widget
GtkWidget * gui_dialog_add_action_widget(struct gui_dialog *dlg, GtkWidget *widget)
Definition gui_stuff.c:690
widget_destroyed
void widget_destroyed(GtkWidget *wdg, void *data)
Definition gui_stuff.c:1155
alert_close_response
void alert_close_response(GObject *dialog, GAsyncResult *result, gpointer data)
Definition gui_stuff.c:1173
gui_stuff.h
colors.h
gui_main.h
font_name
const char * font_name
Definition gui_main_g.h:43
gui_update_font
gui_update_font
Definition gui_main_g.h:43
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
mem.h
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
options.h
size
size_t size
Definition specvec.h:72
y
struct sprite int int y
Definition sprite_g.h:31
x
struct sprite int x
Definition sprite_g.h:31
ITree
Definition gui_stuff.h:32
ITree::model
GtkTreeModel * model
Definition gui_stuff.h:33
ITree::end
gboolean end
Definition gui_stuff.h:34
ITree::it
GtkTreeIter it
Definition gui_stuff.h:35
blocking_dialog_data
Definition gui_stuff.c:1116
blocking_dialog_data::response
gint response
Definition gui_stuff.c:1118
blocking_dialog_data::loop
GMainLoop * loop
Definition gui_stuff.c:1117
gui_dialog
Definition gui_stuff.h:70
gui_dialog::vbox
GtkWidget * vbox
Definition gui_stuff.h:72
gui_dialog::title
char * title
Definition gui_stuff.h:76
gui_dialog::handler_id
gulong handler_id
Definition gui_stuff.h:89
gui_dialog::v
union gui_dialog::@152 v
gui_dialog::grid
GtkWidget * grid
Definition gui_stuff.h:71
gui_dialog::id
int id
Definition gui_stuff.h:78
gui_dialog::content_counter
int content_counter
Definition gui_stuff.h:84
gui_dialog::vertical_content
bool vertical_content
Definition gui_stuff.h:83
gui_dialog::gui_button
GtkSizeGroup * gui_button
Definition gui_stuff.h:99
gui_dialog::action_area
GtkWidget * action_area
Definition gui_stuff.h:73
gui_dialog::response_callback
GUI_DIALOG_RESPONSE_FUN response_callback
Definition gui_stuff.h:96
gui_dialog::label
GtkWidget * label
Definition gui_stuff.h:87
gui_dialog::tab
struct gui_dialog::@152::@153 tab
gui_dialog::notebook
GtkWidget * notebook
Definition gui_stuff.h:88
gui_dialog::return_dialog_id
int return_dialog_id
Definition gui_stuff.h:79
gui_dialog::default_height
int default_height
Definition gui_stuff.h:82
gui_dialog::source
struct gui_dialog ** source
Definition gui_stuff.h:94
gui_dialog::user_data
gpointer user_data
Definition gui_stuff.h:97
gui_dialog::window
GtkWidget * window
Definition gui_stuff.h:85
gui_dialog::type
enum gui_dialog_type type
Definition gui_stuff.h:77
gui_dialog::default_width
int default_width
Definition gui_stuff.h:81
gui_dialog::child
GtkWidget * child
Definition gui_stuff.h:90
gui_dialog::actions
GtkWidget * actions
Definition gui_stuff.h:72
setting
Definition settings.c:92
view
Definition mapview_common.h:36
widget
Definition widget.h:112
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47