add new overloading of scroll_into_view for treebox

This commit is contained in:
Jinhao 2018-09-09 05:52:59 +08:00
parent c1b88c430a
commit 074b96a05a
2 changed files with 112 additions and 72 deletions

View File

@ -450,8 +450,18 @@ namespace nana
item_proxy selected() const; ///< returns the selected node
/// Scrolls a specified item into view
void scroll_into_view(item_proxy item, align_v);
/// Scrolls a specified item into view.
/**
* @param item An item to be requested.
* @param bearing The position where the item to be positioned in the view.
*/
void scroll_into_view(item_proxy item, align_v bearing);
/// Scrolls a specified item into view.
/**
* @param item An item to be requested.
*/
void scroll_into_view(item_proxy item);
private:
std::shared_ptr<scroll_operation_interface> _m_scroll_operation() override;

View File

@ -578,6 +578,96 @@ namespace nana
return screen_px / item_px + 1;
}
bool scroll_into_view(node_type* node, bool use_bearing, align_v bearing)
{
auto & tree = attr.tree_cont;
auto parent = node->owner;
std::vector<node_type*> parent_path;
while (parent)
{
parent_path.push_back(parent);
parent = parent->owner;
}
bool has_expanded = false;
//Expands the shrinked nodes which are ancestors of node
for (auto i = parent_path.rbegin(); i != parent_path.rend(); ++i)
{
if (!(*i)->value.second.expanded)
{
has_expanded = true;
(*i)->value.second.expanded = true;
item_proxy iprx(data.trigger_ptr, *i);
data.widget_ptr->events().expanded.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, true }, data.widget_ptr->handle());
}
}
auto pos = tree.distance_if(node, pred_allow_child{});
auto last_pos = tree.distance_if(last(true), pred_allow_child{});
auto const capacity = screen_capacity(true);
auto const item_px = data.comp_placer->item_height(*data.graph);
//If use_bearing is false, it calculates a bearing depending on the current
//position of the requested item.
if (!use_bearing)
{
auto first_pos = tree.distance_if(shape.first, pred_allow_child{});
if (pos < first_pos)
bearing = align_v::top;
else if (pos >= first_pos + capacity)
bearing = align_v::bottom;
else
{
//The item is already in the view.
//Returns true if a draw operation is needed
return has_expanded;
}
}
if (align_v::top == bearing)
{
if (last_pos - pos + 1 < capacity)
{
if (last_pos + 1 >= capacity)
pos = last_pos + 1 - capacity;
else
pos = 0;
}
}
else if (align_v::center == bearing)
{
auto const short_side = (std::min)(pos, last_pos - pos);
if (short_side >= capacity / 2)
{
pos -= short_side;
}
else
{
if (short_side == pos || (last_pos + 1 < capacity))
pos = 0;
else
pos = last_pos + 1 - capacity;
}
}
else if (align_v::bottom == bearing)
{
if (pos + 1 >= capacity)
pos = pos + 1 - capacity;
else
pos = 0;
}
auto prv_first = shape.first;
shape.first = attr.tree_cont.advance_if(nullptr, pos, drawerbase::treebox::pred_allow_child{});
return has_expanded || (prv_first != shape.first);
}
bool make_adjust(node_type * node, int reason)
{
if(!node) return false;
@ -2287,79 +2377,19 @@ namespace nana
return item_proxy(const_cast<drawer_trigger_t*>(dw), dw->impl()->node_state.selected);
}
void treebox::scroll_into_view(item_proxy item, align_v align)
void treebox::scroll_into_view(item_proxy item, align_v bearing)
{
auto node = item._m_node();
internal_scope_guard lock;
auto impl = get_drawer_trigger().impl();
auto & tree = impl->attr.tree_cont;
auto parent = node->owner;
std::vector<drawerbase::treebox::node_type*> parent_path;
while (parent)
{
parent_path.push_back(parent);
parent = parent->owner;
}
//Expands the shrinked nodes which are ancestors of node
for (auto i = parent_path.rbegin(); i != parent_path.rend(); ++i)
{
if (!(*i)->value.second.expanded)
{
(*i)->value.second.expanded = true;
item_proxy iprx(impl->data.trigger_ptr, *i);
impl->data.widget_ptr->events().expanded.emit(::nana::arg_treebox{ *impl->data.widget_ptr, iprx, true }, impl->data.widget_ptr->handle());
}
}
auto pos = tree.distance_if(node, drawerbase::treebox::pred_allow_child{});
auto last_pos = tree.distance_if(impl->last(true), drawerbase::treebox::pred_allow_child{});
auto const capacity = impl->screen_capacity(false);
auto const item_px = impl->data.comp_placer->item_height(*impl->data.graph);
if (align_v::top == align)
{
if (last_pos - pos + 1 < capacity)
{
if (last_pos + 1 >= capacity)
pos = last_pos + 1 - capacity;
else
pos = 0;
}
}
else if (align_v::center == align)
{
auto const short_side = (std::min)(pos, last_pos - pos);
if (short_side >= capacity / 2)
{
pos -= short_side;
}
else
{
if (short_side == pos || (last_pos + 1 < capacity))
pos = 0;
else
pos = last_pos + 1 - capacity;
}
}
else if (align_v::bottom == align)
{
if (pos + 1 >= capacity)
pos = pos + 1 - capacity;
else
pos = 0;
}
impl->shape.first = impl->attr.tree_cont.advance_if(nullptr, pos, drawerbase::treebox::pred_allow_child{});
impl->draw(true, false, true);
API::update_window(*this);
if(get_drawer_trigger().impl()->scroll_into_view(item._m_node(), true, bearing))
API::refresh_window(*this);
}
void treebox::scroll_into_view(item_proxy item)
{
internal_scope_guard lock;
//The third argument for scroll_into_view is ignored if the second argument is false.
if(get_drawer_trigger().impl()->scroll_into_view(item._m_node(), false, align_v::center))
API::refresh_window(*this);
}
std::shared_ptr<scroll_operation_interface> treebox::_m_scroll_operation()