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-2021 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 <gdk/gdkkeysyms.h>
22 #include <gtk/gtk.h>
23 #include <string.h>
24
25 #include "gui/conversion.h"
26 #include "core/siril.h"
27 #include "core/proto.h"
28 #include "core/processing.h"
29 #include "core/OS_utils.h"
30 #include "io/conversion.h"
31 #include "io/sequence.h"
32 #include "gui/utils.h"
33 #include "gui/callbacks.h"
34 #include "gui/message_dialog.h"
35 #include "gui/progress_and_log.h"
36 #include "algos/sorting.h"
37
38 static gchar *destroot = NULL;
39 static GtkListStore *liststore_convert = NULL;
40 static GtkTreeView *tree_view = NULL;
41 static GtkTreeModel *model = NULL;
42 static gboolean warning_is_displayed = FALSE;
43
44 static void check_for_conversion_form_completeness();
45 static void on_input_files_change();
46 static sequence_type get_activated_output_type();
47
init_widgets()48 static void init_widgets() {
49 if (!tree_view) {
50 tree_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview_convert"));
51 model = gtk_tree_view_get_model(tree_view);
52 liststore_convert = GTK_LIST_STORE(
53 gtk_builder_get_object(builder, "liststore_convert"));
54 }
55 g_assert(tree_view);
56 g_assert(model);
57 g_assert(liststore_convert);
58 }
59
count_converted_files()60 int count_converted_files() {
61 init_widgets();
62 GtkTreeIter iter;
63 gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
64
65 int count = 0;
66 while (valid) {
67 gtk_tree_model_get(model, &iter, -1);
68 valid = gtk_tree_model_iter_next (model, &iter);
69 count++;
70 }
71 return count;
72 }
73
count_selected_files()74 int count_selected_files() {
75 init_widgets();
76 GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
77 return gtk_tree_selection_count_selected_rows(selection);
78 }
79
initialize_convert()80 static void initialize_convert() {
81 gchar *file_data;
82 GtkTreeIter iter;
83 GList *list = NULL;
84
85 init_widgets();
86
87 if (get_thread_run()) {
88 PRINT_ANOTHER_THREAD_RUNNING;
89 return;
90 }
91
92 if (file_name_has_invalid_chars(destroot)) {
93 siril_message_dialog(GTK_MESSAGE_ERROR, _("Invalid char"), _("Please remove invalid characters in the sequence name "
94 "before trying to convert images into a new sequence again."));
95 return;
96 }
97
98 if (g_file_test(destroot, G_FILE_TEST_EXISTS)) {
99 char *title = siril_log_message(_("A file named %s already exists. "
100 "Do you want to replace it?\n"), destroot);
101 gboolean replace = siril_confirm_dialog(title, _("The file already exists. "
102 "Replacing it will overwrite its contents."), _("Replace File"));
103 if (!replace) return;
104 }
105
106 gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
107 if (!valid) return; //The tree is empty
108
109 gboolean no_sequence_to_convert = TRUE;
110 gboolean there_is_an_image = FALSE;
111 gboolean there_is_an_xtrans = FALSE;
112 gboolean there_is_a_film = FALSE;
113 int count = 0;
114 while (valid) {
115 gtk_tree_model_get(model, &iter, COLUMN_FILENAME_FULL, &file_data, -1);
116
117 list = g_list_prepend(list, file_data);
118
119 const char *src_ext = get_filename_ext(file_data);
120
121 image_type type = get_type_for_extension(src_ext);
122 if (type == TYPEAVI || type == TYPESER) {
123 no_sequence_to_convert = FALSE;
124 if (type == TYPEAVI)
125 there_is_a_film = TRUE;
126 }
127 else if (type == TYPEUNDEF) {
128 char *title = siril_log_message(_("Filetype is not supported, cannot convert: %s\n"), src_ext);
129 gchar *msg = g_strdup_printf(_("File extension '%s' is not supported.\n"
130 "Verify that you typed the extension correctly.\n"
131 "If so, you may need to install third-party software to enable "
132 "this file type conversion, look at the README file.\n"
133 "If the file type you are trying to load is listed in supported "
134 "formats, you may notify the developers that the extension you are "
135 "trying to use should be recognized for this type."), src_ext);
136 siril_message_dialog(GTK_MESSAGE_ERROR, title, msg);
137 return;
138
139 }
140 else if (type == TYPERAW && !g_ascii_strcasecmp(src_ext, "raf")) {
141 there_is_an_xtrans = TRUE;
142 there_is_an_image = TRUE;
143 }
144 // because of fitseq, we can't use this check for FITS
145 else if (type != TYPEFITS)
146 there_is_an_image = TRUE;
147 valid = gtk_tree_model_iter_next(model, &iter);
148 count++;
149 }
150
151 sequence_type output_type = get_activated_output_type();
152 int nb_allowed;
153 if (!allow_to_open_files(count, &nb_allowed) && output_type == SEQ_REGULAR) {
154 gboolean confirm = siril_confirm_dialog(_("Too many files are being converted."),
155 _("You are about to convert a large amount of files into standard FITS files."
156 "However, your OS limits the number of files that will be processed in the same time."
157 "You may want to convert your input files into a FITS sequence."), _("Convert to FITS Sequence"));
158 if (!confirm) return;
159 }
160
161 GtkToggleButton *toggle = GTK_TOGGLE_BUTTON(lookup_widget("multiple_seq"));
162 gboolean multiple = gtk_toggle_button_get_active(toggle);
163 toggle = GTK_TOGGLE_BUTTON(lookup_widget("demosaicingButton"));
164 gboolean debayer = gtk_toggle_button_get_active(toggle);
165 toggle = GTK_TOGGLE_BUTTON(lookup_widget("convert_symlink"));
166 gboolean symbolic_link = gtk_toggle_button_get_active(toggle);
167
168 if (output_type == SEQ_REGULAR && debayer && symbolic_link) {
169 siril_log_message(_("Symbolic links cannot be used when demosaicing the images, new images will be created\n"));
170 symbolic_link = FALSE;
171 }
172 if (multiple && there_is_an_image) {
173 siril_message_dialog(GTK_MESSAGE_WARNING, _("A conflict has been detected."),
174 _("Creating multiple sequences can only be done with only sequences as input."));
175 g_list_free_full(list, g_free);
176 return;
177 }
178 if (output_type == SEQ_SER && there_is_an_xtrans && !debayer) {
179 siril_message_dialog(GTK_MESSAGE_WARNING, _("A conflict has been detected."),
180 _("FujiFilm XTRANS sensors are not supported by SER v2 (CFA-style) standard. You may use FITS sequences instead."));
181 g_list_free_full(list, g_free);
182 return;
183 }
184
185 siril_log_color_message(_("Conversion: processing %d files...\n"), "green", count);
186
187 set_cursor_waiting(TRUE);
188 control_window_switch_to_tab(OUTPUT_LOGS);
189
190 /* g_list_append() has to traverse the entire list to find the end,
191 * which is inefficient when adding multiple elements. A common idiom
192 * to avoid the inefficiency is to use g_list_prepend() and reverse the
193 * list with g_list_reverse() when all elements have been added. */
194 list = g_list_reverse(list);
195 /* convert the list to an array for parallel processing */
196 char **files_to_convert = glist_to_array(list, &count);
197
198 struct _convert_data *args = malloc(sizeof(struct _convert_data));
199 if (!args) {
200 PRINT_ALLOC_ERR;
201 return;
202 }
203 if (output_type == SEQ_REGULAR) {
204 GtkEntry *startEntry = GTK_ENTRY(lookup_widget("startIndiceEntry"));
205 const gchar *index = gtk_entry_get_text(startEntry);
206 args->start = (g_ascii_strtoll(index, NULL, 10) <= 0
207 || g_ascii_strtoll(index, NULL, 10) >= INDEX_MAX) ? 1 : g_ascii_strtoll(index, NULL, 10);
208 }
209 else args->start = 0;
210 args->list = files_to_convert;
211 args->total = count;
212 args->nb_converted_files = 0;
213 args->input_has_a_seq = !no_sequence_to_convert;
214 args->input_has_a_film = there_is_a_film;
215 args->destroot = g_strdup(destroot);
216 args->debayer = debayer;
217 args->make_link = symbolic_link;
218 args->output_type = output_type;
219 args->multiple_output = multiple;
220 gettimeofday(&(args->t_start), NULL);
221 start_in_new_thread(convert_thread_worker, args);
222 return;
223 }
224
on_convroot_entry_activate(GtkEntry * entry,gpointer user_data)225 void on_convroot_entry_activate(GtkEntry *entry, gpointer user_data) {
226 initialize_convert();
227 }
228
on_convert_button_clicked(GtkButton * button,gpointer user_data)229 void on_convert_button_clicked(GtkButton *button, gpointer user_data) {
230 initialize_convert();
231 }
232
add_file_to_list(GFile * file)233 static void add_file_to_list(GFile *file) {
234 GtkTreeIter iter;
235
236 GFileInfo *info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED ","
237 G_FILE_ATTRIBUTE_STANDARD_SIZE, 0, NULL, NULL);
238 guint64 mtime = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
239 GDateTime *dt = g_date_time_new_from_unix_local(mtime);
240 gchar *date = g_date_time_format(dt, "%c");
241 const gchar *filename = g_file_peek_path(file);
242 gchar *bname = g_file_get_basename(file);
243 gchar *size = g_format_size(g_file_info_get_size(info));
244
245 gtk_list_store_append(liststore_convert, &iter);
246 gtk_list_store_set(liststore_convert, &iter,
247 COLUMN_FILENAME, bname,
248 COLUMN_FILENAME_FULL, filename,
249 COLUMN_SIZE, size,
250 COLUMN_SIZE_INT64, g_file_info_get_size(info),
251 COLUMN_DATE, date,
252 COLUMN_DATE_UNIX, mtime,
253 -1);
254
255 g_free(bname);
256 g_object_unref(info);
257 g_date_time_unref(dt);
258 g_free(date);
259 g_free(size);
260 }
261
get_row_references_of_selected_rows(GtkTreeSelection * selection,GtkTreeModel * model)262 static GList *get_row_references_of_selected_rows(GtkTreeSelection *selection,
263 GtkTreeModel *model) {
264 GList *ref = NULL;
265 GList *sel, *s;
266
267 sel = gtk_tree_selection_get_selected_rows(selection, &model);
268
269 for (s = sel; s; s = s->next) {
270 GtkTreeRowReference *rowref = gtk_tree_row_reference_new(model, (GtkTreePath *) s->data);
271 ref = g_list_prepend(ref, rowref);
272 }
273 g_list_free_full(sel, (GDestroyNotify) gtk_tree_path_free);
274 return ref;
275 }
276
remove_selected_files_from_list()277 static void remove_selected_files_from_list() {
278 GtkTreeSelection *selection;
279 GList *references, *list;
280
281 init_widgets();
282 selection = gtk_tree_view_get_selection(tree_view);
283 references = get_row_references_of_selected_rows(selection, model);
284 for (list = references; list; list = list->next) {
285 GtkTreeIter iter;
286 GtkTreePath *path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)list->data);
287 if (path) {
288 if (gtk_tree_model_get_iter(model, &iter, path)) {
289 gtk_list_store_remove(liststore_convert, &iter);
290 }
291 gtk_tree_path_free(path);
292 }
293 }
294 g_list_free(references);
295 gtk_tree_selection_unselect_all(selection);
296 }
297
name_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)298 static gint name_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
299 gpointer user_data) {
300 gchar *name_a, *name_b;
301 gchar *collate_key1, *collate_key2;
302 gint ret;
303
304 gtk_tree_model_get(model, a, COLUMN_FILENAME, &name_a, -1);
305 gtk_tree_model_get(model, b, COLUMN_FILENAME, &name_b, -1);
306
307 collate_key1 = g_utf8_collate_key_for_filename(name_a, strlen(name_a));
308 collate_key2 = g_utf8_collate_key_for_filename(name_b, strlen(name_b));
309
310 ret = g_strcmp0(collate_key1, collate_key2);
311
312 g_free(collate_key1);
313 g_free(collate_key2);
314 g_free(name_a);
315 g_free(name_b);
316
317 return ret;
318 }
319
size_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)320 static gint size_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
321 gpointer user_data) {
322 gint64 *size_a, *size_b;
323
324 gtk_tree_model_get(model, a, COLUMN_SIZE_INT64, &size_a, -1);
325 gtk_tree_model_get(model, b, COLUMN_SIZE_INT64, &size_b, -1);
326
327 return size_a < size_b ? -1 : (size_a == size_b ? 0 : 1);
328 }
329
date_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)330 static gint date_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
331 gpointer user_data) {
332 guint64 *date_a, *date_b;
333
334 gtk_tree_model_get(model, a, COLUMN_DATE_UNIX, &date_a, -1);
335 gtk_tree_model_get(model, b, COLUMN_DATE_UNIX, &date_b, -1);
336
337 return date_a < date_b ? -1 : (date_a == date_b ? 0 : 1);
338 }
339
fill_convert_list(GSList * list)340 void fill_convert_list(GSList *list) {
341 GSList *l;
342 init_widgets();
343
344 for (l = list; l; l = l->next) {
345 char *filename;
346
347 filename = (char *) l->data;
348 GFile *file = g_file_new_for_path(filename);
349
350 add_file_to_list(file);
351 g_free(filename);
352 g_object_unref(file);
353 }
354 check_for_conversion_form_completeness();
355 on_input_files_change();
356 }
357
on_clear_convert_button_clicked(GtkToolButton * button,gpointer user_data)358 void on_clear_convert_button_clicked(GtkToolButton *button, gpointer user_data) {
359 init_widgets();
360 gtk_list_store_clear(liststore_convert);
361 check_for_conversion_form_completeness();
362 on_input_files_change();
363 }
364
on_remove_convert_button_clicked(GtkToolButton * button,gpointer user_data)365 void on_remove_convert_button_clicked(GtkToolButton *button, gpointer user_data) {
366 init_widgets();
367 remove_selected_files_from_list();
368 check_for_conversion_form_completeness();
369 on_input_files_change();
370 }
371
on_treeview_convert_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time,gpointer user_data)372 void on_treeview_convert_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time,
373 gpointer user_data) {
374 gtk_drag_unhighlight(widget);
375 }
376
on_treeview_convert_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)377 gboolean on_treeview_convert_drag_motion(GtkWidget *widget, GdkDragContext *context,
378 gint x, gint y, guint time) {
379 gtk_drag_highlight(widget);
380
381 return TRUE;
382 }
383
on_treeview_convert_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time,gpointer user_data)384 void on_treeview_convert_drag_data_received(GtkWidget *widget,
385 GdkDragContext *context, gint x, gint y,
386 GtkSelectionData *selection_data, guint info, guint time,
387 gpointer user_data) {
388
389 gchar **uris, **str;
390 const guchar *data;
391 GSList *list = NULL;
392 gint bad_files = 0;
393
394 if (info != 0)
395 return;
396
397 data = gtk_selection_data_get_data(selection_data);
398 uris = g_uri_list_extract_uris((gchar *) data);
399
400 for (str = uris; *str; str++) {
401 GError *error = NULL;
402 gchar *path = g_filename_from_uri(*str, NULL, &error);
403 if (path) {
404 const char *src_ext = get_filename_ext(path);
405 if (src_ext) {
406 if (get_type_for_extension(src_ext) == TYPEUNDEF) {
407 bad_files++;
408 } else {
409 list = g_slist_prepend(list, path);
410 }
411 } else bad_files++;
412 } else {
413 fprintf(stderr, "Could not convert uri to local path: %s",
414 error->message);
415 bad_files++;
416 g_clear_error(&error);
417 }
418 }
419 list = g_slist_sort(list, (GCompareFunc) strcompare);
420 fill_convert_list(list);
421 if (bad_files) {
422 gchar *loc_str = ngettext("%d file was ignored while drag and drop\n",
423 "%d files were ignored while drag and drop\n", bad_files);
424 loc_str = g_strdup_printf(loc_str, bad_files);
425 char *msg = siril_log_message(loc_str);
426 siril_message_dialog(GTK_MESSAGE_INFO, msg,
427 _("Files with unknown extension cannot be dropped in this area. "
428 "Therefore they are ignored."));
429 g_free(loc_str);
430 }
431 g_strfreev(uris);
432 g_slist_free(list);
433 on_input_files_change();
434 }
435
on_treeview_convert_key_release_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)436 gboolean on_treeview_convert_key_release_event(GtkWidget *widget, GdkEventKey *event,
437 gpointer user_data) {
438 if (event->keyval == GDK_KEY_Delete || event->keyval == GDK_KEY_KP_Delete
439 || event->keyval == GDK_KEY_BackSpace) {
440 remove_selected_files_from_list();
441 check_for_conversion_form_completeness();
442 on_input_files_change();
443 return TRUE;
444 }
445 return FALSE;
446 }
447
check_for_conversion_form_completeness()448 static void check_for_conversion_form_completeness() {
449 GtkTreeIter iter;
450 static GtkWidget *go_button = NULL;
451 if (!go_button)
452 go_button = lookup_widget("convert_button");
453
454 init_widgets();
455 gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
456 gtk_widget_set_sensitive(go_button, destroot && destroot[0] != '\0' && valid);
457 }
458
on_input_files_change()459 static void on_input_files_change() {
460 /* we override the sort function in order to provide natural sort order */
461 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), COLUMN_FILENAME, (GtkTreeIterCompareFunc) name_sort_func, NULL, NULL);
462 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), COLUMN_SIZE, (GtkTreeIterCompareFunc) size_sort_func, NULL, NULL);
463 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), COLUMN_DATE_UNIX, (GtkTreeIterCompareFunc) date_sort_func, NULL, NULL);
464
465 update_statusbar_convert();
466 }
467
468 /******************************* Callback functions ***********************************/
469
470 // TODO: put a red lining around the entry instead of removing bad chars
insert_text_handler(GtkEntry * entry,const gchar * text,gint length,gint * position,gpointer data)471 void insert_text_handler(GtkEntry *entry, const gchar *text, gint length,
472 gint *position, gpointer data) {
473 GtkEditable *editable = GTK_EDITABLE(entry);
474 int i, count = 0;
475
476 gchar *result = g_strndup(text, length);
477
478 for (i = 0; i < length; i++) {
479 if (is_forbiden_in_filename(text[i]))
480 continue;
481 result[count++] = text[i];
482 }
483
484 if (count > 0) {
485 g_signal_handlers_block_by_func(G_OBJECT (editable),
486 G_CALLBACK (insert_text_handler), data);
487 gtk_editable_insert_text(editable, result, count, position);
488 g_signal_handlers_unblock_by_func(G_OBJECT (editable),
489 G_CALLBACK (insert_text_handler), data);
490 }
491 g_signal_stop_emission_by_name(G_OBJECT(editable), "insert_text");
492
493 g_free(result);
494 }
495
update_statusbar_convert()496 void update_statusbar_convert() {
497 static GtkLabel *status_label = NULL;
498 if (!status_label)
499 status_label = GTK_LABEL(lookup_widget("statuslabel_convert"));
500
501 int nb_files = count_converted_files();
502 if (nb_files == 0)
503 gtk_label_set_text(status_label, " ");
504 else {
505 int selected = count_selected_files();
506 gchar *str1, *total;
507
508 str1 = ngettext("%d file loaded", "%d files loaded", nb_files);
509 str1 = g_strdup_printf(str1, nb_files);
510 if (selected == 0) {
511 total = g_strdup(str1);
512 } else {
513 gchar *str2 = ngettext("%d file selected", "%d files selected", selected);
514 str2 = g_strdup_printf(str2, selected);
515 total = g_strdup_printf("%s, %s", str1, str2);
516 g_free(str2);
517 }
518 gtk_label_set_text(status_label, total);
519 g_free(str1);
520 g_free(total);
521 }
522 }
523
on_treeview_selection5_changed(GtkTreeSelection * treeselection,gpointer user_data)524 void on_treeview_selection5_changed(GtkTreeSelection *treeselection,
525 gpointer user_data) {
526 update_statusbar_convert();
527 }
528
process_destroot(sequence_type output_type)529 void process_destroot(sequence_type output_type) {
530 static GtkEntry *convroot_entry = NULL;
531 if (!convroot_entry)
532 convroot_entry = GTK_ENTRY(lookup_widget("convroot_entry"));
533
534 const gchar *name = gtk_entry_get_text(convroot_entry);
535 if (*name == '\0') {
536 g_free(destroot);
537 destroot = NULL;
538 return;
539 }
540 destroot = g_str_to_ascii(name, NULL); // we want to avoid special char
541 gboolean seq_exists = FALSE;
542 if (output_type == SEQ_SER) {
543 if (!g_str_has_suffix(destroot, ".ser"))
544 str_append(&destroot, ".ser");
545 seq_exists = check_if_seq_exist(destroot, FALSE);
546 }
547 else if (output_type == SEQ_FITSEQ) {
548 if (!g_str_has_suffix(destroot, com.pref.ext))
549 str_append(&destroot, com.pref.ext);
550 seq_exists = check_if_seq_exist(destroot, FALSE);
551 }
552 else {
553 destroot = format_basename(destroot, TRUE);
554 seq_exists = check_if_seq_exist(destroot, TRUE);
555 }
556
557 if (seq_exists && !warning_is_displayed) {
558 set_icon_entry(convroot_entry, "gtk-dialog-warning");
559 warning_is_displayed = TRUE;
560 }
561 else if (!seq_exists && warning_is_displayed) {
562 set_icon_entry(convroot_entry, NULL);
563 warning_is_displayed = FALSE;
564 }
565 }
566
567 /* 0: FITS images
568 * 1: SER sequence
569 * 2: FITS sequence
570 */
get_activated_output_type()571 static sequence_type get_activated_output_type() {
572 static GtkComboBox *combo = NULL;
573 if (!combo)
574 combo = GTK_COMBO_BOX(gtk_builder_get_object(builder, "prepro_output_type_combo1"));
575 return (sequence_type)gtk_combo_box_get_active(combo);
576 }
577
578 // truncates destroot if it's more than 120 characters, append a '_' if it
579 // doesn't end with one or a '-'
on_convtoroot_changed(GtkEditable * editable,gpointer user_data)580 void on_convtoroot_changed(GtkEditable *editable, gpointer user_data){
581 process_destroot(get_activated_output_type());
582 check_for_conversion_form_completeness();
583 }
584
585 // used for global file opening
on_demosaicing_toggled(GtkToggleButton * togglebutton,gpointer user_data)586 void on_demosaicing_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
587 com.pref.debayer.open_debayer = gtk_toggle_button_get_active(togglebutton);
588 }
589
on_prepro_output_type_combo1_changed(GtkComboBox * combo,gpointer user_data)590 void on_prepro_output_type_combo1_changed(GtkComboBox *combo, gpointer user_data) {
591 static GtkWidget *multiple_seq = NULL, *convert_symlink = NULL, *start = NULL;
592 if (!multiple_seq) {
593 multiple_seq = lookup_widget("multiple_seq");
594 convert_symlink = lookup_widget("convert_symlink");
595 start = lookup_widget("startIndiceEntry");
596 }
597
598 sequence_type output = gtk_combo_box_get_active(combo);
599 gboolean seqfile_output = output == SEQ_SER || output == SEQ_FITSEQ;
600 gtk_widget_set_visible(multiple_seq, seqfile_output);
601 gtk_widget_set_visible(start, !seqfile_output);
602 if (!seqfile_output)
603 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(multiple_seq), FALSE);
604 gtk_widget_set_visible(convert_symlink, !seqfile_output);
605 process_destroot(output);
606 check_for_conversion_form_completeness();
607 }
608