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 | |
---|
21 | #define td_assert(cond) arb_assert(cond) |
---|
22 | |
---|
23 | #define AWAR_DTREE_BASELINEWIDTH "awt/dtree/baselinewidth" |
---|
24 | #define AWAR_DTREE_VERICAL_DIST "awt/dtree/verticaldist" |
---|
25 | #define AWAR_DTREE_AUTO_JUMP "awt/dtree/autojump" |
---|
26 | #define AWAR_DTREE_SHOW_CIRCLE "awt/dtree/show_circle" |
---|
27 | #define AWAR_DTREE_SHOW_BRACKETS "awt/dtree/show_brackets" |
---|
28 | #define AWAR_DTREE_CIRCLE_ZOOM "awt/dtree/circle_zoom" |
---|
29 | #define AWAR_DTREE_CIRCLE_MAX_SIZE "awt/dtree/max_size" |
---|
30 | #define AWAR_DTREE_USE_ELLIPSE "awt/dtree/ellipse" |
---|
31 | #define AWAR_DTREE_GREY_LEVEL "awt/dtree/greylevel" |
---|
32 | |
---|
33 | #define AWAR_DTREE_RADIAL_ZOOM_TEXT "awt/dtree/radial/zoomtext" |
---|
34 | #define AWAR_DTREE_RADIAL_XPAD "awt/dtree/radial/xpadding" |
---|
35 | |
---|
36 | #define AWAR_DTREE_DENDRO_ZOOM_TEXT "awt/dtree/dendro/zoomtext" |
---|
37 | #define AWAR_DTREE_DENDRO_XPAD "awt/dtree/dendro/xpadding" |
---|
38 | |
---|
39 | void awt_create_dtree_awars(AW_root *aw_root, AW_default db); |
---|
40 | |
---|
41 | #define NT_BOX_WIDTH 7 // pixel |
---|
42 | #define NT_ROOT_WIDTH 9 |
---|
43 | #define NT_SELECTED_WIDTH 11 |
---|
44 | |
---|
45 | #define AWT_TREE(ntw) DOWNCAST(AWT_graphic_tree*, (ntw)->gfx) |
---|
46 | |
---|
47 | |
---|
48 | enum AP_tree_display_type { |
---|
49 | AP_TREE_NORMAL, // normal tree display (dendrogram) |
---|
50 | AP_TREE_RADIAL, // radial tree display |
---|
51 | AP_TREE_IRS, // like AP_TREE_NORMAL, with folding line |
---|
52 | AP_LIST_NDS, |
---|
53 | AP_LIST_SIMPLE // simple display only showing name (used at startup to avoid NDS error messages) |
---|
54 | }; |
---|
55 | |
---|
56 | enum AP_tree_jump_type { // bit-values |
---|
57 | AP_JUMP_UNFOLD_GROUPS = 1, |
---|
58 | AP_JUMP_CENTER_IF_VISIBLE = 2, // if already visible -> center (normally only done if IRS-mode or selected was invisible) |
---|
59 | AP_JUMP_BE_VERBOOSE = 4, // tell why nothing happened etc. |
---|
60 | |
---|
61 | // convenience defs: |
---|
62 | AP_JUMP_AUTO = 0, |
---|
63 | AP_JUMP_BY_BUTTON = AP_JUMP_UNFOLD_GROUPS|AP_JUMP_CENTER_IF_VISIBLE|AP_JUMP_BE_VERBOOSE, |
---|
64 | }; |
---|
65 | |
---|
66 | inline bool sort_is_list_style(AP_tree_display_type sort) { return sort == AP_LIST_NDS || sort == AP_LIST_SIMPLE; } |
---|
67 | inline bool sort_is_tree_style(AP_tree_display_type sort) { return !sort_is_list_style(sort); } |
---|
68 | |
---|
69 | |
---|
70 | class AWT_graphic_tree_group_state; |
---|
71 | |
---|
72 | struct AWT_scaled_font_limits { |
---|
73 | double ascent; |
---|
74 | double descent; |
---|
75 | double height; |
---|
76 | double width; |
---|
77 | |
---|
78 | void init(const AW_font_limits& font_limits, double factor) { |
---|
79 | ascent = font_limits.ascent*factor; |
---|
80 | descent = font_limits.descent*factor; |
---|
81 | height = font_limits.height*factor; |
---|
82 | width = font_limits.width*factor; |
---|
83 | } |
---|
84 | }; |
---|
85 | |
---|
86 | enum AD_MAP_VIEWER_TYPE { |
---|
87 | ADMVT_INFO, |
---|
88 | ADMVT_WWW, |
---|
89 | ADMVT_SELECT |
---|
90 | }; |
---|
91 | |
---|
92 | typedef void (*AD_map_viewer_cb)(GBDATA *gbd, AD_MAP_VIEWER_TYPE type); |
---|
93 | |
---|
94 | struct DendroSubtreeLimits { |
---|
95 | double y_branch; // ypos of branch to subtree |
---|
96 | double y_top; // top ypos of whole subtree |
---|
97 | double y_bot; // bottom ypos of whole subtree |
---|
98 | double x_right; // rightmost xpos of whole subtree |
---|
99 | |
---|
100 | void combine(const DendroSubtreeLimits& other) { |
---|
101 | y_top = std::min(y_top, other.y_top); |
---|
102 | y_bot = std::max(y_bot, other.y_bot); |
---|
103 | x_right = std::max(x_right, other.x_right); |
---|
104 | } |
---|
105 | }; |
---|
106 | |
---|
107 | struct AWT_command_data { |
---|
108 | /*! any kind of data which has to be stored between different events (e.g. to support drag&drop) |
---|
109 | * Purpose of this class is to allow to delete such data w/o knowing anything else. |
---|
110 | */ |
---|
111 | virtual ~AWT_command_data() {} |
---|
112 | }; |
---|
113 | |
---|
114 | class AWT_graphic_tree : public AWT_graphic, virtual Noncopyable { |
---|
115 | char *species_name; |
---|
116 | AW::Position cursor; |
---|
117 | |
---|
118 | int baselinewidth; |
---|
119 | int show_brackets; |
---|
120 | int show_circle; |
---|
121 | int use_ellipse; |
---|
122 | float circle_zoom_factor; |
---|
123 | float circle_max_size; |
---|
124 | |
---|
125 | int zombies; // # of zombies during last load() |
---|
126 | int duplicates; // # of duplicates during last load() |
---|
127 | |
---|
128 | AW_pos paint_irs_sub_tree(AP_tree *node, AW_pos x_offset); // returns y pos |
---|
129 | |
---|
130 | void unload(); |
---|
131 | |
---|
132 | // variables - tree compatibility |
---|
133 | |
---|
134 | AP_tree * tree_proto; |
---|
135 | bool link_to_database; // link on load ? |
---|
136 | |
---|
137 | double list_tree_ruler_y; |
---|
138 | double irs_tree_ruler_scale_factor; |
---|
139 | |
---|
140 | AWT_scaled_font_limits scaled_font; |
---|
141 | double scaled_branch_distance; // vertical distance between branches (may be extra-scaled in options) |
---|
142 | |
---|
143 | AW_pos grey_level; |
---|
144 | |
---|
145 | AW_device *disp_device; // device for recursive functions |
---|
146 | |
---|
147 | const AW_bitset line_filter, vert_line_filter, mark_filter, group_bracket_filter, bs_circle_filter; |
---|
148 | const AW_bitset leaf_text_filter, group_text_filter, remark_text_filter, other_text_filter; |
---|
149 | const AW_bitset ruler_filter, root_filter; |
---|
150 | |
---|
151 | bool nds_show_all; |
---|
152 | |
---|
153 | AD_map_viewer_cb map_viewer_cb; |
---|
154 | AWT_command_data *cmd_data; |
---|
155 | |
---|
156 | void scale_text_koordinaten(AW_device *device, int gc, double& x, double& y, double orientation, int flag); |
---|
157 | |
---|
158 | // functions to compute displayinformation |
---|
159 | |
---|
160 | void show_dendrogram(AP_tree *at, AW::Position& pen, DendroSubtreeLimits& limits); |
---|
161 | |
---|
162 | void show_radial_tree(AP_tree *at, |
---|
163 | double x_center, |
---|
164 | double y_center, |
---|
165 | double tree_sprad, |
---|
166 | double tree_orientation, |
---|
167 | double x_root, |
---|
168 | double y_root); |
---|
169 | |
---|
170 | void show_nds_list(GBDATA * gb_main, bool use_nds); |
---|
171 | void show_irs_tree(AP_tree *at, double height); |
---|
172 | |
---|
173 | void box(int gc, const AW::Position& pos, int pixel_width, bool filled); |
---|
174 | void filled_box(int gc, const AW::Position& pos, int pixel_width) { box(gc, pos, pixel_width, true); } |
---|
175 | void empty_box(int gc, const AW::Position& pos, int pixel_width) { box(gc, pos, pixel_width, false); } |
---|
176 | void diamond(int gc, const AW::Position& pos, int pixel_width); |
---|
177 | |
---|
178 | const char *ruler_awar(const char *name); |
---|
179 | |
---|
180 | void set_line_attributes_for(AP_tree *at) const { |
---|
181 | disp_device->set_line_attributes(at->gr.gc, at->get_linewidth()+baselinewidth, AW_SOLID); |
---|
182 | } |
---|
183 | |
---|
184 | virtual void read_tree_settings(); |
---|
185 | void update_structure() { get_root_node()->compute_tree(); } |
---|
186 | void apply_zoom_settings_for_treetype(AWT_canvas *ntw); |
---|
187 | |
---|
188 | int draw_branch_line(int gc, const AW::Position& root, const AW::Position& leaf, AW_bitset filter) { |
---|
189 | const AW_click_cd *old = disp_device->get_click_cd(); |
---|
190 | td_assert(old && old->get_cd1() && !old->get_cd2()); // cd1 should be the node |
---|
191 | |
---|
192 | AW_click_cd branch(disp_device, old->get_cd1(), (AW_CL)"branch"); |
---|
193 | return disp_device->line(gc, root, leaf, filter); |
---|
194 | } |
---|
195 | |
---|
196 | bool warn_inappropriate_mode(AWT_COMMAND_MODE mode); |
---|
197 | |
---|
198 | protected: |
---|
199 | void store_command_data(AWT_command_data *new_cmd_data) { |
---|
200 | delete cmd_data; |
---|
201 | cmd_data = new_cmd_data; |
---|
202 | } |
---|
203 | AWT_command_data *get_command_data() { return cmd_data; } |
---|
204 | |
---|
205 | public: |
---|
206 | |
---|
207 | // *********** read only variables !!! |
---|
208 | |
---|
209 | AW_root *aw_root; |
---|
210 | AP_tree_display_type tree_sort; |
---|
211 | AP_tree *displayed_root; // root node of shown (sub-)tree; differs from real root if tree is zoomed logically |
---|
212 | AP_tree_root *tree_static; |
---|
213 | GBDATA *gb_main; |
---|
214 | |
---|
215 | // *********** public section |
---|
216 | |
---|
217 | AWT_graphic_tree(AW_root *aw_root, GBDATA *gb_main, AD_map_viewer_cb map_viewer_cb); |
---|
218 | ~AWT_graphic_tree() OVERRIDE; |
---|
219 | |
---|
220 | AP_tree *get_root_node() { return tree_static ? tree_static->get_root_node() : NULL; } |
---|
221 | bool is_logically_zoomed() { return displayed_root != get_root_node(); } |
---|
222 | |
---|
223 | void init(RootedTreeNodeFactory *nodeMaker_, AliView *aliview, AP_sequence *seq_prototype, bool link_to_database_, bool insert_delete_cbs); |
---|
224 | AW_gc_manager init_devices(AW_window *, AW_device *, AWT_canvas *ntw) OVERRIDE; |
---|
225 | |
---|
226 | void show(AW_device *device) OVERRIDE; |
---|
227 | const AW::Position& get_cursor() const { return cursor; } |
---|
228 | |
---|
229 | void info(AW_device *device, AW_pos x, AW_pos y, AW_clicked_line *cl, AW_clicked_text *ct) OVERRIDE; |
---|
230 | |
---|
231 | private: |
---|
232 | void handle_key(AW_device *device, AWT_graphic_event& event); |
---|
233 | public: |
---|
234 | void handle_command(AW_device *device, AWT_graphic_event& event) OVERRIDE; |
---|
235 | |
---|
236 | void mark_species_in_tree(AP_tree *at, int mark); |
---|
237 | void mark_species_in_tree_that(AP_tree *at, int mark, int (*condition)(GBDATA*, void*), void *cd); |
---|
238 | |
---|
239 | void mark_species_in_rest_of_tree(AP_tree *at, int mark); |
---|
240 | void mark_species_in_rest_of_tree_that(AP_tree *at, int mark, int (*condition)(GBDATA*, void*), void *cd); |
---|
241 | |
---|
242 | bool tree_has_marks(AP_tree *at); |
---|
243 | bool rest_tree_has_marks(AP_tree *at); |
---|
244 | |
---|
245 | void detect_group_state(AP_tree *at, AWT_graphic_tree_group_state *state, AP_tree *skip_this_son); |
---|
246 | |
---|
247 | int group_tree(AP_tree *at, int mode, int color_group); |
---|
248 | void group_rest_tree(AP_tree *at, int mode, int color_group); |
---|
249 | void reorder_tree(TreeOrder mode); |
---|
250 | GB_ERROR create_group(AP_tree * at) __ATTR__USERESULT; |
---|
251 | void toggle_group(AP_tree * at); |
---|
252 | GB_ERROR load(GBDATA *gb_main, const char *name, AW_CL, AW_CL) OVERRIDE __ATTR__USERESULT; |
---|
253 | GB_ERROR save(GBDATA *gb_main, const char *name, AW_CL cd1, AW_CL cd2) OVERRIDE __ATTR__USERESULT; |
---|
254 | int check_update(GBDATA *gb_main) OVERRIDE; // reload tree if needed |
---|
255 | void update(GBDATA *gb_main) OVERRIDE; |
---|
256 | void set_tree_type(AP_tree_display_type type, AWT_canvas *ntw); |
---|
257 | |
---|
258 | double get_irs_tree_ruler_scale_factor() const { return irs_tree_ruler_scale_factor; } |
---|
259 | void show_ruler(AW_device *device, int gc); |
---|
260 | void get_zombies_and_duplicates(int& zomb, int& dups) const { zomb = zombies; dups = duplicates; } |
---|
261 | |
---|
262 | #if defined(UNIT_TESTS) // UT_DIFF |
---|
263 | friend class fake_AWT_graphic_tree; |
---|
264 | #endif |
---|
265 | }; |
---|
266 | |
---|
267 | class ClickedTarget { |
---|
268 | /*! Represents any target corresponding to some (mouse-)position in the tree display. |
---|
269 | * |
---|
270 | * The target is e.g. used as target for keystrokes or mouse clicks. |
---|
271 | * |
---|
272 | * For AP_LIST_NDS, this only represents the species (w/o any tree information). |
---|
273 | * For other tree display modes, this represents a specific tree node. |
---|
274 | * |
---|
275 | * The space outside the tree does represent the whole tree (aka the root-node). |
---|
276 | * (the necessary distance to the tree-structure/-text is defined by AWT_CATCH) |
---|
277 | */ |
---|
278 | |
---|
279 | AP_tree *tree_node; |
---|
280 | GBDATA *gb_species; |
---|
281 | bool ruler; |
---|
282 | bool branch; |
---|
283 | |
---|
284 | const AW_clicked_element *elem; |
---|
285 | |
---|
286 | void init() { |
---|
287 | tree_node = NULL; |
---|
288 | gb_species = NULL; |
---|
289 | ruler = false; |
---|
290 | branch = false; |
---|
291 | } |
---|
292 | |
---|
293 | void identify(AWT_graphic_tree *agt) { |
---|
294 | init(); |
---|
295 | if (elem && elem->exists) { |
---|
296 | const char *what = (const char*)elem->cd2(); |
---|
297 | |
---|
298 | if (what) { |
---|
299 | if (strcmp(what, "species") == 0) { // entry in NDS list |
---|
300 | gb_species = (GBDATA*)elem->cd1(); |
---|
301 | td_assert(gb_species); |
---|
302 | } |
---|
303 | else if (strcmp(what, "ruler") == 0) { |
---|
304 | ruler = !elem->cd1(); |
---|
305 | } |
---|
306 | else if (strcmp(what, "branch") == 0) { |
---|
307 | branch = true; // indicates that a line really IS the branch (opposed to other branch-related lines like e.g. group-brackets) |
---|
308 | } |
---|
309 | else { |
---|
310 | td_assert(0); // unknown element type |
---|
311 | } |
---|
312 | } |
---|
313 | |
---|
314 | if (!(gb_species || ruler)) { |
---|
315 | tree_node = (AP_tree*)elem->cd1(); |
---|
316 | td_assert(branch || !what); |
---|
317 | } |
---|
318 | } |
---|
319 | else { // use whole tree if mouse does not point to a subtree |
---|
320 | tree_node = agt ? agt->get_root_node() : NULL; |
---|
321 | } |
---|
322 | td_assert(implicated(branch, tree_node)); |
---|
323 | } |
---|
324 | |
---|
325 | public: |
---|
326 | |
---|
327 | ClickedTarget(AWT_graphic_tree *agt, const AW_clicked_element *clicked) : elem(clicked) { |
---|
328 | // uses root of tree as target, when a position outside of the tree is selected |
---|
329 | // (e.g. used for key-commands) |
---|
330 | identify(agt); |
---|
331 | } |
---|
332 | ClickedTarget(const AW_clicked_element *clicked) : elem(clicked) { |
---|
333 | // accept only normal branches as targets |
---|
334 | identify(NULL); |
---|
335 | } |
---|
336 | |
---|
337 | const AW_clicked_element *element() const { return elem; } |
---|
338 | AP_tree *node() const { return tree_node; } |
---|
339 | GBDATA *species() const { return gb_species; } |
---|
340 | |
---|
341 | bool is_text() const { return elem && elem->is_text(); } |
---|
342 | bool is_line() const { return elem && elem->is_line(); } |
---|
343 | bool is_branch() const { return branch; } |
---|
344 | bool is_ruler() const { return ruler; } |
---|
345 | |
---|
346 | double get_rel_attach() const { |
---|
347 | // return [0..1] according to exact position where element is dropped |
---|
348 | if (is_line() && (is_branch() || ruler)) return elem->get_rel_pos(); |
---|
349 | return 0.5; // act like "drop on branch-center" |
---|
350 | } |
---|
351 | }; |
---|
352 | |
---|
353 | AWT_graphic_tree *NT_generate_tree(AW_root *root, GBDATA *gb_main, AD_map_viewer_cb map_viewer_cb); |
---|
354 | bool AWT_show_branch_remark(AW_device *device, const char *remark_branch, bool is_leaf, AW_pos x, AW_pos y, AW_pos alignment, AW_bitset filteri); |
---|
355 | |
---|
356 | #else |
---|
357 | #error TreeDisplay.hxx included twice |
---|
358 | #endif // TREEDISPLAY_HXX |
---|