ARB
irstree_display.cxx
Go to the documentation of this file.
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 
16 using namespace AW;
17 
18 // *********************** paint sub tree ************************
19 
20 const int TIP_BOX_SIZE = 3;
21 
22 struct IRS_data {
25  AW_pos min_y; // ypos of folding line
30  AW_pos fold_x1, fold_x2;
31 
33  double x_scale;
34 
37 
38  AW_pos gap; // between group frame and (box or text)
39  AW_pos openGroupExtra; // extra y-size of unfolded groups
40 
42 
44 
46  if (draw_separator) {
47  if (!is_size_device) {
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 };
57 static IRS_data IRS;
58 
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 
75 AW_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.y += 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 
298 void 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;
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 }
bool draw_separator
AW_pos halfstep_y
double x_scale
long AW_bitset
Definition: aw_base.hxx:44
unsigned view_sum
Definition: AP_Tree.hxx:159
const AW_bitset AW_PRINTER_CLIP
Definition: aw_device.hxx:41
const AW_bitset AW_SCREEN
Definition: aw_device.hxx:34
void set_line_attributes(int gc, short width, AW_linestyle style)
Definition: AW_device.cxx:465
#define td_assert(cond)
Definition: Group.hxx:18
bool is_clade() const
Definition: TreeNode.h:439
double right() const
bool is_folded_group() const
Definition: AP_Tree.hxx:348
AP_tree_members gr
Definition: AP_Tree.hxx:214
AW_bitset sep_filter
static IRS_data IRS
AW_pos onePixel
const char * count
bool hasName(const char *Name) const
Definition: AP_Tree.hxx:374
GBT_LEN leftlen
Definition: TreeNode.h:132
AW_pos fold_x1
void draw_top_separator_once(AW_device *device)
double AW_pos
Definition: aw_base.hxx:29
AW_pos openGroupExtra
const char * make_node_text_nds(GBDATA *gb_main, GBDATA *gbd, NDS_Type mode, TreeNode *species, const char *tree_name)
Definition: nds.cxx:855
AW_pos fold_x2
bool is_size_device
bool is_son_of_root() const
Definition: TreeNode.h:215
const double & ypos() const
unsigned name_len
static int group[MAXN+1]
Definition: ClustalV.cxx:65
bool line(int gc, const AW::LineVector &Line, AW_bitset filteri=AW_ALL_DEVICES_SCALED)
Definition: aw_device.hxx:430
const double & y() const
int GB_read_flag(GBDATA *gbd)
Definition: arbdb.cxx:2784
Vector adjust_text
GBT_LEN rightlen
Definition: TreeNode.h:132
AW_pos Y_correction_for_IRS()
double bottom() const
double left() const
bool is_leaf() const
Definition: TreeNode.h:171
long AW_CL
Definition: cb.h:21
#define NT_BOX_WIDTH
Definition: TreeDisplay.hxx:72
unsigned count_len
AW_pos tree_depth
GBDATA * gb_node
Definition: TreeNode.h:133
GBDATA * gb_main
Definition: adname.cxx:33
const int TIP_BOX_SIZE
static int info[maxsites+1]
const Position Origin
uint32_t gc
Definition: AP_Tree.hxx:152
float max_tree_depth
Definition: AP_Tree.hxx:161
bool is_normal_group() const
Definition: TreeNode.h:429