1 | // ================================================================ // |
---|
2 | // // |
---|
3 | // File : ED4_seq_colors.cxx // |
---|
4 | // Purpose : Sequence foreground coloring. // |
---|
5 | // Viewing differences only. // |
---|
6 | // // |
---|
7 | // Institute of Microbiology (Technical University Munich) // |
---|
8 | // http://www.arb-home.de/ // |
---|
9 | // // |
---|
10 | // ================================================================ // |
---|
11 | |
---|
12 | #include "ed4_seq_colors.hxx" |
---|
13 | #include "ed4_class.hxx" |
---|
14 | #include "ed4_extern.hxx" |
---|
15 | |
---|
16 | #include <aw_root.hxx> |
---|
17 | #include <aw_awar.hxx> |
---|
18 | #include <aw_awar_defs.hxx> |
---|
19 | #include <aw_msg.hxx> |
---|
20 | #include <arbdbt.h> |
---|
21 | #include <arb_global_defs.h> |
---|
22 | |
---|
23 | #include <cctype> |
---|
24 | |
---|
25 | static int default_NUC_set = 0; // number of default nucleotide set |
---|
26 | static int default_AMI_set = 3; // number of default amino acid set |
---|
27 | |
---|
28 | #define SEQ_COLOR_SETS 8 |
---|
29 | #define SEQ_COLOR_SET_ELEMS 28 // has to be a even number! |
---|
30 | |
---|
31 | #define AWAR_SEQ_PATH "awt/seq_colors/" |
---|
32 | #define AWAR_SEQ_NAME_STRINGS_TEMPLATE AWAR_SEQ_PATH "strings/elem_%i" |
---|
33 | #define AWAR_SEQ_NAME_TEMPLATE AWAR_SEQ_PATH "set_%i/elem_%i" |
---|
34 | #define AWAR_SEQ_NAME_SELECTOR_NA AWAR_SEQ_PATH "na/select" |
---|
35 | #define AWAR_SEQ_NAME_SELECTOR_AA AWAR_SEQ_PATH "aa/select" |
---|
36 | |
---|
37 | static const char *default_sets[SEQ_COLOR_SETS] = { |
---|
38 | //A B C D E F G H I J K L M N O P Q R S T U V W X Y Z * - |
---|
39 | "=2=0=3=0=0=0=4=0=0=0=0=0=0=6=0=0=0=0=0=5=5=0=0=0=0=0=0=6", // A, C, G, TU and N in 5 colors |
---|
40 | "R2=0Y3=0=0=0R2=0=0=0=0=0=0=0=0=0=0=2=0Y3Y3=0=0=0=3=0=0=6", // AG and CTU in 2 colors |
---|
41 | "=6=5=6=5=7=7=6=5=7=7=3=7=3=9=7=7=7=3=3=6=6=5=3=7=3=7=7=6", // ambiguity |
---|
42 | "=7=0=7=8=2=9=8=9=3=0=2=3=7=8=0=8=2=2=2=2=0=3=9=6=9=0=0=6", // Protein colors |
---|
43 | |
---|
44 | "=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=6", |
---|
45 | "o9=0|2=0=0=0o5=0=0=0=0=0=0=0=0=0=0=0=0|8|8=0=0=0=0=0=0=6", // ambiguity (symbols) |
---|
46 | "=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=6", |
---|
47 | "=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=6", |
---|
48 | }; |
---|
49 | |
---|
50 | static bool seq_color_awars_created = false; |
---|
51 | |
---|
52 | // -------------------------------------------------------------------------------- |
---|
53 | |
---|
54 | static const char *default_characters(int elem) { |
---|
55 | static char result[3] = "xX"; |
---|
56 | |
---|
57 | if (elem<26) { // first 26 elements (0-25) are characters |
---|
58 | result[0] = 'a'+elem; |
---|
59 | result[1] = 'A'+elem; |
---|
60 | } |
---|
61 | else if (elem == 26) { // stop codon |
---|
62 | result[0] = '*'; |
---|
63 | result[1] = 0; |
---|
64 | } |
---|
65 | else if (elem == 27) { // gaps |
---|
66 | result[0] = '-'; |
---|
67 | result[1] = '.'; |
---|
68 | } |
---|
69 | |
---|
70 | return result; |
---|
71 | } |
---|
72 | static const char *default_color(int cset, int elem) { |
---|
73 | // returns default color numbers for seq-color-set |
---|
74 | static char result[3] = "=0"; |
---|
75 | const char *pos = default_sets[cset]+2*elem; |
---|
76 | |
---|
77 | result[0] = pos[0]; |
---|
78 | result[1] = pos[1]; |
---|
79 | |
---|
80 | if (result[0] == '=' && result[1] == '0') result[0] = 0; |
---|
81 | |
---|
82 | return result; |
---|
83 | } |
---|
84 | |
---|
85 | static void color_awar_changed_cb(AW_root *, ED4_seq_colors *sc) { |
---|
86 | sc->reload(); |
---|
87 | } |
---|
88 | |
---|
89 | static void create_seq_color_awars(AW_root *awr, ED4_seq_colors *sc) { |
---|
90 | e4_assert(!seq_color_awars_created); |
---|
91 | |
---|
92 | RootCallback update_cb = makeRootCallback(color_awar_changed_cb, sc); |
---|
93 | awr->awar_int(AWAR_SEQ_NAME_SELECTOR_NA, default_NUC_set, AW_ROOT_DEFAULT)->add_callback(update_cb); |
---|
94 | awr->awar_int(AWAR_SEQ_NAME_SELECTOR_AA, default_AMI_set, AW_ROOT_DEFAULT)->add_callback(update_cb); |
---|
95 | |
---|
96 | for (int elem = 0; elem<SEQ_COLOR_SET_ELEMS; ++elem) { |
---|
97 | const char *awar_name = GBS_global_string(AWAR_SEQ_NAME_STRINGS_TEMPLATE, elem); |
---|
98 | awr->awar_string(awar_name, default_characters(elem))->add_callback(update_cb); |
---|
99 | |
---|
100 | for (int cset = 0; cset<SEQ_COLOR_SETS; ++cset) { |
---|
101 | awar_name = GBS_global_string(AWAR_SEQ_NAME_TEMPLATE, cset, elem); |
---|
102 | AW_awar *awar_col = awr->awar_string(awar_name, default_color(cset, elem)); |
---|
103 | |
---|
104 | if (strcmp(awar_col->read_char_pntr(), "=0") == 0) { // translate old->new default |
---|
105 | awar_col->write_string(""); |
---|
106 | } |
---|
107 | |
---|
108 | // add callback AFTER writing to awar above to avoid recursion |
---|
109 | // (the CB calls this function again, and seq_color_awars_created is set |
---|
110 | // to true at the very end... |
---|
111 | awar_col->add_callback(update_cb); |
---|
112 | } |
---|
113 | } |
---|
114 | |
---|
115 | seq_color_awars_created = true; |
---|
116 | } |
---|
117 | |
---|
118 | AW_window *ED4_create_seq_colors_window(AW_root *awr, ED4_seq_colors *sc) { |
---|
119 | char buf[256]; |
---|
120 | static AW_window_simple *aws = NULp; |
---|
121 | if (aws) return aws; |
---|
122 | |
---|
123 | if (!seq_color_awars_created) create_seq_color_awars(awr, sc); |
---|
124 | |
---|
125 | aws = new AW_window_simple; |
---|
126 | aws->init(awr, "SEQUENCE_MAPPING", "Sequence color mapping"); |
---|
127 | |
---|
128 | aws->at(10, 10); |
---|
129 | aws->auto_space(0, 3); |
---|
130 | |
---|
131 | aws->callback(AW_POPDOWN); |
---|
132 | aws->create_button("CLOSE", "CLOSE", "C"); |
---|
133 | |
---|
134 | aws->callback(makeHelpCallback("sequence_colors.hlp")); |
---|
135 | aws->create_button("HELP", "HELP"); |
---|
136 | |
---|
137 | aws->at_newline(); |
---|
138 | |
---|
139 | for (int seqType=0; seqType<2; seqType++) { |
---|
140 | if (seqType==0) { |
---|
141 | aws->label("Select color-set for Nucleotides (NA):"); |
---|
142 | aws->create_toggle_field(AWAR_SEQ_NAME_SELECTOR_NA, 1); |
---|
143 | } |
---|
144 | else { |
---|
145 | aws->label("Select color-set for Amino Acids (AA):"); |
---|
146 | aws->create_toggle_field(AWAR_SEQ_NAME_SELECTOR_AA, 1); |
---|
147 | } |
---|
148 | |
---|
149 | for (int cset = 0; cset < SEQ_COLOR_SETS; cset++) { |
---|
150 | sprintf(buf, "%i", cset+1); |
---|
151 | aws->insert_toggle(buf, " ", cset); |
---|
152 | } |
---|
153 | aws->update_toggle_field(); |
---|
154 | aws->at_newline(); |
---|
155 | } |
---|
156 | |
---|
157 | const int BIG_COLUMNS = 2; |
---|
158 | const int CHAR_COL_WIDTH = 4; |
---|
159 | const int SET_COL_WIDTH = 2; |
---|
160 | |
---|
161 | int col_x_off[BIG_COLUMNS][SEQ_COLOR_SETS+1]; |
---|
162 | |
---|
163 | aws->auto_space(3, 2); |
---|
164 | |
---|
165 | for (int bcol = 0; bcol<BIG_COLUMNS; ++bcol) { |
---|
166 | col_x_off[bcol][0] = aws->get_at_xposition(); |
---|
167 | aws->button_length(CHAR_COL_WIDTH); |
---|
168 | aws->create_button(NULp, "Chars"); |
---|
169 | |
---|
170 | aws->button_length(SET_COL_WIDTH); |
---|
171 | for (int cset = 0; cset < SEQ_COLOR_SETS; cset++) { |
---|
172 | sprintf(buf, " %i", cset+1); |
---|
173 | col_x_off[bcol][cset+1] = aws->get_at_xposition(); |
---|
174 | aws->create_button(NULp, buf); |
---|
175 | } |
---|
176 | |
---|
177 | if (!bcol) { |
---|
178 | int set_col_pixel_width = col_x_off[0][1]-col_x_off[0][0]; |
---|
179 | aws->at_x(aws->get_at_xposition()+set_col_pixel_width); |
---|
180 | } |
---|
181 | } |
---|
182 | |
---|
183 | aws->at_newline(); |
---|
184 | |
---|
185 | const int ROWS = SEQ_COLOR_SET_ELEMS/2; |
---|
186 | for (int r = 0; r<ROWS; r++) { |
---|
187 | for (int bcol = 0; bcol<BIG_COLUMNS; ++bcol) { |
---|
188 | int elem = bcol*ROWS+r; |
---|
189 | |
---|
190 | sprintf(buf, AWAR_SEQ_NAME_STRINGS_TEMPLATE, elem); |
---|
191 | aws->at_x(col_x_off[bcol][0]); |
---|
192 | aws->create_input_field(buf, CHAR_COL_WIDTH); |
---|
193 | |
---|
194 | for (int cset = 0; cset < SEQ_COLOR_SETS; cset++) { |
---|
195 | sprintf(buf, AWAR_SEQ_NAME_TEMPLATE, cset, elem); |
---|
196 | aws->at_x(col_x_off[bcol][cset+1]); |
---|
197 | aws->create_input_field(buf, SET_COL_WIDTH); |
---|
198 | } |
---|
199 | } |
---|
200 | aws->at_newline(); |
---|
201 | } |
---|
202 | |
---|
203 | aws->window_fit(); |
---|
204 | |
---|
205 | return aws; |
---|
206 | } |
---|
207 | |
---|
208 | // GC order needed for sequence coloring |
---|
209 | STATIC_ASSERT((ED4_G_SEQUENCES+1) == ED4_G_HELIX); |
---|
210 | STATIC_ASSERT((ED4_G_HELIX+1) == ED4_G_COLOR_2); |
---|
211 | |
---|
212 | void ED4_seq_colors::reload() { |
---|
213 | for (int i=0; i<256; i++) { // LOOP_VECTORIZED=* // >=8.1: 2x; 7.4: 1x // tested down to gcc 5.5.0 (may fail on older gcc versions) |
---|
214 | char_2_gc[i] = char_2_gc_aa[i] = base_gc; |
---|
215 | char_2_char[i] = char_2_char_aa[i] = i; |
---|
216 | } |
---|
217 | |
---|
218 | AW_root *aw_root = AW_root::SINGLETON; |
---|
219 | |
---|
220 | if (!seq_color_awars_created) create_seq_color_awars(aw_root, this); |
---|
221 | |
---|
222 | const char *selector_awar[2] = { AWAR_SEQ_NAME_SELECTOR_NA, AWAR_SEQ_NAME_SELECTOR_AA }; |
---|
223 | |
---|
224 | for (int selector = 0; selector<2; selector++) { |
---|
225 | long def_set = selector == 0 ? default_NUC_set : default_AMI_set; |
---|
226 | long cset = aw_root->awar(selector_awar[selector])->read_int(); |
---|
227 | |
---|
228 | if (cset < 0 || cset >= SEQ_COLOR_SETS) { |
---|
229 | cset = def_set; |
---|
230 | } |
---|
231 | |
---|
232 | for (int elem = 0; elem < SEQ_COLOR_SET_ELEMS; elem++) { |
---|
233 | char awar_name[256]; |
---|
234 | |
---|
235 | sprintf(awar_name, AWAR_SEQ_NAME_STRINGS_TEMPLATE, elem); |
---|
236 | unsigned char *sc = (unsigned char *)aw_root->awar(awar_name)->read_string(); |
---|
237 | |
---|
238 | sprintf(awar_name, AWAR_SEQ_NAME_TEMPLATE, (int)cset, elem); |
---|
239 | char *val = aw_root->awar(awar_name)->read_string(); |
---|
240 | if (!val[0]) freedup(val, "=0"); // interpret '' as ' = 0' |
---|
241 | |
---|
242 | if (strlen(val) != 2 || val[1] >'9' || val[1] < '0') { |
---|
243 | aw_message(GB_export_errorf("Error in Color Lookup Table: '%s' is not of type X#", val)); |
---|
244 | } |
---|
245 | else { |
---|
246 | if (selector == 0) { // Nucleotide colors |
---|
247 | for (int i=0; sc[i]; i++) { |
---|
248 | char_2_gc[sc[i]] = val[1]-'0' + base_gc; |
---|
249 | if (val[0] != '=') char_2_char[sc[i]] = val[0]; |
---|
250 | } |
---|
251 | } |
---|
252 | else { |
---|
253 | for (int i=0; sc[i]; i++) { |
---|
254 | char_2_gc_aa[sc[i]] = val[1]-'0' + base_gc; |
---|
255 | if (val[0] != '=') char_2_char_aa[sc[i]] = val[0]; |
---|
256 | } |
---|
257 | } |
---|
258 | } |
---|
259 | free(val); |
---|
260 | free(sc); |
---|
261 | } |
---|
262 | } |
---|
263 | |
---|
264 | run_cb(); |
---|
265 | } |
---|
266 | |
---|
267 | ED4_seq_colors::ED4_seq_colors(int baseGC, void (*changed_cb)()) { |
---|
268 | cb = changed_cb; |
---|
269 | base_gc = baseGC; |
---|
270 | |
---|
271 | this->reload(); |
---|
272 | } |
---|
273 | |
---|
274 | // ----------------------- |
---|
275 | // ED4_reference |
---|
276 | |
---|
277 | ED4_reference::ED4_reference() : |
---|
278 | nodiff('#'), // notused; overwritten by user default later |
---|
279 | mindcase(true), |
---|
280 | ref_len(0), |
---|
281 | reference(NULp), |
---|
282 | ref_term(NULp) |
---|
283 | { |
---|
284 | reset_gap_table(); |
---|
285 | } |
---|
286 | |
---|
287 | ED4_reference::~ED4_reference() { |
---|
288 | clear(); |
---|
289 | } |
---|
290 | |
---|
291 | void ED4_reference::reset_gap_table() { |
---|
292 | for (int i = 0; i<256; ++i) is_gap[i] = false; |
---|
293 | } |
---|
294 | |
---|
295 | void ED4_reference::set_gap_handling(bool mindgaptype, const char *gaptypes) { |
---|
296 | reset_gap_table(); |
---|
297 | if (!mindgaptype) { // treat all gaps as "equal" |
---|
298 | for (int i = 0; gaptypes[i]; ++i) { |
---|
299 | is_gap[safeCharIndex(gaptypes[i])] = true; |
---|
300 | } |
---|
301 | } |
---|
302 | } |
---|
303 | |
---|
304 | void ED4_reference::expand_to_length(int len) { |
---|
305 | if (len>ref_len && is_set()) { |
---|
306 | char *ref2 = ARB_calloc<char>(len+1); |
---|
307 | |
---|
308 | if (reference) { |
---|
309 | strcpy(ref2, reference); |
---|
310 | free(reference); |
---|
311 | } |
---|
312 | reference = ref2; |
---|
313 | ref_len = len; |
---|
314 | } |
---|
315 | } |
---|
316 | |
---|
317 | void ED4_reference::update_data() { |
---|
318 | freeset(reference, ref_term->get_sequence_copy(&ref_len)); |
---|
319 | } |
---|
320 | |
---|
321 | void ED4_reference::data_changed_cb(ED4_species_manager *IF_ASSERTION_USED(calledFrom)) { |
---|
322 | e4_assert(ref_term); |
---|
323 | if (ref_term) { |
---|
324 | #if defined(ASSERTION_USED) |
---|
325 | if (calledFrom) e4_assert(ref_term->get_parent(LEV_SPECIES)->to_species_manager() == calledFrom); |
---|
326 | #endif |
---|
327 | update_data(); |
---|
328 | } |
---|
329 | } |
---|
330 | static void refdata_changed_cb(ED4_species_manager *sman, ED4_reference *ref) { |
---|
331 | ref->data_changed_cb(sman); |
---|
332 | ED4_ROOT->request_refresh_for_specific_terminals(LEV_SEQUENCE_STRING); // refresh all sequences |
---|
333 | } |
---|
334 | static void refdata_deleted_cb() { |
---|
335 | ED4_viewDifferences_disable(); |
---|
336 | } |
---|
337 | |
---|
338 | void ED4_reference::clear() { |
---|
339 | // remove change cb |
---|
340 | if (ref_term) { |
---|
341 | ED4_species_manager *sman = ref_term->get_parent(LEV_SPECIES)->to_species_manager(); |
---|
342 | sman->remove_sequence_changed_cb(makeED4_species_managerCallback(refdata_changed_cb, this)); |
---|
343 | sman->remove_delete_callback(makeED4_managerCallback(refdata_deleted_cb)); |
---|
344 | } |
---|
345 | |
---|
346 | freenull(reference); |
---|
347 | ref_len = 0; |
---|
348 | ref_term = NULp; |
---|
349 | } |
---|
350 | |
---|
351 | void ED4_reference::define(const ED4_sequence_terminal *rterm) { |
---|
352 | clear(); |
---|
353 | ref_term = rterm; |
---|
354 | update_data(); |
---|
355 | |
---|
356 | // add change cb |
---|
357 | ED4_species_manager *sman = ref_term->get_parent(LEV_SPECIES)->to_species_manager(); |
---|
358 | sman->add_sequence_changed_cb(makeED4_species_managerCallback(refdata_changed_cb, this)); |
---|
359 | sman->add_delete_callback(makeED4_managerCallback(refdata_deleted_cb)); |
---|
360 | } |
---|
361 | |
---|
362 | bool ED4_reference::reference_is_a_consensus() const { |
---|
363 | return is_set() && ref_term->is_consensus_sequence_terminal(); |
---|
364 | } |
---|
365 | |
---|
366 | // -------------------------------------------------------------------------------- |
---|
367 | |
---|
368 | #define APREFIX_DIFF_SAVE "edit4/diff/" |
---|
369 | #define APREFIX_DIFF_TEMP "tmp/" APREFIX_DIFF_SAVE |
---|
370 | |
---|
371 | #define AWAR_DIFF_TYPE APREFIX_DIFF_TEMP "type" |
---|
372 | #define AWAR_DIFF_NAME APREFIX_DIFF_TEMP "name" |
---|
373 | #define AWAR_NODIFF_INDICATOR APREFIX_DIFF_SAVE "indicator" |
---|
374 | #define AWAR_DIFF_MINDCASE APREFIX_DIFF_SAVE "mindcase" |
---|
375 | #define AWAR_DIFF_MINDGAPTYPE APREFIX_DIFF_SAVE "mindgaptype" |
---|
376 | #define AWAR_DIFF_GAPTYPES APREFIX_DIFF_SAVE "gaptypes" |
---|
377 | |
---|
378 | enum ViewDiffType { |
---|
379 | VD_DISABLED, |
---|
380 | VD_SELECTED, |
---|
381 | VD_FOLLOW, |
---|
382 | }; |
---|
383 | |
---|
384 | static ED4_terminal *detect_current_ref_terminal() { |
---|
385 | ED4_cursor *cursor = ¤t_cursor(); |
---|
386 | ED4_terminal *refTerm = cursor->owner_of_cursor; |
---|
387 | |
---|
388 | if (refTerm) { |
---|
389 | if (!(refTerm->is_consensus_terminal() || |
---|
390 | refTerm->is_SAI_terminal() || |
---|
391 | refTerm->is_species_seq_terminal())) |
---|
392 | { |
---|
393 | refTerm = NULp; |
---|
394 | } |
---|
395 | } |
---|
396 | |
---|
397 | if (!refTerm) { |
---|
398 | aw_message("Please set the cursor to a species, SAI or group consensus."); |
---|
399 | } |
---|
400 | |
---|
401 | return refTerm; |
---|
402 | } |
---|
403 | |
---|
404 | static void set_diff_reference(ED4_terminal *refTerm) { |
---|
405 | ED4_reference *ref = ED4_ROOT->reference; |
---|
406 | if (!refTerm) { |
---|
407 | ref->clear(); |
---|
408 | } |
---|
409 | else { |
---|
410 | ED4_sequence_terminal *refSeqTerm = dynamic_cast<ED4_sequence_terminal*>(refTerm); |
---|
411 | if (refSeqTerm) { |
---|
412 | AW_awar *awar_refName = AW_root::SINGLETON->awar(AWAR_DIFF_NAME); |
---|
413 | ED4_species_name_terminal *nameTerm = refSeqTerm->corresponding_species_name_terminal(); |
---|
414 | |
---|
415 | ref->define(refSeqTerm); |
---|
416 | if (refTerm->is_consensus_terminal()) { |
---|
417 | awar_refName->write_string(GBS_global_string("consensus %s", nameTerm->get_displayed_text())); |
---|
418 | } |
---|
419 | else { |
---|
420 | e4_assert(refTerm->is_species_seq_terminal() || refTerm->is_SAI_terminal()); |
---|
421 | awar_refName->write_string(nameTerm->get_displayed_text()); |
---|
422 | } |
---|
423 | } |
---|
424 | else { |
---|
425 | aw_message("Not supported for this terminal type"); |
---|
426 | } |
---|
427 | } |
---|
428 | |
---|
429 | ED4_ROOT->request_refresh_for_specific_terminals(LEV_SEQUENCE_STRING); |
---|
430 | } |
---|
431 | |
---|
432 | static SmartCharPtr last_used_ref_term_name; |
---|
433 | |
---|
434 | static void set_current_as_diffRef(bool enable) { |
---|
435 | ED4_MostRecentWinContext context; |
---|
436 | |
---|
437 | ED4_terminal *refTerm = enable ? detect_current_ref_terminal() : NULp; |
---|
438 | if (!enable || refTerm) { // do not disable, if current terminal has wrong type |
---|
439 | set_diff_reference(refTerm); |
---|
440 | if (refTerm) last_used_ref_term_name = ARB_strdup(refTerm->id); |
---|
441 | } |
---|
442 | } |
---|
443 | |
---|
444 | static void change_reference_cb(AW_window *aww) { |
---|
445 | set_current_as_diffRef(true); |
---|
446 | |
---|
447 | AW_awar *awar_refType = aww->get_root()->awar(AWAR_DIFF_TYPE); |
---|
448 | if (awar_refType->read_int() == VD_DISABLED) { |
---|
449 | awar_refType->write_int(VD_SELECTED); |
---|
450 | } |
---|
451 | } |
---|
452 | |
---|
453 | static void diff_type_changed_cb(AW_root *awr) { |
---|
454 | AW_awar *awar_refType = awr->awar(AWAR_DIFF_TYPE); |
---|
455 | ViewDiffType type = ViewDiffType(awar_refType->read_int()); |
---|
456 | |
---|
457 | switch (type) { |
---|
458 | case VD_DISABLED: |
---|
459 | set_current_as_diffRef(false); |
---|
460 | break; |
---|
461 | |
---|
462 | case VD_FOLLOW: |
---|
463 | case VD_SELECTED: { |
---|
464 | ED4_terminal *last_used_ref_term = NULp; |
---|
465 | if (last_used_ref_term_name.isSet()) { |
---|
466 | ED4_base *found = ED4_ROOT->main_manager->search_ID(&*last_used_ref_term_name); |
---|
467 | if (found && found->is_terminal()) { |
---|
468 | last_used_ref_term = found->to_terminal(); |
---|
469 | } |
---|
470 | } |
---|
471 | if (last_used_ref_term) { |
---|
472 | set_diff_reference(last_used_ref_term); |
---|
473 | if (type == VD_FOLLOW) set_current_as_diffRef(true); |
---|
474 | } |
---|
475 | else { |
---|
476 | set_current_as_diffRef(true); |
---|
477 | } |
---|
478 | if (!ED4_ROOT->reference->is_set()) { |
---|
479 | awar_refType->write_int(VD_DISABLED); |
---|
480 | } |
---|
481 | break; |
---|
482 | } |
---|
483 | } |
---|
484 | } |
---|
485 | |
---|
486 | static void update_reference_settings(AW_root *awr) { |
---|
487 | ED4_reference *ref = ED4_ROOT->reference; |
---|
488 | ref->set_nodiff_indicator(awr->awar(AWAR_NODIFF_INDICATOR)->read_char_pntr()[0]); |
---|
489 | ref->set_case_sensitive(awr->awar(AWAR_DIFF_MINDCASE)->read_int()); |
---|
490 | ref->set_gap_handling(awr->awar(AWAR_DIFF_MINDGAPTYPE)->read_int(), awr->awar(AWAR_DIFF_GAPTYPES)->read_char_pntr()); |
---|
491 | } |
---|
492 | static void diff_setting_changed_cb(AW_root *awr) { |
---|
493 | update_reference_settings(awr); |
---|
494 | ED4_ROOT->request_refresh_for_specific_terminals(LEV_SEQUENCE_STRING); |
---|
495 | } |
---|
496 | |
---|
497 | static void nodiff_indicator_changed_cb(AW_root *awr) { |
---|
498 | AW_awar *awar_indicator = awr->awar(AWAR_NODIFF_INDICATOR); |
---|
499 | const char *indicator = awar_indicator->read_char_pntr(); |
---|
500 | |
---|
501 | if (!indicator[0]) { |
---|
502 | awar_indicator->write_string(" "); |
---|
503 | } |
---|
504 | else { |
---|
505 | diff_setting_changed_cb(awr); |
---|
506 | } |
---|
507 | } |
---|
508 | |
---|
509 | static bool viewDifferences_awars_initialized = false; |
---|
510 | |
---|
511 | static void create_viewDifferences_awars(AW_root *awr) { |
---|
512 | if (!viewDifferences_awars_initialized) { |
---|
513 | awr->awar_int(AWAR_DIFF_TYPE, VD_DISABLED)->add_callback(diff_type_changed_cb); |
---|
514 | awr->awar_string(AWAR_DIFF_NAME, "<none selected>"); |
---|
515 | awr->awar_string(AWAR_NODIFF_INDICATOR, " ")->add_callback(nodiff_indicator_changed_cb)->set_srt(" ?=?:? =?:?*=?"); |
---|
516 | awr->awar_int(AWAR_DIFF_MINDCASE, 1)->add_callback(diff_setting_changed_cb); |
---|
517 | awr->awar_int(AWAR_DIFF_MINDGAPTYPE, 1)->add_callback(diff_setting_changed_cb); |
---|
518 | awr->awar_string(AWAR_DIFF_GAPTYPES, GAP::anyGapChars())->add_callback(diff_setting_changed_cb); |
---|
519 | |
---|
520 | viewDifferences_awars_initialized = true; |
---|
521 | } |
---|
522 | } |
---|
523 | |
---|
524 | void ED4_toggle_viewDifferences(AW_root *awr) { |
---|
525 | static ViewDiffType lastActiveType = VD_SELECTED; |
---|
526 | |
---|
527 | create_viewDifferences_awars(awr); |
---|
528 | update_reference_settings(awr); |
---|
529 | |
---|
530 | AW_awar *awar_difftype = awr->awar(AWAR_DIFF_TYPE); |
---|
531 | ViewDiffType currType = ViewDiffType(awar_difftype->read_int()); |
---|
532 | |
---|
533 | if (currType == VD_DISABLED || !ED4_ROOT->reference->is_set()) { |
---|
534 | currType = lastActiveType; |
---|
535 | } |
---|
536 | else { |
---|
537 | lastActiveType = currType; |
---|
538 | currType = VD_DISABLED; |
---|
539 | } |
---|
540 | |
---|
541 | awar_difftype->rewrite_int(currType); // rewrite to allow activation after automatic deactivation in ED4_reference (e.g. by killing ref-term) |
---|
542 | } |
---|
543 | void ED4_viewDifferences_setNewReference() { |
---|
544 | set_current_as_diffRef(true); |
---|
545 | } |
---|
546 | void ED4_viewDifferences_announceTerminalChange() { |
---|
547 | if (ED4_ROOT->reference->is_set() && |
---|
548 | ED4_ROOT->aw_root->awar(AWAR_DIFF_TYPE)->read_int() == VD_FOLLOW) |
---|
549 | { |
---|
550 | ED4_viewDifferences_setNewReference(); |
---|
551 | } |
---|
552 | } |
---|
553 | void ED4_viewDifferences_disable() { |
---|
554 | set_current_as_diffRef(false); |
---|
555 | } |
---|
556 | |
---|
557 | AW_window *ED4_create_viewDifferences_window(AW_root *awr) { |
---|
558 | static AW_window_simple *aws = NULp; |
---|
559 | if (!aws) { |
---|
560 | if (!ED4_ROOT->reference->is_set()) ED4_toggle_viewDifferences(awr); // automatically activate if off |
---|
561 | |
---|
562 | aws = new AW_window_simple; |
---|
563 | aws->init(awr, "VIEW_DIFF", "View sequence differences"); |
---|
564 | aws->load_xfig("edit4/viewdiff.fig"); |
---|
565 | |
---|
566 | aws->at("close"); |
---|
567 | aws->callback(AW_POPDOWN); |
---|
568 | aws->create_button("CLOSE", "CLOSE", "C"); |
---|
569 | |
---|
570 | aws->at("help"); |
---|
571 | aws->callback(makeHelpCallback("viewdiff.hlp")); |
---|
572 | aws->create_button("HELP", "HELP"); |
---|
573 | |
---|
574 | aws->at("show"); |
---|
575 | aws->create_toggle_field(AWAR_DIFF_TYPE); |
---|
576 | aws->insert_toggle("None (=disable)", "N", VD_DISABLED); |
---|
577 | aws->insert_toggle("Selected:", "S", VD_SELECTED); |
---|
578 | aws->insert_toggle("Follow cursor", "F", VD_FOLLOW); |
---|
579 | aws->update_toggle_field(); |
---|
580 | |
---|
581 | aws->at("ref"); |
---|
582 | aws->button_length(20); |
---|
583 | aws->create_button(NULp, AWAR_DIFF_NAME, NULp, "+"); |
---|
584 | |
---|
585 | aws->at("set"); |
---|
586 | aws->button_length(4); |
---|
587 | aws->callback(change_reference_cb); |
---|
588 | aws->create_button("SET", "SET"); |
---|
589 | |
---|
590 | aws->at("nodiff"); |
---|
591 | aws->create_input_field(AWAR_NODIFF_INDICATOR); |
---|
592 | |
---|
593 | aws->at("case"); |
---|
594 | aws->create_toggle(AWAR_DIFF_MINDCASE); |
---|
595 | |
---|
596 | aws->at("gap"); |
---|
597 | aws->create_toggle(AWAR_DIFF_MINDGAPTYPE); |
---|
598 | aws->at("gapchars"); |
---|
599 | aws->create_input_field(AWAR_DIFF_GAPTYPES, 8); |
---|
600 | } |
---|
601 | return aws; |
---|
602 | } |
---|