fix issues that occur when expands/shrinks treebox

This commit is contained in:
Jinhao
2017-02-20 03:41:04 +08:00
parent 9fa0bc2db9
commit 66be23c920
2 changed files with 114 additions and 132 deletions

View File

@@ -37,7 +37,7 @@ namespace nana
{ {
enum class component enum class component
{ {
begin, expender = begin, crook, icon, text, bground, end begin, expander = begin, crook, icon, text, bground, end
}; };
struct node_image_tag struct node_image_tag
@@ -120,9 +120,6 @@ namespace nana
void check(node_type*, checkstate); void check(node_type*, checkstate);
const tree_cont_type & tree() const;
tree_cont_type & tree();
void renderer(::nana::pat::cloneable<renderer_interface>&&); void renderer(::nana::pat::cloneable<renderer_interface>&&);
const ::nana::pat::cloneable<renderer_interface>& renderer() const; const ::nana::pat::cloneable<renderer_interface>& renderer() const;
void placer(::nana::pat::cloneable<compset_placer_interface>&&); void placer(::nana::pat::cloneable<compset_placer_interface>&&);

View File

@@ -198,7 +198,7 @@ namespace nana
template<typename Renderer> template<typename Renderer>
struct trigger::basic_implement struct trigger::basic_implement
{ {
typedef trigger::node_type node_type; using node_type = trigger::node_type;
struct rep_tag struct rep_tag
{ {
@@ -215,7 +215,6 @@ namespace nana
{ {
nana::upoint border; nana::upoint border;
nana::scroll<true> scroll; nana::scroll<true> scroll;
std::size_t prev_first_value;
mutable std::map<std::string, node_image_tag> image_table; mutable std::map<std::string, node_image_tag> image_table;
@@ -234,9 +233,9 @@ namespace nana
{ {
tooltip_window * tooltip; tooltip_window * tooltip;
component comp_pointed; component comp_pointed;
tree_cont_type::node_type * pointed; node_type * pointed;
tree_cont_type::node_type * selected; node_type * selected;
tree_cont_type::node_type * event_node; node_type * pressed_node;
}node_state; }node_state;
struct track_node_tag struct track_node_tag
@@ -259,7 +258,6 @@ namespace nana
data.widget_ptr = nullptr; data.widget_ptr = nullptr;
data.stop_drawing = false; data.stop_drawing = false;
shape.prev_first_value = 0;
shape.first = nullptr; shape.first = nullptr;
shape.indent_pixels = 10; shape.indent_pixels = 10;
shape.offset_x = 0; shape.offset_x = 0;
@@ -270,7 +268,7 @@ namespace nana
node_state.comp_pointed = component::end; node_state.comp_pointed = component::end;
node_state.pointed = nullptr; node_state.pointed = nullptr;
node_state.selected = nullptr; node_state.selected = nullptr;
node_state.event_node = nullptr; node_state.pressed_node = nullptr;
track_node.key_time = 0; track_node.key_time = 0;
@@ -321,9 +319,6 @@ namespace nana
if (node->is_ancestor_of(node_state.selected)) if (node->is_ancestor_of(node_state.selected))
node_state.selected = nullptr; node_state.selected = nullptr;
if (node->is_ancestor_of(node_state.event_node))
node_state.event_node = nullptr;
if (perf_clear) if (perf_clear)
{ {
if (node->child) if (node->child)
@@ -338,16 +333,15 @@ namespace nana
return true; 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(data.graph && (false == data.stop_drawing))
{ {
if (reset_scroll) if (reset_scroll)
show_scroll(); show_scroll();
if (attr.auto_draw) if (attr.auto_draw || ignore_auto_draw)
{ {
//Draw background //Draw background
data.graph->rectangle(true, data.widget_ptr->bgcolor()); data.graph->rectangle(true, data.widget_ptr->bgcolor());
@@ -448,27 +442,41 @@ namespace nana
{ {
if(!node) return false; 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) switch(reason)
{ {
case 0: case 0:
//adjust if the node expanded and the number of its children are over the max number allowed if (node->value.second.expanded)
if(shape.first != node)
{ {
unsigned child_size = tree_container.child_size_if(*node, pred_allow_child()); //adjust if the number of its children are over the max number allowed
const std::size_t max_allow = max_allowed(); if (shape.first != node)
if(child_size < max_allow)
{ {
unsigned off1 = tree_container.distance_if(shape.first, pred_allow_child()); auto child_size = tree.child_size_if(*node, pred_allow_child());
unsigned off2 = tree_container.distance_if(node, pred_allow_child()); if (child_size < max_allow)
const unsigned size = off2 - off1 + child_size + 1; {
if(size > max_allow) auto const size = node_pos - first_pos + child_size + 1;
shape.first = tree_container.advance_if(shape.first, size - max_allow, pred_allow_child()); 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 else
shape.first = node; shape.first = nullptr;
} }
break; break;
case 1: case 1:
@@ -476,7 +484,7 @@ namespace nana
case 3: case 3:
//param is the begin pos of an item in absolute. //param is the begin pos of an item in absolute.
{ {
int beg = static_cast<int>(tree_container.indent_size(node) * shape.indent_pixels) - shape.offset_x; int beg = static_cast<int>(tree.indent_size(node) * shape.indent_pixels) - shape.offset_x;
int end = beg + static_cast<int>(node_w_pixels(node)); int end = beg + static_cast<int>(node_w_pixels(node));
bool take_adjust = false; bool take_adjust = false;
@@ -499,16 +507,14 @@ namespace nana
case 4: case 4:
if(shape.first != node) if(shape.first != node)
{ {
unsigned off_first = tree_container.distance_if(shape.first, pred_allow_child()); if (node_pos < first_pos)
unsigned off_node = tree_container.distance_if(node, pred_allow_child());
if(off_node < off_first)
{ {
shape.first = node; shape.first = node;
return true; 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; return true;
} }
} }
@@ -603,44 +609,24 @@ namespace nana
{ {
if(scroll.empty()) if(scroll.empty())
{ {
shape.prev_first_value = 0;
scroll.create(*data.widget_ptr, nana::rectangle(data.graph->width() - 16, 0, 16, data.graph->height())); scroll.create(*data.widget_ptr, nana::rectangle(data.graph->width() - 16, 0, 16, data.graph->height()));
auto fn = [this](const arg_mouse& arg){ scroll.events().value_changed.connect_unignorable([this](const arg_scroll& arg)
this->event_scrollbar(arg); {
}; adjust.scroll_timestamp = nana::system::timestamp();
auto & events = scroll.events(); adjust.timer.start();
events.mouse_down(fn);
events.mouse_move(fn); shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll.value(), pred_allow_child{});
events.mouse_wheel(fn); draw(false, false, true);
});
} }
scroll.amount(visual_items); scroll.amount(visual_items);
scroll.range(max_allow); scroll.range(max_allow);
} }
scroll.value(attr.tree_cont.distance_if(shape.first, pred_allow_child())); auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{});
} scroll.value(pos);
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());
}
}
}
} }
std::size_t visual_item_size() const std::size_t visual_item_size() const
@@ -702,11 +688,10 @@ namespace nana
attr.tree_cont.template for_each<item_locator&>(shape.first, nl); attr.tree_cont.template for_each<item_locator&>(shape.first, nl);
bool redraw = false; bool redraw = false;
node_state.event_node = nl.node(); auto const node = nl.node();
if (node && (nl.what() != component::end))
if(nl.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(); node_state.comp_pointed = nl.what();
@@ -715,12 +700,11 @@ namespace nana
item_proxy iprx(data.trigger_ptr, node_state.pointed); 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()); 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(); close_tooltip_window();
} }
node_state.pointed = node;
node_state.pointed = nl.node();
item_proxy iprx(data.trigger_ptr, node_state.pointed); 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()); 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(); auto & events = node_state.tooltip->events();
events.mouse_leave(fn); events.mouse_leave.connect_unignorable(fn);
events.mouse_move(fn); events.mouse_move.connect_unignorable(fn);
events.mouse_down.connect(fn); events.mouse_down.connect_unignorable(fn);
events.mouse_up.connect(fn); events.mouse_up.connect_unignorable(fn);
events.dbl_click.connect(fn); events.dbl_click.connect_unignorable(fn);
} }
} }
@@ -1170,7 +1154,7 @@ namespace nana
{ {
switch(comp) switch(comp)
{ {
case component_t::expender: case component_t::expander:
if(attr.has_children) if(attr.has_children)
{ {
r->width = item_offset; r->width = item_offset;
@@ -1259,7 +1243,7 @@ namespace nana
void expander(graph_reference graph, const compset_interface * compset) const override void expander(graph_reference graph, const compset_interface * compset) const override
{ {
comp_attribute_t attr; comp_attribute_t attr;
if(compset->comp_attribute(component::expender, attr)) if(compset->comp_attribute(component::expander, attr))
{ {
facade<element::arrow> arrow("solid_triangle"); facade<element::arrow> arrow("solid_triangle");
arrow.direction(direction::southeast); arrow.direction(direction::southeast);
@@ -1374,7 +1358,7 @@ namespace nana
{ {
node_ = &node; node_ = &node;
what_ = static_cast<component>(comp); what_ = static_cast<component>(comp);
if (component::expender == what_ && (false == node_attr_.has_children)) if (component::expander == what_ && (false == node_attr_.has_children))
what_ = component::end; what_ = component::end;
if (component::text == what_) 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<renderer_interface>&& r) void trigger::renderer(::nana::pat::cloneable<renderer_interface>&& r)
{ {
impl_->data.renderer = std::move(r); impl_->data.renderer = std::move(r);
@@ -1726,7 +1700,7 @@ namespace nana
void trigger::selected(node_type* node) 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); impl_->draw(true);
} }
@@ -1750,7 +1724,7 @@ namespace nana
void trigger::node_icon(node_type* node, const std::string& id) 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; node->value.second.img_idstr = id;
auto i = impl_->shape.image_table.find(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) 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)) if(key && (key != node->value.first))
{ {
@@ -1813,12 +1787,21 @@ namespace nana
item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y);
impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl); impl_->attr.tree_cont.for_each<item_locator&>(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(); case component::icon:
impl_->set_expanded(impl_->node_state.event_node, !impl_->node_state.event_node->value.second.expanded); case component::text:
impl_->draw(true); impl_->set_expanded(node, !node->value.second.expanded);
impl_->draw(true, true, false);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
break;
default:
break;
} }
} }
@@ -1833,26 +1816,19 @@ namespace nana
bool has_redraw = false; bool has_redraw = false;
auto & node_state = impl_->node_state; 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(impl_->set_expanded(node_state.pressed_node, !node_state.pressed_node->value.second.expanded))
if(nl.what() != component::end) impl_->make_adjust(node_state.pressed_node, 0);
{
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);
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; has_redraw = true;
} }
@@ -1871,25 +1847,33 @@ namespace nana
item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y);
impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl); impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl);
auto const pressed_node = impl_->node_state.pressed_node;
impl_->node_state.pressed_node = nullptr;
if(!nl.node()) if(!nl.node())
return; return;
if((impl_->node_state.selected != nl.node()) && nl.item_body()) if (pressed_node == nl.node())
{ {
impl_->set_selected(nl.node()); if ((impl_->node_state.selected != nl.node()) && nl.item_body())
if(impl_->make_adjust(impl_->node_state.selected, 1)) {
impl_->adjust.scroll_timestamp = 1; impl_->set_selected(nl.node());
} if (impl_->make_adjust(impl_->node_state.selected, 1))
else if (nl.what() == component::crook) impl_->adjust.scroll_timestamp = 1;
{ }
checkstate cs = checkstate::unchecked; else if (nl.what() == component::crook)
if (checkstate::unchecked == nl.node()->value.second.checked) {
cs = checkstate::checked; 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 else
return; //Do not refresh return; //Don't refresh
impl_->draw(true); impl_->draw(true);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
@@ -1906,18 +1890,19 @@ namespace nana
void trigger::mouse_wheel(graph_reference, const arg_wheel& arg) void trigger::mouse_wheel(graph_reference, const arg_wheel& arg)
{ {
auto & shape = impl_->shape; auto & scroll = impl_->shape.scroll;
std::size_t prev = shape.prev_first_value; 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_->track_mouse(arg.pos.x, arg.pos.y);
impl_->draw(false); impl_->draw(false, true, true);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
} }
@@ -2162,7 +2147,7 @@ namespace nana
auto treebox::find(const std::string& keypath) -> item_proxy auto treebox::find(const std::string& keypath) -> item_proxy
{ {
auto * trg = &get_drawer_trigger(); 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) 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 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(); auto pnode = i._m_node();
if(tree.verify(pnode)) if(tree.verify(pnode))
{ {