40 #define RULER_LINEWIDTH "ruler/ruler_width" // line width of ruler
41 #define RULER_SIZE "ruler/size"
43 #define DEFAULT_RULER_LINEWIDTH tree_defaults::LINEWIDTH
44 #define DEFAULT_RULER_LENGTH tree_defaults::LENGTH
46 int TREE_canvas::count = 0;
69 GraphicTreeCallback AWT_graphic_tree::group_changed_cb = makeGraphicTreeCallback(
nocb);
89 "Branch remarks$#3d8a99",
90 "+-Bootstrap$#abe3ff",
"-B.(limited)$#cfe9ff",
91 "-IRS group box$#000",
93 "Some marked$#d9c45c",
95 "Zombies etc.$#7aa3cc",
97 "+-None (black)$#000000",
"-All (white)$#ffffff",
99 "+-P1(red)$#ff0000",
"+-P2(green)$#00ff00",
"-P3(blue)$#0000ff",
100 "+-P4(orange)$#ffd060",
"+-P5(aqua)$#40ffc0",
"-P6(purple)$#c040ff",
101 "+-P7(1&2,yellow)$#ffff00",
"+-P8(2&3,cyan)$#00ffff",
"-P9(3&1,magenta)$#ff00ff",
102 "+-P10(lawn)$#c0ff40",
"+-P11(skyblue)$#40c0ff",
"-P12(pink)$#f030b0",
107 "*Linear,linear:+-lower$#a00,-upper$#0a0",
108 "*Rainbow,cyclic:+-col1$#a00,-col2$#990,"
109 "+-col3$#0a0,-col4$#0aa,"
110 "+-col5$#00a,-col6$#b0b",
111 "*Planar,planar:+-off$#000,-dim1$#a00,"
113 "*Spatial,spatial:+-off$#000,-dim1$#a00,"
114 "+-dim2$#0a0,-dim3$#00a",
148 mark_species_in_tree(at->get_leftson(),
mark_mode) +
149 mark_species_in_tree(at->get_rightson(),
mark_mode);
170 if (oldMark != mark_mode && condition(at->
gb_node, cd)) {
175 case 3: count += !!oldMark;
break;
184 mark_species_in_tree_that(at->get_leftson(),
mark_mode, condition, cd) +
185 mark_species_in_tree_that(at->get_rightson(),
mark_mode, condition, cd);
192 AP_tree *pa = at->get_father();
195 mark_species_in_rest_of_tree(pa, mark_mode);
201 if (!at)
return false;
204 if (!at->
gb_node)
return false;
209 return tree_has_marks(at->get_leftson()) || tree_has_marks(at->get_rightson());
213 if (!at)
return false;
215 AP_tree *pa = at->get_father();
216 if (!pa)
return false;
218 return tree_has_marks(at->
get_brother()) || rest_tree_has_marks(pa);
224 int closed_terminal, opened_terminal;
225 int closed_with_marked;
226 int closed_with_unmarked;
229 int marked_in_groups, marked_outside_groups;
230 int unmarked_in_groups, unmarked_outside_groups;
241 closed_with_marked = 0;
242 closed_with_unmarked = 0;
244 marked_in_groups = 0;
245 marked_outside_groups = 0;
246 unmarked_in_groups = 0;
247 unmarked_outside_groups = 0;
253 int marked()
const {
return marked_in_groups+marked_outside_groups; }
254 int unmarked()
const {
return unmarked_in_groups+unmarked_outside_groups; }
262 if (closed_with_unmarked) {
281 else state->unmarked_outside_groups++;
288 if (at->
leftson != skip_this_son) detect_group_state(at->get_leftson(), &sub_state, skip_this_son);
289 if (at->
rightson != skip_this_son) detect_group_state(at->get_rightson(), &sub_state, skip_this_son);
293 if (!sub_state.
has_groups()) state->closed_terminal++;
294 if (sub_state.
marked()) state->closed_with_marked++;
295 if (sub_state.
unmarked()) state->closed_with_unmarked++;
296 state->closed += sub_state.opened;
300 if (!sub_state.
has_groups()) state->opened_terminal++;
301 state->opened += sub_state.opened;
304 state->marked_in_groups += sub_state.
marked();
305 state->unmarked_in_groups += sub_state.
unmarked();
307 state->closed += sub_state.closed;
308 state->opened_terminal += sub_state.opened_terminal;
309 state->closed_terminal += sub_state.closed_terminal;
310 state->closed_with_marked += sub_state.closed_with_marked;
311 state->closed_with_unmarked += sub_state.closed_with_unmarked;
314 if (at->
leftson != skip_this_son) detect_group_state(at->get_leftson(), state, skip_this_son);
315 if (at->
rightson != skip_this_son) detect_group_state(at->get_rightson(), state, skip_this_son);
321 AP_tree *pa = at->get_father();
324 group_rest_tree(pa, mode, color_group);
335 if (!at)
return true;
339 bool expand_me =
false;
351 my_color_group == color_group ||
352 (my_color_group != 0 && color_group == -1);
362 expand_me = group_tree(at->get_leftson(), mode, color_group);
363 expand_me = group_tree(at->get_rightson(), mode, color_group) || expand_me;
383 exports.request_save();
397 bool is_bootstrap =
false;
414 int bootstrap = is_bootstrap ?
int(dboot) : -1;
417 const char *text =
NULp;
437 buf.
nprintf(4,
"%4.2f",
double(bootstrap/100.0));
440 buf.
nprintf(3,
"%i", bootstrap);
453 double radius = .01 * bootstrap;
455 if (radius < .1) radius = .1;
457 radius = 1.0 / sqrt(radius);
471 const double radiusx = radius * blen;
472 const bool circleTooSmall = radiusx<0 ||
nearlyZero(radiusx);
473 if (!circleTooSmall) {
477 if (radiusy > radiusx) radiusy = radiusx;
530 char *gname =
aw_input(
"Enter name of new group");
531 if (gname && gname[0]) {
567 error =
"Please select an inner node to create a group";
571 AP_tree *gat = keeled ? at->get_father() : at;
575 switch (
aw_question(
NULp, msg,
"KeelOver,Rename,Destroy,Cancel" + (keeled ? 0 : 9)) - (keeled ? 1 : 0)) {
590 char *new_gname =
aw_input(
"Rename group",
"Change group name:", gat->
name);
594 freeset(gat->
name, new_gname);
618 error = create_group(at);
646 virtual void abort() = 0;
664 aw_message(
"Please select the radial tree display mode to use this command");
681 AP_tree *AWT_graphic_tree::find_selected_node()
const {
686 if (!node && displayed_root && species_name[0]) {
692 AP_tree *AWT_graphic_tree::find_selected_group() {
716 if (gb_next == gb_sel) {
754 for (
AP_tree_set_citer g = want_unfolded.begin(); g != want_unfolded.end(); ++g) {
759 need_update(affected_subtree, node);
760 keep_unfolded.insert(node);
767 if (want_unfolded.find(node) == want_unfolded.end()) {
769 need_update(affected_subtree, node);
772 keep_unfolded.insert(node);
775 unfolded = keep_unfolded;
776 return affected_subtree;
783 return unfolded.find(node) != unfolded.end();
791 AP_tree *outdated_subtree = autoUnfolded->
unfold(parentGroups);
792 if (outdated_subtree) {
804 bool handled =
false;
805 if (!displayed_root)
return false;
812 bool upwards =
false;
813 bool ignore_selected =
false;
827 bool at_group =
false;
828 if (!ignore_selected) {
829 sel_node = find_selected_node();
831 sel_node = find_selected_group();
840 ?
ARB_edge(sel_node, sel_node->get_rightson()).previous()
841 : ARB_edge(sel_node->get_leftson(), sel_node))
849 while (!jump_to_node && maxIter-->0) {
873 if (nds_only_marked) marked_only =
true;
874 if (!species_name[0]) ignore_selected =
true;
889 AP_tree *start_node = find_selected_group();
890 bool started_from_species =
false;
893 start_node = find_selected_node();
894 started_from_species = start_node;
901 bool at_target =
false;
902 if (started_from_species) {
916 int start_clade_level = iter.get_clade_level();
917 AP_tree *start_group = iter.node();
923 if (iter.node() == start_group)
break;
925 while (iter.get_clade_level() > start_clade_level);
927 if (iter.get_clade_level() < start_clade_level) {
937 if (iter.node() == start_group)
break;
939 while (iter.get_clade_level() > start_clade_level);
941 if (iter.get_clade_level() < start_clade_level) {
962 if (iter.get_clade_level() == start_clade_level) {
963 last_visited = iter.node();
966 if (iter.node() == start_group)
break;
968 while (iter.get_clade_level() >= start_clade_level);
987 if (iter.node()->find_parent_clade() != start_group) {
989 unfold_to = start_group->get_leftson();
1000 else kcode = inject_kcode;
1004 AP_tree *jump_to = iter.node();
1005 select_group(jump_to);
1021 void AWT_graphic_tree::toggle_folding_at(
AP_tree *at,
bool force_jump) {
1031 top_change = at->get_father();
1056 #if defined(DEBUG) && 0
1078 bool handled =
true;
1092 if (species_name[0]) {
1101 AP_tree *subtree = find_selected_group();
1110 default: handled =
false;
break;
1117 toggle_folding_at(find_selected_group(),
true);
1119 default: handled =
false;
break;
1126 handled = handle_cursor(event.
key_code(),
event.key_modifier());
1133 if (pointed.species()) {
1157 default: handled =
false;
break;
1161 if (!handled && event.
key_char() ==
'0') {
1170 else if (pointed.is_ruler()) {
1174 switch (event.
cmd()) {
1194 else if (pointed.node()) {
1196 switch (event.
cmd()) {
1208 if (!handled && pointed.node()) {
1246 at = at->get_father();
1249 at = at->get_father();
1276 AP_tree *root_node = pointed.node();
1277 while (root_node->
father) root_node = root_node->get_father();
1297 default: handled =
false;
break;
1306 bool refresh =
false;
1311 switch (event.
cmd()) {
1313 switch (event.
button()) {
1333 map_viewer_cb(gbd, selectType);
1362 virtual void perform_drop() = 0;
1365 Drop = drag_target ? *drag_target : Drag;
1374 case DRAGGING: drag(target);
break;
1375 case DROPPED: drop(target);
break;
1436 if (group_moved) agt.select_group(gb_node);
1441 if (!source.
node()) printf(
"No source.node\n");
1442 if (!dest.
node()) printf(
"No dest.node\n");
1443 if (dest.
node() == source.
node()) printf(
"source==dest\n");
1462 virtual void draw_scale_indicator(
const AW::Position& drag_pos,
AW_device *device,
int drag_gc)
const = 0;
1463 virtual void do_scale(
const Position& drag_pos) = 0;
1468 last_drag_pos = mousepos;
1488 last_drag_pos(start),
1495 draw_scale_indicator(last_drag_pos, device, drag_gc);
1505 if (analog_value<0.0)
return -
discrete_value(-analog_value, discretion_factor);
1506 return int(analog_value*discretion_factor+0.5)/double(discretion_factor);
1515 int discretion_factor;
1518 static CONSTEXPR double INTSCALE = 100.0;
1524 discretion_factor = 0;
1541 return inversed ? -res : res;
1546 if (inversed) val = -val;
1548 val = val<=min ? min : (val>=max ? max : val);
1549 val = discretion_factor ?
discrete_value(val, discretion_factor) : val;
1561 return old !=
read();
1576 if (!gbd) gbd = y.
data();
1585 return xchanged || ychanged;
1589 void do_scale(
const Position& drag_pos) {
1595 :
Scaler(start, unscale_, exports_),
1600 awar_start = read_pos();
1607 device->
text(gc, text, at);
1617 bool zero_val_removed;
1622 int discretion_factor;
1626 float get_val()
const {
1635 void set_val(
float val) {
1643 void init_discretion_factor(
bool discrete) {
1644 if (start_val != 0 && discrete) {
1645 discretion_factor = 10;
1646 while ((start_val*discretion_factor)<1) {
1647 discretion_factor *= 10;
1651 discretion_factor = 0;
1660 if (attach2tip.
length()>0) {
1662 return attach+moveOnBranch;
1665 if (attach2base.
length()>0) {
1667 return attach+moveOnBranch;
1675 Position attach_dragged = get_dragged_attach(drag_pos);
1676 if (attach_dragged.
valid()) {
1678 LineVector to_dragged(attach_dragged, drag_world);
1683 device->
line(drag_gc, to_start);
1684 device->
line(drag_gc, to_dragged);
1691 device->
line(drag_gc, branch);
1694 void do_scale(
const Position& drag_pos) {
1695 double oldval = get_val();
1697 if (start_val == 0.0) {
1698 if (!zero_val_removed) {
1703 aw_message(
"Cannot scale zero sized branches\nBranchlength has been set to 0.1\nNow you may scale the branch");
1707 aw_message(
"Cannot spread unspreaded branches\nSpreading has been set to 1.0\nNow you may spread the branch");
1710 zero_val_removed =
true;
1714 Position attach_dragged = get_dragged_attach(drag_pos);
1715 if (attach_dragged.
valid()) {
1717 Vector to_attach_dragged(branch.
start(), attach_dragged);
1719 double tal = to_attach.
length();
1720 double tdl = to_attach_dragged.length();
1722 if (tdl>0.0 && tal>0.0) {
1724 double scale = tdl/tal * (negate ? -1 : 1);
1726 float val = start_val * scale;
1728 if (node->
is_leaf() || !allow_neg_val) {
1732 if (discretion_factor) {
1735 set_val(
NONAN(val));
1740 if (oldval != get_val()) {
1748 :
Scaler(start, unscale_, exports_),
1751 start_val(get_val()),
1752 zero_val_removed(
false),
1755 allow_neg_val(allow_neg_values_)
1757 init_discretion_factor(discrete);
1768 :
Scaler(start, 0.1, exports_),
1770 start_width(node->get_linewidth()),
1771 wholeSubtree(wholeSubtree_)
1777 double ymove = -moved.
y();
1780 int width = start_width + ymove;
1804 mousepos_world = device->rtransform(mousepos);
1808 Angle current(hinge, mousepos_world);
1812 node->
set_angle(orig_angle + diff.radian());
1827 clicked_branch(clicked_branch_),
1828 orig_angle(node->get_angle()),
1829 hinge(clicked_branch.
start()),
1830 mousepos_world(device->rtransform(mousepos))
1839 device->line(drag_gc, clicked_branch);
1840 device->line(drag_gc,
LineVector(hinge, mousepos_world));
1857 const double dist = text_height * dist_factor;
1861 shift.
sety(shift.
y()>0 ? sqrt(shift.
y()) : -sqrt(-shift.
y()));
1864 near.
movey(.3*text_height);
1866 alignment = .5 - .5*orientation.
cos();
1895 Vector toClick(center, click_world);
1903 device->
line(drag_gc, toHead);
1909 device->
text(drag_gc, name.c_str(), textPos, alignment);
1922 marker(marker_->clone()),
1944 return AW_device_click::PREFER_LINE;
1947 return AW_device_click::PREFER_NEARER;
1954 if (!tree_static)
return;
1969 if (clicked.species()) {
1976 if (!tree_static->get_root_node())
return;
1978 const Position& mousepos =
event.position();
1994 switch (event.
type()) {
1996 dragging->
do_drag(clicked.element(), mousepos);
2001 dragging->
do_drop(clicked.element(), mousepos);
2015 if (clicked.is_ruler()) {
2021 switch (event.
cmd()) {
2026 double rel = clicked.get_rel_attach();
2028 unscale /= (rel-1)*irs_tree_ruler_scale_factor;
2045 bool isText = clicked.is_text();
2057 if (clicked.is_marker()) {
2058 if (clicked.element()->get_distance() <= 3) {
2061 const char *name = display_markers->
get_marker_name(clicked.get_markerindex());
2072 switch (event.
cmd()) {
2077 if (clicked.node() && clicked.node()->father) {
2087 if (clicked.node() && clicked.is_branch()) {
2103 if (clicked.node()) {
2104 BranchRotator *rotator =
NULp;
2105 if (clicked.is_branch()) {
2108 rotator =
new BranchRotator(device, clicked.node(), cl->
get_line(), mousepos,
exports);
2111 const AW_clicked_polygon *poly =
dynamic_cast<const AW_clicked_polygon*
>(clicked.element());
2123 rotator =
new BranchRotator(device, clicked.node()->get_leftson(), left, mousepos,
exports);
2126 rotator =
new BranchRotator(device, clicked.node()->get_rightson(), right, mousepos,
exports);
2133 rotator->draw_drag_indicator(device,
drag_gc);
2139 if (clicked.node()) {
2147 if (clicked.node() && clicked.is_branch()) {
2160 switch (event.
button()) {
2162 if (clicked.node()) {
2168 if (displayed_root->
father) {
2180 if (clicked.node()) {
2181 switch (event.
button()) {
2183 toggle_folding_at(clicked.node(),
false);
2196 switch (event.
button()) {
2198 if (clicked.node()) {
2199 clicked.node()->set_root();
2213 if (clicked.node()) {
2214 switch (event.
button()) {
2224 if (clicked.node()) {
2227 switch (event.
button()) {
2239 if (clicked.node()) {
2253 if (clicked.node() && clicked.node()->gb_node) {
2267 if (tree_style == style) {
2268 nds_only_marked = !nds_only_marked;
2271 nds_only_marked =
false;
2314 link_to_database(
false),
2329 display_markers(
NULp),
2330 map_viewer_cb(map_viewer_cb_),
2333 displayed_root(
NULp),
2338 nds_only_marked(
false)
2349 delete display_markers;
2350 delete autoUnfolded;
2359 td_assert(!insert_delete_cbs || link_to_database);
2360 link_to_database = link_to_database_;
2363 void AWT_graphic_tree::unload() {
2365 if (display_markers) display_markers->
flush_cache();
2367 destroy(tree_static->get_root_node());
2368 displayed_root =
NULp;
2380 error =
"Please select a tree (name lost)";
2394 char *name_dup = strdup(name);
2400 if (!error && link_to_database) {
2401 error = tree_static->
linkToDB(&zombies, &duplicates);
2405 destroy(tree_static->get_root_node());
2417 select_group(gb_group);
2421 tree_changed_cb(
this);
2429 if (display_markers) display_markers->
flush_cache();
2438 error = ta.close(error);
2452 tree_changed_cb(
this);
2517 summarizeGroupMarkers(at->get_leftson(), markers);
2519 summarizeGroupMarkers(at->get_rightson(), rightMarkers);
2520 markers.
add(rightMarkers);
2537 : Width((marker_width-1) / scale),
2538 Offset(marker_width / scale),
2545 double leftx (
int markerIdx)
const {
return (markerIdx - markers - 1.0) *
offset(); }
2565 void AWT_graphic_tree::drawMarker(
const class MarkerPosition& marker,
const bool partial,
const int markerIdx) {
2574 void AWT_graphic_tree::detectAndDrawMarkers(
AP_tree *at,
const double y1,
const double y2) {
2580 int numMarkers = display_markers->
size();
2584 summarizeGroupMarkers(at, markers);
2588 for (
int markerIdx = 0 ; markerIdx < numMarkers ; markerIdx++) {
2591 bool partial =
false;
2596 if (markRate>=groupThreshold.partiallyMarked && markRate>0.0) {
2598 partial = markRate<groupThreshold.marked;
2603 clickflag.set_cd1(markerIdx);
2604 drawMarker(
flag, partial, markerIdx);
2612 void AWT_graphic_tree::drawMarkerNames(
Position& Pen) {
2615 int numMarkers = display_markers->
size();
2620 Pen.
movey(scaled_branch_distance);
2623 Vector sizeb(
flag.width(), scaled_branch_distance);
2624 Vector b2t(2*
flag.offset(), scaled_branch_distance);
2625 Vector toNext(-
flag.offset(), scaled_branch_distance);
2631 for (
int markerIdx = numMarkers - 1 ; markerIdx >= 0 ; markerIdx--) {
2636 clickflag.set_cd1(markerIdx);
2638 disp_device->
line(gc, pl1, pl2, marker_filter);
2639 disp_device->
box(gc, AW::FillStyle::SOLID, mbox, marker_filter);
2640 disp_device->
text(gc, markerName, mbox.upper_left_corner()+b2t, 0, marker_filter);
2643 pl1.movex(toNext.x());
2648 Pen.
movey(scaled_branch_distance * (numMarkers+2));
2651 Pen.
movey(scaled_branch_distance * (numMarkers+3));
2659 Vector diagonal(diameter, diameter);
2664 disp_device->
box(gc, filled, pos-0.5*diagonal, diagonal, mark_filter);
2680 disp_device->
polygon(gc, AW::FillStyle::SOLID, 4, corner, mark_filter);
2692 Position p(0, Pen.
ypos() - scaled_branch_distance *2.0);
2695 bool is_clipped =
false;
2698 offset = scaled_branch_distance;
2702 p.sety(Pen.
ypos() + scaled_branch_distance *(at->
gr.
view_sum+2));
2706 offset = scaled_branch_distance*at->
gr.
view_sum;
2720 static int recursion_depth = 0;
2730 bool is_group =
false;
2732 if (at->
hasName(species_name)) {
2737 bool is_selected = selected_group.
at_node(at);
2744 if ((at->
name || is_group) && (disp_device->
get_filter() & leaf_text_filter)) {
2751 if (display_markers) {
2752 detectAndDrawMarkers(at, Pen.
ypos() - scaled_branch_distance * 0.495, Pen.
ypos() + scaled_branch_distance * 0.495);
2755 const char *data = labeler.speciesLabel(this->gb_main, at->
gb_node, at, tree_static->
get_tree_name());
2757 static SmartCharPtr buf;
2769 disp_device->
text(gc, sdata, textPos, 0.0, leaf_text_filter);
2779 Pen.
movey(scaled_branch_distance);
2789 disp_device->
text(gc, sdata, textPos, 0.0, leaf_text_filter);
2794 Pen.
movey(scaled_branch_distance);
2804 double height = scaled_branch_distance * at->
gr.
view_sum;
2805 double box_height = height-scaled_branch_distance;
2808 Position s1(s0); s1.movey(box_height);
2814 if (display_markers) {
2815 detectAndDrawMarkers(at, s0.ypos(), s1.ypos());
2820 bool is_selected = selected_group.
at_node(at);
2829 switch (group_orientation) {
2830 case GO_TOP: flip =
false;
break;
2836 double x2 = group[2].
xpos();
2837 group[2].
setx(group[3].xpos());
2845 s_attach = s1+(flip ? 1.0-attach_group : attach_group)*(s0-s1);
2848 group[1] = s_attach;
2859 if (is_selected) selGroup =
PaintedNode(s_attach, at);
2863 if (disp_device->
get_filter() & group_text_filter) {
2875 const double group_height = fabs(gy);
2877 if (group_height<=text_ascent) {
2884 const double shift_right = g_diag.
line_vector().
x() * text_ascent / group_height;
2887 pmin.movex(shift_right);
2888 pmax.movey(text_ascent);
2891 pmin.move(
Vector(shift_right, text_ascent));
2894 textPos = pmin + 0.125*(pmax-pmin);
2897 textPos.
movex(char_width);
2900 disp_device->
text(group_gc, infoName, textPos, 0.0, group_text_filter);
2911 countPos = s_attach +
Vector(g_diag.
centroid()-s_attach)*0.666 +
Vector(-textsize, text_ascent)*0.5;
2914 countPos = s_attach +
Vector(char_width, 0.5*text_ascent);
2916 disp_device->
text(group_gc, infoCount, countPos, 0.0, group_text_filter);
2922 limits.
y_top = s0.ypos();
2923 limits.
y_bot = s1.ypos();
2930 bool is_selected = is_group && selected_group.
at_node(at);
2931 const int group_gc = is_selected ? int(
AWT_GC_CURSOR) : at->gr.gc;
2940 show_dendrogram(at->get_leftson(), Pen, limits, labeler);
2942 n0.sety(limits.y_branch);
2943 s0.sety(limits.y_branch);
2945 Pen.
setx(s0.xpos());
2946 Position subtree_border(Pen); subtree_border.movey(- .5*scaled_branch_distance);
2951 show_dendrogram(at->get_rightson(), Pen, right_lim, labeler);
2952 n1.sety(right_lim.y_branch);
2953 limits.combine(right_lim);
2966 if (attach_size != 0.0) {
2968 shift_by_size = -attach_size * (subtree_border-attach);
2971 if (attach_len != 0.0) {
2975 barycenter = attach;
2997 barycenter = attach-big2small/2+big2small*fraction;
3001 Vector shift_to_barycenter = barycenter-attach;
3002 shift_by_len = shift_to_barycenter*attach_len;
3008 double sum = fabs(attach_size) + fabs(attach_len);
3009 double f_size = fabs(attach_size)/sum;
3010 double f_len = fabs(attach_len)/sum;
3012 attach += f_size * shift_by_size;
3013 attach += f_len * shift_by_len;
3016 attach += shift_by_size;
3017 attach += shift_by_len;
3021 if (is_group && show_brackets) {
3024 double half_text_ascent = charLimits.
ascent * unscale * 0.5;
3026 double x1 = limits.x_right + scaled_branch_distance*0.1;
3027 double x2 = x1 + scaled_branch_distance * 0.3;
3028 double y1 = limits.y_top - half_text_ascent * 0.5;
3029 double y2 = limits.y_bot + half_text_ascent * 0.5;
3035 disp_device->
line(group_gc, bracket.upper_edge(), group_bracket_filter);
3036 disp_device->
line(group_gc, bracket.lower_edge(), group_bracket_filter);
3037 disp_device->
line(group_gc, bracket.right_edge(), group_bracket_filter);
3039 limits.x_right = x2;
3041 if (disp_device->
get_filter() & group_text_filter) {
3045 bool visible = disp_device->
clip(worldBracket, clippedWorldBracket);
3055 disp_device->
text(group_gc, infoName, namePos, 0.0, group_text_filter);
3057 double textsize = disp_device->
get_string_size(group_gc, infoName) * unscale;
3058 limits.x_right = namePos.
xpos() + textsize;
3065 disp_device->
text(group_gc, infoCount, countPos, 0.0, group_text_filter);
3067 double textsize = disp_device->
get_string_size(group_gc, infoCount) * unscale;
3068 limits.x_right = countPos.
xpos() + textsize;
3076 for (
int right = 0; right<2; ++right) {
3077 const Position& n = right ? n1 : n0;
3078 const Position& s = right ? s1 : s0;
3083 son = at->get_rightson();
3087 son = at->get_leftson();
3094 unsigned int gc = son->
gr.
gc;
3120 if (is_selected) selGroup =
PaintedNode(attach, at);
3122 limits.y_branch = attach.
ypos();
3134 static int recursion_depth = 0;
3140 if (at->is_leaf()) {
3145 if (at->name && (disp_device->
get_filter() & leaf_text_filter)) {
3146 if (at->hasName(species_name)) selSpec =
PaintedNode(tip, at);
3151 const char *data = labeler.speciesLabel(this->gb_main, at->gb_node, at, tree_static->
get_tree_name());
3152 disp_device->
text(at->gr.gc, data,
3169 else if (at->is_folded_group()) {
3170 bool is_selected = at->name && selected_group.
at_node(at);
3171 const int group_gc = is_selected ? int(
AWT_GC_CURSOR) : at->gr.gc;
3178 Angle left(orientation.
radian() + 0.25*tree_spread + at->gr.left_angle);
3179 corner[1] = tip + left.normal()*at->gr.min_tree_depth;
3182 Angle right(orientation.
radian() - 0.25*tree_spread + at->gr.right_angle);
3183 corner[2] = tip + right.normal()*at->gr.max_tree_depth;
3188 if (group_gc !=
int(at->gr.gc)) {
3192 if (disp_device->
get_filter() & group_text_filter) {
3195 Angle toText = orientation;
3204 Vector v01 = corner[1]-corner[0];
3205 Vector v02 = corner[2]-corner[0];
3214 bool is_selected = at->name && selected_group.
at_node(at);
3218 sub[0].
at = at->get_leftson();
3219 sub[1].
at = at->get_rightson();
3222 sub[1].
pc = 1.0-sub[0].
pc;
3227 sub[0].
len = at->leftlen;
3228 sub[1].
len = at->rightlen;
3230 if (sub[0].at->gr.gc < sub[1].
at->
gr.
gc) {
3235 for (
int s = 0; s<2; ++
s) {
3236 show_radial_tree(sub[s].at,
3238 tip + sub[s].len * sub[s].orientation.
normal(),
3245 for (
int s = 0; s<2; ++
s) {
3270 if (at->is_clade()) {
3279 const char *tree_awar =
NULp;
3280 switch (tree_style) {
3285 tree_awar =
"RADIAL";
3297 static char awar_name[256];
3298 sprintf(awar_name,
"ruler/%s/%s", tree_awar, name);
3304 if (!gb_tree)
return;
3307 if (mode_has_ruler) {
3311 float ruler_y = 0.0;
3318 ruler_y = world.
b * 1.3;
3322 double half_ruler_width = ruler_size*0.5;
3324 float ruler_add_y = 0.0;
3325 float ruler_add_x = 0.0;
3326 switch (tree_style) {
3329 half_ruler_width *= irs_tree_ruler_scale_factor;
3331 ruler_add_y = this->list_tree_ruler_y;
3332 ruler_add_x = -half_ruler_width;
3336 ruler_add_y = this->list_tree_ruler_y;
3337 ruler_add_x = half_ruler_width;
3344 float ruler_x = 0.0;
3349 float ruler_text_x = 0.0;
3354 float ruler_text_y = 0.0;
3365 ruler_x - half_ruler_width, ruler_y,
3366 ruler_x + half_ruler_width, ruler_y,
3369 char ruler_text[20];
3370 sprintf(ruler_text,
"%4.2f", ruler_size);
3371 device->
text(gc, ruler_text,
3372 ruler_x + ruler_text_x,
3373 ruler_y + ruler_text_y,
3389 len = strlen(text_);
3392 is_numeric = (strspn(text,
"0123456789.") ==
len);
3405 : gb_species(gb_species_),
3406 y_position(y_position_),
3409 const char *nds = use_nds
3410 ? labeler.speciesLabel(gb_main, gb_species,
NULp, tree_name)
3415 part_count = parts.
size();
3417 column =
new Column[part_count];
3418 for (
size_t i = 0; i<part_count; ++i) {
3419 column[i].
init(parts[i], device, gc);
3441 void AWT_graphic_tree::show_nds_list(
GBDATA *,
bool use_nds,
const NDS_Labeler& labeler) {
3442 AW_pos y_position = scaled_branch_distance;
3446 GBS_global_string(
"%s of %s species", use_nds ?
"NDS List" :
"Simple list", nds_only_marked ?
"marked" :
"all"),
3448 (
AW_pos) 0, other_text_filter);
3451 double text_y_offset = scaled_font.
ascent*.5;
3453 GBDATA *selected_species;
3473 y1 -= 2*scaled_branch_distance;
3474 y2 += 2*scaled_branch_distance;
3476 size_t displayed_rows = (y2-y1)/scaled_branch_distance+1;
3479 size_t species_count = 0;
3480 size_t max_parts = 0;
3484 int skip_over = (y1-y_position)/scaled_branch_distance-2;
3486 gb_species = nds_only_marked
3489 y_position += skip_over*scaled_branch_distance;
3497 y_position += scaled_branch_distance;
3501 if (y_position>y1) {
3502 if (y_position>y2)
break;
3504 bool is_marked = nds_only_marked ||
GB_read_flag(gb_species);
3510 bool colorize_marked = is_marked && !nds_only_marked;
3512 int gc = shader->
calc_leaf_GC(gb_species, colorize_marked);
3517 ListDisplayRow *curr =
new ListDisplayRow(gb_main, gb_species, y_position+text_y_offset, gc, *disp_device, use_nds, tree_name, labeler);
3519 row[species_count++] = curr;
3523 td_assert(species_count <= displayed_rows);
3526 double *max_part_width =
new double[max_parts];
3527 bool *align_right =
new bool[max_parts];
3529 for (
size_t p = 0; p<max_parts; ++p) {
3530 max_part_width[p] = 0;
3531 align_right[p] =
true;
3534 for (
size_t s = 0; s<species_count; ++
s) {
3536 for (
size_t p = 0; p<parts; ++p) {
3539 align_right[p] = align_right[p] && col.
is_numeric;
3543 double column_space = scaled_branch_distance;
3545 double *part_x_pos =
new double[max_parts];
3546 for (
size_t p = 0; p<max_parts; ++p) {
3547 part_x_pos[p] = x_position;
3548 x_position += max_part_width[p]+column_space;
3554 for (
size_t s = 0; s<species_count; ++
s) {
3564 for (
size_t p = 0; p<parts; ++p) {
3567 AW_pos x = part_x_pos[p];
3568 if (align_right[p]) x += max_part_width[p] - col.
print_width;
3574 delete [] part_x_pos;
3575 delete [] align_right;
3576 delete [] max_part_width;
3578 for (
size_t s = 0; s<species_count; ++
s)
delete row[s];
3613 if (display_markers) {
3625 bool zoom_fit_text =
false;
3626 int left_padding = 0;
3627 int right_padding = 0;
3629 switch (tree_style) {
3633 right_padding = left_padding;
3657 disp_device = device;
3670 scaled_branch_distance *= scaled_font.
height;
3676 static const char *no_tree_text[] = {
3677 "No tree (selected)",
3679 "In the top area you may click on",
3680 "- the listview-button to see a plain list of species",
3681 "- the tree-selection-button to select a tree",
3685 Position p0(0, -3*scaled_branch_distance);
3687 for (
int i = 0; no_tree_text[i]; ++i) {
3688 cursor.
movey(scaled_branch_distance);
3689 device->
text(AWT_GC_CURSOR, no_tree_text[i], cursor);
3693 p0.
movex(-scaled_branch_distance);
3694 cursor.
movex(-scaled_branch_distance);
3697 p0.
movey(-scaled_branch_distance);
3698 cursor.
movey(scaled_branch_distance);
3701 device->
line(AWT_GC_CURSOR, p0, cursor);
3702 device->
line(AWT_GC_CURSOR, p0, horizontal);
3707 double range_display_size = scaled_branch_distance;
3708 bool allow_range_display =
true;
3713 switch (tree_style) {
3718 show_dendrogram(displayed_root, pen, limits, labeler);
3720 int rulerOffset = 2;
3721 if (display_markers) {
3722 drawMarkerNames(pen);
3725 list_tree_ruler_y = pen.
ypos() + double(rulerOffset) * scaled_branch_distance;
3742 show_irs_tree(displayed_root, scaled_branch_distance, labeler);
3746 show_nds_list(gb_main,
true, labeler);
3752 allow_range_display =
false;
3762 if (allow_range_display) {
3781 unsigned pc = unsigned(percent*100.0+0.5);
3787 else if (pc == 100) {
3800 static SmartCharPtr
copy;
3804 copy = strdup(info.
name);
3817 #if defined(ASSERTION_USED)
3832 static char countBuf[50];
3838 switch (count_mode) {
3850 switch (count_mode) {
3860 info.
count = countBuf;
3865 memmove(countBuf+1, countBuf, info.
count_len);
3886 else if (info.
count) {
3905 td_assert(tree_changed_cb == treeChangeIgnore_cb);
3906 tree_changed_cb = gtcb;
3909 td_assert(!(tree_changed_cb == treeChangeIgnore_cb));
3919 #if defined(ASSERTION_USED)
3922 if (display_markers) display_markers->
flush_cache();
3938 static bool avoid_recursion =
false;
3939 if (!avoid_recursion) {
3946 float partMarked = awar_partMarked->
read_float();
3948 if (partMarked>marked) {
4025 static bool in_recursion =
false;
4026 if (!in_recursion) {
4035 if (rlower>rupper) {
4036 if (upper_changed) {
4172 static AW_window_simple *aws =
NULp;
4174 aws =
new AW_window_simple;
4175 aws->init(aw_root,
"TREE_EXPERT_SETUP",
"Expert tree settings");
4178 aws->auto_space(5, 5);
4179 aws->label_length(LABEL_WIDTH);
4180 aws->button_length(8);
4183 aws->create_button(
"CLOSE",
"CLOSE",
"C");
4185 aws->create_button(
"HELP",
"HELP",
"H");
4190 aws->label(
"Attach by size");
4194 aws->label(
"Attach by len");
4198 aws->label(
"Attach (at groups)");
4204 const int PAD_SCALER_WIDTH = SCALER_WIDTH-39;
4206 aws->label(
"Text zoom/pad (dendro)");
4211 aws->label(
"Text zoom/pad (radial)");
4222 static AW_window_simple *aws =
NULp;
4224 aws =
new AW_window_simple;
4225 aws->init(aw_root,
"TREE_BOOT_SETUP",
"Bootstrap display settings");
4228 aws->auto_space(5, 5);
4229 aws->label_length(LABEL_WIDTH);
4230 aws->button_length(8);
4233 aws->create_button(
"CLOSE",
"CLOSE",
"C");
4235 aws->create_button(
"HELP",
"HELP",
"H");
4240 aws->label(
"Show bootstraps");
4244 aws->label(
"Hide bootstraps below");
4248 aws->label(
"Hide bootstraps above");
4254 aws->label(
"Bootstrap style");
4256 aws->insert_default_option(
"percent%",
"p",
BS_PERCENT);
4258 aws->insert_option (
"float",
"f",
BS_FLOAT);
4259 aws->update_option_menu();
4264 aws->label(
"Show bootstrap circles");
4268 aws->label(
"Greylevel of circles (%)");
4272 aws->label(
"Use ellipses");
4276 aws->label(
"Bootstrap circle zoom factor");
4280 aws->label(
"Bootstrap radius limit");
4290 static AW_window_simple *aws =
NULp;
4292 aws =
new AW_window_simple;
4293 aws->init(aw_root,
"TREE_SETUP",
"Tree settings");
4294 aws->load_xfig(
"awt/tree_settings.fig");
4297 aws->auto_space(5, 5);
4298 aws->label_length(LABEL_WIDTH);
4299 aws->button_length(8);
4302 aws->create_button(
"CLOSE",
"CLOSE",
"C");
4304 aws->create_button(
"HELP",
"HELP",
"H");
4310 aws->label(
"Base line width");
4314 aws->label(
"Branch style");
4317 aws->insert_option (
"Diagonal",
"D",
BS_DIAGONAL);
4318 aws->update_option_menu();
4323 aws->label(
"Show group brackets");
4327 aws->label(
"Group style");
4329 aws->insert_default_option(
"Trapeze",
"z",
GS_TRAPEZE);
4330 aws->insert_option (
"Triangle",
"i",
GS_TRIANGLE);
4331 aws->update_option_menu();
4333 aws->insert_default_option(
"Top",
"T",
GO_TOP);
4334 aws->insert_option (
"Bottom",
"B",
GO_BOTTOM);
4335 aws->insert_option (
"Interior",
"I",
GO_INTERIOR);
4336 aws->insert_option (
"Exterior",
"E",
GO_EXTERIOR);
4337 aws->update_option_menu();
4340 aws->label(
"Greylevel of groups (%)");
4344 aws->label(
"Show group counter");
4346 aws->insert_default_option(
"None",
"N",
GCM_NONE);
4348 aws->insert_option (
"Marked",
"a",
GCM_MARKED);
4349 aws->insert_option (
"Marked/Members",
"b",
GCM_BOTH);
4351 aws->insert_option (
"%Marked/Members",
"e",
GCM_BOTH_PC);
4352 aws->update_option_menu();
4355 aws->label(
"Group counter position");
4357 aws->insert_default_option(
"Attached",
"A",
GIP_ATTACHED);
4360 aws->update_option_menu();
4365 aws->label(
"Vertical distance");
4369 aws->label(
"Vertical group scaling");
4373 aws->label(
"'Biggroup' scaling");
4382 aws->label(
"Auto unfold selected species?");
4390 aws->button_length(19);
4395 aws->at(
"bootstrap");
4397 aws->create_button(
"bootstrap",
"Bootstrap settings",
"B");
4401 aws->create_button(
"expert",
"Expert settings",
"E");
4409 static AW_window_simple *aws =
NULp;
4412 aws =
new AW_window_simple;
4414 aws->init(root,
"MARKER_SETTINGS",
"Tree marker settings");
4416 aws->auto_space(10, 10);
4419 aws->create_button(
"CLOSE",
"CLOSE",
"C");
4421 aws->create_button(
"HELP",
"HELP",
"H");
4424 const int FIELDSIZE = 5;
4425 const int SCALERSIZE = 250;
4426 aws->label_length(35);
4428 aws->label(
"Group marked threshold");
4433 aws->label(
"Group partially marked threshold");
4438 aws->label(
"Marker width");
4443 aws->label(
"Partial marker greylevel");
4456 #include <../../WINDOW/aw_common.hxx>
4460 static AW_rgb colors_def[] = {
4506 static AW_rgb *fcolors = colors_def;
4507 static AW_rgb *dcolors = colors_def;
4508 static long dcolors_count =
ARRAY_ELEMS(colors_def);
4510 class fake_AW_GC :
public AW_GC {
4528 struct fake_AW_common :
public AW_common {
4530 :
AW_common(fcolors, dcolors, dcolors_count)
4539 gcm->
set_fg_color(colors_def[gc+AW_STD_COLOR_IDX_MAX]);
4544 virtual AW_GC *create_gc() {
4545 return new fake_AW_GC(
this);
4551 double att_size, att_len;
4555 scaled_branch_distance = 1.0;
4560 static const double group_attach[] = { 0.5, 1.0, 0.0, };
4561 static const double tested_greylevel[] = { 0.0, 0.25, 0.75, 1.0 };
4563 int mvar_mode = var_mode+int(tree_style)+int(group_style);
4565 groupScale.pow = .33;
4567 group_greylevel = tested_greylevel[mvar_mode%4];
4569 baselinewidth = (var_mode == 3)+1;
4570 show_brackets = (var_mode != 2);
4573 attach_size = att_size;
4574 attach_len = att_len;
4575 attach_group = group_attach[var_mode%3];
4576 branch_style = bstyle;
4578 bconf.zoom_factor = 1.3;
4579 bconf.max_radius = 1.95;
4580 bconf.show_circle = var_mode%3;
4581 bconf.fill_level = 1.0 - group_greylevel;
4583 bconf.elipsoid = var_mode%2;
4584 bconf.show_boots = !(var_mode == 0 && bstyle ==
BS_DIAGONAL);
4585 bconf.bootstrap_min = var_mode<2 ? 0 : 5;
4586 bconf.bootstrap_max = !(var_mode%2) ? 100 : 95;
4587 if (var_mode != ((bconf.show_circle+branch_style)%3) && bconf.bootstrap_max == 100) {
4588 bconf.bootstrap_max = 99;
4601 case 1: group_count_mode =
GCM_NONE;
break;
4608 fake_AWT_graphic_tree(
GBDATA *gbmain,
const char *selected_species)
4615 species_name = strdup(selected_species);
4616 exports.modifying = 1;
4619 void set_var_mode(
int mode) { var_mode = mode; }
4620 void set_attach(
double asize,
double alen) { att_size = asize; att_len = alen; }
4621 void set_branchstyle(
BranchStyle bstyle_) { bstyle = bstyle_; }
4623 void test_show_tree(
AW_device *device,
bool force_compute) {
4624 if (force_compute) {
4633 void test_print_tree(AW_device_print *print_device,
AP_tree_display_style style,
bool show_handles) {
4634 const int SCREENSIZE = 541;
4637 size_device.
reset();
4638 size_device.zoom(1.0);
4640 test_show_tree(&size_device,
true);
4642 Rectangle drawn = size_device.get_size_information();
4646 double zoomx = SCREENSIZE/drawn.
width();
4647 double zoomy = SCREENSIZE/drawn.
height();
4668 size_device.restart_tracking();
4669 size_device.reset();
4670 size_device.zoom(zoom);
4672 test_show_tree(&size_device,
false);
4675 drawn = size_device.get_size_information();
4677 const AW_borders& text_overlap = size_device.get_unscaleable_overlap();
4678 Rectangle drawn_text = size_device.get_size_information_inclusive_text();
4680 int EXTRA = SCREENSIZE*0.05;
4683 clipping.
l = 0; clipping.
r = drawn.
width()+text_overlap.
l+text_overlap.
r + 2*EXTRA;
4684 clipping.
t = 0; clipping.
b = drawn.
height()+text_overlap.
t+text_overlap.
b + 2*EXTRA;
4686 print_device->get_common()->set_screen(clipping);
4688 print_device->reset();
4690 print_device->zoom(zoom);
4692 Rectangle drawn_world = print_device->rtransform(drawn);
4693 Rectangle drawn_text_world = print_device->rtransform(drawn_text);
4700 print_device->set_offset(offset/(zoom*zoom));
4702 test_show_tree(print_device,
false);
4711 static bool replaceFirstRemark(
TreeNode *node,
const char *oldRem,
const char *newRem) {
4714 if (rem && strcmp(rem, oldRem) == 0) {
4720 replaceFirstRemark(node->get_leftson(), oldRem, newRem) ||
4721 replaceFirstRemark(node->get_rightson(), oldRem, newRem);
4726 void TEST_treeDisplay() {
4730 fake_AWT_graphic_tree agt(gb_main,
"OctSprin");
4731 fake_AW_common fake_common;
4733 AW_device_print print_dev(&fake_common);
4737 agt.init(
new AliView(gb_main),
NULp,
true,
false);
4744 const char *spoolnameof[] = {
4755 TEST_EXPECT(replaceFirstRemark(rootNode,
"97%",
"hello"));
4756 TEST_EXPECT(replaceFirstRemark(rootNode,
"44%",
"100%"));
4762 for (
int show_handles = 0; show_handles <= 1; ++show_handles) {
4763 for (
int color = 0; color <= 1; ++color) {
4764 print_dev.set_color_mode(color);
4768 if (spoolnameof[style]) {
4769 char *spool_name =
GBS_global_string_copy(
"display/%s_%c%c", spoolnameof[style],
"MC"[color],
"NH"[show_handles]);
4771 agt.set_tree_style(style,
NULp);
4773 int var_mode = show_handles+2*color;
4775 static struct AttachSettings {
4779 } attach_settings[] = {
4782 {
"_shortSmall", -1, -1 },
4783 {
"_centered", 0, 0 },
4787 for (
int attach_style = 0; attach_settings[attach_style].suffix; ++attach_style) {
4788 if (attach_style>0) {
4790 if (attach_style != var_mode)
continue;
4793 const AttachSettings& SETT = attach_settings[attach_style];
4799 if (attach_style != 0 && attach_style != 3)
continue;
4802 static const char *suffix[] = {
4814 #if defined(TEST_AUTO_UPDATE)
4815 #warning TEST_AUTO_UPDATE is active (non-default)
4823 agt.set_var_mode(var_mode);
4824 agt.set_attach(SETT.bySize, SETT.byLength);
4825 agt.set_branchstyle(bstyle);
4826 agt.test_print_tree(&print_dev, style, show_handles);
4831 #if !defined(TEST_AUTO_UPDATE)
4835 free(spool_expected);
4851 #endif // UNIT_TESTS
#define MAX_TREEDISP_RECURSION_DEPTH
AP_tree * get_node() const
#define AWAR_DTREE_GROUP_STYLE
void reorderTree(TreeOrder mode)
Position nearest_corner(const Position &topos) const
#define AWAR_DTREE_BOOTSTRAP_MAX
void insert_option(AW_label choice_label, const char *mnemonic, const char *var_value, const char *name_of_color=NULp)
GB_ERROR GB_copy_dropProtectMarksAndTempstate(GBDATA *dest, GBDATA *source)
void set_branchlength_unrooted(GBT_LEN newlen)
GBDATA * get_gb_main() const
AW::Vector transform(const AW::Vector &vec) const
bool are_antiparallel(const Vector &v1, const Vector &v2)
returns true, if two vectors have opposite orientations
GBDATA * get_group_data() const
MarkerXPos(AW_pos scale, int markers_)
AW_key_code key_code() const
ClickedElement(const ClickedElement &other)
GBDATA * GB_open(const char *path, const char *opent)
AP_tree * get_logical_root()
bool warn_inappropriate_mode(AWT_COMMAND_MODE mode)
AP_tree_root * get_tree_root()
AWT_graphic_tree_group_state()