source: trunk/EDIT4/ED4_base.cxx

Last change on this file was 19206, checked in by westram, 21 months ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.3 KB
Line 
1#include <arbdbt.h>
2#include <ad_cb.h>
3
4#include <aw_preset.hxx>
5#include <aw_awar.hxx>
6#include <aw_msg.hxx>
7#include <aw_root.hxx>
8#include <aw_question.hxx>
9
10#include <arb_progress.h>
11#include <arb_strbuf.h>
12
13#include <ed4_extern.hxx>
14
15#include "ed4_class.hxx"
16#include "ed4_awars.hxx"
17#include "ed4_edit_string.hxx"
18#include "ed4_list.hxx"
19
20ED4_group_manager *ED4_base::is_in_folded_group() const {
21    if (!parent) return NULp;
22    ED4_manager *group = get_parent(LEV_GROUP);
23    if (!group) return NULp;
24    if (group->has_property(PROP_IS_FOLDED)) return group->to_group_manager();
25    return group->is_in_folded_group();
26}
27
28void ED4_base::changed_by_database() {
29    e4_assert(0);
30    // this happens if you add a new species_pointer to a ED4_base-derived type
31    // without defining changed_by_database for this type
32}
33
34void ED4_manager::changed_by_database() { request_refresh(); }
35
36void ED4_terminal::changed_by_database() {
37    GBDATA *gb_main = ED4_ROOT->get_gb_main();
38    if (GB_read_clock(gb_main) > curr_timestamp) { // only if timer_cb occurred after last change by EDIT4
39
40        // test if alignment length has changed:
41        {
42            GBDATA *gb_alignment = GBT_get_alignment(gb_main, ED4_ROOT->get_alignment_name());
43            e4_assert(gb_alignment);
44            GBDATA *gb_alignment_len = GB_search(gb_alignment, "alignment_len", GB_FIND);
45            int alignment_length = GB_read_int(gb_alignment_len);
46
47            if (MAXSEQUENCECHARACTERLENGTH!=alignment_length) {
48                ED4_alignment_length_changed(gb_alignment_len, GB_CB_CHANGED);
49            }
50        }
51
52        GBDATA *gb_seq = get_species_pointer();
53        int type = GB_read_type(gb_seq);
54
55        if (type==GB_STRING) {
56            char *data = (char*)GB_read_old_value();
57            if (data) {
58                int data_len = GB_read_old_size();
59                e4_assert(data_len >= 0);
60                char *dup_data = new char[data_len+1];
61
62                memcpy(dup_data, data, data_len);
63                dup_data[data_len] = 0;
64
65#if defined(DEBUG) && 0
66                char *n = GB_read_string(gb_seq);
67                e4_assert(strcmp(n, dup_data)!=0); // not really changed
68                delete n;
69#endif
70
71                ED4_species_manager *spman = get_parent(LEV_SPECIES)->to_species_manager();
72                spman->do_callbacks();
73
74                if (has_property(PROP_CONSENSUS_RELEVANT)) {
75                    ED4_multi_species_manager *multiman = get_parent(LEV_MULTI_SPECIES)->to_multi_species_manager();
76                    multiman->update_bases_and_rebuild_consensi(dup_data, data_len, spman, ED4_U_UP);
77                    request_refresh();
78                }
79
80                delete [] dup_data;
81            }
82            else { // sth else changed (e.g. protection)
83                GB_clear_error();
84            }
85        }
86    }
87}
88
89void ED4_base::deleted_from_database() {
90    my_species_pointer.notify_deleted();
91}
92
93void ED4_terminal::deleted_from_database() {
94    ED4_base::deleted_from_database();
95}
96
97void ED4_text_terminal::deleted_from_database() {
98    ED4_terminal::deleted_from_database();
99    parent->Delete();
100}
101
102void ED4_sequence_terminal::deleted_from_database() {
103#if defined(DEBUG)
104    printf("ED4_sequence_terminal::deleted_from_database (%p)\n", this);
105#endif // DEBUG
106
107    ED4_terminal::deleted_from_database();
108
109    bool was_consensus_relevant = has_property(PROP_CONSENSUS_RELEVANT);
110
111    clr_property(ED4_properties(PROP_CONSENSUS_RELEVANT|PROP_ALIGNMENT_DATA));
112
113    if (was_consensus_relevant) {
114        const char *data     = (const char*)GB_read_old_value();
115        int         data_len = GB_read_old_size();
116
117        ED4_multi_species_manager *multi_species_man = get_parent(LEV_MULTI_SPECIES)->to_multi_species_manager();
118
119        multi_species_man->update_bases(data, data_len, NULp);
120        multi_species_man->rebuild_consensi(get_parent(LEV_SPECIES)->to_species_manager(), ED4_U_UP);
121    }
122
123    parent->Delete();
124}
125
126void ED4_manager::deleted_from_database() {
127    if (is_species_manager()) {
128        ED4_species_manager *species_man = to_species_manager();
129        ED4_multi_species_manager *multi_man = species_man->parent->to_multi_species_manager();
130
131        multi_man->remove_member(species_man);
132        {
133            GB_transaction ta(ED4_ROOT->get_gb_main());
134            multi_man->update_consensus(multi_man, NULp, species_man);
135            multi_man->rebuild_consensi(species_man, ED4_U_UP);
136        }
137
138        request_resize();
139        // parent = 0;
140        // delete this; // @@@ crashes when removing callback deleted_from_database()
141    }
142    else {
143        e4_assert(0);
144    }
145}
146
147static void sequence_changed_cb(GBDATA *gb_seq, ED4_base *base, GB_CB_TYPE gbtype) {
148    if (base->get_species_pointer()!=gb_seq) {
149        e4_assert(0);
150        aw_message("Illegal callback (ED4_sequence_changed_cb())");
151    }
152
153    if (gbtype&GB_CB_DELETE) {
154        e4_assert(gbtype==GB_CB_DELETE);
155        base->deleted_from_database();
156    }
157
158    if (gbtype&GB_CB_CHANGED) {
159        base->changed_by_database();
160    }
161
162    if (gbtype&GB_CB_SON_CREATED) {
163        // @@@ New son for database-member was created ... what may we do now?
164    }
165}
166
167ED4_species_pointer::ED4_species_pointer() {
168    species_pointer = NULp;
169}
170ED4_species_pointer::~ED4_species_pointer() {
171    e4_assert(!species_pointer); // has to be destroyed before
172}
173
174void ED4_species_pointer::addCallback(ED4_base *base) {
175    GB_transaction ta(ED4_ROOT->get_gb_main());
176    GB_add_callback(species_pointer, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(sequence_changed_cb, base));
177}
178void ED4_species_pointer::removeCallback(ED4_base *base) {
179    GB_transaction ta(ED4_ROOT->get_gb_main());
180    GB_remove_callback(species_pointer, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(sequence_changed_cb, base));
181}
182
183void ED4_species_pointer::Set(GBDATA *gbd, ED4_base *base) {
184    if (species_pointer) removeCallback(base);
185    species_pointer = gbd;
186    if (species_pointer) addCallback(base);
187}
188
189// -----------------
190//      ED4_base
191
192inline bool ranges_overlap(int p1, int p2, int r1, int r2) {
193    // return true if ranges p1..p2 and r1..r2 overlap
194    e4_assert(p1 <= p2);
195    e4_assert(r1 <= r2);
196
197    return !((r2 <= p1) || (p2 <= r1)); // "exactly adjacent" means "not overlapping"
198}
199
200inline bool range_contained_in(int p1, int p2, int r1, int r2) {
201    // return true if range p1..p2 is contained in range r1..r2
202    e4_assert(p1 <= p2);
203    e4_assert(r1 <= r2);
204
205    return p1 >= r1 && p2 <= r2;
206}
207
208bool ED4_window::partly_shows(int x1, int y1, int x2, int y2) const {
209    // return true if rectangle x1/y1/x2/y2 overlaps with clipped screen
210    e4_assert(x1 <= x2);
211    e4_assert(y1 <= y2);
212
213    bool visible = (ranges_overlap(x1, x2, coords.window_left_clip_point, coords.window_right_clip_point) &&
214                    ranges_overlap(y1, y2, coords.window_upper_clip_point, coords.window_lower_clip_point));
215
216    return visible;
217}
218
219bool ED4_window::completely_shows(int x1, int y1, int x2, int y2) const {
220    // return true if rectangle x1/y1/x2/y2 is contained in clipped screen
221    e4_assert(x1 <= x2);
222    e4_assert(y1 <= y2);
223
224    bool visible = (range_contained_in(x1, x2, coords.window_left_clip_point, coords.window_right_clip_point) &&
225                    range_contained_in(y1, y2, coords.window_upper_clip_point, coords.window_lower_clip_point));
226
227    return visible;
228}
229
230char *ED4_base::resolve_pointer_to_string_copy(int *) const { return NULp; }
231const char *ED4_base::resolve_pointer_to_char_pntr(int *) const { return NULp; }
232
233ED4_group_manager *ED4_build_group_manager_start(ED4_manager                 *group_parent,
234                                                 GB_CSTR                      group_name,
235                                                 int                          group_depth,
236                                                 bool                         is_folded,
237                                                 ED4_reference_terminals&     refterms,
238                                                 ED4_multi_species_manager*&  multi_species_manager)
239{
240    char namebuffer[NAME_BUFFERSIZE];
241
242    sprintf(namebuffer, "Group_Manager.%ld", ED4_counter); // create new group manager
243    ED4_group_manager *group_manager = new ED4_group_manager(namebuffer, 0, 0, group_parent);
244    group_parent->append_member(group_manager);
245
246    sprintf(namebuffer, "Bracket_Terminal.%ld", ED4_counter);
247    ED4_bracket_terminal *bracket_terminal = new ED4_bracket_terminal(namebuffer, BRACKET_WIDTH, 0, group_manager);
248    group_manager->append_member(bracket_terminal);
249
250    sprintf(namebuffer, "MultiSpecies_Manager.%ld", ED4_counter); // create new multi_species_manager
251    multi_species_manager = new ED4_multi_species_manager(namebuffer, 0, 0, group_manager);
252    group_manager->append_member(multi_species_manager);
253
254    if (is_folded) group_manager->set_property(PROP_IS_FOLDED);
255    group_manager->set_property(PROP_MOVABLE);
256
257    multi_species_manager->set_property(PROP_IS_HANDLE);
258    bracket_terminal     ->set_property(PROP_IS_HANDLE);
259
260    {
261        sprintf(namebuffer, "Group_Spacer_Terminal_Beg.%ld", ED4_counter); // spacer at beginning of group
262        ED4_spacer_terminal *group_spacer_terminal = new ED4_spacer_terminal(namebuffer, false, 10, SPACER_HEIGHT, multi_species_manager);
263        multi_species_manager->append_member(group_spacer_terminal);
264    }
265
266    {
267        sprintf(namebuffer, "Consensus_Manager.%ld", ED4_counter);
268        ED4_species_manager *species_manager = new ED4_species_manager(ED4_SP_CONSENSUS, namebuffer, 0, 0, multi_species_manager);
269        species_manager->set_property(PROP_MOVABLE);
270        multi_species_manager->append_member(species_manager);
271
272        {
273            ED4_species_name_terminal *species_name_terminal = new ED4_species_name_terminal(group_name, MAXNAME_WIDTH - group_depth*BRACKET_WIDTH, TERMINAL_HEIGHT, species_manager);
274            species_name_terminal->set_property((ED4_properties) (PROP_SELECTABLE | PROP_DRAGABLE | PROP_IS_HANDLE));
275            species_name_terminal->set_links(NULp, refterms.sequence());
276            species_manager->append_member(species_name_terminal);
277        }
278
279
280        {
281            // add flag header terminal
282            sprintf(namebuffer, "Flag_Header_Terminal.%ld", ED4_counter);
283            ED4_flag_header_terminal *flag_header_terminal = new ED4_flag_header_terminal(namebuffer, 100, TERMINAL_HEIGHT, species_manager);
284            flag_header_terminal->set_links(NULp, refterms.sequence());
285            species_manager->append_member(flag_header_terminal);
286        }
287
288        {
289            sprintf(namebuffer, "Consensus_Seq_Manager.%ld", ED4_counter);
290            ED4_sequence_manager *sequence_manager = new ED4_sequence_manager(namebuffer, 0, 0, species_manager);
291            sequence_manager->set_property(PROP_MOVABLE);
292            species_manager->append_member(sequence_manager);
293
294            {
295                ED4_sequence_info_terminal *seq_info_term = new ED4_sequence_info_terminal("CONS", SEQUENCE_INFO_WIDTH, TERMINAL_HEIGHT, sequence_manager); // group info
296                seq_info_term->set_both_links(refterms.sequence_info());
297                seq_info_term->set_property((ED4_properties) (PROP_SELECTABLE | PROP_DRAGABLE | PROP_IS_HANDLE));
298                sequence_manager->append_member(seq_info_term);
299            }
300
301            {
302                sprintf(namebuffer, "Consensus_Seq_Terminal.%ld", ED4_counter);
303                ED4_sequence_terminal *sequence_terminal = new ED4_consensus_sequence_terminal(namebuffer, 0, TERMINAL_HEIGHT, sequence_manager);
304                sequence_terminal->set_property(PROP_CURSOR_ALLOWED);
305                sequence_terminal->set_both_links(refterms.sequence());
306                sequence_manager->append_member(sequence_terminal);
307            }
308        }
309    }
310
311    bracket_terminal->set_links(NULp, multi_species_manager);
312
313    return group_manager;
314}
315
316void ED4_build_group_manager_end(ED4_multi_species_manager *multi_species_manager) {
317    char namebuffer[NAME_BUFFERSIZE];
318
319    sprintf(namebuffer, "Group_Spacer_Terminal_End.%ld", ED4_counter); // spacer at end of group
320    ED4_spacer_terminal *group_spacer_terminal = new ED4_spacer_terminal(namebuffer, false, 10, SPACER_HEIGHT, multi_species_manager);
321    multi_species_manager->append_member(group_spacer_terminal);
322}
323
324void ED4_base::generate_configuration_string(GBS_strstruct& buffer) {
325    const char SEPARATOR = '\1';
326    if (is_manager()) {
327        ED4_container *container = to_manager();
328        if (is_group_manager()) {
329            buffer.put(SEPARATOR);
330            buffer.put(has_property(PROP_IS_FOLDED) ? 'F' : 'G');
331
332            for (int writeConsensus = 1; writeConsensus>=0; --writeConsensus) {
333                for (int i=0; i<container->members(); ++i) {
334                    ED4_base *child       = container->member(i);
335                    bool      isConsensus = child->is_consensus_manager();
336
337                    if (bool(writeConsensus) == isConsensus) {
338                        child->generate_configuration_string(buffer);
339                    }
340                }
341            }
342
343            buffer.put(SEPARATOR);
344            buffer.put('E');
345        }
346        else {
347            for (int i=0; i<container->members(); i++) {
348                container->member(i)->generate_configuration_string(buffer);
349            }
350        }
351    }
352    else {
353        if (is_species_name_terminal() && !((ED4_terminal*)this)->tflag.deleted) {
354            ED4_species_type species_type = get_species_type();
355            switch (species_type) {
356                case ED4_SP_CONSENSUS: {
357                    // write group name (control info already written inside manager-branch above)
358                    const char *paren = strchr(id, '(');
359                    if (paren) {
360                        int namelen = std::max(int(paren-id)-1, 0); // skip starting at " (" behind consensus name
361
362                        if (namelen>0) buffer.ncat(id, namelen);
363                        else           buffer.cat("<unnamed>");
364                    }
365                    else buffer.cat(id);
366                    break;
367                }
368                case ED4_SP_SAI:
369                    buffer.put(SEPARATOR);
370                    buffer.put('S');
371                    buffer.cat(resolve_pointer_to_char_pntr(NULp));
372                    break;
373                case ED4_SP_SPECIES:
374                    buffer.put(SEPARATOR);
375                    buffer.put('L');
376                    buffer.cat(resolve_pointer_to_char_pntr(NULp));
377                    break;
378                case ED4_SP_NONE:
379                    e4_assert(0);
380                    break;
381            }
382        }
383    }
384}
385
386
387ARB_ERROR ED4_base::route_down_hierarchy(const ED4_route_cb& cb) {
388    // executes 'cb' for every element in hierarchy
389    return cb(this);
390}
391
392ARB_ERROR ED4_manager::route_down_hierarchy(const ED4_route_cb& cb) {
393    ARB_ERROR error = cb(this);
394    if (!error) {
395        for (int i=0; i<members() && !error; i++) {
396            error = member(i)->route_down_hierarchy(cb);
397        }
398    }
399    return error;
400}
401
402ED4_base *ED4_manager::find_first_that(ED4_level level, const ED4_basePredicate& fulfills_predicate) {
403    if ((spec.level&level) && fulfills_predicate(this)) {
404        return this;
405    }
406
407    for (int i=0; i<members(); i++) {
408        ED4_base *child = member(i);
409
410        if (child->is_manager()) {
411            ED4_base *found = child->to_manager()->find_first_that(level, fulfills_predicate);
412            if (found) {
413                return found;
414            }
415        }
416        else if ((child->spec.level&level) && fulfills_predicate(child)) {
417            return child;
418        }
419    }
420
421    return NULp;
422}
423
424int ED4_base::calc_group_depth() {
425    int       cntr        = 0;
426    ED4_base *temp_parent = parent;
427    while (temp_parent->parent && !(temp_parent->is_area_manager())) {
428        if (temp_parent->is_group_manager()) cntr++;
429        temp_parent = temp_parent->parent;
430    }
431    return cntr; // don't count our own group
432}
433
434ED4_base *ED4_manager::search_spec_child_rek(ED4_level level) {
435    // if (spec.level & level) return this; // old behavior (unwanted)
436    e4_assert(!(spec.level & level)); // if this fails, the old behavior was used => behavior of this call did change!
437
438    for (int i=0; i<members(); i++) { // first check children
439        if (member(i)->spec.level & level) {
440            return member(i);
441        }
442    }
443
444    for (int i=0; i<members(); i++) {
445        if (member(i)->is_manager()) {
446            ED4_base *result = member(i)->to_manager()->search_spec_child_rek(level);
447            if (result) return result;
448        }
449    }
450
451    return NULp;
452}
453
454ED4_terminal *ED4_base::get_next_terminal() {
455    ED4_terminal *terminal = NULp;
456
457    if (parent) {
458        terminal = parent->get_first_terminal(index+1);
459        if (!terminal) {
460            terminal = parent->get_next_terminal();
461        }
462    }
463
464    return terminal;
465}
466
467ED4_terminal *ED4_base::get_prev_terminal() {
468    ED4_terminal *terminal = NULp;
469
470    if (parent) {
471        if (index) {
472            terminal = parent->get_last_terminal(index-1);
473        }
474        if (!terminal) {
475            terminal = parent->get_prev_terminal();
476        }
477    }
478
479    return terminal;
480}
481
482
483bool ED4_base::has_parent(ED4_manager *Parent) {
484    // return true if 'parent' is a parent of this
485
486    if (is_manager()) {
487        if (this == static_cast<ED4_base*>(Parent)) {
488            return true;
489        }
490    }
491
492    if (!parent) return false;
493    return parent->has_parent(Parent);
494}
495
496
497ED4_AREA_LEVEL ED4_base::get_area_level(ED4_multi_species_manager **multi_species_manager) const {
498    ED4_base       *area_base = get_parent(LEV_AREA);
499    ED4_AREA_LEVEL  result    = ED4_A_ERROR;
500
501    if (area_base) {
502        ED4_area_manager *area_man = area_base->to_area_manager();
503
504        if      (area_man == ED4_ROOT->top_area_man)    result = ED4_A_TOP_AREA;
505        else if (area_man == ED4_ROOT->middle_area_man) result = ED4_A_MIDDLE_AREA;
506
507        if (result != ED4_A_ERROR && multi_species_manager) {
508            *multi_species_manager = area_man->get_multi_species_manager();
509        }
510    }
511    return result;
512}
513
514
515void ED4_multi_species_manager::update_group_id() {
516    ED4_species_name_terminal *consensus_name_terminal = get_consensus_name_terminal();
517    if (consensus_name_terminal) { // top managers dont show consensus
518        e4_assert(has_valid_counters());
519
520        const char *cntid = consensus_name_terminal->id;
521        char       *name  = ARB_calloc<char>(strlen(cntid)+10);
522
523        int i;
524        for (i=0; cntid[i] && cntid[i] != '(';   i++) {
525            name[i] = cntid[i];
526        }
527        if (i>0 && cntid[i-1] == ' ') --i; // skip terminal space
528        sprintf(name+i, " (%d)", species);
529
530        freeset(consensus_name_terminal->id, name);
531
532        consensus_name_terminal->request_refresh();
533    }
534}
535
536PosRange ED4_abstract_sequence_terminal::pixel2index(PosRange pixel_range) {
537    int length_of_char = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
538
539    int left_index  = int((pixel_range.start()-CHARACTEROFFSET)/length_of_char);
540    int right_index = int((pixel_range.end()  -CHARACTEROFFSET)/length_of_char) + 1;
541
542    return PosRange(left_index, std::min(right_index, MAXSEQUENCECHARACTERLENGTH-1));
543}
544
545PosRange ED4_abstract_sequence_terminal::calc_interval_displayed_in_rectangle(AW_screen_area *rect) { // rect contains win-coords
546    AW_pos x, y;
547    calc_world_coords(&x, &y);
548    current_ed4w()->world_to_win_coords(&x, &y);
549
550    int rel_left_x  = int(rect->l-x);
551    int rel_right_x = int(rect->r-x);
552
553    return pixel2index(PosRange(rel_left_x, rel_right_x)); // changed behavior: clip at MAXSEQUENCECHARACTERLENGTH-1 (was MAXSEQUENCECHARACTERLENGTH)
554}
555
556PosRange ED4_abstract_sequence_terminal::calc_update_interval() {
557    AW_pos x, y;
558    calc_world_coords(&x, &y);
559
560    const AW_screen_area& clip_rect = current_device()->get_cliprect();
561
562    int scroll_shift = current_ed4w()->coords.window_left_clip_point-x; // Verschiebung der Sequenz (durch Scrollen) == slider Position
563    int rel_left_x   = int(clip_rect.l - x + scroll_shift);                   // Abstand vom linken Terminalrand zum Anfang des Clipping rectangles + scroll_shift
564    int rel_right_x  = int(clip_rect.r - x + scroll_shift);
565
566    return pixel2index(PosRange(rel_left_x, rel_right_x));
567}
568
569void ED4_manager::create_consensus(ED4_abstract_group_manager *upper_group_manager, arb_progress *progress) {
570    // creates consensus
571    // is called by group manager
572
573    ED4_abstract_group_manager *group_manager_for_child = upper_group_manager;
574
575    if (is_abstract_group_manager()) {
576        ED4_abstract_group_manager *group_manager = to_abstract_group_manager();
577
578        group_manager->table().init(MAXSEQUENCECHARACTERLENGTH);
579        group_manager_for_child = group_manager;
580
581        if (progress) progress->inc();
582    }
583
584    for (int i=0; i<members(); i++) {
585        ED4_base *child = member(i);
586
587        if (child->is_species_manager()) {
588            ED4_species_manager *species_manager        = child->to_species_manager();
589            const ED4_terminal  *sequence_data_terminal = species_manager->get_consensus_relevant_terminal();
590
591            if (sequence_data_terminal) {
592                int   db_pointer_len;
593                char *db_pointer = sequence_data_terminal->resolve_pointer_to_string_copy(&db_pointer_len);
594                group_manager_for_child->table().add(db_pointer, db_pointer_len);
595                e4_assert(!group_manager_for_child->table().empty());
596                free(db_pointer);
597
598                if (progress) progress->inc();
599            }
600        }
601        else if (child->is_group_manager()) {
602            ED4_group_manager *sub_group = child->to_group_manager();
603
604            sub_group->create_consensus(sub_group, progress);
605            e4_assert(sub_group!=upper_group_manager);
606            upper_group_manager->table().add(sub_group->table());
607#if defined(TEST_CHAR_TABLE_INTEGRITY)
608            if (!sub_group->table().empty() && !sub_group->table().is_ignored()) {
609                e4_assert(!upper_group_manager->table().empty());
610            }
611#endif
612        }
613        else if (child->is_manager()) {
614            child->to_manager()->create_consensus(group_manager_for_child, progress);
615        }
616    }
617}
618
619const ED4_terminal *ED4_base::get_consensus_relevant_terminal() const {
620    int i;
621
622    if (is_terminal()) {
623        if (has_property(PROP_CONSENSUS_RELEVANT)) {
624            return this->to_terminal();
625        }
626        return NULp;
627    }
628
629    const ED4_manager  *manager           = this->to_manager();
630    const ED4_terminal *relevant_terminal = NULp;
631
632    int members = manager->members();
633
634    for (i=0; !relevant_terminal && i<members; ++i) {
635        ED4_base *child  = manager->member(i);
636        relevant_terminal = child->get_consensus_relevant_terminal();
637    }
638
639#if defined(DEBUG)
640    if (relevant_terminal) {
641        for (; i<members; ++i) {
642            ED4_base *child = manager->member(i);
643            e4_assert(!child->get_consensus_relevant_terminal()); // there shall be only 1 consensus relevant terminal, since much code assumes that
644        }
645    }
646#endif // DEBUG
647
648    return relevant_terminal;
649}
650
651int ED4_multi_species_manager::count_visible_children() { // is called by a multi_species_manager
652    int counter = 0;
653
654    for (int i=0; i<members(); i++) {
655        ED4_base *child = member(i);
656        if (child->is_species_manager()) {
657            counter ++;
658        }
659        else if (child->is_group_manager()) {
660            ED4_group_manager *group_manager = child->to_group_manager();
661            if (group_manager->has_property(PROP_IS_FOLDED)) {
662                counter ++;
663            }
664            else {
665                ED4_multi_species_manager *multi_species_manager = group_manager->get_multi_species_manager();
666                counter += multi_species_manager->count_visible_children();
667            }
668        }
669    }
670    return counter;
671}
672
673
674
675void ED4_base::unlink_from_parent() {
676    e4_assert(parent);
677    parent->remove_member(this);
678}
679
680char *ED4_base::get_name_of_species() {
681    char                *name        = NULp;
682    ED4_species_manager *species_man = get_parent(LEV_SPECIES)->to_species_manager();
683    if (species_man) {
684        ED4_species_name_terminal *species_name = species_man->search_spec_child_rek(LEV_SPECIES_NAME)->to_species_name_terminal();
685        if (species_name) {
686            GBDATA *gb_name   = species_name->get_species_pointer();
687            if (gb_name) {
688                GB_transaction ta(gb_name);
689                name = GB_read_as_string(gb_name);
690            }
691        }
692    }
693    return name;
694}
695
696ED4_base *ED4_manager::get_defined_level(ED4_level lev) const {
697    for (int i=0; i<members(); i++) { // first test direct children ..
698        if (member(i)->spec.level & lev) {
699            return member(i);
700        }
701    }
702
703    for (int i=0; i<members(); i++) { // .. then all containers
704        ED4_base *child = member(i);
705
706        if (child->is_multi_species_manager()) {
707            return child->to_multi_species_manager()->get_defined_level(lev);
708        }
709        else if (child->is_group_manager()) {
710            return child->to_group_manager()->member(1)->to_multi_species_manager()->get_defined_level(lev);
711        }
712        else {
713            e4_assert(!child->is_manager());
714        }
715    }
716    return NULp;
717}
718
719ED4_returncode ED4_base::set_width() {
720    // sets object length of terminals to Consensus_Name_terminal if existing
721    // else to MAXNAME_WIDTH
722
723    if (is_species_manager()) {
724        ED4_species_manager *species_manager = to_species_manager();
725
726        if (!species_manager->is_consensus_manager()) {
727            ED4_multi_name_manager    *multi_name_manager = species_manager->get_defined_level(LEV_MULTI_NAME)->to_multi_name_manager();  // case I'm a species
728            ED4_species_name_terminal *consensus_terminal = parent->to_multi_species_manager()->get_consensus_name_terminal();
729
730            for (int i=0; i<multi_name_manager->members(); i++) {
731                ED4_name_manager *name_manager = multi_name_manager->member(i)->to_name_manager();
732                ED4_base         *nameTerm     = name_manager->member(0);
733                int               width        = consensus_terminal ? consensus_terminal->extension.size[WIDTH] : MAXNAME_WIDTH;
734
735                nameTerm->extension.size[WIDTH] = width;
736                nameTerm->request_resize();
737            }
738
739            for (int i=0; i<species_manager->members(); i++) { // adjust all managers as far as possible
740                ED4_base *smember = species_manager->member(i);
741                if (consensus_terminal) {
742                    ED4_base *kmember = consensus_terminal->parent->member(i);
743                    if (kmember) {
744                        smember->extension.position[X_POS] = kmember->extension.position[X_POS];
745                        ED4_base::touch_world_cache();
746                    }
747                }
748                else { // got no consensus
749                    ED4_species_manager *a_species = parent->get_defined_level(LEV_SPECIES)->to_species_manager();
750                    if (a_species) {
751                        smember->extension.position[X_POS] = a_species->member(i)->extension.position[X_POS];
752                        ED4_base::touch_world_cache();
753                    }
754                }
755                smember->request_resize();
756            }
757        }
758    }
759    else if (is_group_manager()) {
760        ED4_group_manager         *group_manager           = to_group_manager();
761        ED4_multi_species_manager *multi_species_manager   = group_manager->get_multi_species_manager();
762        ED4_species_name_terminal *mark_consensus_terminal = multi_species_manager->get_consensus_name_terminal();
763        ED4_species_name_terminal *consensus_terminal      = parent->to_multi_species_manager()->get_consensus_name_terminal();
764
765        if (consensus_terminal) { // we're a group in another group
766            mark_consensus_terminal->extension.size[WIDTH] = consensus_terminal->extension.size[WIDTH] - BRACKET_WIDTH;
767        }
768        else { // we're at the top (no consensus terminal)
769            mark_consensus_terminal->extension.size[WIDTH] = MAXNAME_WIDTH - BRACKET_WIDTH;
770        }
771
772        mark_consensus_terminal->request_resize();
773
774        for (int i=0; i<multi_species_manager->members(); i++) {
775            multi_species_manager->member(i)->set_width();
776        }
777
778        for (int i=0; i < group_manager->members(); i++) { // for all groups below from us
779            if (group_manager->member(i)->is_group_manager()) {
780                group_manager->member(i)->set_width();
781            }
782        }
783    }
784
785    return ED4_R_OK;
786}
787
788
789short ED4_base::in_border(AW_pos x, AW_pos y, ED4_movemode mode) {
790    // determines if given world coords x and y are within borders of current object according to move mode
791    AW_pos world_x, world_y;
792    calc_world_coords(&world_x, &world_y); // calculate absolute extension of current object
793
794    switch (mode) { // which direction?
795        case ED4_M_HORIZONTAL:
796            if ((x >= world_x) && (x < (world_x + extension.size[WIDTH]))) return 1; // target location is within the borders of parent
797            break;
798        case ED4_M_VERTICAL:
799            if ((y >= world_y) && (y < (world_y + extension.size[HEIGHT]))) return 1; // target location is within the borders of parent
800            break;
801        case ED4_M_FREE:
802            return in_border(x, y, ED4_M_HORIZONTAL) && in_border(x, y, ED4_M_VERTICAL);
803        case ED4_M_NO_MOVE:
804            break;
805    }
806    return 0;
807}
808
809
810void ED4_base::calc_rel_coords(AW_pos *x, AW_pos *y) { // calculates coordinates relative to current object from given world coords
811    AW_pos   world_x, world_y;
812
813    calc_world_coords(&world_x, &world_y);          // calculate world coordinates of current object
814
815    *x -= world_x;                                  // calculate relative coordinates by subtracting world
816    *y -= world_y;                                  // coords of current object
817}
818
819void ED4_manager::hide_children() {
820    for (int i=0; i<members(); i++) {
821        ED4_base *child = member(i);
822        if (!child->is_spacer_terminal() && !child->is_consensus_manager()) { // don't hide spacer and Consensus
823            child->flag.hidden = 1;
824        }
825    }
826    request_resize();
827}
828
829
830void ED4_manager::unhide_children() {
831    for (int i=0; i<members(); i++) {
832        member(i)->flag.hidden = 0; // make child visible
833    }
834    request_resize();
835}
836
837void ED4_group_manager::unfold() {
838    for (int i=0; i<members(); i++) {
839        ED4_base *child = member(i);
840
841        if (child->is_multi_species_manager()) {
842            ED4_multi_species_manager *multi_species_manager = child->to_multi_species_manager();
843            multi_species_manager->unhide_children();
844        }
845    }
846
847    clr_property(PROP_IS_FOLDED);
848    ED4_request_relayout();
849}
850
851void ED4_group_manager::fold() {
852    ED4_multi_species_manager *multi_species_manager = get_defined_level(LEV_MULTI_SPECIES)->to_multi_species_manager();
853
854    bool consensus_shown = false;
855    if (!(multi_species_manager->member(1)->is_consensus_manager())) { // if consensus is not at top => move to top
856        ED4_manager *consensus_manager = NULp;
857        int i;
858        for (i=0; i<multi_species_manager->members(); i++) { // search for consensus
859            if (multi_species_manager->member(i)->is_consensus_manager()) {
860                consensus_manager = multi_species_manager->member(i)->to_manager();
861                break;
862            }
863        }
864
865        if (consensus_manager) {
866            multi_species_manager->move_member(i, 1); // move Consensus to top of list
867            consensus_manager->extension.position[Y_POS] = SPACER_HEIGHT;
868            ED4_base::touch_world_cache();
869            consensus_shown = true;
870        }
871    }
872    else {
873        consensus_shown = true;
874    }
875
876    if (consensus_shown && ED4_ROOT->aw_root->awar(ED4_AWAR_CONSENSUS_SHOW)->read_int()==0) {
877        consensus_shown = false;
878    }
879
880    multi_species_manager->hide_children();
881    set_property(PROP_IS_FOLDED);
882
883    ED4_request_relayout();
884}
885
886void ED4_group_manager::toggle_folding() {
887    if (has_property(PROP_IS_FOLDED)) unfold();
888    else fold();
889}
890void ED4_bracket_terminal::toggle_folding() {
891    parent->to_group_manager()->toggle_folding();
892}
893
894void ED4_base::check_all() {
895    AW_pos x, y;
896
897    calc_world_coords(&x, &y);
898
899    printf("Typ des Aufrufers :\t\t\t%s\n", is_manager() ? "Manager" : "Terminal");
900    printf("Name des Aufrufers von Check_All : \t%.30s\n", (id) ? id : "Keine ID");
901    printf("Linke obere Ecke x, y : \t\t%f, %f\n", extension.position[0], extension.position[1]);
902    printf("Breite und Hoehe x, y : \t\t%f, %f\n", extension.size[0], extension.size[1]);
903    printf("World Coords     x, y : \t\t%f, %f\n\n", x, y);
904    printf("***********************************************\n\n");
905}
906
907int ED4_base::adjust_clipping_rectangle() {
908    // return 0 if clipping rectangle disappeared (nothing left to draw)
909    AW::Rectangle base_area = get_win_area(current_ed4w());
910    return current_device()->reduceClipBorders(base_area.top(), base_area.bottom(), base_area.left(), base_area.right());
911}
912
913void ED4_base::set_links(ED4_base *width_ref, ED4_base *height_ref) {
914    // links 'this' to (one or two) reference terminal(s)
915    // => 'this' will resize when size of reference changes (maybe more effects?)
916    // (Note: passing NULp means "do not change")
917
918    if (width_ref) {
919        if (width_link) width_link->linked_objects->remove_elem(this);
920        width_link = width_ref;
921        if (!width_ref->linked_objects) width_ref->linked_objects = new ED4_base_list;
922        width_ref->linked_objects->append_elem(this);
923    }
924
925    if (height_ref) {
926        if (height_link) height_link->linked_objects->remove_elem(this);
927        height_link = height_ref;
928        if (!height_ref->linked_objects) height_ref->linked_objects = new ED4_base_list;
929        height_ref->linked_objects->append_elem(this);
930    }
931}
932
933int ED4_base::currTimestamp = 1;
934
935#if defined(DEBUG)
936// #define VISIBLE_AREA_REFRESH
937#endif
938
939ED4_returncode ED4_base::clear_background(int color) {
940    if (current_device()) { // @@@ should clear be done for all windows?
941        AW_pos x, y;
942        calc_world_coords(&x, &y);
943        current_ed4w()->world_to_win_coords(&x, &y);
944
945        current_device()->push_clip_scale();
946        if (adjust_clipping_rectangle()) {
947            if (!color) {
948#if defined(VISIBLE_AREA_REFRESH)
949                // for debugging draw each clear in different color:
950                static int gc_area = ED4_G_FIRST_COLOR_GROUP;
951
952                current_device()->box(gc_area, true, x, y, extension.size[WIDTH], extension.size[HEIGHT]);
953                gc_area = (gc_area == ED4_G_LAST_COLOR_GROUP) ? ED4_G_FIRST_COLOR_GROUP : gc_area+1;
954#else // !defined(VISIBLE_AREA_REFRESH)
955                current_device()->clear_part(x, y, extension.size[WIDTH], extension.size[HEIGHT], AW_ALL_DEVICES);
956#endif
957            }
958            else {
959                // fill range with color for debugging
960                current_device()->box(color, AW::FillStyle::SOLID, x, y, extension.size[WIDTH], extension.size[HEIGHT]);
961            }
962        }
963        current_device()->pop_clip_scale();
964    }
965    return ED4_R_OK;
966}
967
968void ED4_main_manager::clear_whole_background() {
969    // clear AW_MIDDLE_AREA
970    for (ED4_window *window = ED4_ROOT->first_window; window; window=window->next) {
971        AW_device *device = window->get_device();
972        if (device) {
973            device->push_clip_scale();
974            device->clear(AW_ALL_DEVICES);
975            device->pop_clip_scale();
976        }
977    }
978}
979
980void ED4_base::draw_bb(int color) {
981    if (current_device()) {
982        current_device()->push_clip_scale();
983        if (adjust_clipping_rectangle()) {
984            AW_pos x1, y1;
985            calc_world_coords(&x1, &y1);
986            current_ed4w()->world_to_win_coords(&x1, &y1);
987            current_device()->box(color, AW::FillStyle::EMPTY, x1, y1, extension.size[WIDTH]-1, extension.size[HEIGHT]-1);
988        }
989        current_device()->pop_clip_scale();
990    }
991}
992
993ED4_base::ED4_base(const ED4_objspec& spec_, GB_CSTR temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
994    : spec(spec_)
995{
996    index = 0;
997    dynamic_prop = ED4_properties(PROP_NONE | (spec.static_prop & PROP_DYNA_RESIZE));
998    timestamp =  0; // invalid - almost always..
999
1000    e4_assert(temp_id);
1001    if (temp_id) {
1002        id = ARB_alloc<char>(strlen(temp_id)+1);
1003        strcpy(id, temp_id);
1004    }
1005
1006    linked_objects = NULp;
1007
1008    extension.position[X_POS] = -1; // position set here has no effect (will be overwritten by next resize)
1009    extension.position[Y_POS] = -1;
1010
1011    ED4_base::touch_world_cache(); // invalidate position
1012
1013    extension.size[WIDTH]  = width;
1014    extension.size[HEIGHT] = height;
1015
1016    extension.y_folded = 0;
1017    parent             = temp_parent;
1018    width_link         = NULp;
1019    height_link        = NULp;
1020
1021    memset((char*)&update_info, 0, sizeof(update_info));
1022    memset((char*)&flag, 0, sizeof(flag));
1023}
1024
1025
1026ED4_base::~ED4_base() {
1027    // before calling this function the first time, parent has to be set NULp
1028    e4_assert(!parent); // unlink from parent first!
1029
1030    if (linked_objects) {
1031        ED4_base_list_elem *list_elem = linked_objects->head();
1032        while (list_elem) {
1033            ED4_base *object = list_elem->elem();
1034            if (object->width_link == this) {
1035                object->width_link->linked_objects->remove_elem(this);              // delete link and
1036                object->width_link = NULp;
1037            }
1038
1039            if (object->height_link == this) {
1040                object->height_link->linked_objects->remove_elem(this);             // delete link and
1041                object->height_link = NULp;
1042            }
1043
1044            ED4_base_list_elem *old_elem = list_elem;
1045            list_elem = list_elem->next();
1046            linked_objects->remove_elem(old_elem->elem());
1047        }
1048        delete linked_objects;
1049    }
1050
1051    if (update_info.linked_to_scrolled_rectangle) {
1052        if (ED4_ROOT->main_manager) {
1053            ED4_base *sequence_terminal = ED4_ROOT->main_manager->search_spec_child_rek(LEV_SEQUENCE_STRING);
1054
1055            if (sequence_terminal) sequence_terminal->update_info.linked_to_scrolled_rectangle = 1;
1056
1057            update_info.linked_to_scrolled_rectangle = 0;
1058            ED4_ROOT->scroll_links.link_for_hor_slider = sequence_terminal;
1059
1060            ED4_window *ed4w = ED4_ROOT->first_window;
1061            while (ed4w) {
1062                ed4w->scrolled_rect.replace_x_width_link_to(this, sequence_terminal);
1063                ed4w = ed4w->next;
1064            }
1065        }
1066    }
1067
1068    if (width_link) {
1069        width_link->linked_objects->remove_elem(this);
1070        width_link = NULp;
1071    }
1072
1073    if (height_link) {
1074        height_link->linked_objects->remove_elem(this);
1075        height_link = NULp;
1076    }
1077
1078    set_species_pointer(NULp);     // clear pointer to database and remove callbacks
1079    free(id);
1080}
1081
Note: See TracBrowser for help on using the repository browser.