Merge remote-tracking branch 'cnjinhao/develop-1.7' into cmake-dev

This commit is contained in:
qPCR4vir 2018-10-01 11:39:04 +02:00
commit 65d2440e26
11 changed files with 441 additions and 185 deletions

View File

@ -211,10 +211,10 @@
#undef _nana_std_optional #undef _nana_std_optional
#if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703))) || \ #if ((defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703))) || \
((__cplusplus < 201703L) || \ ((!defined(_MSC_VER)) && ((__cplusplus < 201703L) || \
(defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ < 400)) || \ (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ < 400)) || \
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 701)) \ (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 701))) \
) )
# define _nana_std_optional # define _nana_std_optional
#endif #endif

View File

@ -1,7 +1,7 @@
/* /*
* An Animation Implementation * An Animation Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2018 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
@ -49,24 +49,18 @@ namespace nana
struct impl; struct impl;
class performance_manager; class performance_manager;
/// Non-copyable
animation(const animation&) = delete;
animation& operator=(const animation&) = delete;
public: public:
animation(std::size_t fps = 23); animation(std::size_t fps = 23);
~animation(); ~animation();
void push_back(frameset frms); animation(animation&&);
/* animation& operator=(animation&&);
void branch(const std::string& name, const frameset& frms)
{
impl_->branches[name].frames = frms;
}
void branch(const std::string& name, const frameset& frms, std::function<std::size_t(const std::string&, std::size_t, std::size_t&)> condition) void push_back(frameset frms);
{
auto & br = impl_->branches[name];
br.frames = frms;
br.condition = condition;
}
*/
void looped(bool enable); ///< Enables or disables the animation repeating playback. void looped(bool enable); ///< Enables or disables the animation repeating playback.

View File

@ -1,7 +1,7 @@
/* /*
* A Menubar implementation * A Menubar implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2017 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2009-2018 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
@ -34,26 +34,6 @@ namespace nana
color_proxy border_highlight{ colors::highlight }; color_proxy border_highlight{ colors::highlight };
}; };
class item_renderer
{
public:
enum class state
{
normal, highlighted, selected
};
using graph_reference = paint::graphics&;
using scheme = ::nana::drawerbase::menubar::scheme;
item_renderer(window, graph_reference);
virtual void background(const point&, const ::nana::size&, state);
virtual void caption(const point&, const native_string_type&);
scheme *scheme_ptr() const { return scheme_ptr_; };
private:
graph_reference graph_;
scheme *scheme_ptr_;
};
class trigger class trigger
: public drawer_trigger : public drawer_trigger
{ {

View File

@ -87,13 +87,15 @@ namespace nana
class trigger class trigger
:public drawer_trigger :public drawer_trigger
{ {
template<typename Renderer> //template<typename Renderer>
struct basic_implement; //struct basic_implement; //deprecated
class item_renderer; class implementation;
//class item_renderer; //deprecated
class item_locator; class item_locator;
typedef basic_implement<item_renderer> implement; //typedef basic_implement<item_renderer> implement; //deprecated
public: public:
struct treebox_node_type struct treebox_node_type
{ {
@ -116,27 +118,30 @@ namespace nana
trigger(); trigger();
~trigger(); ~trigger();
implement * impl() const; implementation * impl() const;
void check(node_type*, checkstate); void check(node_type*, checkstate);
void renderer(::nana::pat::cloneable<renderer_interface>&&); pat::cloneable<renderer_interface>& renderer() const;
const ::nana::pat::cloneable<renderer_interface>& renderer() const;
//void renderer(::nana::pat::cloneable<renderer_interface>&&);
//const ::nana::pat::cloneable<renderer_interface>& renderer() const; //deprecated
void placer(::nana::pat::cloneable<compset_placer_interface>&&); void placer(::nana::pat::cloneable<compset_placer_interface>&&);
const ::nana::pat::cloneable<compset_placer_interface>& placer() const; const ::nana::pat::cloneable<compset_placer_interface>& placer() const;
node_type* insert(node_type*, const std::string& key, std::string&&); node_type* insert(node_type*, const std::string& key, std::string&&);
node_type* insert(const std::string& path, std::string&&); node_type* insert(const std::string& path, std::string&&);
node_type * selected() const; //node_type * selected() const; //deprecated
void selected(node_type*); //void selected(node_type*);
node_image_tag& icon(const ::std::string&) const; node_image_tag& icon(const ::std::string&);
void icon_erase(const ::std::string&); void icon_erase(const ::std::string&);
void node_icon(node_type*, const ::std::string& id); void node_icon(node_type*, const ::std::string& id);
unsigned node_width(const node_type*) const; unsigned node_width(const node_type*) const;
bool rename(node_type*, const char* key, const char* name); bool rename(node_type*, const char* key, const char* name);
private: private:
//Overrides drawer_trigger methods //Overrides drawer_trigger methods
void attached(widget_reference, graph_reference) override; void attached(widget_reference, graph_reference) override;
@ -152,7 +157,7 @@ namespace nana
void key_press(graph_reference, const arg_keyboard&) override; void key_press(graph_reference, const arg_keyboard&) override;
void key_char(graph_reference, const arg_keyboard&) override; void key_char(graph_reference, const arg_keyboard&) override;
private: private:
implement * const impl_; implementation * const impl_;
}; //end class trigger }; //end class trigger
@ -171,11 +176,11 @@ namespace nana
/// Append a child with a specified value (user object.). /// Append a child with a specified value (user object.).
template<typename T> template<typename T>
item_proxy append(const ::std::string& key, ::std::string name, const T&t) item_proxy append(const ::std::string& key, ::std::string name, T&& t)
{ {
item_proxy ip = append(key, std::move(name)); item_proxy ip = append(key, std::move(name));
if(false == ip.empty()) if(false == ip.empty())
ip.value(t); ip.value(std::forward<T>(t));
return ip; return ip;
} }
@ -291,17 +296,19 @@ namespace nana
return *p; return *p;
} }
/*
template<typename T> template<typename T>
item_proxy & value(const T& t) item_proxy & value(const T& t) //deprecated
{ {
_m_value() = t; _m_value() = t;
return *this; return *this;
} }
*/
template<typename T> template<typename T>
item_proxy & value(T&& t) item_proxy & value(T&& t)
{ {
_m_value() = std::move(t); _m_value() = std::forward<T>(t);
return *this; return *this;
} }
@ -378,7 +385,7 @@ namespace nana
template<typename ItemRenderer> template<typename ItemRenderer>
treebox & renderer(const ItemRenderer & rd) ///< set user-defined node renderer treebox & renderer(const ItemRenderer & rd) ///< set user-defined node renderer
{ {
get_drawer_trigger().renderer(::nana::pat::cloneable<renderer_interface>(rd)); get_drawer_trigger().renderer() = ::nana::pat::cloneable<renderer_interface>{rd};
return *this; return *this;
} }
@ -403,6 +410,23 @@ namespace nana
/// @param enable bool whether to enable. /// @param enable bool whether to enable.
void auto_draw(bool enable); void auto_draw(bool enable);
/// Prevents drawing during execution.
template<typename Function>
void avoid_drawing(Function fn)
{
this->auto_draw(false);
try
{
fn();
}
catch (...)
{
this->auto_draw(true);
throw;
}
this->auto_draw(true);
}
/// \brief Enable the checkboxs for each item of the widget. /// \brief Enable the checkboxs for each item of the widget.
/// @param enable bool indicates whether to show or hide the checkboxs. /// @param enable bool indicates whether to show or hide the checkboxs.
treebox & checkable(bool enable); treebox & checkable(bool enable);
@ -419,8 +443,9 @@ namespace nana
/// These states are 'normal', 'hovered' and 'expanded'. /// These states are 'normal', 'hovered' and 'expanded'.
/// If 'hovered' or 'expanded' are not set, it uses 'normal' state image for these 2 states. /// If 'hovered' or 'expanded' are not set, it uses 'normal' state image for these 2 states.
/// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm) /// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm)
node_image_type& icon(const ::std::string& id ///< the name of an icon scheme. If the name is not existing, it creates a new scheme for the name. /// @param id The name of an icon scheme. If the name is not existing, it creates a new scheme for the name.
) const; /// @return The reference of node image scheme correspending with the specified id.
node_image_type& icon(const ::std::string& id);
void icon_erase(const ::std::string& id); void icon_erase(const ::std::string& id);
@ -445,6 +470,19 @@ namespace nana
item_proxy selected() const; ///< returns the selected node item_proxy selected() const; ///< returns the selected node
/// 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: private:
std::shared_ptr<scroll_operation_interface> _m_scroll_operation() override; std::shared_ptr<scroll_operation_interface> _m_scroll_operation() override;

View File

@ -658,21 +658,31 @@ namespace detail
platform_scope_guard lock; platform_scope_guard lock;
if(umake_owner(wd)) if(umake_owner(wd))
{ {
auto & wd_manager = detail::bedrock::instance().wd_manager();
std::vector<native_window_type> owned_children;
auto i = wincontext_.find(wd); auto i = wincontext_.find(wd);
if(i != wincontext_.end()) if(i != wincontext_.end())
{ {
if(i->second.owned) if(i->second.owned)
{ {
set_error_handler(); for(auto child : *i->second.owned)
auto & wd_manager = detail::bedrock::instance().wd_manager(); owned_children.push_back(child);
for(auto u = i->second.owned->rbegin(); u != i->second.owned->rend(); ++u) }
wd_manager.close(wd_manager.root(*u));
rev_error_handler();
delete i->second.owned;
} }
//Closing a child will erase the wd from the table wincontext_, so the
//iterator i can't be reused after children closed.
set_error_handler();
for(auto u = owned_children.rbegin(); u != owned_children.rend(); ++u)
wd_manager.close(wd_manager.root(*u));
rev_error_handler();
i = wincontext_.find(wd);
if(i != wincontext_.end())
{
delete i->second.owned;
wincontext_.erase(i); wincontext_.erase(i);
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* An Animation Implementation * An Animation Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2018 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
@ -571,6 +571,25 @@ namespace nana
delete impl_; delete impl_;
} }
animation::animation(animation&& rhs)
: impl_(rhs.impl_)
{
rhs.impl_ = new impl(23);
}
animation& animation::operator=(animation&& rhs)
{
if (this != &rhs)
{
auto imp = new impl{ 23 };
delete impl_;
impl_ = rhs.impl_;
rhs.impl_ = imp;
}
return *this;
}
void animation::push_back(frameset frms) void animation::push_back(frameset frms)
{ {
impl_->framesets.emplace_back(std::move(frms)); impl_->framesets.emplace_back(std::move(frms));

View File

@ -973,7 +973,12 @@ namespace detail
case Expose: case Expose:
if(msgwnd->visible && (msgwnd->root_graph->empty() == false)) if(msgwnd->visible && (msgwnd->root_graph->empty() == false))
{ {
nana::detail::platform_scope_guard lock; nana::internal_scope_guard lock;
//Don't lock this scope using platform-scope-guard. Because it would cause the platform-scope-lock to be locked
//before the internal-scope-guard, and the order of locking would cause dead-lock.
//
//Locks this scope using internal-scope-guard is correct and safe. In the scope, the Xlib functions aren't called
//directly.
if(msgwnd->is_draw_through()) if(msgwnd->is_draw_through())
{ {
msgwnd->other.attribute.root->draw_through(); msgwnd->other.attribute.root->draw_through();

View File

@ -371,6 +371,8 @@ namespace nana{
} }
Window parent = (owner ? reinterpret_cast<Window>(owner) : restrict::spec.root_window()); Window parent = (owner ? reinterpret_cast<Window>(owner) : restrict::spec.root_window());
//The position passed to XCreateWindow is a screen coordinate.
nana::point pos(r.x, r.y); nana::point pos(r.x, r.y);
if((false == nested) && owner) if((false == nested) && owner)
{ {
@ -396,7 +398,9 @@ namespace nana{
{ {
auto origin_owner = (owner ? owner : reinterpret_cast<native_window_type>(restrict::spec.root_window())); auto origin_owner = (owner ? owner : reinterpret_cast<native_window_type>(restrict::spec.root_window()));
restrict::spec.make_owner(origin_owner, reinterpret_cast<native_window_type>(handle)); restrict::spec.make_owner(origin_owner, reinterpret_cast<native_window_type>(handle));
exposed_positions[handle] = pos;
//The exposed_position is a relative position to its owner/parent.
exposed_positions[handle] = r.position();
} }
XChangeWindowAttributes(disp, handle, attr_mask, &win_attr); XChangeWindowAttributes(disp, handle, attr_mask, &win_attr);
@ -945,13 +949,14 @@ namespace nana{
auto fm_extents = window_frame_extents(wd); auto fm_extents = window_frame_extents(wd);
origin.x = -fm_extents.left; origin.x = -fm_extents.left;
origin.y = -fm_extents.top; origin.y = -fm_extents.top;
#if 0 //deprecated
if(reinterpret_cast<Window>(coord_wd) != restrict::spec.root_window()) if(reinterpret_cast<Window>(coord_wd) != restrict::spec.root_window())
{ {
fm_extents = window_frame_extents(coord_wd); fm_extents = window_frame_extents(coord_wd);
origin.x += fm_extents.left; origin.x += fm_extents.left;
origin.y += fm_extents.top; origin.y += fm_extents.top;
} }
#endif
} }
else else
coord_wd = get_window(wd, window_relationship::parent); coord_wd = get_window(wd, window_relationship::parent);
@ -1010,8 +1015,14 @@ namespace nana{
if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window()))) if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window())))
{ {
auto origin = window_position(owner); auto origin = window_position(owner);
#if 0
x += origin.x; x += origin.x;
y += origin.y; y += origin.y;
#else
auto owner_extents = window_frame_extents(owner);
x += origin.x + owner_extents.left;
y += origin.y + owner_extents.top;
#endif
} }
::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y); ::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y);
@ -1099,8 +1110,14 @@ namespace nana{
if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window()))) if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window())))
{ {
auto origin = window_position(owner); auto origin = window_position(owner);
#if 0
x += origin.x; x += origin.x;
y += origin.y; y += origin.y;
#else
auto owner_extents = window_frame_extents(owner);
x += origin.x + owner_extents.left;
y += origin.y + owner_extents.top;
#endif
} }
::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height); ::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height);
@ -1580,14 +1597,21 @@ namespace nana{
pos.y = point.y; pos.y = point.y;
return true; return true;
} }
return false;
#elif defined(NANA_X11) #elif defined(NANA_X11)
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard psg;
int x = pos.x, y = pos.y; int x = pos.x, y = pos.y;
Window child; Window child;
return (True == ::XTranslateCoordinates(restrict::spec.open_display(), if(True == ::XTranslateCoordinates(restrict::spec.open_display(),
reinterpret_cast<Window>(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child)); reinterpret_cast<Window>(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child))
{
//deprecated
//auto fm_extents = window_frame_extents(wd);
//pos.x += fm_extents.left;
//pos.y += fm_extents.top;
return true;
}
#endif #endif
return false;
} }
bool native_interface::calc_window_point(native_window_type wd, nana::point& pos) bool native_interface::calc_window_point(native_window_type wd, nana::point& pos)
@ -1600,14 +1624,21 @@ namespace nana{
pos.y = point.y; pos.y = point.y;
return true; return true;
} }
return false;
#elif defined(NANA_X11) #elif defined(NANA_X11)
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard psg;
int x = pos.x, y = pos.y; int x = pos.x, y = pos.y;
Window child; Window child;
return (True == ::XTranslateCoordinates(restrict::spec.open_display(), if(True == ::XTranslateCoordinates(restrict::spec.open_display(), restrict::spec.root_window(), reinterpret_cast<Window>(wd), x, y, &pos.x, &pos.y, &child))
restrict::spec.root_window(), reinterpret_cast<Window>(wd), x, y, &pos.x, &pos.y, &child)); {
//deprecated
//Now the origin of pos is the left-top corner of the window(including titlebar and border)
//auto fm_extents = window_frame_extents(wd);
//pos.x += fm_extents.left;
//pos.y += fm_extents.top;
return true;
}
#endif #endif
return false;
} }
native_window_type native_interface::find_window(int x, int y) native_window_type native_interface::find_window(int x, int y)

View File

@ -303,7 +303,7 @@ namespace nana
extent_size.width = width_px; extent_size.width = width_px;
for (auto & vsline : rs.vslines) for (auto & vsline : rs.vslines)
extent_size.height += vsline.extent_height_px; extent_size.height += static_cast<size::value_type>(vsline.extent_height_px);
content_lines.emplace_back(std::move(rs.vslines)); content_lines.emplace_back(std::move(rs.vslines));
@ -311,7 +311,8 @@ namespace nana
break; break;
} }
if (allowed_width_px < extent_size.width) //The width is not restricted if the allowed_width_px is zero.
if (allowed_width_px && (allowed_width_px < extent_size.width))
extent_size.width = allowed_width_px; extent_size.width = allowed_width_px;
if (transient_.current_font != pre_font) if (transient_.current_font != pre_font)
@ -445,6 +446,10 @@ namespace nana
unsigned sub_text_px = 0; unsigned sub_text_px = 0;
auto sub_text_len = _m_fit_text(graph, data->text().substr(text_begin), rs.allowed_width, sub_text_px); auto sub_text_len = _m_fit_text(graph, data->text().substr(text_begin), rs.allowed_width, sub_text_px);
//At least one character must be displayed no matter whether the width is enough or not.
if (0 == sub_text_len)
sub_text_len = 1;
if (text_begin + sub_text_len < data->text().size()) if (text_begin + sub_text_len < data->text().size())
{ {
//make a new visual line //make a new visual line
@ -886,7 +891,8 @@ namespace nana
if(graph_ptr->empty()) if(graph_ptr->empty())
{ {
graph_ptr = &substitute; graph_ptr = &substitute;
graph_ptr->make({ 10, 10 }); substitute.make({ 10, 10 });
substitute.typeface(this->typeface());
} }
return impl->renderer.measure(*graph_ptr, limited, impl->text_align, impl->text_align_v); return impl->renderer.measure(*graph_ptr, limited, impl->text_align, impl->text_align_v);

View File

@ -1,7 +1,7 @@
/* /*
* A Menubar implementation * A Menubar implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2017 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2009-2018 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
@ -215,6 +215,26 @@ namespace nana
}; };
//class item_renderer //class item_renderer
class item_renderer
{
public:
enum class state
{
normal, highlighted, selected
};
using graph_reference = paint::graphics&;
using scheme = ::nana::drawerbase::menubar::scheme;
item_renderer(window, graph_reference);
virtual void background(const point&, const ::nana::size&, state);
virtual void caption(const point&, const native_string_type&);
scheme *scheme_ptr() const { return scheme_ptr_; };
private:
graph_reference graph_;
scheme *scheme_ptr_;
};
item_renderer::item_renderer(window wd, graph_reference graph) item_renderer::item_renderer(window wd, graph_reference graph)
:graph_(graph), scheme_ptr_(static_cast<scheme*>(API::dev::get_scheme(wd))) :graph_(graph), scheme_ptr_(static_cast<scheme*>(API::dev::get_scheme(wd)))
{} {}
@ -250,7 +270,6 @@ namespace nana
void item_renderer::caption(const point& pos, const native_string_type& text) void item_renderer::caption(const point& pos, const native_string_type& text)
{ {
graph_.string(pos, text, scheme_ptr_->text_fgcolor); graph_.string(pos, text, scheme_ptr_->text_fgcolor);
} }
//end class item_renderer //end class item_renderer

View File

@ -180,13 +180,13 @@ namespace nana
} }
};//end class tooltip_window };//end class tooltip_window
//item_locator should be defined before the definition of basic_implement //item_locator should be defined before the definition of implementation
class trigger::item_locator class trigger::item_locator
{ {
public: public:
using node_type = tree_cont_type::node_type; using node_type = tree_cont_type::node_type;
item_locator(implement * 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); int operator()(node_type &node, int affect);
node_type * node() const; node_type * node() const;
component what() const; component what() const;
@ -194,7 +194,7 @@ namespace nana
nana::rectangle text_pos() const; nana::rectangle text_pos() const;
private: private:
trigger::implement * impl_; implementation * const impl_;
nana::point item_pos_; nana::point item_pos_;
const nana::point pos_; //Mouse pointer position const nana::point pos_; //Mouse pointer position
component what_; component what_;
@ -212,11 +212,89 @@ namespace nana
} }
}; };
//struct implement //struct implementation
//@brief: some data for treebox trigger //@brief: some data for treebox trigger
template<typename Renderer> class trigger::implementation
struct trigger::basic_implement
{ {
class item_rendering_director
: public compset_interface
{
public:
using node_type = tree_cont_type::node_type;
item_rendering_director(implementation * impl, const nana::point& pos):
impl_(impl),
pos_(pos)
{
}
//affect
//0 = Sibling, the last is a sibling 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.
int operator()(const node_type& node, int affect)
{
iterated_node_ = &node;
switch (affect)
{
case 1:
pos_.x += impl_->shape.indent_pixels;
break;
default:
if (affect >= 2)
pos_.x -= impl_->shape.indent_pixels * (affect - 1);
}
auto & comp_placer = impl_->data.comp_placer;
impl_->assign_node_attr(node_attr_, iterated_node_);
node_r_.x = node_r_.y = 0;
node_r_.width = comp_placer->item_width(*impl_->data.graph, node_attr_);
node_r_.height = comp_placer->item_height(*impl_->data.graph);
auto renderer = impl_->data.renderer;
renderer->begin_paint(*impl_->data.widget_ptr);
renderer->bground(*impl_->data.graph, this);
renderer->expander(*impl_->data.graph, this);
renderer->crook(*impl_->data.graph, this);
renderer->icon(*impl_->data.graph, this);
renderer->text(*impl_->data.graph, this);
pos_.y += node_r_.height;
if (pos_.y > static_cast<int>(impl_->data.graph->height()))
return 0;
return (node.child && node.value.second.expanded ? 1 : 2);
}
private:
//Overrides compset_interface
virtual const item_attribute_t& item_attribute() const override
{
return node_attr_;
}
virtual bool comp_attribute(component_t comp, comp_attribute_t& attr) const override
{
attr.area = node_r_;
if (impl_->data.comp_placer->locate(comp, node_attr_, &attr.area))
{
attr.mouse_pointed = node_attr_.mouse_pointed;
attr.area.x += pos_.x;
attr.area.y += pos_.y;
return true;
}
return false;
}
private:
implementation * const impl_;
::nana::point pos_;
const node_type * iterated_node_;
item_attribute_t node_attr_;
::nana::rectangle node_r_;
};
public:
using node_type = trigger::node_type; using node_type = trigger::node_type;
struct rep_tag struct rep_tag
@ -271,7 +349,7 @@ namespace nana
nana::timer timer; nana::timer timer;
}adjust; }adjust;
public: public:
basic_implement() implementation()
{ {
data.graph = nullptr; data.graph = nullptr;
data.widget_ptr = nullptr; data.widget_ptr = nullptr;
@ -353,6 +431,11 @@ namespace nana
return true; return true;
} }
static constexpr unsigned margin_top_bottom()
{
return 1;
}
bool draw(bool reset_scroll, bool ignore_update = false, bool ignore_auto_draw = 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))
@ -368,7 +451,7 @@ namespace nana
data.graph->rectangle(true, data.widget_ptr->bgcolor()); data.graph->rectangle(true, data.widget_ptr->bgcolor());
//Draw tree //Draw tree
attr.tree_cont.for_each(shape.first, Renderer(this, nana::point(static_cast<int>(attr.tree_cont.indent_size(shape.first) * shape.indent_pixels) - shape.offset_x, 1))); attr.tree_cont.for_each(shape.first, item_rendering_director(this, nana::point(static_cast<int>(attr.tree_cont.indent_size(shape.first) * shape.indent_pixels) - shape.offset_x, margin_top_bottom())));
if (!ignore_update) if (!ignore_update)
API::update_window(data.widget_ptr->handle()); API::update_window(data.widget_ptr->handle());
@ -460,6 +543,129 @@ namespace nana
return nullptr; return nullptr;
} }
node_type* last(bool ignore_folded_children) const
{
auto p = attr.tree_cont.get_root();
while (true)
{
while (p->next)
p = p->next;
if (p->child)
{
if (p->value.second.expanded || !ignore_folded_children)
{
p = p->child;
continue;
}
}
break;
}
return p;
}
std::size_t screen_capacity(bool completed) const
{
auto const item_px = data.comp_placer->item_height(*data.graph);
auto screen_px = data.graph->size().height - (margin_top_bottom() << 1);
if (completed || ((screen_px % item_px) == 0))
return screen_px / item_px;
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 -= capacity / 2;
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{});
//Update the position of scroll
show_scroll();
return has_expanded || (prv_first != shape.first);
}
bool make_adjust(node_type * node, int reason) bool make_adjust(node_type * node, int reason)
{ {
if(!node) return false; if(!node) return false;
@ -1356,7 +1562,7 @@ namespace nana
//class trigger::item_locator //class trigger::item_locator
trigger::item_locator::item_locator(implement * impl, int item_pos, int x, int y) trigger::item_locator::item_locator(implementation * impl, int item_pos, int x, int y)
: impl_(impl), : impl_(impl),
item_pos_(item_pos, 1), item_pos_(item_pos, 1),
pos_(x, y), pos_(x, y),
@ -1439,86 +1645,6 @@ namespace nana
return{node_text_r_.x + item_pos_.x, node_text_r_.y + item_pos_.y, node_text_r_.width, node_text_r_.height}; return{node_text_r_.x + item_pos_.x, node_text_r_.y + item_pos_.y, node_text_r_.width, node_text_r_.height};
} }
//end class item_locator //end class item_locator
class trigger::item_renderer
: public compset_interface
{
public:
typedef tree_cont_type::node_type node_type;
item_renderer(implement * impl, const nana::point& pos)
: impl_(impl),
pos_(pos)
{
}
//affect
//0 = Sibling, the last is a sibling 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.
int operator()(const node_type& node, int affect)
{
implement * draw_impl = impl_;
iterated_node_ = &node;
switch(affect)
{
case 1:
pos_.x += draw_impl->shape.indent_pixels;
break;
default:
if(affect >= 2)
pos_.x -= draw_impl->shape.indent_pixels * (affect - 1);
}
auto & comp_placer = impl_->data.comp_placer;
impl_->assign_node_attr(node_attr_, iterated_node_);
node_r_.x = node_r_.y = 0;
node_r_.width = comp_placer->item_width(*impl_->data.graph, node_attr_);
node_r_.height = comp_placer->item_height(*impl_->data.graph);
auto renderer = draw_impl->data.renderer;
renderer->begin_paint(*draw_impl->data.widget_ptr);
renderer->bground(*draw_impl->data.graph, this);
renderer->expander(*draw_impl->data.graph, this);
renderer->crook(*draw_impl->data.graph, this);
renderer->icon(*draw_impl->data.graph, this);
renderer->text(*draw_impl->data.graph, this);
pos_.y += node_r_.height;
if(pos_.y > static_cast<int>(draw_impl->data.graph->height()))
return 0;
return (node.child && node.value.second.expanded ? 1 : 2);
}
private:
//Overrides compset_interface
virtual const item_attribute_t& item_attribute() const override
{
return node_attr_;
}
virtual bool comp_attribute(component_t comp, comp_attribute_t& attr) const override
{
attr.area = node_r_;
if (impl_->data.comp_placer->locate(comp, node_attr_, &attr.area))
{
attr.mouse_pointed = node_attr_.mouse_pointed;
attr.area.x += pos_.x;
attr.area.y += pos_.y;
return true;
}
return false;
}
private:
trigger::implement * impl_;
::nana::point pos_;
const node_type * iterated_node_;
item_attribute_t node_attr_;
::nana::rectangle node_r_;
};
} }
//Treebox Implementation //Treebox Implementation
@ -1548,7 +1674,7 @@ namespace nana
//end struct treebox_node_type //end struct treebox_node_type
trigger::trigger() trigger::trigger()
: impl_(new implement) : impl_(new implementation)
{ {
impl_->data.trigger_ptr = this; impl_->data.trigger_ptr = this;
impl_->data.renderer = nana::pat::cloneable<renderer_interface>(internal_renderer()); impl_->data.renderer = nana::pat::cloneable<renderer_interface>(internal_renderer());
@ -1615,7 +1741,7 @@ namespace nana
delete impl_; delete impl_;
} }
trigger::implement * trigger::impl() const trigger::implementation * trigger::impl() const
{ {
return impl_; return impl_;
} }
@ -1687,6 +1813,7 @@ namespace nana
} }
} }
/* //deprecated
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);
@ -1696,6 +1823,12 @@ namespace nana
{ {
return impl_->data.renderer; return impl_->data.renderer;
} }
*/
::nana::pat::cloneable<renderer_interface>& trigger::renderer() const
{
return impl_->data.renderer;
}
void trigger::placer(::nana::pat::cloneable<compset_placer_interface>&& r) void trigger::placer(::nana::pat::cloneable<compset_placer_interface>&& r)
{ {
@ -1729,18 +1862,22 @@ namespace nana
return x; return x;
} }
trigger::node_type* trigger::selected() const /*
trigger::node_type* trigger::selected() const //deprecated
{ {
return impl_->node_state.selected; return impl_->node_state.selected;
} }
*/
void trigger::selected(node_type* node) /*
void trigger::selected(node_type* node) //deprecated
{ {
if(impl_->attr.tree_cont.verify(node) && impl_->set_selected(node)) if(impl_->attr.tree_cont.verify(node) && impl_->set_selected(node))
impl_->draw(true); impl_->draw(true);
} }
*/
node_image_tag& trigger::icon(const std::string& id) const node_image_tag& trigger::icon(const std::string& id)
{ {
auto i = impl_->shape.image_table.find(id); auto i = impl_->shape.image_table.find(id);
if(i != impl_->shape.image_table.end()) if(i != impl_->shape.image_table.end())
@ -2167,7 +2304,7 @@ namespace nana
impl->draw(true); impl->draw(true);
} }
treebox::node_image_type& treebox::icon(const std::string& id) const treebox::node_image_type& treebox::icon(const std::string& id)
{ {
return get_drawer_trigger().icon(id); return get_drawer_trigger().icon(id);
} }
@ -2233,7 +2370,24 @@ namespace nana
treebox::item_proxy treebox::selected() const treebox::item_proxy treebox::selected() const
{ {
return item_proxy(const_cast<drawer_trigger_t*>(&get_drawer_trigger()), get_drawer_trigger().selected()); //return item_proxy(const_cast<drawer_trigger_t*>(&get_drawer_trigger()), get_drawer_trigger().selected()); //deprecated
auto dw = &get_drawer_trigger();
return item_proxy(const_cast<drawer_trigger_t*>(dw), dw->impl()->node_state.selected);
}
void treebox::scroll_into_view(item_proxy item, align_v bearing)
{
internal_scope_guard lock;
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() std::shared_ptr<scroll_operation_interface> treebox::_m_scroll_operation()