Merge branch 'hotfix-1.4.1' into develop

This commit is contained in:
Jinhao 2017-03-16 02:07:37 +08:00
commit 33424f0c75
24 changed files with 451 additions and 368 deletions

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_layout_file>
<FileVersion major="1" minor="0" />
<ActiveTarget name="Debug" />
</CodeBlocks_layout_file>

View File

@ -222,9 +222,6 @@ namespace detail
basic_window* focus{nullptr}; basic_window* focus{nullptr};
basic_window* menubar{nullptr}; basic_window* menubar{nullptr};
bool ime_enabled{false}; bool ime_enabled{false};
#if defined(NANA_WINDOWS)
cursor running_cursor{ nana::cursor::arrow };
#endif
cursor state_cursor{nana::cursor::arrow}; cursor state_cursor{nana::cursor::arrow};
basic_window* state_cursor_window{ nullptr }; basic_window* state_cursor_window{ nullptr };

View File

@ -292,7 +292,7 @@ namespace API
* @param window_handle A handle to the window to be refreshed. * @param window_handle A handle to the window to be refreshed.
*/ */
void refresh_window(window window_handle); void refresh_window(window window_handle);
void refresh_window_tree(window); ///< Refreshs the specified window and all its children windows, then display it immediately void refresh_window_tree(window); ///< Refreshes the specified window and all its children windows, then display it immediately
void update_window(window); ///< Copies the off-screen buffer to the screen for immediate display. void update_window(window); ///< Copies the off-screen buffer to the screen for immediate display.
void window_caption(window, const std::string& title_utf8); void window_caption(window, const std::string& title_utf8);

View File

@ -1,7 +1,7 @@
/** /**
* A Categorize Implementation * A Categorize Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2017 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

View File

@ -1,6 +1,6 @@
/* /*
* A Tree Container class implementation * A Tree Container class implementation
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2017 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
@ -58,6 +58,31 @@ namespace detail
t = t_next; t = t_next;
} }
} }
bool is_ancestor_of(const tree_node* child) const
{
while (child)
{
if (child->owner == this)
return true;
child = child->owner;
}
return false;
}
tree_node * front() const
{
if (this->owner && (this != this->owner->child))
{
auto i = this->owner->child;
while (i->next != this)
i = i->next;
return i;
}
return nullptr;
}
}; };
template<typename UserData> template<typename UserData>
@ -76,12 +101,17 @@ namespace detail
~tree_cont() ~tree_cont()
{ {
clear(); clear(&root_);
} }
void clear() void clear(node_type* node)
{ {
remove(root_.child); while (node->child)
{
//If there is a sibling of child, the root_.child
//will be assigned with the sibling.
remove(node->child);
}
} }
bool verify(const node_type* node) const bool verify(const node_type* node) const

View File

@ -122,7 +122,9 @@ namespace nana
void value(size_type s) void value(size_type s)
{ {
if (s + metrics_.range > metrics_.peak) if (metrics_.range > metrics_.peak)
s = 0;
else if (s + metrics_.range > metrics_.peak)
s = metrics_.peak - metrics_.range; s = metrics_.peak - metrics_.range;
if (graph_ && (metrics_.value != s)) if (graph_ && (metrics_.value != s))

View File

@ -1,7 +1,7 @@
/** /**
* A Spin box widget * A Spin box widget
* 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-2017 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

View File

@ -37,7 +37,7 @@ namespace nana
{ {
enum class component enum class component
{ {
begin, expender = begin, crook, icon, text, bground, end begin, expander = begin, crook, icon, text, bground, end
}; };
struct node_image_tag struct node_image_tag
@ -119,27 +119,17 @@ namespace nana
implement * impl() const; implement * impl() const;
void check(node_type*, checkstate); void check(node_type*, checkstate);
bool draw();
const tree_cont_type & tree() const;
tree_cont_type & tree();
void renderer(::nana::pat::cloneable<renderer_interface>&&); void renderer(::nana::pat::cloneable<renderer_interface>&&);
const ::nana::pat::cloneable<renderer_interface>& renderer() const; const ::nana::pat::cloneable<renderer_interface>& renderer() const;
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;
nana::any & value(node_type*) 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&&);
bool verify_kinship(node_type* parent, node_type* child) const;
void remove(node_type*);
node_type * selected() const; node_type * selected() const;
void selected(node_type*); void selected(node_type*);
void set_expand(node_type*, bool);
void set_expand(const ::std::string& path, bool);
node_image_tag& icon(const ::std::string&) const; node_image_tag& icon(const ::std::string&) const;
void icon_erase(const ::std::string&); void icon_erase(const ::std::string&);
@ -201,6 +191,9 @@ namespace nana
/// Set the check state, and it returns itself. /// Set the check state, and it returns itself.
item_proxy& check(bool); item_proxy& check(bool);
/// Clears the child nodes
item_proxy& clear();
/// Return true when the node is expanded \todo change to expanded ?? /// Return true when the node is expanded \todo change to expanded ??
bool expanded() const; bool expanded() const;

View File

@ -38,6 +38,8 @@ namespace system{
void get(std::string& text_utf8); void get(std::string& text_utf8);
void get(std::wstring& text); void get(std::wstring& text);
std::wstring wget();
private: private:
bool _m_set(format, const void* buf, std::size_t size, native_window_type); bool _m_set(format, const void* buf, std::size_t size, native_window_type);
void* _m_get(format, size_t& size); void* _m_get(format, size_t& size);

View File

@ -30,7 +30,7 @@
#define STRING2(x) #x #define STRING2(...) #__VA_ARGS__
#define STRING(x) STRING2(x) #define STRING(x) STRING2(x)
#define SHOW_VALUE(x) " " #x " = " STRING2(x) #define SHOW_VALUE(x) " " #x " = " STRING2(x)

View File

@ -1,7 +1,7 @@
/* /*
* Platform Specification Implementation * Platform Specification Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Nana Software License, Version 1.0. * Distributed under the Nana 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
@ -1163,8 +1163,16 @@ namespace detail
// 2 = msg_dispatcher should ignore the msg, because the XEvent is processed by _m_msg_filter // 2 = msg_dispatcher should ignore the msg, because the XEvent is processed by _m_msg_filter
int platform_spec::_m_msg_filter(XEvent& evt, msg_packet_tag& msg) int platform_spec::_m_msg_filter(XEvent& evt, msg_packet_tag& msg)
{ {
auto & bedrock = detail::bedrock::instance();
platform_spec & self = instance(); platform_spec & self = instance();
if(SelectionNotify == evt.type) if(KeyPress == evt.type || KeyRelease == evt.type)
{
auto menu_wd = bedrock.get_menu(reinterpret_cast<native_window_type>(evt.xkey.window), true);
if(menu_wd)
evt.xkey.window = reinterpret_cast<Window>(menu_wd);
}
else if(SelectionNotify == evt.type)
{ {
if(evt.xselection.property) if(evt.xselection.property)
{ {
@ -1197,7 +1205,6 @@ namespace detail
} }
} }
self.selection_.items.erase(self.selection_.items.begin()); self.selection_.items.erase(self.selection_.items.begin());
std::lock_guard<decltype(im->cond_mutex)> lock(im->cond_mutex); std::lock_guard<decltype(im->cond_mutex)> lock(im->cond_mutex);
@ -1373,9 +1380,8 @@ namespace detail
{ {
Window child; Window child;
::XTranslateCoordinates(self.display_, self.root_window(), evt.xclient.window, x, y, &self.xdnd_.pos.x, &self.xdnd_.pos.y, &child); ::XTranslateCoordinates(self.display_, self.root_window(), evt.xclient.window, x, y, &self.xdnd_.pos.x, &self.xdnd_.pos.y, &child);
typedef detail::bedrock bedrock;
auto wd = bedrock::instance().wd_manager().find_window(reinterpret_cast<native_window_type>(evt.xclient.window), self.xdnd_.pos.x, self.xdnd_.pos.y); auto wd = bedrock.wd_manager().find_window(reinterpret_cast<native_window_type>(evt.xclient.window), self.xdnd_.pos.x, self.xdnd_.pos.y);
if(wd && wd->flags.dropable) if(wd && wd->flags.dropable)
{ {
accepted = true; accepted = true;

View File

@ -1,6 +1,6 @@
/* /*
* Message Dispatcher Implementation * Message Dispatcher Implementation
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2017 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
@ -51,7 +51,7 @@ namespace detail
typedef std::list<msg_packet_tag> msg_queue_type; typedef std::list<msg_packet_tag> msg_queue_type;
msg_dispatcher(Display* disp) msg_dispatcher(Display* disp)
: display_(disp), is_work_(false) : display_(disp)
{ {
proc_.event_proc = 0; proc_.event_proc = 0;
proc_.timer_proc = 0; proc_.timer_proc = 0;
@ -338,7 +338,7 @@ namespace detail
private: private:
Display * display_; Display * display_;
volatile bool is_work_; volatile bool is_work_{ false };
std::unique_ptr<std::thread> thrd_; std::unique_ptr<std::thread> thrd_;
struct table_tag struct table_tag

View File

@ -611,11 +611,18 @@ namespace detail
//If a root window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. //If a root window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event.
if (msgwnd->root != native_interface::get_focus_window()) if (msgwnd->root != native_interface::get_focus_window())
{ {
//call the drawer mouse up event for restoring the surface graphics auto pos = native_interface::cursor_position();
msgwnd->set_action(mouse_action::normal); auto rootwd = native_interface::find_window(pos.x, pos.y);
native_interface::calc_window_point(rootwd, pos);
if(msgwnd != wd_manager.find_window(rootwd, pos.x, pos.y))
{
//call the drawer mouse up event for restoring the surface graphics
msgwnd->set_action(mouse_action::normal);
draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); arg.evt_code = event_code::mouse_up;
wd_manager.do_lazy_refresh(msgwnd, false); draw_invoker(&drawer::mouse_up, msgwnd, arg, &context);
wd_manager.do_lazy_refresh(msgwnd, false);
}
} }
} }
else else
@ -1147,7 +1154,7 @@ namespace detail
} }
} }
void bedrock::pump_event(window modal_window, bool /*is_modal*/) void bedrock::pump_event(window condition_wd, bool is_modal)
{ {
thread_context * context = open_thread_context(); thread_context * context = open_thread_context();
if(0 == context->window_count) if(0 == context->window_count)
@ -1162,11 +1169,11 @@ namespace detail
auto & lock = wd_manager().internal_lock(); auto & lock = wd_manager().internal_lock();
lock.revert(); lock.revert();
native_window_type owner_native = 0; native_window_type owner_native{};
core_window_t * owner = 0; core_window_t * owner = 0;
if(modal_window) if(condition_wd && is_modal)
{ {
native_window_type modal = reinterpret_cast<core_window_t*>(modal_window)->root; native_window_type modal = reinterpret_cast<core_window_t*>(condition_wd)->root;
owner_native = native_interface::get_owner_window(modal); owner_native = native_interface::get_owner_window(modal);
if(owner_native) if(owner_native)
{ {
@ -1177,7 +1184,7 @@ namespace detail
} }
} }
nana::detail::platform_spec::instance().msg_dispatch(modal_window ? reinterpret_cast<core_window_t*>(modal_window)->root : 0); nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? reinterpret_cast<core_window_t*>(condition_wd)->root : 0);
if(owner_native) if(owner_native)
{ {
@ -1190,7 +1197,7 @@ namespace detail
if(0 == --(context->event_pump_ref_count)) if(0 == --(context->event_pump_ref_count))
{ {
if(0 == modal_window || 0 == context->window_count) if(0 == condition_wd || 0 == context->window_count)
remove_thread_context(); remove_thread_context();
} }

View File

@ -1,7 +1,7 @@
/** /**
* A Bedrock Implementation * A Bedrock Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2017 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
@ -345,7 +345,7 @@ namespace detail
} }
} }
void bedrock::pump_event(window modal_window, bool is_modal) void bedrock::pump_event(window condition_wd, bool is_modal)
{ {
const unsigned tid = ::GetCurrentThreadId(); const unsigned tid = ::GetCurrentThreadId();
auto context = this->open_thread_context(tid); auto context = this->open_thread_context(tid);
@ -365,9 +365,9 @@ namespace detail
try try
{ {
MSG msg; MSG msg;
if(modal_window) if (condition_wd)
{ {
HWND native_handle = reinterpret_cast<HWND>(reinterpret_cast<core_window_t*>(modal_window)->root); HWND native_handle = reinterpret_cast<HWND>(reinterpret_cast<core_window_t*>(condition_wd)->root);
if (is_modal) if (is_modal)
{ {
HWND owner = ::GetWindow(native_handle, GW_OWNER); HWND owner = ::GetWindow(native_handle, GW_OWNER);
@ -437,27 +437,27 @@ namespace detail
} }
catch(std::exception& e) catch(std::exception& e)
{ {
(msgbox(modal_window, "An uncaptured std::exception during message pumping: ").icon(msgbox::icon_information) (msgbox(condition_wd, "An uncaptured std::exception during message pumping: ").icon(msgbox::icon_information)
<<"\n in form: "<< API::window_caption(modal_window) << "\n in form: " << API::window_caption(condition_wd)
<<"\n exception : "<< e.what() <<"\n exception : "<< e.what()
).show(); ).show();
internal_scope_guard lock; internal_scope_guard lock;
_m_except_handler(); _m_except_handler();
intr_locker.forward(); intr_locker.forward();
if (0 == --(context->event_pump_ref_count)) if (0 == --(context->event_pump_ref_count))
{ {
if ((nullptr == modal_window) || (0 == context->window_count)) if ((nullptr == condition_wd) || (0 == context->window_count))
remove_thread_context(); remove_thread_context();
} }
throw; throw;
} }
catch(...) catch(...)
{ {
(msgbox(modal_window, "An exception during message pumping!").icon(msgbox::icon_information) (msgbox(condition_wd, "An exception during message pumping!").icon(msgbox::icon_information)
<<"An uncaptured non-std exception during message pumping!" <<"An uncaptured non-std exception during message pumping!"
<< "\n in form: " << API::window_caption(modal_window) << "\n in form: " << API::window_caption(condition_wd)
).show(); ).show();
internal_scope_guard lock; internal_scope_guard lock;
_m_except_handler(); _m_except_handler();
@ -465,7 +465,7 @@ namespace detail
intr_locker.forward(); intr_locker.forward();
if(0 == --(context->event_pump_ref_count)) if(0 == --(context->event_pump_ref_count))
{ {
if((nullptr == modal_window) || (0 == context->window_count)) if ((nullptr == condition_wd) || (0 == context->window_count))
remove_thread_context(); remove_thread_context();
} }
throw; throw;
@ -474,7 +474,7 @@ namespace detail
intr_locker.forward(); intr_locker.forward();
if(0 == --(context->event_pump_ref_count)) if(0 == --(context->event_pump_ref_count))
{ {
if((nullptr == modal_window) || (0 == context->window_count)) if ((nullptr == condition_wd) || (0 == context->window_count))
remove_thread_context(); remove_thread_context();
} }
}//end pump_event }//end pump_event
@ -784,7 +784,7 @@ namespace detail
static auto& brock = bedrock::instance(); static auto& brock = bedrock::instance();
static restrict::TRACKMOUSEEVENT track = {sizeof track, 0x00000002}; static restrict::TRACKMOUSEEVENT track = {sizeof track, 0x00000002};
auto native_window = reinterpret_cast<native_window_type>(root_window); auto const native_window = reinterpret_cast<native_window_type>(root_window);
auto & wd_manager = brock.wd_manager(); auto & wd_manager = brock.wd_manager();
auto* root_runtime = wd_manager.root_runtime(native_window); auto* root_runtime = wd_manager.root_runtime(native_window);
@ -1720,9 +1720,16 @@ namespace detail
thrd->cursor.handle = ::LoadCursor(nullptr, translate(cur)); thrd->cursor.handle = ::LoadCursor(nullptr, translate(cur));
} }
if (wd->root_widget->other.attribute.root->running_cursor != cur) auto this_cur = reinterpret_cast<HCURSOR>(
#ifdef _WIN64
::GetClassLongPtr(reinterpret_cast<HWND>(wd->root), GCLP_HCURSOR)
#else
::GetClassLong(reinterpret_cast<HWND>(wd->root), GCL_HCURSOR)
#endif
);
if(this_cur != thrd->cursor.handle)
{ {
wd->root_widget->other.attribute.root->running_cursor = cur;
#ifdef _WIN64 #ifdef _WIN64
::SetClassLongPtr(reinterpret_cast<HWND>(wd->root), GCLP_HCURSOR, ::SetClassLongPtr(reinterpret_cast<HWND>(wd->root), GCLP_HCURSOR,
reinterpret_cast<LONG_PTR>(thrd->cursor.handle)); reinterpret_cast<LONG_PTR>(thrd->cursor.handle));
@ -1731,6 +1738,7 @@ namespace detail
static_cast<unsigned long>(reinterpret_cast<size_t>(thrd->cursor.handle))); static_cast<unsigned long>(reinterpret_cast<size_t>(thrd->cursor.handle)));
#endif #endif
} }
if (cursor::arrow == thrd->cursor.predef_cursor) if (cursor::arrow == thrd->cursor.predef_cursor)
{ {
thrd->cursor.window = nullptr; thrd->cursor.window = nullptr;
@ -1804,10 +1812,7 @@ namespace detail
undefine_state_cursor(wd, thrd); undefine_state_cursor(wd, thrd);
if(wd == thrd->cursor.window) if(wd == thrd->cursor.window)
{
set_cursor(wd, cursor::arrow, thrd); set_cursor(wd, cursor::arrow, thrd);
wd->root_widget->other.attribute.root->running_cursor = cursor::arrow;
}
break; break;
default: default:
break; break;

View File

@ -80,19 +80,22 @@ namespace nana
internal_scope_guard lock; internal_scope_guard lock;
if (dockers_) if (dockers_)
{ {
for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i)
{ {
if (reinterpret_cast<detail::docker_interface*>(evt) == *i) if (reinterpret_cast<detail::docker_interface*>(evt) == *i)
{ {
//Checks whether this event is working now. //Checks whether this event is working now.
if (emitting_count_ > 1) if (emitting_count_)
{ {
static_cast<docker_base*>(*i)->flag_deleted = true; static_cast<docker_base*>(*i)->flag_deleted = true;
deleted_flags_ = true; deleted_flags_ = true;
} }
else else
{
bedrock::instance().evt_operation().cancel(evt);
dockers_->erase(i); dockers_->erase(i);
delete reinterpret_cast<detail::docker_interface*>(evt);
}
break; break;
} }
} }
@ -131,7 +134,11 @@ namespace nana
for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();) for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();)
{ {
if (static_cast<docker_base*>(*i)->flag_deleted) if (static_cast<docker_base*>(*i)->flag_deleted)
{
bedrock::instance().evt_operation().cancel(reinterpret_cast<event_handle>(*i));
delete (*i);
i = evt_->dockers_->erase(i); i = evt_->dockers_->erase(i);
}
else else
++i; ++i;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Platform Implementation * Platform Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2017 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
@ -197,6 +197,13 @@ namespace nana{
return rectangle{ primary_monitor_size() }; return rectangle{ primary_monitor_size() };
} }
#ifdef NANA_X11
//The XMoveWindow and XMoveResizeWindow don't take effect if the specified window is
//unmapped, and the members x and y of XSetSizeHints is obsoluted. So the position that
//set to a unmapped windows should be kept and use the position when the window is mapped.
std::map<Window, ::nana::point> exposed_positions; //locked by platform_scope_guard
#endif
//platform-dependent //platform-dependent
native_interface::window_result native_interface::create_window(native_window_type owner, bool nested, const rectangle& r, const appearance& app) native_interface::window_result native_interface::create_window(native_window_type owner, bool nested, const rectangle& r, const appearance& app)
{ {
@ -289,6 +296,7 @@ namespace nana{
{ {
win_attr.save_under = True; win_attr.save_under = True;
attr_mask |= CWSaveUnder; attr_mask |= CWSaveUnder;
parent = restrict::spec.root_window(); parent = restrict::spec.root_window();
calc_screen_point(owner, pos); calc_screen_point(owner, pos);
} }
@ -303,7 +311,12 @@ namespace nana{
{ {
//make owner if it is a popup window //make owner if it is a popup window
if((!nested) && owner) if((!nested) && owner)
{
restrict::spec.make_owner(owner, reinterpret_cast<native_window_type>(handle)); restrict::spec.make_owner(owner, reinterpret_cast<native_window_type>(handle));
exposed_positions[handle] = pos;
}
XChangeWindowAttributes(disp, handle, attr_mask, &win_attr);
XTextProperty name; XTextProperty name;
char text[] = "Nana Window"; char text[] = "Nana Window";
@ -655,6 +668,14 @@ namespace nana{
if(show) if(show)
{ {
::XMapWindow(disp, reinterpret_cast<Window>(wd)); ::XMapWindow(disp, reinterpret_cast<Window>(wd));
auto i = exposed_positions.find(reinterpret_cast<Window>(wd));
if(i != exposed_positions.end())
{
::XMoveWindow(disp, reinterpret_cast<Window>(wd), i->second.x, i->second.y);
exposed_positions.erase(i);
}
Window grab = restrict::spec.grab(0); Window grab = restrict::spec.grab(0);
if(grab == reinterpret_cast<Window>(wd)) if(grab == reinterpret_cast<Window>(wd))
capture_window(wd, true); capture_window(wd, true);
@ -882,13 +903,7 @@ namespace nana{
XWindowAttributes attr; XWindowAttributes attr;
::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr); ::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr);
if(attr.map_state == IsUnmapped) if(attr.map_state == IsUnmapped)
{ exposed_positions[reinterpret_cast<Window>(wd)] = ::nana::point{x, y};
XSizeHints hints;
hints.flags = USPosition;
hints.x = x;
hints.y = y;
::XSetWMNormalHints(disp, reinterpret_cast<Window>(wd), &hints);
}
::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y); ::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y);
#endif #endif
@ -959,11 +974,11 @@ namespace nana{
::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr); ::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr);
if(attr.map_state == IsUnmapped) if(attr.map_state == IsUnmapped)
{ {
hints.flags |= (USPosition | USSize); hints.flags |= USSize;
hints.x = x;
hints.y = y;
hints.width = r.width; hints.width = r.width;
hints.height = r.height; hints.height = r.height;
exposed_positions[reinterpret_cast<Window>(wd)] = point{x, y};
} }
if(hints.flags) if(hints.flags)

View File

@ -1,7 +1,7 @@
/* /*
* Window Manager Implementation * Window Manager Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2017 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
@ -685,6 +685,30 @@ namespace detail
} }
} }
void sync_child_root_display(window_manager::core_window_t* wd)
{
for (auto & child : wd->children)
{
if (category::flags::root != child->other.category)
{
sync_child_root_display(child);
continue;
}
auto const vs_parents = child->visible_parents();
if (vs_parents != child->visible)
{
native_interface::show_window(child->root, vs_parents, false);
}
else
{
if (child->visible != native_interface::is_window_visible(child->root))
native_interface::show_window(child->root, child->visible, false);
}
}
}
//show //show
//@brief: show or hide a window //@brief: show or hide a window
bool window_manager::show(core_window_t* wd, bool visible) bool window_manager::show(core_window_t* wd, bool visible)
@ -719,8 +743,15 @@ namespace detail
if(category::flags::root != wd->other.category) if(category::flags::root != wd->other.category)
bedrock::instance().event_expose(wd, visible); bedrock::instance().event_expose(wd, visible);
if(nv) if (nv)
{
if (visible && !wd->visible_parents())
return true;
native_interface::show_window(nv, visible, wd->flags.take_active); native_interface::show_window(nv, visible, wd->flags.take_active);
}
sync_child_root_display(wd);
} }
return true; return true;
} }
@ -1386,6 +1417,8 @@ namespace detail
void window_manager::remove_trash_handle(unsigned tid) void window_manager::remove_trash_handle(unsigned tid)
{ {
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
impl_->wd_register.delete_trash(tid); impl_->wd_register.delete_trash(tid);
} }

View File

@ -618,7 +618,7 @@ namespace nana
place_.field_display(img_fields[i], false); place_.field_display(img_fields[i], false);
} }
size({desc_extent.width, height }); move(API::make_center(this->owner(), desc_extent.width, height));
caption(title); caption(title);
} }

View File

@ -1,7 +1,7 @@
/* /*
* A Categorize Implementation * A Categorize Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2017 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
@ -343,7 +343,7 @@ namespace nana
{ {
if(tree_.get_root()->child) if(tree_.get_root()->child)
{ {
tree_.clear(); tree_.clear(tree_.get_root());
return true; return true;
} }
return false; return false;

View File

@ -747,7 +747,7 @@ namespace nana
//add a is_wd_parent_menu to determine whether the menu wants the focus. //add a is_wd_parent_menu to determine whether the menu wants the focus.
//if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed //if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed
: base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()), : base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()),
want_focus_{ (!wd) || ((!is_wd_parent_menu) && (API::focus_window() != wd)) }, want_focus_{ (!wd) || ((!is_wd_parent_menu) && (API::root(API::focus_window()) != API::root(wd))) },
event_focus_{ nullptr } event_focus_{ nullptr }
{ {
caption("nana menu window"); caption("nana menu window");
@ -991,6 +991,12 @@ namespace nana
case keyboard::enter: case keyboard::enter:
this->pick(); this->pick();
break; break;
case keyboard::escape:
//Leave sub menu. But if the sub menu doesn't exist,
//close the menu.
if (!this->submenu(false))
close();
break;
default: default:
if (2 != send_shortkey(arg.key)) if (2 != send_shortkey(arg.key))
{ {
@ -1141,7 +1147,14 @@ namespace nana
throw std::out_of_range("menu: a new item inserted to an invalid position"); throw std::out_of_range("menu: a new item inserted to an invalid position");
std::unique_ptr<item_type> item{ new item_type{ std::move(text_utf8), handler } }; std::unique_ptr<item_type> item{ new item_type{ std::move(text_utf8), handler } };
impl_->mbuilder.data().items.emplace(impl_->mbuilder.data().items.cbegin() + pos, item.get());
items.emplace(
#ifdef _MSC_VER
items.cbegin() + pos,
#else
items.begin() + pos,
#endif
item.get());
return item_proxy{ pos, *item.release() }; return item_proxy{ pos, *item.release() };
} }

View File

@ -2050,24 +2050,29 @@ namespace nana{ namespace widgets
void text_editor::paste() void text_editor::paste()
{ {
std::wstring text; auto text = system::dataexch{}.wget();
nana::system::dataexch().get(text);
//If it is required check the acceptable //If it is required check the acceptable
if (accepts::no_restrict != impl_->capacities.acceptive) if ((accepts::no_restrict != impl_->capacities.acceptive) || impl_->capacities.pred_acceptive)
{ {
for (auto i = text.begin(); i != text.end(); ++i) for (auto i = text.begin(); i != text.end(); ++i)
{ {
if (!_m_accepts(*i)) if (_m_accepts(*i))
{
if (accepts::no_restrict == impl_->capacities.acceptive)
put(*i);
continue;
}
if (accepts::no_restrict != impl_->capacities.acceptive)
{ {
text.erase(i, text.end()); text.erase(i, text.end());
break; put(std::move(text));
} }
break;
} }
} }
if (!text.empty())
put(std::move(text));
} }
void text_editor::enter(bool record_undo) void text_editor::enter(bool record_undo)
@ -2794,8 +2799,12 @@ namespace nana{ namespace widgets
bool text_editor::_m_accepts(char_type ch) const bool text_editor::_m_accepts(char_type ch) const
{ {
if(accepts::no_restrict == impl_->capacities.acceptive) if (accepts::no_restrict == impl_->capacities.acceptive)
{
if (impl_->capacities.pred_acceptive)
return impl_->capacities.pred_acceptive(ch);
return true; return true;
}
//Checks the input whether it meets the requirement for a numeric. //Checks the input whether it meets the requirement for a numeric.
auto str = text(); auto str = text();

View File

@ -1,7 +1,7 @@
/* /*
* A Spin box widget * A Spin box widget
* 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-2017 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
@ -295,13 +295,13 @@ namespace nana
return range_->value(); return range_->value();
} }
bool value(const ::std::string& value_str) bool value(const ::std::string& value_str, bool reset_editor)
{ {
bool diff; bool diff;
if (!range_->value(value_str, diff)) if (!range_->value(value_str, diff))
return false; return false;
if (diff) if (diff && reset_editor)
reset_text(); reset_text();
return true; return true;
} }
@ -572,7 +572,7 @@ namespace nana
{ {
if (impl_->editor()->respond_char(arg)) if (impl_->editor()->respond_char(arg))
{ {
if (!impl_->value(to_utf8(impl_->editor()->text()))) if (!impl_->value(to_utf8(impl_->editor()->text()), false))
impl_->draw_spins(); impl_->draw_spins();
API::dev::lazy_refresh(); API::dev::lazy_refresh();
@ -657,7 +657,7 @@ namespace nana
internal_scope_guard lock; internal_scope_guard lock;
if (handle()) if (handle())
{ {
if (get_drawer_trigger().impl()->value(s)) if (get_drawer_trigger().impl()->value(s, true))
API::refresh_window(handle()); API::refresh_window(handle());
} }
} }

View File

@ -14,7 +14,6 @@
#include <nana/gui/element.hpp> #include <nana/gui/element.hpp>
#include <nana/gui/layout_utility.hpp> #include <nana/gui/layout_utility.hpp>
#include <nana/system/platform.hpp> #include <nana/system/platform.hpp>
#include <stdexcept>
#include <map> #include <map>
namespace nana namespace nana
@ -166,7 +165,7 @@ namespace nana
class trigger::item_locator class trigger::item_locator
{ {
public: public:
typedef tree_cont_type::node_type node_type; using node_type = tree_cont_type::node_type;
item_locator(implement * impl, int item_pos, int x, int y); item_locator(implement * impl, int item_pos, int x, int y);
int operator()(node_type &node, int affect); int operator()(node_type &node, int affect);
@ -199,7 +198,7 @@ namespace nana
template<typename Renderer> template<typename Renderer>
struct trigger::basic_implement struct trigger::basic_implement
{ {
typedef trigger::node_type node_type; using node_type = trigger::node_type;
struct rep_tag struct rep_tag
{ {
@ -216,11 +215,10 @@ namespace nana
{ {
nana::upoint border; nana::upoint border;
nana::scroll<true> scroll; nana::scroll<true> scroll;
std::size_t prev_first_value;
mutable std::map<std::string, node_image_tag> image_table; mutable std::map<std::string, node_image_tag> image_table;
tree_cont_type::node_type * first; tree_cont_type::node_type * first; //The node at the top of screen
int indent_pixels; int indent_pixels;
int offset_x; int offset_x;
}shape; }shape;
@ -235,9 +233,9 @@ namespace nana
{ {
tooltip_window * tooltip; tooltip_window * tooltip;
component comp_pointed; component comp_pointed;
tree_cont_type::node_type * pointed; node_type * pointed;
tree_cont_type::node_type * selected; node_type * selected;
tree_cont_type::node_type * event_node; node_type * pressed_node;
}node_state; }node_state;
struct track_node_tag struct track_node_tag
@ -260,7 +258,6 @@ namespace nana
data.widget_ptr = nullptr; data.widget_ptr = nullptr;
data.stop_drawing = false; data.stop_drawing = false;
shape.prev_first_value = 0;
shape.first = nullptr; shape.first = nullptr;
shape.indent_pixels = 10; shape.indent_pixels = 10;
shape.offset_x = 0; shape.offset_x = 0;
@ -271,7 +268,7 @@ namespace nana
node_state.comp_pointed = component::end; node_state.comp_pointed = component::end;
node_state.pointed = nullptr; node_state.pointed = nullptr;
node_state.selected = nullptr; node_state.selected = nullptr;
node_state.event_node = nullptr; node_state.pressed_node = nullptr;
track_node.key_time = 0; track_node.key_time = 0;
@ -304,19 +301,58 @@ namespace nana
} }
} }
bool draw(bool scrollbar_react) bool unlink(node_type* node, bool perf_clear)
{
if (!attr.tree_cont.verify(node))
return false;
if (node->is_ancestor_of(shape.first))
{
shape.first = node->front();
if (shape.first)
shape.first = node->owner;
}
if (node->is_ancestor_of(node_state.pointed))
node_state.pointed = nullptr;
if (node->is_ancestor_of(node_state.selected))
node_state.selected = nullptr;
if (perf_clear)
{
if (node->child)
{
attr.tree_cont.clear(node);
return true;
}
return false;
}
attr.tree_cont.remove(node);
return true;
}
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))
{ {
if(scrollbar_react) if (reset_scroll)
show_scroll(); show_scroll();
//Draw background if (attr.auto_draw || ignore_auto_draw)
data.graph->rectangle(true, data.widget_ptr->bgcolor()); {
//Draw background
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, Renderer(this, nana::point(static_cast<int>(attr.tree_cont.indent_size(shape.first) * shape.indent_pixels) - shape.offset_x, 1)));
return true;
if (!ignore_update)
API::update_window(data.widget_ptr->handle());
return true;
}
} }
return false; return false;
} }
@ -402,42 +438,45 @@ namespace nana
return nullptr; return nullptr;
} }
static bool check_kinship(const node_type* parent, const node_type * child)
{
if((!parent) || (!child))
return false;
while(child && (child != parent))
child = child->owner;
return (nullptr != child);
}
bool make_adjust(node_type * node, int reason) bool make_adjust(node_type * node, int reason)
{ {
if(!node) return false; if(!node) return false;
auto & tree_container = attr.tree_cont; auto & tree = attr.tree_cont;
auto const first_pos = tree.distance_if(shape.first, pred_allow_child{});
auto const node_pos = tree.distance_if(node, pred_allow_child{});
auto const max_allow = max_allowed();
switch(reason) switch(reason)
{ {
case 0: case 0:
//adjust if the node expanded and the number of its children are over the max number allowed if (node->value.second.expanded)
if(shape.first != node)
{ {
unsigned child_size = tree_container.child_size_if(*node, pred_allow_child()); //adjust if the number of its children are over the max number allowed
const std::size_t max_allow = max_allowed(); if (shape.first != node)
if(child_size < max_allow)
{ {
unsigned off1 = tree_container.distance_if(shape.first, pred_allow_child()); auto child_size = tree.child_size_if(*node, pred_allow_child());
unsigned off2 = tree_container.distance_if(node, pred_allow_child()); if (child_size < max_allow)
const unsigned size = off2 - off1 + child_size + 1; {
if(size > max_allow) auto const size = node_pos - first_pos + child_size + 1;
shape.first = tree_container.advance_if(shape.first, size - max_allow, pred_allow_child()); if (size > max_allow)
shape.first = tree.advance_if(shape.first, size - max_allow, pred_allow_child{});
}
else
shape.first = node;
}
}
else
{
//The node is shrank
auto visual_size = visual_item_size();
if (visual_size > max_allow)
{
if (first_pos + max_allow > visual_size)
shape.first = tree.advance_if(nullptr, visual_size - max_allow, pred_allow_child{});
} }
else else
shape.first = node; shape.first = nullptr;
} }
break; break;
case 1: case 1:
@ -445,7 +484,7 @@ namespace nana
case 3: case 3:
//param is the begin pos of an item in absolute. //param is the begin pos of an item in absolute.
{ {
int beg = static_cast<int>(tree_container.indent_size(node) * shape.indent_pixels) - shape.offset_x; int beg = static_cast<int>(tree.indent_size(node) * shape.indent_pixels) - shape.offset_x;
int end = beg + static_cast<int>(node_w_pixels(node)); int end = beg + static_cast<int>(node_w_pixels(node));
bool take_adjust = false; bool take_adjust = false;
@ -468,16 +507,14 @@ namespace nana
case 4: case 4:
if(shape.first != node) if(shape.first != node)
{ {
unsigned off_first = tree_container.distance_if(shape.first, pred_allow_child()); if (node_pos < first_pos)
unsigned off_node = tree_container.distance_if(node, pred_allow_child());
if(off_node < off_first)
{ {
shape.first = node; shape.first = node;
return true; return true;
} }
else if(off_node - off_first > max_allowed()) else if (node_pos - first_pos > max_allow)
{ {
shape.first = tree_container.advance_if(0, off_node - max_allowed() + 1, pred_allow_child()); shape.first = tree.advance_if(nullptr, node_pos - max_allow + 1, pred_allow_child{});
return true; return true;
} }
} }
@ -535,7 +572,7 @@ namespace nana
if(value == false) if(value == false)
{ {
//if contracting a parent of the selected node, select the contracted node. //if contracting a parent of the selected node, select the contracted node.
if(check_kinship(node, node_state.selected)) if (node->is_ancestor_of(node_state.selected))
set_selected(node); set_selected(node);
} }
@ -543,7 +580,6 @@ namespace nana
if(node->child) if(node->child)
{ {
data.stop_drawing = true; data.stop_drawing = true;
//attr.ext_event.expand(data.widget_ptr->handle(), item_proxy(data.trigger_ptr, node), value);
item_proxy iprx(data.trigger_ptr, node); item_proxy iprx(data.trigger_ptr, node);
data.widget_ptr->events().expanded.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, value }, data.widget_ptr->handle()); data.widget_ptr->events().expanded.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, value }, data.widget_ptr->handle());
data.stop_drawing = false; data.stop_drawing = false;
@ -573,44 +609,24 @@ namespace nana
{ {
if(scroll.empty()) if(scroll.empty())
{ {
shape.prev_first_value = 0;
scroll.create(*data.widget_ptr, nana::rectangle(data.graph->width() - 16, 0, 16, data.graph->height())); scroll.create(*data.widget_ptr, nana::rectangle(data.graph->width() - 16, 0, 16, data.graph->height()));
auto fn = [this](const arg_mouse& arg){ scroll.events().value_changed.connect_unignorable([this](const arg_scroll& arg)
this->event_scrollbar(arg); {
}; adjust.scroll_timestamp = nana::system::timestamp();
auto & events = scroll.events(); adjust.timer.start();
events.mouse_down(fn);
events.mouse_move(fn); shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll.value(), pred_allow_child{});
events.mouse_wheel(fn); draw(false, false, true);
});
} }
scroll.amount(visual_items); scroll.amount(visual_items);
scroll.range(max_allow); scroll.range(max_allow);
} }
scroll.value(attr.tree_cont.distance_if(shape.first, pred_allow_child())); auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{});
} scroll.value(pos);
void event_scrollbar(const arg_mouse& arg)
{
if((event_code::mouse_wheel == arg.evt_code) || arg.is_left_button())
{
if(shape.prev_first_value != shape.scroll.value())
{
shape.prev_first_value = shape.scroll.value();
adjust.scroll_timestamp = nana::system::timestamp();
adjust.timer.start();
shape.first = attr.tree_cont.advance_if(nullptr, shape.prev_first_value, pred_allow_child());
if(arg.window_handle == shape.scroll.handle())
{
draw(false);
API::update_window(data.widget_ptr->handle());
}
}
}
} }
std::size_t visual_item_size() const std::size_t visual_item_size() const
@ -672,11 +688,10 @@ namespace nana
attr.tree_cont.template for_each<item_locator&>(shape.first, nl); attr.tree_cont.template for_each<item_locator&>(shape.first, nl);
bool redraw = false; bool redraw = false;
node_state.event_node = nl.node(); auto const node = nl.node();
if (node && (nl.what() != component::end))
if(nl.node() && (nl.what() != component::end))
{ {
if((nl.what() != node_state.comp_pointed || nl.node() != node_state.pointed)) if ((nl.what() != node_state.comp_pointed) || (node != node_state.pointed))
{ {
node_state.comp_pointed = nl.what(); node_state.comp_pointed = nl.what();
@ -685,12 +700,11 @@ namespace nana
item_proxy iprx(data.trigger_ptr, node_state.pointed); item_proxy iprx(data.trigger_ptr, node_state.pointed);
data.widget_ptr->events().hovered.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, false }, data.widget_ptr->handle()); data.widget_ptr->events().hovered.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, false }, data.widget_ptr->handle());
if (nl.node() != node_state.pointed) if (node != node_state.pointed)
close_tooltip_window(); close_tooltip_window();
} }
node_state.pointed = node;
node_state.pointed = nl.node();
item_proxy iprx(data.trigger_ptr, node_state.pointed); item_proxy iprx(data.trigger_ptr, node_state.pointed);
data.widget_ptr->events().hovered.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, true }, data.widget_ptr->handle()); data.widget_ptr->events().hovered.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, true }, data.widget_ptr->handle());
@ -751,11 +765,11 @@ namespace nana
}; };
auto & events = node_state.tooltip->events(); auto & events = node_state.tooltip->events();
events.mouse_leave(fn); events.mouse_leave.connect_unignorable(fn);
events.mouse_move(fn); events.mouse_move.connect_unignorable(fn);
events.mouse_down.connect(fn); events.mouse_down.connect_unignorable(fn);
events.mouse_up.connect(fn); events.mouse_up.connect_unignorable(fn);
events.dbl_click.connect(fn); events.dbl_click.connect_unignorable(fn);
} }
} }
@ -866,7 +880,18 @@ namespace nana
item_proxy& item_proxy::check(bool ck) item_proxy& item_proxy::check(bool ck)
{ {
trigger_->check(node_, ck ? checkstate::checked : checkstate::unchecked); trigger_->check(node_, ck ? checkstate::checked : checkstate::unchecked);
trigger_->draw(); trigger_->impl()->draw(false);
return *this;
}
item_proxy& item_proxy::clear()
{
if (node_)
{
auto impl = trigger_->impl();
if(impl->unlink(node_, true))
impl->draw(true);
}
return *this; return *this;
} }
@ -879,10 +904,8 @@ namespace nana
{ {
auto * impl = trigger_->impl(); auto * impl = trigger_->impl();
if(impl->set_expanded(node_, exp)) if(impl->set_expanded(node_, exp))
{
impl->draw(true); impl->draw(true);
API::update_window(impl->data.widget_ptr->handle());
}
return *this; return *this;
} }
@ -895,10 +918,8 @@ namespace nana
{ {
auto * impl = trigger_->impl(); auto * impl = trigger_->impl();
if(impl->set_selected(s ? node_ : nullptr)) if(impl->set_selected(s ? node_ : nullptr))
{
impl->draw(true); impl->draw(true);
API::update_window(*impl->data.widget_ptr);
}
return *this; return *this;
} }
@ -1133,7 +1154,7 @@ namespace nana
{ {
switch(comp) switch(comp)
{ {
case component_t::expender: case component_t::expander:
if(attr.has_children) if(attr.has_children)
{ {
r->width = item_offset; r->width = item_offset;
@ -1222,7 +1243,7 @@ namespace nana
void expander(graph_reference graph, const compset_interface * compset) const override void expander(graph_reference graph, const compset_interface * compset) const override
{ {
comp_attribute_t attr; comp_attribute_t attr;
if(compset->comp_attribute(component::expender, attr)) if(compset->comp_attribute(component::expander, attr))
{ {
facade<element::arrow> arrow("solid_triangle"); facade<element::arrow> arrow("solid_triangle");
arrow.direction(direction::southeast); arrow.direction(direction::southeast);
@ -1323,29 +1344,31 @@ namespace nana
node_r.width = comp_placer->item_width(*impl_->data.graph, node_attr_); node_r.width = comp_placer->item_width(*impl_->data.graph, node_attr_);
node_r.height = comp_placer->item_height(*impl_->data.graph); node_r.height = comp_placer->item_height(*impl_->data.graph);
if(pos_.y < item_pos_.y + static_cast<int>(node_r.height)) if ((pos_.y < item_pos_.y + static_cast<int>(node_r.height)) && (pos_.y >= item_pos_.y))
{ {
auto logic_pos = pos_ - item_pos_; auto const logic_pos = pos_ - item_pos_;
node_ = &node;
for(int comp = static_cast<int>(component::begin); comp != static_cast<int>(component::end); ++comp) for (int comp = static_cast<int>(component::begin); comp != static_cast<int>(component::end); ++comp)
{ {
nana::rectangle r = node_r; nana::rectangle r = node_r;
if(comp_placer->locate(static_cast<component>(comp), node_attr_, &r)) if (!comp_placer->locate(static_cast<component>(comp), node_attr_, &r))
continue;
if (r.is_hit(logic_pos))
{ {
if(r.is_hit(logic_pos)) node_ = &node;
{ what_ = static_cast<component>(comp);
what_ = static_cast<component>(comp); if (component::expander == what_ && (false == node_attr_.has_children))
if(component::expender == what_ && (false == node_attr_.has_children)) what_ = component::end;
what_ = component::end;
if(component::text == what_) if (component::text == what_)
node_text_r_ = r; node_text_r_ = r;
return 0; break;
}
} }
} }
return 0; //Stop iterating
} }
item_pos_.y += node_r.height; item_pos_.y += node_r.height;
@ -1530,7 +1553,6 @@ namespace nana
} }
impl_->draw(false); impl_->draw(false);
API::update_window(impl_->data.widget_ptr->handle());
if (impl_->node_state.tooltip) if (impl_->node_state.tooltip)
{ {
@ -1629,26 +1651,6 @@ namespace nana
} }
} }
bool trigger::draw()
{
if (!impl_->attr.auto_draw)
return false;
if(impl_->draw(false))
API::update_window(impl_->data.widget_ptr->handle());
return true;
}
auto trigger::tree() -> tree_cont_type &
{
return impl_->attr.tree_cont;
}
auto trigger::tree() const -> tree_cont_type const &
{
return impl_->attr.tree_cont;
}
void trigger::renderer(::nana::pat::cloneable<renderer_interface>&& r) void trigger::renderer(::nana::pat::cloneable<renderer_interface>&& r)
{ {
impl_->data.renderer = std::move(r); impl_->data.renderer = std::move(r);
@ -1669,14 +1671,6 @@ namespace nana
return impl_->data.comp_placer; return impl_->data.comp_placer;
} }
nana::any & trigger::value(node_type* node) const
{
if(impl_->attr.tree_cont.verify(node) == false)
throw std::invalid_argument("Nana.GUI.treebox.value() invalid node");
return node->value.second.value;
}
trigger::node_type* trigger::insert(node_type* node, const std::string& key, std::string&& title) trigger::node_type* trigger::insert(node_type* node, const std::string& key, std::string&& title)
{ {
node_type * p = impl_->attr.tree_cont.node(node, key); node_type * p = impl_->attr.tree_cont.node(node, key);
@ -1685,49 +1679,20 @@ namespace nana
else else
p = impl_->attr.tree_cont.insert(node, key, treebox_node_type(std::move(title))); p = impl_->attr.tree_cont.insert(node, key, treebox_node_type(std::move(title)));
if(p && impl_->attr.auto_draw && impl_->draw(true)) if (p)
API::update_window(impl_->data.widget_ptr->handle()); impl_->draw(true);
return p; return p;
} }
trigger::node_type* trigger::insert(const std::string& path, std::string&& title) trigger::node_type* trigger::insert(const std::string& path, std::string&& title)
{ {
auto x = impl_->attr.tree_cont.insert(path, treebox_node_type(std::move(title))); auto x = impl_->attr.tree_cont.insert(path, treebox_node_type(std::move(title)));
if(x && impl_->attr.auto_draw && impl_->draw(true)) if (x)
API::update_window(impl_->data.widget_ptr->handle()); impl_->draw(true);
return x; return x;
} }
bool trigger::verify_kinship(node_type* parent, node_type* child) const
{
if(false == (parent && child)) return false;
while(child && (child != parent))
child = child->owner;
return (nullptr != child);
}
void trigger::remove(node_type* node)
{
if (!tree().verify(node))
return;
auto & shape = impl_->shape;
auto & node_state = impl_->node_state;
if(verify_kinship(node, node_state.event_node))
node_state.event_node = nullptr;
if(verify_kinship(node, shape.first))
shape.first = nullptr;
if(verify_kinship(node, node_state.selected))
node_state.selected = nullptr;
impl_->attr.tree_cont.remove(node);
}
trigger::node_type* trigger::selected() const trigger::node_type* trigger::selected() const
{ {
return impl_->node_state.selected; return impl_->node_state.selected;
@ -1735,29 +1700,8 @@ namespace nana
void trigger::selected(node_type* node) void trigger::selected(node_type* node)
{ {
if(tree().verify(node) && impl_->set_selected(node)) if(impl_->attr.tree_cont.verify(node) && impl_->set_selected(node))
{
if(impl_->draw(true))
API::update_window(impl_->data.widget_ptr->handle());
}
}
void trigger::set_expand(node_type* node, bool exp)
{
if((impl_->data.widget_ptr) && impl_->set_expanded(node, exp))
{
impl_->draw(true); impl_->draw(true);
API::update_window(impl_->data.widget_ptr->handle());
}
}
void trigger::set_expand(const std::string& path, bool exp)
{
if(impl_->set_expanded(impl_->attr.tree_cont.find(path), exp))
{
impl_->draw(true);
API::update_window(impl_->data.widget_ptr->handle());
}
} }
node_image_tag& trigger::icon(const std::string& id) const node_image_tag& trigger::icon(const std::string& id) const
@ -1780,12 +1724,12 @@ namespace nana
void trigger::node_icon(node_type* node, const std::string& id) void trigger::node_icon(node_type* node, const std::string& id)
{ {
if(tree().verify(node)) if(impl_->attr.tree_cont.verify(node))
{ {
node->value.second.img_idstr = id; node->value.second.img_idstr = id;
auto i = impl_->shape.image_table.find(id); auto i = impl_->shape.image_table.find(id);
if((i != impl_->shape.image_table.end()) && impl_->draw(true)) if (i != impl_->shape.image_table.end())
API::update_window(impl_->data.widget_ptr->handle()); impl_->draw(true);
} }
} }
@ -1798,7 +1742,7 @@ namespace nana
bool trigger::rename(node_type *node, const char* key, const char* name) bool trigger::rename(node_type *node, const char* key, const char* name)
{ {
if((key || name ) && tree().verify(node)) if((key || name ) && impl_->attr.tree_cont.verify(node))
{ {
if(key && (key != node->value.first)) if(key && (key != node->value.first))
{ {
@ -1831,7 +1775,8 @@ namespace nana
void trigger::refresh(graph_reference) void trigger::refresh(graph_reference)
{ {
impl_->draw(false); //Don't reset the scroll and update the window
impl_->draw(false, true);
} }
void trigger::dbl_click(graph_reference, const arg_mouse& arg) void trigger::dbl_click(graph_reference, const arg_mouse& arg)
@ -1842,12 +1787,21 @@ namespace nana
item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y);
impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl); impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl);
if(nl.node() && (nl.what() == component::text || nl.what() == component::icon)) auto const node = nl.node();
if (!node)
return;
auto & node_state = impl_->node_state;
switch (nl.what())
{ {
impl_->node_state.event_node = nl.node(); case component::icon:
impl_->set_expanded(impl_->node_state.event_node, !impl_->node_state.event_node->value.second.expanded); case component::text:
impl_->draw(true); impl_->set_expanded(node, !node->value.second.expanded);
impl_->draw(true, true, false);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
break;
default:
break;
} }
} }
@ -1862,34 +1816,20 @@ namespace nana
bool has_redraw = false; bool has_redraw = false;
auto & node_state = impl_->node_state; auto & node_state = impl_->node_state;
node_state.event_node = nullptr; node_state.pressed_node = nl.node();
if(nl.node()) if (node_state.pressed_node && (component::expander == nl.what()))
{ {
node_state.event_node = nl.node(); if(impl_->set_expanded(node_state.pressed_node, !node_state.pressed_node->value.second.expanded))
if(nl.what() != component::end) impl_->make_adjust(node_state.pressed_node, 0);
{
if(nl.what() == component::expender)
{
if(impl_->set_expanded(node_state.event_node, !node_state.event_node->value.second.expanded))
impl_->make_adjust(node_state.event_node, 0);
has_redraw = true; has_redraw = true; //btw, don't select the node
} }
else if(nl.item_body())
{ if ((!has_redraw) && (node_state.selected != node_state.pressed_node))
if(node_state.selected != node_state.event_node) {
{ impl_->set_selected(node_state.pressed_node);
impl_->set_selected(node_state.event_node); has_redraw = true;
has_redraw = true;
}
}
}
else if(node_state.selected != node_state.event_node)
{
impl_->set_selected(node_state.event_node);
has_redraw = true;
}
} }
if(has_redraw) if(has_redraw)
@ -1907,25 +1847,33 @@ namespace nana
item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y);
impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl); impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl);
auto const pressed_node = impl_->node_state.pressed_node;
impl_->node_state.pressed_node = nullptr;
if(!nl.node()) if(!nl.node())
return; return;
if((impl_->node_state.selected != nl.node()) && nl.item_body()) if (pressed_node == nl.node())
{ {
impl_->set_selected(nl.node()); if ((impl_->node_state.selected != nl.node()) && nl.item_body())
if(impl_->make_adjust(impl_->node_state.selected, 1)) {
impl_->adjust.scroll_timestamp = 1; impl_->set_selected(nl.node());
} if (impl_->make_adjust(impl_->node_state.selected, 1))
else if (nl.what() == component::crook) impl_->adjust.scroll_timestamp = 1;
{ }
checkstate cs = checkstate::unchecked; else if (nl.what() == component::crook)
if (checkstate::unchecked == nl.node()->value.second.checked) {
cs = checkstate::checked; checkstate cs = checkstate::unchecked;
if (checkstate::unchecked == nl.node()->value.second.checked)
cs = checkstate::checked;
check(nl.node(), cs); check(nl.node(), cs);
}
else
return; //Do not refresh
} }
else else
return; //Do not refresh return; //Don't refresh
impl_->draw(true); impl_->draw(true);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
@ -1942,18 +1890,19 @@ namespace nana
void trigger::mouse_wheel(graph_reference, const arg_wheel& arg) void trigger::mouse_wheel(graph_reference, const arg_wheel& arg)
{ {
auto & shape = impl_->shape; auto & scroll = impl_->shape.scroll;
std::size_t prev = shape.prev_first_value; if (scroll.empty())
return;
shape.scroll.make_step(!arg.upwards); auto const value_before = scroll.value();
impl_->event_scrollbar(arg); scroll.make_step(!arg.upwards);
if(prev != shape.prev_first_value) if (value_before != scroll.value())
{ {
impl_->track_mouse(arg.pos.x, arg.pos.y); impl_->track_mouse(arg.pos.x, arg.pos.y);
impl_->draw(false); impl_->draw(false, true, true);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
} }
@ -2168,7 +2117,7 @@ namespace nana
if (comp_placer->enabled(component::crook) != enable) if (comp_placer->enabled(component::crook) != enable)
{ {
comp_placer->enable(component::crook, enable); comp_placer->enable(component::crook, enable);
get_drawer_trigger().draw(); impl->draw(false);
} }
return *this; return *this;
} }
@ -2181,8 +2130,8 @@ namespace nana
void treebox::clear() void treebox::clear()
{ {
auto impl = get_drawer_trigger().impl(); auto impl = get_drawer_trigger().impl();
impl->attr.tree_cont.clear(); if (impl->unlink(impl->attr.tree_cont.get_root(), true))
get_drawer_trigger().draw(); impl->draw(true);
} }
treebox::node_image_type& treebox::icon(const std::string& id) const treebox::node_image_type& treebox::icon(const std::string& id) const
@ -2198,7 +2147,7 @@ namespace nana
auto treebox::find(const std::string& keypath) -> item_proxy auto treebox::find(const std::string& keypath) -> item_proxy
{ {
auto * trg = &get_drawer_trigger(); auto * trg = &get_drawer_trigger();
return item_proxy(trg, trg->tree().find(keypath)); return item_proxy(trg, trg->impl()->attr.tree_cont.find(keypath));
} }
treebox::item_proxy treebox::insert(const std::string& path_key, std::string title) treebox::item_proxy treebox::insert(const std::string& path_key, std::string title)
@ -2214,20 +2163,21 @@ namespace nana
treebox::item_proxy treebox::erase(item_proxy i) treebox::item_proxy treebox::erase(item_proxy i)
{ {
auto next = i.sibling(); auto next = i.sibling();
get_drawer_trigger().remove(i._m_node()); if (get_drawer_trigger().impl()->unlink(i._m_node(), false))
get_drawer_trigger().impl()->draw(true);
return next; return next;
} }
void treebox::erase(const std::string& keypath) void treebox::erase(const std::string& keypath)
{ {
auto i = find(keypath); auto i = find(keypath);
if(!i.empty()) if (!i.empty())
get_drawer_trigger().remove(i._m_node()); this->erase(i);
} }
std::string treebox::make_key_path(item_proxy i, const std::string& splitter) const std::string treebox::make_key_path(item_proxy i, const std::string& splitter) const
{ {
auto & tree = get_drawer_trigger().tree(); auto & tree = get_drawer_trigger().impl()->attr.tree_cont;
auto pnode = i._m_node(); auto pnode = i._m_node();
if(tree.verify(pnode)) if(tree.verify(pnode))
{ {

View File

@ -118,6 +118,7 @@ namespace nana{ namespace system{
static_cast<void>(g); //eliminate unused parameter compiler warning. static_cast<void>(g); //eliminate unused parameter compiler warning.
static_cast<void>(owner); static_cast<void>(owner);
throw std::logic_error("dataexch::set(const paint::graphics&, native_window_type owner) not implemented yet."); throw std::logic_error("dataexch::set(const paint::graphics&, native_window_type owner) not implemented yet.");
return false; return false;
#endif #endif
} }
@ -183,6 +184,14 @@ namespace nana{ namespace system{
#endif #endif
} }
} }
std::wstring dataexch::wget()
{
std::wstring str;
this->get(str);
return str;
}
//private: //private:
bool dataexch::_m_set(format fmt, const void* buf, std::size_t size, native_window_type owner) bool dataexch::_m_set(format fmt, const void* buf, std::size_t size, native_window_type owner)
{ {