source: branches/stable/EDIT4/ED4_manager.cxx

Last change on this file was 18352, checked in by westram, 4 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.7 KB
Line 
1#include <arbdbt.h>
2
3#include <aw_preset.hxx>
4#include <aw_awar.hxx>
5#include <aw_msg.hxx>
6#include <aw_root.hxx>
7
8#include "ed4_class.hxx"
9#include "ed4_awars.hxx"
10#include "ed4_edit_string.hxx"
11#include "ed4_tools.hxx"
12#include "ed4_list.hxx"
13#include "ed4_ProteinViewer.hxx"
14#include "ed4_protein_2nd_structure.hxx"
15#include "ed4_seq_colors.hxx"
16
17#if defined(DEBUG)
18#define TEST_REFRESH_FLAG
19#endif
20
21// -----------------------------------------------------------------
22//      Manager static properties (used by manager-constructors)
23
24static ED4_objspec main_manager_spec(
25    (ED4_properties)(PROP_IS_MANAGER | PROP_HORIZONTAL), // static props
26    LEV_ROOT,                                              // level
27    LEV_ROOTGROUP,                                         // allowed children level
28    LEV_NONE,                                              // handled object
29    LEV_NONE                                               // restriction level
30    );
31
32static ED4_objspec device_manager_spec(
33    (ED4_properties)(PROP_IS_MANAGER | PROP_HORIZONTAL), // static props
34    LEV_DEVICE,                                            // level
35    (ED4_level)(LEV_AREA | LEV_SPACER | LEV_LINE),         // allowed children level
36    LEV_NONE,                                              // handled object
37    LEV_NONE                                               // restriction level
38    );
39
40static ED4_objspec area_manager_spec(
41    (ED4_properties)(PROP_IS_MANAGER | PROP_VERTICAL),    // static props
42    LEV_AREA,                                               // level
43    (ED4_level)(LEV_MULTI_SPECIES | LEV_TREE | LEV_SPACER), // allowed children level
44    LEV_NONE,                                               // handled object
45    LEV_NONE                                                // restriction level
46    );
47
48static ED4_objspec multi_species_manager_spec(
49    (ED4_properties)(PROP_IS_MANAGER | PROP_HORIZONTAL), // static props
50    LEV_MULTI_SPECIES,                                     // level
51    (ED4_level)(LEV_SPECIES | LEV_GROUP | LEV_SPACER),     // allowed children level
52    LEV_NONE,                                              // handled object
53    LEV_NONE                                               // restriction level
54    );
55
56static ED4_objspec species_manager_spec(
57    (ED4_properties)(PROP_IS_MANAGER | PROP_VERTICAL),  // static props
58    LEV_SPECIES,                                        // level
59    (ED4_level)(LEV_MULTI_SEQUENCE | LEV_MULTI_NAME |   // (used by normal species)
60                LEV_SPECIES_NAME | LEV_SEQUENCE |       // allowed children level (used by consensus)
61                LEV_FLAG_HEADER),
62    LEV_NONE,                                           // handled object
63    LEV_NONE                                            // restriction level
64    );
65
66static ED4_objspec multi_sequence_manager_spec(
67    (ED4_properties)(PROP_IS_MANAGER | PROP_HORIZONTAL), // static props
68    LEV_MULTI_SEQUENCE,                                    // level
69    LEV_SEQUENCE,                                          // allowed children level
70    LEV_NONE,                                              // handled object
71    LEV_NONE                                               // restriction level
72    );
73
74static ED4_objspec sequence_manager_spec(
75    (ED4_properties)(PROP_IS_MANAGER | PROP_VERTICAL),      // static props
76    LEV_SEQUENCE,                                             // level
77    (ED4_level)(LEV_SEQUENCE_INFO | LEV_SEQUENCE_STRING | LEV_ORF | LEV_PURE_TEXT | LEV_COL_STAT), // allowed children level
78    LEV_NONE,                                                 // handled object
79    LEV_SPECIES                                               // restriction level
80    );
81
82static ED4_objspec multi_name_manager_spec(
83    (ED4_properties)(PROP_IS_MANAGER | PROP_HORIZONTAL), // static props
84    LEV_MULTI_NAME,                                        // level
85    LEV_NAME_MANAGER,                                      // allowed children level
86    LEV_NONE,                                              // handled object
87    LEV_NONE                                               // restriction level
88    );
89
90static ED4_objspec name_manager_spec(
91    (ED4_properties)(PROP_IS_MANAGER | PROP_VERTICAL),   // static props
92    LEV_NAME_MANAGER,                                    // level
93    (ED4_level)(LEV_SPECIES_NAME | LEV_FLAG),            // allowed children level
94    LEV_NONE,                                            // handled object
95    LEV_SPECIES                                          // restriction level
96    );
97
98static ED4_objspec group_manager_spec(
99    (ED4_properties)(PROP_IS_MANAGER | PROP_VERTICAL), // static props
100    LEV_GROUP,                                           // level
101    (ED4_level)(LEV_MULTI_SPECIES | LEV_BRACKET),        // allowed children level
102    LEV_NONE,                                            // handled object
103    LEV_NONE                                             // restriction level
104    );
105
106static ED4_objspec root_group_manager_spec(
107    (ED4_properties)(PROP_IS_MANAGER | PROP_VERTICAL), // static props
108    LEV_ROOTGROUP,                                       // level
109    (ED4_level)(LEV_DEVICE),                             // allowed children level
110    LEV_NONE,                                            // handled object
111    LEV_NONE                                             // restriction level
112    );
113
114// ----------------------------
115//      ED4_manager methods
116
117ED4_returncode ED4_manager::rebuild_consensi(ED4_base *start_species, ED4_update_flag update_flag) {
118    int                        i;
119    ED4_base                  *temp_parent;
120    ED4_multi_species_manager *multi_species_manager = NULp;
121    ED4_group_manager         *first_group_manager   = NULp;
122
123    temp_parent = start_species;
124
125    switch (update_flag) {
126        case ED4_U_UP:          // rebuild consensus from a certain starting point upwards
127            while (temp_parent) {
128                if (temp_parent->is_group_manager()) {
129                    multi_species_manager = temp_parent->to_group_manager()->get_multi_species_manager();
130                    for (i=0; i<multi_species_manager->members(); i++) {
131                        if (multi_species_manager->member(i)->is_consensus_manager()) {
132                            rebuild_consensus(multi_species_manager->member(i)).expect_no_error();
133                        }
134                    }
135                }
136                temp_parent = temp_parent->parent;
137            }
138            break;
139        case ED4_U_UP_DOWN:     // only search first groupmanager and update consensi recursively downwards
140            while (temp_parent) {
141                if (temp_parent->is_group_manager()) {
142                    first_group_manager = temp_parent->to_group_manager();
143                }
144                temp_parent = temp_parent->parent;
145            }
146            if (first_group_manager)
147                first_group_manager->route_down_hierarchy(makeED4_route_cb(rebuild_consensus)).expect_no_error();
148            break;
149    }
150    return ED4_R_OK;
151}
152
153ED4_returncode ED4_manager::check_in_bases(ED4_base *added_base) {
154    if (added_base->is_species_manager()) { // add a sequence
155        ED4_species_manager *species_manager = added_base->to_species_manager();
156        const ED4_terminal *sequence_terminal = species_manager->get_consensus_relevant_terminal();
157
158        if (sequence_terminal) {
159            int   seq_len;
160            char *seq          = sequence_terminal->resolve_pointer_to_string_copy(&seq_len);
161            ED4_returncode res = update_bases(NULp, 0, seq, seq_len);
162            free(seq);
163            return res;
164        }
165    }
166
167    e4_assert(!added_base->is_root_group_manager());
168    if (added_base->is_group_manager()) { // add a group
169        return update_bases(NULp, &added_base->to_group_manager()->table());
170    }
171
172    e4_assert(0); // wrong type
173   
174    return ED4_R_OK;
175}
176
177ED4_returncode ED4_manager::check_out_bases(ED4_base *subbed_base) {
178    if (subbed_base->is_species_manager()) { // sub a sequence
179        ED4_species_manager *species_manager = subbed_base->to_species_manager();
180        const ED4_terminal *sequence_terminal = species_manager->get_consensus_relevant_terminal();
181
182        if (sequence_terminal) {
183            int   seq_len;
184            char *seq          = sequence_terminal->resolve_pointer_to_string_copy(&seq_len);
185            ED4_returncode res = update_bases(seq, seq_len, NULp, 0);
186            free(seq);
187            return res;
188        }
189    }
190    else {
191        e4_assert(!subbed_base->is_root_group_manager());
192        if (subbed_base->is_group_manager()) { // sub a group
193            return update_bases(&subbed_base->to_group_manager()->table(), NULp);
194        }
195        e4_assert(0); // wrong type
196    }
197    return ED4_R_OK;
198}
199
200ED4_returncode ED4_manager::update_bases(const char *old_sequence, int old_len, const ED4_base *new_base, PosRange range) {
201    if (!new_base) {
202        return update_bases(old_sequence, old_len, NULp, 0, range);
203    }
204
205    e4_assert(new_base->is_species_manager());
206
207    const ED4_species_manager *new_species_manager   = new_base->to_species_manager();
208    const ED4_terminal        *new_sequence_terminal = new_species_manager->get_consensus_relevant_terminal();
209
210    int   new_len;
211    char *new_sequence = new_sequence_terminal->resolve_pointer_to_string_copy(&new_len);
212
213    if (range.is_whole()) {
214        const PosRange *restricted = BaseFrequencies::changed_range(old_sequence, new_sequence, std::min(old_len, new_len));
215       
216        e4_assert(restricted);
217        range = *restricted;
218    }
219
220    ED4_returncode res = update_bases(old_sequence, old_len, new_sequence, new_len, range);
221    free(new_sequence);
222    return res;
223}
224
225ED4_returncode ED4_manager::update_bases_and_rebuild_consensi(const char *old_sequence, int old_len, ED4_base *new_base, ED4_update_flag update_flag, PosRange range) {
226    e4_assert(new_base);
227    e4_assert(new_base->is_species_manager());
228
229    ED4_species_manager *new_species_manager   = new_base->to_species_manager();
230    const ED4_terminal  *new_sequence_terminal = new_species_manager->get_consensus_relevant_terminal();
231
232    int         new_len;
233    const char *new_sequence = new_sequence_terminal->resolve_pointer_to_char_pntr(&new_len);
234
235#if defined(DEBUG) && 0
236    printf("old: %s\n", old_sequence);
237    printf("new: %s\n", new_sequence);
238#endif // DEBUG
239
240    const PosRange *changedRange = NULp;
241    if (range.is_whole()) {
242        changedRange = BaseFrequencies::changed_range(old_sequence, new_sequence, std::min(old_len, new_len));
243    }
244    else {
245        changedRange = &range; // @@@ use method similar to changed_range here, which just reduces the existing range
246    }
247
248    ED4_returncode result = ED4_R_OK;
249    if (changedRange) {
250        ED4_returncode result1 = update_bases(old_sequence, old_len, new_sequence, new_len, *changedRange);
251        ED4_returncode result2 = rebuild_consensi(new_base, update_flag);
252
253        result = (result1 != ED4_R_OK) ? result1 : result2;
254
255        // Refresh aminoacid sequence terminals in Protein Viewer or protstruct // @@@ this is definitely wrong here (omg)
256        if (ED4_ROOT->alignment_type == GB_AT_DNA) {
257            PV_SequenceUpdate_CB(GB_CB_CHANGED);
258        }
259        else if (ED4_ROOT->alignment_type == GB_AT_AA) { 
260            GB_ERROR err = ED4_pfold_set_SAI(&ED4_ROOT->protstruct, ED4_ROOT->get_gb_main(), ED4_ROOT->alignment_name, &ED4_ROOT->protstruct_len);
261            if (err) { aw_message(err); result = ED4_R_WARNING; }
262        }
263    }
264    return result;
265}
266
267ED4_returncode ED4_manager::update_bases(const ED4_base *old_base, const ED4_base *new_base, PosRange range) {
268    e4_assert(old_base);
269    e4_assert(new_base);
270
271    if (old_base->is_species_manager()) {
272        e4_assert(new_base->is_species_manager());
273        const ED4_species_manager *old_species_manager   = old_base->to_species_manager();
274        const ED4_species_manager *new_species_manager   = new_base->to_species_manager();
275        const ED4_terminal        *old_sequence_terminal = old_species_manager->get_consensus_relevant_terminal();
276        const ED4_terminal        *new_sequence_terminal = new_species_manager->get_consensus_relevant_terminal();
277
278        int   old_len;
279        int   new_len;
280        char *old_seq = old_sequence_terminal->resolve_pointer_to_string_copy(&old_len);
281        char *new_seq = new_sequence_terminal->resolve_pointer_to_string_copy(&new_len);
282
283        ED4_returncode res = update_bases(old_seq, old_len, new_seq, new_len, range);
284        free(new_seq);
285        free(old_seq);
286        return res;
287    }
288
289    e4_assert(!old_base->is_root_group_manager());
290    e4_assert(!new_base->is_root_group_manager());
291    if (old_base->is_group_manager()) {
292        e4_assert(new_base->is_group_manager());
293
294        return update_bases(&old_base->to_group_manager()->table(),
295                           &new_base->to_group_manager()->table(),
296                           range);
297    }
298
299    return ED4_R_OK;
300}
301
302// WITH_ALL_ABOVE_GROUP_MANAGER_TABLES performs a command with all groupmanager-tables
303// starting at walk_up (normally the current) until top (or until one table has an ignore flag)
304
305#define WITH_ALL_ABOVE_GROUP_MANAGER_TABLES(walk_up, COMMAND)                                   \
306    do {                                                                                        \
307        while (walk_up) {                                                                       \
308            if (walk_up->is_abstract_group_manager()) {                                         \
309                BaseFrequencies& char_table = walk_up->to_abstract_group_manager()->table();     \
310                char_table.COMMAND;                                                             \
311                if (char_table.is_ignored()) break; /* @@@ problematic */                       \
312            }                                                                                   \
313            walk_up = walk_up->parent;                                                          \
314        }                                                                                       \
315    } while (0)
316
317ED4_returncode ED4_manager::update_bases(const char *old_sequence, int old_len, const char *new_sequence, int new_len, PosRange range) {
318    ED4_manager *walk_up = this;
319
320    if (old_sequence) {
321        if (new_sequence) {
322            if (range.is_whole()) {
323                const PosRange *restricted = BaseFrequencies::changed_range(old_sequence, new_sequence, std::min(old_len, new_len));
324                if (!restricted) return ED4_R_OK;
325               
326                range = *restricted;
327            }
328
329#if defined(DEBUG) && 0
330            printf("update_bases(..., %i, %i)\n", start_pos, end_pos);
331#endif
332
333            WITH_ALL_ABOVE_GROUP_MANAGER_TABLES(walk_up, sub_and_add(old_sequence, new_sequence, range));
334        }
335        else {
336            e4_assert(range.is_whole());
337            WITH_ALL_ABOVE_GROUP_MANAGER_TABLES(walk_up, sub(old_sequence, old_len));
338        }
339    }
340    else {
341        if (new_sequence) {
342            e4_assert(range.is_whole());
343            WITH_ALL_ABOVE_GROUP_MANAGER_TABLES(walk_up, add(new_sequence, new_len));
344        }
345        else {
346            return ED4_R_OK;
347        }
348    }
349
350    ED4_ROOT->root_group_man->remap()->mark_compile_needed();
351    return ED4_R_OK;
352}
353
354ED4_returncode ED4_manager::update_bases(const BaseFrequencies *old_table, const BaseFrequencies *new_table, PosRange range) {
355    ED4_manager *walk_up = this;
356
357    if (old_table) {
358        if (new_table) {
359            if (range.is_whole()) {
360                const PosRange *restricted = old_table->changed_range(*new_table);
361                if (!restricted) return ED4_R_OK;
362
363                range = *restricted;
364            }
365            WITH_ALL_ABOVE_GROUP_MANAGER_TABLES(walk_up, sub_and_add(*old_table, *new_table, range));
366        }
367        else {
368            e4_assert(range.is_whole());
369            WITH_ALL_ABOVE_GROUP_MANAGER_TABLES(walk_up, sub(*old_table));
370        }
371    }
372    else {
373        if (new_table) {
374            e4_assert(range.is_whole());
375            WITH_ALL_ABOVE_GROUP_MANAGER_TABLES(walk_up, add(*new_table));
376        }
377        else {
378            return ED4_R_OK;
379        }
380    }
381
382    ED4_ROOT->root_group_man->remap()->mark_compile_needed();
383    return ED4_R_OK;
384}
385
386#undef WITH_ALL_ABOVE_GROUP_MANAGER_TABLES
387
388void ED4_manager::remove_callbacks() {
389    // removes callbacks
390    for (int i=0; i < members(); i++) {
391        member(i)->remove_callbacks();
392    }
393}
394
395void ED4_manager::update_consensus(ED4_manager *old_parent, ED4_manager *new_parent, ED4_base *sequence) {
396    if (old_parent) old_parent->check_out_bases(sequence);
397    if (new_parent) new_parent->check_in_bases(sequence);
398}
399
400ED4_terminal* ED4_manager::get_first_terminal(int start_index) const {
401    ED4_terminal *terminal = NULp;
402
403    for (int i=start_index; !terminal && i>=0 && i<members(); i++) {
404        ED4_base *base = member(i);
405        if (base->is_terminal()) {
406            terminal = base->to_terminal();
407        }
408        else {
409            terminal = base->to_manager()->get_first_terminal();
410        }
411    }
412
413    return terminal;
414}
415
416ED4_terminal* ED4_manager::get_last_terminal(int start_index) const {
417    ED4_terminal *terminal = NULp;
418
419    if (start_index<0) start_index = members()-1;
420    for (int i=start_index; !terminal && i>=0 && i<members(); i--) {
421        ED4_base *base = member(i);
422        if (base->is_terminal()) {
423            terminal = base->to_terminal();
424        }
425        else {
426            terminal = base->to_manager()->get_last_terminal();
427        }
428    }
429
430    return terminal;
431}
432
433ED4_base* ED4_manager::get_competent_child(AW_pos x, AW_pos y, ED4_properties relevant_prop) {
434    ED4_extension  ext;
435    ED4_index      temp_index;
436    ED4_base      *child;
437
438    ext.position[X_POS] = x;
439    ext.position[Y_POS] = y;
440    ED4_base::touch_world_cache();
441
442    temp_index = search_member(&ext, spec.static_prop);
443
444    if ((temp_index < 0) || (temp_index >= members())) {     // no child at given location
445        return NULp;
446    }
447
448    child = member(temp_index);
449
450    return (child->spec.static_prop & relevant_prop) ? child : (ED4_base*)NULp;
451}
452
453ED4_base* ED4_manager::get_competent_clicked_child(AW_pos x, AW_pos y, ED4_properties relevant_prop) {
454    ED4_extension  ext;
455    ED4_base      *child;
456    ED4_base      *temp_parent = NULp;
457
458    ext.position[X_POS] = x;
459    ext.position[Y_POS] = y;
460    ED4_base::touch_world_cache();
461
462    search_target_species(&ext, spec.static_prop, &temp_parent, LEV_MULTI_SPECIES);
463
464    if (!temp_parent) {
465        temp_parent = this;
466    }
467
468    child = temp_parent;
469    if (child->spec.static_prop & relevant_prop) {
470        return child;
471    }
472    else {
473        return NULp;
474    }
475}
476
477ED4_returncode ED4_manager::handle_move(ED4_move_info *mi) {
478    // handles a move request with target world
479    // coordinates within current object's borders
480
481    if ((!mi) || (mi->object->spec.level <= spec.level)) {
482        return ED4_R_IMPOSSIBLE;
483    }
484
485    AW_pos rel_x = mi->end_x; // calculate target position relative to current object
486    AW_pos rel_y = mi->end_y;
487    calc_rel_coords(&rel_x, &rel_y);
488
489    if ((mi->preferred_parent & spec.level) ||             // desired parent or levels match = > can handle moving
490        (mi->object->spec.level & spec.allowed_children)) // object(s) myself, take info from list of selected objects
491    {
492        ED4_base *object;
493        bool      i_am_consensus = false;
494
495        if (mi->object->has_property(PROP_IS_HANDLE)) { // object is a handle for an object up in the hierarchy = > search it
496            ED4_level mlevel = mi->object->spec.handled_level;
497
498            object = mi->object;
499
500            while (object && !(object->spec.level & mlevel)) object = object->parent;
501            if (!object) return ED4_R_IMPOSSIBLE; // no target level found
502        }
503        else {
504            object = mi->object; // selected object is no handle => take it directly
505
506            if (object->is_consensus_manager()) {
507                if (this->is_child_of(object->parent)) return ED4_R_IMPOSSIBLE; // has to pass multi_species_manager
508                i_am_consensus = true;
509                if (object->parent != this) {
510                    object = object->parent->parent;
511                    mi->object = object;
512                }
513            }
514        }
515
516
517        ED4_manager *old_parent = object->parent;
518
519        AW_pos x_off = 0;
520
521        // now do move action => determine insertion offsets and insert object
522
523        if (ED4_ROOT->selected_objects->size()>1) {
524            ED4_selected_elem *list_elem = ED4_ROOT->selected_objects->head();
525            while (list_elem) {
526                ED4_selection_entry *sel_info   = list_elem->elem();
527                ED4_terminal        *sel_object = sel_info->object;
528
529                if (sel_object==mi->object) break;
530                if (spec.static_prop & PROP_VERTICAL) x_off += sel_info->actual_width;
531
532                list_elem = list_elem->next();
533            }
534        }
535
536        {
537            ED4_extension loc;
538            loc.position[Y_POS] = mi->end_y;
539            loc.position[X_POS] = mi->end_x;
540            ED4_base::touch_world_cache();
541
542            ED4_base *found_member = NULp;
543            {
544                ED4_manager *dummy_mark = ED4_ROOT->main_manager->search_spec_child_rek(LEV_DEVICE)->to_manager();
545                dummy_mark->search_target_species(&loc, PROP_HORIZONTAL, &found_member, LEV_NONE);
546            }
547
548            if (found_member==object) { // if we are dropped on ourself => don't move
549                return ED4_R_BREAK;
550            }
551        }
552
553        {
554            ED4_base *parent_man = object->get_parent(LEV_MULTI_SPECIES);
555            object->parent->remove_member(object);
556            parent_man->to_multi_species_manager()->invalidate_species_counters();
557        }
558
559        object->extension.position[X_POS] = rel_x + x_off;
560        object->extension.position[Y_POS] = rel_y;
561        ED4_base::touch_world_cache();
562
563        object->parent = this;
564
565        if (old_parent != this) { // check whether consensus has to be calculated new or not
566            GB_transaction ta(ED4_ROOT->get_gb_main());
567            update_consensus(old_parent, this, object);
568            rebuild_consensi(old_parent, ED4_U_UP);
569            rebuild_consensi(this, ED4_U_UP);
570        }
571
572        if ((i_am_consensus && object->parent != old_parent) || !i_am_consensus) {
573            object->set_width();
574
575            if (parent->has_property(PROP_IS_FOLDED)) { // add spacer and consensusheight
576                e4_assert(parent->is_group_manager());
577                object->extension.position[Y_POS] = member(0)->extension.size[HEIGHT] + member(1)->extension.size[HEIGHT];
578                object->flag.hidden = 1;
579                ED4_base::touch_world_cache();
580            }
581        }
582
583        insert_member(object);
584        if (is_multi_species_manager()) {
585            to_multi_species_manager()->invalidate_species_counters();
586        }
587        else {
588            get_parent(LEV_MULTI_SPECIES)->to_multi_species_manager()->invalidate_species_counters();
589        }
590
591        ED4_request_relayout();
592
593        return ED4_R_OK;
594    }
595    else {
596        // levels do not match = > ask competent manager child to handle move request
597        ED4_manager *manager = (ED4_manager *) get_competent_child(rel_x, rel_y, PROP_IS_MANAGER);
598        if (!manager) return ED4_R_IMPOSSIBLE; // no manager child covering target location = > move not possible
599        return manager->move_requested_by_parent(mi); // there is a manager child covering target location = > pass on move request
600    }
601}
602
603
604ED4_returncode ED4_manager::move_requested_by_parent(ED4_move_info *mi) {
605    // handles a move request with target world coordinates coming from parent
606    if ((!mi) || !(in_border(mi->end_x, mi->end_y, mi->mode)))
607        return ED4_R_IMPOSSIBLE;
608
609    return handle_move(mi);
610}
611
612
613ED4_returncode  ED4_manager::move_requested_by_child(ED4_move_info *mi) {
614    // handles a move request coming from a child,
615    // target location can be out of borders
616    if (!mi)
617        return ED4_R_IMPOSSIBLE;
618
619    if (spec.level < mi->object->spec.restriction_level) return ED4_R_IMPOSSIBLE; // check if there is a level restriction to the move request
620
621    if (mi->object->has_property(PROP_IS_HANDLE)) { // determine first if we could be the moving object
622        if (has_property(PROP_MOVABLE) && (spec.level & mi->object->spec.handled_level)) { // yes, we are meant to be the moving object
623            mi->object = this;
624        }
625
626        if (!parent) return ED4_R_WARNING;
627
628        return parent->move_requested_by_child(mi);
629    }
630
631    if (!(in_border(mi->end_x, mi->end_y, mi->mode))) {
632        // determine if target location is within
633        // the borders of current object, do boundary
634        // adjustment of target coordinates if necessary
635        // target location is not within borders =>
636        // ask parent, i.e. move recursively up
637        if (!parent) return ED4_R_WARNING;
638        return parent->move_requested_by_child(mi);
639    }
640    else { // target location within current borders = > handle move myself
641        ED4_base *temp_parent = get_competent_clicked_child(mi->end_x, mi->end_y, PROP_IS_MANAGER);
642
643        if (!temp_parent) {
644            return handle_move(mi);
645        }
646        else {
647            if ((temp_parent->is_group_manager()) || (temp_parent->is_area_manager())) {
648                temp_parent = temp_parent->to_group_manager()->get_defined_level(LEV_MULTI_SPECIES);
649            }
650            else if (!(temp_parent->is_multi_species_manager())) {
651                temp_parent = temp_parent->get_parent(LEV_MULTI_SPECIES);
652            }
653            if (!temp_parent) {
654                return ED4_R_IMPOSSIBLE;
655            }
656            return temp_parent->to_manager()->handle_move(mi);
657        }
658    }
659}
660
661ED4_returncode ED4_manager::event_sent_by_parent(AW_event *event, AW_window *aww) {
662    // handles an input event coming from parent
663    if (flag.hidden) {
664        return ED4_R_BREAK;
665    }
666
667    ED4_extension ext;
668    ext.position[X_POS] = event->x;
669    ext.position[Y_POS] = event->y;
670
671    calc_rel_coords(&ext.position[X_POS], &ext.position[Y_POS]);
672
673    ED4_index temp_index = search_member(&ext, spec.static_prop); // search child who is competent for the location of given event
674    if (!existing_index(temp_index)) {
675        return ED4_R_IMPOSSIBLE; // no suitable member found
676    }
677
678    return member(temp_index)->event_sent_by_parent(event, aww);
679}
680
681ED4_returncode  ED4_manager::refresh_requested_by_child() {
682    // handles a refresh-request from a child
683    if (!update_info.refresh) { // determine if there were more refresh requests already => no need to tell parent about it
684        update_info.set_refresh(1); // this is the first refresh request
685        if (parent) parent->refresh_requested_by_child(); // if we have a parent, tell him about the refresh request
686    }
687
688#ifdef TEST_REFRESH_FLAG
689    e4_assert(refresh_flag_ok());
690#endif
691    return ED4_R_OK;
692}
693
694int ED4_manager::refresh_flag_ok() {
695    ED4_index i;
696
697    for (i=0; i<members(); i++) {
698        ED4_base *child = member(i);
699
700        if (child->is_manager()) {
701            if (!child->to_manager()->refresh_flag_ok()) {
702                return 0;
703            }
704        }
705
706        if (child->update_info.refresh==1 && update_info.refresh==0) {
707            printf("Forgotten refresh-flag in '%s' (son of '%s')\n", child->id, id);
708            fflush(stdout);
709            return 0;
710        }
711    }
712
713    return 1;
714}
715
716inline void ED4_base::resize_requested_by_link(ED4_base *IF_ASSERTION_USED(link)) {
717    e4_assert((width_link == link) || (height_link == link)); // wrong link
718    if (calc_bounding_box()) request_resize();
719}
720
721void ED4_base::request_resize_of_linked() {
722    if (linked_objects) {
723        ED4_base_list_elem *current_list_elem = linked_objects->head();
724        while (current_list_elem) {
725            ED4_base *object = current_list_elem->elem();
726            object->resize_requested_by_link(this);
727            current_list_elem = current_list_elem->next();
728        }
729    }
730}
731
732bool ED4_manager::calc_bounding_box() {
733    // calculates the smallest rectangle containing the object.
734    // returns true if bounding box has changed.
735    AW_pos     sum_width  = 0;
736    AW_pos     sum_height = 0;
737    AW_pos     max_x      = 0;
738    AW_pos     max_y      = 0;
739    AW_pos     dummy      = 0;
740
741    for (ED4_index i = 0; existing_index(i); ++i) { // check all children
742        ED4_base *child = member(i);
743        if (!child->flag.hidden) {
744            sum_width  += child->extension.size[WIDTH];
745            sum_height += child->extension.size[HEIGHT];
746
747            dummy = child->extension.position[X_POS] + child->extension.size[WIDTH];
748            if (dummy > max_x) {
749                max_x = dummy;
750            }
751
752            dummy = child->extension.position[Y_POS] + child->extension.size[HEIGHT];
753            if (dummy > max_y) {
754                max_y = dummy;
755            }
756            ED4_base::touch_world_cache();
757        }
758    }
759
760    bool bb_changed = false;
761    if (spec.static_prop & PROP_HORIZONTAL) {
762        bb_changed = extension.set_size_does_change(WIDTH, max_x) || bb_changed;
763        bb_changed = extension.set_size_does_change(HEIGHT, sum_height) || bb_changed;
764    }
765
766    if (spec.static_prop & PROP_VERTICAL) {
767        bb_changed = extension.set_size_does_change(WIDTH, sum_width) || bb_changed;
768        bb_changed = extension.set_size_does_change(HEIGHT, max_y) || bb_changed;
769    }
770
771    if (bb_changed) {
772        request_resize_of_linked();
773    }
774    return bb_changed;
775}
776
777ED4_returncode ED4_manager::distribute_children() {
778    // distributes all children of current object according to current object's properties and
779    // justification value; a recalculation of current object's extension will take place if necessary
780
781    ED4_index rel_pos        = 0;
782    ED4_index rel_size       = 0;
783    ED4_index other_pos      = 0;
784    ED4_index other_size     = 0;
785    AW_pos    max_rel_size   = 0;
786    AW_pos    max_other_size = 0;
787
788    // set extension-indexes rel_pos and rel_size according to properties
789    if (spec.static_prop & PROP_HORIZONTAL) {
790        rel_pos    = X_POS;
791        other_pos  = Y_POS;
792        rel_size   = WIDTH;
793        other_size = HEIGHT;
794    }
795    if (spec.static_prop & PROP_VERTICAL) {
796        rel_pos    = Y_POS;
797        other_pos  = X_POS;
798        rel_size   = HEIGHT;
799        other_size = WIDTH;
800    }
801
802    // get maximal relevant and other size of children, set children's other position increasingly
803    for (ED4_index i = 0; existing_index(i); ++i) {
804        ED4_base *child = member(i);
805
806        max_rel_size = std::max(int(max_rel_size), int(child->extension.size[rel_size]));
807        if (child->extension.position[other_pos] != max_other_size) {
808            child->extension.position[other_pos] = max_other_size;
809            ED4_base::touch_world_cache();
810        }
811        max_other_size += child->extension.size[other_size];
812    }
813
814    // set children's relevant position according to justification value
815    // (0.0 means top- or left-justified, 1.0 means bottom- or right-justified)
816    for (ED4_index i = 0; existing_index(i); ++i) {
817        member(i)->extension.position[rel_pos] = 0.0;
818        ED4_base::touch_world_cache();
819    }
820
821    refresh_requested_by_child();
822    return ED4_R_OK;
823}
824
825void ED4_manager::resize_requested_children() {
826    if (update_info.resize) { // object wants to resize
827        update_info.set_resize(0); // first clear the resize flag (remember it could be set again from somewhere below the hierarchy)
828
829        for (ED4_index i = 0; existing_index(i); ++i) {
830            ED4_base *child = member(i);
831
832            child->update_info.set_resize(1);
833            child->resize_requested_children();
834        }
835
836        distribute_children();
837        if (calc_bounding_box()) request_resize();
838    }
839}
840void ED4_root_group_manager::resize_requested_children() {
841    if (update_info.resize) {
842        if (update_remap()) ED4_ROOT->request_refresh_for_specific_terminals(LEV_SEQUENCE_STRING);
843        ED4_manager::resize_requested_children();
844    }
845    else {
846        e4_assert(!update_remap());
847    }
848}
849
850static void update_scrolled_rectangles(ED4_window *win) { win->update_scrolled_rectangle(); }
851void ED4_main_manager::resize_requested_children() {
852    if (update_info.resize) {
853        ED4_manager::resize_requested_children();
854        ED4_with_all_edit_windows(update_scrolled_rectangles);
855    }
856}
857
858void ED4_main_manager::Show(bool refresh_all, bool is_cleared) {
859#ifdef TEST_REFRESH_FLAG
860    e4_assert(refresh_flag_ok());
861#endif
862
863    AW_device *device = current_device();
864
865    if (!flag.hidden && (refresh_all || update_info.refresh)) {
866#if defined(TRACE_REFRESH)
867        fprintf(stderr, "- really paint in ED4_main_manager::Show(refresh_all=%i, is_cleared=%i)\n", int(refresh_all), int(is_cleared)); fflush(stderr);
868#endif
869        const AW_screen_area& area_rect = device->get_area_size();
870
871        // if update all -> clear_background
872
873        if (update_info.clear_at_refresh && !is_cleared) {
874            device->push_clip_scale();
875            if (device->reduceClipBorders(area_rect.t, area_rect.b, area_rect.l, area_rect.r)) {
876                clear_background();
877            }
878            is_cleared = 1;
879            device->pop_clip_scale();
880        }
881
882        // loop through all rectangles between folding lines:
883
884        int x1, y1, x2, y2;
885        ED4_window& win = *current_ed4w();
886        x1 = area_rect.l;
887        for (const ED4_folding_line *flv = win.get_vertical_folding(); ; flv = flv->get_next()) {
888            if (flv) {
889                x2 = int(flv->get_pos()); // @@@ use AW_INT ?
890            }
891            else {
892                x2 = area_rect.r;
893                if (x1==x2) break; // do not draw last range, if it's only 1 pixel width
894            }
895
896            y1 = area_rect.t;
897            for (const ED4_folding_line *flh = win.get_horizontal_folding(); ; flh = flh->get_next()) {
898                if (flh) {
899                    y2 = int(flh->get_pos()); // @@@ use AW_INT ?
900                }
901                else {
902                    y2 = area_rect.b;
903                    if (y1==y2) break; // do not draw last range, if it's only 1 pixel high
904                }
905
906                device->push_clip_scale();
907                if (device->reduceClipBorders(y1, y2-1, x1, x2-1)) {
908                    ED4_manager::Show(refresh_all, is_cleared);
909                }
910                device->pop_clip_scale();
911
912                if (!flh) break; // break out after drawing lowest range
913                y1 = y2;
914            }
915            if (!flv) break; // break out after drawing rightmost range
916
917            x1 = x2;
918        }
919
920        // to avoid text clipping problems between top and middle area we redraw the top-middle-spacer :
921        {
922            device->push_clip_scale();
923            const AW_screen_area& clip_rect = device->get_cliprect();
924            device->set_top_clip_border(clip_rect.t-TERMINAL_HEIGHT);
925
926            int char_width = ED4_ROOT->font_group.get_max_width();
927            device->set_left_clip_border(clip_rect.l-char_width);
928            device->set_right_clip_border(clip_rect.r+char_width);
929
930            get_top_middle_spacer_terminal()->Show(true, false);
931            get_top_middle_line_terminal()->Show(true, false);
932            device->pop_clip_scale();
933        }
934
935        // always draw cursor
936        ED4_cursor& cursor = current_cursor();
937        if (cursor.owner_of_cursor && cursor.allowed_to_draw) {
938            if (cursor.is_partly_visible()) {
939                cursor.ShowCursor(0, ED4_C_NONE, 0);
940            }
941        }
942    }
943#ifdef TEST_REFRESH_FLAG
944    e4_assert(refresh_flag_ok());
945#endif
946}
947
948
949void ED4_root_group_manager::Show(bool refresh_all, bool is_cleared) {
950    if (update_remap()) { // @@@ dont call here ?
951#if defined(TRACE_REFRESH)
952        printf("map updated in ED4_root_group_manager::Show (bad?)\n");
953#endif
954    }
955    ED4_manager::Show(refresh_all, is_cleared);
956}
957
958void ED4_manager::Show(bool refresh_all, bool is_cleared) {
959#ifdef TEST_REFRESH_FLAG
960    e4_assert(refresh_flag_ok());
961#endif
962
963    if (!flag.hidden && (refresh_all || update_info.refresh)) {
964        if (update_info.clear_at_refresh && !is_cleared) {
965            clear_background();
966            is_cleared = 1;
967        }
968
969        AW_screen_area rect; // clipped rectangle in world coordinates
970
971        {
972            const AW_screen_area &clip_rect = current_device()->get_cliprect();      // clipped rectangle in win coordinates
973           
974            double x, y;
975            x = clip_rect.l;
976            y = clip_rect.t;
977
978            current_ed4w()->win_to_world_coords(&x, &y);
979
980            rect.l = int(x);
981            rect.t = int(y);
982
983            e4_assert(AW::nearlyEqual(current_device()->get_scale(), 1.0)); // assumed by calculation below
984            rect.r = rect.l+(clip_rect.r-clip_rect.l);
985            rect.b = rect.t+(clip_rect.b-clip_rect.t);
986        }
987
988        // binary search to find first visible child
989
990        int first_visible_child = 0; //@@@FIXME: this variable is never again set
991
992        {
993            int l = 0;
994            int h = members()-1;
995
996            while (l<h) {
997
998                while (member(l)->flag.hidden && l<h) l++;
999                while (member(h)->flag.hidden && l<h) h--;
1000
1001                int m = (l+h)/2;
1002                int min_m = m;
1003                int max_m = m+1;
1004
1005                while (member(m)->flag.hidden) {
1006                    if (m==h) {
1007                        m = (l+h)/2-1;
1008                        while (member(m)->flag.hidden) {
1009                            if (m==l) {
1010                                // all children between l..h are flag.hidden
1011                                goto no_visible_child_found;
1012                            }
1013                            m--;
1014                        }
1015                        min_m = m;
1016                        break;
1017                    }
1018                    m++;
1019                    max_m = m;
1020                }
1021
1022                ED4_base *child = member(m);
1023                e4_assert(!child->flag.hidden);
1024
1025                AW_pos x, y;
1026                child->calc_world_coords(&x, &y);
1027
1028                if (spec.static_prop & PROP_HORIZONTAL) { // horizontal manager
1029                    e4_assert((spec.static_prop&PROP_VERTICAL)==0);   // otherwise this binary search will not work correctly
1030                    if ((x+child->extension.size[WIDTH])<=rect.l) { // left of clipping range
1031                        l = max_m;
1032                    }
1033                    else {
1034                        h = min_m;
1035                    }
1036                }
1037                else if (spec.static_prop & PROP_VERTICAL) { // vertical manager
1038                    if ((y+child->extension.size[HEIGHT])<=rect.t) { // above clipping range
1039                        l = max_m;
1040                    }
1041                    else {
1042                        h = min_m;
1043                    }
1044                }
1045                else {
1046                    e4_assert(0);
1047                }
1048            }
1049        }
1050
1051      no_visible_child_found :
1052
1053        for (ED4_index i = 0; existing_index(i); ++i) {
1054            ED4_base *child = member(i);
1055            e4_assert(child);
1056
1057            if (!child->flag.hidden && (refresh_all || child->update_info.refresh) && i>=first_visible_child) {
1058                AW_pos x, y;
1059                child->calc_world_coords(&x, &y);
1060
1061                AW_device *device = current_device();
1062
1063                if (!(((y-rect.b)>0.5) ||
1064                      ((rect.t-(y+child->extension.size[HEIGHT]-1))>0.5) ||
1065                      ((x-rect.r)>0.5) ||
1066                      ((rect.l-(x+child->extension.size[WIDTH]-1))>0.5)
1067                     ))
1068                {
1069                    // they overlap -> show it
1070                    device->push_clip_scale();
1071                    if (child->adjust_clipping_rectangle()) {
1072                        child->Show(refresh_all, is_cleared);
1073                    }
1074                    device->pop_clip_scale();
1075                }
1076            }
1077        }
1078    }
1079
1080#ifdef TEST_REFRESH_FLAG
1081    e4_assert(refresh_flag_ok());
1082#endif
1083}
1084
1085ED4_returncode ED4_manager::clear_refresh() {
1086    e4_assert(update_info.refresh);
1087
1088    for (int i=0; i<members(); i++) {
1089        ED4_base *child = member(i);
1090
1091        if (child->update_info.refresh) {
1092            if (child->is_manager()) {
1093                child->to_manager()->clear_refresh();
1094            }
1095            else {
1096                child->update_info.set_refresh(0);
1097                child->update_info.set_clear_at_refresh(0);
1098            }
1099        }
1100    }
1101
1102    update_info.set_refresh(0);
1103    update_info.set_clear_at_refresh(0);
1104
1105    return ED4_R_OK;
1106}
1107
1108void ED4_manager::update_requested_by_child() { // @@@ same as set_update -> DRY
1109    if (!update_info.update_requested) {
1110        if (parent) parent->update_requested_by_child();
1111        update_info.update_requested = 1;
1112    }
1113}
1114void ED4_manager::delete_requested_by_child() {
1115    if (!update_info.delete_requested) {
1116        if (parent) parent->delete_requested_by_child();
1117        update_info.delete_requested = 1;
1118    }
1119}
1120void ED4_terminal::delete_requested_children() {
1121    e4_assert(update_info.delete_requested);
1122    e4_assert(tflag.deleted);
1123
1124    ED4_ROOT->announce_deletion(this);
1125
1126    unlink_from_parent();
1127    delete this;
1128}
1129
1130void ED4_manager::update_requested_children() {
1131    e4_assert(update_info.update_requested);
1132
1133    for (int i=0; i<members(); i++) {
1134        ED4_base *child = member(i);
1135        if (child->update_info.update_requested) {
1136            child->update_requested_children();
1137        }
1138    }
1139
1140    update_info.update_requested = 0;
1141}
1142
1143void ED4_multi_species_manager::update_requested_children() {
1144    e4_assert(update_info.update_requested);
1145    ED4_manager::update_requested_children();
1146    update_species_counters();
1147    update_group_id();
1148
1149    ED4_base *group_base = get_parent(LEV_GROUP);
1150    if (group_base) {
1151        e4_assert(group_base->is_group_manager());
1152        e4_assert(!group_base->is_root_group_manager());
1153
1154        ED4_group_manager *group_man    = parent->to_group_manager();
1155        ED4_base          *bracket_base = group_man->get_defined_level(LEV_BRACKET);
1156
1157        if (bracket_base) bracket_base->request_refresh();
1158    }
1159}
1160
1161void ED4_manager::delete_requested_children() {
1162    e4_assert(update_info.delete_requested);
1163
1164    for (int i = members()-1; i >= 0; --i) {
1165        ED4_base *child = member(i);
1166        if (child->update_info.delete_requested) {
1167            child->delete_requested_children();
1168        }
1169    }
1170
1171    update_info.delete_requested = 0;
1172
1173    if (!members()) {
1174        ED4_ROOT->announce_deletion(this);
1175       
1176        unlink_from_parent();
1177        delete this;
1178    }
1179}
1180
1181void ED4_multi_species_manager::delete_requested_children() {
1182    e4_assert(update_info.delete_requested);
1183    invalidate_species_counters();
1184    ED4_manager::delete_requested_children();
1185}
1186
1187void ED4_terminal::Delete() {
1188    if (!tflag.deleted) {
1189        tflag.deleted                = 1;
1190        update_info.delete_requested = 1;
1191        parent->delete_requested_by_child();
1192    }
1193}
1194
1195void ED4_manager::Delete() {
1196    delete_cbs.call(this);
1197    delete_cbs.clear();
1198
1199    for (int i=0; i<members(); i++) {
1200        member(i)->Delete();
1201    }
1202}
1203
1204void ED4_manager::request_refresh(int clear_at_refresh) {
1205    // sets refresh flag of current object and its children
1206    update_info.set_refresh(1);
1207    update_info.set_clear_at_refresh(clear_at_refresh);
1208
1209    if (parent) parent->refresh_requested_by_child();
1210
1211    for (ED4_index i = 0; existing_index(i); ++i) {
1212        member(i)->request_refresh(0); // clear_at_refresh not needed for childs!
1213    }
1214}
1215
1216
1217ED4_base* ED4_manager::search_ID(const char *temp_id) {
1218    if (strcmp(temp_id, id) == 0) return this; // this object is the sought one
1219
1220    // search whole memberlist recursively for object with the given id
1221    for (ED4_index i = 0; existing_index(i); ++i) {
1222        ED4_base *object = member(i)->search_ID(temp_id);
1223        if (object) return object;
1224    }
1225
1226    return NULp; // no object found
1227}
1228
1229
1230ED4_manager::ED4_manager(const ED4_objspec& spec_, const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1231    ED4_base(spec_, temp_id, width, height, temp_parent)
1232{}
1233
1234ED4_manager::~ED4_manager() {
1235    ED4_container::clear();
1236}
1237
1238// --------------------------
1239//      ED4_main_manager
1240
1241ED4_main_manager::ED4_main_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1242    ED4_manager(main_manager_spec, temp_id, width, height, temp_parent),
1243    top_middle_line(NULp),
1244    top_middle_spacer(NULp)
1245{
1246}
1247
1248// ----------------------------
1249//      ED4_device_manager
1250
1251ED4_device_manager::ED4_device_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1252    ED4_manager(device_manager_spec, temp_id, width, height, temp_parent)
1253{
1254}
1255
1256// --------------------------
1257//      ED4_area_manager
1258
1259ED4_area_manager::ED4_area_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1260    ED4_manager(area_manager_spec, temp_id, width, height, temp_parent)
1261{
1262}
1263
1264// -----------------------------------
1265//      ED4_multi_species_manager
1266
1267ED4_multi_species_manager::ED4_multi_species_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1268    ED4_manager(multi_species_manager_spec, temp_id, width, height, temp_parent),
1269    species(-1),
1270    selected_species(-1)
1271{
1272}
1273
1274int ED4_multi_species_manager::get_no_of_species() {
1275    if (!has_valid_counters()) {
1276        update_species_counters();
1277        e4_assert(has_valid_counters());
1278    }
1279    return species;
1280}
1281
1282int ED4_multi_species_manager::get_no_of_selected_species() {
1283    if (!has_valid_counters()) {
1284        update_species_counters();
1285        e4_assert(has_valid_counters());
1286    }
1287    return selected_species;
1288}
1289
1290void ED4_multi_species_manager::invalidate_species_counters() {
1291    if (has_valid_counters()) {
1292        species          = -1;
1293        selected_species = -1;
1294
1295        ED4_base *pms = get_parent(LEV_MULTI_SPECIES);
1296        if (pms) pms->to_multi_species_manager()->invalidate_species_counters();
1297       
1298        update_requested_by_child();
1299    }
1300}
1301
1302void ED4_multi_species_manager::set_species_counters(int no_of_species, int no_of_selected) {
1303
1304#if defined(DEBUG)
1305    int sp, sel;
1306
1307    count_species(&sp, &sel);
1308    e4_assert(no_of_species==sp);
1309    e4_assert(no_of_selected==sel);
1310#endif
1311
1312    e4_assert(no_of_species>=no_of_selected);
1313
1314    if (species!=no_of_species || selected_species!=no_of_selected) {
1315        int species_diff  = no_of_species-species;
1316        int selected_diff = no_of_selected-selected_species;
1317
1318        int quickSet = 1;
1319        if (species==-1 || selected_species==-1) {
1320            quickSet = 0;
1321        }
1322
1323        species          = no_of_species;
1324        selected_species = no_of_selected;
1325
1326        ED4_manager *gm = get_parent(LEV_GROUP);
1327        if (gm) gm->search_spec_child_rek(LEV_BRACKET)->request_refresh();
1328
1329        ED4_manager *ms = get_parent(LEV_MULTI_SPECIES);
1330        if (ms) {
1331            ED4_multi_species_manager *parent_multi_species_man = ms->to_multi_species_manager();
1332
1333            if (!quickSet) parent_multi_species_man->invalidate_species_counters();
1334
1335            if (parent_multi_species_man->has_valid_counters()) {
1336                parent_multi_species_man->set_species_counters(parent_multi_species_man->species+species_diff,
1337                                                               parent_multi_species_man->selected_species+selected_diff);
1338            }
1339        }
1340    }
1341}
1342
1343#ifdef DEBUG
1344void ED4_multi_species_manager::count_species(int *speciesPtr, int *selectedPtr) const {
1345    int m;
1346    int sp  = 0;
1347    int sel = 0;
1348
1349    for (m=0; m<members(); m++) {
1350        ED4_base *child = member(m);
1351
1352        if (child->is_group_manager()) {
1353            ED4_multi_species_manager *multi_species_man = child->to_group_manager()->get_multi_species_manager();
1354
1355            if (!multi_species_man->has_valid_counters()) {
1356                int sp1, sel1;
1357
1358                multi_species_man->count_species(&sp1, &sel1);
1359                sel += sel1;
1360                sp += sp1;
1361            }
1362            else {
1363                sel += multi_species_man->get_no_of_selected_species();
1364                sp += multi_species_man->get_no_of_species();
1365            }
1366        }
1367        else if (child->is_species_manager()) {
1368            ED4_species_manager *species_man = child->to_species_manager();
1369            if (!species_man->is_consensus_manager()) {
1370                sp++;
1371                if (species_man->is_selected()) sel++;
1372            }
1373        }
1374    }
1375
1376    *speciesPtr = sp;
1377    *selectedPtr = sel;
1378}
1379#endif
1380
1381void ED4_multi_species_manager::update_species_counters() {
1382    int m;
1383    int sp  = 0;
1384    int sel = 0;
1385
1386    for (m=0; m<members(); m++) {
1387        ED4_base *child = member(m);
1388
1389        if (child->is_group_manager()) {
1390            ED4_multi_species_manager *multi_species_man = child->to_group_manager()->get_multi_species_manager();
1391
1392            if (!multi_species_man->has_valid_counters()) {
1393                multi_species_man->update_species_counters();
1394            }
1395            sel += multi_species_man->get_no_of_selected_species();
1396            sp += multi_species_man->get_no_of_species();
1397        }
1398        else if (child->is_species_manager()) {
1399            ED4_species_manager *species_man = child->to_species_manager();
1400
1401            if (!species_man->is_consensus_manager()) {
1402                sp++;
1403                if (species_man->is_selected()) sel++;
1404            }
1405        }
1406    }
1407    set_species_counters(sp, sel);
1408}
1409
1410void ED4_multi_species_manager::select_all(bool only_species) {
1411    int m;
1412    int sp  = 0;
1413    int sel = 0;
1414
1415    for (m=0; m<members(); m++) {
1416        ED4_base *child = member(m);
1417
1418        if (child->is_group_manager()) {
1419            ED4_multi_species_manager *multi_species_man = child->to_group_manager()->get_multi_species_manager();
1420            multi_species_man->select_all(only_species);
1421            sp += multi_species_man->get_no_of_species();
1422            sel += multi_species_man->get_no_of_selected_species();
1423        }
1424        else if (child->is_species_manager()) {
1425            ED4_species_manager *species_man = child->to_species_manager();
1426
1427            if (!species_man->is_consensus_manager()) {
1428                sp++;
1429                if (!species_man->is_selected()) {
1430                    if (!only_species || !species_man->is_SAI_manager()) {
1431                        ED4_species_name_terminal *species_name = species_man->search_spec_child_rek(LEV_SPECIES_NAME)->to_species_name_terminal();
1432                        ED4_ROOT->add_to_selected(species_name);
1433                    }
1434                }
1435                if (species_man->is_selected()) sel++;
1436            }
1437        }
1438    }
1439    set_species_counters(sp, sel);
1440}
1441void ED4_multi_species_manager::deselect_all_species_and_SAI() {
1442    int m;
1443    int sp = 0;
1444
1445    for (m=0; m<members(); m++) {
1446        ED4_base *child = member(m);
1447
1448        if (child->is_group_manager()) {
1449            ED4_multi_species_manager *multi_species_man = child->to_group_manager()->get_multi_species_manager();
1450            multi_species_man->deselect_all_species_and_SAI();
1451            sp += multi_species_man->get_no_of_species();
1452        }
1453        else if (child->is_species_manager()) {
1454            ED4_species_manager *species_man = child->to_species_manager();
1455
1456            if (!species_man->is_consensus_manager()) {
1457                sp++;
1458                if (species_man->is_selected()) {
1459                    ED4_species_name_terminal *species_name = species_man->search_spec_child_rek(LEV_SPECIES_NAME)->to_species_name_terminal();
1460                    ED4_ROOT->remove_from_selected(species_name);
1461                }
1462            }
1463        }
1464        else {
1465            e4_assert(!child->is_manager());
1466        }
1467    }
1468    set_species_counters(sp, 0);
1469}
1470void ED4_multi_species_manager::invert_selection_of_all_species() {
1471    int m;
1472    int sp  = 0;
1473    int sel = 0;
1474
1475    for (m=0; m<members(); m++) {
1476        ED4_base *child = member(m);
1477
1478        if (child->is_group_manager()) {
1479            ED4_multi_species_manager *multi_species_man = child->to_group_manager()->get_multi_species_manager();
1480            multi_species_man->invert_selection_of_all_species();
1481            sp += multi_species_man->get_no_of_species();
1482            sel += multi_species_man->get_no_of_selected_species();
1483        }
1484        else if (child->is_species_manager()) {
1485            ED4_species_manager *species_man = child->to_species_manager();
1486
1487            if (!species_man->is_consensus_manager()) {
1488                sp++;
1489
1490                if (!species_man->is_SAI_manager()) {
1491                    ED4_species_name_terminal *species_name = species_man->search_spec_child_rek(LEV_SPECIES_NAME)->to_species_name_terminal();
1492
1493                    if (species_man->is_selected()) ED4_ROOT->remove_from_selected(species_name);
1494                    else                            ED4_ROOT->add_to_selected(species_name);
1495                }
1496                if (species_man->is_selected()) sel++;
1497            }
1498        }
1499        else {
1500            e4_assert(!child->is_manager());
1501        }
1502    }
1503
1504    e4_assert(get_no_of_selected_species()==sel);
1505    e4_assert(get_no_of_species()==sp);
1506}
1507void ED4_multi_species_manager::marked_species_select(bool select) {
1508    int m;
1509    int sp  = 0;
1510    int sel = 0;
1511
1512    for (m=0; m<members(); m++) {
1513        ED4_base *child = member(m);
1514
1515        if (child->is_group_manager()) {
1516            ED4_multi_species_manager *multi_species_man = child->to_group_manager()->get_multi_species_manager();
1517            multi_species_man->marked_species_select(select);
1518            sp += multi_species_man->get_no_of_species();
1519            sel += multi_species_man->get_no_of_selected_species();
1520        }
1521        else if (child->is_species_manager()) {
1522            ED4_species_manager *species_man = child->to_species_manager();
1523
1524            if (!species_man->is_consensus_manager()) {
1525                sp++;
1526
1527                if (species_man->is_species_seq_manager()) {
1528                    GBDATA *gbd = species_man->get_species_pointer();
1529                    e4_assert(gbd);
1530                    int is_marked = GB_read_flag(gbd);
1531
1532                    if (is_marked) {
1533                        if (select) { // select marked
1534                            if (!species_man->is_selected()) {
1535                                ED4_species_name_terminal *species_name = species_man->search_spec_child_rek(LEV_SPECIES_NAME)->to_species_name_terminal();
1536                                ED4_ROOT->add_to_selected(species_name);
1537                            }
1538                        }
1539                        else { // de-select marked
1540                            if (species_man->is_selected()) {
1541                                ED4_species_name_terminal *species_name = species_man->search_spec_child_rek(LEV_SPECIES_NAME)->to_species_name_terminal();
1542                                ED4_ROOT->remove_from_selected(species_name);
1543                            }
1544                        }
1545                    }
1546                }
1547                if (species_man->is_selected()) sel++;
1548            }
1549        }
1550        else {
1551            e4_assert(!child->is_manager());
1552        }
1553    }
1554    set_species_counters(sp, sel);
1555}
1556void ED4_multi_species_manager::selected_species_mark(bool mark) {
1557    int m;
1558    int sp  = 0;
1559    int sel = 0;
1560
1561    for (m=0; m<members(); m++) {
1562        ED4_base *child = member(m);
1563
1564        if (child->is_group_manager()) {
1565            ED4_multi_species_manager *multi_species_man = child->to_group_manager()->get_multi_species_manager();
1566            multi_species_man->selected_species_mark(mark);
1567            sp += multi_species_man->get_no_of_species();
1568            sel += multi_species_man->get_no_of_selected_species();
1569        }
1570        else if (child->is_species_manager()) {
1571            ED4_species_manager *species_man = child->to_species_manager();
1572
1573            if (!species_man->is_consensus_manager()) {
1574                sp++;
1575                if (species_man->is_selected()) {
1576                    if (species_man->is_species_seq_manager()) {
1577                        GBDATA *gbd = species_man->get_species_pointer();
1578                        e4_assert(gbd);
1579
1580                        GB_write_flag(gbd, mark ? 1 : 0);
1581                    }
1582                    sel++;
1583                }
1584            }
1585        }
1586        else {
1587            e4_assert(!child->is_manager());
1588        }
1589    }
1590    set_species_counters(sp, sel);
1591}
1592
1593ED4_species_manager *ED4_multi_species_manager::get_consensus_manager() const {
1594    ED4_species_manager *consensus_manager = NULp;
1595
1596    for (int i=0; i<members(); i++) {
1597        ED4_base *child = member(i);
1598        if (child->is_consensus_manager()) {
1599            consensus_manager = child->to_species_manager();
1600            break;
1601        }
1602    }
1603
1604    return consensus_manager;
1605}
1606
1607// -----------------------------
1608//      ED4_species_manager
1609
1610ED4_species_manager::ED4_species_manager(ED4_species_type type_, const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1611    ED4_manager(species_manager_spec, temp_id, width, height, temp_parent),
1612    type(type_),
1613    selected(false)
1614{
1615    e4_assert(type != ED4_SP_NONE);
1616    if (type == ED4_SP_SAI) ED4_ROOT->loadable_SAIs_may_have_changed();
1617}
1618
1619ED4_species_manager::~ED4_species_manager() {
1620    if (type == ED4_SP_SAI) ED4_ROOT->loadable_SAIs_may_have_changed();
1621}
1622
1623void ED4_root::remove_all_callbacks() {
1624    for (ED4_window *ew = first_window; ew; ew = ew->next) {
1625        ew->cursor.prepare_shutdown(); // removes any callbacks
1626    }
1627    ED4_viewDifferences_disable();
1628}
1629
1630// ------------------------
1631//      group managers
1632
1633ED4_abstract_group_manager::ED4_abstract_group_manager(const ED4_objspec& spec_, const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1634    ED4_manager(spec_, temp_id, width, height, temp_parent),
1635    my_table(0)
1636{
1637}
1638
1639ED4_group_manager::ED4_group_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent) :
1640    ED4_abstract_group_manager(group_manager_spec, temp_id, width, height, temp_parent)
1641{
1642}
1643
1644// -------------------
1645//      ED4_remap
1646
1647ED4_remap::ED4_remap() {
1648    mode               = ED4_RM_NONE;
1649    show_above_percent = 0;
1650
1651    sequence_table_len = 1;
1652    screen_table_len   = 1;
1653
1654    screen_to_sequence_tab = new int[1];        screen_to_sequence_tab[0] = 0;
1655    sequence_to_screen_tab = new int[1];        sequence_to_screen_tab[0] = 0;
1656
1657    sequence_len               = 0;
1658    MAXSEQUENCECHARACTERLENGTH = screen_len = 0;
1659
1660    changed       = 0;
1661    update_needed = 1;
1662
1663}
1664ED4_remap::~ED4_remap() {
1665    delete [] screen_to_sequence_tab;
1666    delete [] sequence_to_screen_tab;
1667}
1668int ED4_remap::screen_to_sequence(int screen_pos) const {
1669    if (size_t(screen_pos) == screen_len) {
1670        return screen_to_sequence_tab[screen_len-1];
1671    }
1672    e4_assert(screen_pos>=0 && size_t(screen_pos)<screen_len);
1673    return screen_to_sequence_tab[screen_pos];
1674}
1675int ED4_remap::clipped_sequence_to_screen_PLAIN(int sequence_pos) const {
1676    if (sequence_pos<0) {
1677        sequence_pos = 0;
1678    }
1679    else if (size_t(sequence_pos)>sequence_len) {
1680        sequence_pos = sequence_len;
1681    }
1682    return sequence_to_screen_PLAIN(sequence_pos);
1683}
1684int ED4_remap::sequence_to_screen(int sequence_pos) const {
1685    int scr_pos = sequence_to_screen_PLAIN(sequence_pos);
1686    if (scr_pos<0) scr_pos = -scr_pos;
1687    return scr_pos;
1688}
1689
1690void ED4_remap::adjacent_screen_positions(int seq_pos, int& screen_pos_left, int& screen_pos_right) {
1691    e4_assert(!is_shown(seq_pos)); // otherwise use sequence_to_screen()
1692
1693    screen_pos_left = -1;
1694    for (int p = seq_pos-1; screen_pos_left<0 && p>=0; --p) {
1695        screen_pos_left = sequence_to_screen_PLAIN(p);
1696    }
1697    screen_pos_right = -1;
1698    for (int p = seq_pos+1; screen_pos_right<0 && size_t(p)<=sequence_len; ++p) {
1699        screen_pos_right = sequence_to_screen_PLAIN(p);
1700    }
1701}
1702
1703inline void ED4_remap::set_sequence_to_screen(int pos, int newVal) {
1704    e4_assert(pos>=0 && size_t(pos)<sequence_table_len);
1705    if (sequence_to_screen_tab[pos]!=newVal) {
1706        sequence_to_screen_tab[pos] = newVal;
1707        changed = 1;
1708    }
1709}
1710void ED4_remap::mark_compile_needed_force() {
1711    if (!update_needed) {
1712        update_needed = 1;
1713        if (ED4_ROOT && ED4_ROOT->root_group_man) {                     // test if root_group_man already exists
1714            ED4_ROOT->root_group_man->resize_requested_by_child();      // remapping is recompiled while re-displaying the root_group_manager
1715        }
1716    }
1717}
1718void ED4_remap::mark_compile_needed() {
1719    if (mode!=ED4_RM_NONE) mark_compile_needed_force();
1720}
1721
1722GB_ERROR ED4_remap::compile(ED4_root_group_manager *gm) {
1723    e4_assert(update_needed);
1724
1725    const BaseFrequencies& table = gm->table();
1726    size_t i, j;
1727
1728    changed = 0; // is changed by set_sequence_to_screen
1729    update_needed = 0;
1730
1731    sequence_len = table.size(); // take size of any table
1732    if ((sequence_len+1) > sequence_table_len) {
1733        delete [] sequence_to_screen_tab;
1734        sequence_to_screen_tab = new int[sequence_table_len = sequence_len+1];
1735        memset(sequence_to_screen_tab, 0, sequence_table_len*sizeof(int));
1736        changed = 1;
1737    }
1738
1739    int above_percent;
1740    switch (gm->remap()->get_mode()) {
1741        default: e4_assert(0); FALLTHROUGH; // in NDEBUG
1742        case ED4_RM_NONE: {
1743        dont_map :
1744            for (i=0; i<sequence_table_len; i++) {
1745                set_sequence_to_screen(i, i);
1746            }
1747            screen_len = sequence_len;
1748            break;
1749        }
1750        case ED4_RM_SHOW_ABOVE: {
1751            above_percent = show_above_percent;
1752            goto calc_percent;
1753        }
1754        case ED4_RM_MAX_ALIGN:
1755        case ED4_RM_MAX_EDIT: {
1756            above_percent = 0;
1757        calc_percent :
1758            for (i=0, j=0; i<(sequence_table_len-1); i++) {
1759                int bases;
1760                int gaps;
1761
1762                table.bases_and_gaps_at(i, &bases, &gaps);
1763
1764                if (bases==0 && gaps==0) {  // special case (should occur only after inserting columns)
1765                    set_sequence_to_screen(i, -j); // hide
1766                }
1767                else {
1768                    int percent = (int)((bases*100L)/table.added_sequences());
1769
1770                    e4_assert(percent==((bases*100)/(bases+gaps)));
1771
1772                    if (bases && percent>=above_percent) {
1773                        set_sequence_to_screen(i, j++);
1774                    }
1775                    else {
1776                        set_sequence_to_screen(i, -j);
1777                    }
1778                }
1779            }
1780            for (; i<sequence_table_len; i++) { // fill rest of table
1781                set_sequence_to_screen(i, j++);
1782            }
1783            screen_len = j;
1784            break;
1785        }
1786        case ED4_RM_DYNAMIC_GAPS: {
1787            for (i=0, j=0; i<(sequence_table_len-1); i++) {
1788                int bases;
1789
1790                table.bases_and_gaps_at(i, &bases, NULp);
1791                if (bases) {
1792                    set_sequence_to_screen(i, j++);
1793                }
1794                else {
1795                    size_t k = i+1;
1796
1797                    while (k<(sequence_table_len-1)) {
1798                        int bases2;
1799
1800                        table.bases_and_gaps_at(k, &bases2, NULp);
1801                        if (bases2) {
1802                            break;
1803                        }
1804                        k++;
1805                    }
1806
1807                    int gaps = k-i;
1808                    int shown_gapsize;
1809
1810                    if (gaps<100) {
1811                        shown_gapsize = gaps/10 + 1;
1812                    }
1813                    else if (gaps<1000) {
1814                        shown_gapsize = gaps/100 + 10;
1815                    }
1816                    else {
1817                        shown_gapsize = gaps/1000 + 19;
1818                    }
1819
1820                    for (; i<k && shown_gapsize; i++, shown_gapsize--) {
1821                        set_sequence_to_screen(i, j++);
1822                    }
1823                    for (; i<k; i++) {
1824                        set_sequence_to_screen(i, -j);
1825                    }
1826                    i--;
1827                }
1828            }
1829            for (; i<sequence_table_len; i++) {
1830                set_sequence_to_screen(i, j++); // fill rest of table
1831            }
1832            screen_len = j;
1833            break;
1834        }
1835    }
1836
1837    if (sequence_table_len) {
1838        if (!screen_len && sequence_len) {
1839            goto dont_map;
1840        }
1841        if ((screen_len+1) > screen_table_len) {
1842            delete [] screen_to_sequence_tab;
1843            screen_to_sequence_tab = new int[screen_table_len = screen_len+1];
1844        }
1845        memset(screen_to_sequence_tab, 0, sizeof(int)*screen_table_len);
1846        for (i=0; i<sequence_table_len; i++) {
1847            int screen_pos = sequence_to_screen_tab[i];
1848            if (screen_pos>=0) {
1849                screen_to_sequence_tab[screen_pos] = i;
1850            }
1851        }
1852    }
1853
1854    if (sequence_len>1) {
1855        MAXSEQUENCECHARACTERLENGTH = sequence_len;
1856    }
1857
1858    return NULp;
1859}
1860
1861// --------------------------------
1862//      ED4_root_group_manager
1863
1864ED4_root_group_manager::ED4_root_group_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
1865    : ED4_abstract_group_manager(root_group_manager_spec, temp_id, width, height, temp_parent),
1866      my_remap()
1867{
1868    AW_root *awr = ED4_ROOT->aw_root;
1869    my_remap.set_mode((ED4_remap_mode)awr->awar(ED4_AWAR_COMPRESS_SEQUENCE_TYPE)->read_int(),
1870                      awr->awar(ED4_AWAR_COMPRESS_SEQUENCE_PERCENT)->read_int());
1871    my_remap.mark_compile_needed_force();
1872}
1873
1874bool ED4_root_group_manager::update_remap() {
1875    bool remapped = false;
1876
1877    if (my_remap.compile_needed()) {
1878        my_remap.compile(this);
1879        if (my_remap.was_changed()) remapped = true;
1880    }
1881
1882    return remapped;
1883}
1884
1885// -----------------------------------
1886//      ED4_multi_species_manager
1887
1888ED4_multi_sequence_manager::ED4_multi_sequence_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
1889    : ED4_manager(multi_sequence_manager_spec, temp_id, width, height, temp_parent)
1890{}
1891
1892ED4_sequence_manager::ED4_sequence_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
1893    : ED4_manager(sequence_manager_spec, temp_id, width, height, temp_parent)
1894{}
1895
1896ED4_multi_name_manager::ED4_multi_name_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
1897    : ED4_manager(multi_name_manager_spec, temp_id, width, height, temp_parent)
1898{}
1899
1900ED4_name_manager::ED4_name_manager(const char *temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
1901    : ED4_manager(name_manager_spec, temp_id, width, height, temp_parent)
1902{}
1903
1904
Note: See TracBrowser for help on using the repository browser.