source: tags/ms_r16q2/SL/TREEDISP/TreeDisplay.hxx

Last change on this file was 15032, checked in by westram, 8 years ago
  • AWT_graphic_tree::set_logical_root_to
    • call tree_changed_cb
    • use in methods of AWT_graphic_tree (to trigger callback)
  • document when callback is triggered
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.5 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 AWT_CANVAS_HXX
18#include <awt_canvas.hxx>
19#endif
20#ifndef _GLIBCXX_VECTOR
21#include <vector>
22#endif
23#ifndef _GLIBCXX_MAP
24#include <map>
25#endif
26
27
28#define td_assert(cond) arb_assert(cond)
29
30#define AWAR_DTREE_BASELINEWIDTH   "awt/dtree/baselinewidth"
31#define AWAR_DTREE_VERICAL_DIST    "awt/dtree/verticaldist"
32#define AWAR_DTREE_GROUP_DOWNSCALE "awt/dtree/downscaling"
33#define AWAR_DTREE_GROUP_SCALE     "awt/dtree/groupscaling"
34#define AWAR_DTREE_AUTO_JUMP       "awt/dtree/autojump"
35#define AWAR_DTREE_AUTO_JUMP_TREE  "awt/dtree/autojump_tree"
36#define AWAR_DTREE_SHOW_CIRCLE     "awt/dtree/show_circle"
37#define AWAR_DTREE_SHOW_BRACKETS   "awt/dtree/show_brackets"
38#define AWAR_DTREE_CIRCLE_ZOOM     "awt/dtree/circle_zoom"
39#define AWAR_DTREE_CIRCLE_MAX_SIZE "awt/dtree/max_size"
40#define AWAR_DTREE_USE_ELLIPSE     "awt/dtree/ellipse"
41#define AWAR_DTREE_GREY_LEVEL      "awt/dtree/greylevel"
42#define AWAR_DTREE_GROUPCOUNTMODE  "awt/dtree/groupcountmode"
43#define AWAR_DTREE_GROUPINFOPOS    "awt/dtree/groupinfopos"
44#define AWAR_DTREE_BOOTSTRAP_MIN   "awt/dtree/bootstrap/inner/min"
45
46#define AWAR_DTREE_RADIAL_ZOOM_TEXT "awt/dtree/radial/zoomtext"
47#define AWAR_DTREE_RADIAL_XPAD      "awt/dtree/radial/xpadding"
48
49#define AWAR_DTREE_DENDRO_ZOOM_TEXT "awt/dtree/dendro/zoomtext"
50#define AWAR_DTREE_DENDRO_XPAD      "awt/dtree/dendro/xpadding"
51
52#define AWAR_DTREE_GROUP_MARKED_THRESHOLD           "awt/dtree/markers/group_marked_threshold"
53#define AWAR_DTREE_GROUP_PARTIALLY_MARKED_THRESHOLD "awt/dtree/markers/group_partially_marked_threshold"
54#define AWAR_DTREE_MARKER_WIDTH                     "awt/dtree/markers/marker_width"
55#define AWAR_DTREE_PARTIAL_GREYLEVEL                "awt/dtree/markers/partial_greylevel"
56
57#define NT_BOX_WIDTH      7   // pixel
58#define NT_DIAMOND_RADIUS 5
59#define NT_ROOT_WIDTH     9
60#define NT_SELECTED_WIDTH 11
61
62#define AWT_TREE(ntw) DOWNCAST(AWT_graphic_tree*, (ntw)->gfx)
63
64
65enum AP_tree_display_type {
66    AP_TREE_NORMAL, // normal tree display (dendrogram)
67    AP_TREE_RADIAL, // radial tree display
68    AP_TREE_IRS, // like AP_TREE_NORMAL, with folding line
69    AP_LIST_NDS,
70    AP_LIST_SIMPLE // simple display only showing name (used at startup to avoid NDS error messages)
71};
72
73enum AP_tree_jump_type { // bit-values
74    AP_JUMP_KEEP_VISIBLE  = 1,  // automatically make selected node visible (on changes)
75    AP_JUMP_UNFOLD_GROUPS = 2,  //
76    AP_JUMP_FORCE_VCENTER = 4,  // force vertical centering (even if visible)
77    AP_JUMP_ALLOW_HCENTER = 8,  // force horizontal centering (if vertically centered); only works together with AP_JUMP_FORCE_VCENTER
78    AP_JUMP_FORCE_HCENTER = 16, // force horizontal centering
79    AP_JUMP_BE_VERBOOSE   = 32, // tell why nothing happened etc.
80
81    // convenience defs:
82    AP_DONT_JUMP         = 0,
83    AP_JUMP_SMART_CENTER = AP_JUMP_FORCE_VCENTER|AP_JUMP_ALLOW_HCENTER,
84    AP_JUMP_FORCE_CENTER = AP_JUMP_FORCE_VCENTER|AP_JUMP_FORCE_HCENTER,
85
86    AP_JUMP_BY_BUTTON = AP_JUMP_SMART_CENTER|AP_JUMP_UNFOLD_GROUPS|AP_JUMP_BE_VERBOOSE,
87};
88
89inline bool sort_is_list_style(AP_tree_display_type sort) { return sort == AP_LIST_NDS || sort == AP_LIST_SIMPLE; }
90inline bool sort_is_tree_style(AP_tree_display_type sort) { return !sort_is_list_style(sort); }
91
92
93class AWT_graphic_tree_group_state;
94
95struct AWT_scaled_font_limits {
96    double ascent;
97    double descent;
98    double height;
99    double width;
100
101    void init(const AW_font_limits& font_limits, double factor) {
102        ascent  = font_limits.ascent*factor;
103        descent = font_limits.descent*factor;
104        height  = font_limits.height*factor;
105        width   = font_limits.width*factor;
106    }
107};
108
109enum AD_MAP_VIEWER_TYPE {
110    ADMVT_NONE = 0,
111    ADMVT_INFO,
112    ADMVT_WWW,
113    ADMVT_SELECT
114};
115
116typedef void (*AD_map_viewer_cb)(GBDATA *gbd, AD_MAP_VIEWER_TYPE type);
117
118struct DendroSubtreeLimits {
119    double y_branch;                                // ypos of branch to subtree
120    double y_top;                                   // top ypos of whole subtree
121    double y_bot;                                   // bottom ypos of whole subtree
122    double x_right;                                 // rightmost xpos of whole subtree
123
124    void combine(const DendroSubtreeLimits& other) {
125        y_top   = std::min(y_top, other.y_top);
126        y_bot   = std::max(y_bot, other.y_bot);
127        x_right = std::max(x_right, other.x_right);
128    }
129};
130
131struct AWT_command_data {
132    /*! any kind of data which has to be stored between different events (e.g. to support drag&drop)
133     * Purpose of this class is to allow to delete such data w/o knowing anything else.
134     */
135    virtual ~AWT_command_data() {}
136};
137
138enum CollapseMode {
139    COLLAPSE_ALL      = 0,
140    EXPAND_MARKED     = 1,  // do not collapse groups containing marked species
141    COLLAPSE_TERMINAL = 2,  // do not collapse groups with subgroups
142    EXPAND_ALL        = 4,
143    EXPAND_COLOR      = 8,  // do not collapse groups containing species with color == parameter 'color_group' (or any color if 'color_group' is -1)
144    EXPAND_ZOMBIES    = 16, // do not collapse groups containing zombies
145};
146
147class NodeMarkers {
148    // represents markers at a node (species or group)
149
150    int              nodeSize; // number of species in group (or 1)
151    std::vector<int> mark;     // how often each marker is set in group
152public:
153    NodeMarkers() {} // default for cache
154    explicit NodeMarkers(int numMarks)
155        : nodeSize(0),
156          mark(numMarks, 0)
157    {}
158
159    void incMarker(size_t markerIdx) {
160        td_assert(markerIdx<mark.size());
161        mark[markerIdx]++;
162    }
163    int markerCount(size_t markerIdx) const {
164        td_assert(markerIdx<mark.size());
165        return mark[markerIdx];
166    }
167
168    void incNodeSize() { nodeSize++; }
169    int getNodeSize() const { return nodeSize; }
170
171    double getMarkRate(size_t markerIdx) const { return markerCount(markerIdx) / double(getNodeSize()); }
172
173    void add(const NodeMarkers& other) {
174        size_t size = mark.size();
175        td_assert(size == other.mark.size());
176        for (size_t i = 0; i<size; ++i) {
177            mark[i] += other.mark[i];
178        }
179        nodeSize += other.nodeSize;
180    }
181};
182
183class MarkerDisplay {
184    // defines which markers shall be displayed
185
186    typedef std::map<const AP_tree*,NodeMarkers> GroupMarkerCache;
187
188    GroupMarkerCache cache;
189    int              numMarkers;
190
191public:
192    MarkerDisplay(int numMarkers_)
193        : numMarkers(numMarkers_)
194    {
195        td_assert(numMarkers>0);
196    }
197    virtual ~MarkerDisplay() {}
198
199    virtual const char *get_marker_name(int markerIdx) const                                      = 0;
200    virtual void retrieve_marker_state(const char *speciesName, NodeMarkers& matches)             = 0;
201    virtual void handle_click(int markerIdx, AW_MouseButton button, AWT_graphic_exports& exports) = 0;
202
203    const NodeMarkers *read_cache(const AP_tree *at) const {
204        GroupMarkerCache::const_iterator found = cache.find(at);
205        return found == cache.end() ? NULL : &found->second;
206    }
207    void write_cache(const AP_tree *at, const NodeMarkers& markers) { cache[at] = markers; }
208    void flush_cache() { cache.erase(cache.begin(), cache.end()); }
209
210    int size() const { return numMarkers; }
211};
212
213struct GroupInfo {
214    const char *name;
215    const char *count;
216    unsigned    name_len;
217    unsigned    count_len;
218};
219
220enum GroupInfoMode {
221    GI_COMBINED,             // only sets GroupInfo::name (will contain "name (count)" or only "name" if counters disabled)
222    GI_SEPARATED,            // set GroupInfo::name and GroupInfo::count (to "name" and "count")
223    GI_SEPARATED_PARENTIZED, // like GI_SEPARATED, but GroupInfo::count will be "(count)"
224};
225
226enum GroupInfoPosition {
227    GIP_SEPARATED, // name attached, count overlayed             (=old hardcoded default for AP_TREE_NORMAL and AP_TREE_IRS)
228    GIP_ATTACHED,  // "name (count)" attached "next to" group    (=old hardcoded default for AP_TREE_RADIAL)
229    GIP_OVERLAYED, // "name (count)" overlayed with group polygon
230};
231
232enum GroupCountMode {
233    GCM_NONE,    // do not show group count         (=old hardcoded default for AP_TREE_RADIAL)
234    GCM_MEMBERS, // show number of group members    (=old hardcoded default for AP_TREE_NORMAL and AP_TREE_IRS)
235    GCM_MARKED,  // show number of marked group members (show nothing if none marked)
236    GCM_BOTH,    // show "marked/members" (or "members" if none marked)
237    GCM_PERCENT, // show percent of marked group members (show nothing if none marked)
238    GCM_BOTH_PC, // show "percent/members" (or "members" if none marked)
239};
240
241class AWT_graphic_tree;
242DECLARE_CBTYPE_FVV_AND_BUILDERS(GraphicTreeCallback, void, AWT_graphic_tree*); // generates makeGraphicTreeCallback
243
244class AWT_graphic_tree : public AWT_graphic, virtual Noncopyable {
245    char         *species_name;
246    AW::Position  cursor;
247
248    int    baselinewidth;
249    int    show_brackets;
250    int    show_circle;
251    int    use_ellipse;
252    float  circle_zoom_factor;
253    float  circle_max_size;
254    int    bootstrap_min;
255
256    int zombies; // # of zombies during last load()
257    int duplicates; // # of duplicates during last load()
258
259    AW_pos paint_irs_sub_tree(AP_tree *node, AW_pos x_offset); // returns y pos
260
261    void unload();
262
263    // variables - tree compatibility
264
265    AP_tree * tree_proto;
266    bool link_to_database; // link on load ?
267
268    double list_tree_ruler_y;
269    double irs_tree_ruler_scale_factor;
270
271    AWT_scaled_font_limits scaled_font;
272
273    double        scaled_branch_distance; // vertical distance between branches (may be extra-scaled in options)
274    group_scaling groupScale; // scaling for folded groups
275
276    AW_grey_level group_greylevel;
277    AW_grey_level marker_greylevel;
278
279    AW_device *disp_device; // device for recursive functions
280
281    const AW_bitset line_filter, vert_line_filter, mark_filter, group_bracket_filter, bs_circle_filter;
282    const AW_bitset leaf_text_filter, group_text_filter, remark_text_filter, other_text_filter;
283    const AW_bitset ruler_filter, root_filter, marker_filter;
284
285    bool nds_only_marked;
286
287    GroupInfoPosition group_info_pos;
288    GroupCountMode    group_count_mode;
289
290    MarkerDisplay *display_markers;
291    struct {
292        double marked;
293        double partiallyMarked;
294    } groupThreshold;
295
296    AD_map_viewer_cb  map_viewer_cb;
297    AWT_command_data *cmd_data;
298
299    AP_tree_root *tree_static;
300    AP_tree      *displayed_root; // root node of shown (sub-)tree; differs from real root if tree is zoomed logically
301
302    GraphicTreeCallback tree_changed_cb;
303
304    // functions to compute displayinformation
305
306    void show_dendrogram(AP_tree *at, AW::Position& pen, DendroSubtreeLimits& limits);
307    void show_radial_tree(AP_tree *at, const AW::Position& base, const AW::Position& tip, const AW::Angle& orientation, const double tree_spread);
308    void show_nds_list(GBDATA * gb_main, bool use_nds);
309    void show_irs_tree(AP_tree *at, double height);
310
311    void summarizeGroupMarkers(AP_tree *at, NodeMarkers& markers);
312    void drawMarker(const class MarkerPosition& marker, const bool partial, const int midx);
313    void detectAndDrawMarkers(AP_tree *at, double y1, double y2);
314    void drawMarkerNames(AW::Position& Pen);
315
316    void pixel_box(int gc, const AW::Position& pos, int pixel_width, AW::FillStyle filled);
317
318    const GroupInfo& get_group_info(AP_tree *at, GroupInfoMode mode, bool swap = false) const;
319
320public:
321    void filled_box(int gc, const AW::Position& pos, int pixel_width) { pixel_box(gc, pos, pixel_width, AW::FillStyle::SOLID); }
322    void empty_box(int gc, const AW::Position& pos, int pixel_width) { pixel_box(gc, pos, pixel_width, AW::FillStyle::EMPTY); }
323    void diamond(int gc, const AW::Position& pos, int pixel_radius);
324
325    const char *ruler_awar(const char *name);
326
327    void set_line_attributes_for(AP_tree *at) const {
328        disp_device->set_line_attributes(at->gr.gc, at->get_linewidth()+baselinewidth, AW_SOLID);
329    }
330
331    virtual void read_tree_settings();
332    void update_structure() {
333        AP_tree *root = get_root_node();
334        if (root) root->compute_tree();
335    }
336    void apply_zoom_settings_for_treetype(AWT_canvas *ntw);
337
338    int draw_branch_line(int gc, const AW::Position& root, const AW::Position& leaf, AW_bitset filter) {
339        const AW_click_cd *old = disp_device->get_click_cd();
340        td_assert(old && old->get_cd1() && !old->get_cd2()); // cd1 should be the node
341
342        AW_click_cd branch(disp_device, old->get_cd1(), (AW_CL)"branch");
343        return disp_device->line(gc, root, leaf, filter);
344    }
345
346    bool warn_inappropriate_mode(AWT_COMMAND_MODE mode);
347
348    virtual AP_tree_root *create_tree_root(AliView *aliview, AP_sequence *seq_prototype, bool insert_delete_cbs);
349
350protected:
351    void store_command_data(AWT_command_data *new_cmd_data) {
352        delete cmd_data;
353        cmd_data = new_cmd_data;
354    }
355    AWT_command_data *get_command_data() { return cmd_data; }
356
357public:
358
359    // *********** read only variables !!!
360
361    AW_root              *aw_root;
362    AP_tree_display_type  tree_sort;
363    GBDATA               *gb_main;
364
365    // *********** public section
366
367    AWT_graphic_tree(AW_root *aw_root, GBDATA *gb_main, AD_map_viewer_cb map_viewer_cb);
368    ~AWT_graphic_tree() OVERRIDE;
369
370    AP_tree_root *get_tree_root() { return tree_static; }
371
372    AP_tree       *get_root_node()       { return tree_static ? tree_static->get_root_node() : NULL; }
373    const AP_tree *get_root_node() const { return const_cast<AWT_graphic_tree*>(this)->get_root_node(); }
374
375    AP_tree       *get_logical_root()       { return displayed_root; }
376    const AP_tree *get_logical_root() const { return displayed_root; }
377
378    bool is_logically_zoomed() { return displayed_root != get_root_node(); }
379    void set_logical_root_to(AP_tree *node) {
380        displayed_root = node;
381        tree_changed_cb(this);
382    }
383
384    void init(AliView *aliview, AP_sequence *seq_prototype, bool link_to_database_, bool insert_delete_cbs);
385    AW_gc_manager *init_devices(AW_window *, AW_device *, AWT_canvas *ntw) OVERRIDE;
386
387    void show(AW_device *device) OVERRIDE;
388    const AW::Position& get_cursor() const { return cursor; }
389
390private:
391    void handle_key(AW_device *device, AWT_graphic_event& event);
392public:
393    void handle_command(AW_device *device, AWT_graphic_event& event) OVERRIDE;
394
395    void mark_species_in_tree(AP_tree *at, int mark);
396    void mark_species_in_tree_that(AP_tree *at, int mark, int (*condition)(GBDATA*, void*), void *cd);
397
398    void mark_species_in_rest_of_tree(AP_tree *at, int mark);
399    void mark_species_in_rest_of_tree_that(AP_tree *at, int mark, int (*condition)(GBDATA*, void*), void *cd);
400
401    bool tree_has_marks(AP_tree *at);
402    bool rest_tree_has_marks(AP_tree *at);
403
404    void detect_group_state(AP_tree *at, AWT_graphic_tree_group_state *state, AP_tree *skip_this_son);
405
406    bool     group_tree(AP_tree *at, CollapseMode mode, int color_group);
407    void     group_rest_tree(AP_tree *at, CollapseMode mode, int color_group);
408    void     reorder_tree(TreeOrder mode);
409    GB_ERROR create_group(AP_tree * at) __ATTR__USERESULT;
410    void     toggle_group(AP_tree * at);
411    GB_ERROR load(GBDATA *gb_main, const char *name) OVERRIDE __ATTR__USERESULT;
412    GB_ERROR save(GBDATA *gb_main, const char *name) OVERRIDE __ATTR__USERESULT;
413    int      check_update(GBDATA *gb_main) OVERRIDE;         // reload tree if needed
414    void     update(GBDATA *gb_main) OVERRIDE;
415    void     set_tree_type(AP_tree_display_type type, AWT_canvas *ntw);
416
417    double get_irs_tree_ruler_scale_factor() const { return irs_tree_ruler_scale_factor; }
418    void show_ruler(AW_device *device, int gc);
419    void get_zombies_and_duplicates(int& zomb, int& dups) const { zomb = zombies; dups = duplicates; }
420
421    void hide_marker_display() {
422        delete display_markers;
423        display_markers = NULL;
424    }
425    void set_marker_display(MarkerDisplay *display) { // takes ownership of 'display'
426        hide_marker_display();
427        display_markers = display;
428    }
429    MarkerDisplay *get_marker_display() { return display_markers; }
430
431    void install_tree_changed_callback(const GraphicTreeCallback& gtcb);
432    void uninstall_tree_changed_callback();
433
434#if defined(UNIT_TESTS) // UT_DIFF
435    friend class fake_AWT_graphic_tree;
436#endif
437};
438
439class ClickedTarget {
440    /*! Represents any target corresponding to some (mouse-)position in the tree display.
441     *
442     * The target is e.g. used as target for keystrokes or mouse clicks.
443     *
444     * For AP_LIST_NDS, this only represents the species (w/o any tree information).
445     * For other tree display modes, this represents a specific tree node.
446     *
447     * The space outside the tree does represent the whole tree (aka the root-node).
448     * (the necessary distance to the tree-structure/-text is defined by AWT_CATCH)
449     */
450
451    AP_tree *tree_node;
452    GBDATA  *gb_species;
453
454    bool ruler;
455    bool branch;
456    int  markerflag; // = markerindex + 1
457
458    const AW_clicked_element *elem;
459
460    void init() {
461        tree_node  = NULL;
462        gb_species = NULL;
463        ruler      = false;
464        branch     = false;
465        markerflag  = 0;
466    }
467
468    void identify(AWT_graphic_tree *agt) {
469        init();
470        if (elem && elem->does_exist()) {
471            const char *what = (const char*)elem->cd2();
472
473            if (what) {
474                if (strcmp(what, "species") == 0) { // entry in NDS list
475                    gb_species = (GBDATA*)elem->cd1();
476                    td_assert(gb_species);
477                }
478                else if (strcmp(what, "ruler") == 0) {
479                    ruler = !elem->cd1();
480                }
481                else if (strcmp(what, "flag") == 0) {
482                    markerflag = elem->cd1()+1;
483                }
484                else if (strcmp(what, "branch") == 0) {
485                    branch = true; // indicates that a line really IS the branch (opposed to other branch-related lines like e.g. group-brackets)
486                }
487                else {
488                    td_assert(0); // unknown element type
489                }
490            }
491
492            if (!(gb_species || ruler || markerflag)) {
493                tree_node = (AP_tree*)elem->cd1();
494                td_assert(branch || !what);
495            }
496        }
497        else { // use whole tree if mouse does not point to a subtree
498            tree_node = agt ? agt->get_root_node() : NULL;
499        }
500        td_assert(implicated(branch, tree_node));
501    }
502
503public:
504
505    ClickedTarget(AWT_graphic_tree *agt, const AW_clicked_element *clicked) : elem(clicked) {
506        // uses root of tree as target, when a position outside of the tree is selected
507        // (e.g. used for key-commands)
508        identify(agt);
509    }
510    ClickedTarget(const AW_clicked_element *clicked) : elem(clicked) {
511        // accept only normal branches as targets
512        identify(NULL);
513    }
514
515    const AW_clicked_element *element() const { return elem; }
516    AP_tree *node() const { return tree_node; }
517    GBDATA *species() const { return gb_species; }
518    int get_markerindex() const { return markerflag-1; }
519
520    bool is_text() const { return elem && elem->is_text(); }
521    bool is_line() const { return elem && elem->is_line(); }
522    bool is_branch() const { return branch; }
523    bool is_ruler() const { return ruler; }
524    bool is_marker() const { return markerflag; }
525
526    double get_rel_attach() const {
527        // return [0..1] according to exact position where element is dropped
528        if (is_line() && (is_branch() || ruler)) return elem->get_rel_pos();
529        return 0.5; // act like "drop on branch-center"
530    }
531};
532
533void       TREE_create_awars(AW_root *aw_root, AW_default db);
534void       TREE_install_update_callbacks(AWT_canvas *ntw);
535void       TREE_insert_jump_option_menu(AW_window *aws, const char *label, const char *awar_name);
536AW_window *TREE_create_settings_window(AW_root *aw_root);
537AW_window *TREE_create_marker_settings_window(AW_root *root);
538
539AWT_graphic_tree *NT_generate_tree(AW_root *root, GBDATA *gb_main, AD_map_viewer_cb map_viewer_cb);
540
541bool TREE_show_branch_remark(AW_device *device, const char *remark_branch, bool is_leaf, const AW::Position& pos, AW_pos alignment, AW_bitset filteri, int bootstrap_min);
542
543#else
544#error TreeDisplay.hxx included twice
545#endif // TREEDISPLAY_HXX
Note: See TracBrowser for help on using the repository browser.