source: trunk/NTREE/NT_split_ali.cxx

Last change on this file was 19432, checked in by westram, 17 months ago
  • GBT_get_alignment_len
    • now also reports error if alignment length is zero
      • this case often was unhandled and did easily lead to allocation problems.
    • catch error in case of zero alignment length ⇒ fixes alloc-size-larger-than-warning (in NT_count_different_chars).
    • check + fix callers.
File size: 23.6 KB
Line 
1// ========================================================= //
2//                                                           //
3//   File      : NT_split_ali.cxx                            //
4//   Purpose   : split alignments                            //
5//                                                           //
6//   Coded by Ralf Westram (coder@reallysoft.de) in Jun 22   //
7//   http://www.arb-home.de/                                 //
8//                                                           //
9// ========================================================= //
10
11#include "NT_local_proto.h"
12
13#include <arbdbt.h>
14#include <arb_progress.h>
15#include <arb_defs.h>
16#include <arb_strbuf.h>
17#include <pos_range.h>
18
19#include <aw_root.hxx>
20#include <aw_window.hxx>
21
22#include <limits>
23#include <vector>
24#include <insdel.h>
25
26using namespace std;
27
28typedef vector<ExplicitRange> RangeVec;
29
30static const int END__ = numeric_limits<int>::max();
31
32static GB_ERROR calculate_and_check_ranges(int ali_source_len, const int *splitBefore, RangeVec& ranges) {
33    GB_ERROR      error = NULp;
34    ExplicitRange rest(ali_source_len);
35    for (int p = 0; splitBefore[p] != END__ && !error; ++p) {
36        ExplicitRange next = intersection(ExplicitRange::prior(splitBefore[p]), rest);
37        if (next.is_empty()) {
38            if      (rest.is_empty())             error = GBS_global_string("position %i exceeds overall length (=%i)", p ? info2bio(splitBefore[p-1]) : 0, ali_source_len);
39            else if (splitBefore[p]<rest.start()) error = "invalid position order";
40            else                                  error = "empty range dectected";
41        }
42        else {
43            ranges.push_back(next);
44            rest = intersection(rest, next.after());
45        }
46    }
47
48    if (!error) {
49        if (rest.is_empty()) error = GBS_global_string("last position exceeds overall length (=%i)", ali_source_len);
50        else                 ranges.push_back(rest); //  append final range
51    }
52
53    return error;
54}
55
56CONSTEXPR_INLINE int digits(int parts) { // when using numbers from [1 .. parts]
57    return parts<0 ? digits(-parts) : (parts<10 ? 1 : (parts<100 ? 2 : 3)); // works up to 999
58}
59
60inline const char *target_ali_name(const char *ali_target_prefix, int p, int digits) {
61    static SmartCharPtr ali;
62    ali = GBS_global_string_copy("%s_%0*i", ali_target_prefix, digits, p+1);
63    return &*ali;
64}
65
66inline char *build_split_id(const RangeVec& ranges) {
67    GBS_strstruct buf(100);
68    for (size_t r = 0; r<ranges.size(); ++r) {
69        if (r>0) buf.put('-');
70        buf.putlong(ranges[r].size());
71    }
72    return buf.get_copy();
73}
74
75static GB_ERROR split_data_into_parts(GBDATA *gb_data, const RangeVec& ranges, const char *ali_target_prefix) {
76    GB_ERROR    error      = NULp;
77    char       *seq        = GB_read_as_string(gb_data);
78    const char *key        = GB_read_key_pntr(gb_data);
79    GB_TYPES    type       = GB_read_type(gb_data);
80    int         security   = GB_read_security_write(gb_data);
81    size_t      seq_len    = strlen(seq);
82    const int   parts      = ranges.size();
83    GBDATA     *gb_item    = GB_get_grandfather(gb_data);
84
85    // [Note: the way elements are handled here is a bit q&d; see EditedTerminal::apply for howto properly handle all data types]
86
87    // write splitted sequence data
88    for (int p = 0; p<parts && !error; ++p) {
89        const char *ali          = target_ali_name(ali_target_prefix, p, digits(parts));
90        GBDATA     *gb_part_data = GBT_create_sequence_data(gb_item, ali, key, type, security);
91
92        if (!gb_part_data) {
93            UNCOVERED();
94            error = GB_await_error();
95        }
96        else {
97            char *part = ranges[p].dup_corresponding_part(seq, seq_len);
98            error      = GB_write_autoconv_string(gb_part_data, part);
99            free(part);
100        }
101    }
102
103    free(seq);
104
105    return error;
106}
107
108static GB_ERROR copy_field_into_partial_alignments(GBDATA *gb_data, const int parts, const char *ali_target_prefix) {
109    GB_ERROR    error   = NULp;
110    GB_TYPES    type    = GB_read_type(gb_data);
111    GBDATA     *gb_item = GB_get_grandfather(gb_data);
112    const char *key     = GB_read_key_pntr(gb_data);
113
114    char *target_val;
115    if (type == GB_STRING) target_val = GBS_global_string_copy("[splitted] %s", GB_read_char_pntr(gb_data));
116    else {
117        target_val = GBS_global_string_copy("[split skipped copy of field '%s' (type: %i)]", key, type);
118        type       = GB_STRING;
119    }
120
121    const int security = GB_read_security_write(gb_data);
122    for (int p = 0; p<parts && !error; ++p) {
123        const char *ali          = target_ali_name(ali_target_prefix, p, digits(parts));
124        GBDATA     *gb_part_data = GBT_create_sequence_data(gb_item, ali, key, type, security);
125
126        error = GB_write_string(gb_part_data, target_val);
127    }
128    free(target_val);
129
130    return error;
131}
132
133static GB_ERROR split_alignment(GBDATA *gb_main, const char *ali_source, const char *ali_target_prefix, const int *splitBefore, bool markedOnly, bool overwriteAlignments) {
134    /*! splits one alignment into multiple alignments.
135     * @param ali_source name of source alignment
136     * @param ali_target_prefix prefix of target alignment. will be extended by '_1', '_2', ...
137     * @param splitBefore list of positions [0..N-1] where 2nd, 3rd, ... part shall begin. Terminate with 'END__'.
138     * @param markedOnly true->operate only on marked species, false->operate on all species
139     * @param overwriteAlignments true->delete+recreate existing alignments, false->bail-out with error
140     * @return error if sth went wrong.
141     */
142
143    GB_ERROR       error = NULp;
144    GB_transaction ta(gb_main);
145
146    arb_progress progress_main("Splitting sequences");
147
148    // check source alignment exists:
149    long ali_source_len = GBT_get_alignment_len(gb_main, ali_source);
150    if (ali_source_len<=0) {
151        error = GB_await_error();
152    }
153    else {
154        RangeVec ranges;
155        error = calculate_and_check_ranges(ali_source_len, splitBefore, ranges);
156
157        const int parts = ranges.size();
158        if (parts<2 && !error) {
159            error = GBS_global_string("Not enough parts (%i) specified to split alignment", parts);
160        }
161
162        // @@@ read the following values from source alignment:
163        bool        is_aligned = true; // @@@ if source alignment is not formatted -> abort with error (for safety and to avoid special cases here)
164        int         security   = 3;
165        const char *ali_type   = "rna";
166
167        char *split_id = build_split_id(ranges);
168
169        // create alignments:
170        for (int p = 0; p<parts && !error; ++p) {
171            const char *ali = target_ali_name(ali_target_prefix, p, digits(parts));
172            {
173                GBDATA *gb_ali = GBT_get_alignment(gb_main, ali);
174                if (!gb_ali) {
175                    GB_clear_error(); // from GBT_get_alignment
176                }
177                else {
178                    if (overwriteAlignments) {
179                        error = GBT_delete_alignment(gb_main, ali); // delete existing alignment
180                    }
181                    else {
182                        error = GBS_global_string("alignment '%s' already exists", ali);
183                    }
184                }
185            }
186            if (!error) {
187                // create target alignment:
188                const ExplicitRange&  range       = ranges[p];
189                char                 *why_created = GBS_global_string_copy("while splitting %s into %s [%i-%i]", ali_source, split_id, info2bio(range.start()), info2bio(range.end()));
190
191                GBDATA *gb_ali = GBT_create_alignment(gb_main, ali, ranges[p].size(), is_aligned, security, ali_type, why_created);
192                if (!gb_ali) {
193                    error = GB_await_error();
194                }
195                else {
196                    error = GBT_add_alignment_changekeys(gb_main, ali);
197                }
198
199                free(why_created);
200            }
201        }
202
203        if (!error) {
204            size_t data_count         = 0; // count species with sequence data in alignment (during pass 1)
205            size_t sai_data_count     = 0; // count sequence associated data in alignment containers of all SAIs (during pass 1)
206            size_t sequences_splitted = 0; // count splitted sequences (species)
207            size_t sai_data_splitted  = 0; // count splitted data entries (SAI; may be multiple per SAI)
208
209            SmartPtr<arb_progress> progress;
210
211            for (int pass = 1; pass<=2 && !error; ++pass) {
212                if (pass == 2) {
213                    progress = new arb_progress(data_count+sai_data_count);
214                    progress->auto_subtitles("seq");
215                }
216
217                // generate sequence data in splitted alignments:
218                for (GBDATA *gb_species = markedOnly ? GBT_first_marked_species(gb_main) : GBT_first_species(gb_main);
219                     gb_species && !error;
220                     gb_species = markedOnly ? GBT_next_marked_species(gb_species) : GBT_next_species(gb_species))
221                {
222                    GBDATA *gb_seq = GBT_find_sequence(gb_species, ali_source);
223                    if (gb_seq) {
224                        if (pass == 1) ++data_count;
225                        else           {
226                            error = split_data_into_parts(gb_seq, ranges, ali_target_prefix);
227                            if (!error) ++sequences_splitted; // count splits
228                            progress->inc_and_check_user_abort(error);
229                        }
230                    }
231                }
232
233                for (GBDATA *gb_sai = GBT_first_SAI(gb_main);  gb_sai && !error; gb_sai = GBT_next_SAI(gb_sai)) {
234                    GBDATA *gb_ali = GB_entry(gb_sai, ali_source);
235                    if (gb_ali) {
236                        for (GBDATA *gb_data = GB_child(gb_ali); gb_data && !error; gb_data = GB_nextChild(gb_data)) {
237                            if (ARB_is_alignment_relative_data(gb_data)) {
238                                if (pass == 1) {
239                                    ++sai_data_count;
240                                }
241                                else {
242                                    error = split_data_into_parts(gb_data, ranges, ali_target_prefix);
243                                    if (!error) ++sai_data_splitted; // count splits
244                                    progress->inc_and_check_user_abort(error);
245                                }
246                            }
247                            else if (pass == 2) {
248                                error = copy_field_into_partial_alignments(gb_data, parts, ali_target_prefix);
249                            }
250                        }
251                    }
252                }
253            }
254
255            if (!error) {
256                size_t overall_data_splitted = sequences_splitted + sai_data_splitted;
257                if (overall_data_splitted) {
258                    size_t split_count = overall_data_splitted*parts;
259                    fprintf(stdout, "Summary: splitted %zu element%s into %zu parts.\n", overall_data_splitted, plural(overall_data_splitted), split_count);
260                }
261                else {
262                    UNCOVERED();
263                    error = "No sequences were splitted (none of the handled species contained data in alignment; check settings)";
264                }
265            }
266        }
267
268        free(split_id);
269    }
270    error = ta.close(error);
271
272    return error;
273}
274
275// --------------------------------------------------------------------------------
276
277#ifdef UNIT_TESTS
278#include <arb_diff.h>
279#include <arb_file.h>
280#ifndef TEST_UNIT_H
281#include <test_unit.h>
282#endif
283
284// #define TEST_AUTO_UPDATE // uncomment to auto-update expected result DB
285
286void TEST_split_alignment() {
287    GB_shell  shell;
288    GBDATA   *gb_main = GB_open("TEST_prot_tiny.arb", "rw"); // source: ../UNIT_TESTER/run/TEST_prot_tiny.arb
289                                                             // target: ../UNIT_TESTER/run/TEST_split_expected.arb
290
291    // alignments existing in DB:
292    // --------------------------
293    // alignment_name   "ali_dna"            alignment_len    %i 337
294    // alignment_name   "ali_prot"           alignment_len    %i 112
295    // alignment_name   "ali_dna_incomplete" alignment_len    %i 337
296
297    {
298        GB_securityLevel raised(gb_main, 3);
299
300        // split some alignment
301        {
302            GB_transaction ta(gb_main);
303            TEST_EXPECT_NO_ERROR(GBT_restore_marked_species(gb_main, "CytLyti6;BctFra12;StrCoel9;MucRace2"));
304
305            int split[] = { 41, 175, END__ };
306            TEST_EXPECT_NO_ERROR(split_alignment(gb_main, "ali_dna", "ali_dna_split1", split, true, false));
307        }
308        {
309            GB_transaction ta(gb_main);
310            TEST_EXPECT_NO_ERROR(GBT_restore_marked_species(gb_main, "CytLyti6;TaxOcell;BctFra12;StrRamo3"));
311
312            int split[] = { 168, END__ }; // approx. split in the middle of the sequence
313            TEST_EXPECT_NO_ERROR(split_alignment(gb_main, "ali_dna", "ali_dna_split2", split, true, false));
314            TEST_EXPECT_NO_ERROR(split_alignment(gb_main, "ali_dna", "ali_overwrite", split, true, false)); // created to be overwritten below
315        }
316        {
317            GB_transaction ta(gb_main);
318            TEST_EXPECT_NO_ERROR(GBT_restore_marked_species(gb_main, "TaxOcell"));
319
320            int split[] = { 1, 160, 161, 336, END__ }; // test short parts (at 5'-end, in the middle and at 3'-end)
321            TEST_EXPECT_NO_ERROR(split_alignment(gb_main, "ali_dna", "ali_dna_split3", split, true, false));
322        }
323        {
324            GB_transaction ta(gb_main);
325
326            int split[] = { 25, 65, END__ };
327            TEST_EXPECT_NO_ERROR(split_alignment(gb_main, "ali_prot", "ali_prot_split", split, false, false));
328        }
329        { // split alignment not occurring in all species (applied to all species)
330            GB_transaction ta(gb_main);
331
332            int split[] = { 150, END__ };
333            TEST_EXPECT_NO_ERROR(split_alignment(gb_main, "ali_dna_incomplete", "ali_dna_incomplete_split", split, false, false));
334        }
335
336
337        // provoke errors (invalid ali positions):
338        {
339            int split[] = { END__ };
340            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_any", split, true, false),
341                                       "Not enough parts (1) specified to split alignment");
342        }
343        {
344            int split[] = { 41, 470, END__ }; // requests invalid split (beyond 3-end) -> error wanted
345            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_any", split, true, false),
346                                       "last position exceeds overall length (=337)");
347        }
348
349        {
350            int split[] = { 336, 4100, END__ }; // tests that offset 336 is a legal split position
351            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_any", split, true, false),
352                                       "last position exceeds overall length (=337)"); // 2nd offset causes this failure
353        }
354        {
355            int split[] = { 337, 4100, END__ }; // test that offset 337 is NO legal split position (no data behind)
356            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_any", split, true, false),
357                                       "position 338 exceeds overall length (=337)");
358        }
359        {
360            int split[] = { 338, 4100, END__ }; // requests invalid split (beyond 3-end) with first offset -> error wanted
361            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_any", split, true, false),
362                                       "position 339 exceeds overall length (=337)");
363        }
364        {
365            int split[] = { 0, 4100, END__ }; // requests invalid split (at 5-end) with first offset -> error wanted
366            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_any", split, true, false),
367                                       "empty range dectected");
368        }
369
370        {
371            int split[] = { 41, 30, 175, END__ }; // 2nd offset < 1st offset -> error wanted
372            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_any", split, true, false),
373                                       "invalid position order");
374        }
375        {
376            int split[] = { 41, 41, 175, END__ }; // empty range -> error wanted
377            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_any", split, true, false),
378                                       "empty range dectected");
379        }
380
381        {
382            // provoke error (no such alignment)
383            int split[] = { 41, 175, END__ };
384            TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_nosuch", "ali_any", split, true, false),
385                                       "alignment 'ali_nosuch' not found");
386        }
387
388        {
389            // provoke error (target alignment exists)
390
391            const char *ali_conflict    = "ali_existing_3";
392            GBDATA     *gb_ali_conflict = NULp;
393            {
394                GB_transaction ta(gb_main);
395                gb_ali_conflict = GBT_create_alignment(gb_main, ali_conflict, 123, 0, 0, "dna", "by TEST_split_alignment");
396                TEST_REJECT_NULL(gb_ali_conflict);
397            }
398
399            {
400                int split[] = { 41, 175, END__ };
401                TEST_EXPECT_ERROR_CONTAINS(split_alignment(gb_main, "ali_dna", "ali_existing", split, true, false),
402                                           "alignment 'ali_existing_3' already exists");
403            }
404
405            // overwrite existing alignment
406            {
407                GB_transaction ta(gb_main);
408                TEST_EXPECT_NO_ERROR(GBT_restore_marked_species(gb_main, "CytLyti6;BctFra12;MucRace2"));
409            }
410            {
411                int split[] = { 170, END__ }; // approx. split in the middle of the sequence (but different than in 1st split to ali_overwrite..)
412
413                GB_topSecurityLevel raise(gb_main);
414                TEST_EXPECT_NO_ERROR(split_alignment(gb_main, "ali_dna", "ali_overwrite", split, true, true));
415            }
416        }
417    }
418
419    GBT_mark_all(gb_main, 0); // clear marks before saving database
420
421    {
422        // save as ascii with different name + compare result with expected file
423
424        char *savename = ARB_strdup(GB_path_in_ARBHOME("UNIT_TESTER/run/TEST_split.arb"));
425        char *expected = ARB_strdup(GB_path_in_ARBHOME("UNIT_TESTER/run/TEST_split_expected.arb"));
426
427        TEST_EXPECT_NO_ERROR(GB_save_as(gb_main, savename, "a"));
428
429#if defined(TEST_AUTO_UPDATE)
430        TEST_COPY_FILE(savename, expected);
431#else // !defined(TEST_AUTO_UPDATE)
432        TEST_EXPECT_TEXTFILES_EQUAL(savename, expected);
433#endif
434        TEST_EXPECT_ZERO_OR_SHOW_ERRNO(GB_unlink(savename));
435
436        free(expected);
437        free(savename);
438    }
439
440    GB_close(gb_main);
441}
442
443#endif // UNIT_TESTS
444
445// --------------------------------------------------------------------------------
446
447#include "NT_local.h"
448
449#include <arb_strarray.h>
450
451#include <aw_awar.hxx>
452#include <aw_awar_defs.hxx>
453#include <aw_msg.hxx>
454
455
456#define AWAR_SPLIT_ALI_BASE "split_ali/"
457#define AWAR_SPLIT_ALI_BTMP "tmp/" AWAR_SPLIT_ALI_BASE
458
459#define AWAR_SPLIT_ALI_TARGET    AWAR_SPLIT_ALI_BTMP "target"
460#define AWAR_SPLIT_ALI_POSITIONS AWAR_SPLIT_ALI_BASE "pos"
461#define AWAR_SPLIT_ALI_MARKED    AWAR_SPLIT_ALI_BASE "marked"
462#define AWAR_SPLIT_ALI_OVERWRITE AWAR_SPLIT_ALI_BASE "overwrite"
463
464static void create_splitAlignment_awars(AW_root *root, AW_default properties, GBDATA *gb_main) {
465    // use current alignment to init default for target alignment:
466    const char *ali_part = "ali_example_part";
467    {
468        char *ali_source = GBT_get_default_alignment(gb_main);
469        if (!ali_source) GB_clear_error();
470        else             ali_part = GBS_global_string("%s_part", ali_source);
471        free(ali_source);
472    }
473
474    root->awar_string(AWAR_SPLIT_ALI_TARGET,    ali_part, properties);
475    root->awar_string(AWAR_SPLIT_ALI_POSITIONS, "",       properties);
476    root->awar_int   (AWAR_SPLIT_ALI_MARKED,    0,        properties);
477    root->awar_int   (AWAR_SPLIT_ALI_OVERWRITE, 0,        properties);
478
479    root->awar_string(AWAR_RANGE, "", gb_main);
480}
481
482static void split_ali_cb(AW_window *aww) {
483    AW_root  *awr     = aww->get_root();
484    GBDATA   *gb_main = GLOBAL.gb_main;
485    GB_ERROR  error   = NULp;
486
487    char *ali_source = GBT_get_default_alignment(gb_main);
488    if (!ali_source) {
489        error = GB_await_error();
490    }
491    else {
492        char *ali_target_prefix = awr->awar(AWAR_SPLIT_ALI_TARGET)->read_string();
493
494        ConstStrArray numbers;
495        {
496            char *split_pos_list    = awr->awar(AWAR_SPLIT_ALI_POSITIONS)->read_string();
497            GBT_splitNdestroy_string(numbers, split_pos_list, ", ", SPLIT_DROPEMPTY);
498        }
499
500        int split_positions[numbers.size()+1];
501        for (size_t n = 0; n<numbers.size() && !error; ++n) {
502            const char *num    = numbers[n];
503            split_positions[n] = bio2info(atoi(num));
504            if (split_positions[n]<1) {
505                error = GBS_global_string("invalid position '%s'", num); // shows biological position
506            }
507        }
508        split_positions[numbers.size()] = END__;
509
510        if (!error) {
511            bool markedOnly = awr->awar(AWAR_SPLIT_ALI_MARKED)->read_int();
512            bool overwrite  = awr->awar(AWAR_SPLIT_ALI_OVERWRITE)->read_int();
513
514            error = split_alignment(gb_main, ali_source, ali_target_prefix, split_positions, markedOnly, overwrite);
515        }
516
517        free(ali_target_prefix);
518        free(ali_source);
519    }
520
521    aw_message_if(error);
522}
523
524static void use_editor_range_cb(AW_window *aww) {
525    AW_root    *awr          = aww->get_root();
526    GB_ERROR    error        = NULp;
527    const char *editor_range = awr->awar(AWAR_RANGE)->read_char_pntr();
528    const char *hyphen       = strchr(editor_range, '-');
529
530    if (!hyphen) {
531        if (editor_range[0]) {
532            error = "expected range to contain '-'.";
533        }
534        else {
535            error = "No block has been highlighted in sequence editor.";
536        }
537    }
538    else {
539        long i1 = atol(editor_range);
540        long i2 = atol(hyphen+1);
541
542        const char *pos_list = GBS_global_string("%li,%li", i1, i2+1); // split BEFORE i1 + AFTER i2
543        awr->awar(AWAR_SPLIT_ALI_POSITIONS)->write_string(pos_list);
544    }
545
546    aw_message_if(error);
547}
548
549AW_window *NT_create_splitAlignment_window(AW_root *awr) {
550    create_splitAlignment_awars(awr, AW_ROOT_DEFAULT, GLOBAL.gb_main);
551
552    AW_window_simple *aws = new AW_window_simple;
553    aws->init(awr, "SPLIT_ALIGNMENT", "Split alignment");
554
555    const int PAD = 10;
556
557    const int BUTTON_LENGTH = 10;
558    const int FIELD_LENGTH  = 40;
559    const int LABEL_LENGTH  = 30;
560
561    aws->at(PAD, PAD);
562    aws->auto_space(PAD/2, PAD);
563
564    aws->button_length(BUTTON_LENGTH);
565
566    aws->callback(AW_POPDOWN);
567    aws->create_button("CLOSE", "Close", "C");
568
569    aws->callback(makeHelpCallback("split.hlp"));
570    aws->create_button("HELP", "Help", "H");
571
572    aws->at_newline();
573
574    aws->label_length(LABEL_LENGTH);
575
576    aws->label("Target alignment prefix:");
577    aws->create_input_field(AWAR_SPLIT_ALI_TARGET, FIELD_LENGTH);
578    aws->at_newline();
579
580    aws->label("Position(s) to split before:\n"
581               "(comma-separated)");
582    aws->create_input_field(AWAR_SPLIT_ALI_POSITIONS, FIELD_LENGTH);
583    aws->at_newline();
584
585    aws->button_length(LABEL_LENGTH-1);
586    aws->callback(use_editor_range_cb);
587    aws->create_button("USE_EDITOR_RANGE", "Use editor range:");
588    aws->button_length(FIELD_LENGTH);
589    aws->create_button(NULp, AWAR_RANGE, "", "-");
590    aws->button_length(BUTTON_LENGTH);
591    aws->at_newline();
592
593    aws->label("Split marked only:");
594    aws->create_toggle(AWAR_SPLIT_ALI_MARKED);
595    aws->at_newline();
596
597    aws->label("Overwrite existing alignments:\n"
598               "(deletes ALL data)");
599    aws->create_toggle(AWAR_SPLIT_ALI_OVERWRITE);
600    aws->at_newline();
601
602    aws->callback(split_ali_cb);
603    aws->create_button("GO", "GO", "G");
604
605    return aws;
606}
607
Note: See TracBrowser for help on using the repository browser.