From 342a6a7ac0acb531f942cba6f2744ad27e8dce64 Mon Sep 17 00:00:00 2001 From: Yuchen Deng Date: Sun, 24 Jun 2018 14:36:21 +0800 Subject: [PATCH 01/34] Add missing changes after branch merged --- CMakeLists.txt | 82 ++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d023469..f47642f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # Robert Hauck - Enable support for PNG/Freetype # Qiangqiang Wu - Add biicode support # Ariel Vina-Rodriguez (qPCR4vir) -# Pavel O. - fix compilation with boost::filesystem (#281) +# Pavel O. - fix compilation with boost::filesystem (#281) # Frostbane - Add option for compiling a shared library (#263,#265) # # Nana uses some build systems: MS-VS solution, MAKE, bakefile, codeblock, etc. manually optimized. @@ -142,11 +142,11 @@ endif() # if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") + if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") set(CMAKE_CXX_FLAGS "-std=gnu++14 -Wall -I/usr/local/include") - else() - set(CMAKE_CXX_FLAGS "-std=gnu++14 -Wall") - endif() + else() + set(CMAKE_CXX_FLAGS "-std=gnu++14 -Wall") + endif() else() set(CMAKE_CXX_FLAGS "-std=c++14 -Wall") endif() @@ -156,27 +156,26 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") if(NANA_CMAKE_SHARED_LIB) list(APPEND NANA_LINKS -lgcc -lstdc++ -pthread) else() - set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread") - # message("Setting NANA_LINKS to -static-libgcc -static-libstdc++ -pthread or ${NANA_LINKS}") - endif(NANA_CMAKE_SHARED_LIB) + if(MINGW) + set(CMAKE_EXE_LINKER_FLAGS "-static -pthread") + else() + set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread") + endif() + endif() if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) - # GCC 4.9 + # GCC 4.9 list(APPEND NANA_LINKS "-lboost_system -lboost_thread") - elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3) - # IS_GNUCXX < 5.3 + # IS_GNUCXX < 5.3 else() list(APPEND NANA_LINKS -lstdc++fs) - endif() + endif() +endif() -endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW - - -if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # APPLE Clang - # set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libstdc++") - list(APPEND NANA_LINKS -stdlib=libstdc++) -endif () +if(APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + list(APPEND NANA_LINKS -stdlib=libstdc++) +endif() ############# Optional libraries @@ -355,27 +354,26 @@ endif() # Just for information: -message ("") -message ( "CMAKE_CXX_COMPILER_ID = " ${CMAKE_CXX_COMPILER_ID}) -message ( "COMPILER_IS_CLANG = " ${COMPILER_IS_CLANG}) -message ( "CMAKE_COMPILER_IS_GNUCXX = " ${CMAKE_COMPILER_IS_GNUCXX}) -message ( "CMAKE_CXX_FLAGS = " ${CMAKE_CXX_FLAGS}) -message ( "CMAKE_EXE_LINKER_FLAGS = " ${CMAKE_EXE_LINKER_FLAGS}) -message ( "CMAKE_STATIC_LINKER_FLAGS = " ${CMAKE_STATIC_LINKER_FLAGS}) -message ( "NANA_LINKS = " ${NANA_LINKS}) -message ( "DESTDIR = " ${DESTDIR}) -message ( "CMAKE_INSTALL_PREFIX = " ${CMAKE_INSTALL_PREFIX}) -message ( "NANA_INCLUDE_DIR = " ${NANA_INCLUDE_DIR}) -message ( "CMAKE_CURRENT_SOURCE_DIR = " ${CMAKE_CURRENT_SOURCE_DIR}) -message ( "NANA_CMAKE_ENABLE_AUDIO = " ${NANA_CMAKE_ENABLE_AUDIO}) -message ( "NANA_CMAKE_SHARED_LIB = " ${NANA_CMAKE_SHARED_LIB}) -message ( "NANA_CLION = " ${NANA_CLION}) -message ( "CMAKE_MAKE_PROGRAM = " ${CMAKE_MAKE_PROGRAM}) -message ( "CMAKE_CXX_COMPILER_VERSION = " ${CMAKE_CXX_COMPILER_VERSION}) +message("") +message("CMAKE_CXX_COMPILER_ID = " ${CMAKE_CXX_COMPILER_ID}) +message("COMPILER_IS_CLANG = " ${COMPILER_IS_CLANG}) +message("CMAKE_COMPILER_IS_GNUCXX = " ${CMAKE_COMPILER_IS_GNUCXX}) +message("CMAKE_CXX_FLAGS = " ${CMAKE_CXX_FLAGS}) +message("CMAKE_EXE_LINKER_FLAGS = " ${CMAKE_EXE_LINKER_FLAGS}) +message("CMAKE_STATIC_LINKER_FLAGS = " ${CMAKE_STATIC_LINKER_FLAGS}) +message("NANA_LINKS = " ${NANA_LINKS}) +message("DESTDIR = " ${DESTDIR}) +message("CMAKE_INSTALL_PREFIX = " ${CMAKE_INSTALL_PREFIX}) +message("NANA_INCLUDE_DIR = " ${NANA_INCLUDE_DIR}) +message("CMAKE_CURRENT_SOURCE_DIR = " ${CMAKE_CURRENT_SOURCE_DIR}) +message("NANA_CMAKE_ENABLE_AUDIO = " ${NANA_CMAKE_ENABLE_AUDIO}) +message("NANA_CMAKE_SHARED_LIB = " ${NANA_CMAKE_SHARED_LIB}) +message("NANA_CLION = " ${NANA_CLION}) +message("CMAKE_MAKE_PROGRAM = " ${CMAKE_MAKE_PROGRAM}) -message ( "NANA_CMAKE_FIND_BOOST_FILESYSTEM = " ${NANA_CMAKE_FIND_BOOST_FILESYSTEM}) -message ( "NANA_CMAKE_BOOST_FILESYSTEM_FORCE = " ${NANA_CMAKE_BOOST_FILESYSTEM_FORCE}) -message ( "NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT = " ${NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT}) -message ( "NANA_CMAKE_BOOST_FILESYSTEM_LIB = " ${NANA_CMAKE_BOOST_FILESYSTEM_LIB}) -message ( "NANA_CMAKE_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_AUTOMATIC_GUI_TESTING}) -message ( "NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING}) +message("NANA_CMAKE_FIND_BOOST_FILESYSTEM = " ${NANA_CMAKE_FIND_BOOST_FILESYSTEM}) +message("NANA_CMAKE_BOOST_FILESYSTEM_FORCE = " ${NANA_CMAKE_BOOST_FILESYSTEM_FORCE}) +message("NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT = " ${NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT}) +message("NANA_CMAKE_BOOST_FILESYSTEM_LIB = " ${NANA_CMAKE_BOOST_FILESYSTEM_LIB}) +message("NANA_CMAKE_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_AUTOMATIC_GUI_TESTING}) +message("NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING}) From 3d810fddac0caee17b8fbb3d8b32938776e37d76 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 30 Jun 2018 05:22:34 +0800 Subject: [PATCH 02/34] fix issue of fold expressions test(#320,#321) --- include/nana/gui/msgbox.hpp | 4 ++++ include/nana/internationalization.hpp | 2 +- source/gui/msgbox.cpp | 4 ++-- source/internationalization.cpp | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/nana/gui/msgbox.hpp b/include/nana/gui/msgbox.hpp index 02b4fe35..a8a447bf 100644 --- a/include/nana/gui/msgbox.hpp +++ b/include/nana/gui/msgbox.hpp @@ -255,7 +255,11 @@ namespace nana bool show_modal(Args&& ... args) { std::vector contents; +#ifdef __cpp_fold_expressions + (contents.emplace_back(&args), ...); +#else _m_fetch_args(contents, std::forward(args)...); +#endif if (contents.empty()) return false; diff --git a/include/nana/internationalization.hpp b/include/nana/internationalization.hpp index cab02568..cba03bf5 100644 --- a/include/nana/internationalization.hpp +++ b/include/nana/internationalization.hpp @@ -1,7 +1,7 @@ /* * An Implementation of i18n * 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 diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 36a7c202..caf6380b 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -1,7 +1,7 @@ /* * A Message Box Class * 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 @@ -1294,7 +1294,7 @@ namespace nana min_width_entry_field_pixels_ = pixels; } -#ifndef _nana_cxx_folding_expression +#ifndef __cpp_fold_expressions void inputbox::_m_fetch_args(std::vector&) {} #endif diff --git a/source/internationalization.cpp b/source/internationalization.cpp index 6e4a99d5..d41b775c 100644 --- a/source/internationalization.cpp +++ b/source/internationalization.cpp @@ -417,7 +417,7 @@ namespace nana } } -#ifndef _nana_cxx_folding_expression +#ifndef __cpp_fold_expressions void internationalization::_m_fetch_args(std::vector&) {} #endif From 40a6584a757f7adaf0fe4eaaf62d6a7f4d10f747 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 1 Jul 2018 15:06:15 +0800 Subject: [PATCH 03/34] fix bug that group draws gradual rectangle for caption at wrong position --- include/nana/gui/msgbox.hpp | 2 +- source/gui/widgets/group.cpp | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/nana/gui/msgbox.hpp b/include/nana/gui/msgbox.hpp index a8a447bf..a004fd21 100644 --- a/include/nana/gui/msgbox.hpp +++ b/include/nana/gui/msgbox.hpp @@ -1,7 +1,7 @@ /* * A Message Box Class * 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/group.cpp b/source/gui/widgets/group.cpp index e9ece21a..21a9ffe0 100644 --- a/source/gui/widgets/group.cpp +++ b/source/gui/widgets/group.cpp @@ -264,15 +264,22 @@ namespace nana{ drawing dw(*this); + //When the group is resized, the drawing is called before moving the caption, but + //the drawing of group requires the lastest position of caption for gradual rectangle. + //For the requirement, a move event handler is required for listning the change of caption's position. + impl_->caption.events().move([this](const arg_move& arg){ + if (align::left != impl_->caption_align) + API::refresh_window(*this); + }); + // This drawing function is owner by the onwer of dw (the outer panel of the group widget), not by dw !! dw.draw([this](paint::graphics& graph) { auto gap_px = impl_->gap - 1; - graph.rectangle(true, API::bgcolor(this->parent())); - auto const top_round_line = static_cast(impl_->caption_dimension.height) / 2; + graph.rectangle(true, API::bgcolor(this->parent())); graph.round_rectangle(rectangle(point(gap_px, top_round_line), nana::size(graph.width() - 2 * gap_px, graph.height() - top_round_line - gap_px) ), @@ -281,11 +288,10 @@ namespace nana{ 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) } }; + rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width + 4, static_cast(top_round_line - opt_r->y) } }; grad_r.y += top_round_line*2 / 3; grad_r.x -= 2; - grad_r.width += 4; graph.gradual_rectangle(grad_r, API::bgcolor(this->parent()), this->bgcolor(), true From 56a9647d56ef58203909444bcac923b02d99fe75 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 2 Jul 2018 04:31:41 +0800 Subject: [PATCH 04/34] use std::string_view --- include/nana/deploy.hpp | 3 ++- include/nana/gui/widgets/combox.hpp | 28 +++++++++------------------- include/nana/gui/widgets/listbox.hpp | 7 ++++++- source/deploy.cpp | 11 ++++++++--- source/gui/widgets/combox.cpp | 11 ++++++++++- source/gui/widgets/listbox.cpp | 12 ++++++++++++ 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index c9d12f88..71ad399d 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -65,11 +65,12 @@ namespace nana bool review_utf8(std::string& text); const std::string& to_utf8(const std::string&); - std::string to_utf8(const std::wstring&); #ifdef _nana_std_has_string_view + std::string to_utf8(std::wstring_view sv); std::wstring to_wstring(std::string_view utf8_str); #else + std::string to_utf8(const std::wstring&); std::wstring to_wstring(const std::string& utf8_str); #endif diff --git a/include/nana/gui/widgets/combox.hpp b/include/nana/gui/widgets/combox.hpp index 551c65d3..f6ba12df 100644 --- a/include/nana/gui/widgets/combox.hpp +++ b/include/nana/gui/widgets/combox.hpp @@ -1,7 +1,7 @@ /** * A Combox 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 @@ -77,6 +77,7 @@ namespace nana public: item_proxy(drawer_impl*, std::size_t pos); item_proxy& text(const ::std::string&); + ::std::string text() const; item_proxy& select(); bool selected() const; @@ -103,22 +104,19 @@ namespace nana } template - item_proxy& value(const T& t) + item_proxy& value(T&& val) { - *_m_anyobj(true) = t; - return *this; - } - - template - item_proxy& value(T&& t) - { - *_m_anyobj(true) = ::std::move(t); + *_m_anyobj(true) = ::std::forward(val); return *this; } public: /// Behavior of Iterator's value_type +#ifdef _nana_std_has_string_view + bool operator==(::std::string_view) const; +#else bool operator==(const ::std::string&) const; bool operator==(const char*) const; +#endif /// Behavior of Iterator item_proxy & operator=(const item_proxy&); @@ -192,19 +190,11 @@ namespace nana return _m_at_key(std::move(p)); } - template - void erase_key(const Key& kv) - { - typedef typename nana::detail::type_escape::type key_t; - std::unique_ptr p(new nana::key >(kv)); - _m_erase(p.get()); - } - template void erase_key(Key&& kv) { typedef typename nana::detail::type_escape::type key_t; - std::unique_ptr p(new nana::key >(std::move(kv))); + std::unique_ptr p(new nana::key >(std::forward(kv))); _m_erase(p.get()); } diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 21f20856..9a70cc6d 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -933,15 +933,20 @@ namespace nana template item_proxy & value(T&& t) { - *_m_value(true) = std::forward(t); + *_m_value(true) = ::std::forward(t); return *this; } /// Behavior of Iterator's value_type +#ifdef _nana_std_has_string_view + bool operator==(::std::string_view sv) const; + bool operator==(::std::wstring_view sv) const; +#else bool operator==(const char * s) const; bool operator==(const wchar_t * s) const; bool operator==(const ::std::string& s) const; bool operator==(const ::std::wstring& s) const; +#endif /// Behavior of Iterator item_proxy & operator=(const item_proxy&); diff --git a/source/deploy.cpp b/source/deploy.cpp index 06bbda02..1ae165ef 100644 --- a/source/deploy.cpp +++ b/source/deploy.cpp @@ -175,12 +175,12 @@ namespace nana return str; } - std::string to_utf8(const std::wstring& text) +#ifdef _nana_std_has_string_view + std::string to_utf8(std::wstring_view text) { - return ::nana::charset(text).to_bytes(::nana::unicode::utf8); + return ::nana::charset(std::wstring{text}).to_bytes(::nana::unicode::utf8); } -#ifdef _nana_std_has_string_view std::wstring to_wstring(std::string_view utf8_str) { if (utf8_str.empty()) @@ -189,6 +189,11 @@ namespace nana return ::nana::charset(std::string{ utf8_str.data(), utf8_str.size() }, unicode::utf8); } #else + std::string to_utf8(const std::wstring& text) + { + return ::nana::charset(text).to_bytes(::nana::unicode::utf8); + } + std::wstring to_wstring(const std::string& utf8_str) { return ::nana::charset(utf8_str, ::nana::unicode::utf8); diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index dcaf5c43..a8401d5f 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -1,7 +1,7 @@ /* * A Combox 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 @@ -823,6 +823,14 @@ namespace nana } /// Behavior of Iterator's value_type +#ifdef _nana_std_has_string_view + bool item_proxy::operator == (::std::string_view s) const + { + if (pos_ == nana::npos) + return false; + return (impl_->at(pos_).item_text == s); + } +#else bool item_proxy::operator == (const ::std::string& s) const { if (pos_ == nana::npos) @@ -836,6 +844,7 @@ namespace nana return false; return (impl_->at(pos_).item_text == s); } +#endif /// Behavior of Iterator diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 3b41311d..230891c2 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -4825,6 +4825,17 @@ namespace nana } //Behavior of Iterator's value_type +#ifdef _nana_std_has_string_view + bool item_proxy::operator==(std::string_view sv) const + { + return (text(0) == sv); + } + + bool item_proxy::operator==(std::wstring_view sv) const + { + return (text(0) == to_utf8(sv)); + } +#else bool item_proxy::operator==(const char * s) const { return this->operator==(std::string(s)); @@ -4844,6 +4855,7 @@ namespace nana { return (text(0) == to_utf8(s)); } +#endif item_proxy & item_proxy::operator=(const item_proxy& rhs) { From 5a4edd2fefd0da46cf461e59485572380ddea35b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 2 Jul 2018 05:42:56 +0800 Subject: [PATCH 05/34] fix bug that widgets may not draw correctly --- source/gui/detail/window_manager.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 2a98269e..785f45be 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -950,6 +950,19 @@ namespace detail if (wd->dimension == sz) return false; + std::vector presence; + + if (wd->dimension.width < sz.width || wd->dimension.height < sz.height) + { + auto wd_r = rectangle{ wd->dimension }; + for (auto child : wd->children) + { + auto child_r = rectangle{ child->pos_owner, child->dimension }; + if (!overlapped(wd_r, child_r)) + presence.push_back(child); + } + } + //Before resiz the window, creates the new graphics paint::graphics graph; paint::graphics root_graph; @@ -1010,6 +1023,11 @@ namespace detail } } + for (auto child : presence) + { + refresh_tree(child); + } + arg_resized arg; arg.window_handle = reinterpret_cast(wd); arg.width = sz.width; From 6add8868da61505e1db96fef2279a98c4a03fb1b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 4 Jul 2018 21:47:47 +0800 Subject: [PATCH 06/34] nana::listbox::scroll not scrolling to correct location(#322) --- 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 3b41311d..e0c67f0a 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2996,11 +2996,11 @@ namespace nana } else { - auto last_off = this->distance(this->first(), this->last()) * ess_->item_height(); - if (last_off - off >= screen_px) + auto const content_px = ess_->content_view->content_size().height; + if (content_px - off >= screen_px) origin.y = static_cast(off); - else if (last_off >= screen_px) - origin.y = static_cast(last_off - screen_px); + else if (content_px >= screen_px) + origin.y = static_cast(content_px - screen_px); } if (ess_->content_view->move_origin(origin - ess_->content_view->origin())) From e08bb0bfe1832055fb2430a7cabe8ccc35c84af9 Mon Sep 17 00:00:00 2001 From: rbrugo Date: Sun, 8 Jul 2018 12:35:14 +0200 Subject: [PATCH 07/34] New textbox::getline returning an optional --- include/nana/gui/widgets/textbox.hpp | 9 +++++++++ source/gui/widgets/textbox.cpp | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index c46aa1ca..01c9a9d1 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -17,6 +17,8 @@ #include "skeletons/textbase_export_interface.hpp" #include "skeletons/text_editor_part.hpp" +#include + namespace nana { class textbox; @@ -173,6 +175,13 @@ namespace nana /// Read the text from a specified line with a set offset. It returns true for success. bool getline(std::size_t line_index,std::size_t offset,std::string& text) const; + /// Read the text from a specified line; returns an empty optional on failure + std::optional getline(std::size_t pos) const; + + ///Read the text from a specified line with a set offset. Returns an empty optional for + /// failure. + std::optional getline(std::size_t line_index, std::size_t offset) const; + /// Gets the caret position /// Returns true if the caret is in the area of display, false otherwise. bool caret_pos(point& pos, bool text_coordinate) const; diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index db57ae82..6836c231 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -377,6 +377,27 @@ namespace drawerbase { return false; } + std::optional textbox::getline(std::size_t pos) const + { + auto result = std::string{}; + if ( getline(pos, result) ) + { + return { std::move(result) }; + } + return {}; + } + + std::optional textbox::getline(std::size_t line_index, std::size_t offset) const + { + auto result = std::string{}; + if ( getline(line_index, offset, result) ) + { + return { std::move(result) }; + } + return {}; + } + + /// Gets the caret position bool textbox::caret_pos(point& pos, bool text_coordinate) const { From 8e546695d74add42ceb1caf05e943d9029064675 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 15 Jul 2018 16:52:33 +0800 Subject: [PATCH 08/34] fix bug that large listbox not scrolling correctly(#324) --- source/gui/widgets/scroll.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/gui/widgets/scroll.cpp b/source/gui/widgets/scroll.cpp index acc2c8b6..01684d2b 100644 --- a/source/gui/widgets/scroll.cpp +++ b/source/gui/widgets/scroll.cpp @@ -99,12 +99,14 @@ namespace nana //Check scroll_area to avoiding division by zero. if (scroll_area) - metrics_.value = pos * value_max / scroll_area; + metrics_.value = pos * (static_cast(value_max) / scroll_area); //converting to double to avoid overflow. - if(metrics_.value < value_max) + if (metrics_.value < value_max) { - int selfpos = static_cast(metrics_.value * scroll_area / value_max); - int nextpos = static_cast((metrics_.value + 1) * scroll_area / value_max); + //converting to double to avoid overflow. + auto const px_per_value = static_cast(scroll_area) / value_max; + int selfpos = static_cast(metrics_.value * px_per_value); + int nextpos = static_cast((metrics_.value + 1) * px_per_value); if(selfpos != nextpos && (pos - selfpos > nextpos - pos)) ++metrics_.value; From fe6965c4d83399f5a40f1f69b68cb11f72237819 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 17 Jul 2018 00:57:05 +0800 Subject: [PATCH 09/34] fix button and progress issues(#325,#327) --- source/gui/widgets/button.cpp | 9 +++++---- source/gui/widgets/progress.cpp | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index c9ba1221..d407f0eb 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -150,11 +150,12 @@ namespace nana{ namespace drawerbase if (false == cite_.draw(graph, attr_.bgcolor, attr_.fgcolor, ::nana::rectangle{ graph.size() }, e_state)) { - if (!API::is_transparent_background(*wdg_)) - { + if (API::is_transparent_background(*wdg_)) + API::dev::copy_transparent_background(*wdg_, graph); + else _m_draw_background(graph); - _m_draw_border(graph); - } + + _m_draw_border(graph); } _m_draw_title(graph, eb); } diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp index 8a679c4c..49fbda99 100644 --- a/source/gui/widgets/progress.cpp +++ b/source/gui/widgets/progress.cpp @@ -49,7 +49,7 @@ namespace nana if (value_ptr) { if (unknown_) - value_ += (*value_ptr ? 5 : 0); + value_ += 5; else value_ = (std::min)(max_, *value_ptr); @@ -99,7 +99,7 @@ namespace nana auto value_px = (widget_->size().width - border_px * 2); //avoid overflow - if (value_ < max_) + if (unknown_ || (value_ < max_)) value_px = static_cast(value_px * (double(value_) / double(max_))); if (value_px != value_px_) From fa45d7a2526fdc09da432a0f8719f12e35710b87 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 20 Jul 2018 06:51:13 +0800 Subject: [PATCH 10/34] fix bug that listbox unexpected sort is performed --- source/gui/widgets/listbox.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index e0c67f0a..8a1462af 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -4378,9 +4378,11 @@ namespace nana essence_->ptr_state = item_state::highlighted; bool need_refresh = false; - //Do sort - if (essence_->header.sortable() && essence_->pointer_where.first == parts::header && prev_state == item_state::pressed) + + //Don't sort the column when the mouse is due to released for stopping resizing column. + if ((drawer_header_->splitter() == npos) && essence_->header.sortable() && essence_->pointer_where.first == parts::header && prev_state == item_state::pressed) { + //Try to sort the column if(essence_->pointer_where.second < essence_->header.cont().size()) need_refresh = essence_->lister.sort_column(essence_->pointer_where.second, nullptr); } From fa24b280c55e5b815c65fe5d30566d036ba9761e Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 24 Jul 2018 08:49:32 +0800 Subject: [PATCH 11/34] fix bug that listbox hovered is not working(#328) --- 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 8a1462af..589a4846 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2934,9 +2934,9 @@ namespace nana cat_proxy(ess_, pos.cat).at(pos.item).select(true); } - void hovered(index_type /*pos*/) override + void hovered(index_type pos) override { - auto offset = ess_->content_view->origin().y / ess_->item_height(); + auto offset = ess_->lister.distance(ess_->first_display(), ess_->lister.index_cast(pos, false)); if (ess_->pointer_where.first != parts::list || ess_->pointer_where.second != offset) { From 3962cc1aeef35e8e984eecd34bd6f02c94d5f9fd Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 26 Jul 2018 04:07:20 +0800 Subject: [PATCH 12/34] fix bug that all members in widget_iterator are private --- include/nana/gui/widgets/detail/widget_iterator.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/nana/gui/widgets/detail/widget_iterator.hpp b/include/nana/gui/widgets/detail/widget_iterator.hpp index c78e5d4d..6f8945ef 100644 --- a/include/nana/gui/widgets/detail/widget_iterator.hpp +++ b/include/nana/gui/widgets/detail/widget_iterator.hpp @@ -1,6 +1,6 @@ /* * A Widget Iterator Template - * Copyright(C) 2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2017-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -23,6 +23,7 @@ namespace nana { template class widget_iterator { + public: using iterator_category = Category; using value_type = T; using difference_type = std::ptrdiff_t; From df5fda909635d1b4434c819f80352e94c923b281 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 28 Jul 2018 09:34:08 +0800 Subject: [PATCH 13/34] fix listbox thread-safe issue(#329) --- include/nana/gui/widgets/listbox.hpp | 1 + source/gui/widgets/listbox.cpp | 33 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 21f20856..d3bb5bd8 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1028,6 +1028,7 @@ namespace nana template void append_model(const T& t) { + nana::internal_scope_guard lock; _m_try_append_model(const_virtual_pointer{ &t }); _m_update(); } diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 589a4846..05b9687f 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -5380,6 +5380,7 @@ namespace nana void listbox::auto_draw(bool enabled) noexcept { + internal_scope_guard lock; auto & ess = _m_ess(); if (ess.auto_draw != enabled) { @@ -5390,6 +5391,7 @@ namespace nana void listbox::scroll(bool to_bottom, size_type cat_pos) { + internal_scope_guard lock; auto & ess = _m_ess(); auto cats = this->size_categ(); @@ -5488,6 +5490,7 @@ namespace nana rectangle listbox::content_area() const { + internal_scope_guard lock; auto & ess = _m_ess(); auto carea = ess.content_area(); carea.x += ess.header.margin(); @@ -5534,29 +5537,34 @@ namespace nana listbox::cat_proxy listbox::at(size_type pos) { + internal_scope_guard lock; check_range(pos, size_categ()); return{ &_m_ess(), pos }; } const listbox::cat_proxy listbox::at(size_type pos) const { + internal_scope_guard lock; check_range(pos, size_categ()); return{ &_m_ess(), pos }; } listbox::item_proxy listbox::at(const index_pair& abs_pos) { + internal_scope_guard lock; return at(abs_pos.cat).at(abs_pos.item); } const listbox::item_proxy listbox::at(const index_pair& pos_abs) const { + internal_scope_guard lock; return at(pos_abs.cat).at(pos_abs.item); } // Contributed by leobackes(pr#97) listbox::index_pair listbox::cast( const point& pos ) const { + internal_scope_guard lock; auto & ess=_m_ess(); auto _where = ess.where(pos); @@ -5568,27 +5576,32 @@ namespace nana auto listbox::column_at(size_type pos, bool disp_order) -> column_interface& { + internal_scope_guard lock; return _m_ess().header.at(pos, disp_order); } auto listbox::column_at(size_type pos, bool disp_order) const -> const column_interface& { + internal_scope_guard lock; return _m_ess().header.at(pos, disp_order); } auto listbox::column_size() const ->size_type { + internal_scope_guard lock; return _m_ess().header.cont().size(); } //Contributed by leobackes(pr#97) listbox::size_type listbox::column_from_pos ( const point& pos ) const { + internal_scope_guard lock; return _m_ess().column_from_pos(pos.x); } void listbox::checkable(bool chkable) { + internal_scope_guard lock; auto & ess = _m_ess(); if(ess.checkable != chkable) { @@ -5599,11 +5612,13 @@ namespace nana auto listbox::checked() const -> index_pairs { + internal_scope_guard lock; return _m_ess().lister.pick_items(false); } void listbox::clear(size_type cat) { + internal_scope_guard lock; auto & ess = _m_ess(); auto origin = ess.content_view->origin(); @@ -5627,6 +5642,7 @@ namespace nana void listbox::clear() { + internal_scope_guard lock; auto & ess = _m_ess(); ess.lister.clear(); @@ -5641,6 +5657,7 @@ namespace nana void listbox::erase(size_type cat) { + internal_scope_guard lock; auto & ess = _m_ess(); auto origin = ess.content_view->origin(); @@ -5665,6 +5682,7 @@ namespace nana void listbox::erase() { + internal_scope_guard lock; auto & ess = _m_ess(); ess.lister.erase(); ess.calc_content_size(); @@ -5673,6 +5691,8 @@ namespace nana void listbox::erase(index_pairs indexes) { + internal_scope_guard lock; + std::sort(indexes.begin(), indexes.end(), [](const index_pair& pos1, const index_pair& pos2) { return (pos1 > pos2); @@ -5722,6 +5742,7 @@ namespace nana if(ip.empty()) return ip; + internal_scope_guard lock; auto * ess = ip._m_ess(); auto _where = ip.pos(); @@ -5744,48 +5765,57 @@ namespace nana bool listbox::sortable() const { + internal_scope_guard lock; return _m_ess().header.sortable(); } void listbox::sortable(bool enable) { + internal_scope_guard lock; _m_ess().header.sortable(enable); } void listbox::set_sort_compare(size_type col, std::function strick_ordering) { + internal_scope_guard lock; _m_ess().header.at(col).weak_ordering = std::move(strick_ordering); } /// sort() and ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items void listbox::sort_col(size_type col, bool reverse) { + internal_scope_guard lock; _m_ess().lister.sort_column(col, &reverse); } auto listbox::sort_col() const -> size_type { + internal_scope_guard lock; return _m_ess().lister.sort_attrs().column; } /// potencially ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items void listbox::unsort() { + internal_scope_guard lock; this->sort_col(npos, false); } bool listbox::freeze_sort(bool freeze) { + internal_scope_guard lock; return !_m_ess().lister.active_sort(!freeze); } auto listbox::selected() const -> index_pairs { + internal_scope_guard lock; return _m_ess().lister.pick_items(true); // absolute positions, no relative to display } void listbox::show_header(bool sh) { + internal_scope_guard lock; _m_ess().header.visible(sh); _m_ess().update(); } @@ -5797,6 +5827,7 @@ namespace nana void listbox::move_select(bool upwards) /// icon_renderer) { + internal_scope_guard lock; _m_ess().ctg_icon_renderer.swap(icon_renderer); _m_ess().update(); return *this; @@ -5836,6 +5868,7 @@ namespace nana listbox& listbox::category_icon(const paint::image& img_expanded, const paint::image&& img_collapsed) { + internal_scope_guard lock; _m_ess().ctg_icon_renderer = [img_expanded, img_collapsed](paint::graphics& graph, const rectangle& rt_icon, bool expanded) { if (expanded) From 1339658c4c8d913b2b3043ee410d1e709844c51b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 1 Aug 2018 07:31:02 +0800 Subject: [PATCH 14/34] fix bug that window_position returns the pos of WM reparenting frame --- source/detail/mswin/platform_spec.hpp | 2 +- source/detail/platform_spec_posix.cpp | 81 +++++++++++++++++-- source/detail/platform_spec_windows.cpp | 2 +- source/detail/posix/platform_spec.hpp | 5 +- source/gui/detail/native_window_interface.cpp | 19 ++++- source/gui/widgets/scroll.cpp | 2 +- source/gui/widgets/treebox.cpp | 2 - 7 files changed, 97 insertions(+), 16 deletions(-) diff --git a/source/detail/mswin/platform_spec.hpp b/source/detail/mswin/platform_spec.hpp index a1845683..3505f6e3 100644 --- a/source/detail/mswin/platform_spec.hpp +++ b/source/detail/mswin/platform_spec.hpp @@ -1,7 +1,7 @@ /* * Platform Specification 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/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index 8baf1d8f..da46d6ea 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -588,16 +588,59 @@ namespace detail } //There are three members make_owner(), get_owner() and remove(), - //they are maintain a table to discribe the owner of windows because the feature in X11, the + //they are maintain a table to discribe the owner of windows because of the feature in X11, the //owner of top level window must be RootWindow. void platform_spec::make_owner(native_window_type owner, native_window_type wd) { - platform_scope_guard psg; + platform_scope_guard lock; wincontext_[wd].owner = owner; - window_context_t & context = wincontext_[owner]; - if(context.owned == 0) - context.owned = new std::vector; - context.owned->push_back(wd); + + auto& owner_ctx = wincontext_[owner]; + if(!owner_ctx.owned) + owner_ctx.owned = new std::vector; + owner_ctx.owned->push_back(wd); + } + + bool platform_spec::umake_owner(native_window_type child) + { + platform_scope_guard lock; + + auto i = wincontext_.find(child); + if(i == wincontext_.end()) + return false; + + if(i->second.owner) + { + auto u = wincontext_.find(i->second.owner); + if(u != wincontext_.end()) + { + auto * owned = u->second.owned; + if(owned) + { + auto j = std::find(owned->begin(), owned->end(), child); + if(j != owned->end()) + owned->erase(j); + + if(owned->empty()) + { + delete owned; + u->second.owned = nullptr; + //The owner owns no child. If it is not a child of other owners, + //remove it. + if(nullptr == u->second.owner) + wincontext_.erase(u); + } + } + } + + i->second.owner = nullptr; + } + + //Don't remove the ownerships which the child is a owner window. + if(nullptr == i->second.owned) + wincontext_.erase(i); + + return true; } native_window_type platform_spec::get_owner(native_window_type wd) const @@ -610,7 +653,9 @@ namespace detail void platform_spec::remove(native_window_type wd) { msg_dispatcher_->erase(reinterpret_cast(wd)); - platform_scope_guard psg; + + platform_scope_guard lock; +#if 0 auto i = wincontext_.find(wd); if(i == wincontext_.end()) return; @@ -641,6 +686,28 @@ namespace detail } delete vec; wincontext_.erase(i); +#else + if(umake_owner(wd)) + { + auto i = wincontext_.find(wd); + if(i != wincontext_.end()) + { + if(i->second.owned) + { + set_error_handler(); + auto & wd_manager = detail::bedrock::instance().wd_manager(); + for(auto u = i->second.owned->rbegin(); u != i->second.owned->rend(); ++u) + wd_manager.close(wd_manager.root(*u)); + + rev_error_handler(); + + delete i->second.owned; + } + + wincontext_.erase(i); + } + } +#endif iconbase_.erase(wd); } diff --git a/source/detail/platform_spec_windows.cpp b/source/detail/platform_spec_windows.cpp index 179b87cf..812c2ed0 100644 --- a/source/detail/platform_spec_windows.cpp +++ b/source/detail/platform_spec_windows.cpp @@ -1,7 +1,7 @@ /** * Platform Specification 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/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index e8b2be24..167295bb 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -1,7 +1,7 @@ /* * Platform Specification 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 @@ -213,6 +213,9 @@ namespace detail const atombase_tag & atombase() const; void make_owner(native_window_type owner, native_window_type wd); + + // Cancel the ownership + bool umake_owner(native_window_type child); native_window_type get_owner(native_window_type) const; void remove(native_window_type); diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index aee3ea8e..ed1e5772 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -296,6 +296,8 @@ namespace nana{ win_attr.save_under = True; attr_mask |= CWSaveUnder; + ///The parameter of XCreateWindow to create a top level window must be root. + ///But after creation, the real parent is the reparenting frame window. parent = restrict::spec.root_window(); calc_screen_point(owner, pos); } @@ -309,9 +311,10 @@ namespace nana{ if(handle) { //make owner if it is a popup window - if((!nested) && owner) + if(!nested) { - restrict::spec.make_owner(owner, reinterpret_cast(handle)); + auto origin_owner = (owner ? owner : reinterpret_cast(restrict::spec.root_window())); + restrict::spec.make_owner(origin_owner, reinterpret_cast(handle)); exposed_positions[handle] = pos; } @@ -1222,7 +1225,7 @@ namespace nana{ Window drop_wd; int x, y; unsigned mask; - nana::detail::platform_scope_guard psg; + nana::detail::platform_scope_guard lock; ::XQueryPointer(restrict::spec.open_display(), restrict::spec.root_window(), &drop_wd, &drop_wd, &pos.x, &pos.y, &x, &y, &mask); return pos; #endif @@ -1278,9 +1281,19 @@ namespace nana{ if(returns_previous) prev = parent_window(child); + if(native_window_type{} == new_parent) + new_parent = reinterpret_cast(restrict::spec.root_window()); + ::XReparentWindow(restrict::spec.open_display(), reinterpret_cast(child), reinterpret_cast(new_parent), 0, 0); + + + // If umake_owner returns true, it indicates the child windows is a popup window. + // So make the ownership of new_parent and child. + if(restrict::spec.umake_owner(child)) + restrict::spec.make_owner(new_parent, child); + return prev; #endif } diff --git a/source/gui/widgets/scroll.cpp b/source/gui/widgets/scroll.cpp index 01684d2b..10b2c6da 100644 --- a/source/gui/widgets/scroll.cpp +++ b/source/gui/widgets/scroll.cpp @@ -99,7 +99,7 @@ namespace nana //Check scroll_area to avoiding division by zero. if (scroll_area) - metrics_.value = pos * (static_cast(value_max) / scroll_area); //converting to double to avoid overflow. + metrics_.value = static_cast(pos * (static_cast(value_max) / scroll_area)); //converting to double to avoid overflow. if (metrics_.value < value_max) { diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index c68abb4c..3cbf61b7 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -1853,7 +1853,6 @@ namespace nana item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); impl_->attr.tree_cont.for_each(shape.first, nl); - auto & node_state = impl_->node_state; node_state.pressed_node = nl.node(); @@ -1869,7 +1868,6 @@ namespace nana else return; - impl_->draw(true); API::dev::lazy_refresh(); } From 1ff1c55592c17286241ae8f8ab2a9f38c8ec626e Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 5 Aug 2018 16:41:39 +0800 Subject: [PATCH 15/34] fix bug that caused wrong window position in X11 --- include/nana/gui/basis.hpp | 7 + .../gui/detail/native_window_interface.hpp | 6 +- include/nana/gui/widgets/widget.hpp | 17 +- source/detail/platform_spec_posix.cpp | 1 + source/detail/posix/platform_spec.hpp | 1 + source/gui/detail/bedrock_pi.cpp | 6 +- source/gui/detail/bedrock_posix.cpp | 8 +- source/gui/detail/native_window_interface.cpp | 275 +++++++++++++----- source/gui/programming_interface.cpp | 2 +- source/gui/widgets/group.cpp | 2 +- 10 files changed, 237 insertions(+), 88 deletions(-) diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index 4153d439..a582d7b9 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -51,6 +51,13 @@ namespace nana top_left, top_right, bottom_left, bottom_right }; + enum class window_relationship + { + owner, ///< Owner window. + parent, ///< Parent window. + either_po ///< One between owner and parent. + }; + enum class bground_mode { none, diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp index 25b2fc7f..e2a997c6 100644 --- a/include/nana/gui/detail/native_window_interface.hpp +++ b/include/nana/gui/detail/native_window_interface.hpp @@ -1,7 +1,7 @@ /* * Platform 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 @@ -76,8 +76,8 @@ namespace detail static native_string_type window_caption(native_window_type); static void capture_window(native_window_type, bool); static nana::point cursor_position(); - static native_window_type get_owner_window(native_window_type); - static native_window_type parent_window(native_window_type); + + static native_window_type get_window(native_window_type wd, window_relationship); static native_window_type parent_window(native_window_type child, native_window_type new_parent, bool returns_previous); //For Caret static void caret_create(native_window_type, const ::nana::size&); diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index d7be3acf..7448eea9 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -170,7 +170,8 @@ namespace nana } /// Base class of all the classes defined as a widget window. Defaultly a widget_tag - template + template::value>::type> //type DrawerTrigger must be derived from nana::drawer_trigger class widget_object: public detail::widget_base { protected: @@ -182,7 +183,9 @@ namespace nana widget_object() : events_{ std::make_shared() }, scheme_{ API::dev::make_scheme() } - {} + { + static_assert(std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value, "The type DrawerTrigger must be derived from nana::drawer_trigger"); + } ~widget_object() { @@ -291,7 +294,7 @@ namespace nana };//end class widget_object /// Base class of all the classes defined as a non-graphics-buffer widget window. The second template parameter DrawerTrigger is always ignored.\see nana::panel - template + template //type DrawerTrigger must be derived from nana::drawer_trigger class widget_object: public detail::widget_base { protected: @@ -302,7 +305,9 @@ namespace nana widget_object() : events_{ std::make_shared() }, scheme_{ API::dev::make_scheme() } - {} + { + static_assert(std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value, "The type DrawerTrigger must be derived from nana::drawer_trigger"); + } ~widget_object() { @@ -355,7 +360,7 @@ namespace nana /// Base class of all the classes defined as a root window. \see nana::form - template + template //type DrawerTrigger must be derived from nana::drawer_trigger class widget_object: public detail::widget_base { protected: @@ -367,10 +372,12 @@ namespace nana widget_object() : widget_object(nullptr, false, API::make_center(300, 150), appearance(), this) { + static_assert(std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value, "The type DrawerTrigger must be derived from nana::drawer_trigger"); } widget_object(window owner, bool nested, const rectangle& r = {}, const appearance& apr = {}) { + static_assert(std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value, "The type DrawerTrigger must be derived from nana::drawer_trigger"); handle_ = API::dev::create_window(owner, nested, r, apr, this); _m_bind_and_attach(); } diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index da46d6ea..1a58ec6c 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -486,6 +486,7 @@ namespace detail atombase_.wm_protocols = ::XInternAtom(display_, "WM_PROTOCOLS", False); atombase_.wm_change_state = ::XInternAtom(display_, "WM_CHANGE_STATE", False); atombase_.wm_delete_window = ::XInternAtom(display_, "WM_DELETE_WINDOW", False); + atombase_.net_frame_extents = ::XInternAtom(display_, "_NET_FRAME_EXTENTS", False); atombase_.net_wm_state = ::XInternAtom(display_, "_NET_WM_STATE", False); atombase_.net_wm_state_skip_taskbar = ::XInternAtom(display_, "_NET_WM_STATE_SKIP_TASKBAR", False); atombase_.net_wm_state_fullscreen = ::XInternAtom(display_, "_NET_WM_STATE_FULLSCREEN", False); diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index 167295bb..a4755370 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -132,6 +132,7 @@ namespace detail Atom wm_change_state; Atom wm_delete_window; //ext + Atom net_frame_extents; Atom net_wm_state; Atom net_wm_state_skip_taskbar; Atom net_wm_state_fullscreen; diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index a69d5807..221d04c8 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -308,11 +308,11 @@ namespace nana { if (pi_data_->menu.window && (pi_data_->menu.window != wd)) { - wd = native_interface::get_owner_window(wd); + wd = native_interface::get_window(wd, window_relationship::owner); while (wd) { if (wd != pi_data_->menu.window) - wd = native_interface::get_owner_window(wd); + wd = native_interface::get_window(wd, window_relationship::owner); else return false; } @@ -329,7 +329,7 @@ namespace nana erase_menu(true); pi_data_->menu.window = menu_wd; - pi_data_->menu.owner = native_interface::get_owner_window(menu_wd); + pi_data_->menu.owner = native_interface::get_window(menu_wd, window_relationship::owner); pi_data_->menu.has_keyboard = has_keyboard; } } diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index abb38f11..62dd68ee 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -26,6 +26,9 @@ namespace nana { namespace detail { + //Declarations of helper functions defined in native_window_interface.cpp + void x11_apply_exposed_position(native_window_type wd); + #pragma pack(1) union event_mask { @@ -905,6 +908,9 @@ namespace detail break; case MapNotify: case UnmapNotify: + if(xevent.type == MapNotify) + x11_apply_exposed_position(native_window); + brock.event_expose(msgwnd, (xevent.type == MapNotify)); context.platform.motion_window = nullptr; break; @@ -1281,7 +1287,7 @@ namespace detail if(condition_wd && is_modal) { native_window_type modal = reinterpret_cast(condition_wd)->root; - owner_native = native_interface::get_owner_window(modal); + owner_native = native_interface::get_window(modal, window_relationship::owner); if(owner_native) { native_interface::enable_window(owner_native, false); diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index ed1e5772..1f683075 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-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 @@ -129,6 +129,140 @@ namespace nana{ { nana::detail::platform_spec & spec = nana::detail::platform_spec::instance(); } + + struct frame_extents + { + long left; + long right; + long top; + long bottom; + }; + + frame_extents x11_frame_extents(Window wd) + { + frame_extents fm_extents; + Atom type; + int format; + unsigned long len, bytes_left = 0; + unsigned char *data; + + if(Success == ::XGetWindowProperty(restrict::spec.open_display(), wd, + restrict::spec.atombase().net_frame_extents, 0, 16, 0, + XA_CARDINAL, &type, &format, + &len, &bytes_left, &data)) + { + if(type != None && len == 4) + { + fm_extents.left = ((long*)data)[0]; + fm_extents.right = ((long*)data)[1]; + fm_extents.top = ((long*)data)[2]; + fm_extents.bottom = ((long*)data)[3]; + } + ::XFree(data); + } + + return fm_extents; + } + + //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 + + //Returns the parent window. + //It may return a decoration frame window if the requested window is a top level and WM is a + //reparenting window manager. + native_window_type x11_parent_window(native_window_type wd) + { + Window root; + Window parent; + Window * children; + unsigned size; + + platform_scope_guard lock; + + if(0 != ::XQueryTree(restrict::spec.open_display(), reinterpret_cast(wd), + &root, &parent, &children, &size)) + { + ::XFree(children); + return reinterpret_cast(parent); + } + return nullptr; + } + + // Revise the position for moving window. Because the window is moved depending on + //implementation of Window Manager. A reparenting window may not be moved the origin to + //the specified location. it may be moved the left-top corner to the specified location. + void x11_revise_position(native_window_type wd, int &x, int& y) + { + auto const disp = restrict::spec.open_display(); + auto const owner = reinterpret_cast(restrict::spec.get_owner(wd)); + auto const root_wd = restrict::spec.root_window(); + + Window decoration_wd = 0; + if(owner) + { + Window child; + + if(owner != root_wd) + { + ::XTranslateCoordinates(disp, owner, root_wd, + x, y, &x, &y, &child); + } + + decoration_wd = reinterpret_cast(x11_parent_window(wd)); + if((decoration_wd == owner) || (decoration_wd == root_wd)) + decoration_wd = 0; + } + + if(decoration_wd) + { + auto fm_extents = x11_frame_extents(reinterpret_cast(wd)); + + XWindowAttributes attr; + ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); + + x += attr.x - fm_extents.left; + y += attr.y - fm_extents.top; + } + } + + void x11_apply_exposed_position(native_window_type wd) + { + nana::detail::platform_scope_guard lock; + + auto i = exposed_positions.find(reinterpret_cast(wd)); + if(i == exposed_positions.cend()) + return; + + native_interface::move_window(wd, i->second.x, i->second.y); + + exposed_positions.erase(i); + } + + namespace x11_wait + { + static Bool configure(Display *disp, XEvent *evt, char *arg) + { + return disp && evt && arg && (evt->type == ConfigureNotify) && (evt->xconfigure.window == *reinterpret_cast(arg)); + } + + static Bool map(Display *disp, XEvent *evt, char *arg) + { + return disp && evt && arg && (evt->type == MapNotify) && (evt->xmap.window == *reinterpret_cast(arg)); + } + + static Bool unmap(Display *disp, XEvent *evt, char *arg) + { + return disp && evt && arg && (evt->type == MapNotify) && (evt->xunmap.window == *reinterpret_cast(arg)); + } + } + + static void x11_wait_for(Window wd, Bool(*pred_fn)(Display*, XEvent*, char*)) + { + XEvent dummy; + ::XPeekIfEvent(restrict::spec.open_display(), &dummy, pred_fn, reinterpret_cast(&wd)); + } #endif //struct native_interface @@ -196,13 +330,6 @@ 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) { @@ -267,7 +394,7 @@ namespace nana{ XSetWindowAttributes win_attr; unsigned long attr_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | - CWWinGravity | CWBitGravity | CWColormap | CWEventMask; + CWColormap | CWEventMask; Display * disp = restrict::spec.open_display(); win_attr.colormap = restrict::spec.colormap(); @@ -276,8 +403,6 @@ namespace nana{ win_attr.background_pixel = 0xFFFFFF; win_attr.border_pixmap = None; win_attr.border_pixel = 0x0; - win_attr.bit_gravity = 0; - win_attr.win_gravity = NorthWestGravity; win_attr.backing_store = 0; win_attr.backing_planes = 0; win_attr.backing_pixel = 0; @@ -424,7 +549,7 @@ namespace nana{ XSetWindowAttributes win_attr; unsigned long attr_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | - CWWinGravity | CWBitGravity | CWColormap | CWEventMask; + CWColormap | CWEventMask | CWOverrideRedirect; Display * disp = restrict::spec.open_display(); win_attr.colormap = restrict::spec.colormap(); @@ -433,15 +558,12 @@ namespace nana{ win_attr.background_pixel = 0xFFFFFF; win_attr.border_pixmap = None; win_attr.border_pixel = 0x0; - win_attr.bit_gravity = 0; - win_attr.win_gravity = NorthWestGravity; win_attr.backing_store = 0; win_attr.backing_planes = 0; win_attr.backing_pixel = 0; win_attr.colormap = restrict::spec.colormap(); win_attr.override_redirect = True; - attr_mask |= CWOverrideRedirect; nana::point pos(r.x, r.y); win_attr.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ExposureMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask; @@ -671,21 +793,21 @@ namespace nana{ { ::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); - } + //Wait for the mapping notify to update the local attribute of visibility so that + //the followed window_visible() call can return the updated visibility value. + x11_wait_for(reinterpret_cast(wd), x11_wait::map); Window grab = restrict::spec.grab(0); if(grab == reinterpret_cast(wd)) capture_window(wd, true); } else + { ::XUnmapWindow(disp, reinterpret_cast(wd)); - - ::XFlush(disp); + //Wait for the mapping notify to update the local attribute of visibility so that + //the followed window_visible() call can return the updated visibility value. + x11_wait_for(reinterpret_cast(wd), x11_wait::unmap); + } } static_cast(active); //eliminate unused parameter compiler warning. #endif @@ -847,19 +969,24 @@ namespace nana{ } return nana::point(r.left, r.top); #elif defined(NANA_X11) - int x, y; - nana::detail::platform_scope_guard psg; - Window coord_wd = reinterpret_cast(restrict::spec.get_owner(wd)); - if(!coord_wd) + point scr_pos; + nana::detail::platform_scope_guard lock; + + auto coord_wd = restrict::spec.get_owner(wd); + if(coord_wd) { - coord_wd = reinterpret_cast(parent_window(wd)); - if(!coord_wd) - coord_wd = restrict::spec.root_window(); + //wd is a top level window. It returns the position of its decoration window. + auto decr = x11_parent_window(wd); + if(decr != coord_wd) + wd = decr; } + else + coord_wd = get_window(wd, window_relationship::parent); + Window child; - if(True == ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), coord_wd, 0, 0, &x, &y, &child)) - return nana::point(x, y); - return nana::point(0, 0); + ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), reinterpret_cast(coord_wd), 0, 0, &scr_pos.x, &scr_pos.y, &child); + + return scr_pos; #endif } @@ -890,21 +1017,21 @@ namespace nana{ #elif defined(NANA_X11) Display * disp = restrict::spec.open_display(); - nana::detail::platform_scope_guard psg; - Window owner = reinterpret_cast(restrict::spec.get_owner(wd)); - if(owner) - { - Window child; - ::XTranslateCoordinates(disp, owner, restrict::spec.root_window(), - x, y, &x, &y, &child); - } + nana::detail::platform_scope_guard lock; XWindowAttributes attr; ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); if(attr.map_state == IsUnmapped) exposed_positions[reinterpret_cast(wd)] = ::nana::point{x, y}; + + x11_revise_position(wd, x, y); + ::XMoveWindow(disp, reinterpret_cast(wd), x, y); + + //Wait for the configuration notify to update the local attribute of position so that + //the followed window_position() call can return the updated position value. + x11_wait_for(reinterpret_cast(wd), x11_wait::configure); #endif } @@ -954,16 +1081,6 @@ namespace nana{ else hints.flags = 0; - Window owner = reinterpret_cast(restrict::spec.get_owner(wd)); - int x = r.x; - int y = r.y; - if(owner) - { - Window child; - ::XTranslateCoordinates(disp, owner, restrict::spec.root_window(), - r.x, r.y, &x, &y, &child); - } - XWindowAttributes attr; ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); if(attr.map_state == IsUnmapped) @@ -972,13 +1089,24 @@ namespace nana{ hints.width = r.width; hints.height = r.height; - exposed_positions[reinterpret_cast(wd)] = point{x, y}; + exposed_positions[reinterpret_cast(wd)] = r.position(); } if(hints.flags) ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); + int x = r.x; + int y = r.y; + x11_revise_position(wd, x, y); ::XMoveResizeWindow(disp, reinterpret_cast(wd), x, y, r.width, r.height); + + //Wait for the configuration notify to update the local attribute of position so that + //the followed window_position() call can return the updated position value. + + //It seems that XMoveResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called + //to make sure the local attribute is updated. + x11_wait_for(reinterpret_cast(wd), x11_wait::configure); + return true; #endif } @@ -1096,6 +1224,10 @@ namespace nana{ ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); } ::XResizeWindow(disp, reinterpret_cast(wd), sz.width, sz.height); + + //It seems that XResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called + //to make sure the local attribute is updated. + x11_wait_for(reinterpret_cast(wd), x11_wait::configure); return true; #endif } @@ -1231,34 +1363,29 @@ namespace nana{ #endif } - native_window_type native_interface::get_owner_window(native_window_type wd) - { -#if defined(NANA_WINDOWS) - return reinterpret_cast(::GetWindow(reinterpret_cast(wd), GW_OWNER)); -#elif defined(NANA_X11) - return restrict::spec.get_owner(wd); -#endif - } - - native_window_type native_interface::parent_window(native_window_type wd) + native_window_type native_interface::get_window(native_window_type wd, window_relationship rsp) { #ifdef NANA_WINDOWS - return reinterpret_cast(::GetParent(reinterpret_cast(wd))); + if(window_relationship::either_po == rsp) + return reinterpret_cast(::GetParent(reinterpret_cast(wd))); + else if(window_relationship::parent == rsp) + return reinterpret_cast(::GetAncestor(reinterpret_cast(wd), GA_PARENT)); + else if(window_relationship::owner == rsp) + return reinterpret_cast(::GetWindow(reinterpret_cast(wd), GW_OWNER)); #elif defined(NANA_X11) - Window root; - Window parent; - Window * children; - unsigned size; - platform_scope_guard lock; - if(0 != ::XQueryTree(restrict::spec.open_display(), reinterpret_cast(wd), - &root, &parent, &children, &size)) + auto owner = restrict::spec.get_owner(wd); + + if(window_relationship::either_po == rsp) { - ::XFree(children); - return reinterpret_cast(parent); + if(owner) + return owner; } - return nullptr; + else if(window_relationship::owner == rsp) + return owner; + + return x11_parent_window(wd); #endif } @@ -1279,7 +1406,7 @@ namespace nana{ platform_scope_guard lock; if(returns_previous) - prev = parent_window(child); + prev = get_window(child, window_relationship::either_po); if(native_window_type{} == new_parent) new_parent = reinterpret_cast(restrict::spec.root_window()); diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 374b4250..09b1e99c 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -669,7 +669,7 @@ namespace API internal_scope_guard lock; if(restrict::wd_manager().available(iwd) && (iwd->other.category == category::flags::root)) { - auto owner = interface_type::get_owner_window(iwd->root); + auto owner = interface_type::get_window(iwd->root, window_relationship::owner); if(owner) return reinterpret_cast(restrict::wd_manager().root(owner)); } diff --git a/source/gui/widgets/group.cpp b/source/gui/widgets/group.cpp index 21a9ffe0..8be557ef 100644 --- a/source/gui/widgets/group.cpp +++ b/source/gui/widgets/group.cpp @@ -267,7 +267,7 @@ namespace nana{ //When the group is resized, the drawing is called before moving the caption, but //the drawing of group requires the lastest position of caption for gradual rectangle. //For the requirement, a move event handler is required for listning the change of caption's position. - impl_->caption.events().move([this](const arg_move& arg){ + impl_->caption.events().move([this](const arg_move&){ if (align::left != impl_->caption_align) API::refresh_window(*this); }); From e91d3446eb3cc908444ed0122ff87511646494a2 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 9 Aug 2018 07:50:56 +0800 Subject: [PATCH 16/34] fix GCC errors when -std=c++17 is specified --- include/nana/gui/detail/general_events.hpp | 4 +- source/gui/detail/native_window_interface.cpp | 5 +- source/paint/graphics.cpp | 55 ++++++++++--------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 0a4881b4..9a9496e2 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -172,7 +172,7 @@ namespace nana } else if constexpr(std::is_invocable_v) { - return _m_emplace(new docker{ this, [fn](arg_reference){ + return _m_emplace(new docker{ this, [fn](arg_reference) mutable{ fn(); }, false }, false); } @@ -200,7 +200,7 @@ namespace nana } else if constexpr(std::is_invocable_v) { - return _m_emplace(new docker{ this, [fn](arg_reference) { + return _m_emplace(new docker{ this, [fn](arg_reference) mutable{ fn(); }, true }, in_front); } diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 1f683075..d922fe44 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -1384,9 +1384,10 @@ namespace nana{ } else if(window_relationship::owner == rsp) return owner; - - return x11_parent_window(wd); + else if(window_relationship::parent == rsp) + return x11_parent_window(wd); #endif + return nullptr; } native_window_type native_interface::parent_window(native_window_type child, native_window_type new_parent, bool returns_previous) diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index fbf07358..004a34a5 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -498,41 +498,42 @@ namespace paint { if (nullptr == impl_->handle || nullptr == impl_->handle->context) return {}; - if (text.empty()) return std::unique_ptr{new unsigned[1]}; + auto pxbuf = std::unique_ptr{ new unsigned[text.size() ? text.size() : 1] }; - unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; -#if defined(NANA_WINDOWS) - int * dx = new int[text.size()]; - SIZE extents; - ::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast(text.size()), 0, 0, dx, &extents); - - auto pxbuf = std::unique_ptr{ new unsigned[text.size()] }; - - pxbuf[0] = (text[0] == '\t' ? tab_pixels : dx[0]); - - for (std::size_t i = 1; i < text.size(); ++i) + if (!text.empty()) { - pxbuf[i] = (text[i] == '\t' ? tab_pixels : dx[i] - dx[i - 1]); - } - delete[] dx; + unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; +#if defined(NANA_WINDOWS) + int * dx = new int[text.size()]; + SIZE extents; + ::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast(text.size()), 0, 0, dx, &extents); + + pxbuf[0] = (text[0] == '\t' ? tab_pixels : dx[0]); + + for (std::size_t i = 1; i < text.size(); ++i) + { + pxbuf[i] = (text[i] == '\t' ? tab_pixels : dx[i] - dx[i - 1]); + } + delete[] dx; #elif defined(NANA_X11) && defined(NANA_USE_XFT) - auto disp = nana::detail::platform_spec::instance().open_display(); - auto xft = reinterpret_cast(impl_->handle->font->native_handle()); + auto disp = nana::detail::platform_spec::instance().open_display(); + auto xft = reinterpret_cast(impl_->handle->font->native_handle()); - XGlyphInfo extents; - for (std::size_t i = 0; i < len; ++i) - { - if (text[i] != '\t') + XGlyphInfo extents; + for (std::size_t i = 0; i < text.size(); ++i) { - FT_UInt glyphs = ::XftCharIndex(disp, xft, text[i]); - ::XftGlyphExtents(disp, xft, &glyphs, 1, &extents); - pxbuf[i] = extents.xOff; + if (text[i] != '\t') + { + FT_UInt glyphs = ::XftCharIndex(disp, xft, text[i]); + ::XftGlyphExtents(disp, xft, &glyphs, 1, &extents); + pxbuf[i] = extents.xOff; + } + else + pxbuf[i] = tab_pixels; } - else - pxbuf[i] = tab_pixels; - } #endif + } return pxbuf; } From 6ab867072d0da9d6836ea7762a8ea489b2cbc2b4 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 9 Aug 2018 07:54:26 +0800 Subject: [PATCH 17/34] implement API::window_outline_size for X11 --- .../gui/detail/native_window_interface.hpp | 9 +++ source/gui/detail/native_window_interface.cpp | 73 ++++++++++--------- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp index e2a997c6..dac3fa97 100644 --- a/include/nana/gui/detail/native_window_interface.hpp +++ b/include/nana/gui/detail/native_window_interface.hpp @@ -36,6 +36,14 @@ namespace detail unsigned extra_height; //extra border size, it is useful in Windows, ignore in X11 always 0 }; + struct frame_extents + { + int left; + int right; + int top; + int bottom; + }; + using native_string_type = ::nana::detail::native_string_type; //Execute a function in a thread which is associated with the specified native window. @@ -70,6 +78,7 @@ namespace detail static void bring_top(native_window_type, bool activated); static void set_window_z_order(native_window_type, native_window_type wd_after, z_order_action action_if_no_wd_after); + static frame_extents window_frame_extents(native_window_type); static bool window_size(native_window_type, const size&); static void get_window_rect(native_window_type, rectangle&); static void window_caption(native_window_type, const native_string_type&); diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index d922fe44..a749fd07 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -130,39 +130,6 @@ namespace nana{ nana::detail::platform_spec & spec = nana::detail::platform_spec::instance(); } - struct frame_extents - { - long left; - long right; - long top; - long bottom; - }; - - frame_extents x11_frame_extents(Window wd) - { - frame_extents fm_extents; - Atom type; - int format; - unsigned long len, bytes_left = 0; - unsigned char *data; - - if(Success == ::XGetWindowProperty(restrict::spec.open_display(), wd, - restrict::spec.atombase().net_frame_extents, 0, 16, 0, - XA_CARDINAL, &type, &format, - &len, &bytes_left, &data)) - { - if(type != None && len == 4) - { - fm_extents.left = ((long*)data)[0]; - fm_extents.right = ((long*)data)[1]; - fm_extents.top = ((long*)data)[2]; - fm_extents.bottom = ((long*)data)[3]; - } - ::XFree(data); - } - - return fm_extents; - } //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 @@ -1186,6 +1153,46 @@ namespace nana{ #endif } + native_interface::frame_extents native_interface::window_frame_extents(native_window_type wd) + { + frame_extents fm_extents{0, 0, 0, 0}; + + #if defined(NANA_WINDOWS) + ::RECT client; + ::GetClientRect(reinterpret_cast(wd), &client); //The right and bottom of client by GetClientRect indicate the width and height of the area + ::RECT wd_area; + ::GetWindowRect(reinterpret_cast(wd), &wd_area); + + fm_extents.left = client.left - wd_area.left; + fm_extents.right = wd_area.right - client.right; + fm_extents.top = client.top - wd_area.top; + fm_extents.bottom = wd_area.bottom - client.bottom; + #elif defined(NANA_X11) + Atom type; + int format; + unsigned long len, bytes_left = 0; + unsigned char *data; + + nana::detail::platform_scope_guard lock; + if(Success == ::XGetWindowProperty(restrict::spec.open_display(), reinterpret_cast(wd), + restrict::spec.atombase().net_frame_extents, 0, 16, 0, + XA_CARDINAL, &type, &format, + &len, &bytes_left, &data)) + { + if(type != None && len == 4) + { + fm_extents.left = ((long*)data)[0]; + fm_extents.right = ((long*)data)[1]; + fm_extents.top = ((long*)data)[2]; + fm_extents.bottom = ((long*)data)[3]; + } + ::XFree(data); + } + #endif + + return fm_extents; + } + bool native_interface::window_size(native_window_type wd, const size& sz) { #if defined(NANA_WINDOWS) From 30fba6e4a497f1daec94072f4e752769e21ba39b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 9 Aug 2018 07:56:32 +0800 Subject: [PATCH 18/34] fix bug that wroing window position in X11 --- source/gui/detail/native_window_interface.cpp | 159 +++++++++++++++--- source/gui/programming_interface.cpp | 25 ++- 2 files changed, 160 insertions(+), 24 deletions(-) diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index a749fd07..a8c86c1a 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -157,42 +157,113 @@ namespace nana{ return nullptr; } + native_window_type x11_decoration_frame(native_window_type wd) + { + auto const owner = restrict::spec.get_owner(wd); + auto const root_wd = restrict::spec.root_window(); + + if(owner) + { + auto test_wd = wd; + while(true) + { + auto upper = x11_parent_window(test_wd); + if((reinterpret_cast(upper) != root_wd) && (upper != owner)) + { + test_wd = upper; + } + else if(wd != test_wd) + return test_wd; + else + return nullptr; + } + } + + return nullptr; + } + // Revise the position for moving window. Because the window is moved depending on //implementation of Window Manager. A reparenting window may not be moved the origin to //the specified location. it may be moved the left-top corner to the specified location. - void x11_revise_position(native_window_type wd, int &x, int& y) + +#if 0 + void x11_revise_position(native_window_type wd, int &x, int& y, bool written) { auto const disp = restrict::spec.open_display(); auto const owner = reinterpret_cast(restrict::spec.get_owner(wd)); auto const root_wd = restrict::spec.root_window(); - Window decoration_wd = 0; - if(owner) + if(written) { - Window child; - - if(owner != root_wd) + Window decoration_wd = 0; + if(owner) { - ::XTranslateCoordinates(disp, owner, root_wd, - x, y, &x, &y, &child); + Window child; + + if(owner != root_wd) + { + ::XTranslateCoordinates(disp, owner, root_wd, + x, y, &x, &y, &child); + } + + decoration_wd = reinterpret_cast(x11_parent_window(wd)); + if((decoration_wd == owner) || (decoration_wd == root_wd)) + decoration_wd = 0; } - decoration_wd = reinterpret_cast(x11_parent_window(wd)); - if((decoration_wd == owner) || (decoration_wd == root_wd)) - decoration_wd = 0; - } + if(decoration_wd) + { + auto fm_extents = native_interface::window_frame_extents(wd); - if(decoration_wd) - { - auto fm_extents = x11_frame_extents(reinterpret_cast(wd)); + XWindowAttributes attr; + ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); - XWindowAttributes attr; - ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); - - x += attr.x - fm_extents.left; - y += attr.y - fm_extents.top; + x += attr.x - fm_extents.left; + y += attr.y - fm_extents.top; + } } } +#else + void x11_revise_position(native_window_type wd, int &x, int& y, bool written) + { + return; + auto const disp = restrict::spec.open_display(); + auto const root_wd = restrict::spec.root_window(); + + if(written) + { + auto decoration_wd = x11_decoration_frame(wd); + + + if(decoration_wd) + { + auto const owner = reinterpret_cast(restrict::spec.get_owner(wd)); + Window child; + ::XTranslateCoordinates(disp, owner, root_wd, + x, y, &x, &y, &child); + + + auto fm_extents = native_interface::window_frame_extents(wd); + + XWindowAttributes attr; + ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); + + point client_pos{0, 0}; + ::XTranslateCoordinates(disp, reinterpret_cast(wd), root_wd, 0, 0, &client_pos.x, &client_pos.y, &child); + + point decoration_pos{0, 0}; + ::XTranslateCoordinates(disp, reinterpret_cast(decoration_wd), root_wd, 0, 0, &decoration_pos.x, &decoration_pos.y, &child); + + auto x1 = (client_pos.x - decoration_pos.x - fm_extents.left); + auto y1 = (client_pos.y - decoration_pos.y - fm_extents.top); + + return; + x -= (client_pos.x - decoration_pos.x - fm_extents.left); + y -= (client_pos.y - decoration_pos.y - fm_extents.top); + } + } + } +#endif void x11_apply_exposed_position(native_window_type wd) { @@ -939,6 +1010,7 @@ namespace nana{ point scr_pos; nana::detail::platform_scope_guard lock; +#if 0 auto coord_wd = restrict::spec.get_owner(wd); if(coord_wd) { @@ -953,6 +1025,32 @@ namespace nana{ Window child; ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), reinterpret_cast(coord_wd), 0, 0, &scr_pos.x, &scr_pos.y, &child); + x11_revise_position(wd, scr_pos.x, scr_pos.y, false); +#else + point origin{}; + + auto coord_wd = restrict::spec.get_owner(wd); + if(coord_wd) + { + auto fm_extents = window_frame_extents(wd); + origin.x = -fm_extents.left; + origin.y = -fm_extents.top; + + if(reinterpret_cast(coord_wd) != restrict::spec.root_window()) + { + fm_extents = window_frame_extents(coord_wd); + origin.x += fm_extents.left; + origin.y += fm_extents.top; + } + } + else + coord_wd = get_window(wd, window_relationship::parent); + + Window child; + ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), reinterpret_cast(coord_wd), origin.x, origin.y, &scr_pos.x, &scr_pos.y, &child); + +#endif + return scr_pos; #endif } @@ -991,8 +1089,16 @@ namespace nana{ if(attr.map_state == IsUnmapped) exposed_positions[reinterpret_cast(wd)] = ::nana::point{x, y}; + auto const owner = restrict::spec.get_owner(wd); + if(owner && (owner != reinterpret_cast(restrict::spec.root_window()))) + { + auto fm_extents = window_frame_extents(owner); + auto origin = window_position(owner); + x += origin.x; + y += origin.y; + } - x11_revise_position(wd, x, y); + x11_revise_position(wd, x, y, true); ::XMoveWindow(disp, reinterpret_cast(wd), x, y); @@ -1064,7 +1170,16 @@ namespace nana{ int x = r.x; int y = r.y; - x11_revise_position(wd, x, y); + + auto const owner = restrict::spec.get_owner(wd); + if(owner && (owner != reinterpret_cast(restrict::spec.root_window()))) + { + auto origin = window_position(owner); + x += origin.x; + y += origin.y; + } + + x11_revise_position(wd, x, y, true); ::XMoveResizeWindow(disp, reinterpret_cast(wd), x, y, r.width, r.height); //Wait for the configuration notify to update the local attribute of position so that diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 09b1e99c..30f33e9a 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -812,8 +812,14 @@ namespace API return{}; auto sz = window_size(wd); - sz.width += iwd->extra_width; - sz.height += iwd->extra_height; + + if(category::flags::root == iwd->other.category) + { + auto fm_extents = interface_type::window_frame_extents(iwd->root); + sz.width += fm_extents.left + fm_extents.right; + sz.height += fm_extents.top + fm_extents.bottom; + } + return sz; } @@ -825,7 +831,11 @@ namespace API { if (category::flags::root == iwd->other.category) { + auto fm_extents = interface_type::window_frame_extents(iwd->root); + size inner_size = sz; + +#if 0 if (inner_size.width < iwd->extra_width) inner_size.width = 0; else @@ -835,6 +845,17 @@ namespace API inner_size.height = 0; else inner_size.height -= iwd->extra_height; +#else + if (inner_size.width < static_cast(fm_extents.left + fm_extents.right)) + inner_size.width = 0; + else + inner_size.width -= static_cast(fm_extents.left + fm_extents.right); + + if (inner_size.height < static_cast(fm_extents.top + fm_extents.bottom)) + inner_size.height = 0; + else + inner_size.height -= static_cast(fm_extents.top + fm_extents.bottom); +#endif window_size(wd, inner_size); } From 9bd6e0a2b0aec8090a345411713bd6ed2babc03f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 10 Aug 2018 08:27:17 +0800 Subject: [PATCH 19/34] fix GCC diagnostic --- include/nana/pop_ignore_diagnostic | 2 +- include/nana/push_ignore_diagnostic | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nana/pop_ignore_diagnostic b/include/nana/pop_ignore_diagnostic index 23c39a69..ff563550 100644 --- a/include/nana/pop_ignore_diagnostic +++ b/include/nana/pop_ignore_diagnostic @@ -1,5 +1,5 @@ -#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) # pragma GCC diagnostic pop #endif diff --git a/include/nana/push_ignore_diagnostic b/include/nana/push_ignore_diagnostic index 9ba463ad..4931e9db 100644 --- a/include/nana/push_ignore_diagnostic +++ b/include/nana/push_ignore_diagnostic @@ -1,4 +1,4 @@ -#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Weffc++" #endif From 04e57771a4b205e5934c75f31aa7f8da3894881f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 10 Aug 2018 23:35:11 +0800 Subject: [PATCH 20/34] eliminate GCC warings when -Wimplicit-fallthrough is enabled --- source/detail/posix/msg_dispatcher.hpp | 4 +- source/gui/detail/bedrock_posix.cpp | 65 +++++++++++ source/gui/detail/native_window_interface.cpp | 104 ------------------ source/gui/place.cpp | 46 ++++---- source/gui/place_parts.hpp | 18 ++- source/gui/widgets/combox.cpp | 12 +- source/gui/widgets/listbox.cpp | 7 +- 7 files changed, 113 insertions(+), 143 deletions(-) diff --git a/source/detail/posix/msg_dispatcher.hpp b/source/detail/posix/msg_dispatcher.hpp index 8aed6ce5..6bef753e 100644 --- a/source/detail/posix/msg_dispatcher.hpp +++ b/source/detail/posix/msg_dispatcher.hpp @@ -1,6 +1,6 @@ /* * Message Dispatcher 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 @@ -221,6 +221,8 @@ namespace detail case 0: msg_pack.kind = msg_pack.kind_xevent; msg_pack.u.xevent = event; + _m_msg_dispatch(msg_pack); + break; case 1: _m_msg_dispatch(msg_pack); } diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 62dd68ee..debbbfee 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -575,6 +575,62 @@ namespace detail return true; } + void x_lookup_chars(const root_misc* rruntime, basic_window * msgwd, char* keybuf, std::size_t keybuf_len, const arg_keyboard& modifiers_status) + { + if (!msgwd->flags.enabled) + return; + + static auto& brock = detail::bedrock::instance(); + auto & wd_manager = brock.wd_manager(); + + auto& context = *brock.get_thread_context(msgwd->thread_id); + + auto const native_window = rruntime->window->root; + + + nana::detail::charset_conv charset(NANA_UNICODE, "UTF-8"); + const std::string& str = charset.charset(std::string(keybuf, keybuf + keybuf_len)); + auto const charbuf = reinterpret_cast(str.c_str()); + auto const len = str.size() / sizeof(wchar_t); + + for(std::size_t i = 0; i < len; ++i) + { + arg_keyboard arg = modifiers_status; + arg.ignore = false; + arg.key = charbuf[i]; + + // ignore Unicode BOM (it may or may not appear) + if (arg.key == 0xFEFF) continue; + + //Only accept tab when it is not ignored. + if ((keyboard::tab == arg.key) && rruntime->condition.ignore_tab) + continue; + + if(context.is_alt_pressed) + { + arg.ctrl = arg.shift = false; + arg.evt_code = event_code::shortkey; + brock.shortkey_occurred(true); + auto shr_wd = wd_manager.find_shortkey(native_window, arg.key); + if(shr_wd) + { + arg.window_handle = reinterpret_cast(shr_wd); + brock.emit(event_code::shortkey, shr_wd, arg, true, &context); + } + continue; + } + + arg.evt_code = event_code::key_char; + arg.window_handle = reinterpret_cast(msgwd); + msgwd->annex.events_ptr->key_char.emit(arg, reinterpret_cast(msgwd)); + if(arg.ignore == false && wd_manager.available(msgwd)) + draw_invoker(&drawer::key_char, msgwd, arg, &context); + } + + if(brock.shortkey_occurred(false)) + context.is_alt_pressed = false; + } + void window_proc_for_xevent(Display* /*display*/, XEvent& xevent) { typedef detail::bedrock::core_window_t core_window_t; @@ -1077,6 +1133,8 @@ namespace detail wd_manager.do_lazy_refresh(msgwnd, false); break; } +#if 0 + //Fall through case XLookupChars: if (msgwnd->flags.enabled) { @@ -1124,6 +1182,13 @@ namespace detail context.is_alt_pressed = false; } break; +#else + x_lookup_chars(root_runtime, msgwnd, keybuf, len, modifiers_status); + break; + case XLookupChars: + x_lookup_chars(root_runtime, msgwnd, keybuf, len, modifiers_status); + break; +#endif } wd_manager.do_lazy_refresh(msgwnd, false); diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index a8c86c1a..3fc6fcaf 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -182,88 +182,6 @@ namespace nana{ return nullptr; } - // Revise the position for moving window. Because the window is moved depending on - //implementation of Window Manager. A reparenting window may not be moved the origin to - //the specified location. it may be moved the left-top corner to the specified location. - -#if 0 - void x11_revise_position(native_window_type wd, int &x, int& y, bool written) - { - auto const disp = restrict::spec.open_display(); - auto const owner = reinterpret_cast(restrict::spec.get_owner(wd)); - auto const root_wd = restrict::spec.root_window(); - - if(written) - { - Window decoration_wd = 0; - if(owner) - { - Window child; - - if(owner != root_wd) - { - ::XTranslateCoordinates(disp, owner, root_wd, - x, y, &x, &y, &child); - } - - decoration_wd = reinterpret_cast(x11_parent_window(wd)); - if((decoration_wd == owner) || (decoration_wd == root_wd)) - decoration_wd = 0; - } - - if(decoration_wd) - { - auto fm_extents = native_interface::window_frame_extents(wd); - - XWindowAttributes attr; - ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); - - x += attr.x - fm_extents.left; - y += attr.y - fm_extents.top; - } - } - } -#else - void x11_revise_position(native_window_type wd, int &x, int& y, bool written) - { - return; - auto const disp = restrict::spec.open_display(); - auto const root_wd = restrict::spec.root_window(); - - if(written) - { - auto decoration_wd = x11_decoration_frame(wd); - - - if(decoration_wd) - { - auto const owner = reinterpret_cast(restrict::spec.get_owner(wd)); - Window child; - ::XTranslateCoordinates(disp, owner, root_wd, - x, y, &x, &y, &child); - - - auto fm_extents = native_interface::window_frame_extents(wd); - - XWindowAttributes attr; - ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); - - point client_pos{0, 0}; - ::XTranslateCoordinates(disp, reinterpret_cast(wd), root_wd, 0, 0, &client_pos.x, &client_pos.y, &child); - - point decoration_pos{0, 0}; - ::XTranslateCoordinates(disp, reinterpret_cast(decoration_wd), root_wd, 0, 0, &decoration_pos.x, &decoration_pos.y, &child); - - auto x1 = (client_pos.x - decoration_pos.x - fm_extents.left); - auto y1 = (client_pos.y - decoration_pos.y - fm_extents.top); - - return; - x -= (client_pos.x - decoration_pos.x - fm_extents.left); - y -= (client_pos.y - decoration_pos.y - fm_extents.top); - } - } - } -#endif void x11_apply_exposed_position(native_window_type wd) { @@ -1010,23 +928,7 @@ namespace nana{ point scr_pos; nana::detail::platform_scope_guard lock; -#if 0 - auto coord_wd = restrict::spec.get_owner(wd); - if(coord_wd) - { - //wd is a top level window. It returns the position of its decoration window. - auto decr = x11_parent_window(wd); - if(decr != coord_wd) - wd = decr; - } - else - coord_wd = get_window(wd, window_relationship::parent); - Window child; - ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), reinterpret_cast(coord_wd), 0, 0, &scr_pos.x, &scr_pos.y, &child); - - x11_revise_position(wd, scr_pos.x, scr_pos.y, false); -#else point origin{}; auto coord_wd = restrict::spec.get_owner(wd); @@ -1049,8 +951,6 @@ namespace nana{ Window child; ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), reinterpret_cast(coord_wd), origin.x, origin.y, &scr_pos.x, &scr_pos.y, &child); -#endif - return scr_pos; #endif } @@ -1092,14 +992,11 @@ namespace nana{ auto const owner = restrict::spec.get_owner(wd); if(owner && (owner != reinterpret_cast(restrict::spec.root_window()))) { - auto fm_extents = window_frame_extents(owner); auto origin = window_position(owner); x += origin.x; y += origin.y; } - x11_revise_position(wd, x, y, true); - ::XMoveWindow(disp, reinterpret_cast(wd), x, y); //Wait for the configuration notify to update the local attribute of position so that @@ -1179,7 +1076,6 @@ namespace nana{ y += origin.y; } - x11_revise_position(wd, x, y, true); ::XMoveResizeWindow(disp, reinterpret_cast(wd), x, y, r.width, r.height); //Wait for the configuration notify to update the local attribute of position so that diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 96d7ac6d..5b22491e 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -798,17 +798,20 @@ namespace nana case number_t::kind::real: return static_cast(number.real()); case number_t::kind::percent: - adjustable_px = area_px * number.real(); case number_t::kind::none: - { - auto fpx = adjustable_px + precise_px; - auto px = static_cast(fpx); - precise_px = fpx - px; - return px; - } break; + default: + return 0; //Useless } - return 0; //Useless + + if(number_t::kind::percent == number.kind_of()) + adjustable_px = area_px * number.real() + precise_px; + else + adjustable_px += precise_px; + + auto const px = static_cast(adjustable_px); + precise_px = adjustable_px - px; + return px; } std::pair calc_weight_floor() @@ -2879,25 +2882,26 @@ namespace nana } field_gather * attached_field = nullptr; - if (name.size()) + + //find the field with specified name. + //the field may not be created. + auto i = fields.find(name); + if (fields.end() != i) { - //find the field with specified name. - //the field may not be created. - auto i = fields.find(name); - if (fields.end() != i) - { - attached_field = i->second; - //the field is attached to a division, it means there is another division with same name. - if (attached_field->attached) - throw std::runtime_error("place, the name '" + name + "' is redefined."); - } + attached_field = i->second; + //the field is attached to a division, it means there is another division with same name. + if (attached_field->attached) + throw std::runtime_error("place, the name '" + name + "' is redefined."); } token unmatch = token::width; switch (div_type) { - case token::eof: unmatch = token::height; // "horitontal" div - case token::vert: // "vertical" div + case token::eof: // "horitontal" div + case token::vert: // "vertical" div + if(token::eof == div_type) + unmatch = token::height; + for (auto& ch : children) if (ch->weigth_type == unmatch) throw std::invalid_argument("nana.place: unmatch vertical-heigth/horizontal-width betwen division '" diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index b17be9cd..ca2ea8d7 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -1,7 +1,7 @@ /* * Parts of Class Place * 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 @@ -607,12 +607,16 @@ namespace nana it = ib = 0; il = ir = 1; break; - default: - il = 3; //left case 3: //top, right, bottom it = 0; ir = 1; ib = 2; + break; + default: //left, top, right, bottom, left + it = 0; + ir = 1; + ib = 2; + il = 3; } int pos = 0; @@ -661,12 +665,16 @@ namespace nana it = ib = 0; il = ir = 1; break; - default: - il = 3; //left case 3: //top, right, bottom it = 0; ir = 1; ib = 2; + break; + default: //left, top, right, bottom, left + it = 0; + ir = 1; + ib = 2; + il = 3; } using px_type = decltype(r.height); diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index dcaf5c43..56ce8b55 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -1,7 +1,7 @@ /* * A Combox 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 @@ -732,7 +732,6 @@ namespace nana bool call_other_keys = false; if(drawer_->editable()) { - bool is_move_up = false; switch(arg.key) { case keyboard::os_arrow_left: @@ -741,9 +740,8 @@ namespace nana drawer_->editor()->reset_caret(); break; case keyboard::os_arrow_up: - is_move_up = true; case keyboard::os_arrow_down: - drawer_->move_items(is_move_up, true); + drawer_->move_items((keyboard::os_arrow_up == arg.key), true); break; default: call_other_keys = true; @@ -751,15 +749,15 @@ namespace nana } else { - bool is_move_up = false; switch(arg.key) { case keyboard::os_arrow_left: case keyboard::os_arrow_up: - is_move_up = true; + drawer_->move_items(true, true); + break; case keyboard::os_arrow_right: case keyboard::os_arrow_down: - drawer_->move_items(is_move_up, true); + drawer_->move_items(false, true); break; default: call_other_keys = true; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 05b9687f..f25ac277 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -4477,14 +4477,11 @@ namespace nana if (list.first().empty()) return; - bool upward = false; - switch(arg.key) { case keyboard::os_arrow_up: - upward = true; case keyboard::os_arrow_down: - list.move_select(upward, !arg.shift, true); + list.move_select((keyboard::os_arrow_up == arg.key), !arg.shift, true); break; case L' ': { @@ -4496,9 +4493,9 @@ namespace nana } break; case keyboard::os_pageup : - upward = true; case keyboard::os_pagedown: { + auto const upward = (keyboard::os_pageup == arg.key); 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]); From a5f0d013c5562b19246906afe3f6b713c0962ca3 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 11 Aug 2018 00:46:07 +0800 Subject: [PATCH 21/34] volatile varibles in favor of std::atmoc<> --- include/nana/audio/detail/buffer_preparation.hpp | 6 ++++-- include/nana/pat/cloneable.hpp | 2 +- include/nana/system/timepiece.hpp | 10 +++++----- source/detail/posix/msg_dispatcher.hpp | 3 ++- source/detail/posix/platform_spec.hpp | 3 ++- source/system/timepiece.cpp | 8 ++++---- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/nana/audio/detail/buffer_preparation.hpp b/include/nana/audio/detail/buffer_preparation.hpp index 57e6f32e..7272d9b1 100644 --- a/include/nana/audio/detail/buffer_preparation.hpp +++ b/include/nana/audio/detail/buffer_preparation.hpp @@ -23,6 +23,8 @@ #include #endif +#include + namespace nana{ namespace audio { namespace detail @@ -52,8 +54,8 @@ namespace nana{ namespace audio private: void _m_prepare_routine(); private: - volatile bool running_; - volatile bool wait_for_buffer_; + std::atomic running_; + std::atomic wait_for_buffer_; std::thread thr_; mutable std::mutex token_buffer_, token_prepared_; mutable std::condition_variable cond_buffer_, cond_prepared_; diff --git a/include/nana/pat/cloneable.hpp b/include/nana/pat/cloneable.hpp index 350dbe1a..60d691f6 100644 --- a/include/nana/pat/cloneable.hpp +++ b/include/nana/pat/cloneable.hpp @@ -193,7 +193,7 @@ namespace nana{ namespace pat{ cwrapper_.reset(); } - operator operator_bool_t() const volatile noexcept + operator operator_bool_t() const noexcept { return (fast_ptr_ ? &inner_bool::true_stand : nullptr); } diff --git a/include/nana/system/timepiece.hpp b/include/nana/system/timepiece.hpp index fe188f45..248a798e 100644 --- a/include/nana/system/timepiece.hpp +++ b/include/nana/system/timepiece.hpp @@ -1,6 +1,6 @@ /* * Timepiece 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 @@ -21,11 +21,11 @@ namespace system { public: timepiece(); - timepiece(const volatile timepiece&); + timepiece(const timepiece&); ~timepiece(); - timepiece & operator=(const volatile timepiece &); - void start() volatile; ///< Set the begin time. - double calc() const volatile; ///< Get the intervals from the begin time. + timepiece & operator=(const timepiece &); + void start() noexcept; ///< Set the begin time. + double calc() const noexcept; ///< Get the intervals from the begin time. private: struct impl_t; impl_t * impl_; diff --git a/source/detail/posix/msg_dispatcher.hpp b/source/detail/posix/msg_dispatcher.hpp index 6bef753e..9ba12ad1 100644 --- a/source/detail/posix/msg_dispatcher.hpp +++ b/source/detail/posix/msg_dispatcher.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace nana { @@ -340,7 +341,7 @@ namespace detail private: Display * display_; - volatile bool is_work_{ false }; + std::atomic is_work_{ false }; std::unique_ptr thrd_; struct table_tag diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index a4755370..3191ddb1 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -20,6 +20,7 @@ #include +#include #include #include #include @@ -268,7 +269,7 @@ namespace detail std::recursive_mutex xlib_locker_; struct caret_holder_tag { - volatile bool exit_thread; + std::atomic exit_thread; std::unique_ptr thr; std::map carets; }caret_holder_; diff --git a/source/system/timepiece.cpp b/source/system/timepiece.cpp index fb2f71b9..e8f98d24 100644 --- a/source/system/timepiece.cpp +++ b/source/system/timepiece.cpp @@ -24,7 +24,7 @@ namespace system : impl_(new impl_t) {} - timepiece::timepiece(const volatile timepiece& rhs) + timepiece::timepiece(const timepiece& rhs) : impl_(new impl_t(*rhs.impl_)) {} @@ -33,7 +33,7 @@ namespace system delete impl_; } - timepiece & timepiece::operator=(const volatile timepiece & rhs) + timepiece & timepiece::operator=(const timepiece & rhs) { if(this != &rhs) *impl_ = *rhs.impl_; @@ -41,7 +41,7 @@ namespace system return *this; } - void timepiece::start() volatile + void timepiece::start() noexcept { #if defined(NANA_WINDOWS) ::QueryPerformanceCounter(&impl_->beg_timestamp); @@ -51,7 +51,7 @@ namespace system #endif } - double timepiece::calc() const volatile + double timepiece::calc() const noexcept { #if defined(NANA_WINDOWS) LARGE_INTEGER li; From c6f5dc0f1b2b2f2ac6a1329f1fab0c651acbd6ac Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 11 Aug 2018 09:12:57 +0800 Subject: [PATCH 22/34] fix compiler error in Visual C++2013 --- include/nana/system/timepiece.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/nana/system/timepiece.hpp b/include/nana/system/timepiece.hpp index 248a798e..443a4a0e 100644 --- a/include/nana/system/timepiece.hpp +++ b/include/nana/system/timepiece.hpp @@ -13,6 +13,8 @@ #ifndef NANA_SYSTEM_TIMEPIECE_HPP #define NANA_SYSTEM_TIMEPIECE_HPP +#include "../c++defines.hpp" + namespace nana { namespace system From 841fa0812c8244c269a2677444de3ddf129f680d Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 15 Aug 2018 23:07:38 +0800 Subject: [PATCH 23/34] fix bug that nested_form mistakely renders sibling as its child --- source/gui/detail/window_layout.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 45764b81..19ec8133 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -166,10 +166,18 @@ namespace nana if (!cover->visible) continue; - if (is_wd_root ? - (category::flags::root == cover->other.category) - : - ((category::flags::root != cover->other.category) && (nullptr == cover->effect.bground))) + if (is_wd_root) + { + if(category::flags::root == cover->other.category) + { + if (overlap(vis_rect, rectangle{ native_interface::window_position(cover->root), cover->dimension }, block.r)) + { + block.window = cover; + blocks.push_back(block); + } + } + } + else if((category::flags::root != cover->other.category) && (nullptr == cover->effect.bground)) { if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r)) { From 9ff6567a03f6d8aa20758dc9b44f9aaf9a9aa534 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 18 Aug 2018 07:21:03 +0800 Subject: [PATCH 24/34] fix bug that program stops if XMoveWindow doesn't generate ConfigureNotify --- source/gui/detail/native_window_interface.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 3fc6fcaf..d6f4b99b 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -984,6 +984,15 @@ namespace nana{ nana::detail::platform_scope_guard lock; + if(point{x, y} == window_position(wd)) + { + //Returns if the requested position is same with the current position. + //In some X-Server versions/implementations, XMoveWindow() doesn't generate + //a ConfigureNotify if the requested position is same with the current position. + //It causes that x11_wait_for always waiting for the ConfigureNotify. + return; + } + XWindowAttributes attr; ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); if(attr.map_state == IsUnmapped) From 79c34392315d93e6a83cbe10cafeed99dec8d686 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 19 Aug 2018 05:53:08 +0800 Subject: [PATCH 25/34] fix bug that label word wrap fails for Japanese(#330) word break error new unicode word break reimplement label word wrap for significant design error --- include/nana/c++defines.hpp | 2 + .../widgets/skeletons/text_token_stream.hpp | 18 +- include/nana/unicode_bidi.hpp | 2 + source/gui/widgets/label.cpp | 413 +++++++++++++++++- source/unicode_bidi.cpp | 64 +++ 5 files changed, 486 insertions(+), 13 deletions(-) diff --git a/include/nana/c++defines.hpp b/include/nana/c++defines.hpp index 39637097..e7860b80 100644 --- a/include/nana/c++defines.hpp +++ b/include/nana/c++defines.hpp @@ -220,12 +220,14 @@ #endif #undef _nana_std_has_string_view +#undef _nana_std_has_returnable_emplace_back #if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && defined(_MSVC_LANG) && _MSVC_LANG >= 201703)) || \ ((__cplusplus >= 201703L) && \ (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ >= 400) || \ (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 701))) \ ) # define _nana_std_has_string_view +# define _nana_std_has_returnable_emplace_back #endif diff --git a/include/nana/gui/widgets/skeletons/text_token_stream.hpp b/include/nana/gui/widgets/skeletons/text_token_stream.hpp index ea61349e..52c33b70 100644 --- a/include/nana/gui/widgets/skeletons/text_token_stream.hpp +++ b/include/nana/gui/widgets/skeletons/text_token_stream.hpp @@ -1,7 +1,7 @@ /* * Text Token Stream * 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 @@ -22,6 +22,7 @@ #include #include +#include namespace nana{ namespace widgets{ namespace skeletons { @@ -95,10 +96,19 @@ namespace nana{ namespace widgets{ namespace skeletons return std::stoi(idstr_, nullptr, 0); } private: - static bool _m_unicode_word_breakable(wchar_t ch) + /* + static bool _m_unicode_word_breakable(wchar_t ch) //deprecated { return ((0x4E00 <= ch) && (ch <= 0x9FFF)); } + */ + + static bool _m_unicode_word_breakable(const wchar_t* ch) noexcept + { + if (*ch) + return unicode_wordbreak(*ch, ch[1]); + return true; + } //Read the data token token _m_token() @@ -112,14 +122,14 @@ namespace nana{ namespace widgets{ namespace skeletons idstr_.clear(); idstr_.append(1, ch); - if(_m_unicode_word_breakable(ch)) + if (_m_unicode_word_breakable(iptr_)) { ++iptr_; return token::data; } ch = *++iptr_; - while((iptr_ != endptr_) && (ch > 0xFF) && (false == _m_unicode_word_breakable(ch))) + while((iptr_ != endptr_) && (ch > 0xFF) && (false == _m_unicode_word_breakable(iptr_))) { idstr_.append(1, ch); diff --git a/include/nana/unicode_bidi.hpp b/include/nana/unicode_bidi.hpp index 72d65860..5efd7003 100644 --- a/include/nana/unicode_bidi.hpp +++ b/include/nana/unicode_bidi.hpp @@ -71,6 +71,8 @@ namespace nana std::vector unicode_reorder(const wchar_t* text, std::size_t length); + bool unicode_wordbreak(wchar_t left, wchar_t right); + } #include diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index 790ae3b8..65b72c81 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -20,6 +20,8 @@ #include #include +#define VISUAL_LINES + namespace nana { namespace drawerbase @@ -28,6 +30,7 @@ namespace nana { class renderer { +#ifndef VISUAL_LINES typedef widgets::skeletons::dstream::linecontainer::iterator iterator; struct pixel_tag @@ -37,6 +40,32 @@ namespace nana std::size_t baseline; //The baseline for drawing text. std::vector values; //line values }; +#else + //Iterator of content element in a line. + using content_element_iterator = widgets::skeletons::dstream::linecontainer::const_iterator; //subsitute for member type iterator + + struct visual_line //subsitute of pixel_tag + { + struct element + { + content_element_iterator content_element; + std::pair range; //A part of text in a text element. first: text begin, second: text length + + element(const content_element_iterator& iterator, std::size_t range_begin, std::size_t range_end): + content_element(iterator), + range(range_begin, range_end) + { + } + }; + + int x_base; //The x position where this line starts. + + std::size_t extent_height_px; + std::size_t baseline; //The baseline for rendering text. + std::vector elements; //description of text element in this rendering line. + }; + +#endif //this is a helper variable, it just keeps the status while drawing. struct render_status @@ -46,8 +75,12 @@ namespace nana align_v text_align_v; nana::point pos; +#ifndef VISUAL_LINES std::vector pixels; - std::size_t index; +#else + std::vector vslines; //The lines description of a line of text. substitute of member pixels. +#endif + std::size_t index; //indicates the current rendering visual line. }; struct traceable @@ -102,18 +135,32 @@ namespace nana rs.text_align = th; rs.text_align_v = tv; +#ifndef VISUAL_LINES std::deque > pixel_lines; +#else + //All visual lines data of whole text. + std::deque> content_lines; +#endif std::size_t extent_v_pixels = 0; //the pixels, in height, that text will be painted. for (auto & line : dstream_) { +#ifndef VISUAL_LINES _m_line_pixels(line, def_line_pixels, rs); for (auto & m : rs.pixels) extent_v_pixels += m.pixels; pixel_lines.emplace_back(std::move(rs.pixels)); +#else + _m_prepare_visual_lines(graph, line, def_line_pixels, rs); + + for (auto & vsline : rs.vslines) + extent_v_pixels += vsline.extent_height_px; + + content_lines.emplace_back(std::move(rs.vslines)); +#endif if(extent_v_pixels >= graph.height()) break; @@ -129,13 +176,17 @@ namespace nana else rs.pos.y = 0; +#ifndef VISUAL_LINES auto pixels_iterator = pixel_lines.begin(); - +#else + auto vsline_iterator = content_lines.begin(); +#endif for (auto & line : dstream_) { if (rs.pos.y >= static_cast(graph.height())) break; +#ifndef VISUAL_LINES rs.index = 0; rs.pixels.clear(); @@ -148,6 +199,17 @@ namespace nana break; rs.pos.y += static_cast(rs.pixels.back().pixels); +#else + rs.index = 0; + rs.vslines.clear(); + rs.vslines.swap(*vsline_iterator++); + rs.pos.x = rs.vslines.front().x_base; + + if (!_m_foreach_visual_line(graph, rs)) + break; + + rs.pos.y += static_cast(rs.vslines.back().extent_height_px); +#endif } graph.typeface(pre_font); @@ -194,8 +256,13 @@ namespace nana for(auto & line: dstream_) { +#ifndef VISUAL_LINES rs.pixels.clear(); unsigned w = _m_line_pixels(line, def_line_pixels, rs); +#else + rs.vslines.clear(); + auto w = _m_prepare_visual_lines(graph, line, def_line_pixels, rs); +#endif if(limited && (w > limited)) w = limited; @@ -203,8 +270,13 @@ namespace nana if(retsize.width < w) retsize.width = w; +#ifndef VISUAL_LINES for (auto & px : rs.pixels) retsize.height += static_cast(px.pixels); +#else + for (auto& vsline : rs.vslines) + retsize.height += static_cast(vsline.extent_height_px); +#endif } return retsize; @@ -315,6 +387,7 @@ namespace nana } } +#ifndef VISUAL_LINES void _m_align_x_base(const render_status& rs, pixel_tag & px, unsigned w) noexcept { switch(rs.text_align) @@ -330,7 +403,209 @@ namespace nana break; } } +#else + void _m_prepare_x(const render_status& rs, visual_line & vsline, unsigned w) noexcept + { + switch (rs.text_align) + { + case align::left: + vsline.x_base = 0; + break; + case align::center: + vsline.x_base = (static_cast(rs.allowed_width - w) >> 1); + break; + case align::right: + vsline.x_base = static_cast(rs.allowed_width - w); + break; + } + } +#endif +#ifdef VISUAL_LINES + + /** + * prepare data for rendering a line of text. + */ + unsigned _m_prepare_visual_lines(graph_reference graph, dstream::linecontainer& line, unsigned def_line_px, render_status& rs) + { + unsigned abs_text_px = 0; + unsigned max_ascent = 0; + unsigned max_descent = 0; + unsigned max_content_height = 0; + + int text_pos = 0; + + std::vector vsline_elements; + + for (auto i = line.cbegin(); i != line.cend(); ++i) + { + auto const data = i->data_ptr; + auto fblock = i->fblock_ptr; + + abs_text_px += data->size().width; + + unsigned ascent = 0; + unsigned descent = 0; + + + auto extent_size = data->size(); + + //Check if the content is displayed in current line. + if ((0 == rs.allowed_width) || (text_pos + extent_size.width <= rs.allowed_width)) + { + text_pos += static_cast(extent_size.width); + + //Adjust height of extent_size for special text alignement. + if (fblock::aligns::baseline == fblock->text_align) + { + ascent = static_cast(data->ascent()); + descent = static_cast(extent_size.height - ascent); + + if (max_descent < descent) + max_descent = descent; + + if ((false == data->is_text()) && (extent_size.height < max_ascent + max_descent)) + extent_size.height = max_ascent + max_descent; + } + + if (max_ascent < ascent) max_ascent = ascent; + if (max_descent < descent) max_descent = descent; + if (max_content_height < extent_size.height) max_content_height = extent_size.height; + vsline_elements.emplace_back(i, 0, data->text().size()); + + continue; + } + + //make a visual line for existing vsline elements + if (text_pos) + { +#ifdef _nana_std_has_returnable_emplace_back + auto & vsline = rs.vslines.emplace_back(); +#else + rs.vslines.emplace_back(); + auto & vsline = rs.vslines.back(); +#endif + _m_prepare_x(rs, vsline, static_cast(text_pos)); + + if (max_ascent + max_descent > max_content_height) + max_content_height = max_descent + max_ascent; + else + max_ascent = max_content_height - max_descent; + + vsline.extent_height_px = max_content_height; + vsline.baseline = max_ascent; + vsline.elements.swap(vsline_elements); + } + + text_pos = 0; + max_content_height = max_ascent = max_descent = 0; + //Adjust height of extent_size for special text alignement. + if (fblock::aligns::baseline == fblock->text_align) + { + ascent = static_cast(data->ascent()); + descent = static_cast(extent_size.height - ascent); + + if (max_descent < descent) + max_descent = descent; + + if ((false == data->is_text()) && (extent_size.height < max_ascent + max_descent)) + extent_size.height = max_ascent + max_descent; + } + + if (max_ascent < ascent) max_ascent = ascent; + if (max_descent < descent) max_descent = descent; + if (max_content_height < extent_size.height) max_content_height = extent_size.height; + + if (data->is_text()) + { + _m_change_font(graph, fblock); + //Split a text into multiple lines + auto rest_extent_size = extent_size.width; + std::size_t text_begin = 0; + while (text_begin < data->text().size()) + { + unsigned sub_text_px = 0; + auto sub_text_len = _m_fit_text(graph, data->text().substr(text_begin), rs.allowed_width, sub_text_px); + + if (text_begin + sub_text_len < data->text().size()) + { + //make a new visual line +#ifdef _nana_std_has_returnable_emplace_back + auto & vsline = rs.vslines.emplace_back(); +#else + rs.vslines.emplace_back(); + auto & vsline = rs.vslines.back(); +#endif + _m_prepare_x(rs, vsline, sub_text_px); + + vsline.extent_height_px = max_content_height; + vsline.baseline = max_ascent; + vsline.elements.emplace_back(i, text_begin, sub_text_len); + } + else + { + //the last part, write it to vsline_elements to keep the status for next line element(next i) + vsline_elements.emplace_back(i, text_begin, sub_text_len); + + text_pos = sub_text_px; + } + + text_begin += sub_text_len; + } + } + else + { + //the last part, write it to vsline_elements to keep the status for next line element(next i) + vsline_elements.emplace_back(i, 0, 0); + + text_pos = static_cast(i->data_ptr->size().width); + } + } + + if (!vsline_elements.empty()) + { +#ifdef _nana_std_has_returnable_emplace_back + auto & vsline = rs.vslines.emplace_back(); +#else + rs.vslines.emplace_back(); + auto & vsline = rs.vslines.back(); +#endif + _m_prepare_x(rs, vsline, static_cast(text_pos)); + + if (max_ascent + max_descent > max_content_height) + max_content_height = max_descent + max_ascent; + else + max_ascent = max_content_height - max_descent; + + vsline.extent_height_px = max_content_height; + vsline.baseline = max_ascent; + vsline.elements.swap(vsline_elements); + } + + return abs_text_px; + } + + //Get the length of characters in a text whose length in pixels doesn't beyond the limited width. + static unsigned _m_fit_text(graph_reference graph, const std::wstring& text, unsigned limited_width_px, unsigned& text_px) noexcept + { +#ifdef _nana_std_has_string_view + auto pxbuf = graph.glyph_pixels(text); +#else + std::unique_ptr pxbuf(new unsigned[text.size()]); + graph.glyph_pixels(text.c_str(), text.size(), pxbuf.get()); +#endif + + text_px = 0; + for (std::size_t i = 0; i < text.size(); ++i) + { + if (text_px + pxbuf[i] > limited_width_px) + return i; + + text_px += pxbuf[i]; + } + return text.size(); + } +#else unsigned _m_line_pixels(dstream::linecontainer& line, unsigned def_line_pixels, render_status & rs) { if (line.empty()) @@ -441,7 +716,9 @@ namespace nana } return total_w; } +#endif +#ifndef VISUAL_LINES bool _m_each_line(graph_reference graph, dstream::linecontainer&, render_status& rs) { std::wstring text; @@ -501,7 +778,36 @@ namespace nana } return (rs.pos.y <= lastpos); } +#else + bool _m_foreach_visual_line(graph_reference graph, render_status& rs) + { + std::wstring text; + + content_element_iterator block_start; + auto const bottom = static_cast(graph.height()) - 1; + + for (auto & vsline : rs.vslines) + { + rs.pos.x = vsline.x_base; + for (auto& content_elm : vsline.elements) + { + _m_draw_vsline_element(graph, content_elm, rs); + } + + ++rs.index; //next line index + rs.pos.y += vsline.extent_height_px; + + if (rs.pos.y > bottom) + return false; + } + + return (rs.pos.y <= bottom); + } +#endif + + +#if 0 //deprecated static bool _m_overline(const render_status& rs, int right, bool equal_required) noexcept { if(align::left == rs.text_align) @@ -509,7 +815,24 @@ namespace nana return (equal_required ? rs.pixels[rs.index].x_base <= 0 : rs.pixels[rs.index].x_base < 0); } +#endif +#ifdef VISUAL_LINES + static int _m_vsline_element_top(const visual_line& vsline, fblock* fblock_ptr, const data* data_ptr) noexcept + { + switch (fblock_ptr->text_align) + { + case fblock::aligns::center: + return static_cast(vsline.extent_height_px - data_ptr->size().height) / 2; + case fblock::aligns::bottom: + return static_cast(vsline.extent_height_px - data_ptr->size().height); + case fblock::aligns::baseline: + return static_cast(vsline.baseline - (data_ptr->is_text() ? data_ptr->ascent() : data_ptr->size().height)); + default: break; + } + return 0; + } +#else static int _m_text_top(const pixel_tag& px, fblock* fblock_ptr, const data* data_ptr) { switch(fblock_ptr->text_align) @@ -524,7 +847,52 @@ namespace nana } return 0; } +#endif +#ifdef VISUAL_LINES + void _m_draw_vsline_element(graph_reference graph, const visual_line::element& vsline_elm, render_status& rs) + { + auto data = vsline_elm.content_element->data_ptr; + auto fblock = vsline_elm.content_element->fblock_ptr; + + if (data->is_text()) + { + auto const text = data->text().c_str() + vsline_elm.range.first; + auto const reordered = unicode_reorder(text, vsline_elm.range.second); + + _m_change_font(graph, fblock); + for (auto & bidi : reordered) + { + auto extent_size = data->size(); +#ifdef _nana_std_has_string_view + std::wstring_view text_sv{ bidi.begin, static_cast(bidi.end - bidi.begin) }; + if (data->text().size() != text_sv.size()) + extent_size = graph.text_extent_size(text_sv); + + const int y = rs.pos.y + _m_vsline_element_top(rs.vslines[rs.index], fblock, data); + graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock)); +#else + std::wstring text{ bidi.begin, static_cast(bidi.end - bidi.begin) }; + if (data->text().size() != text.size()) + extent_size = graph.text_extent_size(text); + + const int y = rs.pos.y + _m_vsline_element_top(rs.vslines[rs.index], fblock, data); + graph.string({ rs.pos.x, y }, text, _m_fgcolor(fblock)); +#endif + _m_insert_if_traceable(rs.pos.x, y, extent_size, fblock); + rs.pos.x += static_cast(extent_size.width); + } + } + else + { + int y = rs.pos.y + _m_vsline_element_top(rs.vslines[rs.index], fblock, data); + + data->nontext_render(graph, rs.pos.x, y); + _m_insert_if_traceable(rs.pos.x, y, data->size(), fblock); + rs.pos.x += static_cast(data->size().width); + } + } +#else void _m_draw_block(graph_reference graph, const std::wstring& s, dstream::linecontainer::iterator block_start, render_status& rs) { auto const reordered = unicode_reorder(s.data(), s.length()); @@ -550,9 +918,35 @@ namespace nana fblock * fblock_ptr = i->fblock_ptr; data * data_ptr = i->data_ptr; +#if 1 + const int range_text_area = static_cast(rs.allowed_width) - rs.pos.x; + + _m_change_font(graph, fblock_ptr); + + auto text_extent_size = data_ptr->size(); +#ifndef _nana_std_has_string_view + std::wstring_view text_sv{ data_ptr->text().c_str() + text_range.first, text_range.second }; + if (data_ptr->text().size() != text_sv.size()) + text_extent_size = graph.text_extent_size(text_sv); +#else + auto text_sv = data_ptr->text().substr(text_range.first, text_range.second); + if (data_ptr->text().size() != text_sv.size()) + text_extent_size = graph.text_extent_size(text_sv); +#endif + if ((static_cast(text_extent_size.width) > range_text_area) && (rs.pos.x != px.x_base)) + { + //Change a new line + rs.pos.y += static_cast(px.pixels); + px = rs.pixels[++rs.index]; + rs.pos.x = px.x_base; + } + + const int y = rs.pos.y + _m_text_top(px, fblock_ptr, data_ptr); + graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock_ptr)); +#else const int w = static_cast(rs.allowed_width) - rs.pos.x; - nana::size sz = data_ptr->size(); - if ((static_cast(sz.width) > w) && (rs.pos.x != px.x_base)) + nana::size text_extent_size = data_ptr->size(); + if ((static_cast(text_extent_size.width) > w) && (rs.pos.x != px.x_base)) { //Change a new line rs.pos.y += static_cast(px.pixels); @@ -569,7 +963,7 @@ namespace nana if (text_range.second != text_sv.size()) { text_sv = text_sv.substr(text_range.first, text_range.second); - sz = graph.text_extent_size(text_sv); + text_extent_size = graph.text_extent_size(text_sv); } graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock_ptr)); @@ -581,15 +975,15 @@ namespace nana else { auto str = data_ptr->text().substr(text_range.first, text_range.second); - sz = graph.text_extent_size(str); + text_extent_size = graph.text_extent_size(str); graph.string({ rs.pos.x, y }, str, _m_fgcolor(fblock_ptr)); } #endif +#endif //#if 0 - - _m_insert_if_traceable(rs.pos.x, y, sz, fblock_ptr); - rs.pos.x += static_cast(sz.width); + _m_insert_if_traceable(rs.pos.x, y, text_extent_size, fblock_ptr); + rs.pos.x += static_cast(text_extent_size.width); if(text_range.second < len) { @@ -601,6 +995,7 @@ namespace nana } } } +#endif //VISUAL_LINES static std::pair _m_locate(dstream::linecontainer::iterator& i, std::size_t pos) { diff --git a/source/unicode_bidi.cpp b/source/unicode_bidi.cpp index 15b77d12..3591d6ef 100644 --- a/source/unicode_bidi.cpp +++ b/source/unicode_bidi.cpp @@ -946,4 +946,68 @@ namespace nana { return unicode_bidi{}.reorder(text, length); } + + enum class unicode_character_type + { + format, + katakana, + aletter, + midletter, + midnumlet, + midnum, + numeric, + other + }; + + //http://www.unicode.org/reports/tr29/WordBreakTest.html + unicode_character_type unicode_char_type(unsigned long ch) + { + if ((0x0600 <= ch && ch <= 0x0603) || (0x06DD == ch || 0x070F == ch || 0x17B4 == ch || 0x17B5 == ch) || (0x200C <= ch && ch <= 0x200F) || + (0x202A <= ch && ch <= 0x202E) || (0x2060 <= ch && ch <= 0x2063) || (0x206A <= ch && ch <= 0x206F) || (0xFEFF == ch) || (0xFFF9 <= ch && ch <= 0xFFFB) || + (0x1D173 <= ch && ch <= 0x1D17A) || (0xE0001 == ch) || (0xE0020 <= ch && ch <= 0xE007F)) + return unicode_character_type::format; + + if ((0x30A1 <= ch && ch <= 0x30FA) || (0x30FC <= ch && ch <= 0x30FF) || (0x31F0 <= ch && ch <= 0x31FF) || (0xFF66 <= ch && ch <= 0xFF9F)) + return unicode_character_type::katakana; + + if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || (0x00AA == ch || 0x00B5 == ch || 0x00BA == ch) || (0x00C0 <= ch && ch <= 0x00D6) || + (0x00D8 <= ch && ch <= 0x00F6) || (0x00F8 <= ch && ch <= 0x0236) || (0x0250 <= ch || ch <= 0x02C1)) + return unicode_character_type::aletter; + + if ('\'' == ch || 0x00AD == ch || 0x00B7 == ch || 0x05F4 == ch || 0x2019 == ch || 0x2027 == ch) + return unicode_character_type::midletter; + + if ('.' == ch || '\\' == ch || ':' == ch) + return unicode_character_type::midnumlet; + + if (0x2024 <= ch && ch <= 0x2026) + return unicode_character_type::midnum; + + if (('0' <= ch && ch <= '9') || (0x0660 <= ch && ch <= 0x0669) || (0x06F0 <= ch && ch <= 0x06F9)) + return unicode_character_type::numeric; + + return unicode_character_type::other; + } + + bool unicode_wordbreak(wchar_t left, wchar_t right) + { + auto l_type = unicode_char_type(left); + auto r_type = unicode_char_type(right); + + switch (l_type) + { + case unicode_character_type::format: + case unicode_character_type::midletter: + case unicode_character_type::midnumlet: + case unicode_character_type::midnum: + case unicode_character_type::other: + return (r_type != unicode_character_type::format); + case unicode_character_type::katakana: + return !(unicode_character_type::format == r_type) || (unicode_character_type::katakana == r_type); + case unicode_character_type::aletter: + case unicode_character_type::numeric: + return !(unicode_character_type::format == r_type) || (unicode_character_type::aletter == r_type) || (unicode_character_type::numeric == r_type); + } + return true; + } }//end namespace nana From 0a7223b37c5322b9a8bc74a7627a3a1091c4cd35 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 19 Aug 2018 15:41:08 +0800 Subject: [PATCH 26/34] Add missing changes after branch merged(#319) --- CMakeLists.txt | 62 ++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f47642f3..80f0e8c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,11 +142,11 @@ endif() # if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") + if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") set(CMAKE_CXX_FLAGS "-std=gnu++14 -Wall -I/usr/local/include") - else() - set(CMAKE_CXX_FLAGS "-std=gnu++14 -Wall") - endif() + else() + set(CMAKE_CXX_FLAGS "-std=gnu++14 -Wall") + endif() else() set(CMAKE_CXX_FLAGS "-std=c++14 -Wall") endif() @@ -161,7 +161,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") else() set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread") endif() - endif() + endif(NANA_CMAKE_SHARED_LIB) if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) # GCC 4.9 @@ -173,9 +173,10 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") endif() endif() -if(APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - list(APPEND NANA_LINKS -stdlib=libstdc++) -endif() + +if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # APPLE Clang + list(APPEND NANA_LINKS -stdlib=libstdc++) +endif () ############# Optional libraries @@ -354,26 +355,27 @@ endif() # Just for information: -message("") -message("CMAKE_CXX_COMPILER_ID = " ${CMAKE_CXX_COMPILER_ID}) -message("COMPILER_IS_CLANG = " ${COMPILER_IS_CLANG}) -message("CMAKE_COMPILER_IS_GNUCXX = " ${CMAKE_COMPILER_IS_GNUCXX}) -message("CMAKE_CXX_FLAGS = " ${CMAKE_CXX_FLAGS}) -message("CMAKE_EXE_LINKER_FLAGS = " ${CMAKE_EXE_LINKER_FLAGS}) -message("CMAKE_STATIC_LINKER_FLAGS = " ${CMAKE_STATIC_LINKER_FLAGS}) -message("NANA_LINKS = " ${NANA_LINKS}) -message("DESTDIR = " ${DESTDIR}) -message("CMAKE_INSTALL_PREFIX = " ${CMAKE_INSTALL_PREFIX}) -message("NANA_INCLUDE_DIR = " ${NANA_INCLUDE_DIR}) -message("CMAKE_CURRENT_SOURCE_DIR = " ${CMAKE_CURRENT_SOURCE_DIR}) -message("NANA_CMAKE_ENABLE_AUDIO = " ${NANA_CMAKE_ENABLE_AUDIO}) -message("NANA_CMAKE_SHARED_LIB = " ${NANA_CMAKE_SHARED_LIB}) -message("NANA_CLION = " ${NANA_CLION}) -message("CMAKE_MAKE_PROGRAM = " ${CMAKE_MAKE_PROGRAM}) +message ("") +message ( "CMAKE_CXX_COMPILER_ID = " ${CMAKE_CXX_COMPILER_ID}) +message ( "COMPILER_IS_CLANG = " ${COMPILER_IS_CLANG}) +message ( "CMAKE_COMPILER_IS_GNUCXX = " ${CMAKE_COMPILER_IS_GNUCXX}) +message ( "CMAKE_CXX_FLAGS = " ${CMAKE_CXX_FLAGS}) +message ( "CMAKE_EXE_LINKER_FLAGS = " ${CMAKE_EXE_LINKER_FLAGS}) +message ( "CMAKE_STATIC_LINKER_FLAGS = " ${CMAKE_STATIC_LINKER_FLAGS}) +message ( "NANA_LINKS = " ${NANA_LINKS}) +message ( "DESTDIR = " ${DESTDIR}) +message ( "CMAKE_INSTALL_PREFIX = " ${CMAKE_INSTALL_PREFIX}) +message ( "NANA_INCLUDE_DIR = " ${NANA_INCLUDE_DIR}) +message ( "CMAKE_CURRENT_SOURCE_DIR = " ${CMAKE_CURRENT_SOURCE_DIR}) +message ( "NANA_CMAKE_ENABLE_AUDIO = " ${NANA_CMAKE_ENABLE_AUDIO}) +message ( "NANA_CMAKE_SHARED_LIB = " ${NANA_CMAKE_SHARED_LIB}) +message ( "NANA_CLION = " ${NANA_CLION}) +message ( "CMAKE_MAKE_PROGRAM = " ${CMAKE_MAKE_PROGRAM}) +message ( "CMAKE_CXX_COMPILER_VERSION = " ${CMAKE_CXX_COMPILER_VERSION}) -message("NANA_CMAKE_FIND_BOOST_FILESYSTEM = " ${NANA_CMAKE_FIND_BOOST_FILESYSTEM}) -message("NANA_CMAKE_BOOST_FILESYSTEM_FORCE = " ${NANA_CMAKE_BOOST_FILESYSTEM_FORCE}) -message("NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT = " ${NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT}) -message("NANA_CMAKE_BOOST_FILESYSTEM_LIB = " ${NANA_CMAKE_BOOST_FILESYSTEM_LIB}) -message("NANA_CMAKE_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_AUTOMATIC_GUI_TESTING}) -message("NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING}) +message ( "NANA_CMAKE_FIND_BOOST_FILESYSTEM = " ${NANA_CMAKE_FIND_BOOST_FILESYSTEM}) +message ( "NANA_CMAKE_BOOST_FILESYSTEM_FORCE = " ${NANA_CMAKE_BOOST_FILESYSTEM_FORCE}) +message ( "NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT = " ${NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT}) +message ( "NANA_CMAKE_BOOST_FILESYSTEM_LIB = " ${NANA_CMAKE_BOOST_FILESYSTEM_LIB}) +message ( "NANA_CMAKE_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_AUTOMATIC_GUI_TESTING}) +message ( "NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING}) From 74f060acbc6439ea78495bbc280dd2a187d14e06 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 24 Aug 2018 22:57:05 +0800 Subject: [PATCH 27/34] x11_wait_for blocks execution in raspbian --- source/gui/detail/native_window_interface.cpp | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index d6f4b99b..ef0b1935 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -745,6 +745,14 @@ namespace nana{ { nana::detail::platform_scope_guard psg; Display* disp = restrict::spec.open_display(); + + //Returns if the requested visibility is same with the current status. + //In some X-Server versions/implementations, XMapWindow() doesn't generate + //a ConfigureNotify if the requested visibility is same with the current status. + //It causes that x11_wait_for always waiting for the ConfigureNotify. + if(show == is_window_visible(wd)) + return; + if(show) { ::XMapWindow(disp, reinterpret_cast(wd)); @@ -1050,6 +1058,16 @@ namespace nana{ XSizeHints hints; nana::detail::platform_scope_guard psg; + + //Returns if the requested rectangle is same with the current rectangle. + //In some X-Server versions/implementations, XMapWindow() doesn't generate + //a ConfigureNotify if the requested rectangle is same with the current rectangle. + //It causes that x11_wait_for always waiting for the ConfigureNotify. + rectangle current_r; + get_window_rect(wd, current_r); + if(r == current_r) + return true; + ::XGetWMNormalHints(disp, reinterpret_cast(wd), &hints, &supplied); if((hints.flags & (PMinSize | PMaxSize)) && (hints.min_width == hints.max_width) && (hints.min_height == hints.max_height)) { @@ -1239,6 +1257,15 @@ namespace nana{ auto disp = restrict::spec.open_display(); nana::detail::platform_scope_guard psg; + //Returns if the requested size is same with the current size. + //In some X-Server versions/implementations, XMapWindow() doesn't generate + //a ConfigureNotify if the requested size is same with the current size. + //It causes that x11_wait_for always waiting for the ConfigureNotify. + rectangle current_r; + get_window_rect(wd, current_r); + if(current_r.dimension() == sz) + return true; + //Check the XSizeHints for testing whether the window is sizable. XSizeHints hints; long supplied; @@ -1274,6 +1301,9 @@ namespace nana{ unsigned border, depth; nana::detail::platform_scope_guard psg; ::XGetGeometry(restrict::spec.open_display(), reinterpret_cast(wd), &root, &x, &y, &r.width, &r.height, &border, &depth); + + auto pos = window_position(wd); + r.position(pos); #endif } From c440613d9020af5a57cc30010fc9852d7de458af Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 25 Aug 2018 06:06:57 +0800 Subject: [PATCH 28/34] fix crash which occurs after calling widget::tooltip("")(#331) --- include/nana/gui/tooltip.hpp | 2 +- source/gui/tooltip.cpp | 71 ++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/include/nana/gui/tooltip.hpp b/include/nana/gui/tooltip.hpp index e724d19b..89ec2c1a 100644 --- a/include/nana/gui/tooltip.hpp +++ b/include/nana/gui/tooltip.hpp @@ -1,6 +1,6 @@ /* * A Tooltip Implementation - * 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 diff --git a/source/gui/tooltip.cpp b/source/gui/tooltip.cpp index 862a2720..34692036 100644 --- a/source/gui/tooltip.cpp +++ b/source/gui/tooltip.cpp @@ -1,7 +1,7 @@ /* * A Tooltip 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,6 +15,7 @@ #include #include #include +#include namespace nana { @@ -157,7 +158,14 @@ namespace nana class controller { - typedef std::pair pair_t; + struct tip_value + { + std::string text; + event_handle evt_msenter; + event_handle evt_msleave; + event_handle evt_msdown; + event_handle evt_destroy; + }; typedef std::function deleter_type; @@ -207,7 +215,7 @@ namespace nana if (str.empty()) _m_untip(wd); else - _m_get(wd).second = str; + _m_get(wd).text = str; } void show(const std::string& text, const point* pos, std::size_t duration) @@ -236,35 +244,35 @@ namespace nana window_.reset(); //Destroy the tooltip controller when there are not tooltips. - if (cont_.empty()) + if (table_.empty()) instance(true); } private: void _m_untip(window wd) { - for (auto i = cont_.begin(); i != cont_.end(); ++i) + auto i = table_.find(wd); + if(i != table_.end()) { - if (i->first == wd) - { - cont_.erase(i); + API::umake_event(i->second.evt_msdown); + API::umake_event(i->second.evt_msenter); + API::umake_event(i->second.evt_msleave); + API::umake_event(i->second.evt_destroy); - if (cont_.empty()) - { - window_.reset(); - instance(true); - } - return; - } + table_.erase(i); + } + + if (table_.empty()) + { + window_.reset(); + instance(true); } } private: - pair_t& _m_get(window wd) + tip_value& _m_get(window wd) { - for (auto & pr : cont_) - { - if (pr.first == wd) - return pr; - } + auto i = table_.find(wd); + if (i != table_.end()) + return i->second; auto & events = API::events(wd); @@ -272,28 +280,29 @@ namespace nana { if (event_code::mouse_enter == arg.evt_code) { - auto & pr = _m_get(arg.window_handle); - if (pr.second.size()) - this->show(pr.second, nullptr, 0); + auto & value = _m_get(arg.window_handle); + if (value.text.size()) + this->show(value.text, nullptr, 0); } else this->close(); }; - events.mouse_enter.connect(mouse_fn); - events.mouse_leave.connect(mouse_fn); - events.mouse_down.connect(mouse_fn); + auto & value = table_[wd]; - events.destroy.connect([this](const arg_destroy& arg){ + value.evt_msenter = events.mouse_enter.connect(mouse_fn); + value.evt_msleave = events.mouse_leave.connect(mouse_fn); + value.evt_msdown = events.mouse_down.connect(mouse_fn); + + value.evt_destroy = events.destroy.connect([this](const arg_destroy& arg){ _m_untip(arg.window_handle); }); - cont_.emplace_back(wd, std::string()); - return cont_.back(); + return value; } private: std::unique_ptr window_; - std::vector cont_; + std::map table_; }; }//namespace tooltip }//namespace drawerbase From e0ba1c7d8a5d064e4e096a3600d4f9e831995184 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 25 Aug 2018 06:34:43 +0800 Subject: [PATCH 29/34] disallows copying text from a masked text-editor. --- source/gui/widgets/skeletons/text_editor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 16963195..a2f81c39 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -2086,6 +2086,10 @@ namespace nana{ namespace widgets void text_editor::copy() const { + //Stops copying text if the text_editor is masked. + if (mask_char_) + return; + auto text = _m_make_select_string(); if (!text.empty()) nana::system::dataexch().set(text, API::root(this->window_)); From e8e7ad543c17968490c33374228b0114fdfe33af Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 25 Aug 2018 06:53:11 +0800 Subject: [PATCH 30/34] the default pool thread number is thread hw concurrency --- include/nana/threads/pool.hpp | 13 ++++++++++--- source/gui/widgets/skeletons/text_editor.cpp | 2 +- source/threads/pool.cpp | 16 +++++++++------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/include/nana/threads/pool.hpp b/include/nana/threads/pool.hpp index 38d9952e..1234bcb2 100644 --- a/include/nana/threads/pool.hpp +++ b/include/nana/threads/pool.hpp @@ -1,6 +1,6 @@ /* * A Thread Pool Implementation - * 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 @@ -13,10 +13,14 @@ #ifndef NANA_THREADS_POOL_HPP #define NANA_THREADS_POOL_HPP +#include #include #include #include +#ifndef STD_THREAD_NOT_SUPPORTED +# include +#endif namespace nana{ /// Some mutex classes for synchronizing. @@ -58,9 +62,12 @@ namespace threads pool(const pool&) = delete; pool& operator=(const pool&) = delete; public: - pool(); ///< Creates a group of threads. +#ifndef STD_THREAD_NOT_SUPPORTED + pool(unsigned thread_number = std::thread::hardware_concurrency()); ///< Creates a group of threads. +#else + pool(unsigned thread_number = 0); +#endif pool(pool&&); - pool(std::size_t thread_number); ///< Creates a number of threads specifed by thread_number. ~pool(); ///< waits for the all running tasks till they are finished and skips all the queued tasks. pool& operator=(pool&&); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index a2f81c39..e04c4ab8 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -2086,7 +2086,7 @@ namespace nana{ namespace widgets void text_editor::copy() const { - //Stops copying text if the text_editor is masked. + //Disallows copying text if the text_editor is masked. if (mask_char_) return; diff --git a/source/threads/pool.cpp b/source/threads/pool.cpp index e83498b0..d4b3af2f 100644 --- a/source/threads/pool.cpp +++ b/source/threads/pool.cpp @@ -351,10 +351,17 @@ namespace threads }container_; };//end class impl - pool::pool() - : impl_(new impl(4)) +#ifndef STD_THREAD_NOT_SUPPORTED + pool::pool(unsigned thread_number) + : impl_(new impl(thread_number ? thread_number : std::thread::hardware_concurrency())) { } +#else + pool::pool(unsigned thread_number) + : impl_(new impl(0)) + { + } +#endif pool::pool(pool&& other) : pool() @@ -362,11 +369,6 @@ namespace threads std::swap(impl_, other.impl_); } - pool::pool(std::size_t thread_number) - : impl_(new impl(thread_number)) - { - } - pool& pool::operator=(pool&& other) { if(this != &other) From e1992fb0d48abf35cd12d0454ff78d289a7e65a6 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 26 Aug 2018 16:42:53 +0800 Subject: [PATCH 31/34] fix crash when drawing in text_changed event with new line inserted(#332) --- .../gui/widgets/skeletons/text_editor.hpp | 10 +- .../nana/gui/widgets/skeletons/textbase.hpp | 52 ++++++---- source/gui/widgets/skeletons/text_editor.cpp | 98 ++++++++++++------- source/gui/widgets/textbox.cpp | 4 +- 4 files changed, 101 insertions(+), 63 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index d3536182..dd24d365 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -191,14 +191,14 @@ namespace nana{ namespace widgets void draw_corner(); void render(bool focused); public: - void put(std::wstring); + void put(std::wstring, bool perform_event); void put(wchar_t); void copy() const; void cut(); void paste(); - void enter(bool record_undo = true); + void enter(bool record_undo, bool perform_event); void del(); - void backspace(bool record_undo = true); + void backspace(bool record_undo, bool perform_event); void undo(bool reverse); void set_undo_queue_length(std::size_t len); void move_ns(bool to_north); //Moves up and down @@ -243,9 +243,9 @@ namespace nana{ namespace widgets void _m_reset(); //Inserts text at position where the caret is - ::nana::upoint _m_put(::std::wstring); + ::nana::upoint _m_put(::std::wstring, bool perform_event); - ::nana::upoint _m_erase_select(); + ::nana::upoint _m_erase_select(bool perform_event); ::std::wstring _m_make_select_string() const; static bool _m_resolve_text(const ::std::wstring&, std::vector> & lines); diff --git a/include/nana/gui/widgets/skeletons/textbase.hpp b/include/nana/gui/widgets/skeletons/textbase.hpp index 751d9888..d11bc872 100644 --- a/include/nana/gui/widgets/skeletons/textbase.hpp +++ b/include/nana/gui/widgets/skeletons/textbase.hpp @@ -1,7 +1,7 @@ /* * A textbase class 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 @@ -301,6 +301,29 @@ namespace skeletons } } + //Triggers the text_changed event. + //It is exposed for outter classes. For a outter class(eg. text_editor), a changing text content operation + //may contains multiple textbase operations, therefore, the outter class determines when an event should be triggered. + // + //Addtional, using text_changed() method, it is possible to allow a outter class performing some updating operations + //before triggering text_changed event. + void text_changed() + { + if (!changed_) + { + _m_first_change(); + changed_ = true; + } + + if (edited_) + { + if (evt_agent_) + evt_agent_->text_changed(); + + edited_ = false; + } + } + size_type lines() const { return text_cont_.size(); @@ -330,7 +353,7 @@ namespace skeletons _m_at(pos).swap(text); _m_make_max(pos); - _m_edited(); + edited_ = true; } void insert(upoint pos, string_type && str) @@ -351,7 +374,7 @@ namespace skeletons } _m_make_max(pos.y); - _m_edited(); + edited_ = true; } void insertln(size_type pos, string_type&& str) @@ -362,7 +385,7 @@ namespace skeletons text_cont_.emplace_back(new string_type(std::move(str))); _m_make_max(pos); - _m_edited(); + edited_ = true; } void erase(size_type line, size_type pos, size_type count) @@ -378,7 +401,7 @@ namespace skeletons if (attr_max_.line == line) _m_scan_for_max(); - _m_edited(); + edited_ = true; } } @@ -398,7 +421,7 @@ namespace skeletons else if (pos < attr_max_.line) attr_max_.line -= n; - _m_edited(); + edited_ = true; return true; } @@ -426,7 +449,7 @@ namespace skeletons if(pos < attr_max_.line) --attr_max_.line; - _m_edited(); + edited_ = true; } } @@ -514,23 +537,12 @@ namespace skeletons changed_ = false; } - - void _m_edited() - { - if(!changed_) - { - _m_first_change(); - changed_ = true; - } - - if (evt_agent_) - evt_agent_->text_changed(); - } private: std::deque> text_cont_; textbase_event_agent_interface* evt_agent_{ nullptr }; - mutable bool changed_{ false }; + mutable bool changed_{ false }; + mutable bool edited_{ false }; mutable std::string filename_; //A string for the saved filename. const string_type nullstr_; diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index e04c4ab8..0510acd9 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -199,7 +199,7 @@ namespace nana{ namespace widgets { editor_.select_.a = sel_a_; editor_.select_.b = sel_b_; - editor_._m_erase_select(); + editor_._m_erase_select(false); editor_.select_.a = editor_.select_.b; editor_.points_.caret = sel_a_; } @@ -208,7 +208,7 @@ namespace nana{ namespace widgets if (is_enter) { editor_.points_.caret = nana::upoint(0, pos_.y + 1); - editor_.backspace(false); + editor_.backspace(false, false); } else editor_.textbase().erase(pos_.y, pos_.x, selected_text_.size()); @@ -218,11 +218,11 @@ namespace nana{ namespace widgets { if (is_enter) { - editor_.enter(false); + editor_.enter(false, false); } else { - editor_._m_put(selected_text_); + editor_._m_put(selected_text_, false); if (sel_a_ != sel_b_) { editor_.select_.a = sel_a_; @@ -234,6 +234,8 @@ namespace nana{ namespace widgets } } + editor_.textbase().text_changed(); + editor_.reset_caret(); } }; @@ -258,7 +260,7 @@ namespace nana{ namespace widgets { if (is_enter) { - editor_.enter(false); + editor_.enter(false, false); } else { @@ -266,9 +268,9 @@ namespace nana{ namespace widgets { editor_.select_.a = sel_a_; editor_.select_.b = sel_b_; - editor_._m_erase_select(); + editor_._m_erase_select(false); } - editor_.points_.caret = editor_._m_put(text_); //redo + editor_.points_.caret = editor_._m_put(text_, false); //redo } } else @@ -277,7 +279,7 @@ namespace nana{ namespace widgets { editor_.points_.caret.x = 0; ++editor_.points_.caret.y; - editor_.backspace(false); + editor_.backspace(false, false); } else { @@ -286,7 +288,7 @@ namespace nana{ namespace widgets { editor_.select_.a = pos_; editor_.select_.b = upoint(static_cast(lines.back().second - lines.back().first), static_cast(pos_.y + lines.size() - 1)); - editor_.backspace(false); + editor_.backspace(false, false); editor_.select_.a = editor_.select_.b; } else @@ -296,12 +298,14 @@ namespace nana{ namespace widgets if (!selected_text_.empty()) { editor_.points_.caret = (std::min)(sel_a_, sel_b_); - editor_._m_put(selected_text_); + editor_._m_put(selected_text_, false); editor_.points_.caret = sel_b_; editor_.select_.a = sel_a_; //Reset the selected text editor_.select_.b = sel_b_; } } + + editor_.textbase().text_changed(); editor_.reset_caret(); } private: @@ -333,8 +337,8 @@ namespace nana{ namespace widgets const auto text = editor_._m_make_select_string(); - editor_._m_erase_select(); - editor_._m_put(text); + editor_._m_erase_select(false); + editor_._m_put(text, false); editor_.select_.a = sel_a_; editor_.select_.b = sel_b_; @@ -342,6 +346,7 @@ namespace nana{ namespace widgets editor_.points_.caret = sel_b_; editor_.reset_caret(); } + editor_.textbase().text_changed(); } void set_destination(const nana::upoint& dest_a, const nana::upoint& dest_b) @@ -1192,9 +1197,9 @@ namespace nana{ namespace widgets switch (key) { case '\b': - backspace(); break; + backspace(true, true); break; case '\n': case '\r': - enter(); break; + enter(true, true); break; case keyboard::sync_idel: paste(); break; case keyboard::tab: @@ -1681,7 +1686,7 @@ namespace nana{ namespace widgets auto undo_ptr = std::unique_ptr{ new undo_input_text(*this, str) }; undo_ptr->set_caret_pos(); - _m_put(std::move(str)); + _m_put(std::move(str), false); impl_->undo.push(std::move(undo_ptr)); @@ -1698,7 +1703,9 @@ namespace nana{ namespace widgets } } else - put(std::move(str)); + put(std::move(str), false); + + textbase().text_changed(); } std::wstring text_editor::text() const @@ -1904,6 +1911,7 @@ namespace nana{ namespace widgets if (_m_move_select(true)) { + textbase().text_changed(); this->_m_adjust_view(); impl_->try_refresh = sync_graph::refresh; return true; @@ -2021,7 +2029,7 @@ namespace nana{ namespace widgets impl_->try_refresh = sync_graph::none; } //public: - void text_editor::put(std::wstring text) + void text_editor::put(std::wstring text, bool perform_event) { if (text.empty()) return; @@ -2032,14 +2040,16 @@ namespace nana{ namespace widgets //Do not forget to assign the _m_erase_select() to caret //because _m_put() will insert the text at the position where the caret is. - points_.caret = _m_erase_select(); + points_.caret = _m_erase_select(false); undo_ptr->set_caret_pos(); - points_.caret = _m_put(std::move(text)); + points_.caret = _m_put(std::move(text), false); impl_->undo.push(std::move(undo_ptr)); _m_reset_content_size(true); + if (perform_event) + textbase().text_changed(); if(graph_) { @@ -2060,7 +2070,7 @@ namespace nana{ namespace widgets undo_ptr->set_selected_text(); if(refresh) - points_.caret = _m_erase_select(); + points_.caret = _m_erase_select(false); undo_ptr->set_caret_pos(); @@ -2070,6 +2080,8 @@ namespace nana{ namespace widgets textbase().insert(points_.caret, std::move(ch_str)); _m_pre_calc_lines(points_.caret.y, 1); + textbase().text_changed(); + points_.caret.x ++; _m_reset_content_size(); @@ -2107,7 +2119,7 @@ namespace nana{ namespace widgets if ((accepts::no_restrict == impl_->capacities.acceptive) || !impl_->capacities.pred_acceptive) { - put(move(text)); + put(move(text), true); return; } @@ -2125,13 +2137,13 @@ namespace nana{ namespace widgets if (accepts::no_restrict != impl_->capacities.acceptive) { text.erase(i, text.end()); - put(move(text)); + put(move(text), true); } break; } } - void text_editor::enter(bool record_undo) + void text_editor::enter(bool record_undo, bool perform_event) { if(false == attributes_.multi_lines) return; @@ -2139,7 +2151,7 @@ namespace nana{ namespace widgets auto undo_ptr = std::unique_ptr(new undo_input_text(*this, std::wstring(1, '\n'))); undo_ptr->set_selected_text(); - points_.caret = _m_erase_select(); + points_.caret = _m_erase_select(false); undo_ptr->set_caret_pos(); @@ -2177,21 +2189,24 @@ namespace nana{ namespace widgets { if (impl_->indent.generator) { - put(to_wstring(impl_->indent.generator())); + put(nana::to_wstring(impl_->indent.generator()), false); } else { auto & text = textbase.getline(points_.caret.y - 1); auto indent_pos = text.find_first_not_of(L"\t "); if (indent_pos != std::wstring::npos) - put(text.substr(0, indent_pos)); + put(text.substr(0, indent_pos), false); else - put(text); + put(text, false); } } else _m_reset_content_size(); + if (perform_event) + textbase.text_changed(); + auto origin_moved = impl_->cview->move_origin(origin - impl_->cview->origin()); if (this->_m_adjust_view() || origin_moved) @@ -2215,10 +2230,10 @@ namespace nana{ namespace widgets return; //No characters behind the caret } - backspace(); + backspace(true, true); } - void text_editor::backspace(bool record_undo) + void text_editor::backspace(bool record_undo, bool perform_event) { auto undo_ptr = std::unique_ptr(new undo_backspace(*this)); bool has_to_redraw = true; @@ -2258,7 +2273,7 @@ namespace nana{ namespace widgets else { undo_ptr->set_selected_text(); - points_.caret = _m_erase_select(); + points_.caret = _m_erase_select(false); undo_ptr->set_caret_pos(); } @@ -2267,6 +2282,11 @@ namespace nana{ namespace widgets _m_reset_content_size(false); + if (perform_event) + textbase().text_changed(); + + textbase().text_changed(); + if(has_to_redraw) { this->_m_adjust_view(); @@ -2960,7 +2980,7 @@ namespace nana{ namespace widgets select_.a = select_.b; } - nana::upoint text_editor::_m_put(std::wstring text) + nana::upoint text_editor::_m_put(std::wstring text, bool perform_event) { auto & textbase = this->textbase(); auto crtpos = points_.caret; @@ -3002,10 +3022,13 @@ namespace nana{ namespace widgets _m_pre_calc_lines(crtpos.y, 1); } + if (perform_event) + textbase.text_changed(); + return crtpos; } - nana::upoint text_editor::_m_erase_select() + nana::upoint text_editor::_m_erase_select(bool perform_event) { nana::upoint a, b; if (get_selected_points(a, b)) @@ -3027,6 +3050,9 @@ namespace nana{ namespace widgets _m_pre_calc_lines(a.y, 1); } + if (perform_event) + textbase.text_changed(); + select_.a = select_.b; return a; } @@ -3239,8 +3265,8 @@ namespace nana{ namespace widgets {//forward undo_ptr->set_caret_pos(); - _m_erase_select(); - _m_put(text); + _m_erase_select(false); + _m_put(text, false); select_.a = caret; select_.b.y = b.y + (caret.y - a.y); @@ -3249,8 +3275,8 @@ namespace nana{ namespace widgets { undo_ptr->set_caret_pos(); - _m_put(text); - _m_erase_select(); + _m_put(text, false); + _m_erase_select(false); select_.b.y = caret.y; select_.a.y = caret.y - (b.y - a.y); diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index db57ae82..6697e567 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -428,7 +428,7 @@ namespace drawerbase { if(at_caret == false) editor->move_caret_end(false); - editor->put(to_wstring(text)); + editor->put(to_wstring(text), true); editor->try_refresh(); API::update_window(this->handle()); @@ -445,7 +445,7 @@ namespace drawerbase { if(at_caret == false) editor->move_caret_end(false); - editor->put(text); + editor->put(text, true); editor->try_refresh(); API::update_window(this->handle()); From fe185e382b3b859c1ecc002e3a861ad0882ab01b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 26 Aug 2018 17:45:24 +0800 Subject: [PATCH 32/34] remove deprecated code --- include/nana/gui/widgets/listbox.hpp | 2 - .../widgets/skeletons/text_token_stream.hpp | 7 - source/detail/platform_spec_posix.cpp | 33 -- source/gui/detail/bedrock_posix.cpp | 51 --- source/gui/programming_interface.cpp | 12 - source/gui/widgets/label.cpp | 388 ------------------ 6 files changed, 493 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index d3bb5bd8..473ba9b9 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -809,7 +809,6 @@ namespace nana /// operate with absolute positions and contain only the position but montain pointers to parts of the real items /// item_proxy self, it references and iterators are not invalidated by sort() class item_proxy - //: public std::iterator //deprecated : public ::nana::widgets::detail::widget_iterator { public: @@ -984,7 +983,6 @@ namespace nana }; class cat_proxy - //: public std::iterator //deprecated : public ::nana::widgets::detail::widget_iterator { public: diff --git a/include/nana/gui/widgets/skeletons/text_token_stream.hpp b/include/nana/gui/widgets/skeletons/text_token_stream.hpp index 52c33b70..f94dfea8 100644 --- a/include/nana/gui/widgets/skeletons/text_token_stream.hpp +++ b/include/nana/gui/widgets/skeletons/text_token_stream.hpp @@ -96,13 +96,6 @@ namespace nana{ namespace widgets{ namespace skeletons return std::stoi(idstr_, nullptr, 0); } private: - /* - static bool _m_unicode_word_breakable(wchar_t ch) //deprecated - { - return ((0x4E00 <= ch) && (ch <= 0x9FFF)); - } - */ - static bool _m_unicode_word_breakable(const wchar_t* ch) noexcept { if (*ch) diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index 1a58ec6c..bf3ab2fb 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -656,38 +656,6 @@ namespace detail msg_dispatcher_->erase(reinterpret_cast(wd)); platform_scope_guard lock; -#if 0 - auto i = wincontext_.find(wd); - if(i == wincontext_.end()) return; - - if(i->second.owner) - { - auto u = wincontext_.find(i->second.owner); - if(u != wincontext_.end()) - { - auto * vec = u->second.owned; - if(vec) - { - auto j = std::find(vec->begin(), vec->end(), i->first); - if(j != vec->end()) - vec->erase(j); - } - } - } - - auto * vec = i->second.owned; - if(vec) - { - set_error_handler(); - auto & wd_manager = detail::bedrock::instance().wd_manager(); - for(auto u = vec->rbegin(); u != vec->rend(); ++u) - wd_manager.close(wd_manager.root(*u)); - - rev_error_handler(); - } - delete vec; - wincontext_.erase(i); -#else if(umake_owner(wd)) { auto i = wincontext_.find(wd); @@ -708,7 +676,6 @@ namespace detail wincontext_.erase(i); } } -#endif iconbase_.erase(wd); } diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index debbbfee..62738e98 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -1133,62 +1133,11 @@ namespace detail wd_manager.do_lazy_refresh(msgwnd, false); break; } -#if 0 - //Fall through - case XLookupChars: - if (msgwnd->flags.enabled) - { - const wchar_t* charbuf; - - nana::detail::charset_conv charset(NANA_UNICODE, "UTF-8"); - const std::string& str = charset.charset(std::string(keybuf, keybuf + len)); - charbuf = reinterpret_cast(str.c_str()); - len = str.size() / sizeof(wchar_t); - - for(int i = 0; i < len; ++i) - { - arg_keyboard arg = modifiers_status; - arg.ignore = false; - arg.key = charbuf[i]; - - // ignore Unicode BOM (it may or may not appear) - if (arg.key == 0xFEFF) continue; - - //Only accept tab when it is not ignored. - if ((keyboard::tab == arg.key) && root_runtime->condition.ignore_tab) - continue; - - if(context.is_alt_pressed) - { - arg.ctrl = arg.shift = false; - arg.evt_code = event_code::shortkey; - brock.shortkey_occurred(true); - auto shr_wd = wd_manager.find_shortkey(native_window, arg.key); - if(shr_wd) - { - arg.window_handle = reinterpret_cast(shr_wd); - brock.emit(event_code::shortkey, shr_wd, arg, true, &context); - } - continue; - } - arg.evt_code = event_code::key_char; - arg.window_handle = reinterpret_cast(msgwnd); - 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); - } - - if(brock.shortkey_occurred(false)) - context.is_alt_pressed = false; - } - break; -#else x_lookup_chars(root_runtime, msgwnd, keybuf, len, modifiers_status); break; case XLookupChars: x_lookup_chars(root_runtime, msgwnd, keybuf, len, modifiers_status); break; -#endif } wd_manager.do_lazy_refresh(msgwnd, false); diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 30f33e9a..698aa543 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -835,17 +835,6 @@ namespace API size inner_size = sz; -#if 0 - if (inner_size.width < iwd->extra_width) - inner_size.width = 0; - else - inner_size.width -= iwd->extra_width; - - if (inner_size.height < iwd->extra_height) - inner_size.height = 0; - else - inner_size.height -= iwd->extra_height; -#else if (inner_size.width < static_cast(fm_extents.left + fm_extents.right)) inner_size.width = 0; else @@ -855,7 +844,6 @@ namespace API inner_size.height = 0; else inner_size.height -= static_cast(fm_extents.top + fm_extents.bottom); -#endif window_size(wd, inner_size); } diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index 65b72c81..53ab80ae 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -20,8 +20,6 @@ #include #include -#define VISUAL_LINES - namespace nana { namespace drawerbase @@ -30,17 +28,6 @@ namespace nana { class renderer { -#ifndef VISUAL_LINES - typedef widgets::skeletons::dstream::linecontainer::iterator iterator; - - struct pixel_tag - { - int x_base; //The x position where this line starts. - std::size_t pixels; - std::size_t baseline; //The baseline for drawing text. - std::vector values; //line values - }; -#else //Iterator of content element in a line. using content_element_iterator = widgets::skeletons::dstream::linecontainer::const_iterator; //subsitute for member type iterator @@ -65,8 +52,6 @@ namespace nana std::vector elements; //description of text element in this rendering line. }; -#endif - //this is a helper variable, it just keeps the status while drawing. struct render_status { @@ -75,11 +60,7 @@ namespace nana align_v text_align_v; nana::point pos; -#ifndef VISUAL_LINES - std::vector pixels; -#else std::vector vslines; //The lines description of a line of text. substitute of member pixels. -#endif std::size_t index; //indicates the current rendering visual line. }; @@ -135,32 +116,19 @@ namespace nana rs.text_align = th; rs.text_align_v = tv; -#ifndef VISUAL_LINES - std::deque > pixel_lines; -#else //All visual lines data of whole text. std::deque> content_lines; -#endif std::size_t extent_v_pixels = 0; //the pixels, in height, that text will be painted. for (auto & line : dstream_) { -#ifndef VISUAL_LINES - _m_line_pixels(line, def_line_pixels, rs); - - for (auto & m : rs.pixels) - extent_v_pixels += m.pixels; - - pixel_lines.emplace_back(std::move(rs.pixels)); -#else _m_prepare_visual_lines(graph, line, def_line_pixels, rs); for (auto & vsline : rs.vslines) extent_v_pixels += vsline.extent_height_px; content_lines.emplace_back(std::move(rs.vslines)); -#endif if(extent_v_pixels >= graph.height()) break; @@ -176,30 +144,12 @@ namespace nana else rs.pos.y = 0; -#ifndef VISUAL_LINES - auto pixels_iterator = pixel_lines.begin(); -#else auto vsline_iterator = content_lines.begin(); -#endif for (auto & line : dstream_) { if (rs.pos.y >= static_cast(graph.height())) break; -#ifndef VISUAL_LINES - rs.index = 0; - rs.pixels.clear(); - - rs.pixels.swap(*pixels_iterator++); - - rs.pos.x = rs.pixels.front().x_base; - - //Stop drawing when it goes out of range. - if(false == _m_each_line(graph, line, rs)) - break; - - rs.pos.y += static_cast(rs.pixels.back().pixels); -#else rs.index = 0; rs.vslines.clear(); rs.vslines.swap(*vsline_iterator++); @@ -209,7 +159,6 @@ namespace nana break; rs.pos.y += static_cast(rs.vslines.back().extent_height_px); -#endif } graph.typeface(pre_font); @@ -256,13 +205,8 @@ namespace nana for(auto & line: dstream_) { -#ifndef VISUAL_LINES - rs.pixels.clear(); - unsigned w = _m_line_pixels(line, def_line_pixels, rs); -#else rs.vslines.clear(); auto w = _m_prepare_visual_lines(graph, line, def_line_pixels, rs); -#endif if(limited && (w > limited)) w = limited; @@ -270,13 +214,8 @@ namespace nana if(retsize.width < w) retsize.width = w; -#ifndef VISUAL_LINES - for (auto & px : rs.pixels) - retsize.height += static_cast(px.pixels); -#else for (auto& vsline : rs.vslines) retsize.height += static_cast(vsline.extent_height_px); -#endif } return retsize; @@ -387,23 +326,6 @@ namespace nana } } -#ifndef VISUAL_LINES - void _m_align_x_base(const render_status& rs, pixel_tag & px, unsigned w) noexcept - { - switch(rs.text_align) - { - case align::left: - px.x_base = 0; - break; - case align::center: - px.x_base = (static_cast(rs.allowed_width - w) >> 1); - break; - case align::right: - px.x_base = static_cast(rs.allowed_width - w); - break; - } - } -#else void _m_prepare_x(const render_status& rs, visual_line & vsline, unsigned w) noexcept { switch (rs.text_align) @@ -419,9 +341,6 @@ namespace nana break; } } -#endif - -#ifdef VISUAL_LINES /** * prepare data for rendering a line of text. @@ -605,180 +524,7 @@ namespace nana } return text.size(); } -#else - unsigned _m_line_pixels(dstream::linecontainer& line, unsigned def_line_pixels, render_status & rs) - { - if (line.empty()) - { - pixel_tag px; - px.baseline = 0; - px.pixels = def_line_pixels; - px.x_base = 0; - rs.pixels.emplace_back(px); - - return 0; - } - - unsigned total_w = 0; - unsigned w = 0; - unsigned max_ascent = 0; - unsigned max_descent = 0; - unsigned max_px = 0; - - //Bidi reorder is requried here - - std::vector line_values; - - for(auto i = line.begin(); i != line.end(); ++i) - { - data * data_ptr = i->data_ptr; - nana::size sz = data_ptr->size(); - total_w += sz.width; - - unsigned as = 0; //ascent - unsigned ds = 0; //descent - - if(fblock::aligns::baseline == i->fblock_ptr->text_align) - { - as = static_cast(data_ptr->ascent()); - ds = static_cast(sz.height - as); - - if(max_descent < ds) - max_descent = ds; - - if((false == data_ptr->is_text()) && (sz.height < max_ascent + max_descent)) - sz.height = max_ascent + max_descent; - } - - //Check if the content is displayed in a new line. - if((0 == rs.allowed_width) || (w + sz.width <= rs.allowed_width)) - { - w += sz.width; - - if(max_ascent < as) max_ascent = as; - if(max_descent < ds) max_descent = ds; - if(max_px < sz.height) max_px = sz.height; - line_values.emplace_back(i); - } - else - { - pixel_tag px; - _m_align_x_base(rs, px, (w ? w : sz.width)); - - if(w) - { - if(max_ascent + max_descent > max_px) - max_px = max_descent + max_ascent; - else - max_ascent = max_px - max_descent; - - px.pixels = max_px; - px.baseline = max_ascent; - px.values.swap(line_values); - - w = sz.width; - max_px = sz.height; - max_ascent = as; - max_descent = ds; - line_values.emplace_back(i); - } - else - { - px.pixels = sz.height; - px.baseline = as; - - px.values.emplace_back(i); - - max_px = 0; - max_ascent = max_descent = 0; - } - - rs.pixels.emplace_back(px); - } - } - - if (max_px) - { - pixel_tag px; - - _m_align_x_base(rs, px, w); - - if (max_ascent + max_descent > max_px) - max_px = max_descent + max_ascent; - else - max_ascent = max_px - max_descent; - - px.pixels = max_px; - px.baseline = max_ascent; - px.values.swap(line_values); - rs.pixels.emplace_back(px); - } - return total_w; - } -#endif - -#ifndef VISUAL_LINES - bool _m_each_line(graph_reference graph, dstream::linecontainer&, render_status& rs) - { - std::wstring text; - iterator block_start; - - const int lastpos = static_cast(graph.height()) - 1; - - for(auto & px : rs.pixels) - { - for(auto & render_iterator: px.values) - { - auto & value = *render_iterator; - if (value.data_ptr->is_text()) - { - //hold the block while the text is empty, - //it stands for the first block - if (text.empty()) - block_start = render_iterator; - - text += value.data_ptr->text(); - continue; - } - - if(text.size()) - { - _m_draw_block(graph, text, block_start, rs); - if(lastpos <= rs.pos.y) - return false; - text.clear(); - } - nana::size sz = value.data_ptr->size(); - - pixel_tag px = rs.pixels[rs.index]; - if ((rs.allowed_width < rs.pos.x + sz.width) && (rs.pos.x != px.x_base)) - { - //Change a line. - rs.pos.y += static_cast(px.pixels); - px = rs.pixels[++rs.index]; - rs.pos.x = px.x_base; - } - - int y = rs.pos.y + _m_text_top(px, value.fblock_ptr, value.data_ptr); - - value.data_ptr->nontext_render(graph, rs.pos.x, y); - _m_insert_if_traceable(rs.pos.x, y, sz, value.fblock_ptr); - rs.pos.x += static_cast(sz.width); - - if(lastpos < y) - return false; - } - - if(text.size()) - { - _m_draw_block(graph, text, block_start, rs); - text.clear(); - } - } - return (rs.pos.y <= lastpos); - } -#else bool _m_foreach_visual_line(graph_reference graph, render_status& rs) { std::wstring text; @@ -804,20 +550,7 @@ namespace nana return (rs.pos.y <= bottom); } -#endif - -#if 0 //deprecated - static bool _m_overline(const render_status& rs, int right, bool equal_required) noexcept - { - if(align::left == rs.text_align) - return (equal_required ? right >= static_cast(rs.allowed_width) : right > static_cast(rs.allowed_width)); - - return (equal_required ? rs.pixels[rs.index].x_base <= 0 : rs.pixels[rs.index].x_base < 0); - } -#endif - -#ifdef VISUAL_LINES static int _m_vsline_element_top(const visual_line& vsline, fblock* fblock_ptr, const data* data_ptr) noexcept { switch (fblock_ptr->text_align) @@ -832,24 +565,7 @@ namespace nana } return 0; } -#else - static int _m_text_top(const pixel_tag& px, fblock* fblock_ptr, const data* data_ptr) - { - switch(fblock_ptr->text_align) - { - case fblock::aligns::center: - return static_cast(px.pixels - data_ptr->size().height) / 2; - case fblock::aligns::bottom: - return static_cast(px.pixels - data_ptr->size().height); - case fblock::aligns::baseline: - return static_cast(px.baseline - (data_ptr->is_text() ? data_ptr->ascent() : data_ptr->size().height)); - default: break; - } - return 0; - } -#endif -#ifdef VISUAL_LINES void _m_draw_vsline_element(graph_reference graph, const visual_line::element& vsline_elm, render_status& rs) { auto data = vsline_elm.content_element->data_ptr; @@ -892,110 +608,6 @@ namespace nana rs.pos.x += static_cast(data->size().width); } } -#else - void _m_draw_block(graph_reference graph, const std::wstring& s, dstream::linecontainer::iterator block_start, render_status& rs) - { - auto const reordered = unicode_reorder(s.data(), s.length()); - - pixel_tag px = rs.pixels[rs.index]; - - for(auto & bidi : reordered) - { - std::size_t pos = bidi.begin - s.data(); - std::size_t len = bidi.end - bidi.begin; - - while (true) - { - auto i = block_start; - - //Text range indicates the position of text where begin to output - //The output length is the min between len and the second of text range. - auto text_range = _m_locate(i, pos); - - if (text_range.second > len) - text_range.second = len; - - fblock * fblock_ptr = i->fblock_ptr; - data * data_ptr = i->data_ptr; - -#if 1 - const int range_text_area = static_cast(rs.allowed_width) - rs.pos.x; - - _m_change_font(graph, fblock_ptr); - - auto text_extent_size = data_ptr->size(); -#ifndef _nana_std_has_string_view - std::wstring_view text_sv{ data_ptr->text().c_str() + text_range.first, text_range.second }; - if (data_ptr->text().size() != text_sv.size()) - text_extent_size = graph.text_extent_size(text_sv); -#else - auto text_sv = data_ptr->text().substr(text_range.first, text_range.second); - if (data_ptr->text().size() != text_sv.size()) - text_extent_size = graph.text_extent_size(text_sv); -#endif - if ((static_cast(text_extent_size.width) > range_text_area) && (rs.pos.x != px.x_base)) - { - //Change a new line - rs.pos.y += static_cast(px.pixels); - px = rs.pixels[++rs.index]; - rs.pos.x = px.x_base; - } - - const int y = rs.pos.y + _m_text_top(px, fblock_ptr, data_ptr); - graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock_ptr)); -#else - const int w = static_cast(rs.allowed_width) - rs.pos.x; - nana::size text_extent_size = data_ptr->size(); - if ((static_cast(text_extent_size.width) > w) && (rs.pos.x != px.x_base)) - { - //Change a new line - rs.pos.y += static_cast(px.pixels); - px = rs.pixels[++rs.index]; - rs.pos.x = px.x_base; - } - - const int y = rs.pos.y + _m_text_top(px, fblock_ptr, data_ptr); - - _m_change_font(graph, fblock_ptr); - -#ifdef _nana_std_has_string_view - std::wstring_view text_sv{ data_ptr->text() }; - if (text_range.second != text_sv.size()) - { - text_sv = text_sv.substr(text_range.first, text_range.second); - text_extent_size = graph.text_extent_size(text_sv); - } - - graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock_ptr)); -#else - if (text_range.second == data_ptr->text().length()) - { - graph.string({ rs.pos.x, y }, data_ptr->text(), _m_fgcolor(fblock_ptr)); - } - else - { - auto str = data_ptr->text().substr(text_range.first, text_range.second); - text_extent_size = graph.text_extent_size(str); - - graph.string({ rs.pos.x, y }, str, _m_fgcolor(fblock_ptr)); - } -#endif -#endif //#if 0 - - _m_insert_if_traceable(rs.pos.x, y, text_extent_size, fblock_ptr); - rs.pos.x += static_cast(text_extent_size.width); - - if(text_range.second < len) - { - len -= text_range.second; - pos += text_range.second; - } - else - break; - } - } - } -#endif //VISUAL_LINES static std::pair _m_locate(dstream::linecontainer::iterator& i, std::size_t pos) { From 81d667dbd799e8b238a63c698705c98554498db2 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 27 Aug 2018 06:51:20 +0800 Subject: [PATCH 33/34] using C++17 emplace return type --- include/nana/c++defines.hpp | 4 ++-- source/basic_types.cpp | 10 ++++++++-- source/gui/detail/window_manager.cpp | 8 ++++++++ source/gui/place.cpp | 6 ++++++ source/gui/place_parts.hpp | 7 +++++-- source/gui/widgets/group.cpp | 4 ++++ source/gui/widgets/label.cpp | 16 ++++++++++------ source/gui/widgets/listbox.cpp | 18 ++++++++++++++++++ source/gui/widgets/menubar.cpp | 7 +++++++ source/gui/widgets/skeletons/text_editor.cpp | 4 ++++ source/gui/widgets/tabbar.cpp | 2 +- source/unicode_bidi.cpp | 5 +++++ 12 files changed, 78 insertions(+), 13 deletions(-) diff --git a/include/nana/c++defines.hpp b/include/nana/c++defines.hpp index e7860b80..ef5d8e9f 100644 --- a/include/nana/c++defines.hpp +++ b/include/nana/c++defines.hpp @@ -220,14 +220,14 @@ #endif #undef _nana_std_has_string_view -#undef _nana_std_has_returnable_emplace_back +#undef _nana_std_has_emplace_return_type #if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && defined(_MSVC_LANG) && _MSVC_LANG >= 201703)) || \ ((__cplusplus >= 201703L) && \ (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ >= 400) || \ (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 701))) \ ) # define _nana_std_has_string_view -# define _nana_std_has_returnable_emplace_back +# define _nana_std_has_emplace_return_type #endif diff --git a/source/basic_types.cpp b/source/basic_types.cpp index 69c6fa78..dafe8574 100644 --- a/source/basic_types.cpp +++ b/source/basic_types.cpp @@ -186,10 +186,12 @@ namespace nana throw std::invalid_argument(excpt_what); std::vector rgb; - +#ifdef _nana_std_has_emplace_return_type + auto const is_real = (rgb.emplace_back(i->str()).back() == '%'); +#else rgb.emplace_back(i->str()); - const bool is_real = (rgb.back().back() == '%'); +#endif pat.assign(is_real ? "(\\d*\\.)?\\d+\\%" : "\\d+"); for (++i; i != end; ++i) @@ -275,9 +277,13 @@ namespace nana { std::vector rgb; +#ifdef _nana_std_has_emplace_return_type + auto const is_real = (rgb.emplace_back(std::move(str)).back() == '%'); +#else rgb.emplace_back(std::move(str)); const bool is_real = (rgb.back().back() == '%'); +#endif for (int i = 0; i < 2; ++i) { diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 785f45be..9d8ebd65 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -85,8 +85,12 @@ namespace nana } } +#ifdef _nana_std_has_emplace_return_type + auto & rep = impl_->base.emplace_back(); +#else impl_->base.emplace_back(); auto & rep = impl_->base.back(); +#endif rep.handle = wd; rep.keys.emplace_back(key); @@ -242,8 +246,12 @@ namespace detail return kv.second; } +#ifdef _nana_std_has_emplace_return_type + return table_.emplace_back(key).second; +#else table_.emplace_back(key); return table_.back().second; +#endif } iterator find(const Key& key) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 5b22491e..9b278111 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -742,8 +742,14 @@ namespace nana void _m_add_agent(const detail::place_agent& ag) override { +#ifdef _nana_std_has_emplace_return_type + this->operator<<( + widgets_.emplace_back(ag.create(place_ptr_->window_handle()))->handle() + ); +#else widgets_.emplace_back(ag.create(place_ptr_->window_handle())); this->operator<<(widgets_.back()->handle()); +#endif } public: division* attached{ nullptr }; diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index ca2ea8d7..2105dd02 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -436,10 +436,13 @@ namespace nana caption_.caption(wdg->caption()); } - panels_.emplace_back(); auto wdg_ptr = wdg.get(); +#ifdef _nana_std_has_emplace_return_type + panels_.emplace_back().widget_ptr = std::move(wdg); +#else + panels_.emplace_back(); panels_.back().widget_ptr.swap(wdg); - +#endif for (auto & pn : panels_) { if (pn.widget_ptr) diff --git a/source/gui/widgets/group.cpp b/source/gui/widgets/group.cpp index 8be557ef..6d697a62 100644 --- a/source/gui/widgets/group.cpp +++ b/source/gui/widgets/group.cpp @@ -136,8 +136,12 @@ namespace nana{ { _THROW_IF_EMPTY() +#ifdef _nana_std_has_emplace_return_type + auto & opt = impl_->options.emplace_back(new checkbox{ handle() }); +#else impl_->options.emplace_back(new checkbox(handle())); auto & opt = impl_->options.back(); +#endif opt->transparent(true); opt->caption(std::move(text)); impl_->place_content[field_options] << *opt; diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index 53ab80ae..013b5605 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -226,8 +226,12 @@ namespace nana { if(fbp->target.size() || fbp->url.size()) { +#ifdef _nana_std_has_emplace_return_type + auto & tr = traceable_.emplace_back(); +#else traceable_.emplace_back(); auto & tr = traceable_.back(); +#endif tr.r.x = x; tr.r.y = y; tr.r.dimension(sz); @@ -398,7 +402,7 @@ namespace nana //make a visual line for existing vsline elements if (text_pos) { -#ifdef _nana_std_has_returnable_emplace_back +#ifdef _nana_std_has_emplace_return_type auto & vsline = rs.vslines.emplace_back(); #else rs.vslines.emplace_back(); @@ -449,7 +453,7 @@ namespace nana if (text_begin + sub_text_len < data->text().size()) { //make a new visual line -#ifdef _nana_std_has_returnable_emplace_back +#ifdef _nana_std_has_emplace_return_type auto & vsline = rs.vslines.emplace_back(); #else rs.vslines.emplace_back(); @@ -483,7 +487,7 @@ namespace nana if (!vsline_elements.empty()) { -#ifdef _nana_std_has_returnable_emplace_back +#ifdef _nana_std_has_emplace_return_type auto & vsline = rs.vslines.emplace_back(); #else rs.vslines.emplace_back(); @@ -515,14 +519,14 @@ namespace nana #endif text_px = 0; - for (std::size_t i = 0; i < text.size(); ++i) + for (unsigned i = 0; i < text.size(); ++i) { if (text_px + pxbuf[i] > limited_width_px) return i; text_px += pxbuf[i]; } - return text.size(); + return static_cast(text.size()); } bool _m_foreach_visual_line(graph_reference graph, render_status& rs) @@ -542,7 +546,7 @@ namespace nana } ++rs.index; //next line index - rs.pos.y += vsline.extent_height_px; + rs.pos.y += static_cast(vsline.extent_height_px); if (rs.pos.y > bottom) return false; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index f25ac277..489f6611 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -312,8 +312,12 @@ namespace nana size_type create(essence* ess, native_string_type&& text, unsigned pixels) { +#ifdef _nana_std_has_emplace_return_type + return cont_.emplace_back(ess, std::move(text), pixels, static_cast(cont_.size())).index; +#else cont_.emplace_back(ess, std::move(text), pixels, static_cast(cont_.size())); return cont_.back().index; +#endif } void clear() @@ -1023,9 +1027,15 @@ namespace nana } } +#ifdef _nana_std_has_emplace_return_type + auto & last_cat = categories_.emplace_back(); + last_cat.key_ptr = ptr; + return &last_cat; +#else categories_.emplace_back(); categories_.back().key_ptr = ptr; return &(categories_.back()); +#endif } /// Inserts a new category at position specified by pos @@ -1033,8 +1043,12 @@ namespace nana { if (::nana::npos == pos) { +#ifdef _nana_std_has_emplace_return_type + return &categories_.emplace_back(std::move(text)); +#else categories_.emplace_back(std::move(text)); return &categories_.back(); +#endif } return &(*categories_.emplace(this->get(pos), std::move(text))); @@ -2622,8 +2636,12 @@ namespace nana oresolver& oresolver::operator<<(std::nullptr_t) { +#ifdef _nana_std_has_emplace_return_type + cells_.emplace_back().text.assign(1, wchar_t{}); +#else cells_.emplace_back(); cells_.back().text.assign(1, wchar_t(0)); //means invalid cell +#endif return *this; } diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 3c211ba6..94d7c6c2 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -89,11 +89,18 @@ namespace nana if (shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41); + +#ifdef _nana_std_has_emplace_return_type + auto & last = items.emplace_back(new item_type{std::move(transformed_text), shortkey, shortkey_pos}); + API::refresh_window(*widget_ptr); + return last->menu_obj; +#else items.emplace_back(new item_type{ std::move(transformed_text), shortkey, shortkey_pos }); API::refresh_window(*widget_ptr); return this->items.back()->menu_obj; +#endif } bool cancel() diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 0510acd9..ca070ace 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1009,8 +1009,12 @@ namespace nana{ namespace widgets auto ki = keywords.schemes.find(ds.scheme); if ((ki != keywords.schemes.end()) && ki->second) { +#ifdef _nana_std_has_emplace_return_type + auto & last = entities.emplace_back(); +#else entities.emplace_back(); auto & last = entities.back(); +#endif last.begin = c_str + pos; last.end = last.begin + ds.text.size(); last.scheme = ki->second.get(); diff --git a/source/gui/widgets/tabbar.cpp b/source/gui/widgets/tabbar.cpp index f0a972c9..8970089b 100644 --- a/source/gui/widgets/tabbar.cpp +++ b/source/gui/widgets/tabbar.cpp @@ -750,8 +750,8 @@ namespace nana { if((pos == npos) || (pos >= list_.size())) { + pos = list_.size(); this->list_.emplace_back(); - pos = list_.size() - 1; } else list_.emplace(iterator_at(pos)); diff --git a/source/unicode_bidi.cpp b/source/unicode_bidi.cpp index 3591d6ef..32ca0541 100644 --- a/source/unicode_bidi.cpp +++ b/source/unicode_bidi.cpp @@ -1,4 +1,5 @@ #include +#include namespace nana { @@ -611,8 +612,12 @@ namespace nana void unicode_bidi::_m_push_entity(const char_type * begin, const char_type *end, unsigned level, bidi_char bidi_char_type) { +#ifdef _nana_std_has_emplace_return_type + auto & e = levels_.emplace_back(); +#else levels_.emplace_back(); auto & e = levels_.back(); +#endif e.begin = begin; e.end = end; e.level = level; From 1145e3d5cd58397812941712170975641a74ba8a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 28 Aug 2018 07:31:05 +0800 Subject: [PATCH 34/34] fix crash that occurs when rendering an empty label(#333) --- source/gui/widgets/label.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index 013b5605..26be5a95 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -351,6 +351,22 @@ namespace nana */ unsigned _m_prepare_visual_lines(graph_reference graph, dstream::linecontainer& line, unsigned def_line_px, render_status& rs) { + if (line.empty()) + { + //Insert an empty visual line for empty content. +#ifdef _nana_std_has_emplace_return_type + auto & vsline = rs.vslines.emplace_back(); +#else + rs.vslines.emplace_back(); + auto & vsline = rs.vslines.back(); + + vsline.baseline = 0; + vsline.extent_height_px = def_line_px; + vsline.x_base = 0; +#endif + return 0; + } + unsigned abs_text_px = 0; unsigned max_ascent = 0; unsigned max_descent = 0;