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 "core/siril.h"
22 #include "core/proto.h"
23 #include "gui/utils.h"
24 #include "gui/callbacks.h"
25 #include "gui/dialogs.h"
26 #include "gui/message_dialog.h"
27 #include "gui/image_display.h"
28 #include "gui/progress_and_log.h"
29 #include "gui/plot.h"
30 #include "io/sequence.h"
31 #include "algos/PSF.h"
32 #include "registration/registration.h" // for update_reg_interface
33 #include "stacking/stacking.h" // for update_stack_interface
34
35 #include "sequence_list.h"
36
37 static gboolean fill_sequence_list_idle(gpointer p);
38
39 static const char *bg_colour[] = { "WhiteSmoke", "#1B1B1B" };
40 static const char *ref_bg_colour[] = { "Beige", "#4A4A39" };
41
42 struct _seq_list {
43 GtkTreeView *tview;
44 sequence *seq;
45 int layer;
46 };
47
48 static GtkListStore *list_store = NULL;
49
50 enum {
51 COLUMN_IMNAME, // string
52 COLUMN_SHIFTX, // int
53 COLUMN_SHIFTY, // int
54 COLUMN_SELECTED, // gboolean
55 COLUMN_FWHM, // gdouble
56 COLUMN_CURRENT, // int weight, current file loaded, display IMNAME in bold
57 COLUMN_REFERENCE, // background color depending on the image being reference
58 COLUMN_INDEX, // int
59 N_COLUMNS
60 };
61
62 enum { //different context_id of the GtkStatusBar
63 COUNT_STATE
64 };
65
66
67 /******* Static functions **************/
fwhm_quality_cell_data_function(GtkTreeViewColumn * col,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer user_data)68 static void fwhm_quality_cell_data_function(GtkTreeViewColumn *col,
69 GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter,
70 gpointer user_data) {
71 gdouble quality;
72 gchar buf[20];
73 gtk_tree_model_get(model, iter, COLUMN_FWHM, &quality, -1);
74 if (quality >= 0.0)
75 g_snprintf(buf, sizeof(buf), "%.3f", quality);
76 else
77 g_strlcpy(buf, "N/A", sizeof(buf));
78 g_object_set(renderer, "text", buf, NULL);
79 }
80
update_seqlist_dialog_combo()81 static void update_seqlist_dialog_combo() {
82 if (!sequence_is_loaded()) return;
83
84 GtkComboBoxText *seqcombo = GTK_COMBO_BOX_TEXT(lookup_widget("seqlist_dialog_combo"));
85 g_signal_handlers_block_by_func(GTK_COMBO_BOX(seqcombo), on_seqlist_dialog_combo_changed, NULL);
86 gtk_combo_box_text_remove_all(seqcombo);
87 g_signal_handlers_unblock_by_func(GTK_COMBO_BOX(seqcombo), on_seqlist_dialog_combo_changed, NULL);
88
89 if (com.seq.nb_layers == 1) {
90 gtk_combo_box_text_append_text(seqcombo, _("B&W channel"));
91 } else {
92 gtk_combo_box_text_append_text(seqcombo, _("Red channel"));
93 gtk_combo_box_text_append_text(seqcombo, _("Green channel"));
94 gtk_combo_box_text_append_text(seqcombo, _("Blue channel"));
95 }
96 gtk_combo_box_set_active(GTK_COMBO_BOX(seqcombo), com.cvport == RGB_VPORT ? 1 : com.cvport);
97 }
98
initialize_title()99 static void initialize_title() {
100 GtkHeaderBar *bar = GTK_HEADER_BAR(lookup_widget("seqlistbar"));
101 gchar *seq_basename;
102
103 if (sequence_is_loaded())
104 seq_basename = g_path_get_basename(com.seq.seqname);
105 else
106 seq_basename = g_strdup(_("No sequence loaded"));
107
108 gtk_header_bar_set_title(bar, _("Frame List"));
109 gtk_header_bar_set_subtitle(bar, seq_basename);
110 gtk_widget_set_sensitive(lookup_widget("seqlist_buttonbar"), sequence_is_loaded());
111 gtk_widget_set_sensitive(lookup_widget("seqlist_dialog_combo"), sequence_is_loaded());
112 gtk_widget_set_sensitive(lookup_widget("refframe2"), sequence_is_loaded());
113
114 g_free(seq_basename);
115 }
116
initialize_search_entry()117 static void initialize_search_entry() {
118 GtkTreeView *tree_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview1"));
119 GtkEntry *entry = GTK_ENTRY(lookup_widget("seqlistsearch"));
120
121 gtk_entry_set_text (entry, "");
122 gtk_tree_view_set_search_entry(tree_view, entry);
123 }
124
get_list_store()125 static void get_list_store() {
126 if (list_store == NULL) {
127 list_store = GTK_LIST_STORE(gtk_builder_get_object(builder, "liststore1"));
128
129 GtkTreeViewColumn *col = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "treeviewcolumn5"));
130 GtkCellRenderer *cell = GTK_CELL_RENDERER(gtk_builder_get_object(builder, "cellrenderertext5"));
131 gtk_tree_view_column_set_cell_data_func(col, cell, fwhm_quality_cell_data_function, NULL, NULL);
132 }
133 }
134
135 /* Add an image to the list. If seq is NULL, the list is cleared. */
add_image_to_sequence_list(sequence * seq,int index,int layer)136 static void add_image_to_sequence_list(sequence *seq, int index, int layer) {
137 GtkTreeSelection *selection;
138 GtkTreeIter iter;
139 char imname[256];
140 char *basename;
141 int shiftx = -1, shifty = -1;
142 double fwhm = -1.0;
143 int color;
144
145 get_list_store();
146
147 if (seq == NULL) {
148 gtk_list_store_clear(list_store);
149 return; // just clear the list
150 }
151 if (seq->regparam && seq->regparam[layer]) {
152 shiftx = roundf_to_int(seq->regparam[layer][index].shiftx);
153 shifty = roundf_to_int(seq->regparam[layer][index].shifty);
154
155 if (seq->regparam[layer][index].fwhm > 0.0f) {
156 fwhm = seq->regparam[layer][index].fwhm;
157 gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "treeviewcolumn5")), _("FWHM"));
158 } else if (seq->regparam[layer][index].quality >= 0.0) {
159 fwhm = seq->regparam[layer][index].quality;
160 gtk_tree_view_column_set_title (GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "treeviewcolumn5")), _("Quality"));
161 }
162 } else {
163 gtk_tree_view_column_set_title (GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "treeviewcolumn5")), _("Quality"));
164 }
165
166 color = (com.pref.combo_theme == 0) ? 1 : 0;
167
168 selection = GTK_TREE_SELECTION(gtk_builder_get_object(builder, "treeview-selection1"));
169
170 basename = g_path_get_basename(seq_get_image_filename(seq, index, imname));
171 gtk_list_store_append (list_store, &iter);
172 gtk_list_store_set (list_store, &iter,
173 COLUMN_IMNAME, basename,
174 COLUMN_SHIFTX, shiftx,
175 COLUMN_SHIFTY, shifty,
176 COLUMN_SELECTED, seq->imgparam[index].incl,
177 COLUMN_FWHM, fwhm,
178 COLUMN_CURRENT, index == seq->current ? 800 : 400,
179 // weight value is 400 by default "normal":
180 // http://developer.gnome.org/gtk3/stable/GtkCellRendererText.html#GtkCellRendererText--weight
181 COLUMN_REFERENCE, index == seq->reference_image ?
182 ref_bg_colour[color] : bg_colour[color],
183 COLUMN_INDEX, (index + 1),
184 -1);
185 /* see example at http://developer.gnome.org/gtk3/3.5/GtkListStore.html */
186 if (index == seq->current) {
187 if (selection)
188 gtk_tree_selection_select_iter(selection, &iter);
189 }
190 g_free(basename);
191 }
192
sequence_list_change_selection(gchar * path,gboolean new_value)193 static void sequence_list_change_selection(gchar *path, gboolean new_value) {
194 GtkTreeIter iter;
195 get_list_store();
196 gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list_store), &iter, path);
197 gtk_list_store_set(list_store, &iter, COLUMN_SELECTED, new_value, -1);
198 }
199
get_row_references_of_selected_rows(GtkTreeSelection * selection,GtkTreeModel * model)200 static GList *get_row_references_of_selected_rows(GtkTreeSelection *selection,
201 GtkTreeModel *model) {
202 GList *ref = NULL;
203 GList *sel, *s;
204
205 sel = gtk_tree_selection_get_selected_rows(selection, &model);
206
207 for (s = sel; s; s = s->next) {
208 GtkTreeRowReference *rowref = gtk_tree_row_reference_new(model, (GtkTreePath *) s->data);
209 ref = g_list_prepend(ref, rowref);
210 }
211 g_list_free_full(sel, (GDestroyNotify) gtk_tree_path_free);
212 return ref;
213 }
214
get_image_index_from_path(GtkTreePath * path)215 static int get_image_index_from_path(GtkTreePath *path) {
216 GValue value = G_VALUE_INIT;
217 gint index;
218 GtkTreeIter iter;
219 get_list_store();
220 gtk_tree_model_get_iter(GTK_TREE_MODEL(list_store), &iter, path);
221 gtk_tree_model_get_value(GTK_TREE_MODEL(list_store), &iter, COLUMN_INDEX, &value);
222 index = g_value_get_int(&value) - 1;
223 g_value_unset(&value);
224 return index;
225 }
226
get_real_index_from_index_in_list(GtkTreeModel * model,GtkTreeIter * iter,int index_in_list)227 static gint get_real_index_from_index_in_list(GtkTreeModel *model, GtkTreeIter *iter, int index_in_list) {
228 gint real_index;
229 gtk_tree_model_get(model, iter, COLUMN_INDEX, &real_index, -1);
230 return real_index - 1;
231 }
232
unselect_select_frame_from_list(GtkTreeView * tree_view)233 static void unselect_select_frame_from_list(GtkTreeView *tree_view) {
234 GtkTreeSelection *selection;
235 GtkTreeModel *model;
236 GList *references, *list;
237
238 get_list_store();
239
240 model = gtk_tree_view_get_model(tree_view);
241 selection = gtk_tree_view_get_selection(tree_view);
242 references = get_row_references_of_selected_rows(selection, model);
243 for (list = references; list; list = list->next) {
244 GtkTreePath *path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)list->data);
245 if (path) {
246 gint *new_index = gtk_tree_path_get_indices(path);
247 GtkTreeIter iter;
248
249 gtk_tree_model_get_iter(GTK_TREE_MODEL(list_store), &iter, path);
250 gint real_index = get_real_index_from_index_in_list(model, &iter, new_index[0]);
251 toggle_image_selection(new_index[0], real_index);
252 gtk_tree_path_free(path);
253 }
254 }
255 g_list_free(references);
256 }
257
display_status()258 static void display_status() {
259 GtkStatusbar *statusbar = GTK_STATUSBAR(lookup_widget("seqlist_statusbar"));
260 gchar *text;
261 if (sequence_is_loaded()) {
262 text = g_strdup_printf("%d/%d", com.seq.current + 1, com.seq.number);
263 gtk_statusbar_push(statusbar, COUNT_STATE, text);
264 g_free(text);
265 } else {
266 gtk_statusbar_push(statusbar, COUNT_STATE, "");
267 }
268 }
269
270 /* method handling all include or all exclude from a sequence */
sequence_setselect_all(gboolean include_all)271 static void sequence_setselect_all(gboolean include_all) {
272 int i;
273
274 if (!com.seq.imgparam)
275 return;
276 for (i = 0; i < com.seq.number; ++i) {
277 /* TODO: we include all and exclude all without checking if frame is already
278 * included of already excluded.
279 * Indeed, in the case of a list sorted by quality, index in lisrt and
280 * real index are different.
281 * We should find a way to compute the real index without using UI
282 * like we do with get_real_index_from_index_in_list()
283 *
284 */
285 // if (com.seq.imgparam[i].incl != include_all) {
286 com.seq.imgparam[i].incl = include_all;
287 sequence_list_change_selection_index(i, i);
288 // }
289 }
290 if (include_all) {
291 com.seq.selnum = com.seq.number;
292 siril_log_message(_("Selected all images from sequence\n"));
293 } else {
294 com.seq.selnum = 0;
295 com.seq.reference_image = -1;
296 siril_log_message(_("Unselected all images from sequence\n"));
297 sequence_list_change_reference();
298 adjust_refimage(com.seq.current);
299 }
300 update_reg_interface(FALSE);
301 update_stack_interface(TRUE);
302 writeseqfile(&com.seq);
303 redraw(com.cvport, REMAP_NONE);
304 drawPlot();
305 adjust_sellabel();
306 }
307
308 /**** Callbacks *****/
309
on_treeview1_cursor_changed(GtkTreeView * tree_view,gpointer user_data)310 void on_treeview1_cursor_changed(GtkTreeView *tree_view, gpointer user_data) {
311 GtkTreeModel *tree_model;
312 GtkTreeSelection *selection;
313 GtkTreeIter iter;
314 GList *list;
315
316 tree_model = gtk_tree_view_get_model(tree_view);
317 selection = gtk_tree_view_get_selection (tree_view);
318
319 list = gtk_tree_selection_get_selected_rows(selection, &tree_model);
320 if (g_list_length(list) == 1) {
321 gint idx;
322 GValue value = G_VALUE_INIT;
323 gtk_tree_model_get_iter(tree_model, &iter, (GtkTreePath *)list->data);
324
325 gtk_tree_model_get_value(tree_model, &iter, COLUMN_INDEX, &value);
326 idx = g_value_get_int(&value) - 1;
327 if (idx != com.seq.current) {
328 fprintf(stdout, "loading image %d\n", idx);
329 seq_load_image(&com.seq, idx, TRUE);
330 }
331 g_value_unset(&value);
332 }
333 g_list_free_full(list, (GDestroyNotify) gtk_tree_path_free);
334 display_status();
335 }
336
on_seqlist_dialog_combo_changed(GtkComboBoxText * widget,gpointer user_data)337 void on_seqlist_dialog_combo_changed(GtkComboBoxText *widget, gpointer user_data) {
338 int active = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
339 if (active >= 0) {
340 fill_sequence_list(&com.seq, active, FALSE);
341 }
342 }
343
update_seqlist()344 void update_seqlist() {
345 initialize_title();
346 update_seqlist_dialog_combo();
347 initialize_search_entry();
348 display_status();
349 }
350
351 /* called on sequence loading (set_seq), on layer tab change and on registration data update.
352 * It is executed safely in the GTK thread if as_idle is true. */
fill_sequence_list(sequence * seq,int layer,gboolean as_idle)353 void fill_sequence_list(sequence *seq, int layer, gboolean as_idle) {
354 struct _seq_list *args;
355 if (seq == NULL || layer >= seq->nb_layers) return;
356
357 args = malloc(sizeof(struct _seq_list));
358 args->seq = seq;
359 args->layer = layer;
360 args->tview = GTK_TREE_VIEW(lookup_widget("treeview1"));
361
362 g_signal_handlers_block_by_func(args->tview, on_treeview1_cursor_changed, NULL);
363
364 if (as_idle)
365 gdk_threads_add_idle(fill_sequence_list_idle, args);
366 else fill_sequence_list_idle(args);
367 }
368
fill_sequence_list_idle(gpointer p)369 static gboolean fill_sequence_list_idle(gpointer p) {
370 int i;
371 struct _seq_list *args = (struct _seq_list *)p;
372 add_image_to_sequence_list(NULL, 0, 0); // clear
373 if (args->seq->number > 0) {
374 for (i = 0; i < args->seq->number; i++) {
375 add_image_to_sequence_list(args->seq, i, args->layer);
376 }
377 }
378 g_signal_handlers_unblock_by_func(args->tview, on_treeview1_cursor_changed, NULL);
379
380 free(args);
381 return FALSE;
382 }
383
exclude_single_frame(int index)384 void exclude_single_frame(int index) {
385 siril_log_message(_("%s image %d in sequence %s\n"),
386 com.seq.imgparam[index].incl ? _("Excluding") : _("Including"),
387 index + 1, com.seq.seqname);
388
389 com.seq.imgparam[index].incl = !com.seq.imgparam[index].incl;
390 if (com.seq.imgparam[index].incl)
391 com.seq.selnum++;
392 else com.seq.selnum--;
393 update_reg_interface(FALSE);
394 update_stack_interface(FALSE);
395 redraw(com.cvport, REMAP_NONE);
396 drawPlot();
397 adjust_sellabel();
398 writeseqfile(&com.seq);
399 }
400
on_seqlist_image_selection_toggled(GtkCellRendererToggle * cell_renderer,gchar * char_path,gpointer user_data)401 void on_seqlist_image_selection_toggled(GtkCellRendererToggle *cell_renderer,
402 gchar *char_path, gpointer user_data) {
403 GtkTreePath *path = gtk_tree_path_new_from_string(char_path);
404 gint index = get_image_index_from_path(path);
405 gtk_tree_path_free(path);
406 if (index < 0 || index >= com.seq.number) return;
407 fprintf(stdout, "toggle selection index = %d\n", index);
408
409 sequence_list_change_selection(char_path, !com.seq.imgparam[index].incl);
410 exclude_single_frame(index);
411 }
412
toggle_image_selection(int index_in_list,int real_index)413 void toggle_image_selection(int index_in_list, int real_index) {
414 gchar *msg;
415 if (com.seq.imgparam[real_index].incl) {
416 com.seq.imgparam[real_index].incl = FALSE;
417 --com.seq.selnum;
418 msg = g_strdup_printf(_("Image %d has been unselected from sequence\n"), real_index + 1);
419 if (real_index == com.seq.reference_image) {
420 com.seq.reference_image = -1;
421 sequence_list_change_reference();
422 adjust_refimage(real_index);
423 }
424 } else {
425 com.seq.imgparam[real_index].incl = TRUE;
426 ++com.seq.selnum;
427 msg = g_strdup_printf(_("Image %d has been selected from sequence\n"), real_index + 1);
428 }
429 siril_log_message(msg);
430 g_free(msg);
431 sequence_find_refimage(&com.seq);
432 if (!com.script) {
433 sequence_list_change_selection_index(index_in_list, real_index);
434 update_reg_interface(FALSE);
435 update_stack_interface(TRUE);
436 redraw(com.cvport, REMAP_NONE);
437 drawPlot();
438 adjust_sellabel();
439 writeseqfile(&com.seq);
440 }
441 }
442
on_selected_frames_select(GtkButton * button,gpointer user_data)443 void on_selected_frames_select(GtkButton *button, gpointer user_data) {
444 unselect_select_frame_from_list((GtkTreeView *)user_data);
445 }
446
on_seqexcludeall_button_clicked(GtkButton * button,gpointer user_data)447 void on_seqexcludeall_button_clicked(GtkButton *button, gpointer user_data) {
448 gboolean exclude_all = siril_confirm_dialog(_("Exclude all images?"),
449 _("This erases previous image selection and there's no possible undo."),
450 _("Exclude All"));
451 if (exclude_all)
452 sequence_setselect_all(FALSE);
453 }
454
on_seqselectall_button_clicked(GtkButton * button,gpointer user_data)455 void on_seqselectall_button_clicked(GtkButton *button, gpointer user_data) {
456 gboolean select_all = siril_confirm_dialog(_("Include all images?"),
457 _("This erases previous image selection and there's no possible undo."),
458 _("Include All"));
459 if (select_all)
460 sequence_setselect_all(TRUE);
461 }
462
on_ref_frame_toggled(GtkToggleButton * togglebutton,gpointer user_data)463 void on_ref_frame_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
464 if (!sequence_is_loaded())
465 return;
466
467 free_reference_image();
468 get_list_store();
469 GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView* ) user_data);
470 GtkTreeSelection *selection = gtk_tree_view_get_selection((GtkTreeView* ) user_data);
471 GList *references = get_row_references_of_selected_rows(selection, model);
472
473 references = g_list_first(references);
474 if (!references) return;
475
476 GtkTreePath *path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)references->data);
477 if (path) {
478 if (!gtk_toggle_button_get_active(togglebutton)) {
479 if (com.seq.reference_image == com.seq.current)
480 com.seq.reference_image = -1;
481 } else {
482 com.seq.reference_image = com.seq.current;
483 test_and_allocate_reference_image(-1);
484 // a reference image should not be excluded to avoid confusion
485 if (!com.seq.imgparam[com.seq.current].incl) {
486 toggle_image_selection(com.seq.current, com.seq.current);
487 }
488 }
489 gtk_tree_path_free(path);
490 }
491
492 g_list_free(references);
493 sequence_list_change_reference();
494 update_stack_interface(FALSE);// get stacking info and enable the Go button
495 adjust_sellabel(); // reference image is named in the label
496 writeseqfile(&com.seq);
497 drawPlot(); // update plots
498 }
499
500 /****************** modification of the list store (tree model) ******************/
501
sequence_list_change_selection_index(int index_in_list,int real_index)502 void sequence_list_change_selection_index(int index_in_list, int real_index) {
503 GtkTreePath *path = gtk_tree_path_new_from_indices(index_in_list, -1);
504 if (path) {
505 sequence_list_change_selection(gtk_tree_path_to_string(path), com.seq.imgparam[real_index].incl);
506 gtk_tree_path_free(path);
507 }
508 }
509
sequence_list_change_current()510 void sequence_list_change_current() {
511 GtkTreeIter iter;
512 gboolean valid;
513
514 get_list_store();
515 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter);
516 while (valid) {
517 gint index = 0;
518 GValue value = G_VALUE_INIT;
519
520 gtk_tree_model_get_value (GTK_TREE_MODEL(list_store), &iter, COLUMN_INDEX, &value);
521 index = g_value_get_int(&value) - 1;
522 g_value_unset(&value);
523 gtk_list_store_set(list_store, &iter, COLUMN_CURRENT,
524 (index == com.seq.current) ? 800 : 400, -1);
525 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter);
526 }
527 }
528
sequence_list_change_reference()529 void sequence_list_change_reference() {
530 GtkTreeIter iter;
531 gboolean valid;
532 int color;
533
534 color = (com.pref.combo_theme == 0) ? 1 : 0;
535
536 get_list_store();
537 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter);
538 while (valid) {
539 gint index = 0;
540 GValue value = G_VALUE_INIT;
541
542 gtk_tree_model_get_value (GTK_TREE_MODEL(list_store), &iter, COLUMN_INDEX, &value);
543 index = g_value_get_int(&value) - 1;
544 g_value_unset(&value);
545 gtk_list_store_set(list_store, &iter,
546 COLUMN_REFERENCE,
547 (index == com.seq.reference_image) ?
548 ref_bg_colour[color] : bg_colour[color], -1);
549 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter);
550 }
551 }
552
clear_sequence_list()553 void clear_sequence_list() {
554 g_signal_handlers_block_by_func(GTK_TREE_VIEW(lookup_widget("treeview1")), on_treeview1_cursor_changed, NULL);
555 get_list_store();
556 gtk_list_store_clear(list_store);
557 g_signal_handlers_unblock_by_func(GTK_TREE_VIEW(lookup_widget("treeview1")), on_treeview1_cursor_changed, NULL);
558 }
559
adjust_refimage(int n)560 void adjust_refimage(int n) {
561 static GtkWidget *ref_butt2 = NULL, *treeview1 = NULL;
562 if (ref_butt2 == NULL) {
563 ref_butt2 = lookup_widget("refframe2");
564 treeview1 = lookup_widget("treeview1");
565 }
566
567 g_signal_handlers_block_by_func(ref_butt2, on_ref_frame_toggled, treeview1);
568 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ref_butt2), com.seq.reference_image == n);
569 g_signal_handlers_unblock_by_func(ref_butt2, on_ref_frame_toggled, treeview1);
570 }
571