source: branches/ali/SL/TREEDISP/TreeDisplay.hxx

Last change on this file was 19271, checked in by westram, 2 years ago
  • fix #824
    • limit display recursion depth (to approx. MAX_TREEDISP_RECURSION_DEPTH)
    • when reached:
      • truncate branch
      • display warning in tree (like a leaf).
    • applied to all 3 tree display modes (dendro, irs + radial)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.8 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : TreeDisplay.hxx                                   //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#ifndef TREEDISPLAY_HXX
12#define TREEDISPLAY_HXX
13
14#ifndef AP_TREE_HXX
15#include <AP_Tree.hxx>
16#endif
17#ifndef GROUP_HXX
18#include <Group.hxx>
19#endif
20#ifndef AWT_CANVAS_HXX
21#include <awt_canvas.hxx>
22#endif
23#ifndef _GLIBCXX_VECTOR
24#include <vector>
25#endif
26#ifndef _GLIBCXX_MAP
27#include <map>
28#endif
29
30// Increase stacklimit to 20Mb (before was ~8Mb on my system).
31// This was done to fix #824 (crash on display of huge trees).
32#define TREEDISP_STACKSIZE (1024L*1024L*20) // stacksize required for tree-display
33
34// the possible MAX_TREEDISP_RECURSION_DEPTH corresponds with the TREEDISP_STACKSIZE:
35#define MAX_TREEDISP_RECURSION_DEPTH 20000
36#define TREEDISP_TRUNCATION_MESSAGE "Warning: depth limit reached => subtree not shown (use logical zoom to workaround)"
37
38
39#define td_assert(cond) arb_assert(cond)
40
41#define AWAR_DTREE_BASELINEWIDTH   "awt/dtree/baselinewidth"
42#define AWAR_DTREE_VERICAL_DIST    "awt/dtree/verticaldist"
43#define AWAR_DTREE_BRANCH_STYLE    "awt/dtree/branch_style"
44#define AWAR_DTREE_ATTACH_SIZE     "awt/dtree/attach_size"
45#define AWAR_DTREE_ATTACH_LEN      "awt/dtree/attach_len"
46#define AWAR_DTREE_ATTACH_GROUP    "awt/dtree/attach_group"
47#define AWAR_DTREE_GROUP_DOWNSCALE "awt/dtree/downscaling"
48#define AWAR_DTREE_GROUP_SCALE     "awt/dtree/groupscaling"
49#define AWAR_DTREE_AUTO_JUMP       "awt/dtree/autojump"
50#define AWAR_DTREE_AUTO_JUMP_TREE  "awt/dtree/autojump_tree"
51#define AWAR_DTREE_AUTO_UNFOLD     "awt/dtree/auto_unfold"
52#define AWAR_DTREE_SHOW_BRACKETS   "awt/dtree/show_brackets"
53#define AWAR_DTREE_GROUP_STYLE     "awt/dtree/groupstyle"
54#define AWAR_DTREE_GROUP_ORIENT    "awt/dtree/grouporient"
55#define AWAR_DTREE_GREY_LEVEL      "awt/dtree/greylevel"
56#define AWAR_DTREE_GROUPCOUNTMODE  "awt/dtree/groupcountmode"
57#define AWAR_DTREE_GROUPINFOPOS    "awt/dtree/groupinfopos"
58
59#define AWAR_DTREE_BOOTSTRAP_MIN   "awt/dtree/bootstrap/min"
60#define AWAR_DTREE_BOOTSTRAP_MAX   "awt/dtree/bootstrap/max"
61#define AWAR_DTREE_BOOTSTRAP_SHOW  "awt/dtree/bootstrap/show"
62#define AWAR_DTREE_BOOTSTRAP_STYLE "awt/dtree/bootstrap/style"
63#define AWAR_DTREE_CIRCLE_SHOW     "awt/dtree/bootstrap/circle/show"
64#define AWAR_DTREE_CIRCLE_FILL     "awt/dtree/bootstrap/circle/fill"
65#define AWAR_DTREE_CIRCLE_ELLIPSE  "awt/dtree/bootstrap/circle/ellipse"
66#define AWAR_DTREE_CIRCLE_ZOOM     "awt/dtree/bootstrap/circle/zoom"
67#define AWAR_DTREE_CIRCLE_LIMIT    "awt/dtree/bootstrap/circle/limit"
68
69#define AWAR_DTREE_RADIAL_ZOOM_TEXT "awt/dtree/radial/zoomtext"
70#define AWAR_DTREE_RADIAL_XPAD      "awt/dtree/radial/xpadding"
71
72#define AWAR_DTREE_DENDRO_ZOOM_TEXT "awt/dtree/dendro/zoomtext"
73#define AWAR_DTREE_DENDRO_XPAD      "awt/dtree/dendro/xpadding"
74
75#define AWAR_DTREE_GROUP_MARKED_THRESHOLD           "awt/dtree/markers/group_marked_threshold"
76#define AWAR_DTREE_GROUP_PARTIALLY_MARKED_THRESHOLD "awt/dtree/markers/group_partially_marked_threshold"
77#define AWAR_DTREE_MARKER_WIDTH                     "awt/dtree/markers/marker_width"
78#define AWAR_DTREE_PARTIAL_GREYLEVEL                "awt/dtree/markers/partial_greylevel"
79
80#define NT_BOX_WIDTH      7   // pixel
81#define NT_DIAMOND_RADIUS 5
82#define NT_ROOT_WIDTH     9
83#define NT_SELECTED_WIDTH 11
84
85#define AWT_TREE(ntw) (ntw)->get_graphic_tree()
86
87enum AP_tree_display_style {
88    AP_TREE_NORMAL, // normal tree display (dendrogram)
89    AP_TREE_RADIAL, // radial tree display
90    AP_TREE_IRS, // like AP_TREE_NORMAL, with folding line
91    AP_LIST_NDS,
92    AP_LIST_SIMPLE // simple display only showing name (used at startup to avoid NDS error messages)
93};
94
95enum AP_tree_jump_type {         // bit-values
96    AP_JUMP_KEEP_VISIBLE   = 1,  // automatically make selected node visible (on changes)          [VALUE STORED IN AWAR!]
97    AP_JUMP_LOGICAL_UNZOOM = 2,  // adapts logical zoom (if target is outside zoomed subtree)
98    AP_JUMP_FORCE_VCENTER  = 4,  // force vertical centering (even if visible)
99    AP_JUMP_ALLOW_HCENTER  = 8,  // force horizontal centering (if vertically centered); only works together with AP_JUMP_FORCE_VCENTER
100    AP_JUMP_FORCE_HCENTER  = 16, // force horizontal centering
101    AP_JUMP_BE_VERBOOSE    = 32, // tell why nothing happened etc.
102    AP_JUMP_AUTO_UNFOLD    = 64, // temporarily auto-unfold folded target node
103
104    // convenience defs:
105    AP_DONT_JUMP         = 0,                                           // [VALUE STORED IN AWAR!]
106    AP_JUMP_SMART_CENTER = AP_JUMP_FORCE_VCENTER|AP_JUMP_ALLOW_HCENTER, // [VALUE STORED IN AWAR!]
107    AP_JUMP_FORCE_CENTER = AP_JUMP_FORCE_VCENTER|AP_JUMP_FORCE_HCENTER, // [VALUE STORED IN AWAR!]
108
109    AP_JUMP_BY_BUTTON = AP_JUMP_SMART_CENTER|AP_JUMP_LOGICAL_UNZOOM|AP_JUMP_AUTO_UNFOLD|AP_JUMP_BE_VERBOOSE,
110};
111
112enum AP_tree_jump_reason {
113    AP_JUMP_REASON_TREE,
114    AP_JUMP_REASON_STYLE,
115    AP_JUMP_REASON_SPECIES,
116    AP_JUMP_REASON_GROUP,
117};
118
119enum ClickedType {
120    CL_NODE = 1,
121    CL_SPECIES,
122    CL_RULER,
123    CL_FLAG,
124    CL_BRANCH,
125    CL_ROOTNODE,
126};
127
128inline bool is_list_style(AP_tree_display_style style) { return style == AP_LIST_NDS || style == AP_LIST_SIMPLE; }
129inline bool is_tree_style(AP_tree_display_style style) { return !is_list_style(style); }
130
131class NDS_Labeler;
132class AWT_graphic_tree_group_state;
133
134struct AWT_scaled_font_limits {
135    double ascent;
136    double descent;
137    double height;
138    double width;
139
140    void init(const AW_font_limits& font_limits, double factor) {
141        ascent  = font_limits.ascent*factor;
142        descent = font_limits.descent*factor;
143        height  = font_limits.get_height()*factor;
144        width   = font_limits.width*factor;
145    }
146};
147
148enum AD_MAP_VIEWER_TYPE {
149    ADMVT_NONE = 0,
150    ADMVT_INFO,
151    ADMVT_WWW,
152    ADMVT_SELECT
153};
154
155typedef void (*AD_map_viewer_cb)(GBDATA *gbd, AD_MAP_VIEWER_TYPE type);
156
157struct DendroSubtreeLimits {
158    double y_branch;                                // ypos of branch to subtree
159    double y_top;                                   // top ypos of whole subtree
160    double y_bot;                                   // bottom ypos of whole subtree
161    double x_right;                                 // rightmost xpos of whole subtree
162
163    void combine(const DendroSubtreeLimits& other) {
164        y_top   = std::min(y_top, other.y_top);
165        y_bot   = std::max(y_bot, other.y_bot);
166        x_right = std::max(x_right, other.x_right);
167    }
168};
169
170struct AWT_command_data {
171    /*! any kind of data which has to be stored between different events (e.g. to support drag&drop)
172     * Purpose of this class is to allow to delete such data w/o knowing anything else.
173     */
174    virtual ~AWT_command_data() {}
175};
176
177enum CollapseMode {
178    COLLAPSE_ALL      = 0,
179    EXPAND_MARKED     = 1,  // do not collapse groups containing marked species
180    COLLAPSE_TERMINAL = 2,  // do not collapse groups with subgroups
181    EXPAND_ALL        = 4,
182    EXPAND_COLOR      = 8,  // do not collapse groups containing species with color == parameter 'color_group' (or any color if 'color_group' is -1)
183    EXPAND_ZOMBIES    = 16, // do not collapse groups containing zombies
184    EXPAND_UNMARKED   = 32, // do not collapse groups containing unmarked species
185};
186
187class NodeMarkers {
188    // represents markers at a node (species or group)
189
190    int              nodeSize; // number of species in group (or 1)
191    std::vector<int> mark;     // how often each marker is set in group
192public:
193    NodeMarkers() {} // default for cache
194    explicit NodeMarkers(int numMarks)
195        : nodeSize(0),
196          mark(numMarks, 0)
197    {}
198
199    void incMarker(size_t markerIdx) {
200        td_assert(markerIdx<mark.size());
201        mark[markerIdx]++;
202    }
203    int markerCount(size_t markerIdx) const {
204        td_assert(markerIdx<mark.size());
205        return mark[markerIdx];
206    }
207
208    void incNodeSize() { nodeSize++; }
209    int getNodeSize() const { return nodeSize; }
210
211    double getMarkRate(size_t markerIdx) const { return markerCount(markerIdx) / double(getNodeSize()); }
212
213    void add(const NodeMarkers& other) {
214        size_t size = mark.size();
215        td_assert(size == other.mark.size());
216        for (size_t i = 0; i<size; ++i) {
217            mark[i] += other.mark[i];
218        }
219        nodeSize += other.nodeSize;
220    }
221};
222
223class MarkerDisplay {
224    // defines which markers shall be displayed
225
226    typedef std::map<const AP_tree*,NodeMarkers> GroupMarkerCache;
227
228    GroupMarkerCache cache;
229    int              numMarkers;
230
231public:
232    MarkerDisplay(int numMarkers_)
233        : numMarkers(numMarkers_)
234    {
235        td_assert(numMarkers>0);
236    }
237    virtual ~MarkerDisplay() {}
238
239    virtual const char *get_marker_name(int markerIdx) const                                      = 0;
240    virtual void retrieve_marker_state(const char *speciesName, NodeMarkers& matches)             = 0;
241    virtual void handle_click(int markerIdx, AW_MouseButton button, AWT_graphic_exports& exports) = 0;
242
243    const NodeMarkers *read_cache(const AP_tree *at) const {
244        GroupMarkerCache::const_iterator found = cache.find(at);
245        return found == cache.end() ? NULp : &found->second;
246    }
247    void write_cache(const AP_tree *at, const NodeMarkers& markers) { cache[at] = markers; }
248    void flush_cache() { cache.erase(cache.begin(), cache.end()); }
249#if defined(ASSERTION_USED)
250    bool cache_is_flushed() const { return cache.empty(); }
251#endif
252
253    int size() const { return numMarkers; }
254};
255
256struct GroupInfo {
257    const char *name;
258    const char *count;
259    unsigned    name_len;
260    unsigned    count_len;
261};
262
263enum GroupInfoMode {
264    GI_COMBINED,             // only sets GroupInfo::name (will contain "name (count)" or only "name" if counters disabled)
265    GI_SEPARATED,            // set GroupInfo::name and GroupInfo::count (to "name" and "count")
266    GI_SEPARATED_PARENTIZED, // like GI_SEPARATED, but GroupInfo::count will be "(count)"
267};
268
269enum GroupInfoPosition {
270    GIP_SEPARATED, // name attached, count overlayed             (=old hardcoded default for AP_TREE_NORMAL and AP_TREE_IRS)
271    GIP_ATTACHED,  // "name (count)" attached "next to" group    (=old hardcoded default for AP_TREE_RADIAL)
272    GIP_OVERLAYED, // "name (count)" overlayed with group polygon
273};
274
275enum GroupCountMode {
276    GCM_NONE,    // do not show group count         (=old hardcoded default for AP_TREE_RADIAL)
277    GCM_MEMBERS, // show number of group members    (=old hardcoded default for AP_TREE_NORMAL and AP_TREE_IRS)
278    GCM_MARKED,  // show number of marked group members (show nothing if none marked)
279    GCM_BOTH,    // show "marked/members" (or "members" if none marked)
280    GCM_PERCENT, // show percent of marked group members (show nothing if none marked)
281    GCM_BOTH_PC, // show "percent/members" (or "members" if none marked)
282};
283
284enum BranchStyle {
285    BS_RECTANGULAR, // traditional rectangular branches
286    BS_DIAGONAL,    // diagonal branches (directly from fathers to sons attach point)
287};
288
289enum GroupStyle {
290    GS_TRAPEZE, // traditional style
291    GS_TRIANGLE,
292};
293
294enum GroupOrientation {
295    GO_TOP,      // long clade side at top
296    GO_BOTTOM,   // long clade side at bottom
297    GO_INTERIOR, // long clade side towards center of subtree
298    GO_EXTERIOR, // long clade side towards margin of subtree
299};
300
301class AWT_graphic_tree;
302DECLARE_CBTYPE_FVV_AND_BUILDERS(GraphicTreeCallback, void, AWT_graphic_tree*); // generates makeGraphicTreeCallback
303
304class PaintedNode {
305    AW::Position  pos;
306    AP_tree      *node;
307public:
308    PaintedNode() : pos(AW::Origin), node(NULp) {}
309    PaintedNode(const PaintedNode& other) : pos(other.pos), node(other.node) {}
310    PaintedNode(const AW::Position& p, AP_tree *n) : pos(p), node(n) {}
311    DECLARE_ASSIGNMENT_OPERATOR(PaintedNode);
312    ~PaintedNode() {}
313
314    bool was_displayed() const { return node || are_distinct(AW::Origin, pos); }
315
316    const AW::Position& get_pos() const { return pos; }
317    AP_tree *get_node() const { return node; } // NULp in list-mode or if got no tree
318};
319
320enum BootstrapStyle {
321    BS_PERCENT,
322    BS_PERCENT_NOSIGN,
323    BS_FLOAT,
324};
325
326struct BootstrapConfig {
327    const AW_bitset circle_filter;
328    const AW_bitset text_filter;
329
330    int bootstrap_min; // minimum shown bootstrap (lower values are hidden)
331    int bootstrap_max; // maximum shown bootstrap (higher values are hidden)
332
333    BootstrapStyle style;
334
335    bool  show_boots;
336    bool  show_circle;
337    float fill_level;
338    bool  elipsoid;
339
340    bool show_100_if_empty; // automatically add 100% at branches w/o bootstraps (last loaded state contains bootstraps!)
341
342    float zoom_factor;
343    float max_radius;
344
345    double scaled_remark_ascend;
346
347    BootstrapConfig();
348
349    void display_remark(AW_device *device, const char *remark, const AW::Position& center, double blen, double bdist, const AW::Position& textpos, AW_pos alignment) const;
350    void display_node_remark(AW_device *device, const AP_tree *at, const AW::Position& center, double blen, double bdist, AW::RoughDirection textArea) const;
351
352    void update_empty_branch_behavior(const TreeRoot *troot)  {
353        show_100_if_empty = troot->has_bootstrap();
354    }
355
356    bool shall_show_remark_for(const TreeNode *node) const {
357        return !node->is_leaf() && (show_100_if_empty || node->get_remark_ptr().isSet());
358    }
359};
360
361class AWT_graphic_tree : public AWT_graphic, virtual Noncopyable {
362    char  *species_name;
363    Group  selected_group;
364
365    PaintedNode selSpec;   // is set while tree display gets refreshed
366    PaintedNode selGroup;  // is set while tree display gets refreshed // @@@ no need to store node; store rectangle area instead of position
367
368    int baselinewidth;
369
370    BootstrapConfig bconf;
371
372    int zombies;    // # of zombies during last load()
373    int duplicates; // # of duplicates during last load()
374
375    AP_tree *tree_proto;
376
377    bool show_brackets;
378
379    bool link_to_database; // link on load?
380
381    GroupStyle       group_style;
382    GroupOrientation group_orientation;
383
384    double list_tree_ruler_y;
385    double irs_tree_ruler_scale_factor;
386    double attach_size;   // 1.0 = at bigger subtree ; 0.0 = centered;         -1.0 = at smaller subtree (trad.)
387    double attach_len;    // 1.0 = at longer branch;   0.0 = centered (trad.); -1.0 = at shorter branch
388    double attach_group;  // 1.0 = at longer side;     0.5 = centered (trad.);  0.0 = at shorter side (of group polygon)
389
390    AWT_scaled_font_limits scaled_font;
391
392    double scaled_branch_distance; // vertical distance between branches (may be extra-scaled in options)
393
394    AW_grey_level group_greylevel;
395    AW_grey_level marker_greylevel;
396
397    AW_device *disp_device; // device for recursive functions
398
399    const AW_bitset line_filter, vert_line_filter, mark_filter, group_bracket_filter;
400    const AW_bitset leaf_text_filter, group_text_filter, other_text_filter;
401    const AW_bitset ruler_filter, root_filter, marker_filter;
402
403    GroupInfoPosition group_info_pos;
404    GroupCountMode    group_count_mode;
405    BranchStyle       branch_style;
406
407    MarkerDisplay *display_markers;
408    struct {
409        double marked;
410        double partiallyMarked;
411    } groupThreshold;
412
413    AD_map_viewer_cb  map_viewer_cb;
414    AWT_command_data *cmd_data;
415
416    AP_tree_root *tree_static;
417    AP_tree      *displayed_root; // root node of shown (sub-)tree; differs from real root if tree is zoomed logically
418
419    GraphicTreeCallback tree_changed_cb;
420    static GraphicTreeCallback group_changed_cb;
421
422    class AP_tree_folding *autoUnfolded;
423
424    AW_root *aw_root;
425    GBDATA  *gb_main;
426
427    AP_tree_display_style tree_style;
428    bool                  nds_only_marked; // true -> display only marked species (only for list-styles)
429
430    AW_pos paint_irs_sub_tree(AP_tree *node, AW_pos x_offset, const NDS_Labeler& labeler); // returns y pos
431    void   unload();
432
433    // functions to compute displayinformation
434
435    void show_dendrogram(AP_tree *at, AW::Position& pen, DendroSubtreeLimits& limits, const NDS_Labeler& labeler);
436    void show_radial_tree(AP_tree *at, const AW::Position& base, const AW::Position& tip, const AW::Angle& orientation, const double tree_spread, const NDS_Labeler& labeler);
437    void show_nds_list(GBDATA * gb_main, bool use_nds, const NDS_Labeler& labeler);
438    void show_irs_tree(AP_tree *at, double height, const NDS_Labeler& labeler);
439
440    void summarizeGroupMarkers(AP_tree *at, NodeMarkers& markers);
441    void drawMarker(const class MarkerPosition& marker, const bool partial, const int midx);
442    void detectAndDrawMarkers(AP_tree *at, double y1, double y2);
443    void drawMarkerNames(AW::Position& Pen);
444
445    void pixel_box(int gc, const AW::Position& pos, int pixel_width, AW::FillStyle filled);
446
447    AP_tree *find_selected_node() const;
448    AP_tree *find_selected_group();
449
450    void toggle_folding_at(AP_tree *at, bool force_jump);
451
452    const GroupInfo& get_group_info(AP_tree *at, GroupInfoMode mode, bool swap, const NDS_Labeler& labeler) const;
453
454    bool handle_cursor(AW_key_code kcode, AW_key_mod mod);
455    void handle_key(AW_device *device, AWT_graphic_event& event);
456
457    GB_ERROR create_group(AP_tree * at) __ATTR__USERESULT;
458
459protected:
460    group_scaling groupScale; // scaling for folded groups
461
462    void store_command_data(AWT_command_data *new_cmd_data) {
463        delete cmd_data;
464        cmd_data = new_cmd_data;
465    }
466    AWT_command_data *get_command_data() { return cmd_data; }
467
468public:
469    AWT_graphic_tree(AW_root *aw_root, GBDATA *gb_main, AD_map_viewer_cb map_viewer_cb);
470    ~AWT_graphic_tree() OVERRIDE;
471
472    void filled_box(int gc, const AW::Position& pos, int pixel_width) { pixel_box(gc, pos, pixel_width, AW::FillStyle::SOLID); }
473    void empty_box(int gc, const AW::Position& pos, int pixel_width) { pixel_box(gc, pos, pixel_width, AW::FillStyle::EMPTY); }
474    void diamond(int gc, const AW::Position& pos, int pixel_radius);
475
476    const char *ruler_awar(const char *name);
477
478    void set_line_attributes_for(AP_tree *at) const {
479        disp_device->set_line_attributes(at->gr.gc, at->get_linewidth()+baselinewidth, AW_SOLID);
480    }
481
482    virtual void read_tree_settings();
483    void update_structure() FINAL_OVERRIDE {
484        AP_tree *root = get_root_node();
485        if (root) {
486            forget_auto_unfolded();
487            root->compute_tree();
488        }
489    }
490    void apply_zoom_settings_for_treetype(AWT_canvas *ntw);
491
492    int draw_branch_line(int gc, const AW::Position& root, const AW::Position& leaf, AW_bitset filter) {
493        const AW_click_cd *old = disp_device->get_click_cd();
494        td_assert(old && old->get_cd1() && old->get_cd2() == CL_NODE); // cd1 should be the node
495
496        AW_click_cd branch(disp_device, old->get_cd1(), CL_BRANCH);
497        return disp_device->line(gc, root, leaf, filter);
498    }
499
500    bool warn_inappropriate_mode(AWT_COMMAND_MODE mode);
501
502    virtual AP_tree_root *create_tree_root(AliView *aliview, AP_sequence *seq_prototype, bool insert_delete_cbs);
503
504    AW_root *get_root() const { return aw_root; }
505    GBDATA *get_gbmain() const { return gb_main; }
506
507    AP_tree_root *get_tree_root() { return tree_static; }
508
509    AP_tree       *get_root_node()       { return tree_static ? tree_static->get_root_node() : NULp; }
510    const AP_tree *get_root_node() const { return const_cast<AWT_graphic_tree*>(this)->get_root_node(); }
511
512    AP_tree       *get_logical_root()       { return displayed_root; }
513    const AP_tree *get_logical_root() const { return displayed_root; }
514
515    bool is_logically_zoomed() { return displayed_root != get_root_node(); }
516    void set_logical_root_to(AP_tree *node) {
517        displayed_root = node;
518        tree_changed_cb(this);
519    }
520
521    void init(AliView *aliview, AP_sequence *seq_prototype, bool link_to_database_, bool insert_delete_cbs);
522    AW_gc_manager *init_devices(AW_window *, AW_device *, AWT_canvas *ntw) OVERRIDE;
523
524    void show(AW_device *device) OVERRIDE;
525    const AW::Position& get_cursor() const { return selSpec.get_pos(); }
526    const AW::Position& get_group_cursor() const { return selGroup.get_pos(); }
527
528    void handle_command(AW_device *device, AWT_graphic_event& event) OVERRIDE;
529
530    long mark_species_in_tree(AP_tree *at, int mark);
531    long mark_species_in_tree_that(AP_tree *at, int mark, bool (*condition)(GBDATA*, void*), void *cd);
532
533    void mark_species_in_rest_of_tree(AP_tree *at, int mark);
534
535    bool tree_has_marks(AP_tree *at);
536    bool rest_tree_has_marks(AP_tree *at);
537
538    void detect_group_state(AP_tree *at, AWT_graphic_tree_group_state *state, AP_tree *skip_this_son);
539
540    bool group_tree(AP_tree *at, CollapseMode mode, int color_group);
541    void group_rest_tree(AP_tree *at, CollapseMode mode, int color_group);
542    void reorderTree(TreeOrder mode);
543    void toggle_group(AP_tree * at);
544
545    GB_ERROR load_from_DB(GBDATA *gb_main, const char *name) FINAL_OVERRIDE __ATTR__USERESULT;
546    GB_ERROR save_to_DB(GBDATA *gb_main, const char *name) FINAL_OVERRIDE __ATTR__USERESULT;
547    void     check_for_DB_update(GBDATA *gb_main) FINAL_OVERRIDE;
548    void     notify_synchronized(GBDATA *gb_main) FINAL_OVERRIDE;
549
550    void fast_sync_changed_folding(AP_tree *parent_of_all_changes); // use carefully
551
552    void set_tree_style(AP_tree_display_style style, AWT_canvas *ntw);
553    AP_tree_display_style get_tree_style() const { return tree_style; }
554
555    double get_irs_tree_ruler_scale_factor() const { return irs_tree_ruler_scale_factor; }
556    void show_ruler(AW_device *device, int gc);
557    void get_zombies_and_duplicates(int& zomb, int& dups) const { zomb = zombies; dups = duplicates; }
558
559    void hide_marker_display() {
560        delete display_markers;
561        display_markers = NULp;
562    }
563    void set_marker_display(MarkerDisplay *display) { // takes ownership of 'display'
564        hide_marker_display();
565        display_markers = display;
566    }
567    MarkerDisplay *get_marker_display() { return display_markers; }
568
569    void install_tree_changed_callback(const GraphicTreeCallback& gtcb);
570    void uninstall_tree_changed_callback();
571
572    static void install_group_changed_callback(const GraphicTreeCallback& gccb) {
573        group_changed_cb = gccb;
574    }
575
576    void auto_unfold(AP_tree *want_visible);
577    void forget_auto_unfolded();
578
579private:
580    void select_group(const Group& group) {
581        if (selected_group != group) {
582            selected_group = group;
583            group_changed_cb(this);
584        }
585    }
586public:
587    void select_group(AP_tree *node) { // select + locate
588        td_assert(node && node->is_clade());
589        select_group(Group(node));
590    }
591    void select_group(GBDATA *gb_group) { // unlocated select (or deselect if called with NULp)
592        select_group(gb_group ? Group(gb_group) : Group());
593    }
594    void deselect_group() {
595        select_group(Group());
596    }
597    const Group& get_selected_group() const {
598        return selected_group;
599    }
600    AP_tree *locate_selected_group(AP_tree *in_subtree) {
601        AP_tree *node = NULp;
602        if (selected_group.is_valid()) {
603            if (selected_group.locate(in_subtree)) {
604                node = selected_group.get_node();
605            }
606        }
607        return node;
608    }
609    void dislocate_selected_group() {
610        // has to be called whenever the keeled-state of a group may change
611        selected_group.dislocate();
612    }
613
614#if defined(UNIT_TESTS) // UT_DIFF
615    friend class fake_AWT_graphic_tree;
616#endif
617    PREPARE_MARK_NONFINAL_CLASS(AWT_graphic_tree);
618};
619MARK_NONFINAL_CLASS(AWT_graphic_tree);
620MARK_NONFINAL_FUNCTION(AWT_graphic_tree,AP_tree_root*,create_tree_root,(AliView*,AP_sequence*,bool),NULp);
621
622class ClickedTarget {
623    /*! Represents any target corresponding to some (mouse-)position in the tree display.
624     *
625     * The target is e.g. used as target for keystrokes or mouse clicks.
626     *
627     * For AP_LIST_NDS, this only represents the species (w/o any tree information).
628     * For other tree display modes, this represents a specific tree node.
629     *
630     * The space outside the tree does represent the whole tree (aka the root-node).
631     * (the necessary distance to the tree-structure/-text is defined by AWT_CATCH)
632     */
633
634    AP_tree *tree_node;
635    GBDATA  *gb_species;
636
637    bool ruler;
638    bool branch;
639    int  markerflag; // = markerindex + 1
640
641    const AW_clicked_element *elem;
642
643    void init() {
644        tree_node  = NULp;
645        gb_species = NULp;
646        ruler      = false;
647        branch     = false;
648        markerflag  = 0;
649    }
650
651    void identify(AWT_graphic_tree *agt) {
652        init();
653        if (elem && elem->does_exist()) {
654            ClickedType what = (ClickedType)elem->cd2();
655
656            switch (what) {
657                case CL_SPECIES:
658                    gb_species = (GBDATA*)elem->cd1();
659                    td_assert(gb_species);
660                    break;
661
662                case CL_RULER:
663                    ruler = !elem->cd1();
664                    break;
665
666                case CL_FLAG:
667                    markerflag = elem->cd1()+1;
668                    break;
669
670                case CL_BRANCH:
671                    branch = true;
672                    // fall-through!
673                case CL_NODE:
674                    tree_node = (AP_tree*)elem->cd1();
675                    break;
676
677                case CL_ROOTNODE:
678                    if (agt) tree_node = agt->get_root_node();
679                    break;
680
681#if defined(DEBUG)
682                default:
683                    td_assert(0); // unknown element type
684#endif
685            }
686        }
687        else { // use whole tree if mouse does not point to a subtree
688            tree_node = agt ? agt->get_root_node() : NULp;
689        }
690        td_assert(implicated(branch, tree_node));
691    }
692
693public:
694
695    ClickedTarget(AWT_graphic_tree *agt, const AW_clicked_element *clicked) : elem(clicked) {
696        // uses root of tree as target, when a position outside of the tree is selected
697        // (e.g. used for key-commands)
698        identify(agt);
699    }
700    ClickedTarget(const AW_clicked_element *clicked) : elem(clicked) {
701        // accept only normal branches as targets
702        identify(NULp);
703    }
704
705    const AW_clicked_element *element() const { return elem; }
706    AP_tree *node() const { return tree_node; }
707    GBDATA *species() const { return gb_species; }
708    int get_markerindex() const { return markerflag-1; }
709
710    bool is_text() const { return elem && elem->is_text(); }
711    bool is_line() const { return elem && elem->is_line(); }
712    bool is_branch() const { return branch; }
713    bool is_ruler() const { return ruler; }
714    bool is_marker() const { return markerflag; }
715
716    double get_rel_attach() const {
717        // return [0..1] according to exact position where element is dropped
718        if (is_line() && (is_branch() || ruler)) return elem->get_rel_pos();
719        return 0.5; // act like "drop on branch-center"
720    }
721};
722
723class TREE_canvas : public AWT_canvas { // derived from Noncopyable
724    AW_awar *awar_tree; // awar containing name of displayed tree
725    int      index;     // unique index [0..MAX_NT_WINDOWS-1]
726
727    static int count;
728
729public:
730    TREE_canvas(GBDATA *gb_main_, AW_window *aww_, const char *gc_base_name_, AWT_graphic *gfx_, AW_awar *awar_tree_) :
731        AWT_canvas(gb_main_, aww_, gc_base_name_, gfx_),
732        awar_tree(awar_tree_),
733        index(count++)
734    {}
735
736    void at_screen_update_call(screen_update_callback cb, AW_CL cd) {
737        td_assert(!announce_update_cb || (announce_update_cb == cb && user_data == cd));
738
739        announce_update_cb = cb;
740        user_data          = cd;
741    }
742
743    AWT_graphic_tree *get_graphic_tree() const { return DOWNCAST(AWT_graphic_tree*, gfx); }
744    AW_awar *get_awar_tree() const { return awar_tree; }
745    int get_index() const { return index; }
746};
747
748
749void       TREE_create_awars(AW_root *aw_root, AW_default db);
750void       TREE_install_update_callbacks(TREE_canvas *ntw);
751AW_window *TREE_create_settings_window(AW_root *aw_root);
752AW_window *TREE_create_marker_settings_window(AW_root *root);
753
754AWT_graphic_tree *NT_generate_tree(AW_root *root, GBDATA *gb_main, AD_map_viewer_cb map_viewer_cb);
755
756#else
757#error TreeDisplay.hxx included twice
758#endif // TREEDISPLAY_HXX
Note: See TracBrowser for help on using the repository browser.