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
{
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<renderer_interface>&&);
const ::nana::pat::cloneable<renderer_interface>& renderer() const;
void placer(::nana::pat::cloneable<compset_placer_interface>&&);

View File

@@ -198,7 +198,7 @@ namespace nana
template<typename Renderer>
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<true> scroll;
std::size_t prev_first_value;
mutable std::map<std::string, node_image_tag> 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,35 +442,49 @@ 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 (node->value.second.expanded)
{
//adjust if the number of its children are over the max number allowed
if (shape.first != node)
{
unsigned child_size = tree_container.child_size_if(*node, pred_allow_child());
const std::size_t max_allow = max_allowed();
auto child_size = tree.child_size_if(*node, pred_allow_child());
if (child_size < max_allow)
{
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;
auto const size = node_pos - first_pos + child_size + 1;
if (size > max_allow)
shape.first = tree_container.advance_if(shape.first, size - max_allow, pred_allow_child());
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 = nullptr;
}
break;
case 1:
case 2:
case 3:
//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));
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<item_locator&>(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<element::arrow> arrow("solid_triangle");
arrow.direction(direction::southeast);
@@ -1374,7 +1358,7 @@ namespace nana
{
node_ = &node;
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;
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)
{
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<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();
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
}
}
}
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,9 +1847,14 @@ namespace nana
item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y);
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())
return;
if (pressed_node == nl.node())
{
if ((impl_->node_state.selected != nl.node()) && nl.item_body())
{
impl_->set_selected(nl.node());
@@ -1890,6 +1871,9 @@ namespace nana
}
else
return; //Do not refresh
}
else
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))
{