From 66be23c9204c5567d1c51e6f57ba23bffa517a7c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 20 Feb 2017 03:41:04 +0800 Subject: [PATCH] fix issues that occur when expands/shrinks treebox --- include/nana/gui/widgets/treebox.hpp | 5 +- source/gui/widgets/treebox.cpp | 241 +++++++++++++-------------- 2 files changed, 114 insertions(+), 132 deletions(-) diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 210ecc31..a7e1bc77 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -37,7 +37,7 @@ namespace nana { enum class component { - begin, expender = begin, crook, icon, text, bground, end + begin, expander = begin, crook, icon, text, bground, end }; struct node_image_tag @@ -120,9 +120,6 @@ namespace nana void check(node_type*, checkstate); - const tree_cont_type & tree() const; - tree_cont_type & tree(); - void renderer(::nana::pat::cloneable&&); const ::nana::pat::cloneable& renderer() const; void placer(::nana::pat::cloneable&&); diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index 3b498ff9..350a4210 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -198,7 +198,7 @@ namespace nana template struct trigger::basic_implement { - typedef trigger::node_type node_type; + using node_type = trigger::node_type; struct rep_tag { @@ -215,7 +215,6 @@ namespace nana { nana::upoint border; nana::scroll scroll; - std::size_t prev_first_value; mutable std::map image_table; @@ -234,9 +233,9 @@ namespace nana { tooltip_window * tooltip; component comp_pointed; - tree_cont_type::node_type * pointed; - tree_cont_type::node_type * selected; - tree_cont_type::node_type * event_node; + node_type * pointed; + node_type * selected; + node_type * pressed_node; }node_state; struct track_node_tag @@ -259,7 +258,6 @@ namespace nana data.widget_ptr = nullptr; data.stop_drawing = false; - shape.prev_first_value = 0; shape.first = nullptr; shape.indent_pixels = 10; shape.offset_x = 0; @@ -270,7 +268,7 @@ namespace nana node_state.comp_pointed = component::end; node_state.pointed = nullptr; node_state.selected = nullptr; - node_state.event_node = nullptr; + node_state.pressed_node = nullptr; track_node.key_time = 0; @@ -321,9 +319,6 @@ namespace nana if (node->is_ancestor_of(node_state.selected)) node_state.selected = nullptr; - if (node->is_ancestor_of(node_state.event_node)) - node_state.event_node = nullptr; - if (perf_clear) { if (node->child) @@ -338,16 +333,15 @@ namespace nana return true; } - bool draw(bool reset_scroll, bool ignore_update = false) + bool draw(bool reset_scroll, bool ignore_update = false, bool ignore_auto_draw = false) { if(data.graph && (false == data.stop_drawing)) { if (reset_scroll) show_scroll(); - if (attr.auto_draw) + if (attr.auto_draw || ignore_auto_draw) { - //Draw background data.graph->rectangle(true, data.widget_ptr->bgcolor()); @@ -448,27 +442,41 @@ namespace nana { if(!node) return false; - auto & tree_container = attr.tree_cont; + auto & tree = attr.tree_cont; + auto const first_pos = tree.distance_if(shape.first, pred_allow_child{}); + auto const node_pos = tree.distance_if(node, pred_allow_child{}); + auto const max_allow = max_allowed(); switch(reason) { case 0: - //adjust if the node expanded and the number of its children are over the max number allowed - if(shape.first != node) + if (node->value.second.expanded) { - unsigned child_size = tree_container.child_size_if(*node, pred_allow_child()); - const std::size_t max_allow = max_allowed(); - - if(child_size < max_allow) + //adjust if the number of its children are over the max number allowed + if (shape.first != node) { - unsigned off1 = tree_container.distance_if(shape.first, pred_allow_child()); - unsigned off2 = tree_container.distance_if(node, pred_allow_child()); - const unsigned size = off2 - off1 + child_size + 1; - if(size > max_allow) - shape.first = tree_container.advance_if(shape.first, size - max_allow, pred_allow_child()); + auto child_size = tree.child_size_if(*node, pred_allow_child()); + if (child_size < max_allow) + { + auto const size = node_pos - first_pos + child_size + 1; + if (size > max_allow) + shape.first = tree.advance_if(shape.first, size - max_allow, pred_allow_child{}); + } + else + shape.first = node; + } + } + else + { + //The node is shrank + auto visual_size = visual_item_size(); + if (visual_size > max_allow) + { + if (first_pos + max_allow > visual_size) + shape.first = tree.advance_if(nullptr, visual_size - max_allow, pred_allow_child{}); } else - shape.first = node; + shape.first = nullptr; } break; case 1: @@ -476,7 +484,7 @@ namespace nana case 3: //param is the begin pos of an item in absolute. { - int beg = static_cast(tree_container.indent_size(node) * shape.indent_pixels) - shape.offset_x; + int beg = static_cast(tree.indent_size(node) * shape.indent_pixels) - shape.offset_x; int end = beg + static_cast(node_w_pixels(node)); bool take_adjust = false; @@ -499,16 +507,14 @@ namespace nana case 4: if(shape.first != node) { - unsigned off_first = tree_container.distance_if(shape.first, pred_allow_child()); - unsigned off_node = tree_container.distance_if(node, pred_allow_child()); - if(off_node < off_first) + if (node_pos < first_pos) { shape.first = node; return true; } - else if(off_node - off_first > max_allowed()) + else if (node_pos - first_pos > max_allow) { - shape.first = tree_container.advance_if(0, off_node - max_allowed() + 1, pred_allow_child()); + shape.first = tree.advance_if(nullptr, node_pos - max_allow + 1, pred_allow_child{}); return true; } } @@ -603,44 +609,24 @@ namespace nana { if(scroll.empty()) { - shape.prev_first_value = 0; scroll.create(*data.widget_ptr, nana::rectangle(data.graph->width() - 16, 0, 16, data.graph->height())); - auto fn = [this](const arg_mouse& arg){ - this->event_scrollbar(arg); - }; - auto & events = scroll.events(); - events.mouse_down(fn); - events.mouse_move(fn); - events.mouse_wheel(fn); + scroll.events().value_changed.connect_unignorable([this](const arg_scroll& arg) + { + adjust.scroll_timestamp = nana::system::timestamp(); + adjust.timer.start(); + + shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll.value(), pred_allow_child{}); + draw(false, false, true); + }); } scroll.amount(visual_items); scroll.range(max_allow); } - scroll.value(attr.tree_cont.distance_if(shape.first, pred_allow_child())); - } - - void event_scrollbar(const arg_mouse& arg) - { - if((event_code::mouse_wheel == arg.evt_code) || arg.is_left_button()) - { - if(shape.prev_first_value != shape.scroll.value()) - { - shape.prev_first_value = shape.scroll.value(); - adjust.scroll_timestamp = nana::system::timestamp(); - adjust.timer.start(); - - shape.first = attr.tree_cont.advance_if(nullptr, shape.prev_first_value, pred_allow_child()); - - if(arg.window_handle == shape.scroll.handle()) - { - draw(false); - API::update_window(data.widget_ptr->handle()); - } - } - } + auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{}); + scroll.value(pos); } std::size_t visual_item_size() const @@ -702,11 +688,10 @@ namespace nana attr.tree_cont.template for_each(shape.first, nl); bool redraw = false; - node_state.event_node = nl.node(); - - if(nl.node() && (nl.what() != component::end)) + auto const node = nl.node(); + if (node && (nl.what() != component::end)) { - if((nl.what() != node_state.comp_pointed || nl.node() != node_state.pointed)) + if ((nl.what() != node_state.comp_pointed) || (node != node_state.pointed)) { node_state.comp_pointed = nl.what(); @@ -715,12 +700,11 @@ namespace nana item_proxy iprx(data.trigger_ptr, node_state.pointed); data.widget_ptr->events().hovered.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, false }, data.widget_ptr->handle()); - if (nl.node() != node_state.pointed) + if (node != node_state.pointed) close_tooltip_window(); } - - node_state.pointed = nl.node(); + node_state.pointed = node; item_proxy iprx(data.trigger_ptr, node_state.pointed); data.widget_ptr->events().hovered.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, true }, data.widget_ptr->handle()); @@ -781,11 +765,11 @@ namespace nana }; auto & events = node_state.tooltip->events(); - events.mouse_leave(fn); - events.mouse_move(fn); - events.mouse_down.connect(fn); - events.mouse_up.connect(fn); - events.dbl_click.connect(fn); + events.mouse_leave.connect_unignorable(fn); + events.mouse_move.connect_unignorable(fn); + events.mouse_down.connect_unignorable(fn); + events.mouse_up.connect_unignorable(fn); + events.dbl_click.connect_unignorable(fn); } } @@ -1170,7 +1154,7 @@ namespace nana { switch(comp) { - case component_t::expender: + case component_t::expander: if(attr.has_children) { r->width = item_offset; @@ -1259,7 +1243,7 @@ namespace nana void expander(graph_reference graph, const compset_interface * compset) const override { comp_attribute_t attr; - if(compset->comp_attribute(component::expender, attr)) + if(compset->comp_attribute(component::expander, attr)) { facade arrow("solid_triangle"); arrow.direction(direction::southeast); @@ -1374,7 +1358,7 @@ namespace nana { node_ = &node; what_ = static_cast(comp); - if (component::expender == what_ && (false == node_attr_.has_children)) + if (component::expander == what_ && (false == node_attr_.has_children)) what_ = component::end; if (component::text == what_) @@ -1667,16 +1651,6 @@ namespace nana } } - auto trigger::tree() -> tree_cont_type & - { - return impl_->attr.tree_cont; - } - - auto trigger::tree() const -> tree_cont_type const & - { - return impl_->attr.tree_cont; - } - void trigger::renderer(::nana::pat::cloneable&& r) { impl_->data.renderer = std::move(r); @@ -1726,7 +1700,7 @@ namespace nana void trigger::selected(node_type* node) { - if(tree().verify(node) && impl_->set_selected(node)) + if(impl_->attr.tree_cont.verify(node) && impl_->set_selected(node)) impl_->draw(true); } @@ -1750,7 +1724,7 @@ namespace nana void trigger::node_icon(node_type* node, const std::string& id) { - if(tree().verify(node)) + if(impl_->attr.tree_cont.verify(node)) { node->value.second.img_idstr = id; auto i = impl_->shape.image_table.find(id); @@ -1768,7 +1742,7 @@ namespace nana bool trigger::rename(node_type *node, const char* key, const char* name) { - if((key || name ) && tree().verify(node)) + if((key || name ) && impl_->attr.tree_cont.verify(node)) { if(key && (key != node->value.first)) { @@ -1813,12 +1787,21 @@ namespace nana item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); impl_->attr.tree_cont.for_each(shape.first, nl); - if(nl.node() && (nl.what() == component::text || nl.what() == component::icon)) + auto const node = nl.node(); + if (!node) + return; + + auto & node_state = impl_->node_state; + switch (nl.what()) { - impl_->node_state.event_node = nl.node(); - impl_->set_expanded(impl_->node_state.event_node, !impl_->node_state.event_node->value.second.expanded); - impl_->draw(true); + case component::icon: + case component::text: + impl_->set_expanded(node, !node->value.second.expanded); + impl_->draw(true, true, false); API::dev::lazy_refresh(); + break; + default: + break; } } @@ -1833,26 +1816,19 @@ namespace nana bool has_redraw = false; auto & node_state = impl_->node_state; - node_state.event_node = nullptr; + node_state.pressed_node = nl.node(); - if(nl.node()) + if (node_state.pressed_node && (component::expander == nl.what())) { - node_state.event_node = nl.node(); - if(nl.what() != component::end) - { - if(nl.what() == component::expender) - { - if(impl_->set_expanded(node_state.event_node, !node_state.event_node->value.second.expanded)) - impl_->make_adjust(node_state.event_node, 0); + if(impl_->set_expanded(node_state.pressed_node, !node_state.pressed_node->value.second.expanded)) + impl_->make_adjust(node_state.pressed_node, 0); - has_redraw = true; //btw, don't select the node - } - } + has_redraw = true; //btw, don't select the node } - if ((!has_redraw) && (node_state.selected != node_state.event_node)) + if ((!has_redraw) && (node_state.selected != node_state.pressed_node)) { - impl_->set_selected(node_state.event_node); + impl_->set_selected(node_state.pressed_node); has_redraw = true; } @@ -1871,25 +1847,33 @@ namespace nana item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); impl_->attr.tree_cont.for_each(shape.first, nl); + auto const pressed_node = impl_->node_state.pressed_node; + impl_->node_state.pressed_node = nullptr; + if(!nl.node()) return; - if((impl_->node_state.selected != nl.node()) && nl.item_body()) + if (pressed_node == nl.node()) { - impl_->set_selected(nl.node()); - if(impl_->make_adjust(impl_->node_state.selected, 1)) - impl_->adjust.scroll_timestamp = 1; - } - else if (nl.what() == component::crook) - { - checkstate cs = checkstate::unchecked; - if (checkstate::unchecked == nl.node()->value.second.checked) - cs = checkstate::checked; + if ((impl_->node_state.selected != nl.node()) && nl.item_body()) + { + impl_->set_selected(nl.node()); + if (impl_->make_adjust(impl_->node_state.selected, 1)) + impl_->adjust.scroll_timestamp = 1; + } + else if (nl.what() == component::crook) + { + checkstate cs = checkstate::unchecked; + if (checkstate::unchecked == nl.node()->value.second.checked) + cs = checkstate::checked; - check(nl.node(), cs); + check(nl.node(), cs); + } + else + return; //Do not refresh } else - return; //Do not refresh + return; //Don't refresh impl_->draw(true); API::dev::lazy_refresh(); @@ -1906,18 +1890,19 @@ namespace nana void trigger::mouse_wheel(graph_reference, const arg_wheel& arg) { - auto & shape = impl_->shape; - std::size_t prev = shape.prev_first_value; + auto & scroll = impl_->shape.scroll; + if (scroll.empty()) + return; - shape.scroll.make_step(!arg.upwards); + auto const value_before = scroll.value(); - impl_->event_scrollbar(arg); + scroll.make_step(!arg.upwards); - if(prev != shape.prev_first_value) + if (value_before != scroll.value()) { impl_->track_mouse(arg.pos.x, arg.pos.y); - impl_->draw(false); + impl_->draw(false, true, true); API::dev::lazy_refresh(); } } @@ -2162,7 +2147,7 @@ namespace nana auto treebox::find(const std::string& keypath) -> item_proxy { auto * trg = &get_drawer_trigger(); - return item_proxy(trg, trg->tree().find(keypath)); + return item_proxy(trg, trg->impl()->attr.tree_cont.find(keypath)); } treebox::item_proxy treebox::insert(const std::string& path_key, std::string title) @@ -2192,7 +2177,7 @@ namespace nana std::string treebox::make_key_path(item_proxy i, const std::string& splitter) const { - auto & tree = get_drawer_trigger().tree(); + auto & tree = get_drawer_trigger().impl()->attr.tree_cont; auto pnode = i._m_node(); if(tree.verify(pnode)) {