Merge remote-tracking branch 'cnjinhao/develop-1.7' into cmake-dev
This commit is contained in:
commit
65d2440e26
@ -211,10 +211,10 @@
|
||||
|
||||
|
||||
#undef _nana_std_optional
|
||||
#if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703))) || \
|
||||
((__cplusplus < 201703L) || \
|
||||
#if ((defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703))) || \
|
||||
((!defined(_MSC_VER)) && ((__cplusplus < 201703L) || \
|
||||
(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
|
||||
#endif
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An Animation Implementation
|
||||
* 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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -49,24 +49,18 @@ namespace nana
|
||||
|
||||
struct impl;
|
||||
class performance_manager;
|
||||
|
||||
/// Non-copyable
|
||||
animation(const animation&) = delete;
|
||||
animation& operator=(const animation&) = delete;
|
||||
public:
|
||||
animation(std::size_t fps = 23);
|
||||
~animation();
|
||||
|
||||
void push_back(frameset frms);
|
||||
/*
|
||||
void branch(const std::string& name, const frameset& frms)
|
||||
{
|
||||
impl_->branches[name].frames = frms;
|
||||
}
|
||||
animation(animation&&);
|
||||
animation& operator=(animation&&);
|
||||
|
||||
void branch(const std::string& name, const frameset& frms, std::function<std::size_t(const std::string&, std::size_t, std::size_t&)> condition)
|
||||
{
|
||||
auto & br = impl_->branches[name];
|
||||
br.frames = frms;
|
||||
br.condition = condition;
|
||||
}
|
||||
*/
|
||||
void push_back(frameset frms);
|
||||
|
||||
void looped(bool enable); ///< Enables or disables the animation repeating playback.
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Menubar implementation
|
||||
* 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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -34,26 +34,6 @@ namespace nana
|
||||
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
|
||||
: public drawer_trigger
|
||||
{
|
||||
|
||||
@ -87,13 +87,15 @@ namespace nana
|
||||
class trigger
|
||||
:public drawer_trigger
|
||||
{
|
||||
template<typename Renderer>
|
||||
struct basic_implement;
|
||||
//template<typename Renderer>
|
||||
//struct basic_implement; //deprecated
|
||||
|
||||
class item_renderer;
|
||||
class implementation;
|
||||
|
||||
//class item_renderer; //deprecated
|
||||
class item_locator;
|
||||
|
||||
typedef basic_implement<item_renderer> implement;
|
||||
//typedef basic_implement<item_renderer> implement; //deprecated
|
||||
public:
|
||||
struct treebox_node_type
|
||||
{
|
||||
@ -116,27 +118,30 @@ namespace nana
|
||||
trigger();
|
||||
~trigger();
|
||||
|
||||
implement * impl() const;
|
||||
implementation * impl() const;
|
||||
|
||||
void check(node_type*, checkstate);
|
||||
|
||||
void renderer(::nana::pat::cloneable<renderer_interface>&&);
|
||||
const ::nana::pat::cloneable<renderer_interface>& renderer() const;
|
||||
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>&&);
|
||||
const ::nana::pat::cloneable<compset_placer_interface>& placer() const;
|
||||
|
||||
node_type* insert(node_type*, const std::string& key, std::string&&);
|
||||
node_type* insert(const std::string& path, std::string&&);
|
||||
|
||||
node_type * selected() const;
|
||||
void selected(node_type*);
|
||||
//node_type * selected() const; //deprecated
|
||||
//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 node_icon(node_type*, const ::std::string& id);
|
||||
unsigned node_width(const node_type*) const;
|
||||
|
||||
bool rename(node_type*, const char* key, const char* name);
|
||||
|
||||
private:
|
||||
//Overrides drawer_trigger methods
|
||||
void attached(widget_reference, graph_reference) override;
|
||||
@ -152,7 +157,7 @@ namespace nana
|
||||
void key_press(graph_reference, const arg_keyboard&) override;
|
||||
void key_char(graph_reference, const arg_keyboard&) override;
|
||||
private:
|
||||
implement * const impl_;
|
||||
implementation * const impl_;
|
||||
}; //end class trigger
|
||||
|
||||
|
||||
@ -171,11 +176,11 @@ namespace nana
|
||||
|
||||
/// Append a child with a specified value (user object.).
|
||||
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));
|
||||
if(false == ip.empty())
|
||||
ip.value(t);
|
||||
ip.value(std::forward<T>(t));
|
||||
return ip;
|
||||
}
|
||||
|
||||
@ -291,17 +296,19 @@ namespace nana
|
||||
return *p;
|
||||
}
|
||||
|
||||
/*
|
||||
template<typename T>
|
||||
item_proxy & value(const T& t)
|
||||
item_proxy & value(const T& t) //deprecated
|
||||
{
|
||||
_m_value() = t;
|
||||
return *this;
|
||||
}
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
item_proxy & value(T&& t)
|
||||
{
|
||||
_m_value() = std::move(t);
|
||||
_m_value() = std::forward<T>(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -378,7 +385,7 @@ namespace nana
|
||||
template<typename ItemRenderer>
|
||||
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;
|
||||
}
|
||||
|
||||
@ -403,6 +410,23 @@ namespace nana
|
||||
/// @param enable bool whether to 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.
|
||||
/// @param enable bool indicates whether to show or hide the checkboxs.
|
||||
treebox & checkable(bool enable);
|
||||
@ -419,8 +443,9 @@ namespace nana
|
||||
/// These states are 'normal', 'hovered' and 'expanded'.
|
||||
/// 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)
|
||||
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.
|
||||
) const;
|
||||
/// @param id The name of an icon scheme. If the name is not existing, it creates a new scheme for the name.
|
||||
/// @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);
|
||||
|
||||
@ -445,6 +470,19 @@ namespace nana
|
||||
|
||||
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:
|
||||
std::shared_ptr<scroll_operation_interface> _m_scroll_operation() override;
|
||||
|
||||
|
||||
@ -658,21 +658,31 @@ namespace detail
|
||||
platform_scope_guard lock;
|
||||
if(umake_owner(wd))
|
||||
{
|
||||
auto & wd_manager = detail::bedrock::instance().wd_manager();
|
||||
|
||||
std::vector<native_window_type> owned_children;
|
||||
|
||||
auto i = wincontext_.find(wd);
|
||||
if(i != wincontext_.end())
|
||||
{
|
||||
if(i->second.owned)
|
||||
{
|
||||
set_error_handler();
|
||||
auto & wd_manager = detail::bedrock::instance().wd_manager();
|
||||
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;
|
||||
for(auto child : *i->second.owned)
|
||||
owned_children.push_back(child);
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An Animation Implementation
|
||||
* 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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -571,6 +571,25 @@ namespace nana
|
||||
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)
|
||||
{
|
||||
impl_->framesets.emplace_back(std::move(frms));
|
||||
|
||||
@ -973,7 +973,12 @@ namespace detail
|
||||
case Expose:
|
||||
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())
|
||||
{
|
||||
msgwnd->other.attribute.root->draw_through();
|
||||
|
||||
@ -371,6 +371,8 @@ namespace nana{
|
||||
}
|
||||
|
||||
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);
|
||||
if((false == nested) && owner)
|
||||
{
|
||||
@ -396,7 +398,9 @@ namespace nana{
|
||||
{
|
||||
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));
|
||||
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);
|
||||
@ -945,13 +949,14 @@ namespace nana{
|
||||
auto fm_extents = window_frame_extents(wd);
|
||||
origin.x = -fm_extents.left;
|
||||
origin.y = -fm_extents.top;
|
||||
|
||||
#if 0 //deprecated
|
||||
if(reinterpret_cast<Window>(coord_wd) != restrict::spec.root_window())
|
||||
{
|
||||
fm_extents = window_frame_extents(coord_wd);
|
||||
origin.x += fm_extents.left;
|
||||
origin.y += fm_extents.top;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
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())))
|
||||
{
|
||||
auto origin = window_position(owner);
|
||||
#if 0
|
||||
x += origin.x;
|
||||
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);
|
||||
@ -1099,8 +1110,14 @@ namespace nana{
|
||||
if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window())))
|
||||
{
|
||||
auto origin = window_position(owner);
|
||||
#if 0
|
||||
x += origin.x;
|
||||
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);
|
||||
@ -1580,14 +1597,21 @@ namespace nana{
|
||||
pos.y = point.y;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#elif defined(NANA_X11)
|
||||
nana::detail::platform_scope_guard psg;
|
||||
int x = pos.x, y = pos.y;
|
||||
Window child;
|
||||
return (True == ::XTranslateCoordinates(restrict::spec.open_display(),
|
||||
reinterpret_cast<Window>(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child));
|
||||
if(True == ::XTranslateCoordinates(restrict::spec.open_display(),
|
||||
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
|
||||
return false;
|
||||
}
|
||||
|
||||
bool native_interface::calc_window_point(native_window_type wd, nana::point& pos)
|
||||
@ -1600,14 +1624,21 @@ namespace nana{
|
||||
pos.y = point.y;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#elif defined(NANA_X11)
|
||||
nana::detail::platform_scope_guard psg;
|
||||
int x = pos.x, y = pos.y;
|
||||
Window child;
|
||||
return (True == ::XTranslateCoordinates(restrict::spec.open_display(),
|
||||
restrict::spec.root_window(), reinterpret_cast<Window>(wd), x, y, &pos.x, &pos.y, &child));
|
||||
if(True == ::XTranslateCoordinates(restrict::spec.open_display(), 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
|
||||
return false;
|
||||
}
|
||||
|
||||
native_window_type native_interface::find_window(int x, int y)
|
||||
|
||||
@ -303,7 +303,7 @@ namespace nana
|
||||
extent_size.width = width_px;
|
||||
|
||||
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));
|
||||
|
||||
@ -311,7 +311,8 @@ namespace nana
|
||||
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;
|
||||
|
||||
if (transient_.current_font != pre_font)
|
||||
@ -445,6 +446,10 @@ namespace nana
|
||||
unsigned sub_text_px = 0;
|
||||
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())
|
||||
{
|
||||
//make a new visual line
|
||||
@ -886,7 +891,8 @@ namespace nana
|
||||
if(graph_ptr->empty())
|
||||
{
|
||||
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);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Menubar implementation
|
||||
* 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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -215,12 +215,32 @@ namespace nana
|
||||
};
|
||||
|
||||
//class item_renderer
|
||||
item_renderer::item_renderer(window wd, graph_reference graph)
|
||||
:graph_(graph), scheme_ptr_(static_cast<scheme*>(API::dev::get_scheme(wd)))
|
||||
{}
|
||||
|
||||
void item_renderer::background(const nana::point& pos, const nana::size& size, state item_state)
|
||||
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)
|
||||
:graph_(graph), scheme_ptr_(static_cast<scheme*>(API::dev::get_scheme(wd)))
|
||||
{}
|
||||
|
||||
void item_renderer::background(const nana::point& pos, const nana::size& size, state item_state)
|
||||
{
|
||||
auto bground = scheme_ptr_->text_fgcolor;
|
||||
::nana::color border, body;
|
||||
|
||||
@ -245,13 +265,12 @@ namespace nana
|
||||
|
||||
paint::draw{ graph_ }.corner(r, 1);
|
||||
graph_.rectangle(r.pare_off(1), true, body);
|
||||
}
|
||||
}
|
||||
|
||||
void item_renderer::caption(const point& pos, const native_string_type& text)
|
||||
{
|
||||
graph_.string(pos, text, scheme_ptr_->text_fgcolor);
|
||||
|
||||
}
|
||||
void item_renderer::caption(const point& pos, const native_string_type& text)
|
||||
{
|
||||
graph_.string(pos, text, scheme_ptr_->text_fgcolor);
|
||||
}
|
||||
//end class item_renderer
|
||||
|
||||
//class trigger
|
||||
|
||||
@ -180,13 +180,13 @@ namespace nana
|
||||
}
|
||||
};//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
|
||||
{
|
||||
public:
|
||||
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);
|
||||
node_type * node() const;
|
||||
component what() const;
|
||||
@ -194,7 +194,7 @@ namespace nana
|
||||
|
||||
nana::rectangle text_pos() const;
|
||||
private:
|
||||
trigger::implement * impl_;
|
||||
implementation * const impl_;
|
||||
nana::point item_pos_;
|
||||
const nana::point pos_; //Mouse pointer position
|
||||
component what_;
|
||||
@ -212,11 +212,89 @@ namespace nana
|
||||
}
|
||||
};
|
||||
|
||||
//struct implement
|
||||
//struct implementation
|
||||
//@brief: some data for treebox trigger
|
||||
template<typename Renderer>
|
||||
struct trigger::basic_implement
|
||||
class trigger::implementation
|
||||
{
|
||||
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;
|
||||
|
||||
struct rep_tag
|
||||
@ -271,7 +349,7 @@ namespace nana
|
||||
nana::timer timer;
|
||||
}adjust;
|
||||
public:
|
||||
basic_implement()
|
||||
implementation()
|
||||
{
|
||||
data.graph = nullptr;
|
||||
data.widget_ptr = nullptr;
|
||||
@ -353,6 +431,11 @@ namespace nana
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr unsigned margin_top_bottom()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool draw(bool reset_scroll, bool ignore_update = false, bool ignore_auto_draw = false)
|
||||
{
|
||||
if(data.graph && (false == data.stop_drawing))
|
||||
@ -368,7 +451,7 @@ namespace nana
|
||||
data.graph->rectangle(true, data.widget_ptr->bgcolor());
|
||||
|
||||
//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)
|
||||
API::update_window(data.widget_ptr->handle());
|
||||
@ -460,6 +543,129 @@ namespace nana
|
||||
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)
|
||||
{
|
||||
if(!node) return false;
|
||||
@ -1356,7 +1562,7 @@ namespace nana
|
||||
|
||||
|
||||
//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),
|
||||
item_pos_(item_pos, 1),
|
||||
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};
|
||||
}
|
||||
//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
|
||||
@ -1548,7 +1674,7 @@ namespace nana
|
||||
//end struct treebox_node_type
|
||||
|
||||
trigger::trigger()
|
||||
: impl_(new implement)
|
||||
: impl_(new implementation)
|
||||
{
|
||||
impl_->data.trigger_ptr = this;
|
||||
impl_->data.renderer = nana::pat::cloneable<renderer_interface>(internal_renderer());
|
||||
@ -1615,7 +1741,7 @@ namespace nana
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
trigger::implement * trigger::impl() const
|
||||
trigger::implementation * trigger::impl() const
|
||||
{
|
||||
return impl_;
|
||||
}
|
||||
@ -1687,6 +1813,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
/* //deprecated
|
||||
void trigger::renderer(::nana::pat::cloneable<renderer_interface>&& r)
|
||||
{
|
||||
impl_->data.renderer = std::move(r);
|
||||
@ -1696,6 +1823,12 @@ namespace nana
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -1729,18 +1862,22 @@ namespace nana
|
||||
return x;
|
||||
}
|
||||
|
||||
trigger::node_type* trigger::selected() const
|
||||
/*
|
||||
trigger::node_type* trigger::selected() const //deprecated
|
||||
{
|
||||
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))
|
||||
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);
|
||||
if(i != impl_->shape.image_table.end())
|
||||
@ -2167,7 +2304,7 @@ namespace nana
|
||||
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);
|
||||
}
|
||||
@ -2233,7 +2370,24 @@ namespace nana
|
||||
|
||||
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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user