source: tags/ms_r17q1/EDIT4/ED4_container.cxx

Last change on this file was 15223, checked in by westram, 8 years ago
  • reintegrates 'flags' into 'trunk'
    • DRYed
      • group generation code
      • ref-terminal access
    • layout done by managers (removed manual coordinate calculation)
    • dynamic size calculated by terminals themselves
    • fix design issues
      • brackets were used where groups should have been used. fixed
      • fix many bad/spammy names
    • fix broken member-code (only worked with a NULL sentinel present)
    • dynamic indentation (according to visible group-nesting)
  • adds: log:branches/flags@15098:15222
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.5 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ED4_container.cxx                                 //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include <arbdb.h>
12#include "ed4_class.hxx"
13#include <aw_msg.hxx>
14#include <aw_question.hxx>
15
16ED4_returncode ED4_container::search_target_species(ED4_extension *location, ED4_properties prop, ED4_base **found_member, ED4_level return_level)
17{
18    // who's extension falls within the given
19    // location thereby considering orientation given by
20    // prop (only pos[] is relevant) list has to be
21    // ordered in either x- or y- direction, ( binary
22    // search algorithm later ) returns index of found member,
23    // -1 if list is empty or no_of_members if search reached end of list
24
25
26    if (!members()) { // there's no list
27        return ED4_R_IMPOSSIBLE;
28    }
29
30    ED4_base *current_member = member(0);
31    // case for the device_manager:
32    if (current_member->is_area_manager()) {
33        current_member->to_area_manager()
34            ->get_multi_species_manager()
35            ->search_target_species(location, prop, found_member, return_level); // there are always the three areas !!!
36
37        if (*found_member) {
38            return ED4_R_OK;
39        }
40    }
41
42    ED4_index rel_pos; // relative position, i.e. on screen, to check
43    ED4_index rel_size;
44    AW_pos    abs_pos; // relative size of object, to check
45
46    {
47        AW_pos abs_pos_x = 0;
48        AW_pos abs_pos_y = 0;
49        current_member->parent->calc_world_coords(&abs_pos_x, &abs_pos_y);
50
51        // set extension-indexes rel_pos, rel_size and abs_pos according to properties:
52        if (prop & PROP_HORIZONTAL) {
53            rel_pos = Y_POS;
54            rel_size = HEIGHT;
55            abs_pos = abs_pos_y;
56        }
57        else { // i.e. prop & PROP_VERTICAL
58            rel_pos = X_POS;
59            rel_size = WIDTH;
60            abs_pos = abs_pos_x;
61        }
62    }
63
64    ED4_index current_index = 0;
65
66    while (current_member                                                                           &&
67           (location->position[rel_pos] >= (current_member->extension.position[rel_pos] + abs_pos)) && // just as long as possibility exists, to find the object
68           (location->position[rel_pos] >= abs_pos && location->position[rel_pos] <= current_member->parent->extension.size[rel_size] + abs_pos))
69    {
70        e4_assert(!current_member->is_root_group_manager());
71        if (current_member->is_group_manager() &&
72            !current_member->flag.hidden &&
73            !current_member->is_consensus_manager()) { // search_clicked_member for multi_species_manager in groups
74            current_member->to_group_manager()->search_target_species(location, prop, found_member, return_level);
75        }
76        else if (!(current_member->flag.hidden)   &&
77                  (location->position[rel_pos] <= (current_member->extension.position[rel_pos] +
78                                                   abs_pos + current_member->extension.size[rel_size]))) // found a suitable member
79        {
80            if (return_level & LEV_MULTI_SPECIES) { // search for drag target
81                if (current_member->is_multi_species_manager()) {
82                    *found_member = current_member; // we have to return the multi_species_manager for insertion
83                    current_member->to_multi_species_manager()->search_target_species(location, prop, found_member, return_level);
84                }
85                else if ((current_member->is_spacer_terminal()) && (current_index + 1 == no_of_members)) { // if we have found the last spacer in a group
86                    // -> we can move the object behind the group
87                    *found_member = current_member->get_parent(LEV_MULTI_SPECIES);
88                    if ((*found_member) && !((*found_member)->parent->is_area_manager())) {
89                        *found_member = (*found_member)->parent->get_parent(LEV_MULTI_SPECIES);
90                    }
91                }
92                else if (!(current_member->is_terminal()) || (current_member->is_spacer_terminal())) {
93                    *found_member = current_member->get_parent(LEV_MULTI_SPECIES);
94                }
95
96            }
97            else                                                                        // search for drag target line
98            {
99                if (current_member->is_multi_species_manager()) {
100                    current_member->to_multi_species_manager()->search_target_species(location, prop, found_member, return_level);
101                }
102                else if ((current_member->is_spacer_terminal()) && (current_index + 1 == no_of_members)) { // if we have found the last spacer
103                    *found_member = current_member->get_parent(LEV_MULTI_SPECIES);   // in a group we can move the
104                    if ((*found_member) && !((*found_member)->parent->is_area_manager())) {
105                        *found_member = (*found_member)->parent;
106                    }
107                }
108                else if ((current_member->is_species_manager()) ||
109                         ((current_member->is_spacer_terminal()) && current_member->parent->is_multi_species_manager())) { // we are a species manager
110                    *found_member = current_member;
111                }
112            }
113
114        }
115
116        current_index++; // no hit => continue search
117        current_member = existing_index(current_index) ? member(current_index) : NULL;
118
119        if (current_member) { // handle folding groups
120            ED4_index old_index = current_index;
121            while (current_member && current_member->flag.hidden && current_index!=no_of_members) {
122                current_index++;
123                current_member = existing_index(current_index) ? member(current_index) : NULL;
124            }
125
126            if (current_index != old_index) {
127                if (current_member &&
128                    !((location->position[rel_pos] >= (current_member->extension.position[rel_pos] + abs_pos)) &&
129                      (location->position[rel_pos] >= abs_pos && location->position[rel_pos] <= current_member->parent->extension.size[rel_size] + abs_pos)) &&
130                    (current_member->is_spacer_terminal()) && (current_index + 1 == no_of_members))
131                {
132                    if (return_level & LEV_MULTI_SPECIES)
133                        *found_member = current_member->get_parent(LEV_MULTI_SPECIES)->parent->get_parent(LEV_MULTI_SPECIES);
134                    else
135                        *found_member = current_member->get_parent(LEV_MULTI_SPECIES)->parent;
136                }
137            }
138        }
139
140        if (current_member) {
141            if (current_member->is_area_manager()) {
142                current_member->to_area_manager()
143                    ->get_multi_species_manager()
144                    ->search_target_species(location, prop, found_member, return_level);      // there are always the three areas !!!
145
146                if (*found_member) {
147                    return ED4_R_OK;
148                }
149            }
150        }
151    }
152
153    return ED4_R_OK;
154}
155
156void ED4_container::correct_insert_position(ED4_index& index) {
157    // ensure to insert before group_end_spacer
158
159    if (index>1                               && // avoid underflow
160        existing_index(index-1)               &&
161        member(index-1)->is_spacer_terminal() &&
162        !owner()->is_device_manager())           // only in group_manager
163    {
164        index--;
165    }
166}
167
168void ED4_container::resize(ED4_index needed_size) {
169    if (needed_size>size_of_list) {
170        e4_assert(needed_size>0);
171        ED4_index new_size = (needed_size*3)/2+2;
172        ARB_recalloc(memberList, size_of_list, new_size);
173        size_of_list = new_size;
174    }
175}
176
177void ED4_container::insert_member(ED4_base *new_member) {
178    // inserts a new member into current owners's member array and
179    // asks to adjust owner's bounding box
180
181    ED4_properties prop = owner()->spec.static_prop; // properties of parent object
182
183    ED4_index index;
184    if ((index = search_member(&(new_member->extension), prop)) < 0) { // search list for a suitable position
185        index = 0;                                                     // list was empty
186    }
187    else if (index != no_of_members) {                                 // we want to insert new member just behind found position
188        index++;                                                       // if index == no_of_members we reached the end of the list
189    }                                                                  // and index already has the right value
190
191    correct_insert_position(index); // insert before end-spacer
192    shift_list(index, 1);           // shift members if necessary
193
194    e4_assert(index<size_of_list);
195    memberList[index] = new_member;
196    no_of_members ++;
197    new_member->index = index;
198
199    owner()->request_resize(); // tell owner about resize
200}
201
202void ED4_container::append_member(ED4_base *new_member) {
203    ED4_index index = no_of_members;
204
205    e4_assert(owner()->spec.allowed_to_contain(new_member->spec.level));
206
207    correct_insert_position(index); // insert before end-spacer
208    shift_list(index, 1);           // shift members if necessary
209
210    e4_assert(index<size_of_list);
211    memberList[index] = new_member;
212    no_of_members++;
213    new_member->index = index;
214
215    owner()->spec.announce_added(new_member->spec.level);
216    owner()->request_resize();
217}
218
219ED4_returncode ED4_container::remove_member(ED4_base *member_to_del) {
220    if (!member_to_del || (no_of_members <= 0)) {
221        return ED4_R_IMPOSSIBLE;
222    }
223
224    ED4_index index = member_to_del->index;
225    e4_assert(member_to_del->parent == this);
226
227    shift_list(index+1, -1); // shift member list to left, starting at index+1
228
229    member_to_del->parent = 0; // avoid referencing wrong parent
230    no_of_members--;
231    e4_assert(members_ok());
232
233    owner()->request_resize();
234
235    return ED4_R_OK;
236}
237
238void ED4_container::shift_list(ED4_index start_index, int length) {
239    // shifts member_list of current object by |length| positions starting with start_index,
240    // if length is positive => shift to the right; allocates new memory if necessary
241    // if length is negative => shift to the left (down to position 0); does not resize allocated memory
242
243    e4_assert(length != 0);
244
245    if (length>0) { // shift list to the right
246        long needed_size = no_of_members + length;
247
248        e4_assert(start_index<needed_size);
249        resize(needed_size);
250
251        for (ED4_index n = needed_size-1; n > start_index; n--) { // start shifting to the right
252            ED4_index o = n-length;
253
254            e4_assert(valid_index(n));
255            e4_assert(valid_index(o));
256
257            memberList[n] = memberList[o];
258            if (memberList[n]) {
259                memberList[n]->index = n;
260            }
261            memberList[o] = NULL;
262        }
263    }
264    else if (length<0) { // shift list to the left, thereby not freeing any memory !
265        e4_assert((start_index + length) >= 0); // invalid shift!
266
267        for (ED4_index n = start_index + length; n < (no_of_members + length); n++) { // start shifting left
268            ED4_index o = n-length; // Note: length is negative!
269
270            e4_assert(valid_index(n));
271            e4_assert(valid_index(o));
272
273            memberList[n] = memberList[o];
274            if (memberList[n]) {
275                memberList[n]->index = n;
276            }
277            memberList[o] = NULL;
278        }
279    }
280}
281
282
283ED4_returncode ED4_container::move_member(ED4_index old_pos, ED4_index new_pos) {
284    if (old_pos>=0 && old_pos<no_of_members && new_pos>=0 && new_pos<no_of_members) {
285        if (new_pos!=old_pos) {
286            ED4_base *moved_member = memberList[old_pos];
287
288            shift_list(old_pos+1, -1);
289            shift_list(new_pos, 1);
290
291            memberList[new_pos] = moved_member;
292            moved_member->index = new_pos;
293
294            e4_assert(members_ok());
295        }
296        return ED4_R_OK;
297    }
298
299    return ED4_R_IMPOSSIBLE;
300}
301
302ED4_index ED4_container::search_member(ED4_extension *location, ED4_properties prop)
303// searches member_list of current object for a member who's extension falls within the given location
304// thereby considering orientation given by prop (only pos[] is relevant)
305// list has to be ordered in either x- or y- direction, ( binary search algorithm later )
306// returns index of found member, -1 if list is empty or no_of_members if search reached end of list
307{
308    ED4_index   current_index = 0,
309        rel_pos,
310        rel_size;
311
312    ED4_base *current_member;
313
314    if (prop & PROP_HORIZONTAL) {   // set extension-indexes rel_pos and rel_size according to properties
315        rel_pos = Y_POS; rel_size = HEIGHT;
316    }
317    else { // i.e. prop & PROP_VERTICAL
318        rel_pos = X_POS; rel_size = WIDTH;
319    }
320
321    current_member = memberList[0]; // search list
322    if (! current_member) { // there's no list
323        return (-1);
324    }
325
326    current_index = 0;
327    while (current_member) { // just as long as possibility exists, to find the object
328        if (location->position[rel_pos] <= (current_member->extension.position[rel_pos] + current_member->extension.size[rel_size])) {  // found a suitable member
329            return (current_index);
330        }
331        current_index++; // no hit => search on
332        current_member = memberList[current_index];
333    }
334
335    return (no_of_members);                                                           // reached this position => no hit, return no_of_members
336}
337
338#ifdef ASSERTION_USED
339bool ED4_container::members_ok() const {
340    bool error = false;
341    for (int m=0; m<no_of_members; m++) {
342        ED4_base *base = memberList[m];
343
344        if (base->index!=m) {
345            printf("Member %i has illegal index %li\n", m, base->index);
346            error = true;
347        }
348    }
349
350    return !error;
351}
352#endif // ASSERTION_USED
353
354ED4_container::ED4_container() :
355    no_of_members(0),
356    size_of_list(1)
357{
358    ARB_calloc(memberList, size_of_list);
359}
360
361
362void ED4_container::clear() {
363    while (members()) {
364        ED4_index  last  = members()-1;
365        ED4_base  *child = member(last);
366
367        remove_member(child);
368        child->parent = NULL;
369        delete child;
370    }
371}
372
373ED4_container::~ED4_container() {
374    e4_assert(empty());
375    free(memberList);
376}
377
Note: See TracBrowser for help on using the repository browser.