Merge remote-tracking branch 'cnjinhao/develop' into develop

This commit is contained in:
qPCR4vir 2020-02-05 13:26:03 +01:00
commit ec4e7cf33e
3 changed files with 150 additions and 115 deletions

View File

@ -1,6 +1,6 @@
/* /*
* A Tree Container class implementation * A Tree Container class implementation
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -95,6 +95,13 @@ namespace detail
typedef tree_node<element_type> node_type; typedef tree_node<element_type> node_type;
typedef typename node_type::value_type value_type; typedef typename node_type::value_type value_type;
enum class enum_order
{
stop, //Stop enumeration
proceed_with_children,
proceed
};
tree_cont() tree_cont()
:root_(nullptr) :root_(nullptr)
{} {}
@ -234,59 +241,6 @@ namespace detail
return 0; return 0;
} }
template<typename Functor>
void for_each(node_type* node, Functor f)
{
if(nullptr == node) node = root_.child;
int state = 0; //0: Sibling, the last is a sibling of node
//1: Owner, the last is the owner of node
//>= 2: Children, the last is is a child of the node that before this node.
while(node)
{
switch(f(*node, state))
{
case 0: return;
case 1:
{
if(node->child)
{
node = node->child;
state = 1;
}
else
return;
continue;
}
break;
}
if(node->next)
{
node = node->next;
state = 0;
}
else
{
state = 1;
if(node == &root_) return;
while(true)
{
++state;
if(node->owner->next)
{
node = node->owner->next;
break;
}
else
node = node->owner;
if(node == &root_) return;
}
}
}
}
template<typename Functor> template<typename Functor>
void for_each(node_type* node, Functor f) const void for_each(node_type* node, Functor f) const
{ {
@ -296,24 +250,18 @@ namespace detail
//>= 2: Children, the last is is a child of the node that before this node. //>= 2: Children, the last is is a child of the node that before this node.
while(node) while(node)
{ {
switch(f(*node, state)) enum_order order = f(*node, state);
if (enum_order::stop == order)
{ {
case 0: return; return;
case 1: }
{ else if (node->child && (enum_order::proceed_with_children == order))
if(node->child)
{ {
node = node->child; node = node->child;
state = 1; state = 1;
} }
else else if(node->next)
return;
continue;
}
break;
}
if(node->next)
{ {
node = node->next; node = node->next;
state = 0; state = 0;
@ -340,31 +288,37 @@ namespace detail
} }
} }
template<typename PredAllowChild> template<typename PredAllowChild, typename PredAllowNode>
unsigned child_size_if(const ::std::string& key, PredAllowChild pac) const unsigned child_size_if(const ::std::string& key, PredAllowChild pac, PredAllowNode pan) const
{ {
auto node = _m_locate(key); auto node = _m_locate(key);
return (node ? child_size_if<PredAllowChild>(*node, pac) : 0); return (node ? child_size_if<PredAllowChild, PredAllowNode>(*node, pac, pan) : 0);
} }
template<typename PredAllowChild> template<typename PredAllowChild, typename PredAllowNode>
unsigned child_size_if(const node_type& node, PredAllowChild pac) const unsigned child_size_if(const node_type& node, PredAllowChild pac, PredAllowNode pan) const
{ {
unsigned size = 0; unsigned size = 0;
const node_type* pnode = node.child; const node_type* pnode = node.child;
while(pnode) while(pnode)
{ {
if (!pan(*pnode))
{
pnode = pnode->next;
continue;
}
++size; ++size;
if(pnode->child && pac(*pnode)) if(pnode->child && pac(*pnode))
size += child_size_if<PredAllowChild>(*pnode, pac); size += child_size_if<PredAllowChild>(*pnode, pac, pan);
pnode = pnode->next; pnode = pnode->next;
} }
return size; return size;
} }
template<typename PredAllowChild> template<typename PredAllowChild, typename PredAllowNode>
std::size_t distance_if(const node_type * node, PredAllowChild pac) const std::size_t distance_if(const node_type * node, PredAllowChild pac, PredAllowNode pan) const
{ {
if(nullptr == node) return 0; if(nullptr == node) return 0;
const node_type * iterator = root_.child; const node_type * iterator = root_.child;
@ -374,6 +328,12 @@ namespace detail
while(iterator && iterator != node) while(iterator && iterator != node)
{ {
if (!pan(*iterator))
{
iterator = iterator->next;
continue;
}
++off; ++off;
if(iterator->child && pac(*iterator)) if(iterator->child && pac(*iterator))
@ -393,8 +353,8 @@ namespace detail
return off; return off;
} }
template<typename PredAllowChild> template<typename PredAllowChild, typename PredAllowNode>
node_type* advance_if(node_type* node, std::size_t off, PredAllowChild pac) node_type* advance_if(node_type* node, std::size_t off, PredAllowChild pac, PredAllowNode pan)
{ {
if(nullptr == node) node = root_.child; if(nullptr == node) node = root_.child;
@ -402,6 +362,12 @@ namespace detail
while(node && off) while(node && off)
{ {
if (!pan(*node))
{
node = node->next;
continue;
}
--off; --off;
if(node->child && pac(*node)) if(node->child && pac(*node))
{ {
@ -490,7 +456,7 @@ namespace detail
void _m_for_each(const ::std::string& key, Function function) const void _m_for_each(const ::std::string& key, Function function) const
{ {
//Ignores separaters at the begin of key. //Ignores separaters at the begin of key.
::std::string::size_type beg = key.find_first_not_of("\\/"); auto beg = key.find_first_not_of("\\/");
if (key.npos == beg) if (key.npos == beg)
return; return;

View File

@ -1,7 +1,7 @@
/** /**
* A Tree Box Implementation * A Tree Box Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at * (See accompanying file LICENSE or copy at
@ -49,7 +49,7 @@ namespace nana
struct node_attribute struct node_attribute
{ {
bool has_children; bool has_children; ///< Determines whether the node has visible children
bool expended; bool expended;
checkstate checked; checkstate checked;
bool selected; bool selected;
@ -117,6 +117,7 @@ namespace nana
::std::string text; ::std::string text;
nana::any value; nana::any value;
bool expanded; bool expanded;
bool hidden;
checkstate checked; checkstate checked;
::std::string img_idstr; ::std::string img_idstr;
}; };
@ -218,6 +219,12 @@ namespace nana
/// Select the node, and returns itself.. /// Select the node, and returns itself..
item_proxy& select(bool); item_proxy& select(bool);
/// Return true when the node is hidden.
bool hidden() const;
/// Hide the node, and returns itself.
item_proxy& hide(bool);
/// Return the icon. /// Return the icon.
const ::std::string& icon() const; const ::std::string& icon() const;
@ -343,6 +350,7 @@ namespace nana
basic_event<arg_treebox> checked; ///< a user checks or unchecks a node basic_event<arg_treebox> checked; ///< a user checks or unchecks a node
basic_event<arg_treebox> selected; ///< a user selects or unselects a node basic_event<arg_treebox> selected; ///< a user selects or unselects a node
basic_event<arg_treebox> hovered; ///< a user moves the cursor over a node basic_event<arg_treebox> hovered; ///< a user moves the cursor over a node
basic_event<arg_treebox> hidden; ///< a user hides or shows a node
}; };
}//end namespace treebox }//end namespace treebox
}//end namespace drawerbase }//end namespace drawerbase

View File

@ -1,7 +1,7 @@
/* /*
* A Treebox Implementation * A Treebox Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -70,7 +70,7 @@ namespace nana
const node_type* find_track_child_node(const node_type* node, const node_type * end, const char* pattern, std::size_t len, bool &finish) const node_type* find_track_child_node(const node_type* node, const node_type * end, const char* pattern, std::size_t len, bool &finish)
{ {
if(node->value.second.expanded) if(node->value.second.expanded && !node->value.second.hidden)
{ {
node = node->child; node = node->child;
while(node) while(node)
@ -79,7 +79,7 @@ namespace nana
if(node == end) break; if(node == end) break;
if(node->value.second.expanded) if(node->value.second.expanded && !node->value.second.hidden)
{ {
auto t = find_track_child_node(node, end, pattern, len, finish); auto t = find_track_child_node(node, end, pattern, len, finish);
if(t || finish) if(t || finish)
@ -184,10 +184,11 @@ namespace nana
class trigger::item_locator class trigger::item_locator
{ {
public: public:
using enum_order = tree_cont_type::enum_order;
using node_type = tree_cont_type::node_type; using node_type = tree_cont_type::node_type;
item_locator(implementation * impl, int item_pos, int x, int y); item_locator(implementation * impl, int item_pos, int x, int y);
int operator()(node_type &node, int affect); enum_order operator()(node_type &node, int affect);
node_type * node() const; node_type * node() const;
component what() const; component what() const;
bool item_body() const; bool item_body() const;
@ -212,6 +213,14 @@ namespace nana
} }
}; };
struct pred_allow_node
{
bool operator()(const trigger::tree_cont_type::node_type& node)
{
return !node.value.second.hidden;
}
};
//struct implementation //struct implementation
//@brief: some data for treebox trigger //@brief: some data for treebox trigger
class trigger::implementation class trigger::implementation
@ -220,6 +229,7 @@ namespace nana
: public compset_interface : public compset_interface
{ {
public: public:
using enum_order = tree_cont_type::enum_order;
using node_type = tree_cont_type::node_type; using node_type = tree_cont_type::node_type;
item_rendering_director(implementation * impl, const nana::point& pos): item_rendering_director(implementation * impl, const nana::point& pos):
@ -232,9 +242,11 @@ namespace nana
//0 = Sibling, the last is a sibling of node //0 = Sibling, the last is a sibling of node
//1 = Owner, the last is the owner of node //1 = Owner, the last is the owner of node
//>=2 = Children, the last is a child of a node that before this node. //>=2 = Children, the last is a child of a node that before this node.
int operator()(const node_type& node, int affect) enum_order operator()(const node_type& node, int affect)
{ {
iterated_node_ = &node; iterated_node_ = &node;
// Increase/decrease indent
switch (affect) switch (affect)
{ {
case 1: case 1:
@ -245,6 +257,9 @@ namespace nana
pos_.x -= impl_->data.scheme_ptr->indent_displacement * (affect - 1); pos_.x -= impl_->data.scheme_ptr->indent_displacement * (affect - 1);
} }
if (iterated_node_->value.second.hidden) // Skip drawing if the node is hidden
return enum_order::proceed;
auto & comp_placer = impl_->data.comp_placer; auto & comp_placer = impl_->data.comp_placer;
impl_->assign_node_attr(node_attr_, iterated_node_); impl_->assign_node_attr(node_attr_, iterated_node_);
@ -263,9 +278,9 @@ namespace nana
pos_.y += node_r_.height; pos_.y += node_r_.height;
if (pos_.y > static_cast<int>(impl_->data.graph->height())) if (pos_.y > static_cast<int>(impl_->data.graph->height()))
return 0; return enum_order::stop;
return (node.child && node.value.second.expanded ? 1 : 2); return ((node.child && node.value.second.expanded) ? enum_order::proceed_with_children : enum_order::proceed);
} }
private: private:
//Overrides compset_interface //Overrides compset_interface
@ -375,7 +390,18 @@ namespace nana
void assign_node_attr(node_attribute& ndattr, const node_type* node) const void assign_node_attr(node_attribute& ndattr, const node_type* node) const
{ {
ndattr.has_children = (nullptr != node->child); // Check if there is a visible child that node has.
// This is an improvement based on a new feature that allows treebox node to be hidden(PR#500)
ndattr.has_children = false;
for (auto p = node->child; p; p = p->next)
{
if (!p->value.second.hidden)
{
ndattr.has_children = true;
break;
}
}
ndattr.expended = node->value.second.expanded; ndattr.expended = node->value.second.expanded;
ndattr.text = node->value.second.text; ndattr.text = node->value.second.text;
ndattr.checked = node->value.second.checked; ndattr.checked = node->value.second.checked;
@ -552,7 +578,7 @@ namespace nana
if (p->child) if (p->child)
{ {
if (p->value.second.expanded || !ignore_folded_children) if ((p->value.second.expanded || !ignore_folded_children) && !p->value.second.hidden)
{ {
p = p->child; p = p->child;
continue; continue;
@ -603,8 +629,8 @@ namespace nana
} }
} }
auto pos = tree.distance_if(node, pred_allow_child{}); auto pos = tree.distance_if(node, pred_allow_child{}, pred_allow_node{});
auto last_pos = tree.distance_if(last(true), pred_allow_child{}); auto last_pos = tree.distance_if(last(true), pred_allow_child{}, pred_allow_node{});
auto const capacity = screen_capacity(true); auto const capacity = screen_capacity(true);
@ -612,7 +638,7 @@ namespace nana
//position of the requested item. //position of the requested item.
if (!use_bearing) if (!use_bearing)
{ {
auto first_pos = tree.distance_if(shape.first, pred_allow_child{}); auto first_pos = tree.distance_if(shape.first, pred_allow_child{}, pred_allow_node{});
if (pos < first_pos) if (pos < first_pos)
bearing = align_v::top; bearing = align_v::top;
@ -655,7 +681,7 @@ namespace nana
} }
auto prv_first = shape.first; auto prv_first = shape.first;
shape.first = attr.tree_cont.advance_if(nullptr, pos, drawerbase::treebox::pred_allow_child{}); shape.first = attr.tree_cont.advance_if(nullptr, pos, drawerbase::treebox::pred_allow_child{}, pred_allow_node{});
//Update the position of scroll //Update the position of scroll
show_scroll(); show_scroll();
@ -669,8 +695,8 @@ namespace nana
auto & tree = attr.tree_cont; auto & tree = attr.tree_cont;
auto const first_pos = tree.distance_if(shape.first, pred_allow_child{}); auto const first_pos = tree.distance_if(shape.first, pred_allow_child{}, pred_allow_node{});
auto const node_pos = tree.distance_if(node, pred_allow_child{}); auto const node_pos = tree.distance_if(node, pred_allow_child{}, pred_allow_node{});
auto const max_allow = max_allowed(); auto const max_allow = max_allowed();
switch(reason) switch(reason)
{ {
@ -680,12 +706,12 @@ namespace nana
//adjust if the number of its children are over the max number allowed //adjust if the number of its children are over the max number allowed
if (shape.first != node) if (shape.first != node)
{ {
auto child_size = tree.child_size_if(*node, pred_allow_child()); auto child_size = tree.child_size_if(*node, pred_allow_child(), pred_allow_node{});
if (child_size < max_allow) if (child_size < max_allow)
{ {
auto const size = node_pos - first_pos + child_size + 1; auto const size = node_pos - first_pos + child_size + 1;
if (size > max_allow) if (size > max_allow)
shape.first = tree.advance_if(shape.first, size - max_allow, pred_allow_child{}); shape.first = tree.advance_if(shape.first, size - max_allow, pred_allow_child{}, pred_allow_node{});
} }
else else
shape.first = node; shape.first = node;
@ -698,7 +724,7 @@ namespace nana
if (visual_size > max_allow) if (visual_size > max_allow)
{ {
if (first_pos + max_allow > visual_size) if (first_pos + max_allow > visual_size)
shape.first = tree.advance_if(nullptr, visual_size - max_allow, pred_allow_child{}); shape.first = tree.advance_if(nullptr, visual_size - max_allow, pred_allow_child{}, pred_allow_node{});
} }
else else
shape.first = nullptr; shape.first = nullptr;
@ -739,7 +765,7 @@ namespace nana
} }
else if (node_pos - first_pos > max_allow) else if (node_pos - first_pos > max_allow)
{ {
shape.first = tree.advance_if(nullptr, node_pos - max_allow + 1, pred_allow_child{}); shape.first = tree.advance_if(nullptr, node_pos - max_allow + 1, pred_allow_child{}, pred_allow_node{});
return true; return true;
} }
} }
@ -814,6 +840,27 @@ namespace nana
return false; return false;
} }
bool set_hidden(node_type* node, bool value)
{
if (node && node->value.second.hidden != value)
{
if (value == false)
{
//if hiding a parent of the selected node or the selected node itself - select nothing.
if (node->is_ancestor_of(node_state.selected) || node_state.selected == node)
set_selected(nullptr);
}
node->value.second.hidden = value;
data.stop_drawing = true;
item_proxy iprx(data.trigger_ptr, node);
data.widget_ptr->events().hidden.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, value }, data.widget_ptr->handle());
data.stop_drawing = false;
return true;
}
return false;
}
void show_scroll() void show_scroll()
{ {
if(nullptr == data.graph) return; if(nullptr == data.graph) return;
@ -841,7 +888,7 @@ namespace nana
adjust.scroll_timestamp = nana::system::timestamp(); adjust.scroll_timestamp = nana::system::timestamp();
adjust.timer.start(); adjust.timer.start();
shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll->value(), pred_allow_child{}); shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll->value(), pred_allow_child{}, pred_allow_node{});
draw(false, false, true); draw(false, false, true);
}); });
} }
@ -850,13 +897,13 @@ namespace nana
scroll.range(max_allow); scroll.range(max_allow);
} }
auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{}); auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{}, pred_allow_node{});
scroll.value(pos); scroll.value(pos);
} }
std::size_t visual_item_size() const std::size_t visual_item_size() const
{ {
return attr.tree_cont.child_size_if(std::string(), pred_allow_child{}); return attr.tree_cont.child_size_if(std::string(), pred_allow_child{}, pred_allow_node{});
} }
int visible_w_pixels() const int visible_w_pixels() const
@ -1153,6 +1200,20 @@ namespace nana
return *this; return *this;
} }
bool item_proxy::hidden() const
{
return node_->value.second.hidden;
}
item_proxy& item_proxy::hide(bool h)
{
auto* impl = trigger_->impl();
if (impl->set_hidden(node_, h))
impl->draw(true);
return *this;
}
const std::string& item_proxy::icon() const const std::string& item_proxy::icon() const
{ {
return node_->value.second.img_idstr; return node_->value.second.img_idstr;
@ -1398,7 +1459,7 @@ namespace nana
switch(comp) switch(comp)
{ {
case component_t::expander: case component_t::expander:
if(attr.has_children) if (attr.has_children)
{ {
r->width = scheme_.item_offset; r->width = scheme_.item_offset;
return true; return true;
@ -1584,7 +1645,7 @@ namespace nana
node_(nullptr) node_(nullptr)
{} {}
int trigger::item_locator::operator()(node_type &node, int affect) auto trigger::item_locator::operator()(node_type &node, int affect) -> enum_order
{ {
switch(affect) switch(affect)
{ {
@ -1595,6 +1656,9 @@ namespace nana
item_pos_.x -= static_cast<int>(impl_->data.scheme_ptr->indent_displacement) * (affect - 1); item_pos_.x -= static_cast<int>(impl_->data.scheme_ptr->indent_displacement) * (affect - 1);
} }
if (node.value.second.hidden) // Do not account for hidden nodes
return enum_order::proceed;
impl_->assign_node_attr(node_attr_, &node); impl_->assign_node_attr(node_attr_, &node);
nana::rectangle node_r; nana::rectangle node_r;
auto & comp_placer = impl_->data.comp_placer; auto & comp_placer = impl_->data.comp_placer;
@ -1626,15 +1690,12 @@ namespace nana
} }
} }
return 0; //Stop iterating return enum_order::stop; //Stop iterating
} }
item_pos_.y += node_r.height; item_pos_.y += node_r.height;
if(node.value.second.expanded && node.child) return ((node.child && node.value.second.expanded) ? enum_order::proceed_with_children : enum_order::proceed);
return 1;
return 2;
} }
trigger::item_locator::node_type * trigger::item_locator::node() const trigger::item_locator::node_type * trigger::item_locator::node() const
@ -1665,11 +1726,11 @@ namespace nana
//class trigger //class trigger
//struct treebox_node_type //struct treebox_node_type
trigger::treebox_node_type::treebox_node_type() trigger::treebox_node_type::treebox_node_type()
:expanded(false), checked(checkstate::unchecked) :expanded(false), checked(checkstate::unchecked), hidden(false)
{} {}
trigger::treebox_node_type::treebox_node_type(std::string text) trigger::treebox_node_type::treebox_node_type(std::string text)
:text(std::move(text)), expanded(false), checked(checkstate::unchecked) :text(std::move(text)), expanded(false), checked(checkstate::unchecked), hidden(false)
{} {}
trigger::treebox_node_type& trigger::treebox_node_type::operator=(const treebox_node_type& rhs) trigger::treebox_node_type& trigger::treebox_node_type::operator=(const treebox_node_type& rhs)