source: branches/stable/SL/TREEDISP/irstree_display.cxx

Last change on this file was 18641, checked in by westram, 3 years ago
  • fixes #824
    • define stacksize required for tree-display in TreeDisplay.hxx (currently 20Mb)
    • use that stacksize NTREE and PARSIMONY.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : irstree_display.cxx                               //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "TreeDisplay.hxx"
12#include <AP_TreeColors.hxx>
13
14#include <nds.h>
15
16using namespace AW;
17
18// *********************** paint sub tree ************************
19
20const int TIP_BOX_SIZE = 3;
21
22struct IRS_data {
23    bool   draw_separator;
24    AW_pos y;
25    AW_pos min_y;    // ypos of folding line
26    AW_pos max_y;
27    AW_pos step_y;
28    AW_pos halfstep_y;
29    AW_pos onePixel;
30    AW_pos fold_x1, fold_x2;
31
32    int    group_closed;
33    double x_scale;
34
35    Vector adjust_text;
36    AW_pos tree_depth;
37
38    AW_pos gap; // between group frame and (box or text)
39    AW_pos openGroupExtra; // extra y-size of unfolded groups
40
41    AW_bitset sep_filter;
42
43    bool is_size_device;
44
45    void draw_top_separator_once(AW_device *device) {
46        if (draw_separator) {
47            if (!is_size_device) {
48                device->set_line_attributes(AWT_GC_IRS_GROUP_BOX, 4, AW_SOLID);
49                device->line(AWT_GC_IRS_GROUP_BOX, fold_x1, min_y, fold_x2, min_y, sep_filter);
50            }
51            draw_separator = false;
52        }
53    }
54
55
56};
57static IRS_data IRS;
58
59inline AW_pos Y_correction_for_IRS() {
60    if (IRS.is_size_device) {
61        // hack to fix calculated cursor position:
62        // - IRS tree reports different cursor positions in AW_SIZE and normal draw modes.
63        // - the main reason for the difference is the number of open groups clipped away
64        //   above the separator line.
65        // - There is still some unhandled difference mostlikely caused by the number of
66        //   open groups on the screen, but in most cases the cursor position is inside view now.
67
68        double correctionPerGroup = IRS.openGroupExtra; // depends on size of marked-species-font
69        double cursorCorrection   = -IRS.group_closed * correctionPerGroup;
70        return cursorCorrection;
71    }
72    return 0.0;
73}
74
75AW_pos AWT_graphic_tree::paint_irs_sub_tree(AP_tree *node, AW_pos x_offset) {
76    if (!IRS.is_size_device) {
77        // check clipping rectangle
78        if (IRS.y > IRS.max_y) {
79            return IRS.max_y;
80        }
81        AW_pos height_of_subtree = IRS.step_y*node->gr.view_sum;
82        if (IRS.y + height_of_subtree < IRS.min_y) {
83            IRS.y += height_of_subtree;
84            return IRS.min_y;
85        }
86    }
87
88    if (node->is_leaf()) {
89        IRS.y+=IRS.step_y;
90        IRS.draw_top_separator_once(disp_device);
91
92        Position leaf(x_offset, IRS.y);
93
94        if (node->hasName(species_name)) {
95            Position cursor(leaf);
96            cursor.movey(Y_correction_for_IRS());
97            selSpec = PaintedNode(cursor, node);
98        }
99
100        AW_click_cd cd(disp_device, (AW_CL)node, CL_NODE);
101
102        int gc = node->gr.gc;
103        if (node->gb_node && GB_read_flag(node->gb_node)) {
104            set_line_attributes_for(node);
105            filled_box(gc, leaf, NT_BOX_WIDTH);
106        }
107
108        Position    textpos  = leaf+IRS.adjust_text;
109        const char *specinfo = make_node_text_nds(gb_main, node->gb_node, NDS_OUTPUT_LEAFTEXT, node, tree_static->get_tree_name());
110        disp_device->text(gc, specinfo, textpos);
111
112        return IRS.y;
113    }
114
115    AW_pos frame_width = NAN;
116    AW_pos group_y1    = NAN;
117
118    bool      is_group    = node->is_clade();
119    bool      is_selected = is_group && selected_group.at_node(node);
120    const int group_gc    = is_selected ? int(AWT_GC_CURSOR) : node->gr.gc;
121
122    if (is_selected) {
123        Position group(x_offset, IRS.y);
124        group.movey(Y_correction_for_IRS());
125        selGroup = PaintedNode(group, node);
126    }
127
128    if (is_group) {
129        frame_width = node->gr.max_tree_depth * IRS.x_scale;
130
131        if (node->is_folded_group()) {
132            AW_pos y_center;
133
134            AW_pos frame_height = node->gr.view_sum * IRS.step_y;
135            AW_pos frame_y1     = IRS.y+IRS.halfstep_y+IRS.gap;
136            AW_pos frame_y2     = frame_y1 + frame_height;
137
138            if (frame_y2 >= IRS.min_y) {
139                if (frame_y1 < IRS.min_y) { // shift folded groups into the folding area (disappears when completely inside)
140                    frame_y1  = IRS.min_y;
141                    IRS.min_y += IRS.halfstep_y+IRS.gap;
142                }
143
144                AW_pos    visible_frame_height = frame_y2-frame_y1;
145                Rectangle frame(Position(x_offset, frame_y1), Vector(frame_width, visible_frame_height));
146
147                // draw group frame (unclosed on right hand):
148                AW_click_cd cd(disp_device, (AW_CL)node, CL_NODE);
149
150                {
151                    const int gc = is_selected ? AWT_GC_CURSOR : AWT_GC_IRS_GROUP_BOX;
152                    disp_device->set_line_attributes(gc, 1, AW_SOLID);
153                    disp_device->line(gc, frame.upper_edge());
154                    disp_device->line(gc, frame.left_edge());
155                    disp_device->line(gc, frame.lower_edge());
156                }
157
158                const int gc = node->gr.gc;
159                set_line_attributes_for(node);
160                filled_box(group_gc, frame.upper_left_corner(), TIP_BOX_SIZE);
161
162                Vector    frame2box(IRS.gap, IRS.gap);
163                Rectangle gbox(frame.upper_left_corner()+frame2box, Vector(frame.width()*.5, frame.height()-2*IRS.gap));
164
165                disp_device->set_grey_level(gc, group_greylevel);
166                disp_device->box(gc, AW::FillStyle::SHADED_WITH_BORDER, gbox);
167
168                Position box_rcenter = gbox.right_edge().centroid();
169
170                const GroupInfo& info = get_group_info(node, group_info_pos == GIP_SEPARATED ? GI_SEPARATED : GI_COMBINED, group_info_pos == GIP_OVERLAYED);
171                if (info.name) { //  a node name should be displayed
172                    disp_device->text(group_gc, SizedCstr(info.name, info.name_len), box_rcenter+IRS.adjust_text);
173                }
174                if (info.count) {
175                    Position box_lcenter = gbox.left_edge().centroid();
176                    disp_device->text(group_gc, SizedCstr(info.count, info.count_len), box_lcenter+IRS.adjust_text);
177                }
178
179                IRS.draw_top_separator_once(disp_device);
180
181                IRS.y    += frame_height + 2*IRS.gap;
182                y_center  = box_rcenter.ypos();
183            }
184            else {
185                IRS.y    += frame_height + 2*IRS.gap;
186                y_center  = IRS.min_y;
187
188                if (IRS.y > IRS.min_y) {
189                    IRS.y = IRS.min_y;
190                }
191            }
192            return y_center;
193        }
194
195        // -----------------------------------
196        //      otherwise: unfolded group
197
198        group_y1 = IRS.y;
199        if (group_y1 >= IRS.min_y) {
200            IRS.draw_top_separator_once(disp_device);
201            group_y1 = IRS.y + IRS.halfstep_y+IRS.gap;
202        }
203        else {
204            group_y1   = IRS.min_y;
205            IRS.min_y += IRS.openGroupExtra;
206        }
207        IRS.y += IRS.openGroupExtra;
208
209        const int   gc = is_selected ? AWT_GC_CURSOR : AWT_GC_IRS_GROUP_BOX;
210        AW_click_cd cd(disp_device, (AW_CL)node, CL_NODE);
211        disp_device->set_line_attributes(gc, 1, AW_DOTTED);
212        disp_device->line(gc, x_offset-IRS.onePixel, group_y1, x_offset+frame_width, group_y1); // opened-group-frame
213
214        const GroupInfo& info = get_group_info(node, GI_COMBINED);
215
216        td_assert(info.name); // if fails -> maybe skip whole headerline
217        disp_device->text(group_gc,
218                          SizedCstr(info.name, info.name_len),
219                          x_offset-IRS.onePixel + IRS.gap,
220                          group_y1 + 2*IRS.adjust_text.y() + IRS.gap);
221    }
222
223    // draw subtrees
224    AW_pos left_x = x_offset + IRS.x_scale * node->leftlen;
225    AW_pos left_y = paint_irs_sub_tree(node->get_leftson(), left_x);
226
227    AW_pos right_x = x_offset + IRS.x_scale * node->rightlen;
228    AW_pos right_y = paint_irs_sub_tree(node->get_rightson(), right_x);
229
230    if (is_group) IRS.group_closed++; // @@@ only done for unfolded groups. bug?
231
232    // draw structure
233    if (left_y > IRS.min_y) {
234        if (left_y < IRS.max_y) { // clip y on top border
235            AP_tree     *son = node->get_leftson();
236            AW_click_cd  cd(disp_device, (AW_CL)son, CL_NODE);
237            Position     left(left_x, left_y);
238
239            set_line_attributes_for(son);
240            draw_branch_line(son->gr.gc, Position(x_offset, left_y), left, line_filter);
241
242            if (bconf.shall_show_remark_for(son)) {
243                if (!son->is_son_of_root()) { // bootstrap of root-edge is displayed below (at right son)
244                    bconf.display_node_remark(disp_device, son, left, IRS.x_scale * node->leftlen, scaled_branch_distance, D_NORTH_WEST);
245                }
246            }
247        }
248    }
249    else {
250        left_y = IRS.min_y;
251    }
252
253    AW_pos y_center = (left_y + right_y)*0.5;
254
255    if (right_y > IRS.min_y && right_y < IRS.max_y) { // visible right branch in lower part of display
256        AP_tree     *son = node->get_rightson();
257        AW_click_cd  cd(disp_device, (AW_CL)son, CL_NODE);
258        Position     right(right_x, right_y);
259
260        set_line_attributes_for(son);
261        draw_branch_line(son->gr.gc, Position(x_offset, right_y), right, line_filter);
262
263        if (bconf.shall_show_remark_for(son)) {
264            if (son->is_son_of_root()) {
265                AW_click_cd cdr(disp_device, 0, CL_ROOTNODE);
266                bconf.display_node_remark(disp_device, son, Position(x_offset, y_center), IRS.x_scale * (node->rightlen+node->leftlen), scaled_branch_distance, D_EAST);
267            }
268            else {
269                bconf.display_node_remark(disp_device, son, right, IRS.x_scale * node->rightlen, scaled_branch_distance, D_SOUTH_WEST);
270            }
271        }
272    }
273
274    AW_click_cd cd(disp_device, (AW_CL)node, CL_NODE);
275    set_line_attributes_for(node->get_leftson());
276    disp_device->line(node->get_leftson()->gr.gc, x_offset, y_center, x_offset, left_y);
277
278    set_line_attributes_for(node->get_rightson());
279    disp_device->line(node->get_rightson()->gr.gc, x_offset, y_center, x_offset, right_y);
280
281    if (node->is_normal_group()) { // close unfolded group brackets and draw tipbox
282        IRS.+= IRS.halfstep_y+IRS.gap;
283
284        {
285            const int gc = is_selected ? AWT_GC_CURSOR : AWT_GC_IRS_GROUP_BOX;
286            disp_device->set_line_attributes(gc, 1, AW_DOTTED);
287            disp_device->line(gc, x_offset-IRS.onePixel, IRS.y, x_offset+frame_width, IRS.y); // opened-group-frame
288            disp_device->line(gc, x_offset-IRS.onePixel, group_y1, x_offset-IRS.onePixel,  IRS.y); // opened-group-frame
289        }
290
291        const int gc = group_gc;
292        set_line_attributes_for(node);
293        filled_box(gc, Position(x_offset-IRS.onePixel, group_y1), TIP_BOX_SIZE);
294    }
295    return y_center;
296}
297
298void AWT_graphic_tree::show_irs_tree(AP_tree *at, double height) {
299
300    IRS.draw_separator = true;
301    IRS.y              = 0;
302    IRS.step_y         = height;
303    IRS.halfstep_y     = IRS.step_y*0.5;
304    IRS.x_scale        = 200.0;      // @@@ should not have any effect, since display gets x-scaled. But if it's to low (e.g. 1.0) scaling on zoom-reset does not work
305
306    const AW_font_limits& limits = disp_device->get_font_limits(AWT_GC_ALL_MARKED, 0);
307
308    IRS.adjust_text    = disp_device->rtransform(Vector(NT_BOX_WIDTH, limits.ascent*0.5));
309    IRS.onePixel       = disp_device->rtransform_size(1.0);
310    IRS.gap            = 3*IRS.onePixel;
311    IRS.group_closed   = 0;
312    IRS.tree_depth     = at->gr.max_tree_depth;
313    IRS.openGroupExtra = IRS.step_y+IRS.gap;
314    IRS.sep_filter     = AW_SCREEN|AW_PRINTER_CLIP;
315
316    IRS.is_size_device = disp_device->type() == AW_DEVICE_SIZE;
317
318    Position  corner = disp_device->rtransform(Origin);   // real world coordinates of left/upper screen corner
319    Rectangle rclip  = disp_device->get_rtransformed_cliprect();
320
321    // the following values currently contain nonsense for size device @@@
322    IRS.min_y   = corner.ypos();
323    IRS.max_y   = rclip.bottom();
324    IRS.fold_x1 = rclip.left();
325    IRS.fold_x2 = rclip.right();
326
327    list_tree_ruler_y           = paint_irs_sub_tree(at, 0);
328    irs_tree_ruler_scale_factor = IRS.x_scale;
329
330    disp_device->invisible(corner); // @@@ remove when size-dev works
331}
Note: See TracBrowser for help on using the repository browser.