From 5653bd2416bae7fe009c76de05859abdd4bed37a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 13 Dec 2017 06:28:12 +0800 Subject: [PATCH 01/27] fix crash where listbox::item_proxy==str --- source/gui/widgets/listbox.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index e473a080..54611aa1 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -4662,12 +4662,12 @@ namespace nana bool item_proxy::operator==(const std::string& s) const { - return (text(pos_.item) == s); + return (text(0) == s); } bool item_proxy::operator==(const std::wstring& s) const { - return (text(pos_.item) == to_utf8(s)); + return (text(0) == to_utf8(s)); } item_proxy & item_proxy::operator=(const item_proxy& rhs) From 58b7bdf2f7a3654062a07eaa69085cdab385785a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 3 Jan 2018 07:32:21 +0800 Subject: [PATCH 02/27] fix a stackoverflow error --- source/gui/detail/window_layout.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 27357217..4add7b03 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -1,7 +1,7 @@ /* * Window Layout Implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -386,6 +386,13 @@ namespace nana nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension); for (auto wd : data_sect.effects_bground_windows) { + //Don't notify the window if both native root windows are not same(e.g. wd and sigwd have + //a some parent). Otherwise, _m_paint_glass_window() recursively paints sigwd to make stack overflow. + //On the other hand, a nested root window is always floating on its parent's child widgets, it's unnecessary to + //notify the wd if they haven't a same native root window. + if (sigwd->root != wd->root) + continue; + if (wd == sigwd || !wd->displayed() || (false == overlapped(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd))) continue; From 970872c96f92e0891625ff9463bd5ef40c7a7e3a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 7 Jan 2018 04:18:23 +0800 Subject: [PATCH 03/27] fix bug that integer overflow in progress widget --- source/gui/widgets/progress.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp index 2c498f7c..8a679c4c 100644 --- a/source/gui/widgets/progress.cpp +++ b/source/gui/widgets/progress.cpp @@ -1,6 +1,6 @@ /* * A Progress Indicator Implementation - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -96,7 +96,11 @@ namespace nana { if (widget_) { - auto value_px = (widget_->size().width - border_px * 2) * value_ / max_; + auto value_px = (widget_->size().width - border_px * 2); + + //avoid overflow + if (value_ < max_) + value_px = static_cast(value_px * (double(value_) / double(max_))); if (value_px != value_px_) { From 48be0b4b07fbdeb9a6b43c8bdf0066e8fdf3db55 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 13 Jan 2018 10:49:37 +0800 Subject: [PATCH 04/27] improve visualization of group caption --- include/nana/gui/programming_interface.hpp | 2 ++ source/gui/programming_interface.cpp | 9 +++++++++ source/gui/widgets/group.cpp | 23 +++++++++++++++++++--- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 8c0d85fe..814a98b7 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -301,6 +301,8 @@ namespace API void window_size(window, const size&); size window_outline_size(window); void window_outline_size(window, const size&); + + nana::optional window_rectangle(window); bool get_window_rectangle(window, rectangle&); bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window. void window_enabled(window, bool); diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 22e22cac..626803d3 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -821,6 +821,15 @@ namespace API } } + nana::optional window_rectangle(window wd) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (restrict::wd_manager().available(iwd)) + return rectangle(iwd->pos_owner, iwd->dimension); + return{}; + } + bool get_window_rectangle(window wd, rectangle& r) { auto iwd = reinterpret_cast(wd); diff --git a/source/gui/widgets/group.cpp b/source/gui/widgets/group.cpp index ab8e9e73..74d76575 100644 --- a/source/gui/widgets/group.cpp +++ b/source/gui/widgets/group.cpp @@ -208,8 +208,8 @@ namespace nana{ outter[field_title] << impl_->caption; outter.collocate(); + impl_->caption.transparent(true); color pbg = API::bgcolor(this->parent()); - impl_->caption.bgcolor(pbg.blend(colors::black, 0.025)); this->bgcolor(pbg.blend(colors::black, 0.05)); @@ -222,10 +222,27 @@ namespace nana{ auto gap_px = impl_->gap - 1; graph.rectangle(true, API::bgcolor(this->parent())); - graph.round_rectangle(rectangle(point(gap_px, impl_->caption_dimension.height / 2), - nana::size(graph.width() - 2 * gap_px, graph.height() - impl_->caption_dimension.height / 2 - gap_px) + + auto const top_round_line = static_cast(impl_->caption_dimension.height) / 2; + + graph.round_rectangle(rectangle(point(gap_px, top_round_line), + nana::size(graph.width() - 2 * gap_px, graph.height() - top_round_line - gap_px) ), 3, 3, colors::gray_border, true, this->bgcolor()); + + auto opt_r = API::window_rectangle(impl_->caption); + if (opt_r) + { + rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width, static_cast(top_round_line - opt_r->y) } }; + + grad_r.y += top_round_line / 2; + grad_r.x -= 2; + grad_r.width += 4; + + graph.gradual_rectangle(grad_r, + API::bgcolor(this->parent()), this->bgcolor(), true + ); + } }); } From c80b4ce484006db44d5b176e931b9e5c5d73ba26 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 13 Jan 2018 13:07:40 +0800 Subject: [PATCH 05/27] improve visualization of group caption --- source/gui/widgets/group.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/group.cpp b/source/gui/widgets/group.cpp index 74d76575..87d2ebc6 100644 --- a/source/gui/widgets/group.cpp +++ b/source/gui/widgets/group.cpp @@ -235,7 +235,7 @@ namespace nana{ { rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width, static_cast(top_round_line - opt_r->y) } }; - grad_r.y += top_round_line / 2; + grad_r.y += top_round_line*2 / 3; grad_r.x -= 2; grad_r.width += 4; From 08077a98454367a72378557007eecd18ef94e5db Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 13 Jan 2018 13:08:43 +0800 Subject: [PATCH 06/27] fix bug that wrong listbox selection after sorting --- include/nana/gui/widgets/listbox.hpp | 2 +- source/gui/widgets/listbox.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 71280b7e..d57ee4c6 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1,7 +1,7 @@ /** * A List Box Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 54611aa1..b21cf392 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1,7 +1,7 @@ /* * A List Box Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -1586,7 +1586,7 @@ namespace nana return pairs; } - bool select_for_all(bool sel, const index_pair& except = index_pair{npos, npos}) + bool select_for_all(bool sel, const index_pair& except_abs = index_pair{npos, npos}) { bool changed = false; index_pair pos; @@ -1595,7 +1595,7 @@ namespace nana pos.item = 0; for(auto & m : cat.items) { - if (except != pos) + if (except_abs != pos) { if (m.flags.selected != sel) { @@ -4150,12 +4150,12 @@ namespace nana //Unselects all selected items if the current item is not selected before selecting. auto selected = lister.pick_items(true); if (selected.cend() == std::find(selected.cbegin(), selected.cend(), item_pos)) - lister.select_for_all(false, item_pos); + lister.select_for_all(false, abs_item_pos); } else { //Unselects all selected items except current item if right button clicked. - lister.select_for_all(false, item_pos); //cancel all selections + lister.select_for_all(false, abs_item_pos); //cancel all selections } } } From 710880372bc4d1e139572f5d923581c2c9340a60 Mon Sep 17 00:00:00 2001 From: 5cript Date: Sun, 14 Jan 2018 07:52:56 +0100 Subject: [PATCH 07/27] Added missing std::move, withing tabbar insert overload for std::string. --- include/nana/gui/widgets/tabbar.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/nana/gui/widgets/tabbar.hpp b/include/nana/gui/widgets/tabbar.hpp index 0e2e2e9c..56fc213d 100644 --- a/include/nana/gui/widgets/tabbar.hpp +++ b/include/nana/gui/widgets/tabbar.hpp @@ -277,7 +277,7 @@ namespace nana this->get_drawer_trigger().insert(::nana::npos, to_nstring(std::move(text)), std::move(value)); if (attach_wd) this->attach(this->get_drawer_trigger().length() - 1, attach_wd); - + API::update_window(*this); return *this; } @@ -293,7 +293,7 @@ namespace nana if (pos > length()) throw std::out_of_range("tabbar::insert invalid position"); - this->get_drawer_trigger().insert(pos, to_nstring(text), std::move(value)); + this->get_drawer_trigger().insert(pos, to_nstring(std::move(text)), std::move(value)); API::update_window(*this); } @@ -306,7 +306,7 @@ namespace nana API::update_window(*this); } - /// Attach a window to a specified tab. When the tab is activated, tabbar shows the attached window. + /// Attach a window to a specified tab. When the tab is activated, tabbar shows the attached window. /** * @param pos The position of tab to set the attached window. * @param attach_wd A handle to the window to be set. @@ -364,7 +364,7 @@ namespace nana namespace nana -{ +{ namespace drawerbase { namespace tabbar_lite From 0196d2583a3e49c61c968708a9529f98f52e458e Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 18 Jan 2018 00:18:01 +0800 Subject: [PATCH 08/27] mutable variable members of arg_tabbar_removed --- include/nana/gui/widgets/tabbar.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/nana/gui/widgets/tabbar.hpp b/include/nana/gui/widgets/tabbar.hpp index 0e2e2e9c..a9cc70cb 100644 --- a/include/nana/gui/widgets/tabbar.hpp +++ b/include/nana/gui/widgets/tabbar.hpp @@ -1,7 +1,7 @@ /** * A Tabbar implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -42,9 +42,8 @@ namespace nana : arg_tabbar({wdg, v}) {} - bool remove = true; ///< determines whether to remove the item - bool close_attach_window = true; ///< determines whether to close the attached window. It is ignored if remove is false - + mutable bool remove = true; ///< determines whether to remove the item + mutable bool close_attach_window = true; ///< determines whether to close the attached window. It is ignored if remove is false }; namespace drawerbase From 2a262236288c15410382744122bac2e179970f6d Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 22 Jan 2018 06:29:40 +0800 Subject: [PATCH 09/27] small fix for constructor of scroll --- include/nana/gui/widgets/scroll.hpp | 2 +- include/nana/gui/widgets/tabbar.hpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index c4e39981..0603c308 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -398,7 +398,7 @@ namespace nana /// \brief The construct that creates a widget. /// @param wd A handle to the parent window of the widget being created. /// @param visible specify the visibility after creation. - scroll(window wd, bool visible) + scroll(window wd, bool visible = true) { this->create(wd, rectangle(), visible); // add a widget scheme? and take some colors from these wd? } diff --git a/include/nana/gui/widgets/tabbar.hpp b/include/nana/gui/widgets/tabbar.hpp index e0d56f1a..a24cce4a 100644 --- a/include/nana/gui/widgets/tabbar.hpp +++ b/include/nana/gui/widgets/tabbar.hpp @@ -276,7 +276,7 @@ namespace nana this->get_drawer_trigger().insert(::nana::npos, to_nstring(std::move(text)), std::move(value)); if (attach_wd) this->attach(this->get_drawer_trigger().length() - 1, attach_wd); - + API::update_window(*this); return *this; } @@ -305,7 +305,7 @@ namespace nana API::update_window(*this); } - /// Attach a window to a specified tab. When the tab is activated, tabbar shows the attached window. + /// Attach a window to a specified tab. When the tab is activated, tabbar shows the attached window. /** * @param pos The position of tab to set the attached window. * @param attach_wd A handle to the window to be set. @@ -363,7 +363,7 @@ namespace nana namespace nana -{ +{ namespace drawerbase { namespace tabbar_lite From 69616bae40738481d6802286012c28872dc65dfb Mon Sep 17 00:00:00 2001 From: buck-yeh Date: Wed, 24 Jan 2018 15:12:36 +0800 Subject: [PATCH 10/27] Make more Linux distros happy Specifically, Fefora 27 will complain about missing , so will Solus. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cdeb93d..c66f18a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,7 +131,7 @@ endif(APPLE) if(UNIX) list(APPEND NANA_LINKS -lX11) - find_package(Freetype) + include(FindFreetype) if (FREETYPE_FOUND) include_directories( ${FREETYPE_INCLUDE_DIRS}) list(APPEND NANA_LINKS -lXft) From e1c5fcdb0ab8ff6dcc80bc5d63e5e9b74a3391fa Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 28 Jan 2018 11:21:45 +0800 Subject: [PATCH 11/27] enhance performance of setting model for a listbox --- source/gui/widgets/listbox.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index b21cf392..a0c2db52 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -5158,7 +5158,8 @@ namespace nana cat_->make_sort_order(); ess_->lister.sort(); - ess_->update(true); + //Don't ignore the auto-draw flag for performance enhancement. + ess_->update(); } } //end class cat_proxy From 2574f4fffa5d3e097f303816e641089633cdfbfb Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 28 Jan 2018 11:23:05 +0800 Subject: [PATCH 12/27] remove a compiler warning --- source/paint/detail/image_jpeg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/paint/detail/image_jpeg.hpp b/source/paint/detail/image_jpeg.hpp index 1f19373b..d63a2c1d 100644 --- a/source/paint/detail/image_jpeg.hpp +++ b/source/paint/detail/image_jpeg.hpp @@ -91,7 +91,7 @@ namespace nana { ::jpeg_create_decompress(&jdstru); - ::jpeg_mem_src(&jdstru, const_cast(reinterpret_cast(data)), bytes); + ::jpeg_mem_src(&jdstru, const_cast(reinterpret_cast(data)), static_cast(bytes)); _m_read_jpg(jdstru); jpeg_finish_decompress(&jdstru); From 9bd3dc7e582f260283da42fb68b988f33e229995 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 28 Jan 2018 13:57:07 +0800 Subject: [PATCH 13/27] fix bug that nested_form draws incompletely --- source/gui/detail/window_layout.cpp | 49 +++++++++++++++-------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 4add7b03..45764b81 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -106,43 +106,46 @@ namespace nana visual = rectangle{ wd->pos_root, wd->dimension }; - if (wd->root_widget != wd) + if (category::flags::root != wd->other.category) { //Test if the root widget is overlapped the specified widget //the pos of root widget is (0, 0) if (overlapped(visual, rectangle{ wd->root_widget->pos_owner, wd->root_widget->dimension }) == false) return false; - } - for (auto parent = wd->parent; parent; parent = parent->parent) - { - if (category::flags::root == parent->other.category) + for (auto parent = wd->parent; parent; parent = parent->parent) { - //visual rectangle of wd's parent - rectangle vrt_parent{parent->pos_root, parent->dimension}; - - point pos_root; - while (parent->parent) + if (category::flags::root == parent->other.category) { - pos_root -= native_interface::window_position(parent->root); - - if (!overlap(rectangle{ pos_root, parent->parent->root_widget->dimension }, vrt_parent, vrt_parent)) - return false; - - parent = parent->parent->root_widget; + wd = parent; + break; } - if (!overlap(vrt_parent, visual, visual)) + if (!overlap(rectangle{ parent->pos_root, parent->dimension }, visual, visual)) return false; - - return true; } - - if (!overlap(rectangle{ parent->pos_root, parent->dimension }, visual, visual)) - return false; } - return true; + //Now, wd actually is the root widget of original parameter wd + if (nullptr == wd->parent) + return true; + + auto parent_rw = wd->parent->root_widget; + //visual rectangle of wd's parent + rectangle vrt_parent{ parent_rw->pos_root, parent_rw->dimension }; + + point pos_root; + while (parent_rw->parent) + { + pos_root -= native_interface::window_position(parent_rw->root); + + if (!overlap(rectangle{ pos_root, parent_rw->parent->root_widget->dimension }, vrt_parent, vrt_parent)) + return false; + + parent_rw = parent_rw->parent->root_widget; + } + + return overlap(vrt_parent, visual, visual); } //read_overlaps From caa61aba04114c69034d72d516eb9bb9c4754e1b Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Mon, 29 Jan 2018 01:35:09 +0100 Subject: [PATCH 14/27] Fix travis test/demos with gcc 4.9 and boost 1.54 --- include/nana/filesystem/filesystem.hpp | 31 ++++++++++++++++++++++ include/nana/filesystem/filesystem_ext.hpp | 11 ++++++++ 2 files changed, 42 insertions(+) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 067586f5..b6c358b7 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -55,6 +55,37 @@ #define NANA_USING_BOOST_FILESYSTEM 1 # include # include +// dont include generic_u8string +// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp +// enable directory_iterator C++11 range-base for +// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp +// but travis come with an oooold version of boost +// NOT enable directory_iterator C++11 range-base for +// http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp +namespace boost +{ + namespace filesystem + { + + // enable directory_iterator C++11 range-base for statement use --------------------// + + // begin() and end() are only used by a range-based for statement in the context of + // auto - thus the top-level const is stripped - so returning const is harmless and + // emphasizes begin() is just a pass through. + inline + const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT + { + return iter; + } + inline + directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT + { + return directory_iterator(); + } + + } // namespace filesystem +} + // add boost::filesystem into std::experimental::filesystem namespace std { diff --git a/include/nana/filesystem/filesystem_ext.hpp b/include/nana/filesystem/filesystem_ext.hpp index 2c28acad..3458a198 100644 --- a/include/nana/filesystem/filesystem_ext.hpp +++ b/include/nana/filesystem/filesystem_ext.hpp @@ -16,6 +16,7 @@ #define NANA_FILESYSTEM_EXT_HPP #include +#include namespace nana { @@ -34,6 +35,16 @@ namespace filesystem_ext std::experimental::filesystem::path path_user(); ///< extention ? + /// workaround Boost not having path.generic_u8string() - a good point for http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0251r0.pdf +inline std::string generic_u8string(const std::experimental::filesystem::path& p) +{ +#if NANA_USING_BOOST_FILESYSTEM + return nana::to_utf8(p.generic_wstring()); +#else + return p.generic_u8string(); +#endif +} + inline bool is_directory(const std::experimental::filesystem::directory_entry& dir) noexcept { return is_directory(dir.status()); From 3f7dd3fe3e4ebd99d79e3c5028051108412147b2 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 3 Feb 2018 06:28:25 +0800 Subject: [PATCH 15/27] fix bug of scroll.make_page_scroll --- include/nana/gui/widgets/scroll.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index 0603c308..f06ef8e0 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -1,7 +1,7 @@ /** * A Scroll Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -147,7 +147,7 @@ namespace nana void step(size_type s) { - metrics_.step = s; + metrics_.step = (s ? s : 1); } bool make_step(bool forward, unsigned multiple) @@ -501,7 +501,8 @@ namespace nana /// @return true if the vlaue is changed. bool make_page_scroll(bool forward) { - return this->make_step(forward, static_cast(range() - 1)); + auto const count = range() / step(); + return this->make_step(forward, (count > 2 ? count - 1 : 1)); } };//end class scroll }//end namespace nana From f21bbd5deb23d858d8242605243840a298c0db50 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 3 Feb 2018 06:40:10 +0800 Subject: [PATCH 16/27] fix bug that listbox incorrectly performs scroll_down/up --- source/gui/widgets/listbox.cpp | 91 +++++++++++++++++++++++++--------- source/gui/widgets/scroll.cpp | 14 ++++-- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index a0c2db52..398ca3b9 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1273,6 +1273,7 @@ namespace nana } //Backward + n = -n; dpos = pos; if (good(dpos.cat)) { @@ -1618,7 +1619,7 @@ namespace nana } /// return absolute positions, no relative to display - index_pairs pick_items(bool for_selection) const + index_pairs pick_items(bool for_selection, bool find_first = false) const { index_pairs results; index_pair id; @@ -1629,7 +1630,11 @@ namespace nana for (auto & m : cat.items) { if (for_selection ? m.flags.selected : m.flags.checked) + { results.push_back(id); // absolute positions, no relative to display + if (find_first) + return results; + } ++id.item; } ++id.cat; @@ -4336,8 +4341,9 @@ namespace nana void trigger::key_press(graph_reference graph, const arg_keyboard& arg) { + auto & list = essence_->lister; // Exit if list is empty - if (essence_->lister.first().empty()) + if (list.first().empty()) return; bool upward = false; @@ -4347,12 +4353,12 @@ namespace nana case keyboard::os_arrow_up: upward = true; case keyboard::os_arrow_down: - essence_->lister.move_select(upward, !arg.shift, true); + list.move_select(upward, !arg.shift, true); break; case L' ': { index_pairs s; - bool ck = ! essence_->lister.item_selected_all_checked(s); + bool ck = ! list.item_selected_all_checked(s); for(auto i : s) item_proxy(essence_, i).check(ck); } @@ -4361,30 +4367,69 @@ namespace nana upward = true; case keyboard::os_pagedown: { - //Turns page, then returns if no change occurs - if (!essence_->content_view->turn_page(!upward, false)) - return; + auto const item_px = essence_->item_height(); + auto picked_items = list.pick_items(true, true); + index_pair init_idx = (picked_items.empty() ? list.first() : picked_items[0]); essence_->lister.select_for_all(false); - auto idx = essence_->first_display(); + //Get the pixels between the init item and top edge or bottom edge + auto logic_top = static_cast(list.distance(list.first(), init_idx) * item_px); - if (!upward) - idx = essence_->lister.advance(idx, static_cast(essence_->count_of_exposed(false)) - 1); + auto const screen_top = essence_->content_view->origin().y; + auto const screen_bottom = screen_top + essence_->content_view->view_area().height; + index_pair target_idx; - if (!idx.is_category()) - item_proxy::from_display(essence_, idx).select(true); - else if (!essence_->lister.single_status(true)) //not selected - essence_->lister.cat_status(idx.cat, true, true); + //Check if it scrolls in current screen window + //condition: top of target item is not less than top edge of content view and + //the bottom of target item is not greater than bottom edge of content view. + if ((screen_top + item_px <= logic_top) && (logic_top + item_px + item_px <= screen_bottom)) + { + int offset = (static_cast(upward ? screen_top : screen_bottom - item_px) - logic_top) / static_cast(item_px); + target_idx = list.advance(init_idx, offset); + } + else + { + //turn page + auto page_item_count = (std::max)(1, static_cast(essence_->count_of_exposed(false))); - break; + auto origin = essence_->content_view->origin(); + if (upward) + { + target_idx = list.advance(init_idx, -page_item_count); + if (target_idx.empty()) + target_idx = list.first(); + + origin.y = list.distance(list.first(), target_idx) * item_px; + } + else + { + target_idx = list.advance(init_idx, page_item_count); + if (target_idx.empty()) + target_idx = list.last(); + + origin.y = list.distance(list.first(), target_idx) * item_px + item_px; + if (origin.y >= (screen_bottom - screen_top)) + origin.y -= (screen_bottom - screen_top); + else + origin.y = 0; + } + + essence_->content_view->move_origin(origin - essence_->content_view->origin()); + } + + if (!target_idx.is_category()) + item_proxy::from_display(essence_, target_idx).select(true); + else if (!list.single_status(true)) //not selected + list.cat_status(target_idx.cat, true, true); } + break; case keyboard::os_home: case keyboard::os_end: { - essence_->lister.select_for_all(false); + list.select_for_all(false); - auto pos = (keyboard::os_home == arg.key ? essence_->lister.first() : essence_->lister.last()); + auto pos = (keyboard::os_home == arg.key ? list.first() : list.last()); if (!pos.empty()) { //When the pos indicates an empty category, then search forwards/backwards(depending on arg.key whether it is Home or End) for a non empty category. @@ -4393,9 +4438,9 @@ namespace nana { if (keyboard::os_home == arg.key) { - while (0 == essence_->lister.size_item(pos.cat)) + while (0 == list.size_item(pos.cat)) { - if (++pos.cat >= essence_->lister.cat_container().size()) + if (++pos.cat >= list.cat_container().size()) { pos = index_pair{ npos, npos }; break; @@ -4404,7 +4449,7 @@ namespace nana } else { - while (0 == essence_->lister.size_item(pos.cat)) + while (0 == list.size_item(pos.cat)) { if (pos.cat-- == 0) { @@ -4416,7 +4461,7 @@ namespace nana if (!pos.empty()) { - if (essence_->lister.expand(pos.cat)) + if (list.expand(pos.cat)) pos.item = 0; } } @@ -4425,8 +4470,8 @@ namespace nana { if (pos.is_category()) { - if (!essence_->lister.single_status(true)) //multiple selection is not enabled - essence_->lister.cat_status(pos.cat, true, true); + if (!list.single_status(true)) //multiple selection is not enabled + list.cat_status(pos.cat, true, true); } else item_proxy::from_display(essence_, pos).select(true); diff --git a/source/gui/widgets/scroll.cpp b/source/gui/widgets/scroll.cpp index b59e4721..acc2c8b6 100644 --- a/source/gui/widgets/scroll.cpp +++ b/source/gui/widgets/scroll.cpp @@ -1,7 +1,7 @@ /* * A Scroll Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -20,9 +20,15 @@ namespace nana namespace scroll { //struct metrics_type - metrics_type::metrics_type() - :peak(1), range(1), step(1), value(0), - what(buttons::none), pressed(false), scroll_length(0), scroll_pos(0) + metrics_type::metrics_type(): + peak(1), + range(1), + step(1), + value(0), + what(buttons::none), + pressed(false), + scroll_length(0), + scroll_pos(0) {} //end struct metrics_type From 63e64d4bebf51d1c689241635ab59341110007da Mon Sep 17 00:00:00 2001 From: dnso86 Date: Wed, 31 Jan 2018 09:24:11 +0100 Subject: [PATCH 17/27] Checking whether MinGW really supports threads --- include/nana/c++defines.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/nana/c++defines.hpp b/include/nana/c++defines.hpp index 04b5113f..99414127 100644 --- a/include/nana/c++defines.hpp +++ b/include/nana/c++defines.hpp @@ -171,9 +171,9 @@ #endif #endif -//Assume the std::thread is not implement on MinGW +//Assume the std::thread is not implemented on MinGW, +//unless it was compiled with POSIX threading support. //But some toolchains may implement std::thread. -// it seems that MinGW 6.3 and 7.1 have std::thread #ifdef NANA_MINGW # ifndef STD_THREAD_NOT_SUPPORTED # define STD_THREAD_NOT_SUPPORTED @@ -221,8 +221,11 @@ # if __has_include() # undef STD_FILESYSTEM_NOT_SUPPORTED # endif -# if __has_include() -# undef STD_THREAD_NOT_SUPPORTED +# if __has_include() +# if !(defined(NANA_MINGW) && !defined(_GLIBCXX_HAS_GTHREADS)) +//See the comment above regarding MinGW's threading support +# undef STD_THREAD_NOT_SUPPORTED +# endif # endif #endif From 0d6e9e042b1b31ede5a4819e1e26b6d7465d4e84 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 4 Feb 2018 10:46:29 +0800 Subject: [PATCH 18/27] fix bug that listbox select behaves unexpectedly it select last item of a category in single selection mode if category is clicked --- source/gui/widgets/listbox.cpp | 39 ++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 398ca3b9..ea38d98b 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1520,8 +1520,6 @@ namespace nana template std::vector> select_display_range_if(const index_pair& fr_abs, index_pair to_dpl, bool deselect_others, Pred pred) { - const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{}); - if (to_dpl.empty()) { if (fr_abs.empty()) @@ -1534,6 +1532,11 @@ namespace nana if (fr_dpl > to_dpl) std::swap(fr_dpl, to_dpl); + if (to_dpl.is_category() && this->size_item(to_dpl.cat) > 0) + to_dpl.item = this->size_item(to_dpl.cat) - 1; + + const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{}); + const auto begin = fr_dpl; const auto last = to_dpl; @@ -1983,6 +1986,15 @@ namespace nana }; } + bool cs_status(index_pair abs_pos, bool for_selection) const + { + if (abs_pos.is_category()) + return lister.cat_status(abs_pos.cat, for_selection); + + auto & flags = lister.get(abs_pos.cat)->items.at(abs_pos.item).flags; + return (for_selection ? flags.selected : flags.checked); + } + void resize_disp_area() { auto head_px = this->header_visible_px(); @@ -4122,17 +4134,16 @@ namespace nana essence_->content_view->sync(false); } - bool sel = true; + bool new_selected_status = true; - //no single selected - if (!lister.single_status(true)) + if (!lister.single_status(true)) //multiply selection enabled { if (arg.shift) { //Set the first item as the begin of selected item if there //is not a latest selected item.(#154 reported by RenaudAlpes) - if (lister.latest_selected_abs.empty() || lister.latest_selected_abs.is_category()) - lister.latest_selected_abs.set_both(0); + if (lister.latest_selected_abs.empty()) + lister.latest_selected_abs = lister.first(); auto before = lister.latest_selected_abs; @@ -4146,7 +4157,7 @@ namespace nana else if (arg.ctrl) { essence_->mouse_selection.reverse_selection = true; - sel = !item_proxy(essence_, abs_item_pos).selected(); + new_selected_status = !essence_->cs_status(abs_item_pos, true); } else { @@ -4169,14 +4180,14 @@ namespace nana //Clicking on a category is ignored when single selection is enabled. //Fixed by Greentwip(issue #121) if (item_ptr) - sel = !item_proxy(essence_, abs_item_pos).selected(); + new_selected_status = !item_proxy(essence_, abs_item_pos).selected(); } if(item_ptr) { - if (item_ptr->flags.selected != sel) + if (item_ptr->flags.selected != new_selected_status) { - if (sel) + if (new_selected_status) { //Deselects the previously selected item. lister.cancel_others_if_single_enabled(true, abs_item_pos); @@ -4185,13 +4196,15 @@ namespace nana else if (essence_->lister.latest_selected_abs == abs_item_pos) essence_->lister.latest_selected_abs.set_both(npos); - item_ptr->flags.selected = sel; + item_ptr->flags.selected = new_selected_status; lister.emit_cs(abs_item_pos, true); } } else { - lister.cat_status(item_pos.cat, true, true); + //A category was clicked. Sets all child items to be selected only if multiply selection is enabled. + if(!lister.single_status(true)) + lister.cat_status(item_pos.cat, true, true); } } else From 3ff4fbb596b592e73d883b5f61bd42fa517e4f96 Mon Sep 17 00:00:00 2001 From: dnso86 <7543050+dnso86@users.noreply.github.com> Date: Wed, 7 Feb 2018 12:17:31 +0100 Subject: [PATCH 19/27] Fixing typo in button.cpp comment --- source/gui/widgets/button.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index a01d001b..fe6f19c7 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -379,7 +379,7 @@ namespace nana{ namespace drawerbase }//end namespace drawerbase //button - //@brief: Defaine a button widget and it provides the interfaces to be operational + //@brief: Define a button widget and it provides the interfaces to be operational button::button(){} button::button(window wd, bool visible) From 176d9e5dd920da510302bdf72b15f1cf2e53e3ab Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 10 Feb 2018 07:28:54 +0800 Subject: [PATCH 20/27] fix bug that inline widgets aren't closed when lsitbox clears --- source/gui/widgets/listbox.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index ea38d98b..c2d75048 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3433,6 +3433,8 @@ namespace nana rect.y - static_cast(origin.y % item_height_px) }; + essence_->inline_buffered_table.swap(essence_->inline_table); + // The first display is empty when the listbox is empty. if (!first_disp.empty()) { @@ -3455,8 +3457,6 @@ namespace nana auto idx = first_disp; - essence_->inline_buffered_table.swap(essence_->inline_table); - for (auto & cat : lister.cat_container()) for (auto & ind : cat.indicators) { @@ -3526,10 +3526,10 @@ namespace nana ++idx.item; } } - - essence_->inline_buffered_table.clear(); } + essence_->inline_buffered_table.clear(); + if (item_coord.y < rect.bottom()) { rectangle bground_r{ rect.x, item_coord.y, rect.width, static_cast(rect.bottom() - item_coord.y) }; From b00ab1df0fcb47de080edeeea55f1fd3b6d65a9e Mon Sep 17 00:00:00 2001 From: besh81 Date: Mon, 12 Feb 2018 14:48:03 +0100 Subject: [PATCH 21/27] fix filebox.init_file() Fix filebox.init_file() --- source/gui/filebox.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index b31653cc..ff58039d 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -1041,7 +1041,8 @@ namespace nana bool filebox::show() const { #if defined(NANA_WINDOWS) - std::wstring wfile; + auto winitfile = to_wstring(impl_->file); + std::wstring wfile(winitfile); wfile.resize(520); OPENFILENAME ofn; From c8c68c7a6986d79deca09db9bf071caa1e33ae14 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 15 Feb 2018 01:53:11 +0800 Subject: [PATCH 22/27] fix bug that edge nimbus is rendered for disabled widgets --- include/nana/gui/detail/effects_renderer.hpp | 29 ++++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp index 3727933a..3a980caa 100644 --- a/include/nana/gui/detail/effects_renderer.hpp +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -1,3 +1,15 @@ +/* +* Effects Renderer +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/effects_renderer.cpp +*/ + #ifndef NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP #define NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP #include @@ -76,7 +88,7 @@ namespace nana{ nana::rectangle r; for(auto & action : nimbus) { - if(_m_edge_nimbus(focused, action.window) && window_layer::read_visual_rectangle(action.window, r)) + if(_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r)) { if (action.window == wd) { @@ -140,12 +152,17 @@ namespace nana{ } } private: - static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd) + /// Determines whether the effect will be rendered for the given window. + static bool _m_edge_nimbus(core_window_t * const wd, core_window_t * const focused_wd) { - if((focused_wd == wd) && (static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::active))) - return true; - else if((static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered)) - return true; + // Don't render the effect if the window is disabled. + if (wd->flags.enabled) + { + if ((focused_wd == wd) && (static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::active))) + return true; + else if ((static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered)) + return true; + } return false; } From f6548acc842861faa9f7e66ca96614f325928690 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 22 Feb 2018 07:59:27 +0800 Subject: [PATCH 23/27] add keyboard accelerator --- include/nana/gui/basis.hpp | 11 ++- include/nana/gui/detail/bedrock.hpp | 8 +- include/nana/gui/widgets/form.hpp | 4 +- source/gui/detail/bedrock_posix.cpp | 9 +- source/gui/detail/bedrock_windows.cpp | 98 ++++++++++++++++++- .../gui/detail/inner_fwd_implement.hpp | 15 ++- source/gui/detail/window_manager.cpp | 13 ++- source/gui/widgets/form.cpp | 8 +- 8 files changed, 150 insertions(+), 16 deletions(-) rename {include/nana => source}/gui/detail/inner_fwd_implement.hpp (86%) diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index 2cc656ca..cc31f862 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -4,7 +4,7 @@ * * Basis Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -30,6 +30,15 @@ namespace nana struct native_drawable_impl{}; } + struct accel_key + { + char key; + bool case_sensitive{ false }; + bool alt{ false }; + bool ctrl{ false }; + bool shift{ false }; + }; + enum class checkstate { unchecked, checked, partial diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 0db691b3..f0d3f63c 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -1,7 +1,7 @@ /** * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -27,6 +27,7 @@ namespace detail struct basic_window; class window_manager; + struct window_platform_assoc; /// @brief fundamental core component, it provides an abstraction to the OS platform and some basic functions. class bedrock @@ -73,6 +74,11 @@ namespace detail //Closes the windows which are associated with the specified thread. If the given thread_id is 0, it closes all windows void close_thread_window(unsigned thread_id); + + public: + //Platform-dependent functions + static void delete_platform_assoc(window_platform_assoc*); + void keyboard_accelerator(native_window_type, const accel_key&, const std::function&); public: void event_expose(core_window_t *, bool exposed); void event_move(core_window_t*, int x, int y); diff --git a/include/nana/gui/widgets/form.hpp b/include/nana/gui/widgets/form.hpp index 77972a8b..6053a1d7 100644 --- a/include/nana/gui/widgets/form.hpp +++ b/include/nana/gui/widgets/form.hpp @@ -1,7 +1,7 @@ /** * A Form Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -68,6 +68,8 @@ namespace nana void modality() const; void wait_for_this(); + + void keyboard_accelerator(const accel_key&, const std::function& fn); }; class nested_form diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 5f4fa1fa..3e38d5ea 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -1,7 +1,7 @@ /* * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -15,10 +15,10 @@ #include #include #include -#include #include #include #include +#include "inner_fwd_implement.hpp" #include #include @@ -222,6 +222,11 @@ namespace detail arg.shift = (xkey.state & ShiftMask); } + void bedrock::keyboard_accelerator(native_window_type, const accel_key&, const std::function& fn) + { + + } + element_store& bedrock::get_element_store() const { return impl_->estore; diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 2d75e7d4..9618c47e 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-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -20,11 +20,11 @@ #include #include #include -#include #include #include #include #include +#include "inner_fwd_implement.hpp" #include //use std::cerr @@ -182,6 +182,12 @@ namespace detail }cache; }; + struct window_platform_assoc + { + HACCEL accel{ nullptr }; ///< A handle to a Windows keyboard accelerator object. + std::map> accel_commands; + }; + //class bedrock defines a static object itself to implement a static singleton //here is the definition of this object bedrock bedrock::bedrock_object; @@ -345,6 +351,20 @@ namespace detail } } + void process_msg(bedrock* brock, MSG& msg) + { + auto misc = brock->wd_manager().root_runtime(reinterpret_cast(msg.hwnd)); + + if (misc && misc->wpassoc->accel && ::TranslateAccelerator(msg.hwnd, misc->wpassoc->accel, &msg)) + return; + + auto menu_wd = brock->get_menu(reinterpret_cast(msg.hwnd), true); + if (menu_wd) interior_helper_for_menu(msg, menu_wd); + + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + void bedrock::pump_event(window condition_wd, bool is_modal) { const unsigned tid = ::GetCurrentThreadId(); @@ -383,11 +403,15 @@ namespace detail if (msg.message == WM_QUIT) break; if ((WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST) || !::IsDialogMessage(native_handle, &msg)) { +#if 0 auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); if (menu_wd) interior_helper_for_menu(msg, menu_wd); - ::TranslateMessage(&msg); + ::TranslateMessage(&msg); //deprecated ::DispatchMessage(&msg); +#else + process_msg(this, msg); +#endif wd_manager().remove_trash_handle(tid); } @@ -400,11 +424,15 @@ namespace detail { if (-1 != ::GetMessage(&msg, 0, 0, 0)) { +#if 0 auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); if (menu_wd) interior_helper_for_menu(msg, menu_wd); ::TranslateMessage(&msg); ::DispatchMessage(&msg); +#else + process_msg(this, msg); +#endif } wd_manager().call_safe_place(tid); @@ -420,11 +448,15 @@ namespace detail { if(-1 != ::GetMessage(&msg, 0, 0, 0)) { +#if 0 auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); if(menu_wd) interior_helper_for_menu(msg, menu_wd); ::TranslateMessage(&msg); ::DispatchMessage(&msg); +#else + process_msg(this, msg); +#endif } wd_manager().call_safe_place(tid); @@ -635,6 +667,7 @@ namespace detail switch(msg) { + case WM_COMMAND: case WM_DESTROY: case WM_SHOWWINDOW: case WM_SIZING: @@ -786,6 +819,17 @@ namespace detail switch (message) { + case WM_COMMAND: + if ((1 == HIWORD(wParam)) && root_runtime->wpassoc) + { + auto i = root_runtime->wpassoc->accel_commands.find(LOWORD(wParam)); + if (i != root_runtime->wpassoc->accel_commands.end()) + { + auto fn = i->second; + fn(); + } + } + break; case WM_IME_STARTCOMPOSITION: if (msgwnd->other.attribute.root->ime_enabled) { @@ -1582,6 +1626,54 @@ namespace detail kb.shift = (0 != (::GetKeyState(VK_SHIFT) & 0x80)); } + void bedrock::delete_platform_assoc(window_platform_assoc* passoc) + { + delete passoc; + } + + //Generates an identitifer for an accel key. + std::pair id_accel_key(const accel_key& key) + { + std::pair ret; + + //Use virt-key for non-case sensitive + if (!key.case_sensitive) + ret.second = static_cast(std::tolower(key.key) - 'a' + 0x41); + + ret.first = ret.second | int(key.case_sensitive ? (1 << 8) : 0) | int(key.alt ? (1 << 9) : 0) | int(key.ctrl ? (1 << 10) : 0) | int(key.shift ? (1 << 11) : 0); + return ret; + } + + void bedrock::keyboard_accelerator(native_window_type wd, const accel_key& key, const std::function& fn) + { + auto misc = wd_manager().root_runtime(wd); + if (nullptr == misc) + return; + + auto wpassoc = misc->wpassoc; + if (!misc->wpassoc) + misc->wpassoc = new window_platform_assoc; + + auto idkey = id_accel_key(key); + + misc->wpassoc->accel_commands[idkey.first] = fn; + + auto accel_size = ::CopyAcceleratorTable(misc->wpassoc->accel, nullptr, 0); + + std::unique_ptr accels(new ACCEL[accel_size + 1]); + + if (accel_size) + ::CopyAcceleratorTable(misc->wpassoc->accel, accels.get(), accel_size); + + auto p = accels.get() + accel_size; + p->cmd = idkey.first; + p->fVirt = (key.case_sensitive ? 0 : FVIRTKEY) | (key.alt ? FALT : 0) | (key.ctrl ? FCONTROL : 0) | (key.shift ? FSHIFT : 0); + p->key = idkey.second; + + ::DestroyAcceleratorTable(misc->wpassoc->accel); + misc->wpassoc->accel = ::CreateAcceleratorTable(accels.get(), accel_size + 1); + } + element_store& bedrock::get_element_store() const { return impl_->estore; diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/source/gui/detail/inner_fwd_implement.hpp similarity index 86% rename from include/nana/gui/detail/inner_fwd_implement.hpp rename to source/gui/detail/inner_fwd_implement.hpp index 68937148..ed8ef73d 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/source/gui/detail/inner_fwd_implement.hpp @@ -1,7 +1,7 @@ /* * Implementations of Inner Forward Declaration * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -15,9 +15,9 @@ #define NANA_GUI_INNER_FWD_IMPLEMENT_HPP #include -#include "inner_fwd.hpp" -#include "basic_window.hpp" -#include "../../paint/graphics.hpp" +#include +#include +#include #include @@ -54,10 +54,13 @@ namespace nana{ implementation * impl_; }; + struct window_platform_assoc; struct root_misc { basic_window * window; + window_platform_assoc * wpassoc{ nullptr }; + nana::paint::graphics root_graph; shortkey_container shortkeys; @@ -71,6 +74,10 @@ namespace nana{ root_misc(root_misc&&); root_misc(basic_window * wd, unsigned width, unsigned height); + ~root_misc(); + private: + root_misc(const root_misc&) = delete; + root_misc& operator=(const root_misc&) = delete; };//end struct root_misc diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 4bfd1900..38add16a 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-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -16,11 +16,11 @@ #include #include #include -#include "window_register.hpp" #include -#include #include #include +#include "window_register.hpp" +#include "inner_fwd_implement.hpp" #include #include @@ -140,10 +140,12 @@ namespace nana //struct root_misc root_misc::root_misc(root_misc&& other): window(other.window), + wpassoc(other.wpassoc), root_graph(std::move(other.root_graph)), shortkeys(std::move(other.shortkeys)), condition(std::move(other.condition)) { + other.wpassoc = nullptr; //moved-from } root_misc::root_misc(basic_window * wd, unsigned width, unsigned height) @@ -155,6 +157,11 @@ namespace nana condition.pressed_by_space = nullptr; condition.hovered = nullptr; } + + root_misc::~root_misc() + { + bedrock::delete_platform_assoc(wpassoc); + } //end struct root_misc //class root_register diff --git a/source/gui/widgets/form.cpp b/source/gui/widgets/form.cpp index 7f8247ff..9414a07b 100644 --- a/source/gui/widgets/form.cpp +++ b/source/gui/widgets/form.cpp @@ -1,6 +1,6 @@ /* * A Form Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -10,6 +10,7 @@ */ #include +#include namespace nana { @@ -94,6 +95,11 @@ namespace nana { API::wait_for(handle()); } + + void form::keyboard_accelerator(const accel_key& key, const std::function& fn) + { + nana::detail::bedrock::instance().keyboard_accelerator(this->native_handle(), key, fn); + } //end class form //class nested_form From 2ba4b612f178e664bd32c1e1334a4ed02209ea7f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 22 Feb 2018 08:53:44 +0800 Subject: [PATCH 24/27] implement bedrock::delete_platform_assoc for linux --- source/gui/detail/bedrock_posix.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 3e38d5ea..ac297366 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -104,6 +104,11 @@ namespace detail void window_proc_for_packet(Display *, nana::detail::msg_packet_tag&); void window_proc_for_xevent(Display*, XEvent&); + struct window_platform_assoc + { + //Wait... + }; + //class bedrock defines a static object itself to implement a static singleton //here is the definition of this object bedrock bedrock::bedrock_object; @@ -222,6 +227,11 @@ namespace detail arg.shift = (xkey.state & ShiftMask); } + void bedrock::delete_platform_assoc(window_platform_assoc* passoc) + { + delete passoc; + } + void bedrock::keyboard_accelerator(native_window_type, const accel_key&, const std::function& fn) { From 244416088fa5892bcb569beadcd22708fe65bc5a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 24 Feb 2018 06:10:43 +0800 Subject: [PATCH 25/27] add member alt for arg_keyboard --- include/nana/gui/detail/general_events.hpp | 7 ++++--- source/gui/detail/bedrock_posix.cpp | 1 + source/gui/detail/bedrock_windows.cpp | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 5992f1a0..72b4cbf3 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -1,7 +1,7 @@ /** * Definition of General Events * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -460,8 +460,9 @@ namespace nana ::nana::window window_handle; ///< A handle to the event window mutable wchar_t key; ///< the key corresponding to the key pressed mutable bool ignore; ///< this member is only available for key_char event, set 'true' to ignore the input. - bool ctrl; ///< keyboard Ctrl is pressed? - bool shift; ///< keyboard Shift is pressed + bool alt; ///< it is set to indicate the modifier key Alt just prior to the event. + bool ctrl; ///< it is set to indicate the modifier key Ctrl just prior to the event. + bool shift; ///< it is set to indicate the modifier key Shift just prior to the event. }; struct arg_move : public event_arg diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index ac297366..131d42de 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -223,6 +223,7 @@ namespace detail { XKeyEvent xkey; nana::detail::platform_spec::instance().read_keystate(xkey); + arg.alt = (xkey.state & Mod1Mask); arg.ctrl = (xkey.state & ControlMask); arg.shift = (xkey.state & ShiftMask); } diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 9618c47e..96aaed8f 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -1622,6 +1622,7 @@ namespace detail void bedrock::get_key_state(arg_keyboard& kb) { + kb.alt = (0 != (::GetKeyState(VK_MENU) & 0x80)); kb.ctrl = (0 != (::GetKeyState(VK_CONTROL) & 0x80)); kb.shift = (0 != (::GetKeyState(VK_SHIFT) & 0x80)); } From 457d86aa39dacb16e909d8f2529c6da3c0328684 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 24 Feb 2018 06:13:46 +0800 Subject: [PATCH 26/27] implement keyboard accelerators for linux --- source/gui/detail/bedrock_posix.cpp | 93 +++++++++++++++++++++++---- source/gui/detail/bedrock_windows.cpp | 3 +- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 131d42de..b8edb34c 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -104,9 +104,40 @@ namespace detail void window_proc_for_packet(Display *, nana::detail::msg_packet_tag&); void window_proc_for_xevent(Display*, XEvent&); + class accel_key_comparer + { + public: + bool operator()(const accel_key& a, const accel_key& b) const + { + auto va = a.case_sensitive ? a.key : std::tolower(a.key); + auto vb = b.case_sensitive ? b.key : std::tolower(b.key); + + if(va < vb) + return true; + else if(va > vb) + return false; + + if (a.case_sensitive != b.case_sensitive) + return b.case_sensitive; + + if (a.alt != b.alt) + return b.alt; + + if (a.ctrl != b.ctrl) + return b.ctrl; + + return ((a.shift != b.shift) && b.shift); + } + }; + + struct accel_key_value + { + std::function command; + }; + struct window_platform_assoc { - //Wait... + std::map accel_commands; }; //class bedrock defines a static object itself to implement a static singleton @@ -233,9 +264,16 @@ namespace detail delete passoc; } - void bedrock::keyboard_accelerator(native_window_type, const accel_key&, const std::function& fn) + void bedrock::keyboard_accelerator(native_window_type wd, const accel_key& ackey, const std::function& fn) { + auto misc = wd_manager().root_runtime(wd); + if (nullptr == misc) + return; + if (!misc->wpassoc) + misc->wpassoc = new window_platform_assoc; + + misc->wpassoc->accel_commands[ackey].command = fn; } element_store& bedrock::get_element_store() const @@ -506,6 +544,34 @@ namespace detail return wchar_t(keysym); } + bool translate_keyboard_accelerator(root_misc* misc, char os_code, const arg_keyboard& modifiers) + { + if(!misc->wpassoc) + return false; + + auto lower_oc = std::tolower(os_code); + + std::function command; + + for(auto & accel : misc->wpassoc->accel_commands) + { + if(accel.first.key != (accel.first.case_sensitive ? os_code : lower_oc)) + continue; + + if(accel.first.alt == modifiers.alt && accel.first.ctrl == modifiers.ctrl && accel.first.shift == modifiers.shift) + { + command = accel.second.command; + break; + } + } + + if(!command) + return false; + + command(); + return true; + } + void window_proc_for_xevent(Display* /*display*/, XEvent& xevent) { typedef detail::bedrock::core_window_t core_window_t; @@ -865,6 +931,9 @@ namespace detail if(msgwnd) { + arg_keyboard modifiers_status; + brock.get_key_state(modifiers_status); + KeySym keysym; Status status; char fixbuf[33]; @@ -899,16 +968,20 @@ namespace detail keybuf[len] = 0; wchar_t os_code = 0; + bool accel_translated = false; + switch(status) { case XLookupKeySym: case XLookupBoth: os_code = os_code_from_keysym(keysym); + accel_translated = translate_keyboard_accelerator(root_runtime, os_code, modifiers_status); + if(accel_translated) + break; + if(os_code == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab { - arg_keyboard argkey; - brock.get_key_state(argkey); - auto tstop_wd = wd_manager.tabstop(msgwnd, !argkey.shift); + auto tstop_wd = wd_manager.tabstop(msgwnd, !modifiers_status.shift); if (tstop_wd) { root_runtime->condition.ignore_tab = true; @@ -923,9 +996,9 @@ namespace detail if((nullptr == pressed_wd) && (nullptr == pressed_wd_space)) { arg_mouse arg; - arg.alt = false; + arg.alt = modifiers_status.alt; arg.button = ::nana::mouse::left_button; - arg.ctrl = false; + arg.ctrl = modifiers_status.ctrl; arg.evt_code = event_code::mouse_down; arg.left_button = true; arg.mid_button = false; @@ -971,11 +1044,10 @@ namespace detail if(keyboard::os_ctrl == os_code) context.is_ctrl_pressed = true; - arg_keyboard arg; + arg_keyboard arg = modifiers_status; arg.ignore = false; arg.key = os_code; arg.evt_code = event_code::key_press; - brock.get_key_state(arg); arg.window_handle = reinterpret_cast(msgwnd); brock.emit(event_code::key_press, msgwnd, arg, true, &context); @@ -1004,7 +1076,7 @@ namespace detail for(int i = 0; i < len; ++i) { - arg_keyboard arg; + arg_keyboard arg = modifiers_status; arg.ignore = false; arg.key = charbuf[i]; @@ -1027,7 +1099,6 @@ namespace detail } arg.evt_code = event_code::key_char; arg.window_handle = reinterpret_cast(msgwnd); - brock.get_key_state(arg); msgwnd->annex.events_ptr->key_char.emit(arg, reinterpret_cast(msgwnd)); if(arg.ignore == false && wd_manager.available(msgwnd)) draw_invoker(&drawer::key_char, msgwnd, arg, &context); diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 96aaed8f..d1267332 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -1650,8 +1650,7 @@ namespace detail auto misc = wd_manager().root_runtime(wd); if (nullptr == misc) return; - - auto wpassoc = misc->wpassoc; + if (!misc->wpassoc) misc->wpassoc = new window_platform_assoc; From bdc480953ef82b760f44e3bec86c99ae1bafd2ca Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 7 Mar 2018 11:27:31 +0800 Subject: [PATCH 27/27] small improve --- source/gui/detail/bedrock_windows.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index d1267332..ac1626ef 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -353,11 +353,16 @@ namespace detail void process_msg(bedrock* brock, MSG& msg) { - auto misc = brock->wd_manager().root_runtime(reinterpret_cast(msg.hwnd)); + if (WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST) + { + auto misc = brock->wd_manager().root_runtime(reinterpret_cast(msg.hwnd)); + if (misc && misc->wpassoc && misc->wpassoc->accel) + { + if (::TranslateAccelerator(msg.hwnd, misc->wpassoc->accel, &msg)) + return; + } + } - if (misc && misc->wpassoc->accel && ::TranslateAccelerator(msg.hwnd, misc->wpassoc->accel, &msg)) - return; - auto menu_wd = brock->get_menu(reinterpret_cast(msg.hwnd), true); if (menu_wd) interior_helper_for_menu(msg, menu_wd);