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