diff --git a/build/codeblocks/nana.layout b/build/codeblocks/nana.layout new file mode 100644 index 00000000..593c06ed --- /dev/null +++ b/build/codeblocks/nana.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index e772a911..2230a422 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -222,9 +222,6 @@ namespace detail basic_window* focus{nullptr}; basic_window* menubar{nullptr}; bool ime_enabled{false}; -#if defined(NANA_WINDOWS) - cursor running_cursor{ nana::cursor::arrow }; -#endif cursor state_cursor{nana::cursor::arrow}; basic_window* state_cursor_window{ nullptr }; diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 1c6f50d0..4caef33e 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -64,7 +64,7 @@ namespace API void affinity_execute(window window_handle, const std::function&); bool set_events(window, const std::shared_ptr&); - + template std::unique_ptr make_scheme() { @@ -161,7 +161,7 @@ namespace API }//end namespace detail void exit(); ///< close all windows in current thread - void exit_all(); ///< close all windows + void exit_all(); ///< close all windows /// @brief Searchs whether the text contains a '&' and removes the character for transforming. /// If the text contains more than one '&' charachers, the others are ignored. e.g @@ -189,7 +189,7 @@ namespace API void window_icon_default(const paint::image& small_icon, const paint::image& big_icon = {}); void window_icon(window, const paint::image& small_icon, const paint::image& big_icon = {}); - + bool empty_window(window); ///< Determines whether a window is existing. bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. bool is_destroying(window); ///< Determines whether a window is destroying @@ -292,7 +292,7 @@ namespace API * @param window_handle A handle to the window to be refreshed. */ void refresh_window(window window_handle); - void refresh_window_tree(window); ///< Refreshs the specified window and all it’s 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 window_caption(window, const std::string& title_utf8); @@ -304,7 +304,7 @@ namespace API void activate_window(window); - /// Determines whether the specified window will get the keyboard focus when its root window gets native system focus. + /// Determines whether the specified window will get the keyboard focus when its root window gets native system focus. bool is_focus_ready(window); /// Returns the current keyboard focus window. @@ -322,7 +322,7 @@ namespace API * @param ignore_children Indicates whether to redirect the mouse input to its children if the mouse pointer is over its children. */ void set_capture(window window_handle, bool ignore_children); - + /// Disable a window to grab the mouse input. /** * @param window handle A handle to a window to release grab of mouse input. diff --git a/include/nana/gui/widgets/categorize.hpp b/include/nana/gui/widgets/categorize.hpp index 1e64fa14..dcbdde12 100644 --- a/include/nana/gui/widgets/categorize.hpp +++ b/include/nana/gui/widgets/categorize.hpp @@ -1,7 +1,7 @@ /** * A Categorize Implementation * 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. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/nana/gui/widgets/detail/tree_cont.hpp b/include/nana/gui/widgets/detail/tree_cont.hpp index c9684ba6..2490ab95 100644 --- a/include/nana/gui/widgets/detail/tree_cont.hpp +++ b/include/nana/gui/widgets/detail/tree_cont.hpp @@ -1,6 +1,6 @@ /* * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -58,6 +58,31 @@ namespace detail 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 @@ -76,12 +101,17 @@ namespace detail ~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 diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index dbbb6452..c4e39981 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -122,7 +122,9 @@ namespace nana 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; if (graph_ && (metrics_.value != s)) diff --git a/include/nana/gui/widgets/spinbox.hpp b/include/nana/gui/widgets/spinbox.hpp index e090426a..5b9b5a02 100644 --- a/include/nana/gui/widgets/spinbox.hpp +++ b/include/nana/gui/widgets/spinbox.hpp @@ -1,7 +1,7 @@ /** * A Spin box widget * 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. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 2f4fe7d7..a7e1bc77 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -37,7 +37,7 @@ namespace nana { enum class component { - begin, expender = begin, crook, icon, text, bground, end + begin, expander = begin, crook, icon, text, bground, end }; struct node_image_tag @@ -119,27 +119,17 @@ namespace nana implement * impl() const; void check(node_type*, checkstate); - bool draw(); - - const tree_cont_type & tree() const; - tree_cont_type & tree(); void renderer(::nana::pat::cloneable&&); const ::nana::pat::cloneable& renderer() const; void placer(::nana::pat::cloneable&&); const ::nana::pat::cloneable& placer() const; - nana::any & value(node_type*) const; node_type* insert(node_type*, const std::string& key, 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; 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; void icon_erase(const ::std::string&); @@ -201,6 +191,9 @@ namespace nana /// Set the check state, and it returns itself. item_proxy& check(bool); + /// Clears the child nodes + item_proxy& clear(); + /// Return true when the node is expanded \todo change to expanded ?? bool expanded() const; diff --git a/include/nana/system/dataexch.hpp b/include/nana/system/dataexch.hpp index 226515b6..7ce6be72 100644 --- a/include/nana/system/dataexch.hpp +++ b/include/nana/system/dataexch.hpp @@ -38,6 +38,8 @@ namespace system{ void get(std::string& text_utf8); void get(std::wstring& text); + + std::wstring wget(); private: bool _m_set(format, const void* buf, std::size_t size, native_window_type); void* _m_get(format, size_t& size); diff --git a/include/nana/verbose_preprocessor.hpp b/include/nana/verbose_preprocessor.hpp index a8bf2d7b..b4804546 100644 --- a/include/nana/verbose_preprocessor.hpp +++ b/include/nana/verbose_preprocessor.hpp @@ -30,9 +30,9 @@ - #define STRING2(x) #x + #define STRING2(...) #__VA_ARGS__ #define STRING(x) STRING2(x) - #define SHOW_VALUE(x) " " #x " = " STRING2(x) + #define SHOW_VALUE(x) " " #x " = " STRING2(x) #pragma message ( "\n -----> Verbose preprocessor" ) #pragma message ( SHOW_VALUE(VERBOSE_PREPROCESSOR) ) @@ -124,7 +124,7 @@ #pragma message ( SHOW_VALUE(USE_LIBJPEG_FROM_OS) ) #pragma message ( SHOW_VALUE(NANA_LIBJPEG) ) - + // #pragma message ( "\n =" STRING() ", \n =" STRING()" , \n =" STRING() ) #if defined(STOP_VERBOSE_PREPROCESSOR) diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index 7dd11333..cce9028f 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -1,7 +1,7 @@ /* * Platform Specification Implementation * 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. * (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 int platform_spec::_m_msg_filter(XEvent& evt, msg_packet_tag& msg) { + auto & bedrock = detail::bedrock::instance(); + platform_spec & self = instance(); - if(SelectionNotify == evt.type) + if(KeyPress == evt.type || KeyRelease == evt.type) + { + auto menu_wd = bedrock.get_menu(reinterpret_cast(evt.xkey.window), true); + if(menu_wd) + evt.xkey.window = reinterpret_cast(menu_wd); + } + else if(SelectionNotify == evt.type) { if(evt.xselection.property) { @@ -1197,7 +1205,6 @@ namespace detail } } - self.selection_.items.erase(self.selection_.items.begin()); std::lock_guardcond_mutex)> lock(im->cond_mutex); @@ -1373,9 +1380,8 @@ namespace detail { Window 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(evt.xclient.window), self.xdnd_.pos.x, self.xdnd_.pos.y); + auto wd = bedrock.wd_manager().find_window(reinterpret_cast(evt.xclient.window), self.xdnd_.pos.x, self.xdnd_.pos.y); if(wd && wd->flags.dropable) { accepted = true; diff --git a/source/detail/x11/msg_dispatcher.hpp b/source/detail/x11/msg_dispatcher.hpp index 77f43a18..b6fddcce 100644 --- a/source/detail/x11/msg_dispatcher.hpp +++ b/source/detail/x11/msg_dispatcher.hpp @@ -1,6 +1,6 @@ /* * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -51,7 +51,7 @@ namespace detail typedef std::list msg_queue_type; msg_dispatcher(Display* disp) - : display_(disp), is_work_(false) + : display_(disp) { proc_.event_proc = 0; proc_.timer_proc = 0; @@ -338,7 +338,7 @@ namespace detail private: Display * display_; - volatile bool is_work_; + volatile bool is_work_{ false }; std::unique_ptr thrd_; struct table_tag diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 5a3a4abe..f47ca96a 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -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 (msgwnd->root != native_interface::get_focus_window()) { - //call the drawer mouse up event for restoring the surface graphics - msgwnd->set_action(mouse_action::normal); + auto pos = native_interface::cursor_position(); + 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); - wd_manager.do_lazy_refresh(msgwnd, false); + arg.evt_code = event_code::mouse_up; + draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); + wd_manager.do_lazy_refresh(msgwnd, false); + } } } 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(); if(0 == context->window_count) @@ -1162,11 +1169,11 @@ namespace detail auto & lock = wd_manager().internal_lock(); lock.revert(); - native_window_type owner_native = 0; + native_window_type owner_native{}; core_window_t * owner = 0; - if(modal_window) + if(condition_wd && is_modal) { - native_window_type modal = reinterpret_cast(modal_window)->root; + native_window_type modal = reinterpret_cast(condition_wd)->root; owner_native = native_interface::get_owner_window(modal); if(owner_native) { @@ -1177,7 +1184,7 @@ namespace detail } } - nana::detail::platform_spec::instance().msg_dispatch(modal_window ? reinterpret_cast(modal_window)->root : 0); + nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? reinterpret_cast(condition_wd)->root : 0); if(owner_native) { @@ -1190,7 +1197,7 @@ namespace detail 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(); } diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 11ef721a..80a8fd12 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -1,7 +1,7 @@ /** * A Bedrock Implementation * 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. * (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(); auto context = this->open_thread_context(tid); @@ -365,9 +365,9 @@ namespace detail try { MSG msg; - if(modal_window) + if (condition_wd) { - HWND native_handle = reinterpret_cast(reinterpret_cast(modal_window)->root); + HWND native_handle = reinterpret_cast(reinterpret_cast(condition_wd)->root); if (is_modal) { HWND owner = ::GetWindow(native_handle, GW_OWNER); @@ -437,27 +437,27 @@ namespace detail } catch(std::exception& e) { - (msgbox(modal_window, "An uncaptured std::exception during message pumping: ").icon(msgbox::icon_information) - <<"\n in form: "<< API::window_caption(modal_window) - <<"\n exception : "<< e.what() - ).show(); + (msgbox(condition_wd, "An uncaptured std::exception during message pumping: ").icon(msgbox::icon_information) + << "\n in form: " << API::window_caption(condition_wd) + <<"\n exception : "<< e.what() + ).show(); - internal_scope_guard lock; - _m_except_handler(); + internal_scope_guard lock; + _m_except_handler(); - intr_locker.forward(); - if (0 == --(context->event_pump_ref_count)) - { - if ((nullptr == modal_window) || (0 == context->window_count)) - remove_thread_context(); - } - throw; + intr_locker.forward(); + if (0 == --(context->event_pump_ref_count)) + { + if ((nullptr == condition_wd) || (0 == context->window_count)) + remove_thread_context(); + } + throw; } 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!" - << "\n in form: " << API::window_caption(modal_window) + << "\n in form: " << API::window_caption(condition_wd) ).show(); internal_scope_guard lock; _m_except_handler(); @@ -465,7 +465,7 @@ namespace detail intr_locker.forward(); 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(); } throw; @@ -474,7 +474,7 @@ namespace detail intr_locker.forward(); 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(); } }//end pump_event @@ -784,7 +784,7 @@ namespace detail static auto& brock = bedrock::instance(); static restrict::TRACKMOUSEEVENT track = {sizeof track, 0x00000002}; - auto native_window = reinterpret_cast(root_window); + auto const native_window = reinterpret_cast(root_window); auto & wd_manager = brock.wd_manager(); auto* root_runtime = wd_manager.root_runtime(native_window); @@ -1720,9 +1720,16 @@ namespace detail thrd->cursor.handle = ::LoadCursor(nullptr, translate(cur)); } - if (wd->root_widget->other.attribute.root->running_cursor != cur) + auto this_cur = reinterpret_cast( +#ifdef _WIN64 + ::GetClassLongPtr(reinterpret_cast(wd->root), GCLP_HCURSOR) +#else + ::GetClassLong(reinterpret_cast(wd->root), GCL_HCURSOR) +#endif + ); + + if(this_cur != thrd->cursor.handle) { - wd->root_widget->other.attribute.root->running_cursor = cur; #ifdef _WIN64 ::SetClassLongPtr(reinterpret_cast(wd->root), GCLP_HCURSOR, reinterpret_cast(thrd->cursor.handle)); @@ -1731,6 +1738,7 @@ namespace detail static_cast(reinterpret_cast(thrd->cursor.handle))); #endif } + if (cursor::arrow == thrd->cursor.predef_cursor) { thrd->cursor.window = nullptr; @@ -1804,10 +1812,7 @@ namespace detail undefine_state_cursor(wd, thrd); if(wd == thrd->cursor.window) - { set_cursor(wd, cursor::arrow, thrd); - wd->root_widget->other.attribute.root->running_cursor = cursor::arrow; - } break; default: break; diff --git a/source/gui/detail/events_operation.cpp b/source/gui/detail/events_operation.cpp index bcafd688..40fe338e 100644 --- a/source/gui/detail/events_operation.cpp +++ b/source/gui/detail/events_operation.cpp @@ -80,19 +80,22 @@ namespace nana internal_scope_guard lock; if (dockers_) { - for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) { if (reinterpret_cast(evt) == *i) { //Checks whether this event is working now. - if (emitting_count_ > 1) + if (emitting_count_) { static_cast(*i)->flag_deleted = true; deleted_flags_ = true; } else + { + bedrock::instance().evt_operation().cancel(evt); dockers_->erase(i); + delete reinterpret_cast(evt); + } break; } } @@ -131,7 +134,11 @@ namespace nana for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();) { if (static_cast(*i)->flag_deleted) + { + bedrock::instance().evt_operation().cancel(reinterpret_cast(*i)); + delete (*i); i = evt_->dockers_->erase(i); + } else ++i; } diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 0657dd14..bdf75823 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -1,7 +1,7 @@ /* * Platform Implementation * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -197,6 +197,13 @@ namespace nana{ 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 exposed_positions; //locked by platform_scope_guard +#endif + //platform-dependent 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; attr_mask |= CWSaveUnder; + parent = restrict::spec.root_window(); calc_screen_point(owner, pos); } @@ -303,7 +311,12 @@ namespace nana{ { //make owner if it is a popup window if((!nested) && owner) + { restrict::spec.make_owner(owner, reinterpret_cast(handle)); + exposed_positions[handle] = pos; + } + + XChangeWindowAttributes(disp, handle, attr_mask, &win_attr); XTextProperty name; char text[] = "Nana Window"; @@ -655,6 +668,14 @@ namespace nana{ if(show) { ::XMapWindow(disp, reinterpret_cast(wd)); + + auto i = exposed_positions.find(reinterpret_cast(wd)); + if(i != exposed_positions.end()) + { + ::XMoveWindow(disp, reinterpret_cast(wd), i->second.x, i->second.y); + exposed_positions.erase(i); + } + Window grab = restrict::spec.grab(0); if(grab == reinterpret_cast(wd)) capture_window(wd, true); @@ -882,13 +903,7 @@ namespace nana{ XWindowAttributes attr; ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); if(attr.map_state == IsUnmapped) - { - XSizeHints hints; - hints.flags = USPosition; - hints.x = x; - hints.y = y; - ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); - } + exposed_positions[reinterpret_cast(wd)] = ::nana::point{x, y}; ::XMoveWindow(disp, reinterpret_cast(wd), x, y); #endif @@ -959,11 +974,11 @@ namespace nana{ ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); if(attr.map_state == IsUnmapped) { - hints.flags |= (USPosition | USSize); - hints.x = x; - hints.y = y; + hints.flags |= USSize; hints.width = r.width; hints.height = r.height; + + exposed_positions[reinterpret_cast(wd)] = point{x, y}; } if(hints.flags) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index e301ca5e..affd3abd 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1,7 +1,7 @@ /* * Window Manager Implementation * 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. * (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 //@brief: show or hide a window bool window_manager::show(core_window_t* wd, bool visible) @@ -719,8 +743,15 @@ namespace detail if(category::flags::root != wd->other.category) 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); + } + + sync_child_root_display(wd); } return true; } @@ -1386,6 +1417,8 @@ namespace detail void window_manager::remove_trash_handle(unsigned tid) { + //Thread-Safe Required! + std::lock_guard lock(mutex_); impl_->wd_register.delete_trash(tid); } diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 6b3b9510..6560fe93 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -618,7 +618,7 @@ namespace nana place_.field_display(img_fields[i], false); } - size({desc_extent.width, height }); + move(API::make_center(this->owner(), desc_extent.width, height)); caption(title); } diff --git a/source/gui/widgets/categorize.cpp b/source/gui/widgets/categorize.cpp index cf29e267..0ce7646c 100644 --- a/source/gui/widgets/categorize.cpp +++ b/source/gui/widgets/categorize.cpp @@ -1,7 +1,7 @@ /* * A Categorize Implementation * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -343,7 +343,7 @@ namespace nana { if(tree_.get_root()->child) { - tree_.clear(); + tree_.clear(tree_.get_root()); return true; } return false; diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 02ba5649..78f842bc 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -747,7 +747,7 @@ namespace nana //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 : base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald()), - 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 } { caption("nana menu window"); @@ -991,6 +991,12 @@ namespace nana case keyboard::enter: this->pick(); 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: 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"); std::unique_ptr 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() }; } diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index ad85bd42..f77ec32c 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -2050,24 +2050,29 @@ namespace nana{ namespace widgets void text_editor::paste() { - std::wstring text; - nana::system::dataexch().get(text); + auto text = system::dataexch{}.wget(); //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) { - 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()); - break; + put(std::move(text)); } + break; } } - - if (!text.empty()) - put(std::move(text)); } void text_editor::enter(bool record_undo) @@ -2794,8 +2799,12 @@ namespace nana{ namespace widgets 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; + } //Checks the input whether it meets the requirement for a numeric. auto str = text(); diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index 9f63baa2..ca87855a 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -1,7 +1,7 @@ /* * A Spin box widget * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -295,13 +295,13 @@ namespace nana return range_->value(); } - bool value(const ::std::string& value_str) + bool value(const ::std::string& value_str, bool reset_editor) { bool diff; if (!range_->value(value_str, diff)) return false; - if (diff) + if (diff && reset_editor) reset_text(); return true; } @@ -572,7 +572,7 @@ namespace nana { 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(); API::dev::lazy_refresh(); @@ -657,7 +657,7 @@ namespace nana internal_scope_guard lock; if (handle()) { - if (get_drawer_trigger().impl()->value(s)) + if (get_drawer_trigger().impl()->value(s, true)) API::refresh_window(handle()); } } diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index c7aeba61..350a4210 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include namespace nana @@ -166,7 +165,7 @@ namespace nana class trigger::item_locator { 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); int operator()(node_type &node, int affect); @@ -199,7 +198,7 @@ namespace nana template struct trigger::basic_implement { - typedef trigger::node_type node_type; + using node_type = trigger::node_type; struct rep_tag { @@ -216,11 +215,10 @@ namespace nana { nana::upoint border; nana::scroll scroll; - std::size_t prev_first_value; mutable std::map 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 offset_x; }shape; @@ -235,9 +233,9 @@ namespace nana { tooltip_window * tooltip; component comp_pointed; - tree_cont_type::node_type * pointed; - tree_cont_type::node_type * selected; - tree_cont_type::node_type * event_node; + node_type * pointed; + node_type * selected; + node_type * pressed_node; }node_state; struct track_node_tag @@ -260,7 +258,6 @@ namespace nana data.widget_ptr = nullptr; data.stop_drawing = false; - shape.prev_first_value = 0; shape.first = nullptr; shape.indent_pixels = 10; shape.offset_x = 0; @@ -271,7 +268,7 @@ namespace nana node_state.comp_pointed = component::end; node_state.pointed = nullptr; node_state.selected = nullptr; - node_state.event_node = nullptr; + node_state.pressed_node = nullptr; 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(scrollbar_react) + if (reset_scroll) show_scroll(); - //Draw background - data.graph->rectangle(true, data.widget_ptr->bgcolor()); + if (attr.auto_draw || ignore_auto_draw) + { + //Draw background + data.graph->rectangle(true, data.widget_ptr->bgcolor()); - //Draw tree - attr.tree_cont.for_each(shape.first, Renderer(this, nana::point(static_cast(attr.tree_cont.indent_size(shape.first) * shape.indent_pixels) - shape.offset_x, 1))); - return true; + //Draw tree + attr.tree_cont.for_each(shape.first, Renderer(this, nana::point(static_cast(attr.tree_cont.indent_size(shape.first) * shape.indent_pixels) - shape.offset_x, 1))); + + if (!ignore_update) + API::update_window(data.widget_ptr->handle()); + + return true; + } } return false; } @@ -402,42 +438,45 @@ namespace nana 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) { 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) { case 0: - //adjust if the node expanded and the number of its children are over the max number allowed - if(shape.first != node) + if (node->value.second.expanded) { - unsigned child_size = tree_container.child_size_if(*node, pred_allow_child()); - const std::size_t max_allow = max_allowed(); - - if(child_size < max_allow) + //adjust if the number of its children are over the max number allowed + if (shape.first != node) { - unsigned off1 = tree_container.distance_if(shape.first, pred_allow_child()); - unsigned off2 = tree_container.distance_if(node, pred_allow_child()); - const unsigned size = off2 - off1 + child_size + 1; - if(size > max_allow) - shape.first = tree_container.advance_if(shape.first, size - max_allow, pred_allow_child()); + auto child_size = tree.child_size_if(*node, pred_allow_child()); + if (child_size < max_allow) + { + auto const size = node_pos - first_pos + child_size + 1; + 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 - shape.first = node; + shape.first = nullptr; } break; case 1: @@ -445,7 +484,7 @@ namespace nana case 3: //param is the begin pos of an item in absolute. { - int beg = static_cast(tree_container.indent_size(node) * shape.indent_pixels) - shape.offset_x; + int beg = static_cast(tree.indent_size(node) * shape.indent_pixels) - shape.offset_x; int end = beg + static_cast(node_w_pixels(node)); bool take_adjust = false; @@ -468,16 +507,14 @@ namespace nana case 4: if(shape.first != node) { - unsigned off_first = tree_container.distance_if(shape.first, pred_allow_child()); - unsigned off_node = tree_container.distance_if(node, pred_allow_child()); - if(off_node < off_first) + if (node_pos < first_pos) { shape.first = node; 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; } } @@ -535,7 +572,7 @@ namespace nana if(value == false) { //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); } @@ -543,7 +580,6 @@ namespace nana if(node->child) { 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); data.widget_ptr->events().expanded.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, value }, data.widget_ptr->handle()); data.stop_drawing = false; @@ -573,44 +609,24 @@ namespace nana { if(scroll.empty()) { - shape.prev_first_value = 0; scroll.create(*data.widget_ptr, nana::rectangle(data.graph->width() - 16, 0, 16, data.graph->height())); - auto fn = [this](const arg_mouse& arg){ - this->event_scrollbar(arg); - }; - auto & events = scroll.events(); - events.mouse_down(fn); - events.mouse_move(fn); - events.mouse_wheel(fn); + scroll.events().value_changed.connect_unignorable([this](const arg_scroll& arg) + { + adjust.scroll_timestamp = nana::system::timestamp(); + adjust.timer.start(); + + shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll.value(), pred_allow_child{}); + draw(false, false, true); + }); } scroll.amount(visual_items); scroll.range(max_allow); } - scroll.value(attr.tree_cont.distance_if(shape.first, pred_allow_child())); - } - - 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()); - } - } - } + auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{}); + scroll.value(pos); } std::size_t visual_item_size() const @@ -672,11 +688,10 @@ namespace nana attr.tree_cont.template for_each(shape.first, nl); bool redraw = false; - node_state.event_node = nl.node(); - - if(nl.node() && (nl.what() != component::end)) + auto const node = nl.node(); + if (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(); @@ -685,12 +700,11 @@ namespace nana 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()); - if (nl.node() != node_state.pointed) + if (node != node_state.pointed) close_tooltip_window(); } - - node_state.pointed = nl.node(); + node_state.pointed = node; 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()); @@ -751,11 +765,11 @@ namespace nana }; auto & events = node_state.tooltip->events(); - events.mouse_leave(fn); - events.mouse_move(fn); - events.mouse_down.connect(fn); - events.mouse_up.connect(fn); - events.dbl_click.connect(fn); + events.mouse_leave.connect_unignorable(fn); + events.mouse_move.connect_unignorable(fn); + events.mouse_down.connect_unignorable(fn); + events.mouse_up.connect_unignorable(fn); + events.dbl_click.connect_unignorable(fn); } } @@ -866,7 +880,18 @@ namespace nana item_proxy& item_proxy::check(bool ck) { 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; } @@ -879,10 +904,8 @@ namespace nana { auto * impl = trigger_->impl(); if(impl->set_expanded(node_, exp)) - { impl->draw(true); - API::update_window(impl->data.widget_ptr->handle()); - } + return *this; } @@ -895,10 +918,8 @@ namespace nana { auto * impl = trigger_->impl(); if(impl->set_selected(s ? node_ : nullptr)) - { impl->draw(true); - API::update_window(*impl->data.widget_ptr); - } + return *this; } @@ -1133,7 +1154,7 @@ namespace nana { switch(comp) { - case component_t::expender: + case component_t::expander: if(attr.has_children) { r->width = item_offset; @@ -1222,7 +1243,7 @@ namespace nana void expander(graph_reference graph, const compset_interface * compset) const override { comp_attribute_t attr; - if(compset->comp_attribute(component::expender, attr)) + if(compset->comp_attribute(component::expander, attr)) { facade arrow("solid_triangle"); arrow.direction(direction::southeast); @@ -1323,29 +1344,31 @@ namespace nana node_r.width = comp_placer->item_width(*impl_->data.graph, node_attr_); node_r.height = comp_placer->item_height(*impl_->data.graph); - if(pos_.y < item_pos_.y + static_cast(node_r.height)) + if ((pos_.y < item_pos_.y + static_cast(node_r.height)) && (pos_.y >= item_pos_.y)) { - auto logic_pos = pos_ - item_pos_; - node_ = &node; + auto const logic_pos = pos_ - item_pos_; - for(int comp = static_cast(component::begin); comp != static_cast(component::end); ++comp) + for (int comp = static_cast(component::begin); comp != static_cast(component::end); ++comp) { nana::rectangle r = node_r; - if(comp_placer->locate(static_cast(comp), node_attr_, &r)) + if (!comp_placer->locate(static_cast(comp), node_attr_, &r)) + continue; + + if (r.is_hit(logic_pos)) { - if(r.is_hit(logic_pos)) - { - what_ = static_cast(comp); - if(component::expender == what_ && (false == node_attr_.has_children)) - what_ = component::end; + node_ = &node; + what_ = static_cast(comp); + if (component::expander == what_ && (false == node_attr_.has_children)) + what_ = component::end; - if(component::text == what_) - node_text_r_ = r; + if (component::text == what_) + node_text_r_ = r; - return 0; - } + break; } } + + return 0; //Stop iterating } item_pos_.y += node_r.height; @@ -1530,7 +1553,6 @@ namespace nana } impl_->draw(false); - API::update_window(impl_->data.widget_ptr->handle()); 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&& r) { impl_->data.renderer = std::move(r); @@ -1669,14 +1671,6 @@ namespace nana 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) { node_type * p = impl_->attr.tree_cont.node(node, key); @@ -1685,49 +1679,20 @@ namespace nana else p = impl_->attr.tree_cont.insert(node, key, treebox_node_type(std::move(title))); - if(p && impl_->attr.auto_draw && impl_->draw(true)) - API::update_window(impl_->data.widget_ptr->handle()); + if (p) + impl_->draw(true); + return p; } 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))); - if(x && impl_->attr.auto_draw && impl_->draw(true)) - API::update_window(impl_->data.widget_ptr->handle()); + if (x) + impl_->draw(true); 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 { return impl_->node_state.selected; @@ -1735,29 +1700,8 @@ namespace nana void trigger::selected(node_type* node) { - if(tree().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)) - { + if(impl_->attr.tree_cont.verify(node) && impl_->set_selected(node)) 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 @@ -1780,12 +1724,12 @@ namespace nana 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; auto i = impl_->shape.image_table.find(id); - if((i != impl_->shape.image_table.end()) && impl_->draw(true)) - API::update_window(impl_->data.widget_ptr->handle()); + if (i != impl_->shape.image_table.end()) + impl_->draw(true); } } @@ -1798,7 +1742,7 @@ namespace nana 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)) { @@ -1831,7 +1775,8 @@ namespace nana 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) @@ -1842,12 +1787,21 @@ namespace nana item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); impl_->attr.tree_cont.for_each(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(); - impl_->set_expanded(impl_->node_state.event_node, !impl_->node_state.event_node->value.second.expanded); - impl_->draw(true); + case component::icon: + case component::text: + impl_->set_expanded(node, !node->value.second.expanded); + impl_->draw(true, true, false); API::dev::lazy_refresh(); + break; + default: + break; } } @@ -1862,34 +1816,20 @@ namespace nana bool has_redraw = false; 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(nl.what() != component::end) - { - 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); + if(impl_->set_expanded(node_state.pressed_node, !node_state.pressed_node->value.second.expanded)) + impl_->make_adjust(node_state.pressed_node, 0); - has_redraw = true; - } - else if(nl.item_body()) - { - if(node_state.selected != node_state.event_node) - { - impl_->set_selected(node_state.event_node); - has_redraw = true; - } - } - } - else if(node_state.selected != node_state.event_node) - { - impl_->set_selected(node_state.event_node); - has_redraw = true; - } + has_redraw = true; //btw, don't select the node + } + + if ((!has_redraw) && (node_state.selected != node_state.pressed_node)) + { + impl_->set_selected(node_state.pressed_node); + has_redraw = true; } if(has_redraw) @@ -1907,25 +1847,33 @@ namespace nana item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); impl_->attr.tree_cont.for_each(shape.first, nl); + auto const pressed_node = impl_->node_state.pressed_node; + impl_->node_state.pressed_node = nullptr; + if(!nl.node()) return; - if((impl_->node_state.selected != nl.node()) && nl.item_body()) + if (pressed_node == nl.node()) { - impl_->set_selected(nl.node()); - if(impl_->make_adjust(impl_->node_state.selected, 1)) - impl_->adjust.scroll_timestamp = 1; - } - else if (nl.what() == component::crook) - { - checkstate cs = checkstate::unchecked; - if (checkstate::unchecked == nl.node()->value.second.checked) - cs = checkstate::checked; + if ((impl_->node_state.selected != nl.node()) && nl.item_body()) + { + impl_->set_selected(nl.node()); + if (impl_->make_adjust(impl_->node_state.selected, 1)) + impl_->adjust.scroll_timestamp = 1; + } + else if (nl.what() == component::crook) + { + 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 - return; //Do not refresh + return; //Don't refresh impl_->draw(true); API::dev::lazy_refresh(); @@ -1942,18 +1890,19 @@ namespace nana void trigger::mouse_wheel(graph_reference, const arg_wheel& arg) { - auto & shape = impl_->shape; - std::size_t prev = shape.prev_first_value; + auto & scroll = impl_->shape.scroll; + 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_->draw(false); + impl_->draw(false, true, true); API::dev::lazy_refresh(); } } @@ -2168,7 +2117,7 @@ namespace nana if (comp_placer->enabled(component::crook) != enable) { comp_placer->enable(component::crook, enable); - get_drawer_trigger().draw(); + impl->draw(false); } return *this; } @@ -2181,8 +2130,8 @@ namespace nana void treebox::clear() { auto impl = get_drawer_trigger().impl(); - impl->attr.tree_cont.clear(); - get_drawer_trigger().draw(); + if (impl->unlink(impl->attr.tree_cont.get_root(), true)) + impl->draw(true); } 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 * 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) @@ -2214,20 +2163,21 @@ namespace nana treebox::item_proxy treebox::erase(item_proxy i) { 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; } void treebox::erase(const std::string& keypath) { auto i = find(keypath); - if(!i.empty()) - get_drawer_trigger().remove(i._m_node()); + if (!i.empty()) + this->erase(i); } 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(); if(tree.verify(pnode)) { diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index acc96273..37e4c08d 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -118,6 +118,7 @@ namespace nana{ namespace system{ static_cast(g); //eliminate unused parameter compiler warning. static_cast(owner); throw std::logic_error("dataexch::set(const paint::graphics&, native_window_type owner) not implemented yet."); + return false; #endif } @@ -183,6 +184,14 @@ namespace nana{ namespace system{ #endif } } + + std::wstring dataexch::wget() + { + std::wstring str; + this->get(str); + return str; + } + //private: bool dataexch::_m_set(format fmt, const void* buf, std::size_t size, native_window_type owner) {