| 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) aws->create_toggle_field(AWAR_SEQ_NAME_SELECTOR_NA, "Select color-set for Nucleotides (NA):", AW_HORIZONTAL); |
|---|
| 141 | else aws->create_toggle_field(AWAR_SEQ_NAME_SELECTOR_AA, "Select color-set for Amino Acids (AA):", AW_HORIZONTAL); |
|---|
| 142 | |
|---|
| 143 | for (int cset = 0; cset < SEQ_COLOR_SETS; cset++) { |
|---|
| 144 | sprintf(buf, "%i", cset+1); |
|---|
| 145 | aws->insert_toggle(buf, " ", cset); |
|---|
| 146 | } |
|---|
| 147 | aws->update_toggle_field(); |
|---|
| 148 | aws->at_newline(); |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | const int BIG_COLUMNS = 2; |
|---|
| 152 | const int CHAR_COL_WIDTH = 4; |
|---|
| 153 | const int SET_COL_WIDTH = 2; |
|---|
| 154 | |
|---|
| 155 | int col_x_off[BIG_COLUMNS][SEQ_COLOR_SETS+1]; |
|---|
| 156 | |
|---|
| 157 | aws->auto_space(3, 2); |
|---|
| 158 | |
|---|
| 159 | for (int bcol = 0; bcol<BIG_COLUMNS; ++bcol) { |
|---|
| 160 | col_x_off[bcol][0] = aws->get_at_xposition(); |
|---|
| 161 | aws->button_length(CHAR_COL_WIDTH); |
|---|
| 162 | aws->create_button(NULp, "Chars"); |
|---|
| 163 | |
|---|
| 164 | aws->button_length(SET_COL_WIDTH); |
|---|
| 165 | for (int cset = 0; cset < SEQ_COLOR_SETS; cset++) { |
|---|
| 166 | sprintf(buf, " %i", cset+1); |
|---|
| 167 | col_x_off[bcol][cset+1] = aws->get_at_xposition(); |
|---|
| 168 | aws->create_button(NULp, buf); |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | if (!bcol) { |
|---|
| 172 | int set_col_pixel_width = col_x_off[0][1]-col_x_off[0][0]; |
|---|
| 173 | aws->at_x(aws->get_at_xposition()+set_col_pixel_width); |
|---|
| 174 | } |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | aws->at_newline(); |
|---|
| 178 | |
|---|
| 179 | const int ROWS = SEQ_COLOR_SET_ELEMS/2; |
|---|
| 180 | for (int r = 0; r<ROWS; r++) { |
|---|
| 181 | for (int bcol = 0; bcol<BIG_COLUMNS; ++bcol) { |
|---|
| 182 | int elem = bcol*ROWS+r; |
|---|
| 183 | |
|---|
| 184 | sprintf(buf, AWAR_SEQ_NAME_STRINGS_TEMPLATE, elem); |
|---|
| 185 | aws->at_x(col_x_off[bcol][0]); |
|---|
| 186 | aws->create_input_field(buf, CHAR_COL_WIDTH); |
|---|
| 187 | |
|---|
| 188 | for (int cset = 0; cset < SEQ_COLOR_SETS; cset++) { |
|---|
| 189 | sprintf(buf, AWAR_SEQ_NAME_TEMPLATE, cset, elem); |
|---|
| 190 | aws->at_x(col_x_off[bcol][cset+1]); |
|---|
| 191 | aws->create_input_field(buf, SET_COL_WIDTH); |
|---|
| 192 | } |
|---|
| 193 | } |
|---|
| 194 | aws->at_newline(); |
|---|
| 195 | } |
|---|
| 196 | |
|---|
| 197 | aws->window_fit(); |
|---|
| 198 | |
|---|
| 199 | return aws; |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | // GC order needed for sequence coloring |
|---|
| 203 | STATIC_ASSERT((ED4_G_SEQUENCES+1) == ED4_G_HELIX); |
|---|
| 204 | STATIC_ASSERT((ED4_G_HELIX+1) == ED4_G_COLOR_2); |
|---|
| 205 | |
|---|
| 206 | void ED4_seq_colors::reload() { |
|---|
| 207 | for (int i=0; i<256; i++) { // LOOP_VECTORIZED =1[<8] =2 // 2x for >=8.1; 1x for 7.4 (tested down to gcc 5.5.0 (may fail on older gcc versions)) |
|---|
| 208 | char_2_gc[i] = char_2_gc_aa[i] = base_gc; |
|---|
| 209 | char_2_char[i] = char_2_char_aa[i] = i; |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | AW_root *aw_root = AW_root::SINGLETON; |
|---|
| 213 | |
|---|
| 214 | if (!seq_color_awars_created) create_seq_color_awars(aw_root, this); |
|---|
| 215 | |
|---|
| 216 | const char *selector_awar[2] = { AWAR_SEQ_NAME_SELECTOR_NA, AWAR_SEQ_NAME_SELECTOR_AA }; |
|---|
| 217 | |
|---|
| 218 | for (int selector = 0; selector<2; selector++) { |
|---|
| 219 | long def_set = selector == 0 ? default_NUC_set : default_AMI_set; |
|---|
| 220 | long cset = aw_root->awar(selector_awar[selector])->read_int(); |
|---|
| 221 | |
|---|
| 222 | if (cset < 0 || cset >= SEQ_COLOR_SETS) { |
|---|
| 223 | cset = def_set; |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | for (int elem = 0; elem < SEQ_COLOR_SET_ELEMS; elem++) { |
|---|
| 227 | char awar_name[256]; |
|---|
| 228 | |
|---|
| 229 | sprintf(awar_name, AWAR_SEQ_NAME_STRINGS_TEMPLATE, elem); |
|---|
| 230 | unsigned char *sc = (unsigned char *)aw_root->awar(awar_name)->read_string(); |
|---|
| 231 | |
|---|
| 232 | sprintf(awar_name, AWAR_SEQ_NAME_TEMPLATE, (int)cset, elem); |
|---|
| 233 | char *val = aw_root->awar(awar_name)->read_string(); |
|---|
| 234 | if (!val[0]) freedup(val, "=0"); // interpret '' as ' = 0' |
|---|
| 235 | |
|---|
| 236 | if (strlen(val) != 2 || val[1] >'9' || val[1] < '0') { |
|---|
| 237 | aw_message(GB_export_errorf("Error in Color Lookup Table: '%s' is not of type X#", val)); |
|---|
| 238 | } |
|---|
| 239 | else { |
|---|
| 240 | if (selector == 0) { // Nucleotide colors |
|---|
| 241 | for (int i=0; sc[i]; i++) { |
|---|
| 242 | char_2_gc[sc[i]] = val[1]-'0' + base_gc; |
|---|
| 243 | if (val[0] != '=') char_2_char[sc[i]] = val[0]; |
|---|
| 244 | } |
|---|
| 245 | } |
|---|
| 246 | else { |
|---|
| 247 | for (int i=0; sc[i]; i++) { |
|---|
| 248 | char_2_gc_aa[sc[i]] = val[1]-'0' + base_gc; |
|---|
| 249 | if (val[0] != '=') char_2_char_aa[sc[i]] = val[0]; |
|---|
| 250 | } |
|---|
| 251 | } |
|---|
| 252 | } |
|---|
| 253 | free(val); |
|---|
| 254 | free(sc); |
|---|
| 255 | } |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | run_cb(); |
|---|
| 259 | } |
|---|
| 260 | |
|---|
| 261 | ED4_seq_colors::ED4_seq_colors(int baseGC, void (*changed_cb)()) { |
|---|
| 262 | cb = changed_cb; |
|---|
| 263 | base_gc = baseGC; |
|---|
| 264 | |
|---|
| 265 | this->reload(); |
|---|
| 266 | } |
|---|
| 267 | |
|---|
| 268 | // ----------------------- |
|---|
| 269 | // ED4_reference |
|---|
| 270 | |
|---|
| 271 | ED4_reference::ED4_reference() : |
|---|
| 272 | nodiff('#'), // notused; overwritten by user default later |
|---|
| 273 | mindcase(true), |
|---|
| 274 | ref_len(0), |
|---|
| 275 | reference(NULp), |
|---|
| 276 | ref_term(NULp) |
|---|
| 277 | { |
|---|
| 278 | reset_gap_table(); |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | ED4_reference::~ED4_reference() { |
|---|
| 282 | clear(); |
|---|
| 283 | } |
|---|
| 284 | |
|---|
| 285 | void ED4_reference::reset_gap_table() { |
|---|
| 286 | for (int i = 0; i<256; ++i) is_gap[i] = false; |
|---|
| 287 | } |
|---|
| 288 | |
|---|
| 289 | void ED4_reference::set_gap_handling(bool mindgaptype, const char *gaptypes) { |
|---|
| 290 | reset_gap_table(); |
|---|
| 291 | if (!mindgaptype) { // treat all gaps as "equal" |
|---|
| 292 | for (int i = 0; gaptypes[i]; ++i) { |
|---|
| 293 | is_gap[safeCharIndex(gaptypes[i])] = true; |
|---|
| 294 | } |
|---|
| 295 | } |
|---|
| 296 | } |
|---|
| 297 | |
|---|
| 298 | void ED4_reference::expand_to_length(int len) { |
|---|
| 299 | if (len>ref_len && is_set()) { |
|---|
| 300 | char *ref2 = ARB_calloc<char>(len+1); |
|---|
| 301 | |
|---|
| 302 | if (reference) { |
|---|
| 303 | strcpy(ref2, reference); |
|---|
| 304 | free(reference); |
|---|
| 305 | } |
|---|
| 306 | reference = ref2; |
|---|
| 307 | ref_len = len; |
|---|
| 308 | } |
|---|
| 309 | } |
|---|
| 310 | |
|---|
| 311 | void ED4_reference::update_data() { |
|---|
| 312 | freeset(reference, ref_term->get_sequence_copy(&ref_len)); |
|---|
| 313 | } |
|---|
| 314 | |
|---|
| 315 | void ED4_reference::data_changed_cb(ED4_species_manager *IF_ASSERTION_USED(calledFrom)) { |
|---|
| 316 | e4_assert(ref_term); |
|---|
| 317 | if (ref_term) { |
|---|
| 318 | #if defined(ASSERTION_USED) |
|---|
| 319 | if (calledFrom) e4_assert(ref_term->get_parent(LEV_SPECIES)->to_species_manager() == calledFrom); |
|---|
| 320 | #endif |
|---|
| 321 | update_data(); |
|---|
| 322 | } |
|---|
| 323 | } |
|---|
| 324 | static void refdata_changed_cb(ED4_species_manager *sman, ED4_reference *ref) { |
|---|
| 325 | ref->data_changed_cb(sman); |
|---|
| 326 | ED4_ROOT->request_refresh_for_specific_terminals(LEV_SEQUENCE_STRING); // refresh all sequences |
|---|
| 327 | } |
|---|
| 328 | static void refdata_deleted_cb() { |
|---|
| 329 | ED4_viewDifferences_disable(); |
|---|
| 330 | } |
|---|
| 331 | |
|---|
| 332 | void ED4_reference::clear() { |
|---|
| 333 | // remove change cb |
|---|
| 334 | if (ref_term) { |
|---|
| 335 | ED4_species_manager *sman = ref_term->get_parent(LEV_SPECIES)->to_species_manager(); |
|---|
| 336 | sman->remove_sequence_changed_cb(makeED4_species_managerCallback(refdata_changed_cb, this)); |
|---|
| 337 | sman->remove_delete_callback(makeED4_managerCallback(refdata_deleted_cb)); |
|---|
| 338 | } |
|---|
| 339 | |
|---|
| 340 | freenull(reference); |
|---|
| 341 | ref_len = 0; |
|---|
| 342 | ref_term = NULp; |
|---|
| 343 | } |
|---|
| 344 | |
|---|
| 345 | void ED4_reference::define(const ED4_sequence_terminal *rterm) { |
|---|
| 346 | clear(); |
|---|
| 347 | ref_term = rterm; |
|---|
| 348 | update_data(); |
|---|
| 349 | |
|---|
| 350 | // add change cb |
|---|
| 351 | ED4_species_manager *sman = ref_term->get_parent(LEV_SPECIES)->to_species_manager(); |
|---|
| 352 | sman->add_sequence_changed_cb(makeED4_species_managerCallback(refdata_changed_cb, this)); |
|---|
| 353 | sman->add_delete_callback(makeED4_managerCallback(refdata_deleted_cb)); |
|---|
| 354 | } |
|---|
| 355 | |
|---|
| 356 | bool ED4_reference::reference_is_a_consensus() const { |
|---|
| 357 | return is_set() && ref_term->is_consensus_sequence_terminal(); |
|---|
| 358 | } |
|---|
| 359 | |
|---|
| 360 | // -------------------------------------------------------------------------------- |
|---|
| 361 | |
|---|
| 362 | #define APREFIX_DIFF_SAVE "edit4/diff/" |
|---|
| 363 | #define APREFIX_DIFF_TEMP "tmp/" APREFIX_DIFF_SAVE |
|---|
| 364 | |
|---|
| 365 | #define AWAR_DIFF_TYPE APREFIX_DIFF_TEMP "type" |
|---|
| 366 | #define AWAR_DIFF_NAME APREFIX_DIFF_TEMP "name" |
|---|
| 367 | #define AWAR_NODIFF_INDICATOR APREFIX_DIFF_SAVE "indicator" |
|---|
| 368 | #define AWAR_DIFF_MINDCASE APREFIX_DIFF_SAVE "mindcase" |
|---|
| 369 | #define AWAR_DIFF_MINDGAPTYPE APREFIX_DIFF_SAVE "mindgaptype" |
|---|
| 370 | #define AWAR_DIFF_GAPTYPES APREFIX_DIFF_SAVE "gaptypes" |
|---|
| 371 | |
|---|
| 372 | enum ViewDiffType { |
|---|
| 373 | VD_DISABLED, |
|---|
| 374 | VD_SELECTED, |
|---|
| 375 | VD_FOLLOW, |
|---|
| 376 | }; |
|---|
| 377 | |
|---|
| 378 | static ED4_terminal *detect_current_ref_terminal() { |
|---|
| 379 | ED4_cursor *cursor = ¤t_cursor(); |
|---|
| 380 | ED4_terminal *refTerm = cursor->owner_of_cursor; |
|---|
| 381 | |
|---|
| 382 | if (refTerm) { |
|---|
| 383 | if (!(refTerm->is_consensus_terminal() || |
|---|
| 384 | refTerm->is_SAI_terminal() || |
|---|
| 385 | refTerm->is_species_seq_terminal())) |
|---|
| 386 | { |
|---|
| 387 | refTerm = NULp; |
|---|
| 388 | } |
|---|
| 389 | } |
|---|
| 390 | |
|---|
| 391 | if (!refTerm) { |
|---|
| 392 | aw_message("Please set the cursor to a species, SAI or group consensus."); |
|---|
| 393 | } |
|---|
| 394 | |
|---|
| 395 | return refTerm; |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | static void set_diff_reference(ED4_terminal *refTerm) { |
|---|
| 399 | ED4_reference *ref = ED4_ROOT->reference; |
|---|
| 400 | if (!refTerm) { |
|---|
| 401 | ref->clear(); |
|---|
| 402 | } |
|---|
| 403 | else { |
|---|
| 404 | ED4_sequence_terminal *refSeqTerm = dynamic_cast<ED4_sequence_terminal*>(refTerm); |
|---|
| 405 | if (refSeqTerm) { |
|---|
| 406 | AW_awar *awar_refName = AW_root::SINGLETON->awar(AWAR_DIFF_NAME); |
|---|
| 407 | ED4_species_name_terminal *nameTerm = refSeqTerm->corresponding_species_name_terminal(); |
|---|
| 408 | |
|---|
| 409 | ref->define(refSeqTerm); |
|---|
| 410 | if (refTerm->is_consensus_terminal()) { |
|---|
| 411 | awar_refName->write_string(GBS_global_string("consensus %s", nameTerm->get_displayed_text())); |
|---|
| 412 | } |
|---|
| 413 | else { |
|---|
| 414 | e4_assert(refTerm->is_species_seq_terminal() || refTerm->is_SAI_terminal()); |
|---|
| 415 | awar_refName->write_string(nameTerm->get_displayed_text()); |
|---|
| 416 | } |
|---|
| 417 | } |
|---|
| 418 | else { |
|---|
| 419 | aw_message("Not supported for this terminal type"); |
|---|
| 420 | } |
|---|
| 421 | } |
|---|
| 422 | |
|---|
| 423 | ED4_ROOT->request_refresh_for_specific_terminals(LEV_SEQUENCE_STRING); |
|---|
| 424 | } |
|---|
| 425 | |
|---|
| 426 | static SmartCharPtr last_used_ref_term_name; |
|---|
| 427 | |
|---|
| 428 | static void set_current_as_diffRef(bool enable) { |
|---|
| 429 | ED4_MostRecentWinContext context; |
|---|
| 430 | |
|---|
| 431 | ED4_terminal *refTerm = enable ? detect_current_ref_terminal() : NULp; |
|---|
| 432 | if (!enable || refTerm) { // do not disable, if current terminal has wrong type |
|---|
| 433 | set_diff_reference(refTerm); |
|---|
| 434 | if (refTerm) last_used_ref_term_name = ARB_strdup(refTerm->id); |
|---|
| 435 | } |
|---|
| 436 | } |
|---|
| 437 | |
|---|
| 438 | static void change_reference_cb(AW_window *aww) { |
|---|
| 439 | set_current_as_diffRef(true); |
|---|
| 440 | |
|---|
| 441 | AW_awar *awar_refType = aww->get_root()->awar(AWAR_DIFF_TYPE); |
|---|
| 442 | if (awar_refType->read_int() == VD_DISABLED) { |
|---|
| 443 | awar_refType->write_int(VD_SELECTED); |
|---|
| 444 | } |
|---|
| 445 | } |
|---|
| 446 | |
|---|
| 447 | static void diff_type_changed_cb(AW_root *awr) { |
|---|
| 448 | AW_awar *awar_refType = awr->awar(AWAR_DIFF_TYPE); |
|---|
| 449 | ViewDiffType type = ViewDiffType(awar_refType->read_int()); |
|---|
| 450 | |
|---|
| 451 | switch (type) { |
|---|
| 452 | case VD_DISABLED: |
|---|
| 453 | set_current_as_diffRef(false); |
|---|
| 454 | break; |
|---|
| 455 | |
|---|
| 456 | case VD_FOLLOW: |
|---|
| 457 | case VD_SELECTED: { |
|---|
| 458 | ED4_terminal *last_used_ref_term = NULp; |
|---|
| 459 | if (last_used_ref_term_name.isSet()) { |
|---|
| 460 | ED4_base *found = ED4_ROOT->main_manager->search_ID(&*last_used_ref_term_name); |
|---|
| 461 | if (found && found->is_terminal()) { |
|---|
| 462 | last_used_ref_term = found->to_terminal(); |
|---|
| 463 | } |
|---|
| 464 | } |
|---|
| 465 | if (last_used_ref_term) { |
|---|
| 466 | set_diff_reference(last_used_ref_term); |
|---|
| 467 | if (type == VD_FOLLOW) set_current_as_diffRef(true); |
|---|
| 468 | } |
|---|
| 469 | else { |
|---|
| 470 | set_current_as_diffRef(true); |
|---|
| 471 | } |
|---|
| 472 | if (!ED4_ROOT->reference->is_set()) { |
|---|
| 473 | awar_refType->write_int(VD_DISABLED); |
|---|
| 474 | } |
|---|
| 475 | break; |
|---|
| 476 | } |
|---|
| 477 | } |
|---|
| 478 | } |
|---|
| 479 | |
|---|
| 480 | static void update_reference_settings(AW_root *awr) { |
|---|
| 481 | ED4_reference *ref = ED4_ROOT->reference; |
|---|
| 482 | ref->set_nodiff_indicator(awr->awar(AWAR_NODIFF_INDICATOR)->read_char_pntr()[0]); |
|---|
| 483 | ref->set_case_sensitive(awr->awar(AWAR_DIFF_MINDCASE)->read_int()); |
|---|
| 484 | ref->set_gap_handling(awr->awar(AWAR_DIFF_MINDGAPTYPE)->read_int(), awr->awar(AWAR_DIFF_GAPTYPES)->read_char_pntr()); |
|---|
| 485 | } |
|---|
| 486 | static void diff_setting_changed_cb(AW_root *awr) { |
|---|
| 487 | update_reference_settings(awr); |
|---|
| 488 | ED4_ROOT->request_refresh_for_specific_terminals(LEV_SEQUENCE_STRING); |
|---|
| 489 | } |
|---|
| 490 | |
|---|
| 491 | static void nodiff_indicator_changed_cb(AW_root *awr) { |
|---|
| 492 | AW_awar *awar_indicator = awr->awar(AWAR_NODIFF_INDICATOR); |
|---|
| 493 | const char *indicator = awar_indicator->read_char_pntr(); |
|---|
| 494 | |
|---|
| 495 | if (!indicator[0]) { |
|---|
| 496 | awar_indicator->write_string(" "); |
|---|
| 497 | } |
|---|
| 498 | else { |
|---|
| 499 | diff_setting_changed_cb(awr); |
|---|
| 500 | } |
|---|
| 501 | } |
|---|
| 502 | |
|---|
| 503 | static bool viewDifferences_awars_initialized = false; |
|---|
| 504 | |
|---|
| 505 | static void create_viewDifferences_awars(AW_root *awr) { |
|---|
| 506 | if (!viewDifferences_awars_initialized) { |
|---|
| 507 | awr->awar_int(AWAR_DIFF_TYPE, VD_DISABLED)->add_callback(diff_type_changed_cb); |
|---|
| 508 | awr->awar_string(AWAR_DIFF_NAME, "<none selected>"); |
|---|
| 509 | awr->awar_string(AWAR_NODIFF_INDICATOR, " ")->add_callback(nodiff_indicator_changed_cb)->set_srt(" ?=?:? =?:?*=?"); |
|---|
| 510 | awr->awar_int(AWAR_DIFF_MINDCASE, 1)->add_callback(diff_setting_changed_cb); |
|---|
| 511 | awr->awar_int(AWAR_DIFF_MINDGAPTYPE, 1)->add_callback(diff_setting_changed_cb); |
|---|
| 512 | awr->awar_string(AWAR_DIFF_GAPTYPES, GAP::anyGapChars())->add_callback(diff_setting_changed_cb); |
|---|
| 513 | |
|---|
| 514 | viewDifferences_awars_initialized = true; |
|---|
| 515 | } |
|---|
| 516 | } |
|---|
| 517 | |
|---|
| 518 | void ED4_toggle_viewDifferences(AW_root *awr) { |
|---|
| 519 | static ViewDiffType lastActiveType = VD_SELECTED; |
|---|
| 520 | |
|---|
| 521 | create_viewDifferences_awars(awr); |
|---|
| 522 | update_reference_settings(awr); |
|---|
| 523 | |
|---|
| 524 | AW_awar *awar_difftype = awr->awar(AWAR_DIFF_TYPE); |
|---|
| 525 | ViewDiffType currType = ViewDiffType(awar_difftype->read_int()); |
|---|
| 526 | |
|---|
| 527 | if (currType == VD_DISABLED || !ED4_ROOT->reference->is_set()) { |
|---|
| 528 | currType = lastActiveType; |
|---|
| 529 | } |
|---|
| 530 | else { |
|---|
| 531 | lastActiveType = currType; |
|---|
| 532 | currType = VD_DISABLED; |
|---|
| 533 | } |
|---|
| 534 | |
|---|
| 535 | awar_difftype->rewrite_int(currType); // rewrite to allow activation after automatic deactivation in ED4_reference (e.g. by killing ref-term) |
|---|
| 536 | } |
|---|
| 537 | void ED4_viewDifferences_setNewReference() { |
|---|
| 538 | set_current_as_diffRef(true); |
|---|
| 539 | } |
|---|
| 540 | void ED4_viewDifferences_announceTerminalChange() { |
|---|
| 541 | if (ED4_ROOT->reference->is_set() && |
|---|
| 542 | ED4_ROOT->aw_root->awar(AWAR_DIFF_TYPE)->read_int() == VD_FOLLOW) |
|---|
| 543 | { |
|---|
| 544 | ED4_viewDifferences_setNewReference(); |
|---|
| 545 | } |
|---|
| 546 | } |
|---|
| 547 | void ED4_viewDifferences_disable() { |
|---|
| 548 | set_current_as_diffRef(false); |
|---|
| 549 | } |
|---|
| 550 | |
|---|
| 551 | AW_window *ED4_create_viewDifferences_window(AW_root *awr) { |
|---|
| 552 | static AW_window_simple *aws = NULp; |
|---|
| 553 | if (!aws) { |
|---|
| 554 | if (!ED4_ROOT->reference->is_set()) ED4_toggle_viewDifferences(awr); // automatically activate if off |
|---|
| 555 | |
|---|
| 556 | aws = new AW_window_simple; |
|---|
| 557 | aws->init(awr, "VIEW_DIFF", "View sequence differences"); |
|---|
| 558 | aws->load_xfig("edit4/viewdiff.fig"); |
|---|
| 559 | |
|---|
| 560 | aws->at("close"); |
|---|
| 561 | aws->callback(AW_POPDOWN); |
|---|
| 562 | aws->create_button("CLOSE", "CLOSE", "C"); |
|---|
| 563 | |
|---|
| 564 | aws->at("help"); |
|---|
| 565 | aws->callback(makeHelpCallback("viewdiff.hlp")); |
|---|
| 566 | aws->create_button("HELP", "HELP"); |
|---|
| 567 | |
|---|
| 568 | aws->at("show"); |
|---|
| 569 | aws->create_toggle_field(AWAR_DIFF_TYPE); |
|---|
| 570 | aws->insert_toggle("None (=disable)", "N", VD_DISABLED); |
|---|
| 571 | aws->insert_toggle("Selected:", "S", VD_SELECTED); |
|---|
| 572 | aws->insert_toggle("Follow cursor", "F", VD_FOLLOW); |
|---|
| 573 | aws->update_toggle_field(); |
|---|
| 574 | |
|---|
| 575 | aws->at("ref"); |
|---|
| 576 | aws->button_length(20); |
|---|
| 577 | aws->create_button(NULp, AWAR_DIFF_NAME, NULp, "+"); |
|---|
| 578 | |
|---|
| 579 | aws->at("set"); |
|---|
| 580 | aws->button_length(4); |
|---|
| 581 | aws->callback(change_reference_cb); |
|---|
| 582 | aws->create_button("SET", "SET"); |
|---|
| 583 | |
|---|
| 584 | aws->at("nodiff"); |
|---|
| 585 | aws->create_input_field(AWAR_NODIFF_INDICATOR); |
|---|
| 586 | |
|---|
| 587 | aws->at("case"); |
|---|
| 588 | aws->create_toggle(AWAR_DIFF_MINDCASE); |
|---|
| 589 | |
|---|
| 590 | aws->at("gap"); |
|---|
| 591 | aws->create_toggle(AWAR_DIFF_MINDGAPTYPE); |
|---|
| 592 | aws->at("gapchars"); |
|---|
| 593 | aws->create_input_field(AWAR_DIFF_GAPTYPES, 8); |
|---|
| 594 | } |
|---|
| 595 | return aws; |
|---|
| 596 | } |
|---|