1 /*
2 * This file is part of Siril, an astronomy image processor.
3 * Copyright (C) 2005-2011 Francois Meyer (dulle at free.fr)
4 * Copyright (C) 2012-2017 team free-astro (see more in AUTHORS file)
5 * Reference site is https://free-astro.org/index.php/Siril
6 *
7 * Siril is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Siril is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Siril. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <string.h>
22
23 #include "core/siril.h"
24 #include "core/proto.h"
25 #include "core/initfile.h"
26 #include "gui/utils.h"
27 #include "gui/callbacks.h"
28
29 #include "message_dialog.h"
30
show_modal_dialog(gpointer p)31 static gboolean show_modal_dialog(gpointer p) {
32 struct siril_dialog_data *args = (struct siril_dialog_data *) p;
33 GtkTextIter itBeg, itEnd;
34 GtkWidget *dialog;
35
36 dialog = gtk_message_dialog_new(args->parent,
37 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
38 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", args->primary_text);
39
40 if (args->secondary_text)
41 gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(dialog),
42 "%s", args->secondary_text);
43
44 if (args->data) {
45 GtkTextBuffer *buffer;
46 GtkWidget *swindow;
47 GtkWidget *tview;
48
49 tview = gtk_text_view_new();
50 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tview));
51 gtk_text_buffer_get_bounds(buffer, &itBeg, &itEnd);
52 gtk_text_buffer_delete(buffer, &itBeg, &itEnd);
53 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tview), FALSE);
54 gtk_text_view_set_editable(GTK_TEXT_VIEW(tview), FALSE);
55 gtk_text_buffer_set_text(buffer, args->data, strlen(args->data));
56 gtk_widget_set_halign(tview, GTK_ALIGN_FILL);
57 gtk_widget_set_valign(tview, GTK_ALIGN_FILL);
58 gtk_widget_set_margin_start(tview, 6);
59 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tview), GTK_WRAP_WORD);
60
61 swindow = gtk_scrolled_window_new(NULL, NULL);
62 gtk_container_add(GTK_CONTAINER(swindow), tview);
63 gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
64 swindow, FALSE, FALSE, 0);
65 gtk_widget_set_size_request(swindow, -1, 200);
66
67 gtk_widget_show(swindow);
68 gtk_widget_show(tview);
69 }
70
71 gtk_dialog_run(GTK_DIALOG(dialog));
72
73 gtk_widget_destroy(dialog);
74 g_free(args);
75 return FALSE;
76 }
77
strip_last_ret_char(gchar * str)78 static gchar *strip_last_ret_char(gchar *str) {
79 char *pch;
80 int len;
81
82 pch = strrchr(str, '\0');
83 len = pch - str;
84
85 if (str[len - 1] == '\n') {
86 str[len - 1] = '\0';
87 }
88 return str;
89 }
90
91 /******* Public functions *****************/
92
siril_message_dialog(GtkMessageType type,char * title,char * text)93 void siril_message_dialog(GtkMessageType type, char *title, char *text) {
94 /* headless has no GUI, so no dialog; script has a GUI but calls it from another thread
95 * so it's not safe to use dialogs in the calling thread, we just ignore it for now. */
96 if (com.headless || com.script)
97 return; // show_dialog usually follows a siril_log_message() call
98 struct siril_dialog_data *args = g_try_malloc(sizeof(struct siril_dialog_data));
99
100 args->parent = siril_get_active_window();
101 if (!GTK_IS_WINDOW(args->parent)) {
102 args->parent = GTK_WINDOW(GTK_APPLICATION_WINDOW(lookup_widget("control_window")));
103 }
104 /* first we want to remove the '\n' at the end of the title and text
105 * if message come from siril_log_message
106 */
107 strip_last_ret_char(title);
108 strip_last_ret_char(text);
109
110 args->primary_text = title;
111 args->secondary_text = text;
112 args->data = NULL;
113 args->type = type;
114 show_modal_dialog(args);
115 }
116
117 struct message_data {
118 GtkMessageType type;
119 char *title;
120 char *text;
121 };
122
siril_message_dialog_idle(gpointer p)123 static gboolean siril_message_dialog_idle(gpointer p) {
124 struct message_data *data = (struct message_data *) p;
125 siril_message_dialog(data->type, data->title, data->text);
126 free(data->title);
127 free(data->text);
128 free(data);
129 return FALSE;
130 }
131
queue_message_dialog(GtkMessageType type,char * title,char * text)132 void queue_message_dialog(GtkMessageType type, char *title, char *text) {
133 if (com.headless || com.script)
134 return; // show_dialog usually follows a siril_log_message() call
135 struct message_data *data = malloc(sizeof(struct message_data));
136 data->type = type;
137 data->title = strdup(title);
138 data->text = strdup(text);
139 gdk_threads_add_idle(siril_message_dialog_idle, data);
140 }
141
siril_data_dialog(GtkMessageType type,char * title,char * text,gchar * data)142 void siril_data_dialog(GtkMessageType type, char *title, char *text, gchar *data) {
143 if (com.headless || com.script)
144 return; // show_dialog usually follows a siril_log_message() call
145 struct siril_dialog_data *args = malloc(sizeof(struct siril_dialog_data));
146
147 args->parent = siril_get_active_window();
148 if (!GTK_IS_WINDOW(args->parent)) {
149 args->parent = GTK_WINDOW(GTK_APPLICATION_WINDOW(lookup_widget("control_window")));
150 }
151 /* first we want to remove the '\n' at the end of the title and text
152 * if message come from siril_log_message
153 */
154 strip_last_ret_char(title);
155 strip_last_ret_char(text);
156
157 args->primary_text = title;
158 args->secondary_text = text;
159 args->data = data;
160 args->type = type;
161 show_modal_dialog(args);
162 }
163
siril_confirm_dialog_internal(gchar * title,gchar * msg,gchar * button_accept,gboolean checkbutton,gboolean * user_data)164 static gboolean siril_confirm_dialog_internal(gchar *title, gchar *msg, gchar *button_accept, gboolean checkbutton, gboolean *user_data) {
165 GtkWindow *parent;
166 GtkWidget *dialog, *check = NULL;
167 gint res;
168 gboolean ok = FALSE;
169 gboolean var_to_return = FALSE;
170
171 parent = siril_get_active_window();
172 if (!GTK_IS_WINDOW(parent)) {
173 /* could happen if the GtkWindow has been destroyed right after the call
174 * This is the case for chooser dialog */
175 parent = GTK_WINDOW(GTK_APPLICATION_WINDOW(lookup_widget("control_window")));
176 }
177
178 /* first we want to remove the '\n' at the end of the title and text
179 * if message come from siril_log_message
180 */
181 strip_last_ret_char(title);
182 strip_last_ret_char(msg);
183
184 dialog = gtk_message_dialog_new(parent, GTK_DIALOG_MODAL,
185 GTK_MESSAGE_QUESTION, GTK_BUTTONS_CANCEL, "%s", title);
186 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", msg);
187
188 gtk_dialog_add_button(GTK_DIALOG(dialog), button_accept, GTK_RESPONSE_ACCEPT);
189 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
190
191 if (checkbutton) {
192 check = gtk_check_button_new_with_mnemonic(_("_Do not show this dialog again"));
193 gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG (dialog))),
194 check, FALSE, FALSE, 0);
195 gtk_widget_set_halign(check, GTK_ALIGN_START);
196 gtk_widget_set_margin_start(check, 6);
197 gtk_widget_show(check);
198 }
199 res = gtk_dialog_run(GTK_DIALOG(dialog));
200 if (res == GTK_RESPONSE_ACCEPT) {
201 ok = TRUE;
202 if (check) {
203 var_to_return = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check));
204 }
205 }
206 if (user_data) {
207 *user_data = var_to_return;
208 }
209
210 gtk_widget_destroy(dialog);
211
212 return ok;
213 }
214
siril_confirm_dialog(gchar * title,gchar * msg,gchar * button_accept)215 gboolean siril_confirm_dialog(gchar *title, gchar *msg, gchar *button_accept) {
216 return siril_confirm_dialog_internal(title, msg, button_accept, FALSE, NULL);
217 }
218
siril_confirm_dialog_and_remember(gchar * title,gchar * msg,gchar * button_accept,gboolean * user_data)219 gboolean siril_confirm_dialog_and_remember(gchar *title, gchar *msg, gchar *button_accept, gboolean *user_data) {
220 return siril_confirm_dialog_internal(title, msg, button_accept, TRUE, user_data);
221 }
222