| 1 | #include <stdio.h> |
|---|
| 2 | |
|---|
| 3 | #include <math.h> |
|---|
| 4 | #include <string.h> |
|---|
| 5 | #include <arbdb.h> |
|---|
| 6 | #include <arbdbt.h> |
|---|
| 7 | #include <aw_root.hxx> |
|---|
| 8 | #include <aw_device.hxx> |
|---|
| 9 | #include <aw_window.hxx> |
|---|
| 10 | |
|---|
| 11 | #include <awt_canvas.hxx> |
|---|
| 12 | #include <awt_nds.hxx> |
|---|
| 13 | #include "awt_tree.hxx" |
|---|
| 14 | #include "awt_dtree.hxx" |
|---|
| 15 | #include <aw_awars.hxx> |
|---|
| 16 | |
|---|
| 17 | enum AWT_IRS_TREE_TYPES { |
|---|
| 18 | AWT_IRS_HIDDEN_TREE, |
|---|
| 19 | AWT_IRS_NORMAL_TREE |
|---|
| 20 | }; |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | enum IRS_PRUNE_LEVEL { |
|---|
| 24 | IRS_NOPRUNE |
|---|
| 25 | }; |
|---|
| 26 | |
|---|
| 27 | /* *********************** paint sub tree ************************ */ |
|---|
| 28 | |
|---|
| 29 | #define IS_HIDDEN(node) (type == AWT_IRS_HIDDEN_TREE && node->gr.gc>0) |
|---|
| 30 | |
|---|
| 31 | const int MAXSHOWNNODES = 5000; // Something like max screen height/minimum font size |
|---|
| 32 | const int tipBoxSize = 4; |
|---|
| 33 | const int nodeBoxWidth = 5; |
|---|
| 34 | |
|---|
| 35 | static struct { |
|---|
| 36 | GB_BOOL ftrst_species; |
|---|
| 37 | int y; |
|---|
| 38 | int min_y; |
|---|
| 39 | int max_y; |
|---|
| 40 | int ruler_y; |
|---|
| 41 | int min_x; |
|---|
| 42 | int max_x; |
|---|
| 43 | int step_y; |
|---|
| 44 | double x_scale; |
|---|
| 45 | AW_device *device; |
|---|
| 46 | |
|---|
| 47 | int nodes_xpos[MAXSHOWNNODES]; // needed for Query results drawing |
|---|
| 48 | int nodes_ypos[MAXSHOWNNODES]; |
|---|
| 49 | AP_tree *nodes_id[MAXSHOWNNODES]; |
|---|
| 50 | int nodes_ntip; // counts the tips stored in nodes_xx |
|---|
| 51 | int nodes_nnnodes; // counts the inner nodes (reverse counter !!!) |
|---|
| 52 | |
|---|
| 53 | int font_height_2; |
|---|
| 54 | enum IRS_PRUNE_LEVEL pruneLevel; |
|---|
| 55 | int is_size_device; |
|---|
| 56 | } irs_gl; |
|---|
| 57 | |
|---|
| 58 | void draw_top_seperator(){ |
|---|
| 59 | int gc = AWT_GC_GROUPS; |
|---|
| 60 | int y; |
|---|
| 61 | irs_gl.ftrst_species = GB_FALSE; |
|---|
| 62 | if (!irs_gl.is_size_device){ |
|---|
| 63 | for (y = irs_gl.min_y; y< irs_gl.min_y+4;y++){ |
|---|
| 64 | irs_gl.device->line(gc,-10000,y,10000,y,-1,(AW_CL)0,(AW_CL)0); |
|---|
| 65 | } |
|---|
| 66 | } |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | int AWT_graphic_tree::paint_irs_sub_tree(AP_tree *node, int x_offset, int type){ |
|---|
| 70 | |
|---|
| 71 | int left_y; |
|---|
| 72 | int left_x; |
|---|
| 73 | int right_y; |
|---|
| 74 | int right_x; |
|---|
| 75 | |
|---|
| 76 | |
|---|
| 77 | // if (irs_gl.y > irs_gl.max_clipped_y) irs_gl.max_clipped_y = irs_gl.max_y; // @@@ ralf |
|---|
| 78 | |
|---|
| 79 | /* *********************** Check clipping rectangle ************************ */ |
|---|
| 80 | if (!irs_gl.is_size_device){ |
|---|
| 81 | if (irs_gl.y > irs_gl.max_y) { |
|---|
| 82 | return irs_gl.max_y; |
|---|
| 83 | } |
|---|
| 84 | int height_of_subtree = irs_gl.step_y*node->gr.view_sum; |
|---|
| 85 | if (irs_gl.y + height_of_subtree < irs_gl.min_y) { |
|---|
| 86 | irs_gl.y+= height_of_subtree; |
|---|
| 87 | return irs_gl.min_y; |
|---|
| 88 | } |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | |
|---|
| 92 | |
|---|
| 93 | /* *********************** i'm a leaf ************************ */ |
|---|
| 94 | if (node->is_leaf) { |
|---|
| 95 | irs_gl.y+=irs_gl.step_y; |
|---|
| 96 | if (irs_gl.ftrst_species) { |
|---|
| 97 | draw_top_seperator(); |
|---|
| 98 | } |
|---|
| 99 | int x = x_offset; |
|---|
| 100 | int y = irs_gl.y + irs_gl.font_height_2; |
|---|
| 101 | int gc = node->gr.gc; |
|---|
| 102 | |
|---|
| 103 | |
|---|
| 104 | |
|---|
| 105 | if (node->name && node->name[0] == this->species_name[0] && |
|---|
| 106 | !strcmp(node->name,this->species_name)) { |
|---|
| 107 | x_cursor = x; y_cursor = irs_gl.y; |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | const char *str = 0; |
|---|
| 111 | if (!irs_gl.is_size_device){ |
|---|
| 112 | if (node->gb_node && GB_read_flag(node->gb_node)){ |
|---|
| 113 | NT_scalebox(gc,x, irs_gl.y, NT_BOX_WIDTH); |
|---|
| 114 | } |
|---|
| 115 | str = make_node_text_nds(gb_main,node->gb_node,0,node->get_gbt_tree(), tree_name); |
|---|
| 116 | irs_gl.device->text(gc,str, x, y,0.0,-1, (AW_CL)node,0); |
|---|
| 117 | } |
|---|
| 118 | return irs_gl.y; |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | /* *********************** i'm a grouped subtree ************************ */ |
|---|
| 122 | int last_y = irs_gl.y; |
|---|
| 123 | const char *node_string = 0; |
|---|
| 124 | if (node->gb_node){ |
|---|
| 125 | if (!irs_gl.is_size_device){ |
|---|
| 126 | if (!node->father) { // root node - don't try to get taxonomy |
|---|
| 127 | node_string = tree_name; |
|---|
| 128 | } |
|---|
| 129 | else { |
|---|
| 130 | node_string = make_node_text_nds(gb_main,node->gb_node,0,node->get_gbt_tree(), tree_name); |
|---|
| 131 | } |
|---|
| 132 | }else{ |
|---|
| 133 | node_string = "0123456789"; |
|---|
| 134 | } |
|---|
| 135 | } |
|---|
| 136 | if (node->gr.grouped) { // no recursion here just a group symbol !!! |
|---|
| 137 | int vsize = node->gr.view_sum * irs_gl.step_y; |
|---|
| 138 | int y_center = irs_gl.y + (vsize>>1) + irs_gl.step_y; |
|---|
| 139 | if ( irs_gl.y >= irs_gl.min_y) { |
|---|
| 140 | if (irs_gl.ftrst_species) { // A name of a group just under the seperator |
|---|
| 141 | draw_top_seperator(); |
|---|
| 142 | } |
|---|
| 143 | int topy = irs_gl.y+irs_gl.step_y - 2; |
|---|
| 144 | int boty = irs_gl.y+irs_gl.step_y+ vsize + 2; |
|---|
| 145 | int rx = x_offset + vsize + vsize; |
|---|
| 146 | int gc = AWT_GC_GROUPS; |
|---|
| 147 | |
|---|
| 148 | // draw group box (unclosed on right hand): |
|---|
| 149 | irs_gl.device->line(gc, x_offset, topy, rx, topy, -1, (AW_CL)node, 0); |
|---|
| 150 | irs_gl.device->line(gc, x_offset, topy, x_offset, boty, -1, (AW_CL)node, 0); |
|---|
| 151 | irs_gl.device->line(gc, x_offset, boty, rx, boty, -1, (AW_CL)node, 0); |
|---|
| 152 | |
|---|
| 153 | irs_gl.device->box(node->gr.gc, true, x_offset - (tipBoxSize>>1), topy - (tipBoxSize>>1), tipBoxSize, tipBoxSize, mark_filter, (AW_CL)node, 0); |
|---|
| 154 | irs_gl.device->box(node->gr.gc, true, x_offset+2, irs_gl.y+irs_gl.step_y, vsize, vsize, -1, (AW_CL)node, 0); |
|---|
| 155 | |
|---|
| 156 | irs_gl.y += vsize + 2*irs_gl.step_y ; |
|---|
| 157 | if (node_string) { |
|---|
| 158 | const char *s = GBS_global_string("%s (%i)",node_string,node->gr.leave_sum); |
|---|
| 159 | irs_gl.device->text(node->gr.gc,s,x_offset + vsize + 10 + nodeBoxWidth, |
|---|
| 160 | y_center + (irs_gl.step_y>>1),0.0, // A node name should be displayed |
|---|
| 161 | -1, (AW_CL)node, 0); |
|---|
| 162 | } |
|---|
| 163 | } |
|---|
| 164 | else{ |
|---|
| 165 | irs_gl.y+= vsize; |
|---|
| 166 | y_center = irs_gl.min_y; |
|---|
| 167 | if ( irs_gl.y > irs_gl.min_y) { |
|---|
| 168 | irs_gl.y = irs_gl.min_y; |
|---|
| 169 | } |
|---|
| 170 | } |
|---|
| 171 | return y_center; |
|---|
| 172 | } |
|---|
| 173 | |
|---|
| 174 | // ungrouped groups go here |
|---|
| 175 | |
|---|
| 176 | if ( irs_gl.pruneLevel != IRS_NOPRUNE ){ |
|---|
| 177 | node_string = 0; |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | /* *********************** i'm a labeled node ************************ */ |
|---|
| 181 | /* If I have only one child + pruneLevel != MAXPRUNE -> no labeling */ |
|---|
| 182 | |
|---|
| 183 | if (node_string != NULL) { // A node name should be displayed |
|---|
| 184 | if (last_y >= irs_gl.min_y) { |
|---|
| 185 | if (irs_gl.ftrst_species) { // A name of a group just under the seperator |
|---|
| 186 | draw_top_seperator(); |
|---|
| 187 | } |
|---|
| 188 | last_y = irs_gl.y + irs_gl.step_y; |
|---|
| 189 | }else{ |
|---|
| 190 | last_y = irs_gl.min_y; |
|---|
| 191 | irs_gl.min_y += int(irs_gl.step_y * 1.8); |
|---|
| 192 | } |
|---|
| 193 | irs_gl.y+=int(irs_gl.step_y * 1.8); |
|---|
| 194 | int gc = AWT_GC_GROUPS; |
|---|
| 195 | irs_gl.device->line(gc,x_offset,last_y, x_offset+400, last_y, -1, (AW_CL)node,0); |
|---|
| 196 | |
|---|
| 197 | irs_gl.device->box(node->gr.gc, true, x_offset- (tipBoxSize>>1), last_y- (tipBoxSize>>1), tipBoxSize,tipBoxSize, mark_filter, (AW_CL)node,0); |
|---|
| 198 | const char *s = GBS_global_string("%s (%i)",node_string,node->gr.leave_sum); |
|---|
| 199 | irs_gl.device->text(node->gr.gc,s, x_offset + 10 + nodeBoxWidth, last_y + irs_gl.step_y + 1,0.0, -1, (AW_CL)node,0); |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | /* *********************** connect two nodes == draw branches ************************ */ |
|---|
| 203 | int y_center; |
|---|
| 204 | |
|---|
| 205 | left_x = (int)(x_offset + 0.9 + irs_gl.x_scale * node->leftlen); |
|---|
| 206 | left_y = paint_irs_sub_tree(node->leftson, left_x, type); |
|---|
| 207 | |
|---|
| 208 | right_x = int(x_offset + 0.9 + irs_gl.x_scale * node->rightlen); |
|---|
| 209 | right_y = paint_irs_sub_tree(node->rightson, right_x, type); |
|---|
| 210 | |
|---|
| 211 | |
|---|
| 212 | /* *********************** draw structure ************************ */ |
|---|
| 213 | |
|---|
| 214 | if (left_y > irs_gl.min_y){ |
|---|
| 215 | if (left_y < irs_gl.max_y){ // clip y on top border |
|---|
| 216 | if (node->leftson->remark_branch ) { |
|---|
| 217 | AWT_show_remark_branch(disp_device, node->leftson->remark_branch, node->leftson->is_leaf, left_x, left_y, 1, text_filter, (AW_CL)node->leftson, 0); |
|---|
| 218 | } |
|---|
| 219 | irs_gl.device->line(node->leftson->gr.gc,x_offset,left_y, left_x, left_y, -1, (AW_CL)node->leftson,0); // *** |
|---|
| 220 | } |
|---|
| 221 | }else{ |
|---|
| 222 | left_y = irs_gl.min_y; |
|---|
| 223 | } |
|---|
| 224 | |
|---|
| 225 | y_center = (left_y + right_y) / 2; // clip conter on bottom border |
|---|
| 226 | |
|---|
| 227 | if (right_y > irs_gl.min_y && right_y < irs_gl.max_y) { // visible right branch in lower part of display |
|---|
| 228 | |
|---|
| 229 | if (node->rightson->remark_branch ) { |
|---|
| 230 | AWT_show_remark_branch(disp_device, node->rightson->remark_branch, node->rightson->is_leaf, right_x, right_y, 1, text_filter, (AW_CL)node->rightson, 0); |
|---|
| 231 | } |
|---|
| 232 | irs_gl.device->line(node->rightson->gr.gc,x_offset,right_y, right_x, right_y, -1, (AW_CL)node->rightson,0); |
|---|
| 233 | } |
|---|
| 234 | |
|---|
| 235 | irs_gl.device->line(node->leftson->gr.gc, x_offset,y_center,x_offset, left_y, -1, (AW_CL)node,0); |
|---|
| 236 | irs_gl.device->line(node->rightson->gr.gc,x_offset,y_center,x_offset, right_y, -1, (AW_CL)node,0); |
|---|
| 237 | irs_gl.ruler_y = y_center; |
|---|
| 238 | |
|---|
| 239 | if (node_string != 0) { // A node name should be displayed |
|---|
| 240 | irs_gl.y+=irs_gl.step_y /2; |
|---|
| 241 | int gc = AWT_GC_GROUPS; |
|---|
| 242 | irs_gl.device->line(gc,x_offset-1,irs_gl.y, x_offset+400, irs_gl.y, -1,(AW_CL)node,0); |
|---|
| 243 | irs_gl.device->line(gc,x_offset-1,last_y, x_offset-1, irs_gl.y, -1,(AW_CL)node,0); |
|---|
| 244 | } |
|---|
| 245 | if (0 && !irs_gl.is_size_device){ |
|---|
| 246 | if (irs_gl.nodes_nnnodes>irs_gl.nodes_ntip+1){ |
|---|
| 247 | irs_gl.nodes_nnnodes--; |
|---|
| 248 | irs_gl.nodes_xpos[irs_gl.nodes_nnnodes] = x_offset; |
|---|
| 249 | irs_gl.nodes_ypos[irs_gl.nodes_nnnodes] = y_center; |
|---|
| 250 | irs_gl.nodes_id[irs_gl.nodes_nnnodes] = node; |
|---|
| 251 | } |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | return y_center; |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | int AWT_graphic_tree::draw_slot(int x_offset, GB_BOOL draw_at_tips){ |
|---|
| 258 | int maxx = x_offset; |
|---|
| 259 | int i; |
|---|
| 260 | int no_compress = 0; |
|---|
| 261 | if (!draw_at_tips) no_compress = 1; |
|---|
| 262 | for (i=0;i<irs_gl.nodes_ntip;i++){ |
|---|
| 263 | AP_tree *tip = irs_gl.nodes_id[i]; |
|---|
| 264 | const char *str = make_node_text_nds(gb_main,tip->gb_node,no_compress,tip->get_gbt_tree(), tree_name); |
|---|
| 265 | int len = irs_gl.device->get_string_size(tip->gr.gc,str,0); |
|---|
| 266 | int x = 0; |
|---|
| 267 | int y = irs_gl.nodes_ypos[i]+ irs_gl.font_height_2; |
|---|
| 268 | if (draw_at_tips) { |
|---|
| 269 | x = x_offset + irs_gl.nodes_xpos[i]; |
|---|
| 270 | }else{ |
|---|
| 271 | irs_gl.device->text(tip->gr.gc,str,x,irs_gl.nodes_ypos[i],0,-1,(AW_CL)tip,0); |
|---|
| 272 | } |
|---|
| 273 | if (x + len > maxx) maxx = x+len; |
|---|
| 274 | irs_gl.device->text(tip->gr.gc,str, x, y,0.0,-1, (AW_CL)tip,0); |
|---|
| 275 | } |
|---|
| 276 | return maxx; |
|---|
| 277 | } |
|---|
| 278 | |
|---|
| 279 | |
|---|
| 280 | void AWT_graphic_tree::show_irs_tree(AP_tree *at,AW_device *device, int height){ |
|---|
| 281 | device->push_clip_scale(); |
|---|
| 282 | int x; |
|---|
| 283 | int y; |
|---|
| 284 | const AW_font_information *font_info = device->get_font_information(AWT_GC_SELECTED,0); |
|---|
| 285 | device->rtransform(0,0,x,y); // calculate real world coordinates of left/upper screen border |
|---|
| 286 | int clipped_l,clipped_t; |
|---|
| 287 | int clipped_r,clipped_b; |
|---|
| 288 | device->rtransform(device->clip_rect.l,device->clip_rect.t,clipped_l,clipped_t); |
|---|
| 289 | device->rtransform(device->clip_rect.r,device->clip_rect.b,clipped_r,clipped_b); |
|---|
| 290 | |
|---|
| 291 | irs_gl.nodes_nnnodes = MAXSHOWNNODES; |
|---|
| 292 | irs_gl.nodes_ntip = 0; |
|---|
| 293 | irs_gl.font_height_2 = font_info->max_letter.ascent/2; |
|---|
| 294 | irs_gl.device = device; |
|---|
| 295 | irs_gl.ftrst_species = GB_TRUE; |
|---|
| 296 | irs_gl.y = 0; |
|---|
| 297 | irs_gl.min_x = x; |
|---|
| 298 | irs_gl.max_x = 100; |
|---|
| 299 | irs_gl.min_y = y; |
|---|
| 300 | irs_gl.max_y = clipped_b; |
|---|
| 301 | irs_gl.ruler_y = 0; |
|---|
| 302 | irs_gl.step_y = height; |
|---|
| 303 | irs_gl.x_scale = 600.0 / at->gr.tree_depth; |
|---|
| 304 | irs_gl.is_size_device = 0; |
|---|
| 305 | |
|---|
| 306 | if (irs_gl.device->type() == AW_DEVICE_SIZE){ |
|---|
| 307 | irs_gl.is_size_device = 1; |
|---|
| 308 | } |
|---|
| 309 | |
|---|
| 310 | paint_irs_sub_tree(at,0,AWT_IRS_NORMAL_TREE ); |
|---|
| 311 | |
|---|
| 312 | // provide some information for ruler : |
|---|
| 313 | y_pos = irs_gl.ruler_y; |
|---|
| 314 | irs_tree_ruler_scale_factor = irs_gl.x_scale; |
|---|
| 315 | |
|---|
| 316 | if (irs_gl.is_size_device){ |
|---|
| 317 | irs_gl.device->invisible(0,irs_gl.min_x,irs_gl.y + (irs_gl.min_y-y) + 200,-1,0,0); |
|---|
| 318 | } |
|---|
| 319 | device->pop_clip_scale(); |
|---|
| 320 | } |
|---|