From c5b38f36434832ca86eb6661d8bb21eadf3420d4 Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Thu, 18 Apr 2019 17:12:31 -0400 Subject: [PATCH 01/61] bug: second parameter of category_icon() is rvalue reference --- source/gui/widgets/listbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 3e127628..eaed5195 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -6042,7 +6042,7 @@ namespace nana return *this; } - listbox& listbox::category_icon(const paint::image& img_expanded, const paint::image&& img_collapsed) + 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) From e36a3270e91fb03808256cf41ef9bb4abd2fce18 Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Thu, 18 Apr 2019 17:13:19 -0400 Subject: [PATCH 02/61] bug: second parameter of category_icon() is rvalue reference --- include/nana/gui/widgets/listbox.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index b6279630..5adeb748 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1568,7 +1568,7 @@ the nana::detail::basic_window member pointer scheme * @param img_collapsed An icon displayed in front of category title when the category is collapsed. * @return the reference of *this. */ - listbox& category_icon(const paint::image& img_expanded, const paint::image&& img_collapsed); + listbox& category_icon(const paint::image& img_expanded, const paint::image& img_collapsed); /// Returns first visible element /** From ec38e666a11934b3c78ba1b7ee4ee5e2a41b4573 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 24 Apr 2019 01:18:27 +0800 Subject: [PATCH 03/61] fix bug that grayscale png is mistakely processed --- source/paint/detail/image_png.hpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/source/paint/detail/image_png.hpp b/source/paint/detail/image_png.hpp index 91dd8e2b..8125fe99 100644 --- a/source/paint/detail/image_png.hpp +++ b/source/paint/detail/image_png.hpp @@ -30,16 +30,21 @@ namespace nana png_byte color_type = ::png_get_color_type(png_ptr, info_ptr); const auto bit_depth = ::png_get_bit_depth(png_ptr, info_ptr); + pixbuf_.open(png_width, png_height); + //do some extra work for palette/gray color type if (PNG_COLOR_TYPE_PALETTE == color_type) ::png_set_palette_to_rgb(png_ptr); - else if ((PNG_COLOR_TYPE_GRAY == color_type) && (bit_depth < 8)) + else if ((PNG_COLOR_TYPE_GRAY == color_type) || (PNG_COLOR_TYPE_GRAY_ALPHA == color_type)) ::png_set_gray_to_rgb(png_ptr); auto is_alpha_enabled = (::png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0); if (is_alpha_enabled) ::png_set_tRNS_to_alpha(png_ptr); + is_alpha_enabled |= ((PNG_COLOR_MASK_ALPHA & color_type) != 0); + pixbuf_.alpha_channel(is_alpha_enabled); + //make sure 8-bit per channel if (16 == bit_depth) ::png_set_strip_16(png_ptr); @@ -51,11 +56,6 @@ namespace nana png_bytep * row_ptrs = new png_bytep[png_height]; const std::size_t png_rowbytes = ::png_get_rowbytes(png_ptr, info_ptr); - pixbuf_.open(png_width, png_height); - - is_alpha_enabled |= ((PNG_COLOR_MASK_ALPHA & color_type) != 0); - pixbuf_.alpha_channel(is_alpha_enabled); - if (is_alpha_enabled && (png_rowbytes == png_width * sizeof(pixel_argb_t))) { for (int i = 0; i < png_height; ++i) @@ -63,14 +63,17 @@ namespace nana ::png_read_image(png_ptr, row_ptrs); - for (int i = 0; i < png_height; ++i) + if (std::is_same::value) { - auto p = pixbuf_.raw_ptr(i); - for (int u = 0; u < png_width; ++u) + for (int i = 0; i < png_height; ++i) { - auto t = p[u].element.red; - p[u].element.red = p[u].element.blue; - p[u].element.blue = t; + auto p = pixbuf_.raw_ptr(i); + for (int u = 0; u < png_width; ++u) + { + auto t = p[u].element.red; + p[u].element.red = p[u].element.blue; + p[u].element.blue = t; + } } } } @@ -82,7 +85,6 @@ namespace nana row_ptrs[i] = reinterpret_cast(png_pixbuf + png_rowbytes * i); ::png_read_image(png_ptr, row_ptrs); - //::png_destroy_read_struct(&png_ptr, &info_ptr, 0); std::size_t png_pixel_bytes = png_rowbytes / png_width; From 662a9b6b80b66e1fce78eca963872341a38cdd03 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 3 Nov 2018 01:52:25 +0100 Subject: [PATCH 04/61] FIX big executables in release mode: from 103 MB to 3 MB --- build/cmake/compilers.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/cmake/compilers.cmake b/build/cmake/compilers.cmake index 8cc53765..80daf9e9 100644 --- a/build/cmake/compilers.cmake +++ b/build/cmake/compilers.cmake @@ -17,6 +17,9 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AN target_compile_options(nana PRIVATE -Wall PUBLIC -g ) + # todo: set in target property of nana + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -mtune=native -DNDEBUG") + set(THREADS_PREFER_PTHREAD_FLAG ON) # todo - test this find_package(Threads REQUIRED) target_link_libraries(nana PRIVATE Threads::Threads) From ce3dd2e9a1289974bd3f672fa590d5752bf9be35 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 17 Jan 2019 12:58:44 +0100 Subject: [PATCH 05/61] scheme code format --- include/nana/gui/widgets/group.hpp | 5 ++++- include/nana/gui/widgets/listbox.hpp | 5 ++++- include/nana/gui/widgets/spinbox.hpp | 5 ++++- include/nana/gui/widgets/treebox.hpp | 4 +++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/nana/gui/widgets/group.hpp b/include/nana/gui/widgets/group.hpp index 6188ccce..d62a7abf 100644 --- a/include/nana/gui/widgets/group.hpp +++ b/include/nana/gui/widgets/group.hpp @@ -35,7 +35,10 @@ namespace nana{ }//end namespace drawerbase class group - : public widget_object + : public widget_object { struct implement; public: diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 1d9cdec0..52680582 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1292,7 +1292,10 @@ the nana::detail::basic_window member pointer scheme \example listbox_Resolver.cpp */ class listbox - : public widget_object, + : public widget_object, public concepts::any_objective { public: diff --git a/include/nana/gui/widgets/spinbox.hpp b/include/nana/gui/widgets/spinbox.hpp index d1f779e0..2f489f1d 100644 --- a/include/nana/gui/widgets/spinbox.hpp +++ b/include/nana/gui/widgets/spinbox.hpp @@ -77,7 +77,10 @@ namespace nana /// Spinbox Widget class spinbox - : public widget_object + : public widget_object { public: /// Constructs a spinbox. diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index fd48b022..4d832c27 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -350,7 +350,9 @@ namespace nana /// \brief Displays a hierarchical list of items, such as the files and directories on a disk. /// See also in [documentation](http://nanapro.org/en-us/documentation/widgets/treebox.htm) class treebox - :public widget_object + :public widget_object < category::widget_tag, + drawerbase::treebox::trigger, + drawerbase::treebox::treebox_events> { public: /// A type refers to the item and is also used to iterate through the nodes. From d18a4e9506a62d15246e2b0fd95e513fff5ad01a Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 30 Mar 2019 11:09:38 +0100 Subject: [PATCH 06/61] LanguageStandard -> stdcpplatest --- build/vc2017/nana.vcxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/vc2017/nana.vcxproj b/build/vc2017/nana.vcxproj index 7ae3d890..911548d5 100644 --- a/build/vc2017/nana.vcxproj +++ b/build/vc2017/nana.vcxproj @@ -102,6 +102,7 @@ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) MultiThreadedDebug true + stdcpplatest Windows @@ -116,6 +117,7 @@ _DEBUG;_LIB;%(PreprocessorDefinitions) MultiThreadedDebug true + stdcpplatest Windows @@ -132,6 +134,7 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) MultiThreaded true + stdcpplatest Windows @@ -150,6 +153,7 @@ NDEBUG;_LIB;%(PreprocessorDefinitions) MultiThreaded true + stdcpplatest Windows From 77dd467f73aaf96561d417899ceb4092a34c7d7e Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 9 Apr 2019 13:11:20 +0200 Subject: [PATCH 07/61] Add field name to place error --- source/gui/place.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 968d8736..591e6a5a 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -42,7 +42,7 @@ namespace nana void check_field_name(const char* name) { if (*name && (*name != '_' && !(('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z')))) - throw std::invalid_argument("nana.place: bad field name"); + throw std::invalid_argument(std::string("nana.place: bad field name '")+name+"'."); } }//end namespace place_parts @@ -3358,7 +3358,7 @@ namespace nana //if name violate the naming convention. place_parts::check_field_name(name); - //get the field with specified name, if no such field with specified name + //get the field with the specified name. If no such field with specified name //then create one. auto & p = impl_->fields[name]; if (nullptr == p) @@ -3367,12 +3367,12 @@ namespace nana if ((!p->attached) && impl_->root_division) { //search the division with the specified name, - //and attached the division to the field + //and attaches the division to the field auto div = implement::search_div_name(impl_->root_division.get(), name); if (div) { if (div->field && (div->field != p)) - throw std::runtime_error("nana.place: unexpected error, the division attaches an unexpected field."); + throw std::runtime_error(std::string("nana.place: unexpected error, the division attaches an unexpected field: ") + name); div->field = p; p->attached = div; From 6b3c02b55854e041aaf1ab6e807299ee08001848 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 14 Apr 2019 00:43:45 +0200 Subject: [PATCH 08/61] introduce place::error and badname --- include/nana/gui/place.hpp | 26 ++++++++++++ source/gui/place.cpp | 81 ++++++++++++++++---------------------- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index a20bd50b..1cc8a48c 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -79,6 +79,7 @@ namespace nana { struct implement; + class field_interface { field_interface(const field_interface&) = delete; @@ -103,6 +104,25 @@ namespace nana virtual void _m_add_agent(const detail::place_agent&) = 0; }; public: + class error :public ::std::invalid_argument + { + public: + error(::std::string what, + const place& plc, + std::string field = "unknown", + std::string::size_type pos = std::string::npos) + + : std::invalid_argument(what), + owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, + field{ field }, + div_text{ plc.div() }, + pos{ pos } + {} + std::string owner_caption; ///< truncate caption (title) of the "placed" widget + std::string div_text; + std::string field; ///< posible field where the error ocurred. + std::string::size_type pos; ///< posible position in the div_text where the error ocurred. npos if unknown + }; /// reference to a field manipulator which refers to a field object created by place using field_reference = field_interface &; @@ -121,6 +141,10 @@ namespace nana void div(std::string div_text); ///< Divides the attached widget into fields. const std::string& div() const noexcept; ///< Returns div-text that depends on fields status. + static bool check_field_name(const char* name) ///< must begin with _a-zA-Z + { + return name && (*name == '_' || (('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z'))); + } void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. field_reference field(const char* name);///< Returns a field with the specified name. @@ -152,6 +176,8 @@ namespace nana private: implement * impl_; }; + + }//end namespace nana #include diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 591e6a5a..418b515d 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -36,16 +36,16 @@ namespace nana { - namespace place_parts + struct badname: place::error { - //check the name - void check_field_name(const char* name) - { - if (*name && (*name != '_' && !(('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z')))) - throw std::invalid_argument(std::string("nana.place: bad field name '")+name+"'."); - } - }//end namespace place_parts - + explicit badname( ::std::string what, + const place& plc, + const char* name = "unknown", + std::string::size_type pos = std::string::npos) + :place::error(what + ": bad field name '" + (name ? name : "nullptr") + "'.", + plc, (name ? name : "nullptr"), pos) + {} + }; typedef place_parts::number_t number_t; typedef place_parts::repeated_array repeated_array; @@ -73,7 +73,7 @@ namespace nana return idstr_; } - const number_t& number() const + const number_t& number() const noexcept { return number_; } @@ -3272,22 +3272,18 @@ namespace nana void place::modify(const char* name, const char* div_text) { if (nullptr == div_text) - throw std::invalid_argument("nana.place: invalid div-text"); + throw error("nana::place.modify(): invalid div-text (nullptr)", *this); - if (nullptr == name) name = ""; - - //check the name, it throws std::invalid_argument - //if name violate the naming convention. - place_parts::check_field_name(name); + if (! place::check_field_name(name) ) + throw badname("nana::place.modify()", *this, name); auto div_ptr = impl_->search_div_name(impl_->root_division.get(), name); if (!div_ptr) { - std::string what = "nana::place: field '"; + std::string what = "nana::place.modify(): field '"; what += name; - what += "' is not found."; - - throw std::invalid_argument(what); + what += "' was not found."; + throw error(what, *this, name); } std::unique_ptr* replaced = nullptr; @@ -3342,7 +3338,7 @@ namespace nana } } } - catch (...) + catch (...) /// todo throw error !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! { replaced->swap(impl_->tmp_replaced); throw; @@ -3351,12 +3347,8 @@ namespace nana place::field_reference place::field(const char* name) { - if (nullptr == name) - name = ""; - - //check the name, it throws std::invalid_argument - //if name violate the naming convention. - place_parts::check_field_name(name); + if (!place::check_field_name(name)) + throw badname("nana::place.field()", *this, name); //get the field with the specified name. If no such field with specified name //then create one. @@ -3372,7 +3364,8 @@ namespace nana if (div) { if (div->field && (div->field != p)) - throw std::runtime_error(std::string("nana.place: unexpected error, the division attaches an unexpected field: ") + name); + throw error(std::string("nana::place.field(): unexpected error, the division attaches an unexpected field: ") + name, + *this, name); div->field = p; p->attached = div; @@ -3449,10 +3442,8 @@ namespace nana void place::field_visible(const char* name, bool vsb) { - if (!name) name = ""; - - //May throw std::invalid_argument - place_parts::check_field_name(name); + if (!place::check_field_name(name)) + throw badname("set nana::place.field_visible()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); if (div) @@ -3464,10 +3455,8 @@ namespace nana bool place::field_visible(const char* name) const { - if (!name) name = ""; - - //May throw std::invalid_argument - place_parts::check_field_name(name); + if (!place::check_field_name(name)) + throw badname("get nana::place.field_visible()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); return (div && div->visible); @@ -3475,10 +3464,8 @@ namespace nana void place::field_display(const char* name, bool dsp) { - if (!name) name = ""; - - //May throw std::invalid_argument - place_parts::check_field_name(name); + if (!place::check_field_name(name)) + throw badname("set nana::place.field_display()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); if (div) @@ -3491,10 +3478,8 @@ namespace nana bool place::field_display(const char* name) const { - if (!name) name = ""; - - //May throw std::invalid_argument - place_parts::check_field_name(name); + if (!place::check_field_name(name)) + throw badname("get nana::place.field_display()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); return (div && div->display); @@ -3531,9 +3516,8 @@ namespace nana place& place::dock(const std::string& name, std::string factory_name, std::function(window)> factory) { - //check the name, it throws std::invalid_argument - //if name violate the naming convention. - place_parts::check_field_name(name.data()); + if (!place::check_field_name(name.data())) + throw badname("get nana::place.field_display()", *this, name.data()); auto & dock_ptr = impl_->docks[name]; if (!dock_ptr) @@ -3601,6 +3585,9 @@ namespace nana return nullptr; } //end class place + + //class place::error + }//end namespace nana #include From 064d59de136aac4b7a5c9d07734eb00a614f3de1 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 14 Apr 2019 01:12:19 +0200 Subject: [PATCH 09/61] rename to valid_field_name --- include/nana/gui/place.hpp | 2 +- source/gui/place.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index 1cc8a48c..24cf9382 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -141,7 +141,7 @@ namespace nana void div(std::string div_text); ///< Divides the attached widget into fields. const std::string& div() const noexcept; ///< Returns div-text that depends on fields status. - static bool check_field_name(const char* name) ///< must begin with _a-zA-Z + static bool valid_field_name(const char* name) ///< must begin with _a-zA-Z { return name && (*name == '_' || (('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z'))); } diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 418b515d..4fb3ebab 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -3274,7 +3274,7 @@ namespace nana if (nullptr == div_text) throw error("nana::place.modify(): invalid div-text (nullptr)", *this); - if (! place::check_field_name(name) ) + if (! valid_field_name(name) ) throw badname("nana::place.modify()", *this, name); auto div_ptr = impl_->search_div_name(impl_->root_division.get(), name); @@ -3347,7 +3347,7 @@ namespace nana place::field_reference place::field(const char* name) { - if (!place::check_field_name(name)) + if (!valid_field_name(name)) throw badname("nana::place.field()", *this, name); //get the field with the specified name. If no such field with specified name @@ -3442,7 +3442,7 @@ namespace nana void place::field_visible(const char* name, bool vsb) { - if (!place::check_field_name(name)) + if (!valid_field_name(name)) throw badname("set nana::place.field_visible()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); @@ -3455,7 +3455,7 @@ namespace nana bool place::field_visible(const char* name) const { - if (!place::check_field_name(name)) + if (!valid_field_name(name)) throw badname("get nana::place.field_visible()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); @@ -3464,7 +3464,7 @@ namespace nana void place::field_display(const char* name, bool dsp) { - if (!place::check_field_name(name)) + if (!valid_field_name(name)) throw badname("set nana::place.field_display()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); @@ -3478,7 +3478,7 @@ namespace nana bool place::field_display(const char* name) const { - if (!place::check_field_name(name)) + if (!valid_field_name(name)) throw badname("get nana::place.field_display()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); @@ -3516,7 +3516,7 @@ namespace nana place& place::dock(const std::string& name, std::string factory_name, std::function(window)> factory) { - if (!place::check_field_name(name.data())) + if (!valid_field_name(name.data())) throw badname("get nana::place.field_display()", *this, name.data()); auto & dock_ptr = impl_->docks[name]; From 7830f430c0fc8af10f1f045c7000fcdc019e494e Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 14 Apr 2019 19:44:51 +0200 Subject: [PATCH 10/61] tokenizer::error --- source/gui/place.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 4fb3ebab..a9177e28 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -54,6 +54,18 @@ namespace nana class tokenizer { public: + struct error : std::invalid_argument + { + error(std::string what, + const tokenizer& tok) + + : std::invalid_argument{ what + " from tokenizer at position " + + std::to_string(static_cast(tok.sp_ - tok.divstr_)) }, + pos{static_cast(tok.sp_ - tok.divstr_)} + {} + std::string::size_type pos; + }; + enum class token { div_start, div_end, splitter, @@ -462,8 +474,8 @@ namespace nana return 0; } private: - const char* divstr_; - const char* sp_; + const char* divstr_{}; + const char* sp_{}; std::string idstr_; number_t number_; std::vector array_; From 1d2e489c7fdff1554111229fc3695f6f07a35fd4 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 14 Apr 2019 23:28:28 +0200 Subject: [PATCH 11/61] full error msg at one place --- include/nana/gui/place.hpp | 40 ++++++++++++++++++++++---------------- source/gui/place.cpp | 3 +-- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index 24cf9382..56f27f34 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -1,16 +1,16 @@ -/* +/** * An Implementation of Place for Layout * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/place.cpp + * @file nana/gui/place.cpp * - * @contributions: - * min/max and splitter bar initial weight by Ariel Vina-Rodriguez. + * @contributions + * error, width/height, min/max and splitter bar initial weight by Ariel Vina-Rodriguez. */ #ifndef NANA_GUI_PLACE_HPP @@ -104,23 +104,29 @@ namespace nana virtual void _m_add_agent(const detail::place_agent&) = 0; }; public: - class error :public ::std::invalid_argument + class error :public std::invalid_argument { public: - error(::std::string what, + error( const std::string& what, const place& plc, std::string field = "unknown", std::string::size_type pos = std::string::npos) - : std::invalid_argument(what), - owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, - field{ field }, - div_text{ plc.div() }, - pos{ pos } + : std::invalid_argument{ "Place error " + what + + " from widget " + API::window_caption(plc.window_handle()).substr(0,80) + + " in fleld " + field + + ( pos == std::string::npos ? "" : "at at position " + std::to_string(pos) ) + + "in div_text:\n" + plc.div()}, + base_what { what }, + owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, + field { field }, + div_text { plc.div() }, + pos { pos } {} - std::string owner_caption; ///< truncate caption (title) of the "placed" widget - std::string div_text; - std::string field; ///< posible field where the error ocurred. + std::string base_what; + std::string owner_caption; ///< truncate caption (title) of the "placed" widget + std::string div_text; ///< involved div_text + std::string field; ///< posible field where the error ocurred. std::string::size_type pos; ///< posible position in the div_text where the error ocurred. npos if unknown }; /// reference to a field manipulator which refers to a field object created by place @@ -139,8 +145,8 @@ namespace nana void splitter_renderer(std::function fn); - void div(std::string div_text); ///< Divides the attached widget into fields. - const std::string& div() const noexcept; ///< Returns div-text that depends on fields status. + void div(std::string div_text); ///< Divides the attached widget into fields. May throw placa::error + const std::string& div() const noexcept; ///< Returns div-text that depends on fields status. static bool valid_field_name(const char* name) ///< must begin with _a-zA-Z { return name && (*name == '_' || (('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z'))); diff --git a/source/gui/place.cpp b/source/gui/place.cpp index a9177e28..b6cc7804 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -59,8 +59,7 @@ namespace nana error(std::string what, const tokenizer& tok) - : std::invalid_argument{ what + " from tokenizer at position " - + std::to_string(static_cast(tok.sp_ - tok.divstr_)) }, + : std::invalid_argument{ what + " from tokenizer " }, pos{static_cast(tok.sp_ - tok.divstr_)} {} std::string::size_type pos; From 5b1d0b46062e46f0cc868de1a9f4de66e5647fab Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 14 Apr 2019 23:29:33 +0200 Subject: [PATCH 12/61] tokenizer errors --- source/gui/place.cpp | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index b6cc7804..c6de0c14 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -148,9 +148,13 @@ namespace nana while (true) { sp_ = _m_eat_whitespace(sp_); - auto tk = read(); - if (token::number != tk && token::variable != tk && token::repeated != tk) - _m_throw_error("invalid array element"); + auto tk = read(); // try ?? + + if ( token::number != tk + && token::variable != tk + && token::repeated != tk) + + throw error("invalid array element. Expected a number, variable or repaet", *this); if (!repeated) { @@ -176,7 +180,7 @@ namespace nana return (repeated ? token::reparray : token::array); if (ch != ',') - _m_throw_error("invalid array"); + throw error("invalid array", *this); } } break; @@ -194,7 +198,7 @@ namespace nana if (token::number == read()) parameters_.push_back(number_); else - _m_throw_error("invalid parameter."); + throw error("invalid parameter. Expected a number", *this); sp_ = _m_eat_whitespace(sp_); char ch = *sp_++; @@ -203,7 +207,7 @@ namespace nana return token::parameters; if (ch != ',') - _m_throw_error("invalid parameter."); + throw error("invalid parameter. Expected a ','", *this); } break; case '.': case '-': @@ -222,7 +226,7 @@ namespace nana return token::number; } else - _m_throw_error("invalid character '" + std::string(1, *sp_) + "'"); + throw("invalid character '" + std::string(1, *sp_) + "'", *this); break; default: if ('0' <= *sp_ && *sp_ <= '9') @@ -280,14 +284,14 @@ namespace nana { auto idstr = idstr_; if (token::equal != read()) - _m_throw_error("an equal sign is required after '" + idstr + "'"); + throw error("an equal sign is required after '" + idstr + "'", *this); return ('g' == idstr[0] ? token::grid : token::margin); } else if ("collapse" == idstr_) { if (token::parameters != read()) - _m_throw_error("a parameter list is required after 'collapse'"); + throw error("a parameter list is required after 'collapse'", *this); return token::collapse; } else if (!idstr_.empty()) @@ -344,22 +348,14 @@ namespace nana return token::identifier; } - std::string err = "an invalid character '"; - err += *sp_; - err += "'"; - _m_throw_error(err); + throw("invalid character '" + std::string(1, *sp_) + "'", *this); return token::error; //Useless, just for syntax correction. } private: - void _m_throw_error(const std::string& err) - { - throw std::runtime_error("nana::place: " + err + " at " + std::to_string(static_cast(sp_ - divstr_))); - } - void _m_attr_number_value() { if (token::equal != read()) - _m_throw_error("an equal sign is required after '" + idstr_ + "'"); + throw error("an equal sign is required after '" + idstr_ + "'", *this); auto p = _m_eat_whitespace(sp_); @@ -369,7 +365,7 @@ namespace nana auto len = _m_number(p, neg_ptr != p); if (0 == len) - _m_throw_error("the '" + idstr_ + "' requires a number(integer or real or percent)"); + throw error("the '" + idstr_ + "' requires a number (integer, real or percent)", *this); sp_ += len + (p - sp_); } @@ -378,7 +374,7 @@ namespace nana { auto idstr = idstr_; if (token::equal != read()) - _m_throw_error("an equal sign is required after '" + idstr + "'"); + throw error("an equal sign is required after '" + idstr + "'", *this); sp_ = _m_eat_whitespace(sp_); @@ -396,19 +392,21 @@ namespace nana case token::reparray: break; default: - _m_throw_error("a (repeated) array is required after '" + idstr + "'"); + throw error("a (repeated) array is required after '" + idstr + "'", *this); } } static const char* _m_eat_whitespace(const char* sp) noexcept { - while (*sp && !std::isgraph(*sp)) + while (*sp && !std::isgraph(int(*sp))) ++sp; return sp; } std::size_t _m_number(const char* sp, bool negative) noexcept { + /// \todo use std::from_char() etc. + const char* allstart = sp; sp = _m_eat_whitespace(sp); From 45bb9f4318fc006aaf593acea216dd0b70b1635d Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 14 Apr 2019 23:31:08 +0200 Subject: [PATCH 13/61] \todo introduce a place::implement::field_gather::error ?? --- source/gui/place.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index c6de0c14..88c76bca 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -490,8 +490,7 @@ namespace nana { return (vert ? pos.y : pos.x); } - - + static bool is_idchar(int ch) noexcept { return ('_' == ch || std::isalnum(ch)); @@ -499,6 +498,7 @@ namespace nana static std::size_t find_idstr(const std::string& text, const char* idstr, std::size_t off = 0) { + if (!idstr) return text.npos; /// ?? const auto len = std::strlen(idstr); size_t pos; @@ -652,6 +652,8 @@ namespace nana : public place::field_interface { public: + + /// \todo introduce a place::implement::field_gather::error ?? struct element_t { window handle; @@ -701,13 +703,13 @@ namespace nana return nullptr; } private: - void _m_insert_widget(window wd, bool to_fasten) + void _m_insert_widget(window wd, bool to_fasten) /// \todo better errors caption of failed windows, field { if (API::empty_window(wd)) - throw std::invalid_argument("Place: An invalid window handle."); + throw place::error("Failed to insert an invalid window handle.", *place_ptr_); if (API::get_parent_window(wd) != place_ptr_->window_handle()) - throw std::invalid_argument("Place: the window is not a child of place bind window"); + throw place::error("Failed to insert a window which is not a child of the place-binded window", *place_ptr_); //Listen to destroy of a window //It will delete the element and recollocate when the window destroyed. From 003ffee01a07718b2f53b5807de540fe1696fd20 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 20 Apr 2019 23:10:28 +0200 Subject: [PATCH 14/61] implement error --- source/gui/place.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 88c76bca..d334a579 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -54,6 +54,7 @@ namespace nana class tokenizer { public: + /// \todo add member full_what and overrider what() in internal exeptions struct error : std::invalid_argument { error(std::string what, @@ -605,6 +606,17 @@ namespace nana //struct implement struct place::implement { + /// usefull ?? + struct error : std::invalid_argument + { + error(std::string what, + const implement& impl) + + : std::invalid_argument{ what + " from implementation " }/*, + pos{ static_cast(tok.sp_ - tok.divstr_) }*/ + {} + std::string::size_type pos; + }; class field_gather; class field_dock; @@ -1999,7 +2011,7 @@ namespace nana std::string::size_type tag_pos{ left ? div.find('<', bound.second + 2) : div.rfind('>', bound.first - 2) }; if (div.npos == tag_pos) - throw std::invalid_argument("please report an issue if it throws"); + throw place::error("please report an issue: unable to update division " + div, impl_-> ); auto other_bound = get_field_boundary(div, tag_pos); @@ -3263,7 +3275,7 @@ namespace nana impl_->root_division.swap(div); impl_->div_text.swap(div_text); } - catch (...) + catch (...) // tokenizer error { //redefined a name of field throw; From 74b486e267b9e940b550a8d2291f1a35cdbecf2d Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 3 May 2019 14:52:28 +0200 Subject: [PATCH 15/61] first "working" version of place::error - compiles and run when Ok tested with some errors as espected --- include/nana/gui/place.hpp | 20 +- source/gui/place.cpp | 667 ++++++++++++++++++++----------------- 2 files changed, 359 insertions(+), 328 deletions(-) diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index 56f27f34..f90298ab 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -107,22 +107,10 @@ namespace nana class error :public std::invalid_argument { public: - error( const std::string& what, - const place& plc, - std::string field = "unknown", - std::string::size_type pos = std::string::npos) - - : std::invalid_argument{ "Place error " + what - + " from widget " + API::window_caption(plc.window_handle()).substr(0,80) - + " in fleld " + field - + ( pos == std::string::npos ? "" : "at at position " + std::to_string(pos) ) - + "in div_text:\n" + plc.div()}, - base_what { what }, - owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, - field { field }, - div_text { plc.div() }, - pos { pos } - {} + error( const std::string& what, + const place& plc, + std::string field = "unknown", + std::string::size_type pos = std::string::npos); std::string base_what; std::string owner_caption; ///< truncate caption (title) of the "placed" widget std::string div_text; ///< involved div_text diff --git a/source/gui/place.cpp b/source/gui/place.cpp index d334a579..c932f78f 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -61,9 +61,11 @@ namespace nana const tokenizer& tok) : std::invalid_argument{ what + " from tokenizer " }, - pos{static_cast(tok.sp_ - tok.divstr_)} + pos{tok.pos()}, + div_str(tok.divstr_) {} std::string::size_type pos; + std::string div_str; }; enum class token @@ -105,9 +107,9 @@ namespace nana return parameters_; } - std::size_t pos() const noexcept + std::string::size_type pos() const noexcept { - return (sp_ - divstr_); + return static_cast(sp_ - divstr_); } token read() @@ -227,7 +229,7 @@ namespace nana return token::number; } else - throw("invalid character '" + std::string(1, *sp_) + "'", *this); + throw error("invalid character '" + std::string(1, *sp_) + "'", *this); break; default: if ('0' <= *sp_ && *sp_ <= '9') @@ -349,7 +351,7 @@ namespace nana return token::identifier; } - throw("invalid character '" + std::string(1, *sp_) + "'", *this); + throw error("invalid character '" + std::string(1, *sp_) + "'", *this); return token::error; //Useless, just for syntax correction. } private: @@ -472,7 +474,7 @@ namespace nana return 0; } private: - const char* divstr_{}; + const char* divstr_{}; const char* sp_{}; std::string idstr_; number_t number_; @@ -609,13 +611,16 @@ namespace nana /// usefull ?? struct error : std::invalid_argument { - error(std::string what, - const implement& impl) + error(std::string what, + std::string field = "unknown", + std::string::size_type pos = std::string::npos) - : std::invalid_argument{ what + " from implementation " }/*, - pos{ static_cast(tok.sp_ - tok.divstr_) }*/ + : std::invalid_argument{ what + " from place implementation " }, + pos{ pos }, + field { field.empty() ? "unnamed" : field } {} std::string::size_type pos; + std::string field; }; class field_gather; class field_dock; @@ -2007,11 +2012,11 @@ namespace nana return; auto fieldstr = div.substr(bound.first, bound.second - bound.first); - _m_remove_attr(fieldstr, "weight"); + _m_remove_attr(fieldstr, "weight"); /// \todo and higth, width ? std::string::size_type tag_pos{ left ? div.find('<', bound.second + 2) : div.rfind('>', bound.first - 2) }; if (div.npos == tag_pos) - throw place::error("please report an issue: unable to update division " + div, impl_-> ); + throw place::implement::error("please report an issue: the splitter was unable to update division " + div, name); auto other_bound = get_field_boundary(div, tag_pos); @@ -2727,7 +2732,7 @@ namespace nana return static_cast(arg.real()); const char* pos_strs[] = { "1st", "2nd", "3rd", "4th" }; - throw std::invalid_argument("nana.place: the type of the " + std::string{pos_strs[pos]} +"th parameter for collapse should be integer."); + throw place_parts::tokenizer::error("the type of the " + std::string{pos_strs[pos]} +" parameter for collapse should be integer.", tknizer); } //implicitly_started indicates whether the field in div-text starts without < mark. @@ -2755,82 +2760,83 @@ namespace nana bool invisible = false; token tk = token::eof; - for (tk = tknizer.read(); (tk != token::eof && tk != token::div_end); tk = tknizer.read()) - { - switch (tk) + try { + for (tk = tknizer.read(); (tk != token::eof && tk != token::div_end); tk = tknizer.read()) { - case token::dock: - if (token::eof != div_type && token::dock != div_type) - throw std::invalid_argument("nana.place: conflict of div type at " + std::to_string(tknizer.pos())); - - div_type = token::dock; - break; - case token::fit: - fit = fit_policy::both; - break; - case token::hfit: - case token::vfit: - fit = (token::hfit == tk ? fit_policy::horz : fit_policy::vert); - fit_parameters = tknizer.reparray(); - break; - case token::splitter: - //Ignore the splitter when there is not a division. - if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division)) + switch (tk) { - auto splitter = new div_splitter(tknizer.number(), this); - children.back()->div_next = splitter; + case token::dock: + if (token::eof != div_type && token::dock != div_type) + throw std::invalid_argument("conflict of div type -expected dock type-"); - //Hides the splitter if its left leaf is undisplayed. - if (!children.back()->display) - splitter->display = false; + div_type = token::dock; + break; + case token::fit: + fit = fit_policy::both; + break; + case token::hfit: + case token::vfit: + fit = (token::hfit == tk ? fit_policy::horz : fit_policy::vert); + fit_parameters = tknizer.reparray(); + break; + case token::splitter: + //Ignore the splitter when there is not a division. + if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division)) + { + auto splitter = new div_splitter(tknizer.number(), this); + children.back()->div_next = splitter; - children.emplace_back(std::unique_ptr{ splitter }); + //Hides the splitter if its left leaf is undisplayed. + if (!children.back()->display) + splitter->display = false; + + children.emplace_back(std::unique_ptr{ splitter }); + } + break; + case token::div_start: + { + auto div = scan_div(tknizer, false, ignore_duplicate); + if (!children.empty()) + { + //Hides the splitter if its right leaf is undisplayed. + if ((children.back()->kind_of_division == division::kind::splitter) && !div->display) + children.back()->display = false; + + children.back()->div_next = div.get(); + } + + children.emplace_back(std::move(div)); } break; - case token::div_start: - { - auto div = scan_div(tknizer, false, ignore_duplicate); - if (!children.empty()) - { - //Hides the splitter if its right leaf is undisplayed. - if ((children.back()->kind_of_division == division::kind::splitter) && !div->display) - children.back()->display = false; - - children.back()->div_next = div.get(); - } - - children.emplace_back(std::move(div)); - } - break; - case token::switchable: - div_type = token::switchable; - break; - case token::vert: - div_type = tk; - break; - case token::grid: - div_type = tk; - switch (tknizer.read()) - { - case token::number: - array.push_back(tknizer.number()); - array.push_back(tknizer.number()); + case token::switchable: + div_type = token::switchable; break; - case token::array: - tknizer.array().swap(array); + case token::vert: + div_type = tk; break; - case token::reparray: - array.push_back(tknizer.reparray().at(0)); - array.push_back(tknizer.reparray().at(1)); + case token::grid: + div_type = tk; + switch (tknizer.read()) + { + case token::number: + array.push_back(tknizer.number()); + array.push_back(tknizer.number()); + break; + case token::array: + tknizer.array().swap(array); + break; + case token::reparray: + array.push_back(tknizer.reparray().at(0)); + array.push_back(tknizer.reparray().at(1)); + break; + default: + break; + } break; - default: - break; - } - break; - case token::collapse: + case token::collapse: { if (tknizer.parameters().size() != 4) - throw std::invalid_argument("nana.place: collapse requires 4 parameters."); + throw std::invalid_argument("collapse requires 4 parameters"); ::nana::rectangle col{ get_parameter(tknizer, 0), @@ -2845,7 +2851,7 @@ namespace nana { //Overwrite if a exist_col in collapses has same position as the col. bool use_col = true; - for (auto & exist_col : collapses) + for (auto& exist_col : collapses) { if (exist_col.x == col.x && exist_col.y == col.y) { @@ -2859,7 +2865,7 @@ namespace nana } } break; - case token::weight: case token::min_px: case token::max_px: case token::width: case token::height: + case token::weight: case token::min_px: case token::max_px: case token::width: case token::height: { auto n = tknizer.number(); //If n is the type of real, convert it to integer. @@ -2870,7 +2876,7 @@ namespace nana switch (tk) { case token::weight: weight = n; weight_type = token::weight; break; // we could detect errors here (redefinitions and duplicates) - case token::width : weight = n; weight_type = token::width ; break; + case token::width: weight = n; weight_type = token::width; break; case token::height: weight = n; weight_type = token::height; break; case token::min_px: min_px = n; break; case token::max_px: max_px = n; break; @@ -2878,228 +2884,246 @@ namespace nana } } break; - case token::arrange: - arrange = tknizer.reparray(); - break; - case token::gap: - gap = tknizer.reparray(); - break; - case token::margin: - margin.clear(); - switch (tknizer.read()) - { - case token::number: - margin.push(tknizer.number(), true); + case token::arrange: + arrange = tknizer.reparray(); break; - case token::array: - margin.set_array(tknizer.array()); + case token::gap: + gap = tknizer.reparray(); break; - case token::reparray: - for (std::size_t i = 0; i < 4; ++i) + case token::margin: + margin.clear(); + switch (tknizer.read()) { - auto n = tknizer.reparray().at(i); - if (n.empty()) n.assign(0); - margin.push(n); - } - break; - default: - break; - } - break; - case token::identifier: - name = tknizer.idstr(); - break; - case token::left: - div_dir = ::nana::direction::west; break; - case token::right: - div_dir = ::nana::direction::east; break; - case token::top: - div_dir = ::nana::direction::north; break; - case token::bottom: - div_dir = ::nana::direction::south; break; - case token::undisplayed: - undisplayed = true; break; - case token::invisible: - invisible = true; break; - default: break; - } - } - - if (implicitly_started && (tk == token::div_end)) - throw std::invalid_argument("nana.place: the div-text ends prematurely at " + std::to_string(tknizer.pos())); - - field_gather * attached_field = nullptr; - - //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) - { - //The fields are allowed to have a same name. E.g. - //place.div("A "); - //place.modify("A", ""); Here the same name B must be allowed, otherwise it throws runtime error. - - bool allow_same_name = false; - if (!ignore_duplicate.empty()) - { - auto f = attached_field->attached->div_owner; - while (f) - { - if (f->name == ignore_duplicate) + case token::number: + margin.push(tknizer.number(), true); + break; + case token::array: + margin.set_array(tknizer.array()); + break; + case token::reparray: + for (std::size_t i = 0; i < 4; ++i) { - allow_same_name = true; - break; + auto n = tknizer.reparray().at(i); + if (n.empty()) n.assign(0); + margin.push(n); } - - f = f->div_owner; + break; + default: + break; } + break; + case token::identifier: + name = tknizer.idstr(); + break; + case token::left: + div_dir = ::nana::direction::west; break; + case token::right: + div_dir = ::nana::direction::east; break; + case token::top: + div_dir = ::nana::direction::north; break; + case token::bottom: + div_dir = ::nana::direction::south; break; + case token::undisplayed: + undisplayed = true; break; + case token::invisible: + invisible = true; break; + default: break; } - - if (!allow_same_name) - throw std::runtime_error("place, the name '" + name + "' is redefined."); - } - } - - token unmatch = token::width; - switch (div_type) - { - case token::eof: // "horizontal" 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-height/horizontal-width between division '" - +name+"' and children division '" + ch->name); - - div.reset(new div_arrange(token::vert == div_type, std::move(name), std::move(arrange))); - break; - case token::grid: - { - std::unique_ptr p(new div_grid(std::move(name), std::move(arrange), std::move(collapses))); - - if (array.size()) - p->dimension.first = array[0].integer(); - - if (array.size() > 1) - p->dimension.second = array[1].integer(); - - if (0 == p->dimension.first) - p->dimension.first = 1; - - if (0 == p->dimension.second) - p->dimension.second = 1; - - p->revise_collapses(); - div = std::move(p); - } - break; - case token::dock: - div.reset(new div_dock(std::move(name), this)); - break; - case token::switchable: - div.reset(new div_switchable(std::move(name), this)); - break; - default: - throw std::invalid_argument("nana.place: invalid division type."); - } - div->weigth_type = weight_type; - - //Requirements for min/max - //1, min and max != negative - //2, max >= min - if (min_px.is_negative()) min_px.reset(); - if (max_px.is_negative()) max_px.reset(); - if ((!min_px.empty()) && (!max_px.empty()) && (min_px.get_value(100) > max_px.get_value(100))) - { - min_px.reset(); - max_px.reset(); - } - - if (!min_px.empty()) - div->min_px = min_px; - - if (!max_px.empty()) - div->max_px = max_px; - - if ((!min_px.empty()) && (!weight.empty()) && (weight.get_value(100) < min_px.get_value(100))) - weight.reset(); - - if ((!max_px.empty()) && (!weight.empty()) && (weight.get_value(100) > max_px.get_value(100))) - weight.reset(); - - if (!weight.empty()) - div->weight = weight; - - div->gap = std::move(gap); - - //attach the field to the division - div->field = attached_field; - if (attached_field) - { - //Replaces the previous div with the new div which is allowed to have a same name. - - //Detaches the field from the previous div. - if (attached_field->attached) - attached_field->attached->field = nullptr; - - //Attaches new div - attached_field->attached = div.get(); - } - - if (children.size()) - { - if (division::kind::splitter == children.back()->kind_of_division) - { - children.pop_back(); - if (children.size()) - children.back()->div_next = nullptr; } - for (auto& child : children) - { - child->div_owner = div.get(); - if (division::kind::splitter == child->kind_of_division) - dynamic_cast(*child).direction(div_type != token::vert); - } + if (implicitly_started && (tk == token::div_end)) + throw std::invalid_argument("the div-text ends prematurely"); - if (token::dock == div_type) + field_gather * attached_field = nullptr; + + //find the field with specified name. + //the field may not be created. + auto i = fields.find(name); + if (fields.end() != i) { - //adjust these children for dock division - std::vector> adjusted_children; - for (auto & child : children) + attached_field = i->second; + //the field is attached to a division, it means there is another division with same name. + if (attached_field->attached) { - auto dockpn = new div_dockpane(std::move(child->name), this, child->dir); - dockpn->div_owner = child->div_owner; - dockpn->weight = child->weight; - adjusted_children.emplace_back(std::unique_ptr{ dockpn }); - } + //The fields are allowed to have a same name. E.g. + //place.div("A "); + //place.modify("A", ""); Here the same name B must be allowed, otherwise it throws std::invalid_argument. - division * next = nullptr; - for (int i = static_cast(adjusted_children.size()) - 1; i >= 0; --i) - { - adjusted_children[i]->div_next = next; - next = adjusted_children[i].get(); - } + bool allow_same_name = false; + if (!ignore_duplicate.empty()) + { + auto f = attached_field->attached->div_owner; + while (f) + { + if (f->name == ignore_duplicate) + { + allow_same_name = true; + break; + } - children.swap(adjusted_children); + f = f->div_owner; + } + } + + if (!allow_same_name) + throw std::invalid_argument("redefined field name"); + } } + + token unmatch = token::width; + switch (div_type) + { + case token::eof: // "horizontal" 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("unmatch vertical-height/horizontal-width between division '" + + name + "' and children division '" + ch->name); + + div.reset(new div_arrange(token::vert == div_type, std::move(name), std::move(arrange))); + break; + case token::grid: + { + std::unique_ptr p(new div_grid(std::move(name), std::move(arrange), std::move(collapses))); + + if (array.size()) + p->dimension.first = array[0].integer(); + + if (array.size() > 1) + p->dimension.second = array[1].integer(); + + if (0 == p->dimension.first) + p->dimension.first = 1; + + if (0 == p->dimension.second) + p->dimension.second = 1; + + p->revise_collapses(); + div = std::move(p); + } + break; + case token::dock: + div.reset(new div_dock(std::move(name), this)); + break; + case token::switchable: + div.reset(new div_switchable(std::move(name), this)); + break; + default: + throw std::invalid_argument("invalid division type."); + } + div->weigth_type = weight_type; + + //Requirements for min/max + //1, min and max != negative + //2, max >= min + if (min_px.is_negative()) min_px.reset(); + if (max_px.is_negative()) max_px.reset(); + if ((!min_px.empty()) && (!max_px.empty()) && (min_px.get_value(100) > max_px.get_value(100))) + { + min_px.reset(); + max_px.reset(); + } + + if (!min_px.empty()) + div->min_px = min_px; + + if (!max_px.empty()) + div->max_px = max_px; + + if ((!min_px.empty()) && (!weight.empty()) && (weight.get_value(100) < min_px.get_value(100))) + weight.reset(); + + if ((!max_px.empty()) && (!weight.empty()) && (weight.get_value(100) > max_px.get_value(100))) + weight.reset(); + + if (!weight.empty()) + div->weight = weight; + + div->gap = std::move(gap); + + //attach the field to the division + div->field = attached_field; + if (attached_field) + { + //Replaces the previous div with the new div which is allowed to have a same name. + + //Detaches the field from the previous div. + if (attached_field->attached) + attached_field->attached->field = nullptr; + + //Attaches new div + attached_field->attached = div.get(); + } + + if (children.size()) + { + if (division::kind::splitter == children.back()->kind_of_division) + { + children.pop_back(); + if (children.size()) + children.back()->div_next = nullptr; + } + + for (auto& child : children) + { + child->div_owner = div.get(); + if (division::kind::splitter == child->kind_of_division) + dynamic_cast(*child).direction(div_type != token::vert); + } + + if (token::dock == div_type) + { + //adjust these children for dock division + std::vector> adjusted_children; + for (auto& child : children) + { + auto dockpn = new div_dockpane(std::move(child->name), this, child->dir); + dockpn->div_owner = child->div_owner; + dockpn->weight = child->weight; + adjusted_children.emplace_back(std::unique_ptr{ dockpn }); + } + + division* next = nullptr; + for (int i = static_cast(adjusted_children.size()) - 1; i >= 0; --i) + { + adjusted_children[i]->div_next = next; + next = adjusted_children[i].get(); + } + + children.swap(adjusted_children); + } + } + + div->children.swap(children); + div->margin = std::move(margin); + div->dir = div_dir; + + div->display = !undisplayed; + div->visible = !(undisplayed || invisible); + div->fit = fit; + div->fit_parameters = std::move(fit_parameters); + } + catch (place::error& e) { throw; } + catch ( error& e) { throw; } + catch (place_parts::tokenizer::error& e) + { + throw error(e.what(), name, e.pos); + } + catch (std::invalid_argument& e) + { + throw error(e.what(), name, tknizer.pos()); + } + catch (std::exception& e) + { + throw error(std::string{"unexpected error: "}+e.what(), name, tknizer.pos()); + } + catch (...) + { + throw error("unknow error", name, tknizer.pos()); } - - div->children.swap(children); - div->margin = std::move(margin); - div->dir = div_dir; - - div->display = !undisplayed; - div->visible = !(undisplayed || invisible); - div->fit = fit; - div->fit_parameters = std::move(fit_parameters); - return div; } @@ -3265,16 +3289,20 @@ namespace nana void place::div(std::string div_text) { - place_parts::tokenizer tknizer(div_text.c_str()); - impl_->disconnect(); - auto div = impl_->scan_div(tknizer, true); try { + place_parts::tokenizer tknizer(div_text.c_str()); + impl_->disconnect(); + auto div = impl_->scan_div(tknizer, true); impl_->connect(div.get()); //throws if there is a redefined name of field. impl_->root_division.reset(); //clear attachments div-fields impl_->root_division.swap(div); impl_->div_text.swap(div_text); } + catch (place::implement::error & e) + { + throw place::error("failed to set div('"+div_text+"'): " + e.what(), *this, e.field, e.pos); + } catch (...) // tokenizer error { //redefined a name of field @@ -3295,19 +3323,15 @@ namespace nana void place::modify(const char* name, const char* div_text) { if (nullptr == div_text) - throw error("nana::place.modify(): invalid div-text (nullptr)", *this); + throw error("modify(): invalid div-text (=nullptr)", *this); if (! valid_field_name(name) ) - throw badname("nana::place.modify()", *this, name); + throw badname("modify()", *this, name); auto div_ptr = impl_->search_div_name(impl_->root_division.get(), name); if (!div_ptr) - { - std::string what = "nana::place.modify(): field '"; - what += name; - what += "' was not found."; - throw error(what, *this, name); - } + throw error("modify(): field was not found", *this, name); + std::unique_ptr* replaced = nullptr; @@ -3361,17 +3385,22 @@ namespace nana } } } - catch (...) /// todo throw error !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + catch (std::exception&e) { replaced->swap(impl_->tmp_replaced); - throw; + throw error( std::string("modify()")+e.what(), *this, name); + } + catch (...) + { + replaced->swap(impl_->tmp_replaced); + throw error("modify() unknonw error", *this, name); } } place::field_reference place::field(const char* name) { if (!valid_field_name(name)) - throw badname("nana::place.field()", *this, name); + throw badname("field()", *this, name); //get the field with the specified name. If no such field with specified name //then create one. @@ -3387,8 +3416,7 @@ namespace nana if (div) { if (div->field && (div->field != p)) - throw error(std::string("nana::place.field(): unexpected error, the division attaches an unexpected field: ") + name, - *this, name); + throw error("field(): the division attaches an unexpected field", *this, name); div->field = p; p->attached = div; @@ -3466,7 +3494,7 @@ namespace nana void place::field_visible(const char* name, bool vsb) { if (!valid_field_name(name)) - throw badname("set nana::place.field_visible()", *this, name); + throw badname("field_visible()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); if (div) @@ -3479,7 +3507,7 @@ namespace nana bool place::field_visible(const char* name) const { if (!valid_field_name(name)) - throw badname("get nana::place.field_visible()", *this, name); + throw badname("field_visible()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); return (div && div->visible); @@ -3488,7 +3516,7 @@ namespace nana void place::field_display(const char* name, bool dsp) { if (!valid_field_name(name)) - throw badname("set nana::place.field_display()", *this, name); + throw badname("field_display()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); if (div) @@ -3502,7 +3530,7 @@ namespace nana bool place::field_display(const char* name) const { if (!valid_field_name(name)) - throw badname("get nana::place.field_display()", *this, name); + throw badname("field_display()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); return (div && div->display); @@ -3540,7 +3568,7 @@ namespace nana place& place::dock(const std::string& name, std::string factory_name, std::function(window)> factory) { if (!valid_field_name(name.data())) - throw badname("get nana::place.field_display()", *this, name.data()); + throw badname("dock()", *this, name.data()); auto & dock_ptr = impl_->docks[name]; if (!dock_ptr) @@ -3550,7 +3578,7 @@ namespace nana if (!factory_name.empty()) { if (impl_->dock_factoris.find(factory_name) != impl_->dock_factoris.end()) - throw std::invalid_argument("nana::place - the specified factory name(" + factory_name + ") already exists"); + throw error("dock() - the specified factory name(" + factory_name + ") already exists", *this, name); impl_->dock_factoris[factory_name] = dock_ptr; dock_ptr->factories[factory_name] = std::move(factory); @@ -3586,7 +3614,7 @@ namespace nana { auto i = impl_->dock_factoris.find(factory); if (i == impl_->dock_factoris.end()) - throw std::invalid_argument("invalid factory name(" + factory + ") of dockpane"); + throw std::invalid_argument("nana::place::dock_create - invalid factory name(" + factory + ") of dockpane"); auto dock_ptr = i->second; if (dock_ptr->attached) @@ -3607,9 +3635,24 @@ namespace nana return nullptr; } - //end class place + + place::error::error(const std::string& what, + const place& plc, + std::string field, + std::string::size_type pos) - //class place::error + : std::invalid_argument{ "nana::place error " + what + + " from widget '" + API::window_caption(plc.window_handle()).substr(0,80) + + "' in fleld '" + field + + (pos == std::string::npos ? "' " : "' at at position " + std::to_string(pos)) + + " in div_text:\n" + plc.div() }, + base_what{ what }, + owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, + field{ field }, + div_text{ plc.div() }, + pos{ pos } + {} + //end class place }//end namespace nana From 4e3641ed88eb5dc9de805ece2f0b4033268aa6ca Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Sun, 5 May 2019 11:13:08 -0400 Subject: [PATCH 16/61] fix for issue #428 --- source/gui/widgets/listbox.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index eaed5195..3660dce0 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1198,23 +1198,15 @@ namespace nana return{}; } - /// return a ref to the real item object at display!!! position pos using current sorting only if it is active, and at absolute position if no sorting is currently active. + /// return a ref to the real item object at display position category_t::container::value_type& at(const index_pair& pos) { - auto acc_pos = pos.item; - if (npos != sort_attrs_.column) - acc_pos = index_cast(pos, true).item; //convert display position to absolute position - - return get(pos.cat)->items.at(acc_pos); + return get(pos.cat)->items.at(index_cast(pos, true).item); } const category_t::container::value_type& at(const index_pair& pos) const { - auto acc_pos = pos.item; - if (npos != sort_attrs_.column) - acc_pos = index_cast(pos, true).item; //convert display position to absolute position - - return get(pos.cat)->items.at(acc_pos); + return get(pos.cat)->items.at(index_cast(pos, true).item); } std::vector at_model(const index_pair& pos) const From 20c40a091a3b735ca859bdcc1d88aa748ed74b6b Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 5 May 2019 21:46:20 +0200 Subject: [PATCH 17/61] fix warning about order of initialization --- source/gui/place.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index c932f78f..26c82e95 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -3648,8 +3648,8 @@ namespace nana + " in div_text:\n" + plc.div() }, base_what{ what }, owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, - field{ field }, div_text{ plc.div() }, + field{ field }, pos{ pos } {} //end class place From d6088e5d7d792b22616a05fd56b3955488cd211d Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 5 May 2019 21:53:05 +0200 Subject: [PATCH 18/61] nana dev point to nana-demo cmake-dev. No Boost, print CMAKE_CXX_FLAGS_RELEASE. --- .travis.yml | 2 +- build/cmake/verbose.cmake | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7b71b9ec..6a47d771 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,7 +65,7 @@ before_script : - cd demo-build script: - - cmake -G"Unix Makefiles" ../nana-demo -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=ON -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON + - cmake -G"Unix Makefiles" ../nana-demo -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=OFF -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON - make install # todo: separate resources from sources (a directory for images) - ls diff --git a/build/cmake/verbose.cmake b/build/cmake/verbose.cmake index 6d95eb9e..a1f9be06 100644 --- a/build/cmake/verbose.cmake +++ b/build/cmake/verbose.cmake @@ -30,6 +30,8 @@ if (NANA_CMAKE_VERBOSE_PREPROCESSOR) cmake_print_variables(CMAKE_BUILD_TYPE) cmake_print_variables(CMAKE_CONFIGURATION_TYPES) + cmake_print_variables(CMAKE_CXX_FLAGS_RELEASE) + 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}) From ca96a9d3cab0cea834f8b022418704583c107412 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 5 May 2019 22:15:41 +0200 Subject: [PATCH 19/61] Fix merge # Conflicts: # include/nana/gui/widgets/treebox.hpp # source/gui/place.cpp --- .travis.yml | 2 -- build/vc2017/nana.vcxproj | 1 + build/vc2017/nana.vcxproj.filters | 3 +++ include/nana/gui/dragdrop.hpp | 11 ++++++++++- include/nana/gui/widgets/group.hpp | 5 ++--- include/nana/gui/widgets/listbox.hpp | 2 +- include/nana/gui/widgets/treebox.hpp | 4 ++-- source/gui/widgets/listbox.cpp | 10 +++++----- 8 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a47d771..20ef6e32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,8 +46,6 @@ before_install: - cd .. - git clone --depth=1 --branch=hotfix https://github.com/qPCR4vir/nana-demo.git nana-demo - export PATH="$HOME/bin:$PATH" - - #- mkdir ~/bin #it seemd that a bin already exists from 20170901 - wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.12/cmake-3.12.0-rc3-Linux-x86_64.sh || true - chmod -R +x /tmp/tools diff --git a/build/vc2017/nana.vcxproj b/build/vc2017/nana.vcxproj index 911548d5..24f5ef80 100644 --- a/build/vc2017/nana.vcxproj +++ b/build/vc2017/nana.vcxproj @@ -256,6 +256,7 @@ + diff --git a/build/vc2017/nana.vcxproj.filters b/build/vc2017/nana.vcxproj.filters index e88f7ed3..4923833d 100644 --- a/build/vc2017/nana.vcxproj.filters +++ b/build/vc2017/nana.vcxproj.filters @@ -474,6 +474,9 @@ Include + + Include\gui + diff --git a/include/nana/gui/dragdrop.hpp b/include/nana/gui/dragdrop.hpp index 1eeb9541..70c91013 100644 --- a/include/nana/gui/dragdrop.hpp +++ b/include/nana/gui/dragdrop.hpp @@ -40,7 +40,16 @@ namespace nana simple_dragdrop(simple_dragdrop&&) = delete; simple_dragdrop& operator=(simple_dragdrop&&) = delete; public: - simple_dragdrop(window source); + explicit simple_dragdrop(window source); + simple_dragdrop(window drag_origin, + std::function when, + window drop_target, + std::function how) + : simple_dragdrop{drag_origin} + { + condition(when); + make_drop(drop_target, how); + } ~simple_dragdrop(); /// Condition checker diff --git a/include/nana/gui/widgets/group.hpp b/include/nana/gui/widgets/group.hpp index d62a7abf..43dd5e85 100644 --- a/include/nana/gui/widgets/group.hpp +++ b/include/nana/gui/widgets/group.hpp @@ -59,9 +59,8 @@ namespace nana{ group(window parent, const rectangle& = {}, bool visible = true); /// The construction that creates the widget and set the title or caption - - group(window parent, ///< a handle to the parent - ::std::string title, ///< caption of the group + group(window parent, ///< a handle to the parent + ::std::string title, ///< caption of the group bool formatted = false, ///< Enable/disable the formatted text for the title unsigned gap = 2, ///< between the content and the external limit const rectangle& r = {} , diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 52680582..9a9b6206 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1465,7 +1465,7 @@ the nana::detail::basic_window member pointer scheme size_type column_size() const; /// Move column to view_position - void move_column(size_type abs_pos, size_type view_pos); + void move_column(size_type abs_pos, size_type view_pos); /// Sort columns in range first_col to last_col inclusive using the values from a row void reorder_columns(size_type first_col, diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 4d832c27..c1edbadf 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -350,9 +350,9 @@ namespace nana /// \brief Displays a hierarchical list of items, such as the files and directories on a disk. /// See also in [documentation](http://nanapro.org/en-us/documentation/widgets/treebox.htm) class treebox - :public widget_object < category::widget_tag, + :public widget_object + drawerbase::treebox::treebox_events, drawerbase::treebox::scheme> { public: /// A type refers to the item and is also used to iterate through the nodes. diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 00e2052a..91ce34d8 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -549,9 +549,9 @@ namespace nana if (!front) view++; if (view >= cont_.size() ) return; - auto i = std::find_if( cont_.begin(), - cont_.end(), - [&](const column& c){return col==c.index;}); + auto i = std::find_if( cont_.begin(), + cont_.end(), + [&](const column& c){return col==c.index;}); if (i==cont_.end()) return; @@ -4474,7 +4474,7 @@ namespace nana essence_->stop_mouse_selection(); need_refresh = true; } - + if (operation_states::msup_deselect == essence_->operation.state) { essence_->operation.state = operation_states::none; @@ -6193,7 +6193,7 @@ namespace nana std::vector new_idx; for(size_type i=first_col; i<=last_col; ++i) new_idx.push_back(i); - + internal_scope_guard lock; auto ip_row = this->at(row); auto pnany=_m_ess().lister.anyobj(row,false); From 4d42409a54f74e074dfca233b17fa35a25e7dca6 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 5 May 2019 23:05:25 +0200 Subject: [PATCH 20/61] cover more place methods with place:error --- source/gui/place.cpp | 55 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 26c82e95..c050421f 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -3106,8 +3106,8 @@ namespace nana div->fit = fit; div->fit_parameters = std::move(fit_parameters); } - catch (place::error& e) { throw; } - catch ( error& e) { throw; } + catch (place::error& ) { throw; } + catch ( error& ) { throw; } catch (place_parts::tokenizer::error& e) { throw error(e.what(), name, e.pos); @@ -3260,7 +3260,8 @@ namespace nana void place::bind(window wd) { if (impl_->window_handle) - throw std::runtime_error("place.bind: it has already bound to a window."); + throw error(" bind('"+ API::window_caption(wd).substr(0, 80) + + "'): it was already bound to another window.", *this); impl_->window_handle = wd; impl_->event_size_handle = API::events(wd).resized.connect_unignorable([this](const arg_resized& arg) @@ -3299,14 +3300,26 @@ namespace nana impl_->root_division.swap(div); impl_->div_text.swap(div_text); } + catch (place::error & ) { throw; } catch (place::implement::error & e) { - throw place::error("failed to set div('"+div_text+"'): " + e.what(), *this, e.field, e.pos); + throw error("failed to set div('" + div_text + "'): " + e.what(), *this, e.field, e.pos); } - catch (...) // tokenizer error + catch (place_parts::tokenizer::error & e) { - //redefined a name of field - throw; + throw error("failed to set div('" + div_text + "'): " + e.what(), *this, "", e.pos); + } + catch (std::invalid_argument & e) + { + throw error("failed to set div('" + div_text + "'): " + e.what(), *this); + } + catch (std::exception & e) + { + throw error("failed to set div('"+div_text+"'): unexpected error: " +e.what(), *this ); + } + catch (...) + { + throw error("failed to set div('" + div_text + "'): unknonw error", *this); } } @@ -3385,15 +3398,35 @@ namespace nana } } } - catch (std::exception&e) + catch (place::error & ) { replaced->swap(impl_->tmp_replaced); - throw error( std::string("modify()")+e.what(), *this, name); + throw; } - catch (...) + catch (place::implement::error & e) { replaced->swap(impl_->tmp_replaced); - throw error("modify() unknonw error", *this, name); + throw error("failed to modify('"+std::string(name) +", "+ div_text + "'): " + e.what(), *this, e.field, e.pos); + } + catch (place_parts::tokenizer::error & e) + { + replaced->swap(impl_->tmp_replaced); + throw error("failed to modify('" + std::string(name) + ", " + div_text + "'): " + e.what(), *this, "", e.pos); + } + catch (std::invalid_argument & e) + { + replaced->swap(impl_->tmp_replaced); + throw error("failed to modify('" + std::string(name) + ", " + div_text + "'): " + e.what(), *this); + } + catch (std::exception & e) + { + replaced->swap(impl_->tmp_replaced); + throw error("failed to modify('" + std::string(name) + ", " + div_text + "'): unexpected error: " + e.what(), *this); + } + catch (...) + { + replaced->swap(impl_->tmp_replaced); + throw error("failed to modify('" + std::string(name) + ", " + div_text + "'): unknonw error", *this); } } From 9e60ae87ba874467d868b25cccddf3e60ee27a12 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 5 May 2019 23:47:44 +0200 Subject: [PATCH 21/61] better text error --- include/nana/gui/place.hpp | 2 +- source/gui/place.cpp | 18 ++++++++++-------- source/gui/place_parts.hpp | 8 ++++---- source/gui/widgets/categorize.cpp | 4 ++-- source/gui/widgets/group.cpp | 10 +++++----- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index f90298ab..a7a56f17 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -139,7 +139,7 @@ namespace nana { return name && (*name == '_' || (('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z'))); } - void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. + void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. May throw placa::error field_reference field(const char* name);///< Returns a field with the specified name. diff --git a/source/gui/place.cpp b/source/gui/place.cpp index c050421f..b29d98b0 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -1,14 +1,14 @@ -/* +/** * An Implementation of Place for Layout * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at + * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/place.cpp - * @contributors: Ariel Vina-Rodriguez + * @file nana/gui/place.cpp + * @contributors Ariel Vina-Rodriguez * dankan1890(PR#156) */ @@ -3674,10 +3674,12 @@ namespace nana std::string field, std::string::size_type pos) - : std::invalid_argument{ "nana::place error " + what - + " from widget '" + API::window_caption(plc.window_handle()).substr(0,80) - + "' in fleld '" + field - + (pos == std::string::npos ? "' " : "' at at position " + std::to_string(pos)) + : std::invalid_argument{ "from widget '" + + API::window_caption(plc.window_handle()).substr(0,80) + + "'; nana::place error " + + what + + "' in field '" + field + + (pos == std::string::npos ? "' " : "' at position " + std::to_string(pos)) + " in div_text:\n" + plc.div() }, base_what{ what }, owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 2105dd02..97295d60 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -1,13 +1,13 @@ -/* +/** * Parts of Class Place * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at + * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/place_parts.hpp + * @file nana/gui/place_parts.hpp */ #ifndef NANA_GUI_PLACE_PARTS_HPP #define NANA_GUI_PLACE_PARTS_HPP diff --git a/source/gui/widgets/categorize.cpp b/source/gui/widgets/categorize.cpp index 19d3ab23..fc88b2cc 100644 --- a/source/gui/widgets/categorize.cpp +++ b/source/gui/widgets/categorize.cpp @@ -1,4 +1,4 @@ -/* +/** * A Categorize Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/widgets/categorize.cpp + * @file nana/gui/widgets/categorize.cpp */ #include diff --git a/source/gui/widgets/group.cpp b/source/gui/widgets/group.cpp index 726814e8..b22b662b 100644 --- a/source/gui/widgets/group.cpp +++ b/source/gui/widgets/group.cpp @@ -1,19 +1,19 @@ /** * A group widget implementation * Nana C++ Library(http://www.nanaro.org) - * Copyright(C) 2015-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2015-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at + * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/widgets/group.cpp + * @file nana/gui/widgets/group.cpp * - * @Author: Stefan Pfeifer(st-321), Ariel Vina-Rodriguez (qPCR4vir) + * @author Stefan Pfeifer(st-321), Ariel Vina-Rodriguez (qPCR4vir) * * @brief group is a widget used to visually group and layout other widgets. * - * @contributor: + * @contributor * dankan1890(https://github.com/dankan1890) */ From 5422c430026a3bfe83c110d9e5ae780a106dc690 Mon Sep 17 00:00:00 2001 From: besh81 Date: Wed, 8 May 2019 18:11:21 +0200 Subject: [PATCH 22/61] toolbar : added toggle button Following functions/methods have been add both to toolbar and item_proxy: bool istoggle() const; ///< Returns true if the tool style is toggle. bool toggle() const; ///< Gets the tool toggle state (only if tool style is toggle). item_proxy& toggle(bool toggle_state); ///< Sets the tool toggle state (only if tool style is toggle). std::string toggle_group() const; ///< Returns the toggle group associated with the tool (only if tool style is toggle). item_proxy& toggle_group(const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle). --- include/nana/gui/widgets/toolbar.hpp | 58 +++++++- source/gui/widgets/toolbar.cpp | 206 +++++++++++++++++++++++---- 2 files changed, 231 insertions(+), 33 deletions(-) diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index 02e88c6c..85cf0466 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -33,14 +33,51 @@ namespace nana { namespace toolbar { - struct item_proxy - { - nana::toolbar& widget; - std::size_t button; + enum class tool_type + { + button, + toggle + }; - void enable(bool enable_state); + class item_proxy + { + public: + item_proxy(::nana::toolbar*, std::size_t pos); + + bool enable() const; + item_proxy& enable(bool enable_state); + + item_proxy& tooltype(tool_type type); ///< Sets the tool style. + + bool istoggle() const; ///< Returns true if the tool style is toggle. + bool toggle() const; ///< Gets the tool toggle state (only if tool style is toggle). + item_proxy& toggle(bool toggle_state); ///< Sets the tool toggle state (only if tool style is toggle). + std::string toggle_group() const; ///< Returns the toggle group associated with the tool (only if tool style is toggle). + item_proxy& toggle_group(const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle). + + private: + nana::toolbar* const tb_; + std::size_t const pos_; }; + struct item_type + { + std::string text; + nana::paint::image image; + unsigned pixels{ 0 }; + unsigned position{ 0 }; // last item position. + nana::size textsize; + bool enable{ true }; + + tool_type type{ tool_type::button }; + bool toggle{ false }; + std::string group; + + item_type(const std::string& text, const nana::paint::image& img, tool_type type) + :text(text), image(img), type(type) + {} + }; + struct toolbar_events : public general_events { @@ -49,7 +86,6 @@ namespace nana basic_event leave; ///< The mouse leaves a control button. }; - struct item_type; class item_container; class drawer @@ -90,6 +126,7 @@ namespace nana { public: using size_type = std::size_t; ///< A type to count the number of elements. + using tool_type = drawerbase::toolbar::tool_type; toolbar() = default; toolbar(window, bool visible, bool detached=false); @@ -102,6 +139,15 @@ namespace nana bool enable(size_type index) const; void enable(size_type index, bool enable_state); + + void tooltype(size_type index, tool_type type); ///< Sets the tool style. + + bool istoggle(size_type index) const; ///< Returns true if the tool style is toggle. + bool toggle(size_type index) const; ///< Gets the tool toggle state (only if tool style is toggle). + void toggle(size_type index, bool toggle_state); ///< Sets the tool toggle state (only if tool style is toggle). + std::string toggle_group(size_type index) const; ///< Returns the toggle group associated with the tool (only if tool style is toggle). + void toggle_group(size_type index, const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle). + void scale(unsigned s); ///< Sets the scale of control button. /// Enable to place buttons at right part. After calling it, every new button is right aligned. diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index 963b99cf..3172e966 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -27,26 +27,6 @@ namespace nana { namespace toolbar { - struct item_type - { - enum kind{ button, container}; - - typedef std::size_t size_type; - - std::string text; - nana::paint::image image; - unsigned pixels{0}; - unsigned position{ 0 }; // last item position. - nana::size textsize; - bool enable{true}; - - kind type; - - item_type(const std::string& text, const nana::paint::image& img, kind type) - :text(text), image(img), type(type) - {} - }; - class item_container { public: @@ -58,7 +38,7 @@ namespace nana clear(); } - void insert(size_type pos, std::string text, const nana::paint::image& img, item_type::kind type) + void insert(size_type pos, std::string text, const nana::paint::image& img, tool_type type) { item_type* m = new item_type(std::move(text), img, type); @@ -70,12 +50,12 @@ namespace nana void push_back(const std::string& text, const nana::paint::image& img) { - insert(cont_.size(), text, img, item_type::kind::button); + insert(cont_.size(), text, img, tool_type::button); } void push_back(const std::string& text) { - insert(cont_.size(), text, nana::paint::image(), item_type::kind::button); + insert(cont_.size(), text, nana::paint::image(), tool_type::button); } //Contributed by kmribti(pr#105) @@ -126,6 +106,45 @@ namespace nana cont_.clear(); } + + void update_toggle_group(item_type* item, bool toggle_state, bool clicked = true) + { + if(!item) + return; + + if(item->group.empty()) + { + item->toggle = toggle_state; + return; + } + + // group rules: + // 1. inside a group only one item at the time is selected + // 2. inside a group one item must always be selected + // 3. a group with only one item IS NOT a group + + bool is_group = false; + + // look for other items inside the group + for(auto i : cont_) + { + if(i == item) + continue; + + if(i && i->group == item->group) + { + if(toggle_state == false && clicked == false) // needs to avoid to break rule no. 2 + return; + + is_group = true; + i->toggle = false; + } + } + + item->toggle = is_group ? true : toggle_state; + } + + private: container_type cont_; size_t right_{ npos }; @@ -152,6 +171,13 @@ namespace nana if (state_t::highlighted == state || state_t::selected == state) graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast(state_t::selected == state ? 0x99CCFF : 0xC0DDFC), true); } + else if (item.type == tool_type::toggle && item.toggle) + { + nana::rectangle background_r(x, y, width, height); + graph.rectangle(background_r, false, static_cast(item.enable ? 0x3399FF : 0x999999)); + + graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast(item.enable ? 0xC0DDFC : 0x969696), true); + } if(!item.image.empty()) { @@ -378,6 +404,10 @@ namespace nana size_type which = _m_which(arg.pos, false); if(impl_->which == which) { + // update toggle state + auto m = impl_->items.at(impl_->which); + impl_->items.update_toggle_group(m, !m->toggle); + ::nana::arg_toolbar arg{ *widget_, which }; widget_->events().selected.emit(arg, widget_->handle()); @@ -429,9 +459,52 @@ namespace nana //class drawer // Item Proxy - void item_proxy::enable(bool enable_state) + item_proxy::item_proxy(::nana::toolbar* t, std::size_t pos) + : tb_{ t }, pos_{ pos } + {} + + bool item_proxy::enable() const { - widget.enable(button, enable_state); + return tb_->enable(pos_); + } + + item_proxy& item_proxy::enable(bool enable_state) + { + tb_->enable(pos_, enable_state); + return *this; + } + + item_proxy& item_proxy::tooltype(tool_type type) + { + tb_->tooltype(pos_, type); + return *this; + } + + bool item_proxy::istoggle() const + { + return tb_->istoggle(pos_); + } + + bool item_proxy::toggle() const + { + return tb_->toggle(pos_); + } + + item_proxy& item_proxy::toggle(bool toggle_state) + { + tb_->toggle(pos_, toggle_state); + return *this; + } + + std::string item_proxy::toggle_group() const + { + return tb_->toggle_group(pos_); + } + + item_proxy& item_proxy::toggle_group(const ::std::string& group) + { + tb_->toggle_group(pos_, group); + return *this; } }//end namespace toolbar }//end namespace drawerbase @@ -465,14 +538,14 @@ namespace nana { get_drawer_trigger().items().push_back(text, img); API::refresh_window(handle()); - return {*this, get_drawer_trigger().items().size() - 1u}; + return {this, get_drawer_trigger().items().size() - 1u}; } drawerbase::toolbar::item_proxy toolbar::append(const std::string& text) { get_drawer_trigger().items().push_back(text, {}); API::refresh_window(this->handle()); - return {*this, get_drawer_trigger().items().size() - 1u}; + return {this, get_drawer_trigger().items().size() - 1u}; } void toolbar::clear() @@ -507,6 +580,85 @@ namespace nana } } + void toolbar::tooltype(size_type index, tool_type type) + { + auto & items = get_drawer_trigger().items(); + + if(items.size() > index) + { + auto m = items.at(index); + if(m && m->type != type) + { + m->type = type; + API::refresh_window(this->handle()); + } + } + } + + bool toolbar::istoggle(size_type index) const + { + auto & items = get_drawer_trigger().items(); + + if(items.size() <= index) + return false; + + auto m = items.at(index); + return (m && m->type == tool_type::toggle); + } + + bool toolbar::toggle(size_type index) const + { + auto & items = get_drawer_trigger().items(); + + if(items.size() <= index) + return false; + + auto m = items.at(index); + return (m && m->toggle); + } + + void toolbar::toggle(size_type index, bool toggle_state) + { + auto & items = get_drawer_trigger().items(); + + if(items.size() > index) + { + auto m = items.at(index); + if(m) + { + items.update_toggle_group(m, toggle_state, false); + + API::refresh_window(this->handle()); + } + } + } + + std::string toolbar::toggle_group(size_type index) const + { + auto & items = get_drawer_trigger().items(); + + if(items.size() <= index) + return ""; + + auto m = items.at(index); + return m ? m->group : ""; + } + + void toolbar::toggle_group(size_type index, const ::std::string& group) + { + auto & items = get_drawer_trigger().items(); + + if(items.size() > index) + { + auto m = items.at(index); + if(m && (m->group != group)) + { + m->group = group; + API::refresh_window(this->handle()); //XXX + } + } + } + void toolbar::scale(unsigned s) { get_drawer_trigger().scale(s); From 67f5d1743f15d2d87a8108e2909fb0aaa548cddb Mon Sep 17 00:00:00 2001 From: besh81 Date: Thu, 9 May 2019 09:44:37 +0200 Subject: [PATCH 23/61] toolbar: show text inside the button Added function/method both to toolbar and item_proxy: void textout(size_type index, bool show); ///< Show/Hide the text inside the button Before: button without image weren't display Now: button without image is display as empty square. In case the textout is on the text is show --- include/nana/gui/widgets/toolbar.hpp | 6 ++++ source/gui/widgets/toolbar.cpp | 53 +++++++++++++++++++++------- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index 85cf0466..ed3456e4 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -55,6 +55,8 @@ namespace nana std::string toggle_group() const; ///< Returns the toggle group associated with the tool (only if tool style is toggle). item_proxy& toggle_group(const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle). + item_proxy& textout(bool show); ///< Show/Hide the text inside the button + private: nana::toolbar* const tb_; std::size_t const pos_; @@ -73,6 +75,8 @@ namespace nana bool toggle{ false }; std::string group; + bool textout{ false }; + item_type(const std::string& text, const nana::paint::image& img, tool_type type) :text(text), image(img), type(type) {} @@ -148,6 +152,8 @@ namespace nana std::string toggle_group(size_type index) const; ///< Returns the toggle group associated with the tool (only if tool style is toggle). void toggle_group(size_type index, const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle). + void textout(size_type index, bool show); ///< Show/Hide the text inside the button + void scale(unsigned s); ///< Sets the scale of control button. /// Enable to place buttons at right part. After calling it, every new button is right aligned. diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index 3172e966..f8db43c4 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -156,8 +156,8 @@ namespace nana enum class state_t{normal, highlighted, selected}; const static unsigned extra_size = 6; - item_renderer(nana::paint::graphics& graph, bool textout, unsigned scale, const ::nana::color& bgcolor) - :graph(graph), textout(textout), scale(scale), bgcolor(bgcolor) + item_renderer(nana::paint::graphics& graph, unsigned scale, const ::nana::color& bgcolor, const ::nana::color& fgcolor) + :graph(graph), scale(scale), bgcolor(bgcolor), fgcolor(fgcolor) {} void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state) @@ -207,17 +207,17 @@ namespace nana width -= scale; } - if(textout) + if(item.textout) { - graph.string({ x + static_cast(width - item.textsize.width) / 2, y + static_cast(height - item.textsize.height) / 2 }, item.text); + graph.string({ x + static_cast(width - item.textsize.width) / 2, y + static_cast(height - item.textsize.height) / 2 }, item.text, fgcolor ); } } protected: nana::paint::graphics& graph; - bool textout; unsigned scale; ::nana::color bgcolor; + ::nana::color fgcolor; }; struct drawer::drawer_impl_type @@ -226,7 +226,6 @@ namespace nana paint::graphics* graph_ptr{ nullptr }; unsigned scale{16}; - bool textout{false}; size_type which{npos}; item_renderer::state_t state{item_renderer::state_t::normal}; @@ -263,10 +262,11 @@ namespace nana int x = 2, y = 2; auto bgcolor = API::bgcolor(widget_->handle()); + auto fgcolor = API::fgcolor(widget_->handle()); graph.palette(true, bgcolor); graph.gradual_rectangle(rectangle{ graph.size() }, bgcolor.blend(colors::white, 0.1), bgcolor.blend(colors::black, 0.05), true); - item_renderer ir(graph, impl_->textout, impl_->scale, bgcolor); + item_renderer ir(graph, impl_->scale, bgcolor, fgcolor); size_type index = 0; for (auto item : impl_->items.container()) @@ -449,11 +449,19 @@ namespace nana if (item->text.size()) item->textsize = impl_->graph_ptr->text_extent_size(item->text); - if (item->image.empty() == false) + if(item->image.empty()) + { + if(item->textsize.width && item->textout) + item->pixels = item->textsize.width + 8; + else + item->pixels = impl_->scale + item_renderer::extra_size; + } + else + { item->pixels = impl_->scale + item_renderer::extra_size; - - if (item->textsize.width && impl_->textout) - item->pixels += item->textsize.width + 8; + if(item->textsize.width && item->textout) + item->pixels += item->textsize.width + 8; + } } } //class drawer @@ -501,6 +509,12 @@ namespace nana return tb_->toggle_group(pos_); } + item_proxy& item_proxy::textout(bool show) + { + tb_->textout(pos_, show); + return *this; + } + item_proxy& item_proxy::toggle_group(const ::std::string& group) { tb_->toggle_group(pos_, group); @@ -654,7 +668,22 @@ namespace nana if(m && (m->group != group)) { m->group = group; - API::refresh_window(this->handle()); //XXX + API::refresh_window(this->handle()); + } + } + } + + void toolbar::textout(size_type index, bool show) + { + auto & items = get_drawer_trigger().items(); + + if(items.size() > index) + { + auto m = items.at(index); + if(m && (m->textout != show)) + { + m->textout = show; + API::refresh_window(this->handle()); } } } From 5575a9f2b8223ccd9da8fa729c70ed9cb6a8a79c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 13 May 2019 04:28:30 +0800 Subject: [PATCH 24/61] fix bug that transparent widget may not be updated in event handler(#431) --- include/nana/gui/detail/bedrock.hpp | 16 ++++++++++- include/nana/gui/detail/window_manager.hpp | 1 + source/gui/detail/bedrock_pi.cpp | 19 ++++++++++++- source/gui/detail/bedrock_posix.cpp | 15 ++++------ source/gui/detail/bedrock_windows.cpp | 32 ++-------------------- source/gui/detail/window_manager.cpp | 23 ++++++++++++++++ 6 files changed, 65 insertions(+), 41 deletions(-) diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 9dc3812c..db731e97 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -1,7 +1,7 @@ /** * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -43,6 +43,20 @@ namespace detail class flag_guard; + /// RAII class for window message processing + class root_guard + { + public: + /// Enables lazy_update + root_guard(bedrock& brock, basic_window* root_wd); + + /// Disables lazy-update and clears update requesters queue. + ~root_guard(); + private: + bedrock& brock_; + basic_window* const root_wd_; + }; + ~bedrock(); void pump_event(window, bool is_modal); void flush_surface(core_window_t*, bool forced, const rectangle* update_area = nullptr); diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index d9c26326..1aa18fe2 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -117,6 +117,7 @@ namespace detail void map(core_window_t*, bool forced, const rectangle* update_area = nullptr); bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr); + void update_requesters(core_window_t* root_wd); void refresh_tree(core_window_t*); void do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false); diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index 0cd1e796..fdb1181b 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -91,9 +91,26 @@ namespace nana private: bedrock *const brock_; core_window_t *const wd_; - }; + //class root_guard + bedrock::root_guard::root_guard(bedrock& brock, basic_window* root_wd): + brock_(brock), + root_wd_(root_wd) + { + root_wd_->other.attribute.root->lazy_update = true; + } + + bedrock::root_guard::~root_guard() + { + if (!brock_.wd_manager().available(root_wd_)) + return; + + root_wd_->other.attribute.root->lazy_update = false; + root_wd_->other.attribute.root->update_requesters.clear(); + } + //end class root_guard + bedrock::core_window_t* bedrock::focus() { auto wd = wd_manager().root(native_interface::get_focus_window()); diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 9c96a7cd..9b1160bf 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -556,6 +556,7 @@ namespace detail context.is_alt_pressed = false; } +#if 0 class window_proc_guard { public: @@ -576,6 +577,7 @@ namespace detail private: detail::basic_window* const root_wd_; }; +#endif void window_proc_for_xevent(Display* /*display*/, XEvent& xevent) { @@ -593,7 +595,8 @@ namespace detail { auto const root_wd = root_runtime->window; auto msgwnd = root_wd; - window_proc_guard wp_guard{ root_wd }; + + detail::bedrock::root_guard rw_guard{ brock, root_wd }; auto& context = *brock.get_thread_context(msgwnd->thread_id); @@ -1215,14 +1218,8 @@ namespace detail } } - if (wd_manager.available(root_wd) && root_wd->other.attribute.root->update_requesters.size()) - { - for (auto wd : root_wd->other.attribute.root->update_requesters) - { - window_layout::paint(wd, window_layout::paint_operation::have_refreshed, false); - wd_manager.map(wd, true); - } - } + + wd_manager.update_requesters(root_wd); root_runtime = wd_manager.root_runtime(native_window); if(root_runtime) diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 2747e65f..d549bedc 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -740,27 +740,6 @@ namespace detail return static_cast(vkey); } - class window_proc_guard - { - public: - window_proc_guard(detail::basic_window* wd) : - root_wd_(wd) - { - root_wd_->other.attribute.root->lazy_update = true; - } - - ~window_proc_guard() - { - if (!bedrock::instance().wd_manager().available(root_wd_)) - return; - - root_wd_->other.attribute.root->lazy_update = false; - root_wd_->other.attribute.root->update_requesters.clear(); - } - private: - detail::basic_window* const root_wd_; - }; - LRESULT CALLBACK Bedrock_WIN32_WindowProc(HWND root_window, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT window_proc_value = 0; @@ -793,7 +772,7 @@ namespace detail auto const root_wd = root_runtime->window; auto msgwnd = root_wd; - window_proc_guard wp_guard{ root_wd }; + detail::bedrock::root_guard rw_guard{ brock, root_wd }; switch (message) { @@ -1577,14 +1556,7 @@ namespace detail def_window_proc = true; } - if (wd_manager.available(root_wd) && root_wd->other.attribute.root->update_requesters.size()) - { - for (auto wd : root_wd->other.attribute.root->update_requesters) - { - window_layout::paint(wd, window_layout::paint_operation::have_refreshed, false); - wd_manager.map(wd, true); - } - } + wd_manager.update_requesters(root_wd); root_runtime = wd_manager.root_runtime(native_window); if(root_runtime) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index b5842be8..9f854ee4 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1051,6 +1051,29 @@ namespace detail return true; } + void window_manager::update_requesters(core_window_t* root_wd) + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + + if (this->available(root_wd) && root_wd->other.attribute.root->update_requesters.size()) + { + for (auto wd : root_wd->other.attribute.root->update_requesters) + { + using paint_operation = window_layer::paint_operation; + if (!this->available(wd)) + continue; + + //#431 + //Redraws the widget when it has beground effect. + //Because the widget just redraw if it didn't have bground effect when it was inserted to the update_requesters queue + window_layer::paint(wd, (wd->effect.bground ? paint_operation::try_refresh : paint_operation::have_refreshed), false); + this->map(wd, true); + } + } + + } + void window_manager::refresh_tree(core_window_t* wd) { //Thread-Safe Required! From 037ef43594fe13a7aae1e4b63490adb3a599f349 Mon Sep 17 00:00:00 2001 From: PearlWang Date: Wed, 15 May 2019 09:25:37 +0800 Subject: [PATCH 25/61] add text() function to class textbox --- include/nana/gui/widgets/textbox.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 68c408b7..8557c68a 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -1,4 +1,4 @@ -/** +/** * A Textbox Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) @@ -177,6 +177,10 @@ 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; + // Get all text from textbox. + // It returns a empty string if failed or the textbox is empty. + std::string text() const { return caption(); } + /// Read the text from a specified line; returns an empty optional on failure std::optional getline(std::size_t pos) const; From fbffbcd75d15d42bb9b5adc455a2bf52103d1e69 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 15 May 2019 13:05:19 +0200 Subject: [PATCH 26/61] target_compile_options(nana PUBLIC -static -static-libstdc++) for MINGW too --- CMakeLists.txt | 70 +++++++++++++++++------------------ build/cmake/shared_libs.cmake | 7 +--- 2 files changed, 34 insertions(+), 43 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9252dce..2a3300d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,27 +54,25 @@ target_compile_features(nana # in your own CMakeLists.txt, and them : # target_link_libraries(yourApp PRIVATE nana ) -set(NANA_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source) - -set(NANA_SOURCE_SUBDIRS - /. - /detail - /detail/posix - /filesystem - /gui - /gui/detail - /gui/widgets - /gui/widgets/skeletons - /paint - /paint/detail - /system - /threads - ) +set(NANA_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source) +set(NANA_SOURCE_SUBDIRS /. + /detail + /detail/posix + /filesystem + /gui + /gui/detail + /gui/widgets + /gui/widgets/skeletons + /paint + /paint/detail + /system + /threads + ) if(NANA_CMAKE_ENABLE_AUDIO) list(APPEND NANA_SOURCE_SUBDIRS - /audio - /audio/detail - ) + /audio + /audio/detail + ) endif() # collect all source files in the source-sub-dir @@ -87,26 +85,24 @@ target_sources(nana PRIVATE ${SOURCES}) ### collect all headers sub-directories in a list to avoid duplication ### # To show .h files in Visual Studio, add them to the list of sources in add_executable / add_library / target_sources # and Use SOURCE_GROUP if all your sources are in the same directory -set(NANA_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include) - -set(NANA_INCLUDE_SUBDIRS - /. - /filesystem - /gui - /gui/detail - /gui/widgets - /gui/widgets/skeletons - /paint - /paint/detail - /pat - /system - /threads - ) +set(NANA_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include) +set(NANA_INCLUDE_SUBDIRS /. + /filesystem + /gui + /gui/detail + /gui/widgets + /gui/widgets/skeletons + /paint + /paint/detail + /pat + /system + /threads + ) if(NANA_CMAKE_ENABLE_AUDIO) list(APPEND NANA_INCLUDE_SUBDIRS - /audio - /audio/detail - ) + /audio + /audio/detail + ) endif() foreach(subdir ${NANA_INCLUDE_SUBDIRS}) diff --git a/build/cmake/shared_libs.cmake b/build/cmake/shared_libs.cmake index 0734b47a..1479e0d4 100644 --- a/build/cmake/shared_libs.cmake +++ b/build/cmake/shared_libs.cmake @@ -40,12 +40,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AN if(BUILD_SHARED_LIBS) target_compile_options(nana PUBLIC -lgcc -lstdc++) else() - - if(MINGW) - target_compile_options(nana PUBLIC -static) # -static ?? cmake knows BUILD_SHARED_LIBS - else() - target_compile_options(nana PUBLIC -static-libgcc -static-libstdc++) - endif() + target_compile_options(nana PUBLIC -static -static-libstdc++) endif(BUILD_SHARED_LIBS) endif() \ No newline at end of file From c6b0a7093d91b02bb9355fb588390eaf8fe315b0 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 15 May 2019 13:44:32 +0200 Subject: [PATCH 27/61] use target_link_libraries --- build/cmake/shared_libs.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/cmake/shared_libs.cmake b/build/cmake/shared_libs.cmake index 1479e0d4..104e252f 100644 --- a/build/cmake/shared_libs.cmake +++ b/build/cmake/shared_libs.cmake @@ -40,7 +40,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AN if(BUILD_SHARED_LIBS) target_compile_options(nana PUBLIC -lgcc -lstdc++) else() - target_compile_options(nana PUBLIC -static -static-libstdc++) + target_link_libraries(nana PUBLIC -static -static-libstdc++) endif(BUILD_SHARED_LIBS) endif() \ No newline at end of file From 6fe009961f305b709af3c72265e31fd72d829cf7 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 15 May 2019 14:08:53 +0200 Subject: [PATCH 28/61] fix comments: Boost as workaround --- build/cmake/select_filesystem.cmake | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build/cmake/select_filesystem.cmake b/build/cmake/select_filesystem.cmake index 10c9836f..7b2163de 100644 --- a/build/cmake/select_filesystem.cmake +++ b/build/cmake/select_filesystem.cmake @@ -1,11 +1,12 @@ -# The ISO C++ File System Technical Specification (ISO-TS, or STD) is optional. +# The ISO C++ File System Technical Specification (ISO-TS, or STD) was optional. # http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf -# This is not a workaround, but an user option. -# The library maybe available in the std library in use or from Boost (almost compatible) +# It is part of c++17. +# The library may be not available or working correctly in the std library in use. As a workaround we may try +# to "implement" it (ab)using Boost (almost compatible) # http://www.boost.org/doc/libs/1_60_0/libs/filesystem/doc/index.htm # or you can choose to use the (partial, but functional) implementation provided by nana. # If you include the file or -# the selected option will be set by nana into std::experimental::filesystem +# the selected option will be set by nana into std::filesystem # By default Nana will try to use the STD. If STD is not available and NANA_CMAKE_FIND_BOOST_FILESYSTEM # is set to ON nana will try to use boost if available. Nana own implementation will be use if none of # the previus were selected or available. From 396319ea283f6f1794ab8082d135a2ba496fff46 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 23 May 2019 00:49:56 +0800 Subject: [PATCH 29/61] add new method listbox;:set_deselect set a predicate that decides to deselect selected items in mouse_up event. --- include/nana/gui/widgets/listbox.hpp | 10 ++++++++++ source/gui/widgets/listbox.cpp | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index ac3fc9f7..717d6d91 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1593,6 +1593,16 @@ the nana::detail::basic_window member pointer scheme * @return index_pairs containing all visible items. */ index_pairs visibles() const; + + /// Sets a predicate that indicates whether to deselect items when mouse_up is triggered. + /** + * The predicate is called before the listbox attempts to deselect the selected items in the mouse_up event. Other situations, + * the predicates isn't called, for example, releasing mouse button after user performed a box selection, because listbox doesn't deselect the items during this operation. + * @param predicate Decides to deselect the items. + * The paramater of predicate indicates the mouse button which is releasing. + * It returns true to deselect the selected items. It returns false to cancel to deselect the selected items. + */ + void set_deselect(std::function predicate); private: drawerbase::listbox::essence & _m_ess() const; nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const override; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index f387140f..9d372746 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2011,6 +2011,8 @@ namespace nana std::function ctg_icon_renderer; ///< Renderer for the category icon + std::function pred_msup_deselect; + struct operation_rep { operation_states state{operation_states::none}; @@ -4470,7 +4472,10 @@ namespace nana if (operation_states::msup_deselect == essence_->operation.state) { essence_->operation.state = operation_states::none; - need_refresh |= essence_->lister.select_for_all(false, essence_->operation.item); + + //Don't deselect if the predicate returns false + if(!(essence_->pred_msup_deselect && !essence_->pred_msup_deselect(arg.button))) + need_refresh |= essence_->lister.select_for_all(false, essence_->operation.item); } if (need_refresh) @@ -6102,6 +6107,11 @@ namespace nana return indexes; } + void listbox::set_deselect(std::function predicate) + { + _m_ess().pred_msup_deselect = std::move(predicate); + } + drawerbase::listbox::essence & listbox::_m_ess() const { return get_drawer_trigger().ess(); From 0e8328eba3d2a3ce740332ae7ba0ade53ce32b8a Mon Sep 17 00:00:00 2001 From: Gheorghe Florian GLAVAN Date: Thu, 23 May 2019 12:17:30 +0300 Subject: [PATCH 30/61] fix for #440 (unicode_bidi aletter always true) --- source/unicode_bidi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/unicode_bidi.cpp b/source/unicode_bidi.cpp index 26eaf512..7b054e10 100644 --- a/source/unicode_bidi.cpp +++ b/source/unicode_bidi.cpp @@ -976,7 +976,7 @@ namespace nana 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)) + (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) From b0ae6425ca39cdea393878ca2d8600d42b771a57 Mon Sep 17 00:00:00 2001 From: Xeverous <20820409+Xeverous@users.noreply.github.com> Date: Thu, 30 May 2019 10:59:45 +0200 Subject: [PATCH 31/61] add alias nana::nana in CMakeLists.txt This commit adds the alias to allow the use of nana::nana in other projects as per guideline https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1#using-a-library-defined-in-the-same-cmake-tree-should-look-the-same-as-using-an-external-library. This change should not break anything, it only adds an alternative name --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9252dce..3d842ebd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ project(nana VERSION 1.6.2 ####################### Main setting of Nana targets, sources and installs ##################### add_library(nana) +add_library(nana::nana ALIAS nana) target_compile_features(nana PUBLIC cxx_std_17) # need after cxx_std_14 or cxx_std_17 ?? From f57e8244312f9273fb5d654fcee58af4dfa29a64 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 1 Jun 2019 03:15:59 +0800 Subject: [PATCH 32/61] add support of multi-language under Linux(#439) also fix the font style issue under Linux --- include/nana/gui/programming_interface.hpp | 7 + source/detail/platform_abstraction.cpp | 486 +++++++++++++++++- source/detail/platform_abstraction.hpp | 3 +- source/gui/programming_interface.cpp | 5 + .../paint/detail/native_paint_interface.cpp | 29 +- source/paint/graphics.cpp | 10 +- 6 files changed, 514 insertions(+), 26 deletions(-) diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 0b5e42ed..9c463521 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -183,6 +183,13 @@ namespace API }; }//end namespace detail + ///Sets languages + /** + * Specifies the languages in order to make the program display multi-languages correctly + * Under Windows, the pragram can display multi-languages correctly, so this function is useless for Windows. + */ + void font_languages(const std::string& langs); + void exit(); ///< close all windows in current thread void exit_all(); ///< close all windows diff --git a/source/detail/platform_abstraction.cpp b/source/detail/platform_abstraction.cpp index 515f6ace..ea6032b2 100644 --- a/source/detail/platform_abstraction.cpp +++ b/source/detail/platform_abstraction.cpp @@ -1,4 +1,5 @@ #include "platform_abstraction.hpp" +#include #include #include "../paint/truetype.hpp" @@ -153,6 +154,389 @@ IsWindows8OrGreater() namespace nana { +#ifdef NANA_USE_XFT + //A fallback fontset provides the multiple languages support. + class fallback_fontset + { + public: + fallback_fontset(): + disp_(::nana::detail::platform_spec::instance().open_display()) + { + } + + ~fallback_fontset() + { + for(auto xft: xftset_) + ::XftFontClose(disp_, xft); + } + + void open(const std::string& font_desc, const std::set& langs) + { + for(auto xft: xftset_) + ::XftFontClose(disp_, xft); + + xftset_.clear(); + + std::set loaded; + for(auto & lang : langs) + { + std::string patstr = "*" + font_desc + ":lang=" + lang; + + auto pat = ::XftNameParse(patstr.c_str()); + XftResult res; + auto match_pat = ::XftFontMatch(disp_, ::XDefaultScreen(disp_), pat, &res); + + if (match_pat) + { + char * sf; + if(XftResultTypeMismatch != ::XftPatternGetString(match_pat, "family", 0, &sf)) + { + //Avoid loading a some font repeatedly + if(loaded.count(sf)) + continue; + } + + auto xft = ::XftFontOpenPattern(disp_, match_pat); + if(xft) + xftset_.push_back(xft); + } + } + } + + int draw(::XftDraw* xftdraw, ::XftColor * xftcolor, ::XftFont* xft, int x, int y, const wchar_t* str, std::size_t len) + { + if(nullptr == str || 0 == len) + return 0; + + int const init_x = x; + std::unique_ptr glyph_indexes(new FT_UInt[len]); + + while(true) + { + auto preferred = _m_scan_fonts(xft, str, len, glyph_indexes.get()); + x += _m_draw(xftdraw, xftcolor, preferred.first, x, y, str, preferred.second, glyph_indexes.get()); + + if(len == preferred.second) + break; + + len -= preferred.second; + str += preferred.second; + } + + return x - init_x; + } + + std::unique_ptr glyph_pixels(::XftFont* xft, const wchar_t* str, std::size_t len) + { + if(nullptr == xft || nullptr == str || 0 == len) + return {}; + + std::unique_ptr glyph_indexes{new FT_UInt[len]}; + + std::unique_ptr pxbuf{new unsigned[len]}; + + auto pbuf = pxbuf.get(); + auto pstr = str; + auto size = len; + + while(true) + { + auto preferred = _m_scan_fonts(xft, pstr, size, glyph_indexes.get()); + + _m_glyph_px(preferred.first, pstr, preferred.second, glyph_indexes.get(), pbuf); + + if(size == preferred.second) + break; + + size -= preferred.second; + pstr += preferred.second; + pbuf += preferred.second; + } + + return pxbuf; + } + + nana::size extents(::XftFont* xft, const wchar_t* str, std::size_t len) + { + nana::size extent; + + if(nullptr == str || 0 == len) + return extent; + + std::unique_ptr glyph_indexes(new FT_UInt[len]); + + while(len > 0) + { + auto preferred = _m_scan_fonts(xft, str, len, glyph_indexes.get()); + + extent.width += _m_extents(preferred.first, str, preferred.second, glyph_indexes.get()); + + if(preferred.first->ascent + preferred.first->descent > static_cast(extent.height)) + extent.height = preferred.first->ascent + preferred.first->descent; + + len -= preferred.second; + str += preferred.second; + } + return extent; + } + private: + //Tab is a invisible character + int _m_draw(::XftDraw* xftdraw, ::XftColor* xftcolor, ::XftFont* xft, int x, int y, const wchar_t* str, std::size_t len, const FT_UInt* glyph_indexes) + { + int const init_x = x; + + auto p = str; + auto const end = str + len; + + y += xft->ascent; + + ::XGlyphInfo ext; + while(p < end) + { + auto off = p - str; + auto ptab = _m_find_tab(p, end); + if(ptab == p) + { + ++p; + //x += static_cast(tab_pixels_); + continue; + } + + auto const size = ptab - p; + ::XftDrawGlyphs(xftdraw, xftcolor, xft, x, y, glyph_indexes + off, size); + ::XftGlyphExtents(disp_, xft, glyph_indexes + off, size, &ext); + + x += ext.xOff; + + if(ptab == end) + break; + + p = ptab + 1; + } + + return x - init_x; + } + + //Tab is a invisible character + unsigned _m_extents(::XftFont* xft, const wchar_t* const str, const std::size_t len, const FT_UInt* glyph_indexes) + { + unsigned pixels = 0; + auto p = str; + auto const end = str + len; + + ::XGlyphInfo ext; + while(p < end) + { + auto off = p - str; + auto ptab = _m_find_tab(p, end); + if(ptab == p) + { + ++p; + //extents->xOff += tab_pixels_; + continue; + } + + ::XftGlyphExtents(disp_, xft, glyph_indexes + off, ptab - p, &ext); + + pixels += ext.xOff; + + if(end == ptab) + break; + p = ptab + 1; + } + + return pixels; + } + + //Tab is a invisible character + void _m_glyph_px(::XftFont* xft, const wchar_t* str, std::size_t len, const FT_UInt* glyph_indexes, unsigned* pxbuf) + { + auto const end = str + len; + + ::XGlyphInfo extent; + for(auto p = str; p < end; ++p) + { + if('\t' != *p) + { + ::XftGlyphExtents(disp_, xft, glyph_indexes, 1, &extent); + *pxbuf = extent.xOff; + } + else + *pxbuf = 0;//tab_pixels_; + + ++glyph_indexes; + } + } + + static const wchar_t* _m_find_tab(const wchar_t* begin, const wchar_t* end) + { + while(begin < end) + { + if('\t' == *begin) + return begin; + + ++begin; + } + return end; + } + + std::pair<::XftFont*, std::size_t> _m_scan_fonts(::XftFont* xft, const wchar_t* str, std::size_t len, FT_UInt* const glyphs) const + { + auto preferred = xft; + auto idx = ::XftCharIndex(disp_, xft, *str); + if(0 == idx) + { + for(auto ft : xftset_) + { + idx = ::XftCharIndex(disp_, ft, *str); + if(idx) + { + preferred = ft; + break; + } + } + } + + *glyphs = idx; + + if(0 == idx) + { + //scan the str with all fonts until a char index is found. + for(std::size_t i = 1; i < len; ++i) + { + if(::XftCharIndex(disp_, xft, str[i])) + return {preferred, i}; + + for(auto ft : xftset_) + { + if(::XftCharIndex(disp_, ft, str[i])) + return {preferred, i}; + } + glyphs[i] = 0; + } + + return {preferred, len}; + } + + //scan the str with preferred font until a char index is invalid. + for(std::size_t i = 1; i < len; ++i) + { + idx = ::XftCharIndex(disp_, preferred, str[i]); + if(0 == idx) + return {preferred, i}; + + glyphs[i] = idx; + } + + return {preferred, len}; + } + private: + Display* const disp_; + std::vector<::XftFont*> xftset_; + }; + + /// Fallback fontset manager + class fallback_manager + { + public: + fallback_manager(): + langs_(_m_split_lang("ar,hi,zh-cn,zh-tw,ja,ko,th")) + { + } + + void languages(const std::string& lang) + { + langs_ = _m_split_lang(lang); + + for(auto & xft : xft_table_) + { + xft.second->open(xft.first, langs_); + } + } + + std::shared_ptr make_fallback(const std::string& font_desc) + { + auto i = xft_table_.find(font_desc); + if(i != xft_table_.end()) + return i->second; + + auto fb = std::make_shared(); + + fb->open(font_desc, langs_); + + xft_table_[font_desc] = fb; + + return fb; + } + + void release_fallback(std::shared_ptr& p) + { + for(auto i = xft_table_.cbegin(); i != xft_table_.cend(); ++i) + { + if(i->second == p) + { + if(p.use_count() <= 2) + xft_table_.erase(i); + break; + } + } + } + + private: + static std::set _m_split_lang(const std::string& lang) + { + std::set langs; + std::size_t start_pos = 0; + while(true) + { + auto pos = lang.find(',', start_pos); + auto l = lang.substr(start_pos, lang.npos == pos? lang.npos : pos - start_pos); + + if(!l.empty()) + langs.insert(l); + + if(lang.npos == pos) + break; + + start_pos = pos + 1; + } + + return langs; + } + private: + std::set langs_; + std::map> xft_table_; + }; +#endif + + struct platform_runtime + { + std::shared_ptr font; + +#ifdef NANA_X11 + std::map fontconfig_counts; +#endif +#ifdef NANA_USE_XFT + fallback_manager fb_manager; +#endif + }; + + namespace + { + namespace data + { + static platform_runtime* storage; + } + } + + static platform_runtime& platform_storage() + { + if (nullptr == data::storage) + throw std::runtime_error("platform_abstraction is empty"); + + return *data::storage; + } + class internal_font : public font_interface @@ -160,13 +544,24 @@ namespace nana public: using path_type = std::filesystem::path; +#ifdef NANA_USE_XFT + internal_font(const path_type& ttf, const std::string& font_family, double font_size, const font_style& fs, native_font_type native_font, std::shared_ptr fallback): + ttf_(ttf), + family_(font_family), + size_(font_size), + style_(fs), + native_handle_(native_font), + fallback_(fallback) + {} +#else internal_font(const path_type& ttf, const std::string& font_family, double font_size, const font_style& fs, native_font_type native_font): ttf_(ttf), family_(font_family), size_(font_size), style_(fs), native_handle_(native_font) - {} + {} +#endif ~internal_font() { @@ -175,6 +570,7 @@ namespace nana #elif defined(NANA_X11) auto disp = ::nana::detail::platform_spec::instance().open_display(); # ifdef NANA_USE_XFT + platform_storage().fb_manager.release_fallback(fallback_); ::XftFontClose(disp, reinterpret_cast(native_handle_)); # else ::XFreeFontSet(disp, reinterpret_cast(native_handle_)); @@ -203,39 +599,58 @@ namespace nana { return native_handle_; } + +#ifdef NANA_USE_XFT + fallback_fontset* fallback() const + { + return fallback_.get(); + } +#endif private: path_type const ttf_; std::string const family_; double const size_; font_style const style_; native_font_type const native_handle_; - }; - - struct platform_runtime - { - std::shared_ptr font; - -#ifdef NANA_X11 - std::map fontconfig_counts; +#ifdef NANA_USE_XFT + std::shared_ptr fallback_; #endif }; - namespace +#ifdef NANA_USE_XFT + void nana_xft_draw_string(::XftDraw* xftdraw, ::XftColor* xftcolor, font_interface* ft, const nana::point& pos, const wchar_t * str, std::size_t len) { - namespace data - { - static platform_runtime* storage; - } + auto fallback = static_cast(ft)->fallback(); + if(nullptr == fallback) + return; + + auto xft = reinterpret_cast(static_cast(ft)->native_handle()); + fallback->draw(xftdraw, xftcolor, xft, pos.x, pos.y, str, len); } - static platform_runtime& platform_storage() - { - if (nullptr == data::storage) - throw std::runtime_error("platform_abstraction is empty"); - return *data::storage; + nana::size nana_xft_extents(font_interface* ft, const wchar_t* str, std::size_t len) + { + auto fallback = static_cast(ft)->fallback(); + if(nullptr == fallback) + return {}; + + auto xft = reinterpret_cast(static_cast(ft)->native_handle()); + return fallback->extents(xft, str, len); } + std::unique_ptr nana_xft_glyph_pixels(font_interface* ft, const wchar_t* str, std::size_t len) + { + auto fallback = static_cast(ft)->fallback(); + if(nullptr == fallback) + return {}; + + auto xft = reinterpret_cast(static_cast(ft)->native_handle()); + return fallback->glyph_pixels(xft, str, len); + } +#endif + + void platform_abstraction::initialize() { if (nullptr == data::storage) @@ -284,6 +699,13 @@ namespace nana #endif } + void platform_abstraction::font_languages(const std::string& langs) + { +#ifdef NANA_USE_XFT + platform_storage().fb_manager.languages(langs); +#endif + } + ::std::shared_ptr platform_abstraction::default_font(const ::std::shared_ptr& new_font) { auto & r = platform_storage(); @@ -364,10 +786,22 @@ namespace nana auto disp = ::nana::detail::platform_spec::instance().open_display(); # ifdef NANA_USE_XFT if(font_family.empty()) - font_family = '*'; + font_family = "*"; - std::string pat_str = font_family + '-' + std::to_string(size_pt ? size_pt : platform_abstraction::font_default_pt()); - auto pat = ::XftNameParse(pat_str.c_str()); + std::string pat_str = '-' + std::to_string(size_pt ? size_pt : platform_abstraction::font_default_pt()); + if(fs.weight < 400) + pat_str += ":light"; + else if(400 == fs.weight) + pat_str += ":medium"; + else if(fs.weight < 700) + pat_str += ":demibold"; + else + pat_str += (700 == fs.weight ? ":bold": ":black"); + + if(fs.italic) + pat_str += ":slant=italic"; + + auto pat = ::XftNameParse((font_family + pat_str).c_str()); XftResult res; auto match_pat = ::XftFontMatch(disp, ::XDefaultScreen(disp), pat, &res); @@ -387,8 +821,16 @@ namespace nana XFontSet fd = ::XCreateFontSet(display_, const_cast(pat_str.c_str()), &missing_list, &missing_count, &defstr); # endif #endif + if (fd) + { +#ifdef NANA_USE_XFT + auto fallback = platform_storage().fb_manager.make_fallback(pat_str); + return std::make_shared(std::move(ttf), std::move(font_family), size_pt, fs, reinterpret_cast(fd), fallback); +#else return std::make_shared(std::move(ttf), std::move(font_family), size_pt, fs, reinterpret_cast(fd)); +#endif + } return{}; } diff --git a/source/detail/platform_abstraction.hpp b/source/detail/platform_abstraction.hpp index 3e22112a..6af2d170 100644 --- a/source/detail/platform_abstraction.hpp +++ b/source/detail/platform_abstraction.hpp @@ -1,7 +1,7 @@ /* * Platform Abstraction * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2017-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -34,6 +34,7 @@ namespace nana /// Shutdown before destruction of platform_spec static void shutdown(); static double font_default_pt(); + static void font_languages(const std::string&); static ::std::shared_ptr default_font(const ::std::shared_ptr&); static ::std::shared_ptr make_font(const ::std::string& font_family, double size_pt, const font::font_style& fs); static ::std::shared_ptr make_font_from_ttf(const path_type& ttf, double size_pt, const font::font_style& fs); diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index a73ec1bf..28b61836 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -441,6 +441,11 @@ namespace API return nullptr; } + void font_languages(const std::string& langs) + { + ::nana::platform_abstraction::font_languages(langs); + } + //close all windows in current thread void exit() { diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index 91b34a81..c31a27d7 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -1,7 +1,7 @@ /* * Platform Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -24,6 +24,12 @@ namespace nana { + //Forward-declarations + //These names are defined platform_abstraction.cpp + class font_interface; + void nana_xft_draw_string(::XftDraw* xftdraw, ::XftColor* xftcolor, font_interface* ft, const nana::point& pos, const wchar_t * str, std::size_t len); + nana::size nana_xft_extents(font_interface* ft, const wchar_t* str, std::size_t len); + namespace paint { namespace detail @@ -144,14 +150,19 @@ namespace detail if (::GetTextExtentPoint32(dw->context, text, static_cast(len), &size)) return nana::size(size.cx, size.cy); #elif defined(NANA_X11) - std::string utf8text = to_utf8(std::wstring(text, len)); #if defined(NANA_USE_XFT) + #if 0 + std::string utf8text = to_utf8(std::wstring(text, len)); XGlyphInfo ext; XftFont * fs = reinterpret_cast(dw->font->native_handle()); ::XftTextExtentsUtf8(nana::detail::platform_spec::instance().open_display(), fs, reinterpret_cast(const_cast(utf8text.data())), utf8text.size(), &ext); return nana::size(ext.xOff, fs->ascent + fs->descent); + #else + return nana_xft_extents(dw->font.get(), text, len); + #endif #else + std::string utf8text = to_utf8(std::wstring(text, len)); XRectangle ink; XRectangle logic; ::XmbTextExtents(reinterpret_cast(dw->font->native_handle()), utf8text.c_str(), utf8text.size(), &ink, &logic); @@ -178,11 +189,20 @@ namespace detail return nana::size(size.cx, size.cy); #elif defined(NANA_X11) #if defined(NANA_USE_XFT) + #if 0 XGlyphInfo ext; XftFont * fs = reinterpret_cast(dw->font->native_handle()); ::XftTextExtentsUtf8(nana::detail::platform_spec::instance().open_display(), fs, reinterpret_cast(const_cast(text)), len, &ext); return nana::size(ext.xOff, fs->ascent + fs->descent); + #else +#ifdef _nana_std_has_string_view + auto wstr = to_wstring(std::string_view(text, len)); +#else + auto wstr = to_wstring(std::string(text,len)); +#endif + return nana_xft_extents(dw->font.get(), wstr.data(), wstr.size()); + #endif #else XRectangle ink; XRectangle logic; @@ -240,6 +260,8 @@ namespace detail #elif defined(NANA_X11) auto disp = ::nana::detail::platform_spec::instance().open_display(); #if defined(NANA_USE_XFT) + + #if 0 auto fs = reinterpret_cast(dw->font->native_handle()); //Fixed missing array declaration by dareg @@ -251,6 +273,9 @@ namespace detail (*glyphs++) = XftCharIndex(disp, fs, *chr); } XftDrawGlyphs(dw->xftdraw, &(dw->xft_fgcolor), fs, pos.x, pos.y + fs->ascent, glyphs_ptr.get(), len); + #else + nana_xft_draw_string(dw->xftdraw, &(dw->xft_fgcolor), dw->font.get(), pos, str, len); + #endif #else XFontSet fs = reinterpret_cast(dw->font->native_handle()); XFontSetExtents * ext = ::XExtentsOfFontSet(fs); diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index c217dd70..9a89ba03 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -1,7 +1,7 @@ /* * Paint Graphics Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -28,6 +28,10 @@ namespace nana { + //Forward-declarations + //These names are defined platform_abstraction.cpp + std::unique_ptr nana_xft_glyph_pixels(font_interface*, const wchar_t* str, std::size_t len); + namespace detail { font_style::font_style(unsigned weight, bool italic, bool underline, bool strike_out) : @@ -517,6 +521,7 @@ namespace paint delete[] dx; #elif defined(NANA_X11) && defined(NANA_USE_XFT) + #if 0 auto disp = nana::detail::platform_spec::instance().open_display(); auto xft = reinterpret_cast(impl_->handle->font->native_handle()); @@ -532,6 +537,9 @@ namespace paint else pxbuf[i] = tab_pixels; } + #else + return nana_xft_glyph_pixels(impl_->handle->font.get(), text.data(), text.size()); + #endif #endif } return pxbuf; From 417071e4b531b608cf68150b5caef2cd847a6fc0 Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Mon, 3 Jun 2019 17:51:21 -0400 Subject: [PATCH 33/61] fix for selection bug described in issue #448 --- source/gui/widgets/listbox.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 3660dce0..7dcb2b43 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -4350,6 +4350,8 @@ namespace nana } else lister.select_for_all(false, abs_item_pos); + + lister.latest_selected_abs = abs_item_pos; } } else From 3533b970921e3ee43e51c7fb8488cf2b120480f0 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 4 Jun 2019 08:45:39 +0800 Subject: [PATCH 34/61] XFT code incorrectly enabled under Windows --- source/paint/detail/native_paint_interface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index c31a27d7..db01ea30 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -24,11 +24,13 @@ namespace nana { +#ifdef NANA_USE_XFT //Forward-declarations //These names are defined platform_abstraction.cpp class font_interface; void nana_xft_draw_string(::XftDraw* xftdraw, ::XftColor* xftcolor, font_interface* ft, const nana::point& pos, const wchar_t * str, std::size_t len); nana::size nana_xft_extents(font_interface* ft, const wchar_t* str, std::size_t len); +#endif namespace paint { From 17240f5a51e935de525d9aee144ba697494c93a6 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 12 Jun 2019 12:39:31 +0200 Subject: [PATCH 35/61] NANA_CMAKE_INSTALL=ON, but now normal users need to set OFF or EXCLUDE_FROM_ALL --- build/cmake/install_nana.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/cmake/install_nana.cmake b/build/cmake/install_nana.cmake index 2b6851d6..4450e4f8 100644 --- a/build/cmake/install_nana.cmake +++ b/build/cmake/install_nana.cmake @@ -1,4 +1,4 @@ -option(NANA_CMAKE_INSTALL "Install nana when compile the library (to be consumed without cmake)" OFF) +option(NANA_CMAKE_INSTALL "Install nana when compile the library (to be consumed without cmake)" ON) # Install the include directories too. if(NANA_CMAKE_INSTALL) From ceb81a087695ecf03d76ddc07876fb72b1ad96db Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 12 Jun 2019 12:44:01 +0200 Subject: [PATCH 36/61] eliminate debug info in release, size of executable is 1/10 --- build/cmake/compilers.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/cmake/compilers.cmake b/build/cmake/compilers.cmake index 80daf9e9..c8db4976 100644 --- a/build/cmake/compilers.cmake +++ b/build/cmake/compilers.cmake @@ -14,8 +14,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW?? - target_compile_options(nana PRIVATE -Wall - PUBLIC -g ) + target_compile_options(nana PRIVATE -Wall) # todo: set in target property of nana set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -mtune=native -DNDEBUG") From 76d5138f5529394cc45cc420a97a5526879624ee Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 12 Jun 2019 12:44:52 +0200 Subject: [PATCH 37/61] nana cmake version 1.7.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1814e4fb..69e1de1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ # cmake 3.12 have more better modern c++ support cmake_minimum_required(VERSION 3.12 FATAL_ERROR) -project(nana VERSION 1.6.2 +project(nana VERSION 1.7.1 DESCRIPTION "C++ GUI library" HOMEPAGE_URL http://nanapro.org LANGUAGES CXX ) From 0233af0ba8372dcc6536ca4137b92a7166b7463c Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 12 Jun 2019 12:45:29 +0200 Subject: [PATCH 38/61] use vc2017 in CI --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4305ba46..3689bdc6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ version: 1.0.{build} build: - project: build\vc2015\nana.sln + project: build\vc2017\nana.sln verbosity: minimal \ No newline at end of file From cea2f0138848732d6595d278383a70202a8db2f3 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 12 Jun 2019 13:27:14 +0200 Subject: [PATCH 39/61] Visual Studio 2017 ? --- appveyor.yml | 2 ++ build/cmake/install_nana.cmake | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 3689bdc6..ab87092f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,6 @@ version: 1.0.{build} +image: + - Visual Studio 2017 build: project: build\vc2017\nana.sln verbosity: minimal \ No newline at end of file diff --git a/build/cmake/install_nana.cmake b/build/cmake/install_nana.cmake index 4450e4f8..45636484 100644 --- a/build/cmake/install_nana.cmake +++ b/build/cmake/install_nana.cmake @@ -2,7 +2,7 @@ option(NANA_CMAKE_INSTALL "Install nana when compile the library (to be consumed # Install the include directories too. if(NANA_CMAKE_INSTALL) - # this is the prefered method to consume nana directly with some specific bulid system + # This is a method to consume nana with a bulid system not directly supported by nana. # Is your responsability to ensure all compiler options are compatible with the compilation # of the project linking to the nana lib here generated target_sources(nana PRIVATE ${HEADERS}) From 9a9399130b0409ba76740461a6c42478471014c6 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 12 Jun 2019 13:37:16 +0200 Subject: [PATCH 40/61] DNANA_CMAKE_INSTALL=OFF --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 20ef6e32..160e9abb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,7 +63,7 @@ before_script : - cd demo-build script: - - cmake -G"Unix Makefiles" ../nana-demo -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=OFF -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON + - cmake -G"Unix Makefiles" ../nana-demo -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=OFF -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON -DNANA_CMAKE_INSTALL=OFF - make install # todo: separate resources from sources (a directory for images) - ls From 4818da59a8a7bdc21ed11edfd9bd8ab831af1eb3 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 12 Jun 2019 13:37:49 +0200 Subject: [PATCH 41/61] use nana-demo develop --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 160e9abb..82604edf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,7 @@ matrix: before_install: - cd .. - - git clone --depth=1 --branch=hotfix https://github.com/qPCR4vir/nana-demo.git nana-demo + - git clone --depth=1 --branch=develop https://github.com/qPCR4vir/nana-demo.git nana-demo - export PATH="$HOME/bin:$PATH" - wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.12/cmake-3.12.0-rc3-Linux-x86_64.sh || true - chmod -R +x /tmp/tools From 6a46ec4f521b6d42fb80df32bc23506b6bfc0de5 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 12 Jun 2019 16:13:37 +0200 Subject: [PATCH 42/61] -static-libgcc ? --- build/cmake/shared_libs.cmake | 2 +- include/nana/gui/widgets/group.hpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build/cmake/shared_libs.cmake b/build/cmake/shared_libs.cmake index 104e252f..febb3b42 100644 --- a/build/cmake/shared_libs.cmake +++ b/build/cmake/shared_libs.cmake @@ -40,7 +40,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AN if(BUILD_SHARED_LIBS) target_compile_options(nana PUBLIC -lgcc -lstdc++) else() - target_link_libraries(nana PUBLIC -static -static-libstdc++) + target_link_libraries(nana PUBLIC -static-libgcc -static-libstdc++) endif(BUILD_SHARED_LIBS) endif() \ No newline at end of file diff --git a/include/nana/gui/widgets/group.hpp b/include/nana/gui/widgets/group.hpp index 43dd5e85..139f7f15 100644 --- a/include/nana/gui/widgets/group.hpp +++ b/include/nana/gui/widgets/group.hpp @@ -100,6 +100,10 @@ namespace nana{ group& enable_format_caption(bool format); group& collocate() noexcept; + + /// this will set the `usr_div_str` for an internal field, called the "user field". + /// The "full" `place` of a `group` widget is internally divided into a field for the title, + /// a field for the added "options" and a field for "user" widgets. group& div(const char* div_str) noexcept; field_reference operator[](const char* field); From 363953be20b6603eb448abc43da81122b6ed59bc Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 14 Jun 2019 05:34:28 +0800 Subject: [PATCH 43/61] improve compatability with old compiler --- source/datetime.cpp | 17 ++++++++--------- source/gui/place.cpp | 16 ++++++++-------- source/system/dataexch.cpp | 3 --- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/source/datetime.cpp b/source/datetime.cpp index 8b024735..e6e8fa5b 100644 --- a/source/datetime.cpp +++ b/source/datetime.cpp @@ -14,29 +14,28 @@ #if defined(NANA_WINDOWS) #include #endif -#include #include namespace { std::tm localtime() { #if defined(NANA_WINDOWS) && !defined(NANA_MINGW) - time_t t; - ::time(&t); + std::time_t t = std::time(nullptr); std::tm tm; - if(localtime_s(&tm, &t) != 0) - assert(false); + if (localtime_s(&tm, &t) != 0) + throw std::runtime_error("invalid local time"); return tm; #else time_t t = std::time(nullptr); struct tm * tm_addr = std::localtime(&t); - assert(tm_addr); - + if(nullptr == tm_addr) + throw std::runtime_error("invalid local time"); + return *tm_addr; #endif } - + ::nana::date::value to_dateval(const std::tm& t) { return {static_cast(t.tm_year + 1900), static_cast(t.tm_mon + 1), static_cast(t.tm_mday)}; @@ -51,7 +50,7 @@ namespace { namespace nana { - //class date + //class date void date::set(const std::tm& t) { value_ = to_dateval(t); diff --git a/source/gui/place.cpp b/source/gui/place.cpp index b29d98b0..b9acf02e 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -617,7 +617,7 @@ namespace nana : std::invalid_argument{ what + " from place implementation " }, pos{ pos }, - field { field.empty() ? "unnamed" : field } + field(field.empty() ? "unnamed" : field) {} std::string::size_type pos; std::string field; @@ -3674,18 +3674,18 @@ namespace nana std::string field, std::string::size_type pos) - : std::invalid_argument{ "from widget '" + : std::invalid_argument( "from widget '" + API::window_caption(plc.window_handle()).substr(0,80) + "'; nana::place error " + what + "' in field '" + field + (pos == std::string::npos ? "' " : "' at position " + std::to_string(pos)) - + " in div_text:\n" + plc.div() }, - base_what{ what }, - owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, - div_text{ plc.div() }, - field{ field }, - pos{ pos } + + " in div_text:\n" + plc.div() ), + base_what( what ), + owner_caption( API::window_caption(plc.window_handle()).substr(0,80) ), + div_text( plc.div() ), + field( field ), + pos( pos ) {} //end class place diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index 8c25ed5e..b3f4d5d4 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #if defined(NANA_WINDOWS) @@ -71,7 +70,6 @@ namespace nana{ namespace system{ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); HDC hDC = ::GetDC(NULL); if (::GetDIBits(hDC, (HBITMAP)g.pixmap(), 0, 1, NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS) == 0) { - assert(false); ::ReleaseDC(NULL, hDC); return false; } @@ -109,7 +107,6 @@ namespace nana{ namespace system{ ::CloseClipboard(); } } - assert(false); ::GlobalFree(h_gmem); return false; From a8c269d108b16aa5b27ff9ed68d3c8bf8d24f980 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 17 Jun 2019 07:36:33 +0800 Subject: [PATCH 44/61] refactor text_renderer --- source/paint/text_renderer.cpp | 257 ++++++++++++++------------------- 1 file changed, 105 insertions(+), 152 deletions(-) diff --git a/source/paint/text_renderer.cpp b/source/paint/text_renderer.cpp index 6f5654dd..db5ecfc5 100644 --- a/source/paint/text_renderer.cpp +++ b/source/paint/text_renderer.cpp @@ -16,7 +16,7 @@ namespace nana auto const end = str + len; for(auto i = str; i != end; ++i) { - if(*i == '\n') + if('\n' == *i) { top += static_cast(f(top, str, i - str)); str = i + 1; @@ -26,166 +26,125 @@ namespace nana f(top, str, end - str); } - struct draw_string - { - drawable_type dw; - const int x, endpos; - align text_align; - draw_string(drawable_type dw, int x, int endpos, align ta) - : dw(dw), x(x), endpos(endpos), text_align(ta) - {} + class string_drawer + { + public: + string_drawer(graphics& graph, int left, int right, align ta, bool use_ellipsis): + graph_(graph), + left_(left), + right_(right), + text_align_(ta) + { + if (use_ellipsis) + { +#ifdef _nana_std_has_string_view + ellipsis_px_ = graph.text_extent_size(std::string_view{ "...", 3 }).width; +#else + ellipsis_px_ = graph.text_extent_size("...", 3).width; +#endif + } + } unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) { + auto const drawable = graph_.handle(); auto const reordered = unicode_reorder(buf, bufsize); - if (reordered.empty()) - return 0; + + unsigned return_max_height = 0; + unsigned string_px = 0; + std::vector word_metrics; + for (auto & ent : reordered) + { + auto word_sz = detail::text_extent_size(drawable, ent.begin, ent.end - ent.begin); + word_metrics.push_back(word_sz); - nana::point pos{ x, top }; - unsigned pixels = 0; + string_px += word_sz.width; + if (word_sz.height > return_max_height) + return_max_height = word_sz.height; + } - switch(text_align) + auto text_align = text_align_; + // Checks if ellipsis is enabled and the total pixels of string is larger than the space. + if (ellipsis_px_ && (string_px > static_cast(right_ - left_))) + { + //The string should be drawn from left most point no matter what text align is. + text_align = align::left; + } + + nana::point pos{ left_, top }; + + auto wdm = word_metrics.data(); + switch (text_align) { case align::left: - for(auto & ent : reordered) + for (auto & ent : reordered) { - std::size_t len = ent.end - ent.begin; - nana::size ts = detail::text_extent_size(dw, ent.begin, len); + if (pos.x + static_cast(wdm->width) > 0) + { + if (pos.x + static_cast(wdm->width) <= right_ - static_cast(ellipsis_px_)) + { + //This word can be fully painted. + detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); + } + else + { + //This word is painted partially. Firstly, paints the word on a dummy graphics buffer. - if(ts.height > pixels) pixels = ts.height; - - if(pos.x + static_cast(ts.width) > 0) - detail::draw_string(dw, pos, ent.begin, len); + nana::rectangle r{ nana::size{ static_cast(right_ - ellipsis_px_) - pos.x, wdm->height } }; - pos.x += static_cast(ts.width); - if(pos.x >= endpos) + nana::paint::graphics dummy({ r.width, r.height }); + dummy.typeface(graph_.typeface()); + + dummy.bitblt(r, graph_, pos); + +#ifdef _nana_std_has_string_view + dummy.string({}, { ent.begin, ent.end - ent.begin }, graph_.palette(true)); +#else + dummy.palette(true, graph_.palette(true)); + dummy.string({}, ent.begin, ent.end - ent.begin); +#endif + r.x = pos.x; + r.y = top; + graph_.bitblt(r, dummy); + if (ellipsis_px_) + detail::draw_string(drawable, point{ right_ - static_cast(ellipsis_px_), top }, L"...", 3); + break; + } + } + + pos.x += static_cast(wdm->width); + if (pos.x > right_ - static_cast(ellipsis_px_)) break; + + ++wdm; } break; case align::center: + pos.x = (right_ - left_ - string_px) / 2; + for (auto & ent : reordered) { - unsigned lenpx = 0; - std::unique_ptr entity_pxs(new unsigned[reordered.size()]); - - auto ent_px = entity_pxs.get(); - - for(auto & ent : reordered) - { - auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin); - if(ts.height > pixels) pixels = ts.height; - lenpx += ts.width; - *ent_px++ = ts.width; - } - - pos.x += (endpos - pos.x - static_cast(lenpx))/2; - ent_px = entity_pxs.get(); - - for(auto & ent : reordered) - { - if (pos.x + static_cast(*ent_px) > 0) - detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin); - - pos.x += static_cast(*ent_px++); - - if(pos.x >= endpos) - break; - } + detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); + pos.x += (wdm++)->width; } break; case align::right: + wdm = word_metrics.data() + word_metrics.size() - 1; + pos.x = right_; + for (auto i = reordered.crbegin(); i != reordered.crend(); ++i) { - int xend = endpos; - std::swap(pos.x, xend); - for(auto i = reordered.crbegin(); i != reordered.crend(); ++i) - { - auto & ent = *i; - std::size_t len = ent.end - ent.begin; - nana::size ts = detail::text_extent_size(dw, ent.begin, len); - if(ts.height > pixels) pixels = ts.height; - - if(pos.x > xend) - { - pos.x -= static_cast(ts.width); - detail::draw_string(dw, pos, i->begin, len); - } - - if(pos.x <= xend || pos.x <= 0) - break; - } + pos.x -= (wdm--)->width; + detail::draw_string(drawable, pos, i->begin, i->end - i->begin); } break; } - return pixels; - } - }; - - struct draw_string_omitted - { - graphics & graph; - int x, endpos; - unsigned omitted_pixels; - - draw_string_omitted(graphics& graph, int x, int endpos, bool omitted) - : graph(graph), x(x), endpos(endpos) - { -#ifdef _nana_std_has_string_view - omitted_pixels = (omitted ? graph.text_extent_size(std::string_view{ "...", 3 }).width : 0); -#else - omitted_pixels = (omitted ? graph.text_extent_size("...", 3).width : 0); -#endif - if (endpos - x > static_cast(omitted_pixels)) - this->endpos -= omitted_pixels; - else - this->endpos = x; - } - - unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) - { - drawable_type dw = graph.handle(); - ::nana::point pos{ x, top }; - unsigned pixels = 0; - - auto const reordered = unicode_reorder(buf, bufsize); - - for(auto & i : reordered) - { - std::size_t len = i.end - i.begin; - nana::size ts = detail::text_extent_size(dw, i.begin, len); - if(ts.height > pixels) pixels = ts.height; - - if(pos.x + static_cast(ts.width) <= endpos) - { - detail::draw_string(dw, pos, i.begin, len); - pos.x += static_cast(ts.width); - } - else - { - nana::rectangle r; - r.width = endpos - pos.x; - r.height = ts.height; - - nana::paint::graphics dum_graph({ r.width, r.height }); - - dum_graph.bitblt(r, graph, pos); - -#ifdef _nana_std_has_string_view - dum_graph.string({}, { i.begin, len }, graph.palette(true)); -#else - dum_graph.palette(true, graph.palette(true)); - dum_graph.string({}, i.begin, len); -#endif - - r.x = pos.x; - r.y = top; - graph.bitblt(r, dum_graph); - if(omitted_pixels) - detail::draw_string(dw, point{ endpos, top }, L"...", 3); - break; - } - } - return pixels; + return return_max_height; } + private: + graphics& graph_; + const int left_, right_; //the range of rendering area in x-axis + const align text_align_; + unsigned ellipsis_px_{ 0 }; }; @@ -380,16 +339,10 @@ namespace nana static std::size_t find_splitted(std::size_t begin, std::size_t end, int x, int endpos, unsigned * pxbuf) { - unsigned acc_width = 0; - for(std::size_t i = begin; i < end; ++i) + for (std::size_t i = begin; i < end; ++i) { - if(x + static_cast(acc_width + pxbuf[i]) > endpos) - { - if(i == begin) - ++i; - return i; - } - acc_width += pxbuf[i]; + if ((x += static_cast(pxbuf[i])) > endpos) + return (begin == i ? i + 1 : i); } return end; } @@ -399,12 +352,11 @@ namespace nana wchar_t ch = str[index]; if(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) { - wchar_t prch; if(index) { - prch = str[index - 1]; + auto prch = str[index - 1]; if('0' <= ch && ch <= '9') - return !(('0' <= prch && prch <= '9') || (str[index - 1] == '-')); + return !(('0' <= prch && prch <= '9') || (prch == '-')); return (('z' < prch || prch < 'a') && ('Z' < prch || prch < 'A')); } @@ -481,6 +433,7 @@ namespace nana { for(std::size_t i = idx_head; i < len; ++i) xpos += static_cast(pxbuf[i]); + break; } //Check the word whether it is splittable. @@ -585,8 +538,8 @@ namespace nana { if (graph_) { - helper::draw_string ds(graph_.handle(), pos.x, static_cast(graph_.width()), text_align_); - helper::for_each_line(str, len, pos.y, ds); + helper::string_drawer sd{ graph_, pos.x, static_cast(graph_.width()), text_align_, false }; + helper::for_each_line(str, len, pos.y, sd); } } @@ -594,8 +547,8 @@ namespace nana { if (graph_) { - helper::draw_string_omitted dso(graph_, pos.x, pos.x + static_cast(restricted_pixels), omitted); - helper::for_each_line(str, len, pos.y, dso); + helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast(restricted_pixels), text_align_, omitted }; + helper::for_each_line(str, len, pos.y, sd); } } From e5a935ab8372ac6f44d04b908e69e3b8613514dd Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 18 Jun 2019 08:23:54 +0800 Subject: [PATCH 45/61] fix bug that filebox single selection fails on Linux --- source/gui/filebox.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index b748b5cf..06dfed84 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -1062,6 +1062,8 @@ namespace nana { if(text.length() == start_pos) return files; + else if(0 == start_pos) //single selection + return {text}; return {}; } From 39c3f85627571e9d3420781787a576ce8e300ac1 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 19 Jun 2019 23:42:50 +0800 Subject: [PATCH 46/61] fix bug that click event is triggered by pressing space on disabled button --- source/gui/detail/bedrock_posix.cpp | 4 ++-- source/gui/detail/bedrock_windows.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 9b1160bf..699e7380 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -1019,7 +1019,7 @@ namespace detail else if((keyboard::space == os_code) && msgwnd->flags.space_click_enabled) { //Clicked by spacebar - if((nullptr == pressed_wd) && (nullptr == pressed_wd_space)) + if((nullptr == pressed_wd) && (nullptr == pressed_wd_space) && msgwnd->flags.enabled) { arg_mouse arg; arg.alt = modifiers_status.alt; @@ -1122,7 +1122,7 @@ namespace detail msgwnd = brock.focus(); if(msgwnd) { - if(msgwnd == pressed_wd_space) + if((msgwnd == pressed_wd_space) && msgwnd->flags.enabled) { msgwnd->set_action(mouse_action::normal); diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index d549bedc..a84d9e61 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -1386,7 +1386,7 @@ namespace detail else if ((VK_SPACE == wParam) && msgwnd->flags.space_click_enabled) { //Clicked by spacebar - if (nullptr == pressed_wd && nullptr == pressed_wd_space) + if ((nullptr == pressed_wd) && (nullptr == pressed_wd_space) && msgwnd->flags.enabled) { arg_mouse arg; arg.alt = false; @@ -1468,7 +1468,7 @@ namespace detail msgwnd = brock.focus(); if (msgwnd) { - if (msgwnd == pressed_wd_space) + if ((msgwnd == pressed_wd_space) && msgwnd->flags.enabled) { msgwnd->set_action(mouse_action::normal); From 8a0475c98cc418900ce98a78590df86122398145 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 20 Jun 2019 04:35:29 +0800 Subject: [PATCH 47/61] refactor text_renderer --- include/nana/gui/widgets/listbox.hpp | 3 +- include/nana/paint/text_renderer.hpp | 12 +- source/gui/place_parts.hpp | 2 +- source/gui/widgets/button.cpp | 6 +- source/gui/widgets/checkbox.cpp | 4 +- source/gui/widgets/listbox.cpp | 15 +- source/gui/widgets/menu.cpp | 2 +- source/gui/widgets/tabbar.cpp | 2 +- source/paint/text_renderer.cpp | 274 ++++++++++++++------------- 9 files changed, 170 insertions(+), 150 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 717d6d91..4827a227 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1219,7 +1219,6 @@ namespace nana unsigned min_column_width{ 20 }; ///< def=20 . non counting suspension_width - unsigned suspension_width{ 8 }; ///< def= . the trigger will set this to the width if ("...") unsigned text_margin{ 5 }; ///< def= 5. Additional or extended with added (before) to the text width to determine the cell width. cell_w = text_w + ext_w +1 unsigned item_height_ex{ 6 }; ///< Set !=0 !!!! def=6. item_height = text_height + item_height_ex @@ -1603,6 +1602,8 @@ the nana::detail::basic_window member pointer scheme * It returns true to deselect the selected items. It returns false to cancel to deselect the selected items. */ void set_deselect(std::function predicate); + + unsigned suspension_width() const; private: drawerbase::listbox::essence & _m_ess() const; nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const override; diff --git a/include/nana/paint/text_renderer.hpp b/include/nana/paint/text_renderer.hpp index 96fbbfdb..3510bb3d 100644 --- a/include/nana/paint/text_renderer.hpp +++ b/include/nana/paint/text_renderer.hpp @@ -10,14 +10,20 @@ namespace nana { public: using graph_reference = graphics &; + + enum class mode + { + truncate_with_ellipsis, + truncate_letter_with_ellipsis, + word_wrap + }; text_renderer(graph_reference graph, align = align::left); - nana::size extent_size(int x, int y, const wchar_t*, std::size_t len, unsigned restricted_pixels) const; + nana::size extent_size(int x, int y, const wchar_t*, std::size_t len, unsigned space_pixels) const; void render(const point&, const wchar_t*, std::size_t len); - void render(const point&, const wchar_t*, std::size_t len, unsigned restricted_pixels, bool omitted); - void render(const point&, const wchar_t*, std::size_t len, unsigned restricted_pixels); + void render(const point&, const wchar_t*, std::size_t len, unsigned space_pixels, mode); private: graph_reference graph_; align text_align_; diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 97295d60..74dda204 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -140,7 +140,7 @@ namespace nana //draw caption auto text = to_wstring(API::window_caption(window_handle_)); - text_rd_->render({ 3, 1 }, text.data(), text.size(), graph.size().width - 20, true); + text_rd_->render({ 3, 1 }, text.data(), text.size(), graph.size().width - 20, paint::text_renderer::mode::truncate_with_ellipsis); //draw x button auto r = _m_button_area(); diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 96ff7c25..ecc09817 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -261,7 +261,7 @@ namespace nana{ namespace drawerbase graph.palette(true, text_color); if (attr_.omitted) - tr.render(pos, txtptr, txtlen, omitted_pixels, true); + tr.render(pos, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis); else #ifdef _nana_std_has_string_view graph.bidi_string(pos, { txtptr, txtlen }); @@ -276,9 +276,9 @@ namespace nana{ namespace drawerbase graph.palette(true, color{ colors::white }); if(attr_.omitted) { - tr.render(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen, omitted_pixels, true); + tr.render(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis); graph.palette(true, color{ colors::gray }); - tr.render(pos, txtptr, txtlen, omitted_pixels, true); + tr.render(pos, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis); } else { diff --git a/source/gui/widgets/checkbox.cpp b/source/gui/widgets/checkbox.cpp index fc08fcac..4741d5b2 100644 --- a/source/gui/widgets/checkbox.cpp +++ b/source/gui/widgets/checkbox.cpp @@ -70,13 +70,13 @@ namespace nana{ namespace drawerbase if (!wdg->enabled()) { graph.palette(true, colors::white); - tr.render({ 17 + interval, 2 }, title.c_str(), title.length(), pixels); + tr.render({ 17 + interval, 2 }, title.c_str(), title.length(), pixels, paint::text_renderer::mode::word_wrap); graph.palette(true, static_cast(0x808080)); } else graph.palette(true, wdg->fgcolor()); - tr.render({ 16 + interval, 1 }, title.c_str(), title.length(), pixels); + tr.render({ 16 + interval, 1 }, title.c_str(), title.length(), pixels, paint::text_renderer::mode::word_wrap); } //draw crook diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 8ef8a453..494daa4c 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2059,6 +2059,11 @@ namespace nana }; } + unsigned suspension_width() const + { + return (graph ? graph->text_extent_size(L"...").width : 0); + } + bool cs_status(index_pair abs_pos, bool for_selection) const { if (abs_pos.is_category()) @@ -3352,7 +3357,7 @@ namespace nana else { //Default scheme - new_w = (std::max)(new_w, essence_->scheme_ptr->suspension_width + essence_->scheme_ptr->min_column_width); + new_w = (std::max)(new_w, essence_->suspension_width() + essence_->scheme_ptr->min_column_width); } if(col.width_px != new_w) @@ -3997,6 +4002,7 @@ namespace nana if (draw_column) { + //Draw item text paint::aligner text_aligner{*graph, col.alignment}; unsigned text_margin_right = 0; @@ -4142,7 +4148,6 @@ namespace nana if (graph.text_metrics(as, ds, il)) essence_->text_height = as + ds; - essence_->scheme_ptr->suspension_width = graph.text_extent_size("...").width; essence_->calc_content_size(true); } @@ -6114,6 +6119,12 @@ namespace nana _m_ess().pred_msup_deselect = std::move(predicate); } + unsigned listbox::suspension_width() const + { + nana::internal_scope_guard lock; + return _m_ess().suspension_width(); + } + drawerbase::listbox::essence & listbox::_m_ess() const { return get_drawer_trigger().ess(); diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index e3b181e4..389b39b9 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -147,7 +147,7 @@ namespace nana nana::paint::text_renderer tr(graph); auto wstr = to_wstring(text); - tr.render(pos, wstr.c_str(), wstr.length(), text_pixels, true); + tr.render(pos, wstr.c_str(), wstr.length(), text_pixels, paint::text_renderer::mode::truncate_with_ellipsis); } void sub_arrow(graph_reference graph, const nana::point& pos, unsigned pixels, const attr&) diff --git a/source/gui/widgets/tabbar.cpp b/source/gui/widgets/tabbar.cpp index 4cf17919..6a79c648 100644 --- a/source/gui/widgets/tabbar.cpp +++ b/source/gui/widgets/tabbar.cpp @@ -1050,7 +1050,7 @@ namespace nana std::wstring wtext = to_wstring(item.text); tr.render({ m.r.x + 24, m.r.y + static_cast(m.r.height - ts.height) / 2 }, - wtext.c_str(), wtext.length(), basis_.item_pixels - 24 - 18, true); + wtext.c_str(), wtext.length(), basis_.item_pixels - 24 - 18, paint::text_renderer::mode::truncate_with_ellipsis); } } diff --git a/source/paint/text_renderer.cpp b/source/paint/text_renderer.cpp index db5ecfc5..19b305a9 100644 --- a/source/paint/text_renderer.cpp +++ b/source/paint/text_renderer.cpp @@ -46,6 +46,7 @@ namespace nana } } + unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) { auto const drawable = graph_.handle(); @@ -66,7 +67,7 @@ namespace nana auto text_align = text_align_; // Checks if ellipsis is enabled and the total pixels of string is larger than the space. - if (ellipsis_px_ && (string_px > static_cast(right_ - left_))) + if (ellipsis_px_ && (static_cast(string_px) > right_ - left_)) { //The string should be drawn from left most point no matter what text align is. text_align = align::left; @@ -99,7 +100,7 @@ namespace nana dummy.bitblt(r, graph_, pos); #ifdef _nana_std_has_string_view - dummy.string({}, { ent.begin, ent.end - ent.begin }, graph_.palette(true)); + dummy.string({}, { ent.begin, static_cast(ent.end - ent.begin) }, graph_.palette(true)); #else dummy.palette(true, graph_.palette(true)); dummy.string({}, ent.begin, ent.end - ent.begin); @@ -151,46 +152,54 @@ namespace nana struct draw_string_auto_changing_lines { graphics & graph; - int x, endpos; - align text_align; + const int left, right; + const align text_align; - draw_string_auto_changing_lines(graphics& graph, int x, int endpos, align ta) - : graph(graph), x(x), endpos(endpos), text_align(ta) + draw_string_auto_changing_lines(graphics& graph, int left, int right, align ta): + graph(graph), + left(left), + right(right), + text_align(ta) {} unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) { - unsigned pixels = 0; + unsigned return_max_height = 0; - auto const dw = graph.handle(); - unsigned str_w = 0; + auto const drawable = graph.handle(); + unsigned string_px = 0; - std::vector ts_keeper; + std::vector word_metrics; auto const reordered = unicode_reorder(buf, bufsize); for(auto & i : reordered) { - nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); - if(ts.height > pixels) pixels = ts.height; - ts_keeper.emplace_back(ts); - str_w += ts.width; + auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin); + + word_metrics.emplace_back(word_sz); + string_px += word_sz.width; + + if (return_max_height < word_sz.height) + return_max_height = word_sz.height; } + const nana::size* wdm = word_metrics.data(); + //Test whether the text needs the new line. - if(x + static_cast(str_w) > endpos) + if(left + static_cast(string_px) > right) { - pixels = 0; - unsigned line_pixels = 0; - nana::point pos{ x, top }; - int orig_top = top; - auto i_ts_keeper = ts_keeper.cbegin(); + unsigned max_height = 0; + + nana::point pos{ left, top }; + const int orig_top = top; + for(auto & i : reordered) { - if(line_pixels < i_ts_keeper->height) - line_pixels = i_ts_keeper->height; + if(max_height < wdm->height) + max_height = wdm->height; - bool beyond_edge = (pos.x + static_cast(i_ts_keeper->width) > endpos); + bool beyond_edge = (pos.x + static_cast(wdm->width) > right); if(beyond_edge) { const std::size_t len = i.end - i.begin; @@ -210,10 +219,10 @@ namespace nana { auto pxbuf = pixel_buf.get(); - idx_splitted = find_splitted(idx_head, len, pos.x, endpos, pxbuf); + idx_splitted = find_splitted(idx_head, len, pos.x, right, pxbuf); if(idx_splitted == len) { - detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head); + detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head); for(std::size_t i = idx_head; i < len; ++i) pos.x += static_cast(pxbuf[i]); @@ -223,17 +232,16 @@ namespace nana //Check the word whether it is splittable. if(splittable(i.begin, idx_splitted)) { - detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head); + detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head); idx_head = idx_splitted; - pos.x = x; - pos.y += static_cast(line_pixels); - line_pixels = i_ts_keeper->height; + pos.x = left; + pos.y += static_cast(max_height); } else { //Search the splittable character from idx_head to idx_splitted const wchar_t * u = i.begin + idx_splitted; - const wchar_t * head = i.begin + idx_head; + const wchar_t * const head = i.begin + idx_head; for(; head < u; --u) { @@ -243,98 +251,94 @@ namespace nana if(u != head) { - detail::draw_string(dw, pos, head, u - head); + detail::draw_string(drawable, pos, head, u - head); idx_head += u - head; - pos.x = x; - pos.y += static_cast(line_pixels); - line_pixels = i_ts_keeper->height; + pos.x = left; + pos.y += static_cast(max_height); } else { u = i.begin + idx_splitted; - const wchar_t * end = i.begin + len; - for(; u < end; ++u) + for(; u < i.begin + len; ++u) { if(splittable(head, u - head)) break; } std::size_t splen = u - head; - pos.y += static_cast(line_pixels); - pos.x = x; - detail::draw_string(dw, pos, head, splen); - line_pixels = i_ts_keeper->height; + pos.y += static_cast(max_height); + pos.x = left; + detail::draw_string(drawable, pos, head, splen); for(std::size_t k = idx_head; k < idx_head + splen; ++k) pos.x += static_cast(pxbuf[k]); - if (pos.x >= endpos) + if (pos.x >= right) { - pos.x = x; - pos.y += static_cast(line_pixels); + pos.x = left; + pos.y += static_cast(wdm->height); } idx_head += splen; } } + max_height = wdm->height; }while(idx_head < len); } else { - pos.x = x; - pos.y += static_cast(line_pixels); - detail::draw_string(dw, pos, i.begin, 1); - pos.x += static_cast(i_ts_keeper->width); + pos.x = left; + pos.y += static_cast(max_height); + detail::draw_string(drawable, pos, i.begin, 1); + pos.x += static_cast(wdm->width); } - line_pixels = 0; + max_height = 0; } else { - detail::draw_string(dw, pos, i.begin, i.end - i.begin); - pos.x += static_cast(i_ts_keeper->width); + detail::draw_string(drawable, pos, i.begin, i.end - i.begin); + pos.x += static_cast(wdm->width); } - ++i_ts_keeper; + ++wdm; } - pixels = (top - orig_top) + line_pixels; + return_max_height = (top - orig_top) + max_height; } else { + point pos{ left, top }; //The text could be drawn in a line. if((align::left == text_align) || (align::center == text_align)) { - point pos{ x, top }; if(align::center == text_align) - pos.x += (endpos - x - static_cast(str_w)) / 2; - auto i_ts_keeper = ts_keeper.cbegin(); + pos.x += (right - left - static_cast(string_px)) / 2; + for(auto & ent : reordered) { - const nana::size & ts = *i_ts_keeper; + if (pos.x + static_cast(wdm->width) > 0) + detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); - if (pos.x + static_cast(ts.width) > 0) - detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin); - - pos.x += static_cast(ts.width); - ++i_ts_keeper; + pos.x += static_cast(wdm->width); + ++wdm; } } else if(align::right == text_align) { - point pos{ endpos, top }; - auto i_ts_keeper = ts_keeper.crbegin(); + pos.x = right; for(auto i = reordered.crbegin(); i != reordered.crend(); ++i) { + if (pos.x < 0) + break; + auto & ent = *i; std::size_t len = ent.end - ent.begin; - const nana::size & ts = *i_ts_keeper; - pos.x -= static_cast(ts.width); - if (pos.x >= 0) - detail::draw_string(dw, pos, ent.begin, len); - ++i_ts_keeper; + pos.x -= static_cast(wdm->width); + detail::draw_string(drawable, pos, ent.begin, len); + ++wdm; } } } - return pixels; + return return_max_height; } static std::size_t find_splitted(std::size_t begin, std::size_t end, int x, int endpos, unsigned * pxbuf) @@ -370,44 +374,53 @@ namespace nana struct extent_auto_changing_lines { graphics & graph; - int x, endpos; + const int left, right; + unsigned extents; - extent_auto_changing_lines(graphics& graph, int x, int endpos) - : graph(graph), x(x), endpos(endpos), extents(0) + extent_auto_changing_lines(graphics& graph, int left, int right): + graph(graph), + left(left), + right(right), + extents(0) {} unsigned operator()(int top, const wchar_t * buf, std::size_t bufsize) { - unsigned pixels = 0; + unsigned return_max_height = 0; - drawable_type dw = graph.handle(); - unsigned str_w = 0; - std::vector ts_keeper; + auto drawable = graph.handle(); + + std::vector word_metrics; + unsigned string_px = 0; auto const reordered = unicode_reorder(buf, bufsize); for(auto & i : reordered) { - nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); - ts_keeper.emplace_back(ts); - str_w += ts.width; + auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin); + word_metrics.emplace_back(word_sz); + string_px += word_sz.width; + + if (return_max_height < word_sz.height) + return_max_height = word_sz.height; } - auto i_ts_keeper = ts_keeper.cbegin(); //Test whether the text needs the new line. - if(x + static_cast(str_w) > endpos) + if(left + static_cast(string_px) > right) { - unsigned line_pixels = 0; - int xpos = x; - int orig_top = top; + unsigned max_height = 0; + int xpos = left; + const int orig_top = top; + + auto wdm = word_metrics.data(); for(auto & i : reordered) { - if(line_pixels < i_ts_keeper->height) - line_pixels = i_ts_keeper->height; + if(max_height < wdm->height) + max_height = wdm->height; - bool beyond_edge = (xpos + static_cast(i_ts_keeper->width) > endpos); + bool beyond_edge = (xpos + static_cast(wdm->width) > right); if(beyond_edge) { std::size_t len = i.end - i.begin; @@ -427,7 +440,7 @@ namespace nana do { - idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, endpos, pxbuf); + idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, right, pxbuf); if(idx_splitted == len) { @@ -440,9 +453,9 @@ namespace nana if(draw_string_auto_changing_lines::splittable(i.begin, idx_splitted)) { idx_head = idx_splitted; - xpos = x; - top += line_pixels; - line_pixels = i_ts_keeper->height; + xpos = left; + top += max_height; + max_height = wdm->height; } else { @@ -456,14 +469,11 @@ namespace nana break; } - if(u != head) - { - idx_head += u - head; - xpos = x; - top += line_pixels; - line_pixels = i_ts_keeper->height; - } - else + xpos = left; + top += max_height; + max_height = wdm->height; + + if(u == head) { u = i.begin + idx_splitted; const wchar_t * end = i.begin + len; @@ -473,52 +483,45 @@ namespace nana break; } std::size_t splen = u - head; - top += line_pixels; - xpos = x; - line_pixels = i_ts_keeper->height; for(std::size_t k = idx_head; k < idx_head + splen; ++k) xpos += static_cast(pxbuf[k]); - if(xpos >= endpos) + if(xpos >= right) { - xpos = x; - top += line_pixels; + xpos = left; + top += max_height; } idx_head += splen; } + else + idx_head += u - head; } }while(idx_head < len); } else - xpos = x + static_cast(i_ts_keeper->width); + xpos = left + static_cast(wdm->width); - line_pixels = 0; + max_height = 0; } else - xpos += static_cast(i_ts_keeper->width); + xpos += static_cast(wdm->width); - ++i_ts_keeper; + ++wdm; } - pixels = (top - orig_top) + line_pixels; + return_max_height = (top - orig_top) + max_height; } - else - { - while(i_ts_keeper != ts_keeper.cend()) - { - const nana::size & ts = *(i_ts_keeper++); - if(ts.height > pixels) pixels = ts.height; - } - } - extents += pixels; - return pixels; + + extents += return_max_height; + return return_max_height; } }; }//end namespace helper //class text_renderer - text_renderer::text_renderer(graph_reference graph, align ta) - : graph_(graph), text_align_(ta) + text_renderer::text_renderer(graph_reference graph, align ta): + graph_(graph), + text_align_(ta) {} nana::size text_renderer::extent_size(int x, int y, const wchar_t* str, std::size_t len, unsigned restricted_pixels) const @@ -538,26 +541,25 @@ namespace nana { if (graph_) { - helper::string_drawer sd{ graph_, pos.x, static_cast(graph_.width()), text_align_, false }; + helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast(graph_.width()), text_align_, false }; helper::for_each_line(str, len, pos.y, sd); } } - void text_renderer::render(const point& pos, const wchar_t* str, std::size_t len, unsigned restricted_pixels, bool omitted) + void text_renderer::render(const point& pos, const wchar_t* str, std::size_t len, unsigned space_pixels, mode rendering_mode) { - if (graph_) + if (graph_ && str && len && space_pixels) { - helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast(restricted_pixels), text_align_, omitted }; - helper::for_each_line(str, len, pos.y, sd); - } - } - - void text_renderer::render(const point& pos, const wchar_t * str, std::size_t len, unsigned restricted_pixels) - { - if (graph_) - { - helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast(restricted_pixels), text_align_); - helper::for_each_line(str, len, pos.y, dsacl); + if (mode::truncate_letter_with_ellipsis == rendering_mode || mode::truncate_with_ellipsis == rendering_mode) + { + helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast(space_pixels), text_align_, true }; + helper::for_each_line(str, len, pos.y, sd); + } + else if (mode::word_wrap == rendering_mode) + { + helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast(space_pixels), text_align_); + helper::for_each_line(str, len, pos.y, dsacl); + } } } //end class text_renderer From 975993ff33326f858de2e516cba358cf2ae80cc9 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 26 Jun 2019 05:05:05 +0800 Subject: [PATCH 48/61] refactor types(#450) --- include/nana/gui/basis.hpp | 18 +- include/nana/gui/detail/effects_renderer.hpp | 223 ------ include/nana/gui/detail/general_events.hpp | 18 +- source/gui/detail/basic_window.cpp | 2 +- .../gui/detail/basic_window.hpp | 10 +- source/gui/detail/bedrock_pi.cpp | 40 +- source/gui/detail/bedrock_posix.cpp | 48 +- source/gui/detail/bedrock_windows.cpp | 52 +- source/gui/detail/drawer.cpp | 196 +++++- source/gui/detail/effects_renderer.hpp | 52 ++ source/gui/detail/events_operation.cpp | 38 +- source/gui/detail/inner_fwd_implement.hpp | 2 +- source/gui/detail/window_layout.cpp | 4 +- source/gui/detail/window_manager.cpp | 37 +- source/gui/detail/window_register.hpp | 2 +- source/gui/dragdrop.cpp | 28 +- source/gui/drawing.cpp | 10 +- source/gui/programming_interface.cpp | 659 ++++++++---------- source/gui/state_cursor.cpp | 18 +- source/gui/wvl.cpp | 2 +- 20 files changed, 687 insertions(+), 772 deletions(-) delete mode 100644 include/nana/gui/detail/effects_renderer.hpp rename {include/nana => source}/gui/detail/basic_window.hpp (96%) create mode 100644 source/gui/detail/effects_renderer.hpp diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index b868a00a..e6ee771c 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -24,10 +24,11 @@ namespace nana { namespace detail { - struct native_window_handle_impl{}; - struct window_handle_impl{}; - struct event_handle_impl{}; - struct native_drawable_impl{}; + struct basic_window; + + struct native_window_handle_impl; + struct native_drawable_impl; + struct event_handle_impl; } struct accel_key @@ -87,10 +88,11 @@ namespace nana struct root_tag : public widget_tag{ static const flags value = flags::root; }; }// end namespace category - using native_window_type = detail::native_window_handle_impl*; - using window = detail::window_handle_impl*; ///< \see [What is window class ](https://sourceforge.net/p/nanapro/discussion/general/thread/bd0fabfb/) - using event_handle = detail::event_handle_impl*; - using native_drawable_type = detail::native_drawable_impl*; + using window = detail::basic_window*; ///< The window handle type representing nana window objects + using native_window_type = detail::native_window_handle_impl*; ///< The native window handle type representing system native windows. E.g, HWND in windows, Window in X11 + + using event_handle = detail::event_handle_impl*; ///< The event handle type representing nana window events + using native_drawable_type = detail::native_drawable_impl*; ///< The drawable handle type representing system native drawable objects. E.g. HDC in windows, Drawable in X11 struct keyboard diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp deleted file mode 100644 index 3a980caa..00000000 --- a/include/nana/gui/detail/effects_renderer.hpp +++ /dev/null @@ -1,223 +0,0 @@ -/* -* Effects Renderer -* Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) -* -* Distributed under the Boost Software License, Version 1.0. -* (See accompanying file LICENSE_1_0.txt or copy at -* http://www.boost.org/LICENSE_1_0.txt) -* -* @file: nana/gui/detail/effects_renderer.cpp -*/ - -#ifndef NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP -#define NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP -#include -#include -#include -#include -#include - -namespace nana{ - namespace detail - { - template - class edge_nimbus_renderer - { - edge_nimbus_renderer() = default; - public: - using core_window_t = CoreWindow; - using window_layer = ::nana::detail::window_layout; - using graph_reference = ::nana::paint::graphics&; - - static edge_nimbus_renderer& instance() - { - static edge_nimbus_renderer object; - return object; - } - - constexpr unsigned weight() const - { - return 2; - } - - void erase(core_window_t* wd) - { - if (effects::edge_nimbus::none == wd->effect.edge_nimbus) - return; - - core_window_t * root_wd = wd->root_widget; - auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; - - for (auto i = nimbus.begin(); i != nimbus.end(); ++i) - { - if (i->window == wd) - { - auto pixels = weight(); - rectangle r{wd->pos_root, wd->dimension}; - r.x -= static_cast(pixels); - r.y -= static_cast(pixels); - r.width += static_cast(pixels << 1); - r.height += static_cast(pixels << 1); - - root_wd->root_graph->paste(root_wd->root, r, r.x, r.y); - - nimbus.erase(i); - break; - } - } - } - - void render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr) - { - bool copy_separately = true; - std::vector> rd_set; - - if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size()) - { - auto root_wd = wd->root_widget; - - auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; - - auto focused = root_wd->other.attribute.root->focus; - - const unsigned pixels = weight(); - - auto graph = root_wd->root_graph; - - nana::rectangle r; - for(auto & action : nimbus) - { - if(_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r)) - { - if (action.window == wd) - { - if (update_area) - ::nana::overlap(*update_area, rectangle(r), r); - copy_separately = false; - } - - //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. - if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refreshed)) - { - rd_set.emplace_back(r, action.window); - action.rendered = true; - } - } - else if(action.rendered) - { - action.rendered = false; - - if (action.window == wd) - copy_separately = false; - - ::nana::rectangle erase_r( - action.window->pos_root.x - static_cast(pixels), - action.window->pos_root.y - static_cast(pixels), - static_cast(action.window->dimension.width + (pixels << 1)), - static_cast(action.window->dimension.height + (pixels << 1)) - ); - - graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y); - } - } - } - - if (copy_separately) - { - rectangle vr; - if (window_layer::read_visual_rectangle(wd, vr)) - { - if (update_area) - ::nana::overlap(*update_area, rectangle(vr), vr); - wd->root_graph->paste(wd->root, vr, vr.x, vr.y); - } - } - - rectangle wd_r{ wd->pos_root, wd->dimension }; - wd_r.pare_off(-static_cast(this->weight())); - //Render - for (auto & rd : rd_set) - { - auto other_wd = rd.second; - - if (other_wd != wd) - { - rectangle other_r{ other_wd->pos_root, other_wd->dimension }; - other_r.pare_off(-static_cast(this->weight())); - if (!overlapped(wd_r, other_r)) - continue; - } - _m_render_edge_nimbus(other_wd, rd.first); - } - } - private: - /// Determines whether the effect will be rendered for the given window. - static bool _m_edge_nimbus(core_window_t * const wd, core_window_t * const focused_wd) - { - // Don't render the effect if the window is disabled. - if (wd->flags.enabled) - { - if ((focused_wd == wd) && (static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::active))) - return true; - else if ((static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered)) - return true; - } - return false; - } - - void _m_render_edge_nimbus(core_window_t* wd, const nana::rectangle & visual) - { - wd->flags.action_before = wd->flags.action; - - auto r = visual; - r.pare_off(-static_cast(weight())); - rectangle good_r; - if (overlap(r, rectangle{ wd->root_graph->size() }, good_r)) - { - if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || - (good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom())) - { - auto graph = wd->root_graph; - nana::paint::pixel_buffer pixbuf(graph->handle(), r); - - pixel_argb_t px0, px1, px2, px3; - - px0 = pixbuf.pixel(0, 0); - px1 = pixbuf.pixel(r.width - 1, 0); - px2 = pixbuf.pixel(0, r.height - 1); - px3 = pixbuf.pixel(r.width - 1, r.height - 1); - - good_r.x = good_r.y = 1; - good_r.width = r.width - 2; - good_r.height = r.height - 2; - pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.95, false); - - good_r.x = good_r.y = 0; - good_r.width = r.width; - good_r.height = r.height; - pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.4, false); - - pixbuf.pixel(0, 0, px0); - pixbuf.pixel(r.width - 1, 0, px1); - pixbuf.pixel(0, r.height - 1, px2); - pixbuf.pixel(r.width - 1, r.height - 1, px3); - - pixbuf.paste(wd->root, { r.x, r.y }); - - std::vector overlaps; - if(window_layer::read_overlaps(wd, visual, overlaps)) - { - for(auto & wdr : overlaps) - graph->paste(wd->root, wdr.r, wdr.r.x, wdr.r.y); - } - } - else - wd->root_graph->paste(wd->root, visual, visual.x, visual.y); - } - } - }; - } -}//end namespace nana - -#endif diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 2171cb7a..f58f9680 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -24,9 +24,13 @@ namespace nana { + namespace API + { + bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. + } + namespace detail { - bool check_window(window); void events_operation_register(event_handle); class event_interface @@ -36,16 +40,16 @@ namespace nana virtual void remove(event_handle) = 0; }; - class docker_interface + class event_docker_interface { public: - virtual ~docker_interface() = default; + virtual ~event_docker_interface() = default; virtual event_interface* get_event() const = 0; }; struct docker_base - : public docker_interface + : public event_docker_interface { event_interface * const event_ptr; bool flag_deleted; @@ -78,11 +82,11 @@ namespace nana event_base * const evt_; }; - event_handle _m_emplace(detail::docker_interface*, bool in_front); + event_handle _m_emplace(detail::event_docker_interface*, bool in_front); protected: unsigned emitting_count_{ 0 }; bool deleted_flags_{ false }; - std::vector * dockers_{ nullptr }; + std::vector * dockers_{ nullptr }; }; }//end namespace detail @@ -228,7 +232,7 @@ namespace nana d->invoke(arg); - if (window_handle && (!detail::check_window(window_handle))) + if (window_handle && (!::nana::API::is_window(window_handle))) break; } } diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 661e3619..bb585f49 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -10,7 +10,7 @@ * @file: nana/gui/detail/basic_window.cpp */ -#include +#include "basic_window.hpp" #include namespace nana diff --git a/include/nana/gui/detail/basic_window.hpp b/source/gui/detail/basic_window.hpp similarity index 96% rename from include/nana/gui/detail/basic_window.hpp rename to source/gui/detail/basic_window.hpp index bc0a116f..3d53eab5 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/source/gui/detail/basic_window.hpp @@ -14,11 +14,11 @@ #ifndef NANA_GUI_DETAIL_BASIC_WINDOW_HPP #define NANA_GUI_DETAIL_BASIC_WINDOW_HPP #include -#include "drawer.hpp" -#include "events_holder.hpp" -#include "widget_geometrics.hpp" -#include "widget_content_measurer_interface.hpp" -#include "widget_notifier_interface.hpp" +#include +#include +#include +#include +#include #include #include #include diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index fdb1181b..a247a973 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -11,16 +11,17 @@ */ #include "../../detail/platform_spec_selector.hpp" +#include "basic_window.hpp" #include "bedrock_types.hpp" #include #include -#include #include #include -#include #include #include #include + +#include #include namespace nana @@ -64,11 +65,6 @@ namespace nana namespace detail { - bool check_window(window wd) - { - return bedrock::instance().wd_manager().available(reinterpret_cast(wd)); - } - void events_operation_register(event_handle evt) { bedrock::instance().evt_operation().register_evt(evt); @@ -171,7 +167,7 @@ namespace nana arg_expose arg; arg.exposed = exposed; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; if (emit(event_code::expose, wd, arg, false, get_thread_context())) { //Get the window who has the activated caret @@ -203,7 +199,7 @@ namespace nana if (wd) { arg_move arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.x = x; arg.y = y; emit(event_code::move, wd, arg, true, get_thread_context()); @@ -218,7 +214,7 @@ namespace nana arg_mouse arg; arg.evt_code = event_code::mouse_leave; - arg.window_handle = reinterpret_cast(hovered); + arg.window_handle = hovered; arg.pos.x = arg.pos.y = 0; arg.left_button = arg.right_button = arg.mid_button = false; arg.ctrl = arg.shift = false; @@ -234,7 +230,7 @@ namespace nana auto focused = root_wd->other.attribute.root->focus; arg_focus arg; - arg.window_handle = reinterpret_cast(focused); + arg.window_handle = focused; arg.getting = getting; arg.receiver = receiver; @@ -416,7 +412,7 @@ namespace nana wd->drawer.click(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->click.emit(*arg, reinterpret_cast(wd)); + evts_ptr->click.emit(*arg, wd); } } break; @@ -471,7 +467,7 @@ namespace nana } if (bProcess__External_event) - evt_addr->emit(*arg, reinterpret_cast(wd)); + evt_addr->emit(*arg, wd); break; } case event_code::mouse_wheel: @@ -486,7 +482,7 @@ namespace nana } if (bProcess__External_event) - evts_ptr->mouse_wheel.emit(*arg, reinterpret_cast(wd)); + evts_ptr->mouse_wheel.emit(*arg, wd); } break; } @@ -530,7 +526,7 @@ namespace nana } if (bProcess__External_event) - evt_addr->emit(*arg, reinterpret_cast(wd)); + evt_addr->emit(*arg, wd); break; } case event_code::expose: @@ -538,7 +534,7 @@ namespace nana { auto arg = dynamic_cast(&event_arg); if (arg) - evts_ptr->expose.emit(*arg, reinterpret_cast(wd)); + evts_ptr->expose.emit(*arg, wd); } break; case event_code::focus: @@ -552,7 +548,7 @@ namespace nana wd->drawer.focus(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->focus.emit(*arg, reinterpret_cast(wd)); + evts_ptr->focus.emit(*arg, wd); } break; } @@ -567,7 +563,7 @@ namespace nana wd->drawer.move(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->move.emit(*arg, reinterpret_cast(wd)); + evts_ptr->move.emit(*arg, wd); } break; } @@ -582,7 +578,7 @@ namespace nana wd->drawer.resizing(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->resizing.emit(*arg, reinterpret_cast(wd)); + evts_ptr->resizing.emit(*arg, wd); } break; } @@ -597,7 +593,7 @@ namespace nana wd->drawer.resized(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->resized.emit(*arg, reinterpret_cast(wd)); + evts_ptr->resized.emit(*arg, wd); } break; } @@ -609,7 +605,7 @@ namespace nana { auto evt_root = dynamic_cast(evts_ptr); if (evt_root) - evt_root->unload.emit(*arg, reinterpret_cast(wd)); + evt_root->unload.emit(*arg, wd); } } break; @@ -618,7 +614,7 @@ namespace nana { auto arg = dynamic_cast(&event_arg); if (arg) - evts_ptr->destroy.emit(*arg, reinterpret_cast(wd)); + evts_ptr->destroy.emit(*arg, wd); } break; default: diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 699e7380..69c49efa 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -143,7 +143,7 @@ namespace detail void bedrock::flush_surface(core_window_t* wd, bool forced, const rectangle* update_area) { - wd->drawer.map(reinterpret_cast(wd), forced, update_area); + wd->drawer.map(wd, forced, update_area); } //inc_window @@ -255,7 +255,7 @@ namespace detail void assign_arg(arg_mouse& arg, basic_window* wd, unsigned msg, const XEvent& evt) { - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.button = ::nana::mouse::any_button; int mask_state = 0; @@ -308,7 +308,7 @@ namespace detail void assign_arg(arg_focus& arg, basic_window* wd, native_window_type recv, bool getting) { - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.receiver = recv; arg.getting = getting; arg.focus_reason = arg_focus::reason::general; @@ -317,7 +317,7 @@ namespace detail void assign_arg(arg_wheel& arg, basic_window* wd, const XEvent& evt) { arg.evt_code = event_code::mouse_wheel; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; if (ButtonRelease == evt.type && (evt.xbutton.button == Button4 || evt.xbutton.button == Button5)) { arg.evt_code = event_code::mouse_wheel; @@ -371,12 +371,12 @@ namespace detail if(msgwd) { arg_dropfiles arg; - arg.window_handle = reinterpret_cast(msgwd); + arg.window_handle = msgwd; arg.files.swap(*msg.u.mouse_drop.files); delete msg.u.mouse_drop.files; arg.pos.x = msg.u.mouse_drop.x - msgwd->pos_root.x; arg.pos.y = msg.u.mouse_drop.y - msgwd->pos_root.y; - msgwd->annex.events_ptr->mouse_dropfiles.emit(arg, reinterpret_cast(msgwd)); + msgwd->annex.events_ptr->mouse_dropfiles.emit(arg, msgwd); brock.wd_manager().do_lazy_refresh(msgwd, false); } break; @@ -539,15 +539,15 @@ namespace detail auto shr_wd = wd_manager.find_shortkey(native_window, arg.key); if(shr_wd) { - arg.window_handle = reinterpret_cast(shr_wd); + arg.window_handle = 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)); + arg.window_handle = msgwd; + msgwd->annex.events_ptr->key_char.emit(arg, msgwd); if(arg.ignore == false && wd_manager.available(msgwd)) draw_invoker(&drawer::key_char, msgwd, arg, &context); } @@ -789,7 +789,7 @@ namespace detail { msgwnd->set_action(mouse_action::hovered); - click_arg.window_handle = reinterpret_cast(msgwnd); + click_arg.window_handle = msgwnd; draw_invoker(&drawer::click, msgwnd, click_arg, &context); } } @@ -807,16 +807,16 @@ namespace detail draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); if(click_arg.window_handle) - evt_ptr->click.emit(click_arg, reinterpret_cast(msgwnd)); + evt_ptr->click.emit(click_arg, msgwnd); if (wd_manager.available(msgwnd)) { arg.evt_code = event_code::mouse_up; - evt_ptr->mouse_up.emit(arg, reinterpret_cast(msgwnd)); + evt_ptr->mouse_up.emit(arg, msgwnd); } } else if(click_arg.window_handle) - msgwnd->annex.events_ptr->click.emit(click_arg, reinterpret_cast(msgwnd)); + msgwnd->annex.events_ptr->click.emit(click_arg, msgwnd); wd_manager.do_lazy_refresh(msgwnd, false); } @@ -940,7 +940,7 @@ namespace detail //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed. ::nana::rectangle update_area(xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height); if (!update_area.empty()) - msgwnd->drawer.map(reinterpret_cast(msgwnd), true, &update_area); + msgwnd->drawer.map(msgwnd, true, &update_area); } } break; @@ -1030,7 +1030,7 @@ namespace detail arg.mid_button = false; arg.pos.x = 0; arg.pos.y = 0; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; msgwnd->set_action(mouse_action::pressed); @@ -1052,7 +1052,7 @@ namespace detail bool focused = (brock.focus() == msgwnd); arg_keyboard arg; arg.evt_code = event_code::key_press; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = os_code; brock.get_key_state(arg); @@ -1074,7 +1074,7 @@ namespace detail arg.ignore = false; arg.key = os_code; arg.evt_code = event_code::key_press; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; brock.emit(event_code::key_press, msgwnd, arg, true, &context); @@ -1130,7 +1130,7 @@ namespace detail arg_click click_arg; click_arg.mouse_args = nullptr; - click_arg.window_handle = reinterpret_cast(msgwnd); + click_arg.window_handle = msgwnd; arg_mouse arg; arg.alt = false; @@ -1141,7 +1141,7 @@ namespace detail arg.mid_button = false; arg.pos.x = 0; arg.pos.y = 0; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); @@ -1155,7 +1155,7 @@ namespace detail arg_keyboard arg; arg.evt_code = event_code::key_release; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = os_code; brock.get_key_state(arg); @@ -1181,7 +1181,7 @@ namespace detail arg_keyboard arg; arg.evt_code = event_code::key_release; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = os_code; brock.get_key_state(arg); @@ -1208,7 +1208,7 @@ namespace detail if(msgwnd->flags.enabled && (atoms.wm_delete_window == static_cast(xclient.data.l[0]))) { arg_unload arg; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.cancel = false; brock.emit(event_code::unload, msgwnd, arg, true, &context); if(false == arg.cancel) @@ -1262,7 +1262,7 @@ namespace detail core_window_t * owner = 0; if(condition_wd && is_modal) { - native_window_type modal = reinterpret_cast(condition_wd)->root; + native_window_type modal = condition_wd->root; owner_native = native_interface::get_window(modal, window_relationship::owner); if(owner_native) { @@ -1273,7 +1273,7 @@ namespace detail } } - nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? reinterpret_cast(condition_wd)->root : 0); + nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? condition_wd->root : 0); if(owner_native) { diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index a84d9e61..3765571f 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -311,7 +311,7 @@ namespace detail } } else - wd->drawer.map(reinterpret_cast(wd), forced, update_area); + wd->drawer.map(wd, forced, update_area); } void interior_helper_for_menu(MSG& msg, native_window_type menu_window) @@ -367,7 +367,7 @@ namespace detail MSG msg; if (condition_wd) { - HWND native_handle = reinterpret_cast(reinterpret_cast(condition_wd)->root); + HWND native_handle = reinterpret_cast(condition_wd->root); if (is_modal) { HWND owner = ::GetWindow(native_handle, GW_OWNER); @@ -466,7 +466,7 @@ namespace detail void assign_arg(nana::arg_mouse& arg, basic_window* wd, unsigned msg, const parameter_decoder& pmdec) { - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; bool set_key_state = true; switch (msg) @@ -530,7 +530,7 @@ namespace detail void assign_arg(arg_wheel& arg, basic_window* wd, const parameter_decoder& pmdec) { - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.evt_code = event_code::mouse_wheel; POINT point = { pmdec.mouse.x, pmdec.mouse.y }; @@ -985,7 +985,7 @@ namespace detail msgwnd->set_action(mouse_action::hovered); if ((::nana::mouse::left_button == arg.button) && (pressed_wd == msgwnd)) { - click_arg.window_handle = reinterpret_cast(msgwnd); + click_arg.window_handle = msgwnd; draw_invoker(&drawer::click, msgwnd, click_arg, &context); } } @@ -997,16 +997,16 @@ namespace detail draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); if (click_arg.window_handle) - retain->click.emit(click_arg, reinterpret_cast(msgwnd)); + retain->click.emit(click_arg, msgwnd); if (wd_manager.available(msgwnd)) { arg.evt_code = event_code::mouse_up; - retain->mouse_up.emit(arg, reinterpret_cast(msgwnd)); + retain->mouse_up.emit(arg, msgwnd); } } else if (click_arg.window_handle) - retain->click.emit(click_arg, reinterpret_cast(msgwnd)); + retain->click.emit(click_arg, msgwnd); wd_manager.do_lazy_refresh(msgwnd, false); } @@ -1176,9 +1176,9 @@ namespace detail dropfiles.pos = pos; wd_manager.calc_window_point(msgwnd, dropfiles.pos); - dropfiles.window_handle = reinterpret_cast(msgwnd); + dropfiles.window_handle = msgwnd; - msgwnd->annex.events_ptr->mouse_dropfiles.emit(dropfiles, reinterpret_cast(msgwnd)); + msgwnd->annex.events_ptr->mouse_dropfiles.emit(dropfiles, msgwnd); wd_manager.do_lazy_refresh(msgwnd, false); } } @@ -1232,7 +1232,7 @@ namespace detail static_cast(r->bottom - r->top - msgwnd->extra_height)); arg_resizing arg; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.width = size_before.width; arg.height = size_before.height; @@ -1285,7 +1285,7 @@ namespace detail //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed. ::nana::rectangle update_area(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top); if (!update_area.empty()) - msgwnd->drawer.map(reinterpret_cast(msgwnd), true, &update_area); + msgwnd->drawer.map(msgwnd, true, &update_area); } ::EndPaint(root_window, &ps); } @@ -1300,7 +1300,7 @@ namespace detail arg.evt_code = event_code::shortkey; arg.key = static_cast(wParam < 0x61 ? wParam + 0x61 - 0x41 : wParam); arg.ctrl = arg.shift = false; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; brock.emit(event_code::shortkey, msgwnd, arg, true, &context); def_window_proc = false; @@ -1316,7 +1316,7 @@ namespace detail bool focused = (brock.focus() == msgwnd); arg_keyboard arg; arg.evt_code = event_code::key_press; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = static_cast(wParam); brock.get_key_state(arg); @@ -1344,7 +1344,7 @@ namespace detail arg_keyboard arg; arg.evt_code = event_code::key_release; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = static_cast(wParam); brock.get_key_state(arg); @@ -1397,7 +1397,7 @@ namespace detail arg.mid_button = false; arg.pos.x = 0; arg.pos.y = 0; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; msgwnd->set_action(mouse_action::pressed); @@ -1412,7 +1412,7 @@ namespace detail { arg_keyboard arg; arg.evt_code = event_code::key_press; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = translate_virtual_key(wParam); brock.get_key_state(arg); @@ -1443,12 +1443,12 @@ namespace detail { arg_keyboard arg; arg.evt_code = event_code::key_char; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.key = static_cast(wParam); brock.get_key_state(arg); arg.ignore = false; - msgwnd->annex.events_ptr->key_char.emit(arg, reinterpret_cast(msgwnd)); + msgwnd->annex.events_ptr->key_char.emit(arg, msgwnd); if ((false == arg.ignore) && wd_manager.available(msgwnd)) draw_invoker(&drawer::key_char, msgwnd, arg, &context); @@ -1476,7 +1476,7 @@ namespace detail arg_click click_arg; click_arg.mouse_args = nullptr; - click_arg.window_handle = reinterpret_cast(msgwnd); + click_arg.window_handle = msgwnd; arg_mouse arg; arg.alt = false; @@ -1487,7 +1487,7 @@ namespace detail arg.mid_button = false; arg.pos.x = 0; arg.pos.y = 0; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); @@ -1500,7 +1500,7 @@ namespace detail { arg_keyboard keyboard_arg; keyboard_arg.evt_code = event_code::key_release; - keyboard_arg.window_handle = reinterpret_cast(msgwnd); + keyboard_arg.window_handle = msgwnd; keyboard_arg.key = translate_virtual_key(wParam); brock.get_key_state(keyboard_arg); keyboard_arg.ignore = false; @@ -1521,7 +1521,7 @@ namespace detail case WM_CLOSE: { arg_unload arg; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.cancel = false; brock.emit(event_code::unload, msgwnd, arg, true, &context); if (!arg.cancel) @@ -1742,9 +1742,6 @@ namespace detail void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd) { - if (nullptr == thrd) - thrd = get_thread_context(wd->thread_id); - HCURSOR rev_handle = ::LoadCursor(nullptr, IDC_ARROW); if (!wd_manager().available(wd)) { @@ -1753,6 +1750,9 @@ namespace detail return; } + if (nullptr == thrd) + thrd = get_thread_context(wd->thread_id); + wd->root_widget->other.attribute.root->state_cursor = nana::cursor::arrow; wd->root_widget->other.attribute.root->state_cursor_window = nullptr; diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index da5b0091..379d53b6 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -10,11 +10,11 @@ * @file: nana/gui/detail/drawer.cpp */ +#include "basic_window.hpp" +#include "effects_renderer.hpp" #include #include #include -#include -#include #include "dynamic_drawing_object.hpp" #if defined(NANA_X11) @@ -23,8 +23,6 @@ namespace nana { - typedef detail::edge_nimbus_renderer edge_nimbus_renderer_t; - //class drawer_trigger void drawer_trigger::attached(widget_reference, graph_reference){} void drawer_trigger::detached(){} //none-const @@ -360,7 +358,7 @@ namespace nana #endif } - edge_nimbus_renderer_t::instance().render(iwd, forced, update_area); + edge_nimbus_renderer::instance().render(iwd, forced, update_area); if(owns_caret) { @@ -475,4 +473,192 @@ namespace nana return data_impl_->mth_state[pos]; } }//end namespace detail + + namespace detail + { + //class edge_nimbus_renderer + edge_nimbus_renderer& edge_nimbus_renderer::instance() + { + static edge_nimbus_renderer object; + return object; + } + + void edge_nimbus_renderer::erase(basic_window* wd) + { + if (effects::edge_nimbus::none == wd->effect.edge_nimbus) + return; + + auto root_wd = wd->root_widget; + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + for (auto i = nimbus.begin(); i != nimbus.end(); ++i) + { + if (i->window == wd) + { + auto pixels = weight(); + rectangle r{ wd->pos_root, wd->dimension }; + r.x -= static_cast(pixels); + r.y -= static_cast(pixels); + r.width += static_cast(pixels << 1); + r.height += static_cast(pixels << 1); + + root_wd->root_graph->paste(root_wd->root, r, r.x, r.y); + + nimbus.erase(i); + break; + } + } + } + + void edge_nimbus_renderer::render(basic_window* wd, bool forced, const rectangle* update_area) + { + bool copy_separately = true; + std::vector> rd_set; + + if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size()) + { + auto root_wd = wd->root_widget; + + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + auto focused = root_wd->other.attribute.root->focus; + + const unsigned pixels = weight(); + + auto graph = root_wd->root_graph; + + nana::rectangle r; + for (auto & action : nimbus) + { + if (_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r)) + { + if (action.window == wd) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(r), r); + copy_separately = false; + } + + //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. + if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == basic_window::update_state::refreshed)) + { + rd_set.emplace_back(r, action.window); + action.rendered = true; + } + } + else if (action.rendered) + { + action.rendered = false; + + if (action.window == wd) + copy_separately = false; + + ::nana::rectangle erase_r( + action.window->pos_root.x - static_cast(pixels), + action.window->pos_root.y - static_cast(pixels), + static_cast(action.window->dimension.width + (pixels << 1)), + static_cast(action.window->dimension.height + (pixels << 1)) + ); + + graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y); + } + } + } + + if (copy_separately) + { + rectangle vr; + if (window_layer::read_visual_rectangle(wd, vr)) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(vr), vr); + wd->root_graph->paste(wd->root, vr, vr.x, vr.y); + } + } + + rectangle wd_r{ wd->pos_root, wd->dimension }; + wd_r.pare_off(-static_cast(this->weight())); + //Render + for (auto & rd : rd_set) + { + auto other_wd = rd.second; + + if (other_wd != wd) + { + rectangle other_r{ other_wd->pos_root, other_wd->dimension }; + other_r.pare_off(-static_cast(this->weight())); + if (!overlapped(wd_r, other_r)) + continue; + } + _m_render_edge_nimbus(other_wd, rd.first); + } + } + + /// Determines whether the effect will be rendered for the given window. + bool edge_nimbus_renderer::_m_edge_nimbus(basic_window * const wd, basic_window * const focused_wd) + { + // Don't render the effect if the window is disabled. + if (wd->flags.enabled) + { + if ((focused_wd == wd) && (static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::active))) + return true; + else if ((static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered)) + return true; + } + return false; + } + + void edge_nimbus_renderer::_m_render_edge_nimbus(basic_window* wd, const nana::rectangle & visual) + { + wd->flags.action_before = wd->flags.action; + + auto r = visual; + r.pare_off(-static_cast(weight())); + rectangle good_r; + if (overlap(r, rectangle{ wd->root_graph->size() }, good_r)) + { + if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || + (good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom())) + { + auto graph = wd->root_graph; + nana::paint::pixel_buffer pixbuf(graph->handle(), r); + + pixel_argb_t px0, px1, px2, px3; + + px0 = pixbuf.pixel(0, 0); + px1 = pixbuf.pixel(r.width - 1, 0); + px2 = pixbuf.pixel(0, r.height - 1); + px3 = pixbuf.pixel(r.width - 1, r.height - 1); + + good_r.x = good_r.y = 1; + good_r.width = r.width - 2; + good_r.height = r.height - 2; + pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.95, false); + + good_r.x = good_r.y = 0; + good_r.width = r.width; + good_r.height = r.height; + pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.4, false); + + pixbuf.pixel(0, 0, px0); + pixbuf.pixel(r.width - 1, 0, px1); + pixbuf.pixel(0, r.height - 1, px2); + pixbuf.pixel(r.width - 1, r.height - 1, px3); + + pixbuf.paste(wd->root, { r.x, r.y }); + + std::vector overlaps; + if (window_layer::read_overlaps(wd, visual, overlaps)) + { + for (auto & wdr : overlaps) + graph->paste(wd->root, wdr.r, wdr.r.x, wdr.r.y); + } + } + else + wd->root_graph->paste(wd->root, visual, visual.x, visual.y); + } + } + + //end class edge_nimbus_renderer + }//end namespace detail }//end namespace nana diff --git a/source/gui/detail/effects_renderer.hpp b/source/gui/detail/effects_renderer.hpp new file mode 100644 index 00000000..99fbf49c --- /dev/null +++ b/source/gui/detail/effects_renderer.hpp @@ -0,0 +1,52 @@ +/* +* Effects Renderer +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/effects_renderer.cpp +*/ + +#ifndef NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP +#define NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP +#include "basic_window.hpp" +#include +#include +#include +#include +#include + +namespace nana{ + namespace detail + { + /// Effect edige nimbus renderer + class edge_nimbus_renderer + { + edge_nimbus_renderer() = default; + public: + using window_layer = ::nana::detail::window_layout; + using graph_reference = ::nana::paint::graphics&; + + static edge_nimbus_renderer& instance(); + + constexpr unsigned weight() const + { + return 2; + } + + void erase(basic_window* wd); + + void render(basic_window* wd, bool forced, const rectangle* update_area = nullptr); + private: + /// Determines whether the effect will be rendered for the given window. + static bool _m_edge_nimbus(basic_window * const wd, basic_window * const focused_wd); + + void _m_render_edge_nimbus(basic_window* wd, const nana::rectangle & visual); + }; + } +}//end namespace nana + +#endif diff --git a/source/gui/detail/events_operation.cpp b/source/gui/detail/events_operation.cpp index a278bc96..9c7c12dc 100644 --- a/source/gui/detail/events_operation.cpp +++ b/source/gui/detail/events_operation.cpp @@ -26,9 +26,7 @@ namespace nana auto i = handles_.find(evt); if (i != handles_.end()) - { - reinterpret_cast(evt)->get_event()->remove(evt); - } + reinterpret_cast(evt)->get_event()->remove(evt); } //end namespace events_operation @@ -80,35 +78,33 @@ namespace nana void event_base::remove(event_handle evt) { internal_scope_guard lock; - if (dockers_) + + for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) { - for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) + if (reinterpret_cast(evt) == *i) { - if (reinterpret_cast(evt) == *i) + //Checks whether this event is working now. + if (emitting_count_) { - //Checks whether this event is working now. - if (emitting_count_) - { - static_cast(*i)->flag_deleted = true; - deleted_flags_ = true; - } - else - { - bedrock::instance().evt_operation().cancel(evt); - dockers_->erase(i); - delete reinterpret_cast(evt); - } - break; + static_cast(*i)->flag_deleted = true; + deleted_flags_ = true; } + else + { + bedrock::instance().evt_operation().cancel(evt); + dockers_->erase(i); + delete reinterpret_cast(evt); + } + return; } } } - event_handle event_base::_m_emplace(detail::docker_interface* docker_ptr, bool in_front) + event_handle event_base::_m_emplace(detail::event_docker_interface* docker_ptr, bool in_front) { internal_scope_guard lock; if (nullptr == dockers_) - dockers_ = new std::vector; + dockers_ = new std::vector; auto evt = reinterpret_cast(docker_ptr); diff --git a/source/gui/detail/inner_fwd_implement.hpp b/source/gui/detail/inner_fwd_implement.hpp index 5c66323c..af246905 100644 --- a/source/gui/detail/inner_fwd_implement.hpp +++ b/source/gui/detail/inner_fwd_implement.hpp @@ -15,8 +15,8 @@ #define NANA_GUI_INNER_FWD_IMPLEMENT_HPP #include +#include "basic_window.hpp" #include -#include #include #include diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index b0187eec..db8b3bb8 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -11,8 +11,8 @@ * */ +#include "basic_window.hpp" #include -#include #include #include #include @@ -286,7 +286,7 @@ namespace nana } if (wd->effect.bground) - wd->effect.bground->take_effect(reinterpret_cast(wd), glass_buffer); + wd->effect.bground->take_effect(wd, glass_buffer); } void window_layout::_m_paste_children(core_window_t* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 9f854ee4..4464766d 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -18,7 +18,8 @@ #include #include #include -#include + +#include "effects_renderer.hpp" #include "window_register.hpp" #include "inner_fwd_implement.hpp" @@ -587,7 +588,7 @@ namespace detail { auto &brock = bedrock::instance(); arg_unload arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.cancel = false; brock.emit(event_code::unload, wd, arg, true, brock.get_thread_context()); if (false == arg.cancel) @@ -758,7 +759,7 @@ namespace detail auto &brock = bedrock::instance(); arg_move arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.x = x; arg.y = y; @@ -812,7 +813,7 @@ namespace detail wd->other.upd_state = basic_window::update_state::request_refresh; arg_move arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.x = r.x; arg.y = r.y; brock.emit(event_code::move, wd, arg, true, brock.get_thread_context()); @@ -846,7 +847,7 @@ namespace detail native_interface::move_window(wd->root, root_r); arg_resized arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.width = root_r.width; arg.height = root_r.height; brock.emit(event_code::resized, wd, arg, true, brock.get_thread_context()); @@ -875,7 +876,7 @@ namespace detail if (sz != wd->dimension) { arg_resizing arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.border = window_border::none; arg.width = sz.width; arg.height = sz.height; @@ -970,7 +971,7 @@ namespace detail } arg_resized arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.width = sz.width; arg.height = sz.height; brock.emit(event_code::resized, wd, arg, ask_update, brock.get_thread_context()); @@ -1177,7 +1178,7 @@ namespace detail prev_focus->annex.caret_ptr->activate(false); arg.getting = false; - arg.window_handle = reinterpret_cast(prev_focus); + arg.window_handle = prev_focus; arg.receiver = wd->root; arg.focus_reason = arg_focus::reason::general; brock.emit(event_code::focus, prev_focus, arg, true, brock.get_thread_context()); @@ -1194,7 +1195,7 @@ namespace detail if(wd->annex.caret_ptr) wd->annex.caret_ptr->activate(true); - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.getting = true; arg.receiver = wd->root; arg.focus_reason = reason; @@ -1444,7 +1445,7 @@ namespace detail if (impl_->wd_register.available(wd)) { //the root runtime must exist, because the wd is valid. Otherse, it's bug of library - return root_runtime(wd->root)->shortkeys.make(reinterpret_cast(wd), key); + return root_runtime(wd->root)->shortkeys.make(wd, key); } return false; } @@ -1458,7 +1459,7 @@ namespace detail auto root_rt = root_runtime(wd->root); if (root_rt) { - root_rt->shortkeys.umake(reinterpret_cast(wd)); + root_rt->shortkeys.umake(wd); if (with_children) { for (auto child : wd->children) @@ -1475,7 +1476,7 @@ namespace detail std::lock_guard lock(mutex_); auto object = root_runtime(native_window); if(object) - return reinterpret_cast(object->shortkeys.find(key)); + return object->shortkeys.find(key); } return nullptr; } @@ -1598,10 +1599,8 @@ namespace detail if (!established) { - using effect_renderer = detail::edge_nimbus_renderer; - //remove the window from edge nimbus effect when it is destroying - effect_renderer::instance().erase(wd); + edge_nimbus_renderer::instance().erase(wd); } else if (pa_root_attr != root_attr) { @@ -1705,13 +1704,11 @@ namespace detail wd->annex.caret_ptr = nullptr; } - using effect_renderer = detail::edge_nimbus_renderer; - //remove the window from edge nimbus effect when it is destroying - effect_renderer::instance().erase(wd); + edge_nimbus_renderer::instance().erase(wd); arg_destroy arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); //Delete the children widgets. @@ -1770,7 +1767,7 @@ namespace detail //The root_rt must exist, because wd is valid. Otherwise, it's a bug of the library. auto root_rt = root_runtime(wd->root); - auto pkeys = root_rt->shortkeys.keys(reinterpret_cast(wd)); + auto pkeys = root_rt->shortkeys.keys(wd); if (pkeys) { for (auto key : *pkeys) diff --git a/source/gui/detail/window_register.hpp b/source/gui/detail/window_register.hpp index 7a2500e4..965a1afa 100644 --- a/source/gui/detail/window_register.hpp +++ b/source/gui/detail/window_register.hpp @@ -1,7 +1,7 @@ #ifndef NANA_WINDOW_REGISTER_HEADER_INCLUDED #define NANA_WINDOW_REGISTER_HEADER_INCLUDED -#include +#include "basic_window.hpp" #include #include #include //std::find diff --git a/source/gui/dragdrop.cpp b/source/gui/dragdrop.cpp index 18f51e52..900d86c0 100644 --- a/source/gui/dragdrop.cpp +++ b/source/gui/dragdrop.cpp @@ -13,9 +13,9 @@ #include #include - #include -#include + +#include "detail/basic_window.hpp" #include #include @@ -961,8 +961,7 @@ namespace nana if (API::is_window(window_handle)) { dragging = true; - auto real_wd = reinterpret_cast(window_handle); - real_wd->other.dnd_state = dragdrop_status::not_ready; + window_handle->other.dnd_state = dragdrop_status::not_ready; } API::release_capture(window_handle); @@ -1000,9 +999,7 @@ namespace nana if (arg.is_left_button() && API::is_window(impl_->window_handle)) { impl_->dragging = ((!impl_->predicate) || impl_->predicate()); - - auto real_wd = reinterpret_cast(impl_->window_handle); - real_wd->other.dnd_state = dragdrop_status::ready; + impl_->window_handle->other.dnd_state = dragdrop_status::ready; } }); @@ -1010,14 +1007,13 @@ namespace nana if (!(arg.is_left_button() && impl_->dragging && API::is_window(arg.window_handle))) return; - auto real_wd = reinterpret_cast(arg.window_handle); - real_wd->other.dnd_state = dragdrop_status::in_progress; + arg.window_handle->other.dnd_state = dragdrop_status::in_progress; std::unique_ptr dropdata{new dragdrop_service::dropdata_type}; auto has_dropped = dragdrop_service::instance().dragdrop(arg.window_handle, dropdata.get(), nullptr); - real_wd->other.dnd_state = dragdrop_status::not_ready; + arg.window_handle->other.dnd_state = dragdrop_status::not_ready; impl_->dragging = false; if (has_dropped) @@ -1116,9 +1112,7 @@ namespace nana if (arg.is_left_button() && API::is_window(impl_->source_handle)) { impl_->dragging = ((!impl_->predicate) || impl_->predicate()); - - auto real_wd = reinterpret_cast(impl_->source_handle); - real_wd->other.dnd_state = dragdrop_status::ready; + impl_->source_handle->other.dnd_state = dragdrop_status::ready; } }); @@ -1126,13 +1120,9 @@ namespace nana if (!(arg.is_left_button() && impl_->dragging && API::is_window(arg.window_handle))) return; - auto real_wd = reinterpret_cast(arg.window_handle); - real_wd->other.dnd_state = dragdrop_status::in_progress; - + arg.window_handle->other.dnd_state = dragdrop_status::in_progress; impl_->make_drop(); - - - real_wd->other.dnd_state = dragdrop_status::not_ready; + arg.window_handle->other.dnd_state = dragdrop_status::not_ready; impl_->dragging = false; }); } diff --git a/source/gui/drawing.cpp b/source/gui/drawing.cpp index 2e6e2142..9b1fb7e6 100644 --- a/source/gui/drawing.cpp +++ b/source/gui/drawing.cpp @@ -10,9 +10,9 @@ * @file: nana/gui/drawing.cpp */ +#include "detail/basic_window.hpp" #include #include -#include namespace nana { @@ -22,11 +22,9 @@ namespace nana { namespace { - using core_window_t = detail::basic_window; - inline detail::drawer& get_drawer(window wd) { - return reinterpret_cast(wd)->drawer; + return wd->drawer; } } } @@ -38,7 +36,7 @@ namespace nana if (!API::is_window(wd)) throw std::invalid_argument("drawing: invalid window parameter"); - if (reinterpret_cast(wd)->is_draw_through()) + if (wd->is_draw_through()) throw std::invalid_argument("drawing: the window is draw_through enabled"); } @@ -46,7 +44,7 @@ namespace nana bool drawing::empty() const { - return API::empty_window(handle_) || reinterpret_cast(handle_)->root_graph->empty(); + return API::empty_window(handle_) || handle_->root_graph->empty(); } void drawing::update() const diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 28b61836..2610e17e 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -11,9 +11,9 @@ * @author: Jinhao */ +#include "detail/basic_window.hpp" #include #include -#include #include #include #include @@ -81,104 +81,100 @@ namespace API bool emit_event(event_code evt_code, window wd, const ::nana::event_arg& arg) { - return restrict::bedrock.emit(evt_code, reinterpret_cast<::nana::detail::basic_window*>(wd), arg, true, restrict::bedrock.get_thread_context(), false); + return restrict::bedrock.emit(evt_code, wd, arg, true, restrict::bedrock.get_thread_context(), false); } bool emit_internal_event(event_code evt_code, window wd, const ::nana::event_arg& arg) { - return restrict::bedrock.emit(evt_code, reinterpret_cast<::nana::detail::basic_window*>(wd), arg, true, restrict::bedrock.get_thread_context(), true); + return restrict::bedrock.emit(evt_code, wd, arg, true, restrict::bedrock.get_thread_context(), true); } void enum_widgets_function_base::enum_widgets(window wd, bool recursive) { - auto iwd = reinterpret_cast(wd); - internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - //Use a copy, because enum function may close a child window and the original children container would be changed, - //in the situation, the walking thorugh directly to the iwd->children would cause error. - auto children = iwd->children; + //Use a copy, because enumerating function may close a child window and the original children container would be changed, + //in the situation, the walking thorugh directly to the wd->children would cause error. + auto children = wd->children; for (auto child : children) { - auto widget_ptr = API::get_widget(reinterpret_cast(child)); + auto widget_ptr = API::get_widget(child); if (!widget_ptr) continue; _m_enum_fn(widget_ptr); if (recursive) - enum_widgets(reinterpret_cast(child), recursive); + enum_widgets(child, recursive); } } } general_events* get_general_events(window wd) { - if (!restrict::wd_manager().available(reinterpret_cast(wd))) + if (empty_window(wd)) return nullptr; - return reinterpret_cast(wd)->annex.events_ptr.get(); + return wd->annex.events_ptr.get(); } }//end namespace detail void effects_edge_nimbus(window wd, effects::edge_nimbus en) { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) + internal_scope_guard lock; + if(is_window(wd)) { - auto & cont = iwd->root_widget->other.attribute.root->effects_edge_nimbus; + auto & cont = wd->root_widget->other.attribute.root->effects_edge_nimbus; if(effects::edge_nimbus::none != en) { - if (iwd->effect.edge_nimbus == effects::edge_nimbus::none) + if (wd->effect.edge_nimbus == effects::edge_nimbus::none) { - cont.emplace_back(basic_window::edge_nimbus_action{ iwd, false}); + cont.emplace_back(basic_window::edge_nimbus_action{ wd, false}); } - iwd->effect.edge_nimbus = static_cast(static_cast(en) | static_cast(iwd->effect.edge_nimbus)); + wd->effect.edge_nimbus = static_cast(static_cast(en) | static_cast(wd->effect.edge_nimbus)); } else { - if(effects::edge_nimbus::none != iwd->effect.edge_nimbus) + if(effects::edge_nimbus::none != wd->effect.edge_nimbus) { for(auto i = cont.begin(); i != cont.end(); ++i) - if(i->window == iwd) + if(i->window == wd) { cont.erase(i); break; } } - iwd->effect.edge_nimbus = effects::edge_nimbus::none; + wd->effect.edge_nimbus = effects::edge_nimbus::none; } } } effects::edge_nimbus effects_edge_nimbus(window wd) { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - return (restrict::wd_manager().available(iwd) ? iwd->effect.edge_nimbus : effects::edge_nimbus::none); + internal_scope_guard lock; + return (is_window(wd) ? wd->effect.edge_nimbus : effects::edge_nimbus::none); } void effects_bground(window wd, const effects::bground_factory_interface& factory, double fade_rate) { if (fade_rate < 0.0 || fade_rate > 1.0) throw std::invalid_argument("effects_bground: value range of fade_rate must be [0, 1]."); - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) + + internal_scope_guard lock; + if(is_window(wd)) { auto new_effect_ptr = effects::effects_accessor::create(factory); if(nullptr == new_effect_ptr) return; - delete iwd->effect.bground; - iwd->effect.bground = new_effect_ptr; - iwd->effect.bground_fade_rate = fade_rate; - restrict::wd_manager().enable_effects_bground(iwd, true); + delete wd->effect.bground; + wd->effect.bground = new_effect_ptr; + wd->effect.bground_fade_rate = fade_rate; + restrict::wd_manager().enable_effects_bground(wd, true); if (fade_rate < 0.01) - iwd->flags.make_bground_declared = true; + wd->flags.make_bground_declared = true; API::refresh_window(wd); } @@ -192,21 +188,19 @@ namespace API bground_mode effects_bground_mode(window wd) { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd) && iwd->effect.bground) - return (iwd->effect.bground_fade_rate <= 0.009 ? bground_mode::basic : bground_mode::blend); + internal_scope_guard lock; + if(is_window(wd) && wd->effect.bground) + return (wd->effect.bground_fade_rate <= 0.009 ? bground_mode::basic : bground_mode::blend); return bground_mode::none; } void effects_bground_remove(window wd) { - const auto iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) + internal_scope_guard lock; + if(is_window(wd)) { - if(restrict::wd_manager().enable_effects_bground(iwd, false)) + if(restrict::wd_manager().enable_effects_bground(wd, false)) API::refresh_window(wd); } } @@ -221,99 +215,92 @@ namespace API bool set_events(window wd, const std::shared_ptr& gep) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->set_events(gep); + if (is_window(wd)) + return wd->set_events(gep); return false; } void set_scheme(window wd, widget_geometrics* wdg_geom) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->annex.scheme = wdg_geom; + if (is_window(wd)) + wd->annex.scheme = wdg_geom; } widget_geometrics* get_scheme(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - return (restrict::wd_manager().available(iwd) ? iwd->annex.scheme : nullptr); + return (is_window(wd) ? wd->annex.scheme : nullptr); } void set_measurer(window wd, ::nana::dev::widget_content_measurer_interface* measurer) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->annex.content_measurer = measurer; + if (is_window(wd)) + wd->annex.content_measurer = measurer; } - void attach_drawer(widget& wd, drawer_trigger& dr) + void attach_drawer(widget& wdg, drawer_trigger& dr) { - const auto iwd = reinterpret_cast(wd.handle()); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) + const auto wd = wdg.handle(); + internal_scope_guard lock; + if(is_window(wd)) { - iwd->drawer.graphics.make(iwd->dimension); - iwd->drawer.graphics.rectangle(true, iwd->annex.scheme->background.get_color()); - iwd->drawer.attached(wd, dr); - iwd->drawer.refresh(); //Always redraw no matter it is visible or invisible. This can make the graphics data correctly. + wd->drawer.graphics.make(wd->dimension); + wd->drawer.graphics.rectangle(true, wd->annex.scheme->background.get_color()); + wd->drawer.attached(wdg, dr); + wd->drawer.refresh(); //Always redraw no matter it is visible or invisible. This can make the graphics data correctly. } } ::nana::detail::native_string_type window_caption(window wd) noexcept { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - - if(restrict::wd_manager().available(iwd)) + internal_scope_guard lock; + if(is_window(wd)) { - if (category::flags::root == iwd->other.category) - return interface_type::window_caption(iwd->root); - return iwd->title; + if (category::flags::root == wd->other.category) + return interface_type::window_caption(wd->root); + return wd->title; } return {}; } void window_caption(window wd, ::nana::detail::native_string_type title) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - iwd->title.swap(title); - if (iwd->other.category == category::flags::root) - interface_type::window_caption(iwd->root, iwd->title); + wd->title.swap(title); + if (wd->other.category == category::flags::root) + interface_type::window_caption(wd->root, wd->title); - restrict::wd_manager().update(iwd, true, false); + refresh_window(wd); } } window create_window(window owner, bool nested, const rectangle& r, const appearance& ap, widget* wdg) { - return reinterpret_cast(restrict::wd_manager().create_root(reinterpret_cast(owner), nested, r, ap, wdg)); + return restrict::wd_manager().create_root(owner, nested, r, ap, wdg); } window create_widget(window parent, const rectangle& r, widget* wdg) { - return reinterpret_cast(restrict::wd_manager().create_widget(reinterpret_cast(parent), r, false, wdg)); + return restrict::wd_manager().create_widget(parent, r, false, wdg); } window create_lite_widget(window parent, const rectangle& r, widget* wdg) { - return reinterpret_cast(restrict::wd_manager().create_widget(reinterpret_cast(parent), r, true, wdg)); + return restrict::wd_manager().create_widget(parent, r, true, wdg); } paint::graphics* window_graphics(window wd) { - internal_scope_guard isg; - if(restrict::wd_manager().available(reinterpret_cast(wd))) - return &reinterpret_cast(wd)->drawer.graphics; + internal_scope_guard lock; + if(is_window(wd)) + return &(wd->drawer.graphics); return nullptr; } @@ -325,25 +312,24 @@ namespace API void register_menu_window(window wd, bool has_keyboard) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - restrict::bedrock.set_menu(reinterpret_cast(wd)->root, has_keyboard); + if (is_window(wd)) + restrict::bedrock.set_menu(wd->root, has_keyboard); } void set_menubar(window wd, bool attach) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto root_attr = iwd->root_widget->other.attribute.root; + auto root_attr = wd->root_widget->other.attribute.root; if (attach) { if (!root_attr->menubar) - root_attr->menubar = iwd; + root_attr->menubar = wd; } else { - if (iwd == root_attr->menubar) + if (wd == root_attr->menubar) root_attr->menubar = nullptr; } } @@ -351,35 +337,30 @@ namespace API void enable_space_click(window wd, bool enable) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->flags.space_click_enabled = enable; + if (is_window(wd)) + wd->flags.space_click_enabled = enable; } bool copy_transparent_background(window wd, paint::graphics& graph) { - auto & buf = reinterpret_cast(wd)->other.glass_buffer; internal_scope_guard lock; if (bground_mode::basic != API::effects_bground_mode(wd)) return false; - buf.paste(rectangle{ buf.size() }, graph, 0, 0); - + wd->other.glass_buffer.paste(rectangle{ wd->other.glass_buffer.size() }, graph, 0, 0); return true; } bool copy_transparent_background(window wd, const rectangle& src_r, paint::graphics& graph, const point& dst_pt) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; if (bground_mode::basic != API::effects_bground_mode(wd)) return false; - iwd->other.glass_buffer.paste(src_r, graph, dst_pt.x, dst_pt.y); - + wd->other.glass_buffer.paste(src_r, graph, dst_pt.x, dst_pt.y); return true; } @@ -413,18 +394,16 @@ namespace API void window_draggable(window wd, bool enabled) { - auto real_wd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(real_wd)) - real_wd->flags.draggable = enabled; + if (is_window(wd)) + wd->flags.draggable = enabled; } bool window_draggable(window wd) { - auto real_wd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(real_wd)) - return real_wd->flags.draggable; + if (is_window(wd)) + return wd->flags.draggable; return false; } @@ -435,8 +414,8 @@ namespace API widget* get_widget(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->widget_notifier->widget_ptr(); + if (is_window(wd)) + return wd->widget_notifier->widget_ptr(); return nullptr; } @@ -495,15 +474,15 @@ namespace API bool register_shortkey(window wd, unsigned long key) { - return restrict::wd_manager().register_shortkey(reinterpret_cast(wd), key); + return restrict::wd_manager().register_shortkey(wd, key); } void unregister_shortkey(window wd) { - restrict::wd_manager().unregister_shortkey(reinterpret_cast(wd), false); + restrict::wd_manager().unregister_shortkey(wd, false); } - ::nana::point cursor_position() + ::nana::point cursor_position() { return interface_type::cursor_position(); } @@ -536,37 +515,35 @@ namespace API void window_icon(window wd, const paint::image& small_icon, const paint::image& big_icon) { if(nullptr != wd) - restrict::wd_manager().icon(reinterpret_cast(wd), small_icon, big_icon); + restrict::wd_manager().icon(wd, small_icon, big_icon); } bool empty_window(window wd) { - return (restrict::wd_manager().available(reinterpret_cast(wd)) == false); + return (restrict::wd_manager().available(wd) == false); } bool is_window(window wd) { - return restrict::wd_manager().available(reinterpret_cast(wd)); + return restrict::wd_manager().available(wd); } bool is_destroying(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (!restrict::wd_manager().available(wd)) return false; - return iwd->flags.destroying; + return wd->flags.destroying; } void enable_dropfiles(window wd, bool enb) { internal_scope_guard lock; - auto iwd = reinterpret_cast(wd); auto native_handle = API::root(wd); if (native_handle) { - iwd->flags.dropable = enb; + wd->flags.dropable = enb; interface_type::enable_dropfiles(native_handle, enb); } } @@ -580,88 +557,83 @@ namespace API { internal_scope_guard lock; if(is_window(wd)) - return reinterpret_cast(wd)->root; + return wd->root; return nullptr; } window root(native_window_type wd) { - return reinterpret_cast(restrict::wd_manager().root(wd)); + return restrict::wd_manager().root(wd); } void enable_double_click(window wd, bool dbl) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - iwd->flags.dbl_click = dbl; + if(is_window(wd)) + wd->flags.dbl_click = dbl; } void fullscreen(window wd, bool v) { internal_scope_guard lock; - if(restrict::wd_manager().available(reinterpret_cast(wd))) - reinterpret_cast(wd)->flags.fullscreen = v; + if(is_window(wd)) + wd->flags.fullscreen = v; } void close_window(window wd) { - restrict::wd_manager().close(reinterpret_cast(wd)); + restrict::wd_manager().close(wd); } void show_window(window wd, bool show) { - restrict::wd_manager().show(reinterpret_cast(wd), show); + restrict::wd_manager().show(wd, show); } bool visible(window wd) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - if(iwd->other.category == category::flags::root) - return interface_type::is_window_visible(iwd->root); - return iwd->visible; + if(wd->other.category == category::flags::root) + return interface_type::is_window_visible(wd->root); + return wd->visible; } return false; } void restore_window(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - if(iwd->other.category == category::flags::root) - interface_type::restore_window(iwd->root); + if(wd->other.category == category::flags::root) + interface_type::restore_window(wd->root); } } void zoom_window(window wd, bool ask_for_max) { - auto core_wd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(core_wd)) + if(is_window(wd)) { - if(category::flags::root == core_wd->other.category) - interface_type::zoom_window(core_wd->root, ask_for_max); + if(category::flags::root == wd->other.category) + interface_type::zoom_window(wd->root, ask_for_max); } } window get_parent_window(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if (category::flags::root == iwd->other.category) + if (category::flags::root == wd->other.category) { - return reinterpret_cast(restrict::wd_manager().root( - interface_type::get_window(iwd->root, window_relationship::parent) - )); + return restrict::wd_manager().root( + interface_type::get_window(wd->root, window_relationship::parent) + ); } - return reinterpret_cast(iwd->parent); + return wd->parent; } return nullptr; @@ -669,13 +641,12 @@ namespace API window get_owner_window(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd) && (iwd->other.category == category::flags::root)) + if(is_window(wd) && (wd->other.category == category::flags::root)) { - auto owner = interface_type::get_window(iwd->root, window_relationship::owner); + auto owner = interface_type::get_window(wd->root, window_relationship::owner); if(owner) - return reinterpret_cast(restrict::wd_manager().root(owner)); + return restrict::wd_manager().root(owner); } return nullptr; @@ -683,7 +654,7 @@ namespace API bool set_parent_window(window wd, window new_parent) { - return restrict::wd_manager().set_parent(reinterpret_cast(wd), reinterpret_cast(new_parent)); + return restrict::wd_manager().set_parent(wd, new_parent); } void umake_event(event_handle eh) @@ -693,32 +664,30 @@ namespace API nana::point window_position(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - return ( (iwd->other.category == category::flags::root) ? - interface_type::window_position(iwd->root) : iwd->pos_owner); + return ( (wd->other.category == category::flags::root) ? + interface_type::window_position(wd->root) : wd->pos_owner); } return nana::point{}; } void move_window(window wd, const point& pos) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().move(iwd, pos.x, pos.y, false)) + if(restrict::wd_manager().move(wd, pos.x, pos.y, false)) { basic_window* update_wd = nullptr; - if (iwd->displayed() && iwd->effect.bground) + if (wd->displayed() && wd->effect.bground) { - update_wd = iwd; - restrict::wd_manager().update(iwd, true, false); + update_wd = wd; + refresh_window(wd); } - basic_window* anc = iwd; - if (category::flags::root != iwd->other.category) - anc = iwd->seek_non_lite_widget_ancestor(); + basic_window* anc = wd; + if (category::flags::root != wd->other.category) + anc = wd->seek_non_lite_widget_ancestor(); if (anc != update_wd) restrict::wd_manager().update(anc, false, false); @@ -727,14 +696,13 @@ namespace API void move_window(window wd, const rectangle& r) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().move(iwd, r)) + if(restrict::wd_manager().move(wd, r)) { - if (category::flags::root != iwd->other.category) - iwd = iwd->seek_non_lite_widget_ancestor(); + if (category::flags::root != wd->other.category) + wd = wd->seek_non_lite_widget_ancestor(); - restrict::wd_manager().update(iwd, false, false); + restrict::wd_manager().update(wd, false, false); } } @@ -745,23 +713,21 @@ namespace API bool set_window_z_order(window wd, window wd_after, z_order_action action_if_no_wd_after) { - auto iwd = reinterpret_cast(wd); native_window_type native_after = nullptr; internal_scope_guard lock; - if (restrict::wd_manager().available(iwd) && (category::flags::root == iwd->other.category)) + if (is_window(wd) && (category::flags::root == wd->other.category)) { if(wd_after) { - auto iwd_after = reinterpret_cast(wd_after); - if (restrict::wd_manager().available(iwd_after) && (iwd_after->other.category == category::flags::root)) + if (is_window(wd_after) && (wd_after->other.category == category::flags::root)) { - native_after = iwd_after->root; + native_after = wd_after->root; action_if_no_wd_after = z_order_action::none; } else return false; } - interface_type::set_window_z_order(iwd->root, native_after, action_if_no_wd_after); + interface_type::set_window_z_order(wd->root, native_after, action_if_no_wd_after); return true; } return false; @@ -769,23 +735,21 @@ namespace API void draw_through(window wd, std::function draw_fn) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (empty_window(wd)) throw std::invalid_argument("draw_through: invalid window parameter"); - if (::nana::category::flags::root != iwd->other.category) + if (::nana::category::flags::root != wd->other.category) throw std::invalid_argument("draw_through: the window is not a root widget"); - iwd->other.attribute.root->draw_through.swap(draw_fn); + wd->other.attribute.root->draw_through.swap(draw_fn); } void map_through_widgets(window wd, native_drawable_type drawable) { - auto iwd = reinterpret_cast<::nana::detail::basic_window*>(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd) && iwd->is_draw_through() ) - restrict::bedrock.map_through_widgets(iwd, drawable); + if (is_window(wd) && wd->is_draw_through() ) + restrict::bedrock.map_through_widgets(wd, drawable); } nana::size window_size(window wd) @@ -797,29 +761,27 @@ namespace API void window_size(window wd, const size& sz) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().size(iwd, sz, false, false)) + if(restrict::wd_manager().size(wd, sz, false, false)) { - if (category::flags::root != iwd->other.category) - iwd = iwd->seek_non_lite_widget_ancestor(); + if (category::flags::root != wd->other.category) + wd = wd->seek_non_lite_widget_ancestor(); - restrict::wd_manager().update(iwd, false, false); + restrict::wd_manager().update(wd, false, false); } } ::nana::size window_outline_size(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (empty_window(wd)) return{}; auto sz = window_size(wd); - if(category::flags::root == iwd->other.category) + if(category::flags::root == wd->other.category) { - auto fm_extents = interface_type::window_frame_extents(iwd->root); + auto fm_extents = interface_type::window_frame_extents(wd->root); sz.width += fm_extents.left + fm_extents.right; sz.height += fm_extents.top + fm_extents.bottom; } @@ -829,13 +791,12 @@ namespace API void window_outline_size(window wd, const size& sz) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if (category::flags::root == iwd->other.category) + if (category::flags::root == wd->other.category) { - auto fm_extents = interface_type::window_frame_extents(iwd->root); + auto fm_extents = interface_type::window_frame_extents(wd->root); size inner_size = sz; @@ -858,20 +819,18 @@ namespace API std::optional window_rectangle(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - return rectangle(iwd->pos_owner, iwd->dimension); + if (is_window(wd)) + return rectangle(wd->pos_owner, wd->dimension); return{}; } bool get_window_rectangle(window wd, rectangle& r) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - r = rectangle(iwd->pos_owner, iwd->dimension); + r = rectangle(wd->pos_owner, wd->dimension); return true; } return false; @@ -879,28 +838,27 @@ namespace API bool track_window_size(window wd, const nana::size& sz, bool true_for_max) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd) == false) + if(is_window(wd) == false) return false; - nana::size & ts = (true_for_max ? iwd->max_track_size : iwd->min_track_size); + nana::size & ts = (true_for_max ? wd->max_track_size : wd->min_track_size); if(!sz.empty()) { if(true_for_max) { //Make sure the new size is larger than min size - if (iwd->min_track_size.width > sz.width || iwd->min_track_size.height > sz.height) + if (wd->min_track_size.width > sz.width || wd->min_track_size.height > sz.height) return false; } else { //Make sure that the new size is less than max size - if ((iwd->max_track_size.width || iwd->max_track_size.height) && (iwd->max_track_size.width < sz.width || iwd->max_track_size.height < sz.height)) + if ((wd->max_track_size.width || wd->max_track_size.height) && (wd->max_track_size.width < sz.width || wd->max_track_size.height < sz.height)) return false; } - ts = interface_type::check_track_size(sz, iwd->extra_width, iwd->extra_height, true_for_max); + ts = interface_type::check_track_size(sz, wd->extra_width, wd->extra_height, true_for_max); } else ts.width = ts.height = 0; @@ -909,155 +867,145 @@ namespace API void window_enabled(window wd, bool enabled) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd) && (iwd->flags.enabled != enabled)) + if(is_window(wd) && (wd->flags.enabled != enabled)) { - iwd->flags.enabled = enabled; - restrict::wd_manager().update(iwd, true, true); - if(category::flags::root == iwd->other.category) - interface_type::enable_window(iwd->root, enabled); + wd->flags.enabled = enabled; + restrict::wd_manager().update(wd, true, true); + if(category::flags::root == wd->other.category) + interface_type::enable_window(wd->root, enabled); } } bool window_enabled(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - return (restrict::wd_manager().available(iwd) ? iwd->flags.enabled : false); + return (is_window(wd) ? wd->flags.enabled : false); } //refresh_window //@brief: Refresh the window and display it immediately. void refresh_window(window wd) { - restrict::wd_manager().update(reinterpret_cast(wd), true, false); + restrict::wd_manager().update(wd, true, false); } void refresh_window_tree(window wd) { - restrict::wd_manager().refresh_tree(reinterpret_cast(wd)); + restrict::wd_manager().refresh_tree(wd); } //update_window //@brief: it displays a window immediately without refreshing. void update_window(window wd) { - restrict::wd_manager().update(reinterpret_cast(wd), false, true); + restrict::wd_manager().update(wd, false, true); } void window_caption(window wd, const std::string& title_utf8) { throw_not_utf8(title_utf8); - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->widget_notifier->caption(to_nstring(title_utf8)); + if (is_window(wd)) + wd->widget_notifier->caption(to_nstring(title_utf8)); } void window_caption(window wd, const std::wstring& title) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->widget_notifier->caption(to_nstring(title)); + if (is_window(wd)) + wd->widget_notifier->caption(to_nstring(title)); } std::string window_caption(window wd) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - return to_utf8(iwd->widget_notifier->caption()); + if (is_window(wd)) + return to_utf8(wd->widget_notifier->caption()); return{}; } void window_cursor(window wd, cursor cur) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - iwd->predef_cursor = cur; - restrict::bedrock.update_cursor(iwd); + wd->predef_cursor = cur; + restrict::bedrock.update_cursor(wd); } } cursor window_cursor(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return iwd->predef_cursor; + if(is_window(wd)) + return wd->predef_cursor; return cursor::arrow; } bool is_focus_ready(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return (iwd->root_widget->other.attribute.root->focus == iwd); + if(is_window(wd)) + return (wd->root_widget->other.attribute.root->focus == wd); return false; } void activate_window(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if(iwd->flags.take_active) - interface_type::activate_window(iwd->root); + if(wd->flags.take_active) + interface_type::activate_window(wd->root); } } window focus_window() { internal_scope_guard lock; - return reinterpret_cast(restrict::bedrock.focus()); + return restrict::bedrock.focus(); } void focus_window(window wd) { - restrict::wd_manager().set_focus(reinterpret_cast(wd), false, arg_focus::reason::general); - restrict::wd_manager().update(reinterpret_cast(wd), false, false); + restrict::wd_manager().set_focus(wd, false, arg_focus::reason::general); + restrict::wd_manager().update(wd, false, false); } window capture_window() { - return reinterpret_cast(restrict::wd_manager().capture_window()); + return restrict::wd_manager().capture_window(); } void set_capture(window wd, bool ignore_children) { - restrict::wd_manager().capture_window(reinterpret_cast(wd), true, ignore_children); + restrict::wd_manager().capture_window(wd, true, ignore_children); } void release_capture(window wd) { //The 3rd parameter is useless when the 2nd parameter is false. - restrict::wd_manager().capture_window(reinterpret_cast(wd), false, false); + restrict::wd_manager().capture_window(wd, false, false); } void modal_window(window wd) { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; + internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (empty_window(wd)) return; - if ((iwd->other.category == category::flags::root) && (iwd->flags.modal == false)) + if ((wd->other.category == category::flags::root) && (wd->flags.modal == false)) { - iwd->flags.modal = true; + wd->flags.modal = true; #if defined(NANA_X11) - interface_type::set_modal(iwd->root); + interface_type::set_modal(wd->root); #endif - restrict::wd_manager().show(iwd, true); + restrict::wd_manager().show(wd, true); } else return; @@ -1070,29 +1018,28 @@ namespace API void wait_for(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) + if (is_window(wd)) restrict::bedrock.pump_event(wd, false); } color fgcolor(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->annex.scheme->foreground.get_color(); + if (is_window(wd)) + return wd->annex.scheme->foreground.get_color(); return{}; } color fgcolor(window wd, const color& clr) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto prev = iwd->annex.scheme->foreground.get_color(); + auto prev = wd->annex.scheme->foreground.get_color(); if (prev != clr) { - iwd->annex.scheme->foreground = clr; - restrict::wd_manager().update(iwd, true, false); + wd->annex.scheme->foreground = clr; + refresh_window(wd); } return prev; } @@ -1102,27 +1049,26 @@ namespace API color bgcolor(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->annex.scheme->background.get_color(); + if (is_window(wd)) + return wd->annex.scheme->background.get_color(); return{}; } color bgcolor(window wd, const color& clr) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto prev = iwd->annex.scheme->background.get_color(); + auto prev = wd->annex.scheme->background.get_color(); if (prev != clr) { - iwd->annex.scheme->background = clr; + wd->annex.scheme->background = clr; //If the bground mode of this window is basic, it should remake the background - if (iwd->effect.bground && iwd->effect.bground_fade_rate < 0.01) // fade rate < 0.01 means it is basic mode - iwd->flags.make_bground_declared = true; + if (wd->effect.bground && wd->effect.bground_fade_rate < 0.01) // fade rate < 0.01 means it is basic mode + wd->flags.make_bground_declared = true; - restrict::wd_manager().update(iwd, true, false); + refresh_window(wd); } return prev; } @@ -1132,22 +1078,21 @@ namespace API color activated_color(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->annex.scheme->activated.get_color(); + if (is_window(wd)) + return wd->annex.scheme->activated.get_color(); return{}; } color activated_color(window wd, const color& clr) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto prev = iwd->annex.scheme->activated.get_color(); + auto prev = wd->annex.scheme->activated.get_color(); if (prev != clr) { - iwd->annex.scheme->activated = clr; - restrict::wd_manager().update(iwd, true, false); + wd->annex.scheme->activated = clr; + refresh_window(wd); } return prev; } @@ -1236,7 +1181,7 @@ namespace API private: caret_interface* _m_caret() const { - if (restrict::wd_manager().available(window_) && window_->annex.caret_ptr) + if (is_window(window_) && window_->annex.caret_ptr) return window_->annex.caret_ptr; if (throw_) @@ -1251,27 +1196,25 @@ namespace API void create_caret(window wd, const size& caret_size) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd) && !(iwd->annex.caret_ptr)) - iwd->annex.caret_ptr = new ::nana::detail::caret(iwd, caret_size); + if (is_window(wd) && !(wd->annex.caret_ptr)) + wd->annex.caret_ptr = new ::nana::detail::caret(wd, caret_size); } void destroy_caret(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - auto p = iwd->annex.caret_ptr; - iwd->annex.caret_ptr = nullptr; + auto p = wd->annex.caret_ptr; + wd->annex.caret_ptr = nullptr; delete p; } } std::unique_ptr open_caret(window window_handle, bool disable_throw) { - auto p = new caret_proxy{ reinterpret_cast(window_handle) }; + auto p = new caret_proxy{ window_handle }; if (disable_throw) p->disable_throw(); @@ -1280,72 +1223,63 @@ namespace API void tabstop(window wd) { - restrict::wd_manager().enable_tabstop(reinterpret_cast(wd)); + restrict::wd_manager().enable_tabstop(wd); } //eat_tabstop //@brief: set a eating tab window that it processes a pressing of tab itself void eat_tabstop(window wd, bool eat) { - if(wd) + internal_scope_guard lock; + if(is_window(wd)) { - auto iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) - { - if(eat) - iwd->flags.tab |= ::nana::detail::tab_type::eating; - else - iwd->flags.tab &= ~::nana::detail::tab_type::eating; - } + if(eat) + wd->flags.tab |= ::nana::detail::tab_type::eating; + else + wd->flags.tab &= ~::nana::detail::tab_type::eating; } } window move_tabstop(window wd, bool next) { - basic_window* ts_wd = restrict::wd_manager().tabstop(reinterpret_cast(wd), next); - restrict::wd_manager().set_focus(ts_wd, false, arg_focus::reason::general); - restrict::wd_manager().update(ts_wd, false, false); - return reinterpret_cast(ts_wd); + auto prev_wd = restrict::wd_manager().tabstop(wd, next); + restrict::wd_manager().set_focus(prev_wd, false, arg_focus::reason::general); + restrict::wd_manager().update(prev_wd, false, false); + + return prev_wd; } void take_active(window wd, bool active, window take_if_active_false) { - auto const iwd = reinterpret_cast(wd); - auto take_if_false = reinterpret_cast(take_if_active_false); - internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if (active || (take_if_false && (restrict::wd_manager().available(take_if_false) == false))) - take_if_false = 0; + if (active || (take_if_active_false && empty_window(take_if_active_false))) + take_if_active_false = nullptr; - iwd->flags.take_active = active; - iwd->other.active_window = take_if_false; + wd->flags.take_active = active; + wd->other.active_window = take_if_active_false; } } bool window_graphics(window wd, nana::paint::graphics& graph) { - auto iwd = reinterpret_cast(wd); - internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (empty_window(wd)) return false; - graph.make(iwd->drawer.graphics.size()); - graph.bitblt(0, 0, iwd->drawer.graphics); - nana::detail::window_layout::paste_children_to_graphics(iwd, graph); + graph.make(wd->drawer.graphics.size()); + graph.bitblt(0, 0, wd->drawer.graphics); + nana::detail::window_layout::paste_children_to_graphics(wd, graph); return true; } bool root_graphics(window wd, nana::paint::graphics& graph) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - graph = *(iwd->root_graph); + graph = *(wd->root_graph); return true; } return false; @@ -1353,51 +1287,47 @@ namespace API bool get_visual_rectangle(window wd, nana::rectangle& r) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - return nana::detail::window_layout::read_visual_rectangle(iwd, r); + if (is_window(wd)) + return nana::detail::window_layout::read_visual_rectangle(wd, r); return false; } void typeface(window wd, const nana::paint::font& font) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - iwd->drawer.graphics.typeface(font); - iwd->drawer.typeface_changed(); - restrict::wd_manager().update(iwd, true, false); + wd->drawer.graphics.typeface(font); + wd->drawer.typeface_changed(); + refresh_window(wd); } } nana::paint::font typeface(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return iwd->drawer.graphics.typeface(); + if(is_window(wd)) + return wd->drawer.graphics.typeface(); return{}; } bool calc_screen_point(window wd, nana::point& pos) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - pos += iwd->pos_root; - return interface_type::calc_screen_point(iwd->root, pos); + pos += wd->pos_root; + return interface_type::calc_screen_point(wd->root, pos); } return false; } bool calc_window_point(window wd, nana::point& pos) { - return restrict::wd_manager().calc_window_point(reinterpret_cast(wd), pos); + return restrict::wd_manager().calc_window_point(wd, pos); } window find_window(const nana::point& pos) @@ -1407,65 +1337,59 @@ namespace API { ::nana::point clipos{pos}; interface_type::calc_window_point(wd, clipos); - return reinterpret_cast( - restrict::wd_manager().find_window(wd, clipos, true)); + return restrict::wd_manager().find_window(wd, clipos, true); } return nullptr; } bool is_window_zoomed(window wd, bool ask_for_max) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if (iwd->other.category == nana::category::flags::root) - return interface_type::is_window_zoomed(iwd->root, ask_for_max); + if (wd->other.category == nana::category::flags::root) + return interface_type::is_window_zoomed(wd->root, ask_for_max); } return false; } void widget_borderless(window wd, bool enabled) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if ((category::flags::widget == iwd->other.category) && (iwd->flags.borderless != enabled)) + if ((category::flags::widget == wd->other.category) && (wd->flags.borderless != enabled)) { - iwd->flags.borderless = enabled; - restrict::wd_manager().update(iwd, true, false); + wd->flags.borderless = enabled; + refresh_window(wd); } } } bool widget_borderless(window wd) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - return iwd->flags.borderless; + if (is_window(wd)) + return wd->flags.borderless; return false; } nana::mouse_action mouse_action(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return iwd->flags.action; + if(is_window(wd)) + return wd->flags.action; return nana::mouse_action::normal; } nana::element_state element_state(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - const bool is_focused = (iwd->root_widget->other.attribute.root->focus == iwd); - switch(iwd->flags.action) + const bool is_focused = (wd->root_widget->other.attribute.root->focus == wd); + switch(wd->flags.action) { case nana::mouse_action::normal: case nana::mouse_action::normal_captured: @@ -1475,7 +1399,7 @@ namespace API case nana::mouse_action::pressed: return nana::element_state::pressed; default: - if(false == iwd->flags.enabled) + if(false == wd->flags.enabled) return nana::element_state::disabled; } } @@ -1484,12 +1408,11 @@ namespace API bool ignore_mouse_focus(window wd, bool ignore) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto state = iwd->flags.ignore_mouse_focus; - iwd->flags.ignore_mouse_focus = ignore; + auto state = wd->flags.ignore_mouse_focus; + wd->flags.ignore_mouse_focus = ignore; return state; } return false; @@ -1497,24 +1420,22 @@ namespace API bool ignore_mouse_focus(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - return (restrict::wd_manager().available(iwd) ? iwd->flags.ignore_mouse_focus : false); + return (is_window(wd) ? wd->flags.ignore_mouse_focus : false); } void at_safe_place(window wd, std::function fn) { - restrict::wd_manager().set_safe_place(reinterpret_cast(wd), std::move(fn)); + restrict::wd_manager().set_safe_place(wd, std::move(fn)); } std::optional> content_extent(window wd, unsigned limited_px, bool limit_width) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd) && iwd->annex.content_measurer) + if (is_window(wd) && wd->annex.content_measurer) { - paint::graphics* graph = &iwd->drawer.graphics; + paint::graphics* graph = &wd->drawer.graphics; paint::graphics temp_graph; if (graph->empty()) { @@ -1523,9 +1444,9 @@ namespace API graph = &temp_graph; } - auto extent = iwd->annex.content_measurer->measure(*graph, limited_px, limit_width); + auto extent = wd->annex.content_measurer->measure(*graph, limited_px, limit_width); if (extent) - return std::make_pair(extent.value(), extent.value() + iwd->annex.content_measurer->extension()); + return std::make_pair(extent.value(), extent.value() + wd->annex.content_measurer->extension()); } return{}; @@ -1538,11 +1459,9 @@ namespace API dragdrop_status window_dragdrop_status(::nana::window wd) { - auto real_wd = reinterpret_cast(wd); internal_scope_guard lock; - - if (restrict::wd_manager().available(real_wd)) - return real_wd->other.dnd_state; + if (is_window(wd)) + return wd->other.dnd_state; return dragdrop_status::not_ready; } diff --git a/source/gui/state_cursor.cpp b/source/gui/state_cursor.cpp index 5644ed83..817b6dec 100644 --- a/source/gui/state_cursor.cpp +++ b/source/gui/state_cursor.cpp @@ -9,18 +9,18 @@ * * @file: nana/gui/state_cursor.cpp */ + +#include "detail/basic_window.hpp" #include #include -#include #include namespace nana { - state_cursor::state_cursor(window handle, cursor cur) - : handle_(handle) + state_cursor::state_cursor(window wd, cursor cur) + : handle_(wd) { auto & brock = detail::bedrock::instance(); - auto wd = reinterpret_cast(handle); if (brock.wd_manager().available(wd)) brock.define_state_cursor(wd, cur, nullptr); else @@ -39,10 +39,9 @@ namespace nana { if (handle_) { + nana::internal_scope_guard lock; auto & brock = detail::bedrock::instance(); - auto wd = reinterpret_cast(handle_); - if (brock.wd_manager().available(wd)) - brock.undefine_state_cursor(wd, nullptr); + brock.undefine_state_cursor(handle_, nullptr); } handle_ = rhs.handle_; rhs.handle_ = nullptr; @@ -54,10 +53,9 @@ namespace nana { if (handle_) { + nana::internal_scope_guard lock; auto & brock = detail::bedrock::instance(); - auto wd = reinterpret_cast(handle_); - if (brock.wd_manager().available(wd)) - brock.undefine_state_cursor(wd, nullptr); + brock.undefine_state_cursor(handle_, nullptr); } } } \ No newline at end of file diff --git a/source/gui/wvl.cpp b/source/gui/wvl.cpp index 7497d3c4..e280aef8 100644 --- a/source/gui/wvl.cpp +++ b/source/gui/wvl.cpp @@ -29,7 +29,7 @@ namespace nana { void form_loader_private::insert_form(::nana::widget* p) { - bedrock::instance().manage_form_loader(reinterpret_cast(p->handle()), true); + bedrock::instance().manage_form_loader(p->handle(), true); } } From 065e6f30815e30bb5b5fd25733648d6785e0a2ef Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 27 Jun 2019 07:47:36 +0800 Subject: [PATCH 49/61] remove iconv code --- source/detail/platform_spec_posix.cpp | 10 ++++++++-- source/detail/posix/platform_spec.hpp | 6 +++++- source/gui/detail/bedrock_posix.cpp | 7 ++++++- source/system/dataexch.cpp | 4 ++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index f7cbc9d6..cad5b82e 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -35,6 +34,7 @@ #include #include "posix/msg_dispatcher.hpp" +#include "../gui/detail/basic_window.hpp" namespace nana { @@ -95,7 +95,7 @@ namespace detail return std::string(); } //end class conf - +#if 0 //class charset_conv charset_conv::charset_conv(const char* tocode, const char* fromcode) { @@ -140,6 +140,7 @@ namespace detail return rstr; } //end class charset_conv +#endif #endif //Caret implementation @@ -338,16 +339,21 @@ namespace detail string.tab_length = 4; string.tab_pixels = 0; string.whitespace_pixels = 0; + +#if 0 //deprecated #if defined(NANA_USE_XFT) conv_.handle = ::iconv_open("UTF-8", NANA_UNICODE); conv_.code = NANA_UNICODE; +#endif #endif } drawable_impl_type::~drawable_impl_type() { +#if 0 //deprecated #if defined(NANA_USE_XFT) ::iconv_close(conv_.handle); +#endif #endif } diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index 84c1c24e..9c21625c 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -42,7 +42,7 @@ #if defined(NANA_USE_XFT) #include - #include +// #include //deprecated #include #endif @@ -63,6 +63,7 @@ namespace detail std::ifstream ifs_; }; +#if 0 //deprecated class charset_conv { charset_conv(const charset_conv&) = delete; @@ -75,6 +76,7 @@ namespace detail private: iconv_t handle_; }; +#endif #endif struct drawable_impl_type @@ -118,12 +120,14 @@ namespace detail unsigned color_{ 0xFFFFFFFF }; unsigned text_color_{ 0xFFFFFFFF }; +#if 0 //deprecated #if defined(NANA_USE_XFT) struct conv_tag { iconv_t handle; std::string code; }conv_; +#endif #endif }; diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 69c49efa..6ad96318 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -512,11 +512,16 @@ namespace detail auto const native_window = rruntime->window->root; - +#if 0 //deprecated 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); +#else + auto wstr = nana::to_wstring(std::string{keybuf, keybuf + keybuf_len}); + auto const charbuf = wstr.c_str(); + auto const len = wstr.length(); +#endif for(std::size_t i = 0; i < len; ++i) { diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index b3f4d5d4..6628132a 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -20,9 +20,9 @@ #if defined(NANA_WINDOWS) # include #elif defined(NANA_X11) -# include "../detail/platform_spec_selector.hpp" # include -# include +# include "../detail/platform_spec_selector.hpp" +# include "../gui/detail/basic_window.hpp" #endif namespace nana{ namespace system{ From 01bd43f960d4deeef7bee5d6cd1fa6d4f942f0ec Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 28 Jun 2019 06:32:34 +0800 Subject: [PATCH 50/61] refactoring --- include/nana/deploy.hpp | 2 -- include/nana/gui/notifier.hpp | 4 --- source/detail/mswin/platform_spec.hpp | 11 +++++- source/detail/platform_spec_posix.cpp | 48 ++++++++++++------------- source/detail/platform_spec_windows.cpp | 16 ++++++--- source/detail/posix/platform_spec.hpp | 35 ++++-------------- source/filesystem/filesystem.cpp | 36 ------------------- source/gui/detail/bedrock_posix.cpp | 7 ---- source/paint/graphics.cpp | 19 +++++----- 9 files changed, 62 insertions(+), 116 deletions(-) diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index 168358c5..e3091d23 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -118,7 +118,5 @@ namespace nana } } -#define NANA_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) - #include #endif //NANA_DEPLOY_HPP diff --git a/include/nana/gui/notifier.hpp b/include/nana/gui/notifier.hpp index 31cf28f1..d0d87efa 100644 --- a/include/nana/gui/notifier.hpp +++ b/include/nana/gui/notifier.hpp @@ -59,11 +59,7 @@ namespace nana void text(const ::std::string&); void icon(const ::std::string& icon_file); void insert_icon(const ::std::string& icon_file); -#if 0 //deprecated - void period(unsigned millisecond); -#else void period(std::chrono::milliseconds time); -#endif detail::notifier_events& events(); window handle() const; private: diff --git a/source/detail/mswin/platform_spec.hpp b/source/detail/mswin/platform_spec.hpp index 1a44ce8b..5c0ad5ab 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-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -96,19 +96,28 @@ namespace detail unsigned whitespace_pixels; }string; + unsigned fgcolor_rgb{ 0xFFFFFFFF }; + unsigned bgcolor_rgb{ 0xFFFFFFFF }; + unsigned fgcolor_native{ 0xFFFFFFFF }; //Windows RGB format: 0xBBGGRR + unsigned bgcolor_native{ 0xFFFFFFFF }; //Windows RGB format + drawable_impl_type(const drawable_impl_type&) = delete; drawable_impl_type& operator=(const drawable_impl_type&) = delete; drawable_impl_type(); ~drawable_impl_type(); +#if 0 //deprecated unsigned get_color() const; unsigned get_text_color() const; +#endif void set_color(const ::nana::color&); void set_text_color(const ::nana::color&); +#if 0 //deprecated private: unsigned color_{ 0xffffffff }; unsigned text_color_{0xffffffff}; +#endif }; class platform_spec diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index cad5b82e..5f74dc67 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -1,7 +1,7 @@ /* * Platform Specification Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Nana Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -339,24 +339,9 @@ namespace detail string.tab_length = 4; string.tab_pixels = 0; string.whitespace_pixels = 0; - -#if 0 //deprecated -#if defined(NANA_USE_XFT) - conv_.handle = ::iconv_open("UTF-8", NANA_UNICODE); - conv_.code = NANA_UNICODE; -#endif -#endif } - drawable_impl_type::~drawable_impl_type() - { #if 0 //deprecated -#if defined(NANA_USE_XFT) - ::iconv_close(conv_.handle); -#endif -#endif - } - unsigned drawable_impl_type::get_color() const { return color_; @@ -366,27 +351,28 @@ namespace detail { return text_color_; } +#endif void drawable_impl_type::set_color(const ::nana::color& clr) { - color_ = (clr.px_color().value & 0xFFFFFF); + bgcolor_rgb = (clr.px_color().value & 0xFFFFFF); } void drawable_impl_type::set_text_color(const ::nana::color& clr) { - text_color_ = (clr.px_color().value & 0xFFFFFF); + fgcolor_rgb = (clr.px_color().value & 0xFFFFFF); update_text_color(); } void drawable_impl_type::update_color() { - if (color_ != current_color_) + if (bgcolor_rgb != current_color_) { auto & spec = nana::detail::platform_spec::instance(); platform_scope_guard lock; - current_color_ = color_; - auto col = color_; + current_color_ = bgcolor_rgb; + auto col = bgcolor_rgb; switch (spec.screen_depth()) { case 16: @@ -397,18 +383,32 @@ namespace detail } ::XSetForeground(spec.open_display(), context, col); ::XSetBackground(spec.open_display(), context, col); + +#if defined(NANA_USE_XFT) + //xft_fgcolor also needs to be assigned. + //assumes the xft_fgcolor is not assigned in update_color. There is a situation that causes a bug. + // + //update_text_color ( if fgcolor_rgb = A, then current_color = A and xft_fgcolor = A) + //update_color (if bgcolor_rgb = B, then current_color = B and xft_fgcolor is still A) + //update_text_color ( if fgcolor_rgb = B, then current_color = B, xft_fgcolor is still A) + + xft_fgcolor.color.red = ((0xFF0000 & col) >> 16) * 0x101; + xft_fgcolor.color.green = ((0xFF00 & col) >> 8) * 0x101; + xft_fgcolor.color.blue = (0xFF & col) * 0x101; + xft_fgcolor.color.alpha = 0xFFFF; +#endif } } void drawable_impl_type::update_text_color() { - if (text_color_ != current_color_) + if (fgcolor_rgb != current_color_) { auto & spec = nana::detail::platform_spec::instance(); platform_scope_guard lock; - current_color_ = text_color_; - auto col = text_color_; + current_color_ = fgcolor_rgb; + auto col = fgcolor_rgb; switch (spec.screen_depth()) { case 16: diff --git a/source/detail/platform_spec_windows.cpp b/source/detail/platform_spec_windows.cpp index 812c2ed0..f659b054 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-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -42,6 +42,7 @@ namespace detail ::DeleteObject(pixmap); } +#if 0 //deprecated unsigned drawable_impl_type::get_color() const { return color_; @@ -51,19 +52,24 @@ namespace detail { return text_color_; } +#endif + +#define NANA_WINDOWS_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) void drawable_impl_type::set_color(const ::nana::color& clr) { - color_ = (clr.px_color().value & 0xFFFFFF); + bgcolor_rgb = (clr.px_color().value & 0xFFFFFF); + bgcolor_native = NANA_WINDOWS_RGB(bgcolor_rgb); } void drawable_impl_type::set_text_color(const ::nana::color& clr) { auto rgb = (clr.px_color().value & 0xFFFFFF); - if (text_color_ != rgb) + if (fgcolor_rgb != rgb) { - ::SetTextColor(context, NANA_RGB(rgb)); - text_color_ = rgb; + fgcolor_rgb = rgb; + fgcolor_native = NANA_WINDOWS_RGB(rgb); + ::SetTextColor(context, fgcolor_native); } } diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index 9c21625c..57a61d1e 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-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -42,7 +42,6 @@ #if defined(NANA_USE_XFT) #include -// #include //deprecated #include #endif @@ -62,21 +61,6 @@ namespace detail private: std::ifstream ifs_; }; - -#if 0 //deprecated - class charset_conv - { - charset_conv(const charset_conv&) = delete; - charset_conv& operator=(const charset_conv*) = delete; - public: - charset_conv(const char* tocode, const char* fromcode); - ~charset_conv(); - std::string charset(const std::string& str) const; - std::string charset(const char * buf, std::size_t len) const; - private: - iconv_t handle_; - }; -#endif #endif struct drawable_impl_type @@ -97,16 +81,19 @@ namespace detail unsigned whitespace_pixels; }string; + unsigned fgcolor_rgb{ 0xFFFFFFFF }; + unsigned bgcolor_rgb{ 0xFFFFFFFF }; + #if defined(NANA_USE_XFT) XftDraw * xftdraw{nullptr}; XftColor xft_fgcolor; - const std::string charset(const std::wstring& str, const std::string& strcode); #endif drawable_impl_type(); - ~drawable_impl_type(); +#if 0 //deprecated unsigned get_color() const; unsigned get_text_color() const; +#endif void set_color(const ::nana::color&); void set_text_color(const ::nana::color&); @@ -117,17 +104,9 @@ namespace detail drawable_impl_type& operator=(const drawable_impl_type&) = delete; unsigned current_color_{ 0xFFFFFF }; +#if 0 //deprecated unsigned color_{ 0xFFFFFFFF }; unsigned text_color_{ 0xFFFFFFFF }; - -#if 0 //deprecated -#if defined(NANA_USE_XFT) - struct conv_tag - { - iconv_t handle; - std::string code; - }conv_; -#endif #endif }; diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index 8be0cce9..9180f084 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -110,42 +110,6 @@ namespace nana return tm.str(); } return {}; - -/* - // Deprecated - //Windows stores file times using the FILETIME structure, which is a 64 bit value of 100ns intervals from January 1, 1601. - //What's worse is that this 1601 date is fairly common to see given that it's the all zeroes value, and it is far before the - //earliest date representable with time_t.std::filesystem can't change the reality of the underlying platform. - - - try { -#if NANA_USING_BOOST_FILESYSTEM - // The return type of boost::filesystem::last_write_time isn't - // the same as in nana and std implementations of this function - auto ftime = std::chrono::system_clock::from_time_t(fs::last_write_time(path)); -#else - auto ftime = fs::last_write_time(path); -#endif - - // crash: VS2015 will not read the time for some files (for example: C:/hiberfil.sys) - // and will return file_time_type(-1) without throwing - // https://msdn.microsoft.com/en-us/library/dn823784.aspx - - if (ftime == ((fs::file_time_type::min)())) return{}; - - //A workaround for VC2013 - using time_point = decltype(ftime); - auto cftime = time_point::clock::to_time_t(ftime); - - std::stringstream tm; - tm << std::put_time(std::localtime(&cftime), "%Y-%m-%d, %H:%M:%S"); - return tm.str(); - } - catch (...) { - return{}; - } -#endif -*/ } bool modified_file_time(const fs::path& p, struct tm& t) diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 6ad96318..9839ac6a 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -512,16 +512,9 @@ namespace detail auto const native_window = rruntime->window->root; -#if 0 //deprecated - 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); -#else auto wstr = nana::to_wstring(std::string{keybuf, keybuf + keybuf_len}); auto const charbuf = wstr.c_str(); auto const len = wstr.length(); -#endif for(std::size_t i = 0; i < len; ++i) { diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 9a89ba03..c3c4b97e 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -1108,7 +1108,7 @@ namespace paint ::nana::color graphics::palette(bool for_text) const { if (impl_->handle) - return static_cast(for_text ? impl_->handle->get_text_color() : impl_->handle->get_color()); + return static_cast(for_text ? impl_->handle->fgcolor_rgb : impl_->handle->bgcolor_rgb); return{}; } @@ -1140,7 +1140,7 @@ namespace paint if (impl_->handle) { #if defined(NANA_WINDOWS) - ::SetPixel(impl_->handle->context, x, y, NANA_RGB(impl_->handle->get_color())); + ::SetPixel(impl_->handle->context, x, y, impl_->handle->bgcolor_native); #elif defined(NANA_X11) Display* disp = nana::detail::platform_spec::instance().open_display(); impl_->handle->update_color(); @@ -1336,14 +1336,14 @@ namespace paint #if defined(NANA_WINDOWS) if (pos1 != pos2) { - auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color()))); + auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native)); ::MoveToEx(impl_->handle->context, pos1.x, pos1.y, 0); ::LineTo(impl_->handle->context, pos2.x, pos2.y); ::DeleteObject(::SelectObject(impl_->handle->context, prv_pen)); } - ::SetPixel(impl_->handle->context, pos2.x, pos2.y, NANA_RGB(impl_->handle->get_color())); + ::SetPixel(impl_->handle->context, pos2.x, pos2.y, impl_->handle->bgcolor_native); #elif defined(NANA_X11) Display* disp = nana::detail::platform_spec::instance().open_display(); impl_->handle->update_color(); @@ -1369,7 +1369,7 @@ namespace paint { if (!impl_->handle) return; #if defined(NANA_WINDOWS) - auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color()))); + auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native)); ::LineTo(impl_->handle->context, pos.x, pos.y); @@ -1402,7 +1402,7 @@ namespace paint { #if defined(NANA_WINDOWS) - auto brush = ::CreateSolidBrush(NANA_RGB(impl_->handle->get_color())); + auto brush = ::CreateSolidBrush(impl_->handle->bgcolor_native); ::RECT native_r = { r.x, r.y, r.right(), r.bottom()}; @@ -1527,6 +1527,7 @@ namespace paint if (impl_->changed == false) impl_->changed = true; } +#define NANA_WINDOWS_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) void graphics::round_rectangle(const ::nana::rectangle& r, unsigned radius_x, unsigned radius_y, const color& clr, bool solid, const color& solid_clr) { if (impl_->handle) @@ -1536,8 +1537,8 @@ namespace paint if (solid) { - auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color()))); - auto prv_brush = ::SelectObject(impl_->handle->context, ::CreateSolidBrush(NANA_RGB(solid_clr.px_color().value))); + auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native)); + auto prv_brush = ::SelectObject(impl_->handle->context, ::CreateSolidBrush(NANA_WINDOWS_RGB(solid_clr.px_color().value))); ::RoundRect(impl_->handle->context, r.x, r.y, r.right(), r.bottom(), static_cast(radius_x * 2), static_cast(radius_y * 2)); @@ -1546,7 +1547,7 @@ namespace paint } else { - auto brush = ::CreateSolidBrush(NANA_RGB(impl_->handle->get_color())); + auto brush = ::CreateSolidBrush(impl_->handle->bgcolor_native); auto region = ::CreateRoundRectRgn(r.x, r.y, r.x + static_cast(r.width) + 1, r.y + static_cast(r.height) + 1, static_cast(radius_x + 1), static_cast(radius_y + 1)); From 363a80e9355c5b1e423d858701666b97e7378531 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 30 Jun 2019 11:56:16 +0800 Subject: [PATCH 51/61] refactor remove typedef-name core_window_t remove get_color and get_text_color of the internal class drawable --- include/nana/gui/detail/bedrock.hpp | 36 +++--- include/nana/gui/detail/window_layout.hpp | 26 ++-- include/nana/gui/detail/window_manager.hpp | 88 +++++++------ source/gui/detail/bedrock_pi.cpp | 36 +++--- source/gui/detail/bedrock_posix.cpp | 16 +-- source/gui/detail/bedrock_types.hpp | 12 +- source/gui/detail/bedrock_windows.cpp | 18 +-- source/gui/detail/drawer.cpp | 15 +-- source/gui/detail/window_layout.cpp | 32 ++--- source/gui/detail/window_manager.cpp | 120 +++++++++--------- .../paint/detail/native_paint_interface.cpp | 16 --- source/paint/graphics.cpp | 21 +-- source/system/dataexch.cpp | 4 +- 13 files changed, 198 insertions(+), 242 deletions(-) diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index db731e97..834431ac 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -37,8 +37,6 @@ namespace detail bedrock(const bedrock&) = delete; bedrock& operator=(const bedrock&) = delete; public: - using core_window_t = basic_window; - struct thread_context; class flag_guard; @@ -59,16 +57,16 @@ namespace detail ~bedrock(); void pump_event(window, bool is_modal); - void flush_surface(core_window_t*, bool forced, const rectangle* update_area = nullptr); + void flush_surface(basic_window*, bool forced, const rectangle* update_area = nullptr); static int inc_window(thread_t tid = 0); thread_context* open_thread_context(thread_t tid = 0); thread_context* get_thread_context(thread_t tid = 0); void remove_thread_context(thread_t tid = 0); static bedrock& instance(); - core_window_t* focus(); + basic_window* focus(); - void set_menubar_taken(core_window_t*); + void set_menubar_taken(basic_window*); //Delay Restores focus when a menu which attached to menubar is closed void delay_restore(int); @@ -84,7 +82,7 @@ namespace detail bool shortkey_occurred() const; element_store& get_element_store() const; - void map_through_widgets(core_window_t*, native_drawable_type); + void map_through_widgets(basic_window*, native_drawable_type); //Closes the windows which are associated with the specified thread. If the given thread_id is 0, it closes all windows void close_thread_window(thread_t thread_id); @@ -94,28 +92,28 @@ namespace detail static void delete_platform_assoc(window_platform_assoc*); void keyboard_accelerator(native_window_type, const accel_key&, const std::function&); public: - void event_expose(core_window_t *, bool exposed); - void event_move(core_window_t*, int x, int y); - bool event_msleave(core_window_t*); - void event_focus_changed(core_window_t* root_wd, native_window_type receiver, bool getting); - void thread_context_destroy(core_window_t*); + void event_expose(basic_window *, bool exposed); + void event_move(basic_window*, int x, int y); + bool event_msleave(basic_window*); + void event_focus_changed(basic_window* root_wd, native_window_type receiver, bool getting); + void thread_context_destroy(basic_window*); void thread_context_lazy_refresh(); - void update_cursor(core_window_t*); - void set_cursor(core_window_t*, nana::cursor, thread_context*); - void define_state_cursor(core_window_t*, nana::cursor, thread_context*); - void undefine_state_cursor(core_window_t*, thread_context*); + void update_cursor(basic_window*); + void set_cursor(basic_window*, nana::cursor, thread_context*); + void define_state_cursor(basic_window*, nana::cursor, thread_context*); + void undefine_state_cursor(basic_window*, thread_context*); color_schemes& scheme(); events_operation& evt_operation(); window_manager& wd_manager(); - void manage_form_loader(core_window_t*, bool insert_or_remove); + void manage_form_loader(basic_window*, bool insert_or_remove); public: // if 'bForce__EmitInternal', then ONLY internal (widget's) events are processed (even through explicit filtering) - bool emit(event_code, core_window_t*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false); + bool emit(event_code, basic_window*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false); private: - void _m_emit_core(event_code, core_window_t*, bool draw_only, const event_arg&, const bool bForce__EmitInternal); - void _m_event_filter(event_code, core_window_t*, thread_context*); + void _m_emit_core(event_code, basic_window*, bool draw_only, const event_arg&, const bool bForce__EmitInternal); + void _m_event_filter(event_code, basic_window*, thread_context*); private: static bedrock bedrock_object; diff --git a/include/nana/gui/detail/window_layout.hpp b/include/nana/gui/detail/window_layout.hpp index 9d628946..01256ce6 100644 --- a/include/nana/gui/detail/window_layout.hpp +++ b/include/nana/gui/detail/window_layout.hpp @@ -35,11 +35,9 @@ namespace detail class window_layout { public: - typedef basic_window core_window_t; - struct wd_rectangle { - core_window_t * window; + basic_window * window; rectangle r; }; @@ -49,27 +47,27 @@ namespace detail try_refresh }; public: - static void paint(core_window_t*, paint_operation, bool request_refresh_children); + static void paint(basic_window*, paint_operation, bool request_refresh_children); - static bool maproot(core_window_t*, bool have_refreshed, bool request_refresh_children); + static bool maproot(basic_window*, bool have_refreshed, bool request_refresh_children); - static void paste_children_to_graphics(core_window_t*, nana::paint::graphics& graph); + static void paste_children_to_graphics(basic_window*, nana::paint::graphics& graph); //read_visual_rectangle //@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, // the visual rectangle is a rectangular block that a window should be displayed on screen. // The result is a rectangle that is a visible area for its ancesters. - static bool read_visual_rectangle(core_window_t*, nana::rectangle& visual); + static bool read_visual_rectangle(basic_window*, nana::rectangle& visual); //read_overlaps // reads the overlaps that are overlapped a rectangular block - static bool read_overlaps(core_window_t*, const nana::rectangle& vis_rect, std::vector& blocks); + static bool read_overlaps(basic_window*, const nana::rectangle& vis_rect, std::vector& blocks); - static bool enable_effects_bground(core_window_t *, bool enabled); + static bool enable_effects_bground(basic_window *, bool enabled); //make_bground // update the glass buffer of a glass window. - static void make_bground(core_window_t* const); + static void make_bground(basic_window* const); private: /// _m_paste_children @@ -82,16 +80,16 @@ namespace detail * @param graph A graphics object to which the child windows are pasted. * @param graph_rpos The reference point to the graph. */ - static void _m_paste_children(core_window_t* window, bool has_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); + static void _m_paste_children(basic_window* window, bool has_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); - static void _m_paint_glass_window(core_window_t*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other); + static void _m_paint_glass_window(basic_window*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other); //Notify the windows which have brground to update their background buffer. - static void _m_notify_glasses(core_window_t* const sigwd); + static void _m_notify_glasses(basic_window* const sigwd); private: struct data_section { - std::vector effects_bground_windows; + std::vector effects_bground_windows; }; static data_section data_sect; };//end class window_layout diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index 1aa18fe2..8c4390d3 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -67,95 +67,93 @@ namespace detail using native_window = native_window_type; using mutex_type = revertible_mutex; - using core_window_t = basic_window; - window_manager(); ~window_manager(); - std::size_t number_of_core_window() const; + std::size_t window_count() const; mutex_type & internal_lock() const; - void all_handles(std::vector&) const; + void all_handles(std::vector&) const; - void event_filter(core_window_t*, bool is_make, event_code); + void event_filter(basic_window*, bool is_make, event_code); - bool available(core_window_t*); - bool available(core_window_t *, core_window_t*); + bool available(basic_window*); + bool available(basic_window *, basic_window*); - core_window_t* create_root(core_window_t*, bool nested, rectangle, const appearance&, widget*); - core_window_t* create_widget(core_window_t*, const rectangle&, bool is_lite, widget*); - void close(core_window_t*); + basic_window* create_root(basic_window*, bool nested, rectangle, const appearance&, widget*); + basic_window* create_widget(basic_window*, const rectangle&, bool is_lite, widget*); + void close(basic_window*); //destroy //@brief: Delete the window handle - void destroy(core_window_t*); + void destroy(basic_window*); //destroy_handle //@brief: Delete window handle, the handle type must be a root and a frame. // Deletes a window whose category type is a root type or a frame type. - void destroy_handle(core_window_t*); + void destroy_handle(basic_window*); - void icon(core_window_t*, const paint::image& small_icon, const paint::image& big_icon); + void icon(basic_window*, const paint::image& small_icon, const paint::image& big_icon); - bool show(core_window_t* wd, bool visible); + bool show(basic_window* wd, bool visible); //find a widget window at specified position //@param root A root window //@param pos Position //@param ignore_captured A flag indicates whether to ignore redirecting the result to its captured window. If this paramter is true, it returns the window at the position, if the parameter is false, it returns the captured window if the captured window don't ignore children. - core_window_t* find_window(native_window_type root, const point& pos, bool ignore_captured = false); + basic_window* find_window(native_window_type root, const point& pos, bool ignore_captured = false); //move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window - bool move(core_window_t*, int x, int y, bool passive); - bool move(core_window_t*, const rectangle&); + bool move(basic_window*, int x, int y, bool passive); + bool move(basic_window*, const rectangle&); - bool size(core_window_t*, nana::size, bool passive, bool ask_update); + bool size(basic_window*, nana::size, bool passive, bool ask_update); - core_window_t* root(native_window_type) const; + basic_window* root(native_window_type) const; //Copy the root buffer that wnd specified into DeviceContext - void map(core_window_t*, bool forced, const rectangle* update_area = nullptr); + void map(basic_window*, bool forced, const rectangle* update_area = nullptr); - bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr); - void update_requesters(core_window_t* root_wd); - void refresh_tree(core_window_t*); + bool update(basic_window*, bool redraw, bool force, const rectangle* update_area = nullptr); + void update_requesters(basic_window* root_wd); + void refresh_tree(basic_window*); - void do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false); + void do_lazy_refresh(basic_window*, bool force_copy_to_screen, bool refresh_tree = false); - bool set_parent(core_window_t* wd, core_window_t* new_parent); - core_window_t* set_focus(core_window_t*, bool root_has_been_focused, arg_focus::reason); + bool set_parent(basic_window* wd, basic_window* new_parent); + basic_window* set_focus(basic_window*, bool root_has_been_focused, arg_focus::reason); - core_window_t* capture_redirect(core_window_t*); + basic_window* capture_redirect(basic_window*); bool capture_window_entered(int root_x, int root_y, bool& prev); - core_window_t * capture_window() const; - void capture_window(core_window_t*, bool capture, bool ignore_children_if_captured); + basic_window * capture_window() const; + void capture_window(basic_window*, bool capture, bool ignore_children_if_captured); - void enable_tabstop(core_window_t*); - core_window_t* tabstop(core_window_t*, bool forward) const; //forward means move to next in logic. + void enable_tabstop(basic_window*); + basic_window* tabstop(basic_window*, bool forward) const; //forward means move to next in logic. void remove_trash_handle(thread_t tid); - bool enable_effects_bground(core_window_t*, bool); + bool enable_effects_bground(basic_window*, bool); - bool calc_window_point(core_window_t*, nana::point&); + bool calc_window_point(basic_window*, nana::point&); root_misc* root_runtime(native_window) const; - bool register_shortkey(core_window_t*, unsigned long key); - void unregister_shortkey(core_window_t*, bool with_children); + bool register_shortkey(basic_window*, unsigned long key); + void unregister_shortkey(basic_window*, bool with_children); - core_window_t* find_shortkey(native_window_type, unsigned long key); + basic_window* find_shortkey(native_window_type, unsigned long key); - void set_safe_place(core_window_t* wd, std::function&& fn); + void set_safe_place(basic_window* wd, std::function&& fn); void call_safe_place(thread_t thread_id); private: - void _m_disengage(core_window_t*, core_window_t* for_new); - void _m_destroy(core_window_t*); - void _m_move_core(core_window_t*, const point& delta); - void _m_shortkeys(core_window_t*, bool with_chlidren, std::vector>& keys) const; - core_window_t* _m_find(core_window_t*, const point&); - static bool _m_effective(core_window_t*, const point& root_pos); + void _m_disengage(basic_window*, basic_window* for_new); + void _m_destroy(basic_window*); + void _m_move_core(basic_window*, const point& delta); + void _m_shortkeys(basic_window*, bool with_chlidren, std::vector>& keys) const; + basic_window* _m_find(basic_window*, const point&); + static bool _m_effective(basic_window*, const point& root_pos); private: mutable mutex_type mutex_; @@ -166,10 +164,10 @@ namespace detail { struct captured { - core_window_t *window; + basic_window *window; bool inside; bool ignore_children; - std::vector > history; + std::vector > history; }capture; }attr_; diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index a247a973..bf4e387b 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -73,7 +73,7 @@ namespace nana class bedrock::flag_guard { public: - flag_guard(bedrock* brock, core_window_t * wd) + flag_guard(bedrock* brock, basic_window * wd) : brock_{ brock }, wd_(wd) { wd_->flags.refreshing = true; @@ -86,7 +86,7 @@ namespace nana } private: bedrock *const brock_; - core_window_t *const wd_; + basic_window *const wd_; }; //class root_guard @@ -107,7 +107,7 @@ namespace nana } //end class root_guard - bedrock::core_window_t* bedrock::focus() + basic_window* bedrock::focus() { auto wd = wd_manager().root(native_interface::get_focus_window()); return (wd ? wd->other.attribute.root->focus : nullptr); @@ -123,7 +123,7 @@ namespace nana return pi_data_->wd_manager; } - void bedrock::manage_form_loader(core_window_t* wd, bool insert_or_remove) + void bedrock::manage_form_loader(basic_window* wd, bool insert_or_remove) { if (insert_or_remove) { @@ -140,7 +140,7 @@ namespace nana void bedrock::close_thread_window(thread_t thread_id) { - std::vector v; + std::vector v; wd_manager().all_handles(v); std::vector roots; @@ -159,7 +159,7 @@ namespace nana native_interface::close_window(i); } - void bedrock::event_expose(core_window_t * wd, bool exposed) + void bedrock::event_expose(basic_window * wd, bool exposed) { if (nullptr == wd) return; @@ -171,7 +171,7 @@ namespace nana if (emit(event_code::expose, wd, arg, false, get_thread_context())) { //Get the window who has the activated caret - const core_window_t * caret_wd = ((wd->annex.caret_ptr && wd->annex.caret_ptr->activated()) ? wd : wd->child_caret()); + auto const caret_wd = ((wd->annex.caret_ptr && wd->annex.caret_ptr->activated()) ? wd : wd->child_caret()); if (caret_wd) { if (exposed) @@ -194,7 +194,7 @@ namespace nana } } - void bedrock::event_move(core_window_t* wd, int x, int y) + void bedrock::event_move(basic_window* wd, int x, int y) { if (wd) { @@ -206,7 +206,7 @@ namespace nana } } - bool bedrock::event_msleave(core_window_t* hovered) + bool bedrock::event_msleave(basic_window* hovered) { if (wd_manager().available(hovered) && hovered->flags.enabled) { @@ -225,7 +225,7 @@ namespace nana } //The wd must be a root window - void bedrock::event_focus_changed(core_window_t* root_wd, native_window_type receiver, bool getting) + void bedrock::event_focus_changed(basic_window* root_wd, native_window_type receiver, bool getting) { auto focused = root_wd->other.attribute.root->focus; @@ -256,7 +256,7 @@ namespace nana } } - void bedrock::update_cursor(core_window_t * wd) + void bedrock::update_cursor(basic_window * wd) { internal_scope_guard isg; if (wd_manager().available(wd)) @@ -278,7 +278,7 @@ namespace nana } } - void bedrock::set_menubar_taken(core_window_t* wd) + void bedrock::set_menubar_taken(basic_window* wd) { auto pre = pi_data_->menu.taken_window; pi_data_->menu.taken_window = wd; @@ -392,7 +392,7 @@ namespace nana return pi_data_->scheme; } - void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg, const bool bForce__EmitInternal) + void bedrock::_m_emit_core(event_code evt_code, basic_window* wd, bool draw_only, const ::nana::event_arg& event_arg, const bool bForce__EmitInternal) { auto retain = wd->annex.events_ptr; auto evts_ptr = retain.get(); @@ -622,7 +622,7 @@ namespace nana } } - void bedrock::thread_context_destroy(core_window_t * wd) + void bedrock::thread_context_destroy(basic_window * wd) { auto ctx = get_thread_context(0); if(ctx && ctx->event_window == wd) @@ -633,15 +633,15 @@ namespace nana { auto ctx = get_thread_context(0); if(ctx && ctx->event_window) - ctx->event_window->other.upd_state = core_window_t::update_state::refreshed; + ctx->event_window->other.upd_state = basic_window::update_state::refreshed; } - bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal) + bool bedrock::emit(event_code evt_code, basic_window* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal) { if(wd_manager().available(wd) == false) return false; - core_window_t * prev_wd = nullptr; + basic_window * prev_wd = nullptr; if(thrd) { prev_wd = thrd->event_window; @@ -676,7 +676,7 @@ namespace nana return good_wd; } - void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd) + void bedrock::_m_event_filter(event_code event_id, basic_window * wd, thread_context * thrd) { auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow); diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 9839ac6a..e04278f8 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -141,7 +141,7 @@ namespace detail delete impl_; } - void bedrock::flush_surface(core_window_t* wd, bool forced, const rectangle* update_area) + void bedrock::flush_surface(basic_window* wd, bool forced, const rectangle* update_area) { wd->drawer.map(wd, forced, update_area); } @@ -248,7 +248,7 @@ namespace detail return impl_->estore; } - void bedrock::map_through_widgets(core_window_t*, native_drawable_type) + void bedrock::map_through_widgets(basic_window*, native_drawable_type) { //No implementation for Linux } @@ -579,11 +579,9 @@ namespace detail void window_proc_for_xevent(Display* /*display*/, XEvent& xevent) { - typedef detail::bedrock::core_window_t core_window_t; - static auto& brock = detail::bedrock::instance(); static unsigned long last_mouse_down_time; - static core_window_t* last_mouse_down_window; + static basic_window* last_mouse_down_window; auto native_window = reinterpret_cast(event_window(xevent)); auto & wd_manager = brock.wd_manager(); @@ -1257,7 +1255,7 @@ namespace detail lock.revert(); native_window_type owner_native{}; - core_window_t * owner = 0; + basic_window * owner = nullptr; if(condition_wd && is_modal) { native_window_type modal = condition_wd->root; @@ -1299,7 +1297,7 @@ namespace detail }//end bedrock::event_loop //Dynamically set a cursor for a window - void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + void bedrock::set_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd) { if (nullptr == thrd) thrd = get_thread_context(wd->thread_id); @@ -1342,14 +1340,14 @@ namespace detail } } - void bedrock::define_state_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + void bedrock::define_state_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd) { wd->root_widget->other.attribute.root->state_cursor = cur; wd->root_widget->other.attribute.root->state_cursor_window = wd; set_cursor(wd, cur, thrd); } - void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd) + void bedrock::undefine_state_cursor(basic_window * wd, thread_context* thrd) { if (!wd_manager().available(wd)) return; diff --git a/source/gui/detail/bedrock_types.hpp b/source/gui/detail/bedrock_types.hpp index f3fb55bc..a95b0755 100644 --- a/source/gui/detail/bedrock_types.hpp +++ b/source/gui/detail/bedrock_types.hpp @@ -18,12 +18,12 @@ namespace nana color_schemes scheme; events_operation evt_operation; window_manager wd_manager; - std::set auto_form_set; + std::set auto_form_set; bool shortkey_occurred{ false }; struct menu_rep { - core_window_t* taken_window{ nullptr }; + basic_window* taken_window{ nullptr }; bool delay_restore{ false }; native_window_type window{ nullptr }; native_window_type owner{ nullptr }; @@ -37,7 +37,7 @@ namespace nana { unsigned event_pump_ref_count{0}; int window_count{0}; //The number of windows - core_window_t* event_window{nullptr}; + basic_window* event_window{nullptr}; struct platform_detail_tag { @@ -46,7 +46,7 @@ namespace nana struct cursor_tag { - core_window_t * window; + basic_window * window; native_window_type native_handle; nana::cursor predef_cursor; HCURSOR handle; @@ -66,7 +66,7 @@ namespace nana unsigned event_pump_ref_count{0}; int window_count{0}; //The number of windows - core_window_t* event_window{nullptr}; + basic_window* event_window{nullptr}; bool is_alt_pressed{false}; bool is_ctrl_pressed{false}; @@ -78,7 +78,7 @@ namespace nana struct cursor_tag { - core_window_t * window; + basic_window * window; native_window_type native_handle; nana::cursor predef_cursor; Cursor handle; diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 3765571f..fcc5c20a 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -213,9 +213,9 @@ namespace detail bedrock::~bedrock() { - if(wd_manager().number_of_core_window()) + if(wd_manager().window_count()) { - std::string msg = "Nana.GUI detects a memory leaks in window_manager, " + std::to_string(wd_manager().number_of_core_window()) + " window(s) are not uninstalled."; + std::string msg = "Nana.GUI detects a memory leaks in window_manager, " + std::to_string(wd_manager().window_count()) + " window(s) are not uninstalled."; std::cerr << msg; /// \todo add list of cations of opening windows and if auto testing GUI do auto OK after 2 seconds. ::MessageBoxA(0, msg.c_str(), ("Nana C++ Library"), MB_OK); } @@ -290,7 +290,7 @@ namespace detail return bedrock_object; } - void bedrock::flush_surface(core_window_t* wd, bool forced, const rectangle* update_area) + void bedrock::flush_surface(basic_window* wd, bool forced, const rectangle* update_area) { if (nana::system::this_thread_id() != wd->thread_id) { @@ -581,7 +581,7 @@ namespace detail case nana::detail::messages::remote_flush_surface: { auto stru = reinterpret_cast(lParam); - bedrock.wd_manager().map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area)); + bedrock.wd_manager().map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area)); ::UpdateWindow(wd); ::HeapFree(::GetProcessHeap(), 0, stru); } @@ -652,7 +652,7 @@ namespace detail return true; } - void adjust_sizing(bedrock::core_window_t* wd, ::RECT * const r, int edge, unsigned req_width, unsigned req_height) + void adjust_sizing(basic_window* wd, ::RECT * const r, int edge, unsigned req_width, unsigned req_height) { unsigned width = static_cast(r->right - r->left) - wd->extra_width; unsigned height = static_cast(r->bottom - r->top) - wd->extra_height; @@ -1638,7 +1638,7 @@ namespace detail return impl_->estore; } - void bedrock::map_through_widgets(core_window_t* wd, native_drawable_type drawable) + void bedrock::map_through_widgets(basic_window* wd, native_drawable_type drawable) { auto graph_context = reinterpret_cast(wd->root_graph->handle()->context); @@ -1685,7 +1685,7 @@ namespace detail } //Dynamically set a cursor for a window - void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + void bedrock::set_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd) { if (nullptr == thrd) thrd = get_thread_context(wd->thread_id); @@ -1730,7 +1730,7 @@ namespace detail } } - void bedrock::define_state_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + void bedrock::define_state_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd) { wd->root_widget->other.attribute.root->state_cursor = cur; wd->root_widget->other.attribute.root->state_cursor_window = wd; @@ -1740,7 +1740,7 @@ namespace detail ::ShowCursor(TRUE); } - void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd) + void bedrock::undefine_state_cursor(basic_window * wd, thread_context* thrd) { HCURSOR rev_handle = ::LoadCursor(nullptr, IDC_ARROW); if (!wd_manager().available(wd)) diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 379d53b6..5b21161b 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -1,7 +1,7 @@ /* * A Drawer Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -342,8 +342,7 @@ namespace nana { if(wd) { - auto iwd = reinterpret_cast(wd); - bool owns_caret = (iwd->annex.caret_ptr) && (iwd->annex.caret_ptr->visible()); + bool owns_caret = (wd->annex.caret_ptr) && (wd->annex.caret_ptr->visible()); //The caret in X11 is implemented by Nana, it is different from Windows' //the caret in X11 is asynchronous, it is hard to hide and show the caret @@ -352,20 +351,20 @@ namespace nana if(owns_caret) { #ifndef NANA_X11 - iwd->annex.caret_ptr->visible(false); + wd->annex.caret_ptr->visible(false); #else - owns_caret = nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, false); + owns_caret = nana::detail::platform_spec::instance().caret_update(wd->root, *wd->root_graph, false); #endif } - edge_nimbus_renderer::instance().render(iwd, forced, update_area); + edge_nimbus_renderer::instance().render(wd, forced, update_area); if(owns_caret) { #ifndef NANA_X11 - iwd->annex.caret_ptr->visible(true); + wd->annex.caret_ptr->visible(true); #else - nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, true); + nana::detail::platform_spec::instance().caret_update(wd->root, *wd->root_graph, true); #endif } } diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index db8b3bb8..c94f363c 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -22,7 +22,7 @@ namespace nana namespace detail { //class window_layout - void window_layout::paint(core_window_t* wd, paint_operation operation, bool req_refresh_children) + void window_layout::paint(basic_window* wd, paint_operation operation, bool req_refresh_children) { if (wd->flags.refreshing && (paint_operation::try_refresh == operation)) return; @@ -41,7 +41,7 @@ namespace nana _m_paint_glass_window(wd, (paint_operation::try_refresh == operation), req_refresh_children, false, true); } - bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool req_refresh_children) + bool window_layout::maproot(basic_window* wd, bool have_refreshed, bool req_refresh_children) { auto check_opaque = wd->seek_non_lite_widget_ancestor(); if (check_opaque && check_opaque->flags.refreshing) @@ -80,7 +80,7 @@ namespace nana return false; } - void window_layout::paste_children_to_graphics(core_window_t* wd, nana::paint::graphics& graph) + void window_layout::paste_children_to_graphics(basic_window* wd, nana::paint::graphics& graph) { _m_paste_children(wd, false, false, rectangle{ wd->pos_root, wd->dimension }, graph, wd->pos_root); } @@ -89,7 +89,7 @@ namespace nana ///@brief Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, /// the visual rectangle is a rectangular block that a window should be displayed on screen. /// The result is a rectangle that is a visible area for its ancestors. - bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual) + bool window_layout::read_visual_rectangle(basic_window* wd, nana::rectangle& visual) { if (! wd->displayed()) return false; @@ -139,7 +139,7 @@ namespace nana //read_overlaps // reads the overlaps that are overlapped a rectangular block - bool window_layout::read_overlaps(core_window_t* wd, const nana::rectangle& vis_rect, std::vector& blocks) + bool window_layout::read_overlaps(basic_window* wd, const nana::rectangle& vis_rect, std::vector& blocks) { auto const is_wd_root = (category::flags::root == wd->other.category); wd_rectangle block; @@ -150,7 +150,7 @@ namespace nana { for (++i; i != wd->parent->children.cend(); ++i) { - core_window_t* cover = *i; + basic_window* cover = *i; if (!cover->visible) continue; @@ -182,7 +182,7 @@ namespace nana return (!blocks.empty()); } - bool window_layout::enable_effects_bground(core_window_t * wd, bool enabled) + bool window_layout::enable_effects_bground(basic_window * wd, bool enabled) { if (category::flags::widget != wd->other.category) return false; @@ -220,15 +220,15 @@ namespace nana //make_bground // update the glass buffer of a glass window. - void window_layout::make_bground(core_window_t* const wd) + void window_layout::make_bground(basic_window* const wd) { nana::point rpos{ wd->pos_root }; auto & glass_buffer = wd->other.glass_buffer; if (category::flags::lite_widget == wd->parent->other.category) { - std::vector layers; - core_window_t * beg = wd->parent; + std::vector layers; + auto beg = wd->parent; while (beg && (category::flags::lite_widget == beg->other.category)) { layers.push_back(beg); @@ -240,11 +240,11 @@ namespace nana nana::rectangle r(wd->pos_owner, wd->dimension); for (auto i = layers.rbegin(), layers_rend = layers.rend(); i != layers_rend; ++i) { - core_window_t * pre = *i; + auto pre = *i; if (false == pre->visible) continue; - core_window_t * term = ((i + 1 != layers_rend) ? *(i + 1) : wd); + auto term = ((i + 1 != layers_rend) ? *(i + 1) : wd); r.position(wd->pos_root - pre->pos_root); for (auto child : pre->children) @@ -289,7 +289,7 @@ namespace nana wd->effect.bground->take_effect(wd, glass_buffer); } - void window_layout::_m_paste_children(core_window_t* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) + void window_layout::_m_paste_children(basic_window* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) { nana::rectangle rect; for (auto child : wd->children) @@ -333,7 +333,7 @@ namespace nana } } - void window_layout::_m_paint_glass_window(core_window_t* wd, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other) + void window_layout::_m_paint_glass_window(basic_window* wd, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other) { //A window which has an empty graphics(and lite-widget) does not notify //glass windows for updating their background. @@ -381,7 +381,7 @@ namespace nana /// Notify the glass windows that are overlapped with the specified visual rectangle. /// If a child window of sigwd is a glass window, it doesn't to be notified. - void window_layout::_m_notify_glasses(core_window_t* const sigwd) + void window_layout::_m_notify_glasses(basic_window* const sigwd) { nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension); for (auto wd : data_sect.effects_bground_windows) @@ -420,7 +420,7 @@ namespace nana else { //test if sigwnd is a parent of glass window x, or a slibing of the glass window, or a child of the slibing of the glass window. - core_window_t *p = wd->parent, *signode = sigwd; + basic_window *p = wd->parent, *signode = sigwd; while (signode->parent && (signode->parent != p)) signode = signode->parent; diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 4464766d..90624598 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -282,7 +282,7 @@ namespace detail paint::image default_icon_big; paint::image default_icon_small; - lite_map>> safe_place; + lite_map>> safe_place; }; //end struct wdm_private_impl @@ -455,7 +455,7 @@ namespace detail delete impl_; } - std::size_t window_manager::number_of_core_window() const + std::size_t window_manager::window_count() const { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -468,14 +468,14 @@ namespace detail return mutex_; } - void window_manager::all_handles(std::vector &v) const + void window_manager::all_handles(std::vector &v) const { //Thread-Safe Required! std::lock_guard lock(mutex_); v = impl_->wd_register.queue(); } - void window_manager::event_filter(core_window_t* wd, bool is_make, event_code evtid) + void window_manager::event_filter(basic_window* wd, bool is_make, event_code evtid) { switch(evtid) { @@ -487,21 +487,21 @@ namespace detail } } - bool window_manager::available(core_window_t* wd) + bool window_manager::available(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); return impl_->wd_register.available(wd); } - bool window_manager::available(core_window_t * a, core_window_t* b) + bool window_manager::available(basic_window * a, basic_window* b) { //Thread-Safe Required! std::lock_guard lock(mutex_); return (impl_->wd_register.available(a) && impl_->wd_register.available(b)); } - window_manager::core_window_t* window_manager::create_root(core_window_t* owner, bool nested, rectangle r, const appearance& app, widget* wdg) + basic_window* window_manager::create_root(basic_window* owner, bool nested, rectangle r, const appearance& app, widget* wdg) { native_window_type native = nullptr; if (owner) @@ -525,7 +525,7 @@ namespace detail auto result = native_interface::create_window(native, nested, r, app); if (result.native_handle) { - auto wd = new core_window_t(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr); + auto wd = new basic_window(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr); if (nested) { wd->owner = nullptr; @@ -553,7 +553,7 @@ namespace detail return nullptr; } - window_manager::core_window_t* window_manager::create_widget(core_window_t* parent, const rectangle& r, bool is_lite, widget* wdg) + basic_window* window_manager::create_widget(basic_window* parent, const rectangle& r, bool is_lite, widget* wdg) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -565,17 +565,17 @@ namespace detail auto wdg_notifier = widget_notifier_interface::get_notifier(wdg); - core_window_t * wd; + basic_window * wd; if (is_lite) - wd = new core_window_t(parent, std::move(wdg_notifier), r, (category::lite_widget_tag**)nullptr); + wd = new basic_window(parent, std::move(wdg_notifier), r, (category::lite_widget_tag**)nullptr); else - wd = new core_window_t(parent, std::move(wdg_notifier), r, (category::widget_tag**)nullptr); + wd = new basic_window(parent, std::move(wdg_notifier), r, (category::widget_tag**)nullptr); impl_->wd_register.insert(wd); return wd; } - void window_manager::close(core_window_t *wd) + void window_manager::close(basic_window *wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -617,7 +617,7 @@ namespace detail //destroy //@brief: Delete the window handle - void window_manager::destroy(core_window_t* wd) + void window_manager::destroy(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -641,7 +641,7 @@ namespace detail update(parent, false, false, &update_area); } - void window_manager::destroy_handle(core_window_t* wd) + void window_manager::destroy_handle(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -654,7 +654,7 @@ namespace detail } } - void window_manager::icon(core_window_t* wd, const paint::image& small_icon, const paint::image& big_icon) + void window_manager::icon(basic_window* wd, const paint::image& small_icon, const paint::image& big_icon) { if(!big_icon.empty() || !small_icon.empty()) { @@ -677,7 +677,7 @@ namespace detail //show //@brief: show or hide a window - bool window_manager::show(core_window_t* wd, bool visible) + bool window_manager::show(basic_window* wd, bool visible) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -702,7 +702,7 @@ namespace detail return true; } - window_manager::core_window_t* window_manager::find_window(native_window_type root, const point& pos, bool ignore_captured) + basic_window* window_manager::find_window(native_window_type root, const point& pos, bool ignore_captured) { if (nullptr == root) return nullptr; @@ -740,7 +740,7 @@ namespace detail } //move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window - bool window_manager::move(core_window_t* wd, int x, int y, bool passive) + bool window_manager::move(basic_window* wd, int x, int y, bool passive) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -789,7 +789,7 @@ namespace detail return false; } - bool window_manager::move(core_window_t* wd, const rectangle& r) + bool window_manager::move(basic_window* wd, const rectangle& r) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -865,7 +865,7 @@ namespace detail // e.g, when the size of window is changed by OS/user, the function should not resize the // window again, otherwise, it causes an infinite loop, because when a root_widget is resized, // window_manager will call the function. - bool window_manager::size(core_window_t* wd, nana::size sz, bool passive, bool ask_update) + bool window_manager::size(basic_window* wd, nana::size sz, bool passive, bool ask_update) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -903,7 +903,7 @@ namespace detail if (wd->dimension == sz) return false; - std::vector presence; + std::vector presence; if (wd->dimension.width < sz.width || wd->dimension.height < sz.height) { @@ -978,9 +978,9 @@ namespace detail return true; } - window_manager::core_window_t* window_manager::root(native_window_type wd) const + basic_window* window_manager::root(native_window_type wd) const { - static std::pair cache; + static std::pair cache; if(cache.first == wd) return cache.second; //Thread-Safe Required! @@ -997,7 +997,7 @@ namespace detail } //Copy the root buffer that wnd specified into DeviceContext - void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area) + void window_manager::map(basic_window* wd, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1009,7 +1009,7 @@ namespace detail //@brief: update is used for displaying the screen-off buffer. // Because of a good efficiency, if it is called in an event procedure and the event procedure window is the // same as update's, update would not map the screen-off buffer and just set the window for lazy refresh - bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area) + bool window_manager::update(basic_window* wd, bool redraw, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1046,13 +1046,13 @@ namespace detail else if (redraw) window_layer::paint(wd, paint_operation::try_refresh, false); - if (wd->other.upd_state == core_window_t::update_state::lazy) - wd->other.upd_state = core_window_t::update_state::refreshed; + if (wd->other.upd_state == basic_window::update_state::lazy) + wd->other.upd_state = basic_window::update_state::refreshed; } return true; } - void window_manager::update_requesters(core_window_t* root_wd) + void window_manager::update_requesters(basic_window* root_wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1075,7 +1075,7 @@ namespace detail } - void window_manager::refresh_tree(core_window_t* wd) + void window_manager::refresh_tree(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1087,7 +1087,7 @@ namespace detail //do_lazy_refresh //@brief: defined a behavior of flush the screen - void window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree) + void window_manager::do_lazy_refresh(basic_window* wd, bool force_copy_to_screen, bool refresh_tree) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1101,11 +1101,11 @@ namespace detail using paint_operation = window_layer::paint_operation; if (wd->visible_parents()) { - if ((wd->other.upd_state == core_window_t::update_state::refreshed) || (wd->other.upd_state == core_window_t::update_state::request_refresh) || force_copy_to_screen) + if ((wd->other.upd_state == basic_window::update_state::refreshed) || (wd->other.upd_state == basic_window::update_state::request_refresh) || force_copy_to_screen) { - if (!wd->try_lazy_update(wd->other.upd_state == core_window_t::update_state::request_refresh)) + if (!wd->try_lazy_update(wd->other.upd_state == basic_window::update_state::request_refresh)) { - window_layer::paint(wd, (wd->other.upd_state == core_window_t::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree); + window_layer::paint(wd, (wd->other.upd_state == basic_window::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree); this->map(wd, force_copy_to_screen); } } @@ -1124,10 +1124,10 @@ namespace detail window_layer::paint(wd, paint_operation::try_refresh, refresh_tree); //only refreshing if it has an invisible parent } - wd->other.upd_state = core_window_t::update_state::none; + wd->other.upd_state = basic_window::update_state::none; } - bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa) + bool window_manager::set_parent(basic_window* wd, basic_window* newpa) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1154,7 +1154,7 @@ namespace detail //set_focus //@brief: set a keyboard focus to a window. this may fire a focus event. - window_manager::core_window_t* window_manager::set_focus(core_window_t* wd, bool root_has_been_focused, arg_focus::reason reason) + basic_window* window_manager::set_focus(basic_window* wd, bool root_has_been_focused, arg_focus::reason reason) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1218,7 +1218,7 @@ namespace detail return prev_focus; } - window_manager::core_window_t* window_manager::capture_redirect(core_window_t* wd) + basic_window* window_manager::capture_redirect(basic_window* wd) { if(attr_.capture.window && (attr_.capture.ignore_children == false) && (attr_.capture.window != wd)) { @@ -1245,12 +1245,12 @@ namespace detail return false; } - window_manager::core_window_t * window_manager::capture_window() const + basic_window * window_manager::capture_window() const { return attr_.capture.window; } - void window_manager::capture_window(core_window_t* wd, bool captured, bool ignore_children) + void window_manager::capture_window(basic_window* wd, bool captured, bool ignore_children) { if (!this->available(wd)) return; @@ -1286,7 +1286,7 @@ namespace detail wd->flags.captured = false; if(attr_cap.size()) { - std::pair last = attr_cap.back(); + std::pair last = attr_cap.back(); attr_cap.pop_back(); if (impl_->wd_register.available(last.first)) @@ -1321,7 +1321,7 @@ namespace detail // this method insert a window which catches an user TAB into a TAB window container // the TAB window container is held by a wd's root widget. Not every widget has a TAB window container, // the container is created while a first Tab Window is setting - void window_manager::enable_tabstop(core_window_t* wd) + void window_manager::enable_tabstop(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1333,7 +1333,7 @@ namespace detail } // preconditions of get_tabstop: tabstop is not empty and at least one window is visible - window_manager::core_window_t* get_tabstop(window_manager::core_window_t* wd, bool forward) + basic_window* get_tabstop(basic_window* wd, bool forward) { auto & tabs = wd->root_widget->other.attribute.root->tabstop; @@ -1348,7 +1348,7 @@ namespace detail if (i != end) { ++i; - window_manager::core_window_t* ts = (i != end ? (*i) : tabs.front()); + basic_window* ts = (i != end ? (*i) : tabs.front()); return (ts != wd ? ts : 0); } else @@ -1364,7 +1364,7 @@ namespace detail return nullptr; } - auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t* + auto window_manager::tabstop(basic_window* wd, bool forward) const -> basic_window* { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1408,7 +1408,7 @@ namespace detail impl_->wd_register.delete_trash(tid); } - bool window_manager::enable_effects_bground(core_window_t* wd, bool enabled) + bool window_manager::enable_effects_bground(basic_window* wd, bool enabled) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1418,7 +1418,7 @@ namespace detail return false; } - bool window_manager::calc_window_point(core_window_t* wd, nana::point& pos) + bool window_manager::calc_window_point(basic_window* wd, nana::point& pos) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1438,7 +1438,7 @@ namespace detail return impl_->misc_register.find(native_wd); } - bool window_manager::register_shortkey(core_window_t* wd, unsigned long key) + bool window_manager::register_shortkey(basic_window* wd, unsigned long key) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1450,7 +1450,7 @@ namespace detail return false; } - void window_manager::unregister_shortkey(core_window_t* wd, bool with_children) + void window_manager::unregister_shortkey(basic_window* wd, bool with_children) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1468,7 +1468,7 @@ namespace detail } } - window_manager::core_window_t* window_manager::find_shortkey(native_window_type native_window, unsigned long key) + basic_window* window_manager::find_shortkey(native_window_type native_window, unsigned long key) { if(native_window) { @@ -1481,7 +1481,7 @@ namespace detail return nullptr; } - void window_manager::set_safe_place(core_window_t* wd, std::function&& fn) + void window_manager::set_safe_place(basic_window* wd, std::function&& fn) { if (fn) { @@ -1523,7 +1523,7 @@ namespace detail return false; } - void window_manager::_m_disengage(core_window_t* wd, core_window_t* for_new) + void window_manager::_m_disengage(basic_window* wd, basic_window* for_new) { auto * const wdpa = wd->parent; @@ -1537,7 +1537,7 @@ namespace detail //Holds the shortkeys of wd and its children, and then //register these shortkeys for establishing. - std::vector> sk_holder; + std::vector> sk_holder; if ((!established) || (pa_root_attr != root_attr)) { @@ -1656,8 +1656,8 @@ namespace detail auto delta_pos = wd->pos_root - for_new->pos_root; - std::function set_pos_root; - set_pos_root = [&set_pos_root](core_window_t* wd, const nana::point& delta_pos) + std::function set_pos_root; + set_pos_root = [&set_pos_root](basic_window* wd, const nana::point& delta_pos) { for (auto child : wd->children) { @@ -1688,7 +1688,7 @@ namespace detail } } - void window_manager::_m_destroy(core_window_t* wd) + void window_manager::_m_destroy(basic_window* wd) { if(wd->flags.destroying) return; @@ -1738,7 +1738,7 @@ namespace detail wd->drawer.graphics.release(); } - void window_manager::_m_move_core(core_window_t* wd, const point& delta) + void window_manager::_m_move_core(basic_window* wd, const point& delta) { if(category::flags::root != wd->other.category) //A root widget always starts at (0, 0) and its children are not to be changed { @@ -1760,7 +1760,7 @@ namespace detail } } - void window_manager::_m_shortkeys(core_window_t* wd, bool with_children, std::vector>& keys) const + void window_manager::_m_shortkeys(basic_window* wd, bool with_children, std::vector>& keys) const { if (impl_->wd_register.available(wd)) { @@ -1785,7 +1785,7 @@ namespace detail //_m_find //@brief: find a window on root window through a given root coordinate. // the given root coordinate must be in the rectangle of wnd. - window_manager::core_window_t* window_manager::_m_find(core_window_t* wd, const point& pos) + basic_window* window_manager::_m_find(basic_window* wd, const point& pos) { if(!wd->visible) return nullptr; @@ -1809,7 +1809,7 @@ namespace detail } //_m_effective, test if the window is a handle of window that specified by (root_x, root_y) - bool window_manager::_m_effective(core_window_t* wd, const point& root_pos) + bool window_manager::_m_effective(basic_window* wd, const point& root_pos) { if(wd == nullptr || false == wd->visible) return false; return rectangle{ wd->pos_root, wd->dimension }.is_hit(root_pos); diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index db01ea30..3d41b9a7 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -260,24 +260,8 @@ namespace detail #if defined(NANA_WINDOWS) ::TextOut(dw->context, pos.x, pos.y, str, static_cast(len)); #elif defined(NANA_X11) - auto disp = ::nana::detail::platform_spec::instance().open_display(); #if defined(NANA_USE_XFT) - - #if 0 - auto fs = reinterpret_cast(dw->font->native_handle()); - - //Fixed missing array declaration by dareg - std::unique_ptr glyphs_ptr(new FT_UInt[len]); - auto glyphs = glyphs_ptr.get(); - const auto endstr = str + len; - for(auto chr = str; chr != endstr; ++chr) - { - (*glyphs++) = XftCharIndex(disp, fs, *chr); - } - XftDrawGlyphs(dw->xftdraw, &(dw->xft_fgcolor), fs, pos.x, pos.y + fs->ascent, glyphs_ptr.get(), len); - #else nana_xft_draw_string(dw->xftdraw, &(dw->xft_fgcolor), dw->font.get(), pos, str, len); - #endif #else XFontSet fs = reinterpret_cast(dw->font->native_handle()); XFontSetExtents * ext = ::XExtentsOfFontSet(fs); diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index c3c4b97e..c622aa3f 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -506,8 +506,8 @@ namespace paint if (!text.empty()) { - unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; #if defined(NANA_WINDOWS) + unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; int * dx = new int[text.size()]; SIZE extents; ::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast(text.size()), 0, 0, dx, &extents); @@ -520,26 +520,7 @@ namespace paint } delete[] dx; #elif defined(NANA_X11) && defined(NANA_USE_XFT) - - #if 0 - 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 < text.size(); ++i) - { - 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 return nana_xft_glyph_pixels(impl_->handle->font.get(), text.data(), text.size()); - #endif #endif } return pxbuf; diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index 6628132a..bd6e498c 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -263,8 +263,8 @@ namespace nana{ namespace system{ spec.lock_xlib(); { - internal_scope_guard isg; - detail::bedrock::core_window_t * wd = detail::bedrock::instance().focus(); + internal_scope_guard lock; + auto wd = detail::bedrock::instance().focus(); if(wd) requester = wd->root; } spec.unlock_xlib(); From 46b5e423b5477df37ff2ddebd47c63ab1bcac48b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 1 Jul 2019 07:31:33 +0800 Subject: [PATCH 52/61] remove unused class --- source/gui/detail/bedrock_posix.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index e04278f8..b3ed3fb4 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -554,29 +554,6 @@ namespace detail context.is_alt_pressed = false; } -#if 0 - class window_proc_guard - { - public: - window_proc_guard(detail::basic_window* wd) : - root_wd_(wd) - { - root_wd_->other.attribute.root->lazy_update = true; - } - - ~window_proc_guard() - { - if (!bedrock::instance().wd_manager().available(root_wd_)) - return; - - root_wd_->other.attribute.root->lazy_update = false; - root_wd_->other.attribute.root->update_requesters.clear(); - } - private: - detail::basic_window* const root_wd_; - }; -#endif - void window_proc_for_xevent(Display* /*display*/, XEvent& xevent) { static auto& brock = detail::bedrock::instance(); From 7e310f33f739693482f220479b7c7ae19c4cfc7f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 1 Jul 2019 07:56:29 +0800 Subject: [PATCH 53/61] remove deprecated code --- source/detail/mswin/platform_spec.hpp | 9 --------- source/detail/platform_spec_posix.cpp | 12 ------------ source/detail/platform_spec_windows.cpp | 12 ------------ source/detail/posix/platform_spec.hpp | 8 -------- 4 files changed, 41 deletions(-) diff --git a/source/detail/mswin/platform_spec.hpp b/source/detail/mswin/platform_spec.hpp index 5c0ad5ab..ae83562d 100644 --- a/source/detail/mswin/platform_spec.hpp +++ b/source/detail/mswin/platform_spec.hpp @@ -107,17 +107,8 @@ namespace detail drawable_impl_type(); ~drawable_impl_type(); -#if 0 //deprecated - unsigned get_color() const; - unsigned get_text_color() const; -#endif void set_color(const ::nana::color&); void set_text_color(const ::nana::color&); -#if 0 //deprecated - private: - unsigned color_{ 0xffffffff }; - unsigned text_color_{0xffffffff}; -#endif }; class platform_spec diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index 5f74dc67..b0ef6c11 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -341,18 +341,6 @@ namespace detail string.whitespace_pixels = 0; } -#if 0 //deprecated - unsigned drawable_impl_type::get_color() const - { - return color_; - } - - unsigned drawable_impl_type::get_text_color() const - { - return text_color_; - } -#endif - void drawable_impl_type::set_color(const ::nana::color& clr) { bgcolor_rgb = (clr.px_color().value & 0xFFFFFF); diff --git a/source/detail/platform_spec_windows.cpp b/source/detail/platform_spec_windows.cpp index f659b054..0fc7d8bc 100644 --- a/source/detail/platform_spec_windows.cpp +++ b/source/detail/platform_spec_windows.cpp @@ -42,18 +42,6 @@ namespace detail ::DeleteObject(pixmap); } -#if 0 //deprecated - unsigned drawable_impl_type::get_color() const - { - return color_; - } - - unsigned drawable_impl_type::get_text_color() const - { - return text_color_; - } -#endif - #define NANA_WINDOWS_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) void drawable_impl_type::set_color(const ::nana::color& clr) diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index 57a61d1e..83d91616 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -90,10 +90,6 @@ namespace detail #endif drawable_impl_type(); -#if 0 //deprecated - unsigned get_color() const; - unsigned get_text_color() const; -#endif void set_color(const ::nana::color&); void set_text_color(const ::nana::color&); @@ -104,10 +100,6 @@ namespace detail drawable_impl_type& operator=(const drawable_impl_type&) = delete; unsigned current_color_{ 0xFFFFFF }; -#if 0 //deprecated - unsigned color_{ 0xFFFFFFFF }; - unsigned text_color_{ 0xFFFFFFFF }; -#endif }; struct atombase_tag From d845a82dc4e1412b57713f760193a4fa39cec2de Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Sat, 6 Jul 2019 14:18:24 -0400 Subject: [PATCH 54/61] fixed another listbox selection bug a display position was searched for in a set of absolute positions --- source/gui/widgets/listbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 7dcb2b43..7201af43 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -4334,7 +4334,7 @@ namespace nana else { auto selected = lister.pick_items(true); - if (selected.cend() != std::find(selected.cbegin(), selected.cend(), item_pos)) + if (selected.cend() != std::find(selected.cbegin(), selected.cend(), abs_item_pos)) { //If the current selected one has been selected before selecting, remains the selection states for all //selected items. But these items will be unselected when the mouse is released. From 5acbbf548eff27de12c30e96e828c7bd0322cc28 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 10 Jul 2019 04:25:00 +0800 Subject: [PATCH 55/61] refactoring and fix fix a potential dead-lock caused by timer --- include/nana/gui.hpp | 55 ++++++++++++++++- include/nana/gui/compact.hpp | 57 +++++++++++++++++ include/nana/gui/wvl.hpp | 88 --------------------------- source/gui/detail/bedrock_pi.cpp | 3 +- source/gui/detail/bedrock_windows.cpp | 3 +- source/gui/msgbox.cpp | 4 +- source/gui/timer.cpp | 25 +++----- source/gui/widgets/categorize.cpp | 4 +- source/gui/widgets/combox.cpp | 4 +- source/gui/widgets/listbox.cpp | 2 +- source/gui/widgets/menu.cpp | 3 +- source/gui/wvl.cpp | 5 +- source/unicode_bidi.cpp | 14 +++++ 13 files changed, 152 insertions(+), 115 deletions(-) create mode 100644 include/nana/gui/compact.hpp delete mode 100644 include/nana/gui/wvl.hpp diff --git a/include/nana/gui.hpp b/include/nana/gui.hpp index 70bcb077..09c2f7b9 100644 --- a/include/nana/gui.hpp +++ b/include/nana/gui.hpp @@ -1 +1,54 @@ -#include "gui/wvl.hpp" \ No newline at end of file +/** + * Nana GUI Header + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui.hpp + * @description + * the header file contains the files required for running of Nana.GUI + */ + +#ifndef NANA_GUI_HPP +#define NANA_GUI_HPP + +#include "gui/compact.hpp" +#include "gui/screen.hpp" +#include "gui/widgets/form.hpp" +#include "gui/drawing.hpp" +#include "gui/msgbox.hpp" +#include "gui/place.hpp" + + +namespace nana +{ +#ifdef NANA_AUTOMATIC_GUI_TESTING + + /// @brief Take control of the GUI and optionally automatically tests it. + /// + /// @detail It transfers to nana the program flow control, which begin pumping messages + /// from the underlying OS, interpreting and sending it with suitable arguments + /// to the nana widgets that registered a response in the corresponding event. + /// It also accept arguments to be used in case of automatic GUI testing. + /// Other Way the arguments are ignored. + void exec( + unsigned wait = 1, ///< for the GUI to be constructed, in seconds + unsigned wait_end = 1, ///< for the GUI to be destructed, in seconds + std::function = {} ///< emit events to mimics user actions and may assert results + ); + + /// send a click message to this widget - useful in GUI testing + void click(widget& w); + + /// in seconds + void Wait(unsigned wait = 0); +#else + void exec(); +#endif + + +}//end namespace nana +#endif diff --git a/include/nana/gui/compact.hpp b/include/nana/gui/compact.hpp new file mode 100644 index 00000000..c4a9789a --- /dev/null +++ b/include/nana/gui/compact.hpp @@ -0,0 +1,57 @@ +/** + * Nana GUI Library Definition + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui/compact.hpp + * @description + * the header file contains the files required for running of Nana.GUI + */ + +#ifndef NANA_GUI_WVL_HPP +#define NANA_GUI_WVL_HPP + +#include "programming_interface.hpp" + +namespace nana +{ + namespace detail + { + struct form_loader_private + { + template friend class form_loader; + private: + static void insert_form(::nana::widget*); + }; + + template + class form_loader + { + public: + template + Form & operator()(Args &&... args) const + { + auto p = new Form(std::forward(args)...); + + if (p->empty()) + throw std::runtime_error("form_loader failed to create the form"); + + + detail::form_loader_private::insert_form(p); + if (IsVisible) + p->show(); + + return *p; + } + + }; + } + + template + using form_loader = detail::form_loader; +}//end namespace nana +#endif diff --git a/include/nana/gui/wvl.hpp b/include/nana/gui/wvl.hpp deleted file mode 100644 index c18be253..00000000 --- a/include/nana/gui/wvl.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Nana GUI Library Definition - * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - * @file nana/gui/wvl.hpp - * @description - * the header file contains the files required for running of Nana.GUI - */ - -#ifndef NANA_GUI_WVL_HPP -#define NANA_GUI_WVL_HPP - -#include "programming_interface.hpp" -#include "screen.hpp" -#include "widgets/form.hpp" -#include "drawing.hpp" -#include "msgbox.hpp" -#include "place.hpp" - - -namespace nana -{ - namespace detail - { - struct form_loader_private - { - template friend class form_loader; - private: - static void insert_form(::nana::widget*); - }; - - template - class form_loader - { - public: - template - Form & operator()(Args &&... args) const - { - auto p = new Form(std::forward(args)...); - - if (p->empty()) - throw std::logic_error("form_loader failed to create the form"); - - detail::form_loader_private::insert_form(p); - if (IsVisible) - p->show(); - - return *p; - } - - }; - } - - template - using form_loader = detail::form_loader; - -#ifdef NANA_AUTOMATIC_GUI_TESTING - - /// @brief Take control of the GUI and optionally automatically tests it. - /// - /// @detail It transfers to nana the program flow control, which begin pumping messages - /// from the underlying OS, interpreting and sending it with suitable arguments - /// to the nana widgets that registered a response in the corresponding event. - /// It also accept arguments to be used in case of automatic GUI testing. - /// Other Way the arguments are ignored. - void exec( - unsigned wait = 1, ///< for the GUI to be constructed, in seconds - unsigned wait_end = 1, ///< for the GUI to be destructed, in seconds - std::function = {} ///< emit events to mimics user actions and may assert results - ); - - /// send a click message to this widget - useful in GUI testing - void click(widget& w); - - /// in seconds - void Wait(unsigned wait = 0); -#else - void exec(); -#endif - - -}//end namespace nana -#endif diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index bf4e387b..5f31b3d2 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -13,10 +13,11 @@ #include "../../detail/platform_spec_selector.hpp" #include "basic_window.hpp" #include "bedrock_types.hpp" +#include +#include #include #include #include -#include #include #include #include diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index fcc5c20a..829c909a 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -18,7 +18,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index d11816fa..1c825da1 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -12,7 +12,9 @@ * James Bremner */ -#include +#include +#include +#include #include #include #include diff --git a/source/gui/timer.cpp b/source/gui/timer.cpp index 52981a8e..970aa5ab 100644 --- a/source/gui/timer.cpp +++ b/source/gui/timer.cpp @@ -43,8 +43,6 @@ namespace nana class timer_driver { - typedef std::lock_guard lock_guard; - friend class timer_core; timer_driver() = default; @@ -70,7 +68,7 @@ namespace nana auto tmid = p; ::nana::detail::platform_spec::instance().set_timer(reinterpret_cast(tmid), ms, &timer_driver::_m_timer_proc); #endif - lock_guard lock(mutex_); + ::nana::internal_scope_guard lock; timer_table_[tmid].reset(p); return p; } @@ -82,7 +80,8 @@ namespace nana void destroy(timer_identifier tid) { - lock_guard lock(mutex_); + ::nana::internal_scope_guard lock; + auto i = timer_table_.find(tid); if (i != timer_table_.end()) { @@ -101,7 +100,6 @@ namespace nana static void _m_timer_proc(std::size_t id); #endif private: - std::recursive_mutex mutex_; std::map> timer_table_; }; @@ -141,21 +139,19 @@ namespace nana nana::basic_event & evt_elapse_; }; //end class timer_core + #if defined(NANA_WINDOWS) void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR id, DWORD /*dwTime*/) #else void timer_driver::_m_timer_proc(std::size_t id) #endif { - auto & driver = instance(); + auto & time_tbl = instance().timer_table_; - lock_guard lock(driver.mutex_); -#if defined(NANA_WINDOWS) - auto i = driver.timer_table_.find(id); -#else - auto i = driver.timer_table_.find(reinterpret_cast(id)); -#endif - if (i == driver.timer_table_.end()) + ::nana::internal_scope_guard lock; + + auto i = time_tbl.find(id); + if (i == time_tbl.end()) return; arg_elapse arg; @@ -183,8 +179,7 @@ namespace nana timer::~timer() { - if (impl_->tm_core) - timer_driver::instance().destroy(impl_->tm_core->id()); + stop(); delete impl_; } diff --git a/source/gui/widgets/categorize.cpp b/source/gui/widgets/categorize.cpp index fc88b2cc..596d7cd3 100644 --- a/source/gui/widgets/categorize.cpp +++ b/source/gui/widgets/categorize.cpp @@ -1,7 +1,7 @@ /** * A Categorize Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -10,7 +10,7 @@ * @file nana/gui/widgets/categorize.cpp */ -#include +#include #include #include #include diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index c5ef5f85..816d4ee9 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -10,9 +10,9 @@ * @file: nana/gui/widgets/combox.cpp */ -#include -#include +#include #include +#include #include #include #include diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 43b7615e..460e28f4 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -15,7 +15,7 @@ * Benjamin Navarro(pr#81) * besh81(pr#130) * dankan1890(pr#158) - * ErrorFlynn(pr#418) + * ErrorFlynn(pr#418,pr#448,pr#454) * */ #include diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 389b39b9..078844aa 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -13,12 +13,13 @@ * dankan1890(pr#158) */ +#include +#include #include #include #include #include -#include #include #include //introduces tolower #include diff --git a/source/gui/wvl.cpp b/source/gui/wvl.cpp index e280aef8..103355b1 100644 --- a/source/gui/wvl.cpp +++ b/source/gui/wvl.cpp @@ -1,6 +1,6 @@ /* * Nana GUI Library Definition - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -11,7 +11,8 @@ * the file contains the files required for running of Nana.GUI */ -#include +#include +#include #include #include #include diff --git a/source/unicode_bidi.cpp b/source/unicode_bidi.cpp index 7b054e10..f71645c5 100644 --- a/source/unicode_bidi.cpp +++ b/source/unicode_bidi.cpp @@ -1,3 +1,17 @@ +/* + * Unicode Bidi-Language Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/unicode_bidi.cpp + * @contributors: + * glavangeorge(pr#440) + + */ #include #include From c1b5b87ec353091f48147ecb9807ae7b1a3bcc13 Mon Sep 17 00:00:00 2001 From: besh81 Date: Thu, 11 Jul 2019 17:20:48 +0200 Subject: [PATCH 56/61] Fixed issue on dockpane close Now closing a dockpane when the x button is inside the place area don't show the dock indicator anymore. --- source/gui/place_parts.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 74dda204..03e21894 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -126,6 +126,12 @@ namespace nana { close_fn_ = std::move(fn); } + + bool hit_close() + { + return x_pointed_; + } + private: virtual void attached(widget_reference wdg, graph_reference graph) override { @@ -310,7 +316,9 @@ namespace nana { move_pos += moves_.start_container_pos; API::move_window(container_->handle(), move_pos); - notifier_->notify_move(); + + if(!caption_.get_drawer_trigger().hit_close()) + notifier_->notify_move(); } } } From 07871b1f36ff0f29639235f17092710d55e1075b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 14 Jul 2019 13:40:17 +0800 Subject: [PATCH 57/61] refactor the implementation of timer in Linux --- include/nana/gui/timer.hpp | 6 +- source/detail/platform_spec_posix.cpp | 80 +++++++++++++-------------- source/detail/posix/platform_spec.hpp | 11 +++- source/gui/msgbox.cpp | 1 + source/gui/timer.cpp | 67 ++++++++++++---------- 5 files changed, 91 insertions(+), 74 deletions(-) diff --git a/include/nana/gui/timer.hpp b/include/nana/gui/timer.hpp index 699be103..c360884b 100644 --- a/include/nana/gui/timer.hpp +++ b/include/nana/gui/timer.hpp @@ -22,14 +22,16 @@ namespace nana { - /// Can repeatedly call a piece of code. + + class timer; struct arg_elapse : public event_arg { - long long id; //timer identifier; + timer* sender; //indicates which timer emitted this notification }; + /// Can repeatedly call a piece of code. class timer { struct implement; diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index b0ef6c11..8944468b 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -210,15 +210,15 @@ namespace detail class timer_runner { - typedef void (*timer_proc_t)(std::size_t id); + using handler_type = void(*)(const timer_core*); struct timer_tag { - std::size_t id; - thread_t tid; + const timer_core* handle; + thread_t thread_id; std::size_t interval; std::size_t timestamp; - timer_proc_t proc; + handler_type handler; }; //timer_group @@ -234,32 +234,32 @@ namespace detail struct timer_group { bool proc_entered{false}; //This flag indicates whether the timers are going to do event. - std::set timers; - std::vector delay_deleted; + std::set timers; + std::vector delay_deleted; }; public: timer_runner() : is_proc_handling_(false) {} - void set(std::size_t id, std::size_t interval, timer_proc_t proc) + void set(const timer_core* handle, std::size_t interval, handler_type handler) { - auto i = holder_.find(id); + auto i = holder_.find(handle); if(i != holder_.end()) { i->second.interval = interval; - i->second.proc = proc; + i->second.handler = handler; return; } auto tid = nana::system::this_thread_id(); - threadmap_[tid].timers.insert(id); + threadmap_[tid].timers.insert(handle); - timer_tag & tag = holder_[id]; - tag.id = id; - tag.tid = tid; + timer_tag & tag = holder_[handle]; + tag.handle = handle; + tag.thread_id = tid; tag.interval = interval; tag.timestamp = 0; - tag.proc = proc; + tag.handler = handler; } bool is_proc_handling() const @@ -267,12 +267,12 @@ namespace detail return is_proc_handling_; } - void kill(std::size_t id) + bool kill(const timer_core* handle) { - auto i = holder_.find(id); + auto i = holder_.find(handle); if(i != holder_.end()) { - auto tid = i->second.tid; + auto tid = i->second.thread_id; auto ig = threadmap_.find(tid); if(ig != threadmap_.end()) //Generally, the ig should not be the end of threadmap_ @@ -280,20 +280,16 @@ namespace detail auto & group = ig->second; if(!group.proc_entered) { - group.timers.erase(id); + group.timers.erase(handle); if(group.timers.empty()) threadmap_.erase(ig); } else - group.delay_deleted.push_back(id); + group.delay_deleted.push_back(handle); } holder_.erase(i); } - } - - bool empty() const - { - return (holder_.empty()); + return holder_.empty(); } void timer_proc(thread_t tid) @@ -315,7 +311,7 @@ namespace detail tag.timestamp = ticks; try { - tag.proc(tag.id); + tag.handler(tag.handle); }catch(...){} //nothrow } } @@ -331,7 +327,7 @@ namespace detail private: bool is_proc_handling_; std::map threadmap_; - std::map holder_; + std::map holder_; }; drawable_impl_type::drawable_impl_type() @@ -439,7 +435,7 @@ namespace detail } platform_spec::timer_runner_tag::timer_runner_tag() - : runner(0), delete_declared(false) + : runner(nullptr), delete_declared(false) {} platform_spec::platform_spec() @@ -981,30 +977,32 @@ namespace detail return r; } - void platform_spec::set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t)) + void platform_spec::set_timer(const timer_core* handle, std::size_t interval, void (*timer_proc)(const timer_core*)) { std::lock_guard lock(timer_.mutex); - if(0 == timer_.runner) + if(!timer_.runner) timer_.runner = new timer_runner; - timer_.runner->set(id, interval, timer_proc); + + timer_.runner->set(handle, interval, timer_proc); timer_.delete_declared = false; } - void platform_spec::kill_timer(std::size_t id) + void platform_spec::kill_timer(const timer_core* handle) { - if(timer_.runner == 0) return; - std::lock_guard lock(timer_.mutex); - timer_.runner->kill(id); - if(timer_.runner->empty()) + if(timer_.runner) { - if(timer_.runner->is_proc_handling() == false) + // Test if there is not a timer after killing + if(timer_.runner->kill(handle)) { - delete timer_.runner; - timer_.runner = 0; + if(timer_.runner->is_proc_handling() == false) + { + delete timer_.runner; + timer_.runner = nullptr; + } + else + timer_.delete_declared = true; } - else - timer_.delete_declared = true; } } @@ -1017,7 +1015,7 @@ namespace detail if(timer_.delete_declared) { delete timer_.runner; - timer_.runner = 0; + timer_.runner = nullptr; timer_.delete_declared = false; } } diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index 83d91616..ff37717e 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -146,6 +146,13 @@ namespace detail //A forward declaration of caret data struct caret_rep; + /// class timer_core + /** + * Platform-spec only provides the declaration for intrducing a handle type, the definition + * of timer_core is given by gui/timer.cpp + */ + class timer_core; + class timer_runner; class platform_scope_guard @@ -226,8 +233,8 @@ namespace detail //when native_interface::show a window that is registered as a grab //window, the native_interface grabs the window. Window grab(Window); - void set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t id)); - void kill_timer(std::size_t id); + void set_timer(const timer_core*, std::size_t interval, void (*timer_proc)(const timer_core* tm)); + void kill_timer(const timer_core*); void timer_proc(thread_t tid); //Message dispatcher diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 1c825da1..9d0467d0 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/source/gui/timer.cpp b/source/gui/timer.cpp index 970aa5ab..8374a5fb 100644 --- a/source/gui/timer.cpp +++ b/source/gui/timer.cpp @@ -28,22 +28,26 @@ #if defined(NANA_WINDOWS) #include #elif defined(NANA_POSIX) -#include "../detail/platform_spec_selector.hpp" +#include "../detail/posix/platform_spec.hpp" #include #endif namespace nana { - class timer_core; + namespace detail + { + class timer_core; + } + #if defined(NANA_WINDOWS) typedef UINT_PTR timer_identifier; #else - typedef timer_core* timer_identifier; + typedef const detail::timer_core* timer_identifier; #endif class timer_driver { - friend class timer_core; + friend class detail::timer_core; timer_driver() = default; public: @@ -54,7 +58,7 @@ namespace nana } template - timer_core* create(unsigned ms, Factory && factory) + detail::timer_core* create(unsigned ms, Factory && factory) { #if defined(NANA_WINDOWS) auto tmid = ::SetTimer(nullptr, 0, ms, &timer_driver::_m_timer_proc); @@ -66,7 +70,7 @@ namespace nana #else auto p = factory(); auto tmid = p; - ::nana::detail::platform_spec::instance().set_timer(reinterpret_cast(tmid), ms, &timer_driver::_m_timer_proc); + ::nana::detail::platform_spec::instance().set_timer(tmid, ms, &timer_driver::_m_timer_proc); #endif ::nana::internal_scope_guard lock; timer_table_[tmid].reset(p); @@ -78,17 +82,17 @@ namespace nana return nullptr; } - void destroy(timer_identifier tid) + void destroy(timer_identifier handle) { ::nana::internal_scope_guard lock; - auto i = timer_table_.find(tid); + auto i = timer_table_.find(handle); if (i != timer_table_.end()) { #if defined(NANA_WINDOWS) - ::KillTimer(nullptr, tid); + ::KillTimer(nullptr, handle); #else - ::nana::detail::platform_spec::instance().kill_timer(reinterpret_cast(tid)); + ::nana::detail::platform_spec::instance().kill_timer(handle); #endif timer_table_.erase(i); } @@ -97,22 +101,26 @@ namespace nana #if defined(NANA_WINDOWS) static void __stdcall _m_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime); #else - static void _m_timer_proc(std::size_t id); + static void _m_timer_proc(timer_identifier id); #endif private: - std::map> timer_table_; + std::map> timer_table_; }; - class timer_core + class detail::timer_core { public: #if defined(NANA_WINDOWS) - timer_core(timer_identifier tmid, basic_event& evt_elapse) - : timer_(tmid), evt_elapse_(evt_elapse) + timer_core(timer* sender, timer_identifier tmid, basic_event& evt_elapse): + sender_(sender), + timer_(tmid), + evt_elapse_(evt_elapse) {} #else - timer_core(basic_event& evt_elapse) - : timer_(this), evt_elapse_(evt_elapse) + timer_core(timer* sender, basic_event& evt_elapse): + sender_(sender), + timer_(this), + evt_elapse_(evt_elapse) {} #endif @@ -126,43 +134,44 @@ namespace nana #if defined(NANA_WINDOWS) ::SetTimer(nullptr, timer_, ms, &timer_driver::_m_timer_proc); #else - ::nana::detail::platform_spec::instance().set_timer(reinterpret_cast(timer_), ms, &timer_driver::_m_timer_proc); + ::nana::detail::platform_spec::instance().set_timer(timer_, ms, &timer_driver::_m_timer_proc); #endif } - void emit(const arg_elapse& arg) + void emit() { + arg_elapse arg; + arg.sender = sender_; evt_elapse_.emit(arg, nullptr); } private: + timer * const sender_; const timer_identifier timer_; nana::basic_event & evt_elapse_; }; //end class timer_core #if defined(NANA_WINDOWS) - void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR id, DWORD /*dwTime*/) + void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR handle, DWORD /*dwTime*/) #else - void timer_driver::_m_timer_proc(std::size_t id) + void timer_driver::_m_timer_proc(timer_identifier handle) #endif { auto & time_tbl = instance().timer_table_; ::nana::internal_scope_guard lock; - auto i = time_tbl.find(id); + auto i = time_tbl.find(handle); if (i == time_tbl.end()) return; - arg_elapse arg; - arg.id = id; - i->second->emit(arg); + i->second->emit(); } struct timer::implement { - unsigned interval = 1000; //Defaultly 1 second. - timer_core * tm_core = nullptr; + unsigned interval{ 1000 }; //1 second in default + detail::timer_core * tm_core{ nullptr }; }; //class timer @@ -196,12 +205,12 @@ namespace nana #if defined(NANA_WINDOWS) impl_->tm_core = timer_driver::instance().create(impl_->interval, [this](timer_identifier id) { - return new timer_core(id, elapse_); + return new detail::timer_core(this, id, elapse_); }); #else impl_->tm_core = timer_driver::instance().create(impl_->interval, [this] { - return new timer_core(elapse_); + return new detail::timer_core(this, elapse_); }); #endif } From 3c841ee0c44174ff4e635b564dc0519e089cce24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A7=80=ED=95=9C?= Date: Mon, 15 Jul 2019 23:26:16 +0900 Subject: [PATCH 58/61] add build script files for vc2019 --- build/vc2019/nana.sln | 28 ++ build/vc2019/nana.vcxproj | 316 +++++++++++++++++++ build/vc2019/nana.vcxproj.filters | 489 ++++++++++++++++++++++++++++++ 3 files changed, 833 insertions(+) create mode 100644 build/vc2019/nana.sln create mode 100644 build/vc2019/nana.vcxproj create mode 100644 build/vc2019/nana.vcxproj.filters diff --git a/build/vc2019/nana.sln b/build/vc2019/nana.sln new file mode 100644 index 00000000..d01415ee --- /dev/null +++ b/build/vc2019/nana.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.4 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{42D0520F-EFA5-4831-84FE-2B9085301C5D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x64.ActiveCfg = Debug|x64 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x64.Build.0 = Debug|x64 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x86.ActiveCfg = Debug|Win32 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x86.Build.0 = Debug|Win32 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x64.ActiveCfg = Release|x64 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x64.Build.0 = Release|x64 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x86.ActiveCfg = Release|Win32 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vc2019/nana.vcxproj b/build/vc2019/nana.vcxproj new file mode 100644 index 00000000..34b0b29d --- /dev/null +++ b/build/vc2019/nana.vcxproj @@ -0,0 +1,316 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {42D0520F-EFA5-4831-84FE-2B9085301C5D} + Win32Proj + nana + + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + ..\..\include;$(IncludePath) + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + + + ..\..\include;$(IncludePath) + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + + + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\include;$(IncludePath) + + + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\include;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + true + stdcpplatest + + + Windows + + + + + + + Level3 + Disabled + _DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + true + stdcpplatest + + + Windows + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + stdcpplatest + + + Windows + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + stdcpplatest + + + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vc2019/nana.vcxproj.filters b/build/vc2019/nana.vcxproj.filters new file mode 100644 index 00000000..4923833d --- /dev/null +++ b/build/vc2019/nana.vcxproj.filters @@ -0,0 +1,489 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {81850bad-7436-405a-beb5-357c5e34f039} + + + {44582b36-4575-4663-ac02-e80417f95d05} + + + {b7e3cdb7-99ac-473d-86c8-53dddce70480} + + + {02fa693c-edc1-4e04-bf1d-ec3c2a89182a} + + + {cffe7506-b96c-42aa-a747-41b5115d9580} + + + {b6b2c032-c6a4-4884-8c14-eca4aa69ef0c} + + + {58f2e0f8-4d63-40db-807d-d7adf71c4ebe} + + + {f288a25d-3ce8-4c2e-a86f-9aeda44bc557} + + + {90b2da01-605d-489b-b6c5-2af8d3c2d8a6} + + + {430feed0-e1d9-45cb-8d59-e1a48a04d19f} + + + {dcf62634-a658-453b-a58d-f1a96a12a8b8} + + + {c1cdf46a-519f-422a-947f-39e173045414} + + + {d68bd89c-170f-445f-b79f-aa03c881ab6b} + + + {a5d87649-2cd1-4a8f-a1f9-7151eaf6c772} + + + {0e6a58ab-652c-45d7-b9aa-8d9f2fa80ea1} + + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources\audio\detail + + + Sources\audio\detail + + + Sources\audio\detail + + + Sources\audio + + + Sources\detail + + + Sources\filesystem + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\widgets\skeletons + + + Sources\gui\widgets\skeletons + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\paint\detail + + + Sources\paint\detail + + + Sources\paint + + + Sources\paint + + + Sources\paint + + + Sources\paint + + + Sources\paint + + + Sources\system + + + Sources\system + + + Sources\system + + + Sources\system + + + Sources\threads + + + Sources\detail + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include\gui + + + + + Include + + + Include + + + \ No newline at end of file From 641d4c263d09274a5be91b8381ad01226e1ae475 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 16 Jul 2019 03:32:23 +0800 Subject: [PATCH 59/61] small change --- source/gui/place_parts.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 03e21894..85ef8dfe 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -127,7 +127,7 @@ namespace nana close_fn_ = std::move(fn); } - bool hit_close() + bool hit_close() const { return x_pointed_; } From 496d157b4bf0d09cb83a352ceea1e1b48c1d1c3c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 18 Jul 2019 21:29:02 +0800 Subject: [PATCH 60/61] fix memory leak in class pool(#455) --- source/threads/pool.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/threads/pool.cpp b/source/threads/pool.cpp index d4b3af2f..c58f6d58 100644 --- a/source/threads/pool.cpp +++ b/source/threads/pool.cpp @@ -141,6 +141,7 @@ namespace threads ::pthread_join(thr->handle, 0); ::pthread_detach(thr->handle); #endif + delete thr; } std::lock_guard lock(mutex_); From 2e0f29564fd51124012dfd7ac8b85be8b7968950 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 20 Jul 2019 11:44:53 +0800 Subject: [PATCH 61/61] fix MinGW warnings of compiling dragdrop.cpp --- source/gui/dragdrop.cpp | 523 ++++++++++++++++++++-------------------- 1 file changed, 267 insertions(+), 256 deletions(-) diff --git a/source/gui/dragdrop.cpp b/source/gui/dragdrop.cpp index 900d86c0..5711fbd5 100644 --- a/source/gui/dragdrop.cpp +++ b/source/gui/dragdrop.cpp @@ -1,7 +1,7 @@ /** * Drag and Drop Implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2018 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -157,10 +157,16 @@ namespace nana }; #ifdef NANA_WINDOWS + template - class win32com_iunknown : public Interface + class win32com_iunknown final: public Interface { public: + template + win32com_iunknown(Args&& ... args) : + Interface(std::forward(args)...) + {} + //Implements IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { @@ -188,6 +194,7 @@ namespace nana LONG ref_count_{ 1 }; }; + class win32com_drop_target : public IDropTarget, public dragdrop_session { public: @@ -273,296 +280,300 @@ namespace nana DWORD effect_{ DROPEFFECT_NONE }; }; - class drop_source : public win32com_iunknown +class drop_source_impl : public IDropSource +{ +public: + drop_source_impl(window wd) : + window_handle_(wd) + {} + + window source() const { - public: - drop_source(window wd) : - window_handle_(wd) - {} - - window source() const - { - return window_handle_; - } - private: - // IDropSource - STDMETHODIMP QueryContinueDrag(BOOL esc_pressed, DWORD key_state) override - { - if (esc_pressed) - return DRAGDROP_S_CANCEL; - - //Drop the object if left button is released. - if (0 == (key_state & (MK_LBUTTON))) - return DRAGDROP_S_DROP; - - return S_OK; - } - - STDMETHODIMP GiveFeedback(DWORD effect) override - { - return DRAGDROP_S_USEDEFAULTCURSORS; - } - private: - window const window_handle_; - }; - - class win32_dropdata : public win32com_iunknown + return window_handle_; + } +private: + // IDropSource + STDMETHODIMP QueryContinueDrag(BOOL esc_pressed, DWORD key_state) override { - public: - struct data_entry + if (esc_pressed) + return DRAGDROP_S_CANCEL; + + //Drop the object if left button is released. + if (0 == (key_state & (MK_LBUTTON))) + return DRAGDROP_S_DROP; + + return S_OK; + } + + STDMETHODIMP GiveFeedback(DWORD effect) override + { + return DRAGDROP_S_USEDEFAULTCURSORS; + } +private: + window const window_handle_; +}; +using drop_source = win32com_iunknown; + + +class win32_dropdata_impl: public IDataObject +{ +public: + struct data_entry + { + FORMATETC format; + STGMEDIUM medium; + bool read_from; //Indicates the data which is used for reading. + + ~data_entry() { - FORMATETC format; - STGMEDIUM medium; - bool read_from; //Indicates the data which is used for reading. + ::CoTaskMemFree(format.ptd); + ::ReleaseStgMedium(&medium); + } - ~data_entry() - { - ::CoTaskMemFree(format.ptd); - ::ReleaseStgMedium(&medium); - } - - bool compare(const FORMATETC& fmt, bool rdfrom) const - { - return (format.cfFormat == fmt.cfFormat && - (format.tymed & fmt.tymed) != 0 && - (format.dwAspect == DVASPECT_THUMBNAIL || format.dwAspect == DVASPECT_ICON || medium.tymed == TYMED_NULL || format.lindex == fmt.lindex || (format.lindex == 0 && fmt.lindex == -1) || (format.lindex == -1 && fmt.lindex == 0)) && - format.dwAspect == fmt.dwAspect && read_from == rdfrom); - } + bool compare(const FORMATETC& fmt, bool rdfrom) const + { + return (format.cfFormat == fmt.cfFormat && + (format.tymed & fmt.tymed) != 0 && + (format.dwAspect == DVASPECT_THUMBNAIL || format.dwAspect == DVASPECT_ICON || medium.tymed == TYMED_NULL || format.lindex == fmt.lindex || (format.lindex == 0 && fmt.lindex == -1) || (format.lindex == -1 && fmt.lindex == 0)) && + format.dwAspect == fmt.dwAspect && read_from == rdfrom); +} }; - data_entry * find(const FORMATETC& fmt, bool read_from) const + data_entry * find(const FORMATETC& fmt, bool read_from) const + { + data_entry * last_weak_match = nullptr; + + for (auto & entry : entries_) { - data_entry * last_weak_match = nullptr; - - for (auto & entry : entries_) + if (entry->compare(fmt, read_from)) { - if (entry->compare(fmt, read_from)) - { - auto entry_ptd = entry->format.ptd; - if (entry_ptd && fmt.ptd && entry_ptd->tdSize == fmt.ptd->tdSize && (0 == std::memcmp(entry_ptd, fmt.ptd, fmt.ptd->tdSize))) - return entry.get(); - else if (nullptr == entry_ptd && nullptr == fmt.ptd) - return entry.get(); + auto entry_ptd = entry->format.ptd; + if (entry_ptd && fmt.ptd && entry_ptd->tdSize == fmt.ptd->tdSize && (0 == std::memcmp(entry_ptd, fmt.ptd, fmt.ptd->tdSize))) + return entry.get(); + else if (nullptr == entry_ptd && nullptr == fmt.ptd) + return entry.get(); - last_weak_match = entry.get(); - } - } - return last_weak_match; - } - - void assign(const detail::dragdrop_data& data) - { - if (!data.files.empty()) - { - std::size_t bytes = sizeof(wchar_t); - for (auto & file : data.files) - { - auto file_s = file.wstring(); - bytes += (file_s.size() + 1) * sizeof(file_s.front()); - } - - auto hglobal = ::GlobalAlloc(GHND | GMEM_SHARE, sizeof(DROPFILES) + bytes); - - auto dropfiles = reinterpret_cast(::GlobalLock(hglobal)); - dropfiles->pFiles = sizeof(DROPFILES); - dropfiles->fWide = true; - - auto file_buf = reinterpret_cast(dropfiles) + sizeof(DROPFILES); - - for (auto & file : data.files) - { - auto file_s = file.wstring(); - std::memcpy(file_buf, file_s.data(), (file_s.size() + 1) * sizeof(file_s.front())); - file_buf += (file_s.size() + 1) * sizeof(file_s.front()); - } - *reinterpret_cast(file_buf) = 0; - - ::GlobalUnlock(hglobal); - - assign(hglobal); + last_weak_match = entry.get(); } } + return last_weak_match; + } - data_entry* assign(HGLOBAL hglobal) + void assign(const detail::dragdrop_data& data) + { + if (!data.files.empty()) { - FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - auto entry = find(fmt, true); - if (entry) + std::size_t bytes = sizeof(wchar_t); + for (auto & file : data.files) { - //Free the current entry for reuse - ::CoTaskMemFree(entry->format.ptd); - ::ReleaseStgMedium(&entry->medium); - } - else - { - //Create a new entry - entries_.emplace_back(new data_entry); - entry = entries_.back().get(); + auto file_s = file.wstring(); + bytes += (file_s.size() + 1) * sizeof(file_s.front()); } - //Assign the format to the entry. - entry->read_from = true; - entry->format = fmt; + auto hglobal = ::GlobalAlloc(GHND | GMEM_SHARE, sizeof(DROPFILES) + bytes); - //Assign the stgMedium - entry->medium.tymed = TYMED_HGLOBAL; - entry->medium.hGlobal = hglobal; - entry->medium.pUnkForRelease = nullptr; + auto dropfiles = reinterpret_cast(::GlobalLock(hglobal)); + dropfiles->pFiles = sizeof(DROPFILES); + dropfiles->fWide = true; - return entry; - } - public: - // Implement IDataObject - STDMETHODIMP GetData(FORMATETC *request_format, STGMEDIUM *pmedium) override - { - if (!(request_format && pmedium)) - return E_INVALIDARG; + auto file_buf = reinterpret_cast(dropfiles)+sizeof(DROPFILES); - pmedium->hGlobal = nullptr; - - auto entry = find(*request_format, true); - if (entry) - return _m_copy_medium(pmedium, &entry->medium, &entry->format); - - return DV_E_FORMATETC; - } - - STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) override - { - return E_NOTIMPL; - } - - STDMETHODIMP QueryGetData(FORMATETC *pformatetc) override - { - if (NULL == pformatetc) - return E_INVALIDARG; - - if (!(DVASPECT_CONTENT & pformatetc->dwAspect)) - return DV_E_DVASPECT; - - HRESULT result = DV_E_TYMED; - - for (auto & entry : entries_) + for (auto & file : data.files) { - if (entry->format.tymed & pformatetc->tymed) - { - if (entry->format.cfFormat == pformatetc->cfFormat) - return S_OK; - - result = DV_E_FORMATETC; - } + auto file_s = file.wstring(); + std::memcpy(file_buf, file_s.data(), (file_s.size() + 1) * sizeof(file_s.front())); + file_buf += (file_s.size() + 1) * sizeof(file_s.front()); } - return result; + *reinterpret_cast(file_buf) = 0; + + ::GlobalUnlock(hglobal); + + assign(hglobal); } + } - STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) override + data_entry* assign(HGLOBAL hglobal) + { + FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + auto entry = find(fmt, true); + if (entry) { - return E_NOTIMPL; + //Free the current entry for reuse + ::CoTaskMemFree(entry->format.ptd); + ::ReleaseStgMedium(&entry->medium); } - - STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) override + else { - if (!(pformatetc && pmedium)) - return E_INVALIDARG; - - if (pformatetc->tymed != pmedium->tymed) - return E_FAIL; - + //Create a new entry entries_.emplace_back(new data_entry); - auto entry = entries_.back().get(); - - entry->format = *pformatetc; - - _m_copy_medium(&entry->medium, pmedium, pformatetc); - - if (TRUE == fRelease) - ::ReleaseStgMedium(pmedium); - - return S_OK; + entry = entries_.back().get(); } - STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) override + //Assign the format to the entry. + entry->read_from = true; + entry->format = fmt; + + //Assign the stgMedium + entry->medium.tymed = TYMED_HGLOBAL; + entry->medium.hGlobal = hglobal; + entry->medium.pUnkForRelease = nullptr; + + return entry; + } +public: + // Implement IDataObject + STDMETHODIMP GetData(FORMATETC *request_format, STGMEDIUM *pmedium) override + { + if (!(request_format && pmedium)) + return E_INVALIDARG; + + pmedium->hGlobal = nullptr; + + auto entry = find(*request_format, true); + if (entry) + return _m_copy_medium(pmedium, &entry->medium, &entry->format); + + return DV_E_FORMATETC; + } + + STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) override + { + return E_NOTIMPL; + } + + STDMETHODIMP QueryGetData(FORMATETC *pformatetc) override + { + if (NULL == pformatetc) + return E_INVALIDARG; + + if (!(DVASPECT_CONTENT & pformatetc->dwAspect)) + return DV_E_DVASPECT; + + HRESULT result = DV_E_TYMED; + + for (auto & entry : entries_) { - if (NULL == ppenumFormatEtc) + if (entry->format.tymed & pformatetc->tymed) + { + if (entry->format.cfFormat == pformatetc->cfFormat) + return S_OK; + + result = DV_E_FORMATETC; + } + } + return result; + } + + STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) override + { + return E_NOTIMPL; + } + + STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) override + { + if (!(pformatetc && pmedium)) + return E_INVALIDARG; + + if (pformatetc->tymed != pmedium->tymed) + return E_FAIL; + + entries_.emplace_back(new data_entry); + auto entry = entries_.back().get(); + + entry->format = *pformatetc; + + _m_copy_medium(&entry->medium, pmedium, pformatetc); + + if (TRUE == fRelease) + ::ReleaseStgMedium(pmedium); + + return S_OK; + } + + STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) override + { + if (NULL == ppenumFormatEtc) + return E_INVALIDARG; + + if (DATADIR_GET != dwDirection) + return E_NOTIMPL; + + *ppenumFormatEtc = nullptr; + + FORMATETC rgfmtetc[] = + { + //{ CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL } + { CF_HDROP, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL } + }; + return ::SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc); + } + + STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) override + { + return OLE_E_ADVISENOTSUPPORTED; + } + + STDMETHODIMP DUnadvise(DWORD dwConnection) override + { + return OLE_E_ADVISENOTSUPPORTED; + } + + STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise) override + { + return OLE_E_ADVISENOTSUPPORTED; + } +private: + static HRESULT _m_copy_medium(STGMEDIUM* stgmed_dst, STGMEDIUM* stgmed_src, FORMATETC* fmt_src) + { + if (!(stgmed_dst && stgmed_src && fmt_src)) + return E_INVALIDARG; + + switch (stgmed_src->tymed) + { + case TYMED_HGLOBAL: + stgmed_dst->hGlobal = (HGLOBAL)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0); + break; + case TYMED_GDI: + case TYMED_ENHMF: + //GDI object can't be copied to an existing HANDLE + if (stgmed_dst->hGlobal) return E_INVALIDARG; - if (DATADIR_GET != dwDirection) - return E_NOTIMPL; - - *ppenumFormatEtc = nullptr; - - FORMATETC rgfmtetc[] = - { - //{ CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL } - { CF_HDROP, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL } - }; - return ::SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc); + stgmed_dst->hGlobal = (HBITMAP)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0); + break; + case TYMED_MFPICT: + stgmed_dst->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(stgmed_src->hMetaFilePict, fmt_src->cfFormat, 0); + break; + case TYMED_FILE: + stgmed_dst->lpszFileName = (LPOLESTR)OleDuplicateData(stgmed_src->lpszFileName, fmt_src->cfFormat, 0); + break; + case TYMED_ISTREAM: + stgmed_dst->pstm = stgmed_src->pstm; + stgmed_src->pstm->AddRef(); + break; + case TYMED_ISTORAGE: + stgmed_dst->pstg = stgmed_src->pstg; + stgmed_src->pstg->AddRef(); + break; + case TYMED_NULL: + default: + break; } - - STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) override + stgmed_dst->tymed = stgmed_src->tymed; + stgmed_dst->pUnkForRelease = nullptr; + if (stgmed_src->pUnkForRelease) { - return OLE_E_ADVISENOTSUPPORTED; + stgmed_dst->pUnkForRelease = stgmed_src->pUnkForRelease; + stgmed_src->pUnkForRelease->AddRef(); } - - STDMETHODIMP DUnadvise(DWORD dwConnection) override - { - return OLE_E_ADVISENOTSUPPORTED; - } - - STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise) override - { - return OLE_E_ADVISENOTSUPPORTED; - } - private: - static HRESULT _m_copy_medium(STGMEDIUM* stgmed_dst, STGMEDIUM* stgmed_src, FORMATETC* fmt_src) - { - if (!(stgmed_dst && stgmed_src && fmt_src)) - return E_INVALIDARG; - - switch (stgmed_src->tymed) - { - case TYMED_HGLOBAL: - stgmed_dst->hGlobal = (HGLOBAL)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0); - break; - case TYMED_GDI: - case TYMED_ENHMF: - //GDI object can't be copied to an existing HANDLE - if (stgmed_dst->hGlobal) - return E_INVALIDARG; - - stgmed_dst->hGlobal = (HBITMAP)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0); - break; - case TYMED_MFPICT: - stgmed_dst->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(stgmed_src->hMetaFilePict, fmt_src->cfFormat, 0); - break; - case TYMED_FILE: - stgmed_dst->lpszFileName = (LPOLESTR)OleDuplicateData(stgmed_src->lpszFileName, fmt_src->cfFormat, 0); - break; - case TYMED_ISTREAM: - stgmed_dst->pstm = stgmed_src->pstm; - stgmed_src->pstm->AddRef(); - break; - case TYMED_ISTORAGE: - stgmed_dst->pstg = stgmed_src->pstg; - stgmed_src->pstg->AddRef(); - break; - case TYMED_NULL: - default: - break; - } - stgmed_dst->tymed = stgmed_src->tymed; - stgmed_dst->pUnkForRelease = nullptr; - if (stgmed_src->pUnkForRelease) - { - stgmed_dst->pUnkForRelease = stgmed_src->pUnkForRelease; - stgmed_src->pUnkForRelease->AddRef(); - } - return S_OK; - } - private: - std::vector> entries_; + return S_OK; + } +private: + std::vector> entries_; }; +using win32_dropdata = win32com_iunknown; + #elif defined(NANA_X11) class x11_dropdata @@ -710,7 +721,7 @@ namespace nana i->second->set_current_source(drag_wd); DWORD result_effect{ DROPEFFECT_NONE }; - auto status = ::DoDragDrop(dropdata, drop_src, DROPEFFECT_COPY, &result_effect); + ::DoDragDrop(dropdata, drop_src, DROPEFFECT_COPY, &result_effect); i->second->set_current_source(nullptr);