source: branches/port5/EDIT4/ED4_members.cxx

Last change on this file was 5725, checked in by westram, 16 years ago
  • removed useless macros:
    • GB_STRDUP (easily taken for GB_strdup)
    • GB_MEMCPY + GB_MEMSET + GB_FREE
    • GB_DELETE (replaced by freeset(xx,NULL))
  • added macros:
    • freeset (= free + assign)
    • freedup (= free + assign strdup'ed)
    • reassign (= free + assign + clear source var)
    • nulldup (=strdup accepting NULL; replacement for GB_strdup in C++ code)
  • use these macros where applicable
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.5 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4// #include <malloc.h>
5
6#include <arbdb.h>
7#include <aw_root.hxx>
8#include <aw_window.hxx>
9
10#include "ed4_class.hxx"
11
12// --------------------
13//      ED4_members
14// --------------------
15
16ED4_returncode ED4_members::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    ED4_index   current_index = 0,
25        old_index,
26        rel_pos,                                                                // relativ position, i.e. on screen, to check
27        rel_size;
28    AW_pos              abs_pos_x = 0,
29        abs_pos_y = 0,
30        abs_pos;                                                                // relativ size of object, to check
31    ED4_base    *current_member;
32
33
34    current_member = member(0); // search list
35    if (! current_member) { // there's no list
36        return ( ED4_R_IMPOSSIBLE );
37    }
38
39    // case for the device_manager:
40    if (current_member->is_area_manager()) {
41        current_member->to_area_manager()
42            ->get_defined_level(ED4_L_MULTI_SPECIES)->to_multi_species_manager()
43            ->children->search_target_species(location, prop, found_member,return_level ); //there are always the three areas !!!
44
45        if (*found_member) {
46            return ED4_R_OK;
47        }
48    }
49
50    current_member->parent->calc_world_coords( & abs_pos_x, & abs_pos_y );
51
52    if ( prop & ED4_P_HORIZONTAL )                                                              // set extension-indexes rel_pos and rel_size according to properties
53    {
54        rel_pos = Y_POS;
55        rel_size = HEIGHT;
56        abs_pos = abs_pos_y;
57    }
58    else                                                                                        // i.e. prop & ED4_P_VERTICAL
59    {
60        rel_pos = X_POS;
61        rel_size = WIDTH;
62        abs_pos = abs_pos_x;
63    }
64
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        if (current_member->is_group_manager() &&
71            !current_member->flag.hidden &&
72            !current_member->flag.is_consensus) { // search_clicked_member for multi_species_manager in groups
73            current_member->to_group_manager()->children->search_target_species(location, prop, found_member,return_level);
74        }
75        else if ( !(current_member->flag.hidden)  &&
76                  (location->position[rel_pos] <= (current_member->extension.position[rel_pos] +
77                                                   abs_pos + current_member->extension.size[rel_size])))                        // found a suitable member
78        {
79            if (return_level & ED4_L_MULTI_SPECIES) { // search for drag target
80                if (current_member->is_multi_species_manager()) {
81                    *found_member = current_member;                                     // we have to give back the multi_species_manager for
82                    // insertion
83                    current_member->to_multi_species_manager()->children->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
86                    *found_member = current_member->get_parent( ED4_L_MULTI_SPECIES );                          // in a group we can move the
87                    if ((*found_member) && !((*found_member)->parent->is_area_manager())) {
88                        *found_member = (*found_member)->parent->get_parent( ED4_L_MULTI_SPECIES );
89                    }
90                }
91                else if (!(current_member->is_terminal()) || (current_member->is_spacer_terminal())) { // object behind the group
92                    *found_member = current_member->get_parent( ED4_L_MULTI_SPECIES );
93                }
94
95            }
96            else                                                                        // search for drag target line
97            {
98                if (current_member->is_multi_species_manager()) {
99                    current_member->to_multi_species_manager()->children->search_target_species(location, prop, found_member,return_level);
100                }
101                else if ((current_member->is_spacer_terminal()) && (current_index + 1 == no_of_members)) { // if we have found the last spacer
102                    *found_member = current_member->get_parent( ED4_L_MULTI_SPECIES ); // in a group we can move the
103                    if ((*found_member) && !((*found_member)->parent->is_area_manager())) {
104                        *found_member = (*found_member)->parent;
105                    }
106                }
107                else if ((current_member->is_species_manager()) ||
108                         ((current_member->is_spacer_terminal()) && current_member->parent->is_multi_species_manager())) { // we are a species manager
109                    *found_member = current_member;
110                }
111            }
112
113        }
114
115        current_index++;                                                                // no hit => search on
116        current_member = member(current_index);
117
118        if (current_member) { // handle folding groups
119            old_index = current_index;
120            while (current_member->flag.hidden && current_index!=no_of_members) {
121                current_index ++;
122                current_member = member(current_index);
123            }
124
125            if (current_index != old_index) {
126                if (     current_member &&
127                         !((location->position[rel_pos] >= (current_member->extension.position[rel_pos] + abs_pos)) &&
128                           (location->position[rel_pos] >= abs_pos && location->position[rel_pos] <= current_member->parent->extension.size[rel_size] + abs_pos)) &&
129                         (current_member->is_spacer_terminal()) && (current_index + 1 == no_of_members))
130                {
131                    if (return_level & ED4_L_MULTI_SPECIES)
132                        *found_member = current_member->get_parent( ED4_L_MULTI_SPECIES )->parent->get_parent( ED4_L_MULTI_SPECIES );
133                    else
134                        *found_member = current_member->get_parent( ED4_L_MULTI_SPECIES )->parent;
135                }
136            }
137        }
138
139        if (current_member) {
140            if (current_member->is_area_manager()) {
141                current_member->to_area_manager()
142                    ->get_defined_level(ED4_L_MULTI_SPECIES)->to_multi_species_manager()
143                    ->children->search_target_species( location, prop, found_member,return_level );     //there are always the three areas !!!
144
145                if (*found_member) {
146                    return ED4_R_OK;
147                }
148            }
149        }
150    }
151
152    return ED4_R_OK;
153}
154
155ED4_returncode ED4_members::insert_member( ED4_base *new_member )                       // inserts a new member into current owners's member array and
156{                                                                                       // asks to adjust owner's bounding box
157    ED4_index   index;
158    ED4_properties      prop;
159
160    prop = owner()->spec->static_prop;                                          //properties of parent object
161
162    if ( (index = search_member( &(new_member->extension), prop )) < 0 ) {      // search list for a suitable position
163        index = 0;                                                              // list was empty
164    }
165    else if ( index != no_of_members ) {                                        // we want to insert new member just behind found position
166        index++;                                                                // if index == no_of_members we reached the end of the list
167    }                                                                           // and index already has the right value
168
169    if (index > 0) { // ensure to insert before group_end_spacer
170        if (member(index-1)) {
171            if (member(index-1)->is_spacer_terminal() && !owner()->is_device_manager()) { // only in group_manager
172                if (index > 1) {
173                    index --;
174                }
175            }
176        }
177    }
178
179    if ( shift_list( index, 1 ) != ED4_R_OK ) {// insert new_member at index after shifting to the right
180        return ( ED4_R_WARNING );
181    }
182
183    memberList[index] = new_member; // insert new member in list in just allocated memory
184    no_of_members ++;
185    new_member->index = index;
186
187    owner()->resize_requested_by_child();                                       // tell owner about resize
188
189    return ( ED4_R_OK );
190}
191
192ED4_returncode ED4_members::append_member(ED4_base *new_member) {
193    ED4_index index = no_of_members;
194
195    if (index>=size_of_list) { // ensure free element
196        ED4_index new_size_of_list = (size_of_list*3)/2;        // resize to 1.5*size_of_list
197        ED4_base **new_member_list = (ED4_base**)GB_calloc(new_size_of_list, sizeof(*new_member_list));
198        if (!new_member_list) {
199            GB_memerr();
200            return ED4_R_IMPOSSIBLE;
201        }
202        memcpy(new_member_list, memberList, size_of_list*sizeof(*new_member_list));
203
204        freeset(memberList, new_member_list);
205        size_of_list = new_size_of_list;
206    }
207
208    if (index>0) { // ensure to insert before group_end_spacer
209        if (member(index-1)) {
210            if (member(index-1)->is_spacer_terminal() && !owner()->is_device_manager()) {
211                if (index>1) {
212                    index--;
213                }
214            }
215        }
216    }
217
218    if (shift_list(index, 1)!=ED4_R_OK) { // shift member if necessary
219        return ED4_R_WARNING;
220    }
221
222    memberList[index] = new_member;
223    no_of_members++;
224    new_member->index = index;
225
226    owner()->resize_requested_by_child();
227    return ED4_R_OK;
228}
229
230ED4_returncode ED4_members::delete_member(ED4_base *member_to_del)
231{
232    if (!member_to_del || (no_of_members <= 0)) {
233        return ( ED4_R_IMPOSSIBLE );
234    }
235
236    ED4_index index = member_to_del->index;
237
238    if ( shift_list( (index + 1), -1 ) != ED4_R_OK ) { //shift member list to left, starting at index+1
239        return ( ED4_R_WARNING );
240    }
241
242    member_to_del->parent = 0; // avoid referencing wrong parent
243
244    no_of_members--;
245    e4_assert(members_ok());
246
247    owner()->resize_requested_by_child(); // tell owner about resize
248
249    return ( ED4_R_OK );
250}
251
252ED4_returncode  ED4_members::shift_list( ED4_index start_index, int length )            // shifts member_list of current object by |length| positions starting with start_index,
253{                                                                                       // if length is positive shift is to the right, allocating new memory if necessary
254    // if length is negative shift is to the left (up to position 0) without freeing memory
255    ED4_index   i = 0;
256    ED4_base    **tmp_ptr;
257    unsigned int        new_alloc_size = 0;
258
259    if (length>0) { // shift list to the right
260        if ( (no_of_members + length) >= size_of_list ) { // member_list is full => allocate more memory
261            new_alloc_size = (unsigned int) ((size_of_list + length) * 1.3); // calculate new size of member_list for realloc()
262
263            tmp_ptr = memberList;
264            tmp_ptr = (ED4_base **) realloc((char *) memberList, (new_alloc_size * sizeof(ED4_base *))); // try to realloc memory
265
266            if (! tmp_ptr) { // realloc() failed => try malloc() and copy member_list
267                aw_message("ED4_members::shift_list: realloc problem!");
268                tmp_ptr = (ED4_base **) malloc( (new_alloc_size * sizeof(ED4_base *)) );
269
270                if (! tmp_ptr)                                                                  // malloc has failed, too
271                    return ( ED4_R_DESASTER );
272                else
273                    tmp_ptr = (ED4_base **) memcpy( (char *) tmp_ptr,                   // malloc was successfull, now copy memory
274                                                    (char *) memberList,
275                                                    (new_alloc_size * sizeof(ED4_base *)));
276            }
277            memberList = tmp_ptr;
278            size_of_list = new_alloc_size;
279            for ( i = no_of_members; i < size_of_list; i++ )                            // clear free entries at the end of the list
280                memberList[i] = NULL;
281        }
282
283        for ( i = (no_of_members + length); i > start_index; i-- )                              // start shifting to the right
284        {
285            memberList[i] = memberList[i - length];
286            if ( memberList[i] != NULL )
287                (memberList[i])->index = i;
288        }
289    }
290    else if ( length<0 )                                                                                // shift list to the left, thereby not freeing any memory !
291    {
292        if ( (start_index + length) < 0 )
293        {
294            aw_message("ED4_members::shift_list: shift is too far to the left!");
295            return ( ED4_R_WARNING );
296        }
297
298        for ( i = (start_index + length); i <= (no_of_members + length); i++ )                  //start shifting left
299        {
300            memberList[i] = memberList[i - length];                                     // length is negative
301            if ( memberList[i] != NULL )
302                (memberList[i])->index = i;
303        }
304    }
305
306    return ( ED4_R_OK );
307}
308
309
310ED4_returncode ED4_members::move_member(ED4_index old_pos, ED4_index new_pos) {
311    if (old_pos>=0 && old_pos<no_of_members && new_pos>=0 && new_pos<no_of_members) {
312        if (new_pos!=old_pos) {
313            ED4_base *moved_member = memberList[old_pos];
314
315            shift_list(old_pos+1, -1);
316            shift_list(new_pos, 1);
317
318            memberList[new_pos] = moved_member;
319            moved_member->index = new_pos;
320
321            e4_assert(members_ok());
322        }
323        return ED4_R_OK;
324    }
325
326    return ED4_R_IMPOSSIBLE;
327}
328
329ED4_index ED4_members::search_member( ED4_extension *location, ED4_properties prop)
330// searches member_list of current object for a member who's extension falls within the given location
331// thereby considering orientation given by prop (only pos[] is relevant)
332// list has to be ordered in either x- or y- direction, ( binary search algorithm later )
333// returns index of found member, -1 if list is empty or no_of_members if search reached end of list
334{
335    ED4_index   current_index = 0,
336        rel_pos,
337        rel_size;
338
339    ED4_base *current_member;
340
341    if ( prop & ED4_P_HORIZONTAL ) { // set extension-indexes rel_pos and rel_size according to properties
342        rel_pos = Y_POS; rel_size = HEIGHT;
343    }
344    else { // i.e. prop & ED4_P_VERTICAL
345        rel_pos = X_POS; rel_size = WIDTH;
346    }
347
348    current_member = memberList[0]; // search list
349    if (! current_member) { // there's no list
350        return ( -1 );
351    }
352
353    current_index = 0;
354    while (current_member) { // just as long as possibility exists, to find the object
355        if ( location->position[rel_pos] <= (current_member->extension.position[rel_pos] + current_member->extension.size[rel_size])) { // found a suitable member
356            return ( current_index );
357        }
358        current_index++; // no hit => search on
359        current_member = memberList[current_index];
360    }
361
362    return ( no_of_members );                                                         // reached this position => no hit, return no_of_members
363}
364
365#ifdef ASSERTION_USED
366int ED4_members::members_ok() const {
367    int m;
368    int error = 0;
369
370    for (m=0; m<no_of_members; m++) {
371        ED4_base *base = memberList[m];
372
373        if (base->index!=m) {
374            printf("Member %i has illegal index %li\n", m, base->index);
375            error = 1;
376        }
377    }
378
379    return !error;
380}
381#endif // ASSERTION_USED
382
383ED4_members::ED4_members(ED4_manager *the_owner)
384{
385    my_owner = the_owner;
386    memberList = (ED4_base **) calloc(1, sizeof(ED4_base*));
387
388    if ( memberList == NULL ) {
389        aw_popup_exit("ED4_member::ED4_member: memory problem!");
390    }
391
392    memberList[0] = NULL;
393    no_of_members = 0;
394    size_of_list = 1;
395}
396
397
398ED4_members::~ED4_members()
399{
400    if (memberList) {
401        free( (char *) memberList );
402    }
403}
404
Note: See TracBrowser for help on using the repository browser.