From f25fcade08ce90fb8dbaeb948676aa33e4265fe0 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 27 Feb 2015 19:50:25 +0100 Subject: [PATCH 01/77] ignore *.a --- .gitignore | 3 ++- extrlib/readme (2).txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 extrlib/readme (2).txt diff --git a/.gitignore b/.gitignore index f6f1e54d..36e8ba58 100644 --- a/.gitignore +++ b/.gitignore @@ -21,10 +21,11 @@ Thumbs.db [Bb]in [Dd]ebug*/ *.lib +*.a *.sbr obj/ [Rr]elease*/ _ReSharper*/ [Tt]est[Rr]esult* *.suo -*.sdf \ No newline at end of file +*.sdf diff --git a/extrlib/readme (2).txt b/extrlib/readme (2).txt new file mode 100644 index 00000000..84359ae5 --- /dev/null +++ b/extrlib/readme (2).txt @@ -0,0 +1 @@ +The libpng.a is for MinGW(Not linux), and other .lib files are for VS2013 \ No newline at end of file From ce98ffa7b14667820be8bb71220c71d6c9d10c63 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 4 Mar 2015 03:28:12 +0800 Subject: [PATCH 02/77] fix picture widget transparent image issue --- include/nana/gui/widgets/picture.hpp | 2 +- include/nana/paint/image.hpp | 5 ++++- source/gui/widgets/picture.cpp | 28 ++++++++++++++++------------ source/paint/image.cpp | 5 +++++ 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/include/nana/gui/widgets/picture.hpp b/include/nana/gui/widgets/picture.hpp index 33c67552..f4ba4f22 100644 --- a/include/nana/gui/widgets/picture.hpp +++ b/include/nana/gui/widgets/picture.hpp @@ -34,7 +34,7 @@ namespace nana void attached(widget_reference, graph_reference) override; private: void refresh(graph_reference) override; - void _m_draw_background(); + void _m_draw_background(unsigned,unsigned); private: implement * const impl_; }; diff --git a/include/nana/paint/image.hpp b/include/nana/paint/image.hpp index d8200293..b335a4fe 100644 --- a/include/nana/paint/image.hpp +++ b/include/nana/paint/image.hpp @@ -1,6 +1,7 @@ /* * Paint Image Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -39,6 +40,8 @@ namespace paint bool empty() const; operator unspecified_bool_t() const; void close(); + + bool alpha() const; nana::size size() const; void paste(graphics& dst, int x, int y) const; void paste(const nana::rectangle& r_src, graphics& dst, const point& p_dst) const;///< Paste the area of picture specified by r_src into the destination graphics specified by dst at position p_dst. diff --git a/source/gui/widgets/picture.cpp b/source/gui/widgets/picture.cpp index b9912cc7..db067155 100644 --- a/source/gui/widgets/picture.cpp +++ b/source/gui/widgets/picture.cpp @@ -109,8 +109,7 @@ namespace nana } } - if (fit_size.width < graphsize.width || fit_size.height < graphsize.height) - _m_draw_background(); + _m_draw_background(fit_size.width, fit_size.height); backimg.image.stretch(valid_area, graph, { pos, fit_size }); } @@ -141,14 +140,15 @@ namespace nana break; } - if (valid_area.width < graphsize.width || valid_area.height < graphsize.height) - _m_draw_background(); + _m_draw_background(valid_area.width, valid_area.height); backimg.image.paste(valid_area, graph, pos); } } else { + _m_draw_background(graphsize.width, graphsize.height); + color invalid_clr_for_call; backimg.bground->draw(graph, invalid_clr_for_call, invalid_clr_for_call, graphsize, element_state::normal); } @@ -156,18 +156,22 @@ namespace nana graph.setsta(); } - void drawer::_m_draw_background() + void drawer::_m_draw_background(unsigned w, unsigned h) { auto graph = impl_->graph_ptr; + if (graph && (bground_mode::basic != API::effects_bground_mode(*impl_->wdg_ptr))) { - auto & bground = impl_->gradual_bground; - if (bground.gradual_from.invisible() || bground.gradual_to.invisible()) - graph->rectangle(true, impl_->wdg_ptr->bgcolor()); - else if (bground.gradual_from == bground.gradual_to) - graph->rectangle(true, bground.gradual_from); - else - graph->gradual_rectangle(graph->size(), bground.gradual_from, bground.gradual_to, !bground.horizontal); + if (w < graph->size().width || h < graph->size().width || impl_->backimg.image.alpha()) + { + auto & bground = impl_->gradual_bground; + if (bground.gradual_from.invisible() || bground.gradual_to.invisible()) + graph->rectangle(true, impl_->wdg_ptr->bgcolor()); + else if (bground.gradual_from == bground.gradual_to) + graph->rectangle(true, bground.gradual_from); + else + graph->gradual_rectangle(graph->size(), bground.gradual_from, bground.gradual_to, !bground.horizontal); + } } } //end class drawer diff --git a/source/paint/image.cpp b/source/paint/image.cpp index ec471d6a..a6fcd598 100644 --- a/source/paint/image.cpp +++ b/source/paint/image.cpp @@ -250,6 +250,11 @@ namespace paint image_ptr_.reset(); } + bool image::alpha() const + { + return (image_ptr_ ? image_ptr_->alpha_channel() : false); + } + nana::size image::size() const { return (image_ptr_ ? image_ptr_->size() : nana::size()); From d57fb034e3b89a981b6602af42296dba0bc10a93 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 3 Mar 2015 22:43:44 +0100 Subject: [PATCH 03/77] Doxygen comments --- include/nana/basic_types.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp index 9a2d85f2..2e8c0929 100644 --- a/include/nana/basic_types.hpp +++ b/include/nana/basic_types.hpp @@ -18,7 +18,7 @@ namespace nana { - //A constant value for the invalid position. + /// A constant value for the invalid position. const std::size_t npos = static_cast(-1); @@ -127,8 +127,7 @@ namespace nana using pixel_color_t = pixel_argb_t; - //http://www.w3.org/TR/2011/REC-css3-color-20110607/ - //4.3. Extended color keywords + /// See extended CSS color keywords (4.3) in http://www.w3.org/TR/2011/REC-css3-color-20110607/ enum class colors { alice_blue = 0xf0f8ff, @@ -320,10 +319,10 @@ namespace nana color blend(const color& bgcolor, bool ignore_bgcolor_alpha) const; - ///< Blends two colors with the specified alpha, and the alpha values that come with these two colors are both ignored. + /// Blends two colors with the specified alpha, and the alpha values that come with these two colors are both ignored. color blend(const color& bgcolor, double alpha) const; - ///< Determines whether the color is completely transparent. + /// Determines whether the color is completely transparent. bool invisible() const; pixel_color_t px_color() const; pixel_argb_t argb() const; From 3b2e63da67b24de556a4488ffc8578ffe45de478 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 4 Mar 2015 03:30:54 +0100 Subject: [PATCH 04/77] ignore lib/ --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 36e8ba58..318a153e 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ _ReSharper*/ [Tt]est[Rr]esult* *.suo *.sdf +lib/ From 5b989435f2bc6083ffd337809a3135c9e128efe5 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 5 Mar 2015 00:38:29 +0100 Subject: [PATCH 05/77] add x64 and OutputFile name: $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib --- build/vc2013/nana.sln | 6 +++ build/vc2013/nana.vcxproj | 81 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/build/vc2013/nana.sln b/build/vc2013/nana.sln index 6baefd4a..f92bfa92 100644 --- a/build/vc2013/nana.sln +++ b/build/vc2013/nana.sln @@ -8,13 +8,19 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|Win32.ActiveCfg = Debug|Win32 {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|Win32.Build.0 = Debug|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x64.ActiveCfg = Debug|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x64.Build.0 = Debug|x64 {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|Win32.ActiveCfg = Release|Win32 {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|Win32.Build.0 = Release|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.ActiveCfg = Release|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index d6b6e976..17ac7ac4 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD} @@ -22,6 +30,12 @@ v120 Unicode + + StaticLibrary + true + v120 + Unicode + StaticLibrary false @@ -29,21 +43,48 @@ true Unicode + + StaticLibrary + false + v120 + true + Unicode + + + + + + + ../bin/vc2013/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/vc2013/ ../bin/vc2013/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/vc2013/ @@ -58,7 +99,23 @@ true - $(OutDir)\nana_debug.lib + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib @@ -78,7 +135,27 @@ true - $(OutDir)\nana_release.lib + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib From 24675db26be5c6f6c73b62156dd91de5d776b01a Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Mon, 9 Mar 2015 12:01:35 +0100 Subject: [PATCH 06/77] static link runtime --- build/vc2013/nana.sln | 2 +- build/vc2013/nana.vcxproj | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build/vc2013/nana.sln b/build/vc2013/nana.sln index f92bfa92..3d18acf9 100644 --- a/build/vc2013/nana.sln +++ b/build/vc2013/nana.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Express 2013 for Windows Desktop -VisualStudioVersion = 12.0.21005.1 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{25B21068-491B-4A9F-B99F-6C27BF31BAAD}" EndProject diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 17ac7ac4..c8024ba7 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -93,6 +93,7 @@ Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug Windows @@ -109,6 +110,7 @@ Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug Windows @@ -127,6 +129,7 @@ true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded Windows @@ -147,6 +150,7 @@ true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded Windows From 2c5283eb78f50c39a01f8d6937105ba19ab3c528 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 10 Mar 2015 13:30:15 +0800 Subject: [PATCH 07/77] fix mingw compiling errors Manually merge the commit which is created by Pr0curo --- source/basic_types.cpp | 2 ++ source/gui/notifier.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/basic_types.cpp b/source/basic_types.cpp index b49dc0bb..629ab81b 100644 --- a/source/basic_types.cpp +++ b/source/basic_types.cpp @@ -18,6 +18,8 @@ #endif #include +#include + namespace nana { //class color diff --git a/source/gui/notifier.cpp b/source/gui/notifier.cpp index c0567bc5..9ccc3dd4 100644 --- a/source/gui/notifier.cpp +++ b/source/gui/notifier.cpp @@ -1,7 +1,7 @@ /* * Implementation of Notifier * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -16,7 +16,12 @@ #include #include + +#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED) +#include +#else #include +#endif #if defined(NANA_WINDOWS) #include From b62cbc1cf3df4c8a5b3e5998e4f5fd5d2f0e7b21 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 11 Mar 2015 02:20:40 +0100 Subject: [PATCH 08/77] fix: UB due to pos=57, begin=58 (first char finded) infinite cycle => *chp : crash in text_editor --- source/gui/widgets/skeletons/text_editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index f8ffa7f0..e5125c9c 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -2528,7 +2528,7 @@ namespace nana{ namespace widgets //The number of new lines minus one const auto chp_end = text.data() + (begin == text.npos ? text.size() : begin); - for (auto chp = text.data() + (pos + 2); chp != chp_end; ++chp) + for (auto chp = text.data() + (pos + 1); chp != chp_end; ++chp) // + 2 if (*chp == '\n') lines.emplace_back(0, 0); From fd7f4c61e99392ccc126ca140550608036f8c580 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 12 Mar 2015 15:01:45 +0100 Subject: [PATCH 09/77] avoid collocate a placed widget with size empty als workaround fixing 0% in left field split --- source/gui/place.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 005fd3cf..d9d14665 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -2151,6 +2151,8 @@ namespace nana if (impl_->root_division && impl_->window_handle) { impl_->root_division->field_area = API::window_size(impl_->window_handle); + if (impl_->root_division->field_area.empty()) return; + impl_->root_division->collocate(impl_->window_handle); for (auto & field : impl_->fields) From bc8a157971b7dca9df88f4f85cebc719c94c5679 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 13 Mar 2015 14:24:24 +0800 Subject: [PATCH 10/77] add auto config of numeric conversions auto config of numeric conversions for GCC/MinGW add contributors info --- include/nana/config.hpp | 16 ++++++++++--- include/nana/deploy.hpp | 4 ++-- include/nana/paint/detail/image_bmp.hpp | 12 ++++++++++ source/basic_types.cpp | 1 + source/deploy.cpp | 3 ++- source/gui/layout_utility.cpp | 2 +- source/gui/notifier.cpp | 21 +++++++++-------- source/gui/widgets/skeletons/text_editor.cpp | 24 ++++++++++---------- 8 files changed, 54 insertions(+), 29 deletions(-) diff --git a/include/nana/config.hpp b/include/nana/config.hpp index 418871f1..8969fc88 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -1,7 +1,7 @@ /* * Nana Configuration * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -20,10 +20,13 @@ #define PLATFORM_SPEC_HPP //Test if it is MINGW - #if defined(__MINGW32__) + #if defined(__MINGW32__) || defined(__MINGW64__) #define NANA_MINGW #define STD_CODECVT_NOT_SUPPORTED - //#define STD_THREAD_NOT_SUPPORTED //Use this flag if MinGW version is older than 4.8.1 + #if (__GNUC__ == 4) && ((__GNUC_MINOR__ < 8) || (__GNUC_MINOR__ == 8 && __GNUC_PATCHLEVEL__ < 1)) + //Use this flag if MinGW version is older than 4.8.1 + #define STD_THREAD_NOT_SUPPORTED + #endif #endif #elif (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) //Linux: @@ -33,6 +36,13 @@ #define STD_CODECVT_NOT_SUPPORTED #endif +#if defined(NANA_MINGW) || defined(NANA_LINUX) + #if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ <= 1) + //Some functions which are specified in 21.5 Numeric conversions in Strings library have not yet implemented + #define STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED + #endif +#endif + //Here defines some flags that tell Nana what features will be supported. #define NANA_UNICODE diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index 0862a7a3..743ecf8f 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -21,8 +21,8 @@ #undef NANA_WINDOWS #endif -//Implement workarounds for MinGW -#if defined(NANA_MINGW) +//Implement workarounds for GCC/MinGW which version is below 4.8.2 +#if defined(STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED) namespace std { //Workaround for no implemenation of std::stoi in MinGW. diff --git a/include/nana/paint/detail/image_bmp.hpp b/include/nana/paint/detail/image_bmp.hpp index f5493881..5397faef 100644 --- a/include/nana/paint/detail/image_bmp.hpp +++ b/include/nana/paint/detail/image_bmp.hpp @@ -1,3 +1,15 @@ +/* + * Bitmap Format Graphics Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 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/paint/detail/image_bmp.hpp + * @contributors: Ryan Gonzalez + */ #ifndef NANA_PAINT_DETAIL_IMAGE_BMP_HPP #define NANA_PAINT_DETAIL_IMAGE_BMP_HPP diff --git a/source/basic_types.cpp b/source/basic_types.cpp index 629ab81b..8edc8a0f 100644 --- a/source/basic_types.cpp +++ b/source/basic_types.cpp @@ -8,6 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/basic_types.cpp + * @contributos: Jan */ #include diff --git a/source/deploy.cpp b/source/deploy.cpp index b2d053f4..c4d4d3f8 100644 --- a/source/deploy.cpp +++ b/source/deploy.cpp @@ -23,7 +23,8 @@ #include PLATFORM_SPEC_HPP #endif -#if defined(NANA_MINGW) +//Implement workarounds for GCC/MinGW which version is below 4.8.2 +#if defined(STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED) #include namespace std { diff --git a/source/gui/layout_utility.cpp b/source/gui/layout_utility.cpp index d59e89c3..8ab4c9b9 100644 --- a/source/gui/layout_utility.cpp +++ b/source/gui/layout_utility.cpp @@ -8,7 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/layout_utility.hpp - * + * @contributors: Ryan Gonzalez * */ #include diff --git a/source/gui/notifier.cpp b/source/gui/notifier.cpp index 9ccc3dd4..aec5686f 100644 --- a/source/gui/notifier.cpp +++ b/source/gui/notifier.cpp @@ -1,14 +1,15 @@ /* -* Implementation of Notifier -* Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2015 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/notifier.cpp -*/ + * Implementation of Notifier + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 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/notifier.cpp + * @contributors: Jan + */ #include #include #include diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index e5125c9c..0cb39750 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1,15 +1,15 @@ /* -* A text editor implementation -* Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2015 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/widgets/skeletons/text_editor.cpp -* @description: -*/ + * A text editor implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 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/widgets/skeletons/text_editor.cpp + * @contributors: qPCR4vir + */ #include #include #include @@ -2528,7 +2528,7 @@ namespace nana{ namespace widgets //The number of new lines minus one const auto chp_end = text.data() + (begin == text.npos ? text.size() : begin); - for (auto chp = text.data() + (pos + 1); chp != chp_end; ++chp) // + 2 + for (auto chp = text.data() + (pos + 1); chp != chp_end; ++chp) if (*chp == '\n') lines.emplace_back(0, 0); From b7cd8d00a183b4e9515a10f40dfc22f953e2d0c2 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 13 Mar 2015 08:39:49 +0100 Subject: [PATCH 11/77] valid doxy-comments need to begin with /** --- include/nana/gui/widgets/button.hpp | 6 +++--- include/nana/gui/widgets/categorize.hpp | 4 ++-- include/nana/gui/widgets/checkbox.hpp | 6 +++--- include/nana/gui/widgets/combox.hpp | 4 ++-- include/nana/gui/widgets/date_chooser.hpp | 2 +- include/nana/gui/widgets/float_listbox.hpp | 4 ++-- include/nana/gui/widgets/form.hpp | 2 +- include/nana/gui/widgets/frame.hpp | 6 +++--- include/nana/gui/widgets/label.hpp | 4 ++-- include/nana/gui/widgets/listbox.hpp | 2 +- include/nana/gui/widgets/menu.hpp | 2 +- include/nana/gui/widgets/panel.hpp | 4 ++-- include/nana/gui/widgets/picture.hpp | 4 ++-- include/nana/gui/widgets/progress.hpp | 2 +- include/nana/gui/widgets/scroll.hpp | 2 +- include/nana/gui/widgets/slider.hpp | 2 +- include/nana/gui/widgets/spinbox.hpp | 2 +- include/nana/gui/widgets/tabbar.hpp | 6 +++--- include/nana/gui/widgets/textbox.hpp | 2 +- include/nana/gui/widgets/toolbar.hpp | 2 +- include/nana/gui/widgets/treebox.hpp | 4 ++-- include/nana/gui/widgets/widget.hpp | 2 +- 22 files changed, 37 insertions(+), 37 deletions(-) diff --git a/include/nana/gui/widgets/button.hpp b/include/nana/gui/widgets/button.hpp index 5305e4f6..e57f3b12 100644 --- a/include/nana/gui/widgets/button.hpp +++ b/include/nana/gui/widgets/button.hpp @@ -1,13 +1,13 @@ -/* +/** * A Button Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 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/widgets/button.hpp + * @file: nana/gui/widgets/button.hpp */ #ifndef NANA_GUI_WIDGET_BUTTON_HPP diff --git a/include/nana/gui/widgets/categorize.hpp b/include/nana/gui/widgets/categorize.hpp index 72df23d6..7f6b2521 100644 --- a/include/nana/gui/widgets/categorize.hpp +++ b/include/nana/gui/widgets/categorize.hpp @@ -1,4 +1,4 @@ -/* +/** * A Categorize Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 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.hpp + * @file: nana/gui/widgets/categorize.hpp */ #ifndef NANA_GUI_WIDGET_CATEGORIZE_HPP diff --git a/include/nana/gui/widgets/checkbox.hpp b/include/nana/gui/widgets/checkbox.hpp index 0795fa1a..22f87fff 100644 --- a/include/nana/gui/widgets/checkbox.hpp +++ b/include/nana/gui/widgets/checkbox.hpp @@ -1,13 +1,13 @@ -/* +/** * A CheckBox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 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/widgets/checkbox.hpp + * @file: nana/gui/widgets/checkbox.hpp */ #ifndef NANA_GUI_WIDGET_CHECKBOX_HPP diff --git a/include/nana/gui/widgets/combox.hpp b/include/nana/gui/widgets/combox.hpp index 5a1f7e84..16b22faf 100644 --- a/include/nana/gui/widgets/combox.hpp +++ b/include/nana/gui/widgets/combox.hpp @@ -1,4 +1,4 @@ -/* +/** * A Combox Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 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/combox.hpp + * @file: nana/gui/widgets/combox.hpp */ #ifndef NANA_GUI_WIDGETS_COMBOX_HPP diff --git a/include/nana/gui/widgets/date_chooser.hpp b/include/nana/gui/widgets/date_chooser.hpp index b4bf2126..9fc0ca8d 100644 --- a/include/nana/gui/widgets/date_chooser.hpp +++ b/include/nana/gui/widgets/date_chooser.hpp @@ -1,4 +1,4 @@ -/* +/** * A date chooser Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/float_listbox.hpp b/include/nana/gui/widgets/float_listbox.hpp index 67e48591..f28840ea 100644 --- a/include/nana/gui/widgets/float_listbox.hpp +++ b/include/nana/gui/widgets/float_listbox.hpp @@ -1,7 +1,7 @@ -/* +/** * A float_listbox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/nana/gui/widgets/form.hpp b/include/nana/gui/widgets/form.hpp index 79ec3f6b..66047576 100644 --- a/include/nana/gui/widgets/form.hpp +++ b/include/nana/gui/widgets/form.hpp @@ -1,4 +1,4 @@ -/* +/** * A Form Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/frame.hpp b/include/nana/gui/widgets/frame.hpp index 0b04b4b6..6cc91dce 100644 --- a/include/nana/gui/widgets/frame.hpp +++ b/include/nana/gui/widgets/frame.hpp @@ -1,7 +1,7 @@ -/* +/** * A Frame Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -9,7 +9,7 @@ * * @file: nana/gui/widgets/frame.hpp * - * A frame provides a way to contain the platform window in a stdex GUI Window + * @brief A frame provides a way to contain the platform window in a stdex GUI Window */ #ifndef NANA_GUI_WIDGET_FRAME_HPP diff --git a/include/nana/gui/widgets/label.hpp b/include/nana/gui/widgets/label.hpp index c6488e5b..ba6a5cf0 100644 --- a/include/nana/gui/widgets/label.hpp +++ b/include/nana/gui/widgets/label.hpp @@ -1,7 +1,7 @@ -/* +/** * A Label Control Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 1bc087be..056349cd 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1,4 +1,4 @@ -/* +/** * A List Box Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp index 36f99a28..03e61c9d 100644 --- a/include/nana/gui/widgets/menu.hpp +++ b/include/nana/gui/widgets/menu.hpp @@ -1,4 +1,4 @@ -/* +/** * A Menu implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp index e1d98d00..248a36eb 100644 --- a/include/nana/gui/widgets/panel.hpp +++ b/include/nana/gui/widgets/panel.hpp @@ -1,4 +1,4 @@ -/* +/** * A Panel Implementation * Nana C++ Library(http://www.nanaro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -9,7 +9,7 @@ * * @file: nana/gui/widgets/panel.hpp * - * @brief: panel is a widget used for placing some widgets. + * @brief panel is a widget used for placing some widgets. */ #ifndef NANA_GUI_WIDGETS_PANEL_HPP diff --git a/include/nana/gui/widgets/picture.hpp b/include/nana/gui/widgets/picture.hpp index f4ba4f22..bd40f0e0 100644 --- a/include/nana/gui/widgets/picture.hpp +++ b/include/nana/gui/widgets/picture.hpp @@ -1,4 +1,4 @@ -/* +/** * A Picture Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -9,7 +9,7 @@ * * @file: nana/gui/widgets/picture.hpp * - * Used for showing a picture + * @brief Used for showing a picture */ #ifndef NANA_GUI_WIDGET_PICTURE_HPP #define NANA_GUI_WIDGET_PICTURE_HPP diff --git a/include/nana/gui/widgets/progress.hpp b/include/nana/gui/widgets/progress.hpp index 5464571b..91e58ab7 100644 --- a/include/nana/gui/widgets/progress.hpp +++ b/include/nana/gui/widgets/progress.hpp @@ -1,4 +1,4 @@ -/* +/** * A Progress Indicator Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index 4b165313..f5598efd 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -1,4 +1,4 @@ -/* +/** * A Scroll Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/slider.hpp b/include/nana/gui/widgets/slider.hpp index ca1ab75a..0e32237d 100644 --- a/include/nana/gui/widgets/slider.hpp +++ b/include/nana/gui/widgets/slider.hpp @@ -1,4 +1,4 @@ -/* +/** * A Slider Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/spinbox.hpp b/include/nana/gui/widgets/spinbox.hpp index a1a85021..df962c39 100644 --- a/include/nana/gui/widgets/spinbox.hpp +++ b/include/nana/gui/widgets/spinbox.hpp @@ -1,4 +1,4 @@ -/* +/** * A Spin box widget * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/tabbar.hpp b/include/nana/gui/widgets/tabbar.hpp index 4d641461..94cf2407 100644 --- a/include/nana/gui/widgets/tabbar.hpp +++ b/include/nana/gui/widgets/tabbar.hpp @@ -1,4 +1,4 @@ -/* +/** * A Tabbar implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -7,8 +7,8 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/widgets/tabbar.hpp - * @brief: A tabbar contains tab items and toolbox for scrolling, closing, selecting items. + * @file: nana/gui/widgets/tabbar.hpp + * @brief A tabbar contains tab items and toolbox for scrolling, closing, selecting items. * */ #ifndef NANA_GUI_WIDGET_TABBAR_HPP diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 045a05fc..a678d31c 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-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index 35f539ac..efb8af74 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -1,4 +1,4 @@ -/* +/** * A Toolbar Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 4d8748eb..f5938916 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -1,4 +1,4 @@ -/* +/** * A Tree Box Implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -8,7 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/treebox.hpp - * @brief: + * @brief * The treebox organizes the nodes by a key string. * The treebox would have a vertical scrollbar if the node * is too many to display. And it does not have a horizontal scrollbar, diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index 0de7a33d..2a010b55 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -1,4 +1,4 @@ -/* +/** * The fundamental widget class implementation * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) From dc9ccabdc1f64dc418a484dce0539c86f4611fb3 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 13 Mar 2015 08:40:37 +0100 Subject: [PATCH 12/77] update doxy-comments in treebox --- include/nana/gui/widgets/treebox.hpp | 78 +++++++++++++++++----------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index f5938916..db15a6cd 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -7,12 +7,12 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/widgets/treebox.hpp + * @file: nana/gui/widgets/treebox.hpp * @brief * The treebox organizes the nodes by a key string. - * The treebox would have a vertical scrollbar if the node - * is too many to display. And it does not have a horizontal scrollbar, - * the widget will adjust the node's displaying position for fitting. + * The treebox would have a vertical scrollbar if there are too many nodes + * to display. It does not have an horizontal scrollbar: + * the widget will adjust the node's displaying position for fitting. */ #ifndef NANA_GUI_WIDGETS_TREEBOX_HPP @@ -332,12 +332,13 @@ namespace nana }//end namespace treebox }//end namespace drawerbase - struct arg_treebox + /// a type of treebox event parameter + struct arg_treebox : public event_arg { - treebox& widget; - drawerbase::treebox::item_proxy & item; - bool operated; + treebox& widget; ///< where the event occurs + drawerbase::treebox::item_proxy & item; ///< the operated node + bool operated; ///< operation state of the event arg_treebox(treebox&, drawerbase::treebox::item_proxy&, bool operated); }; @@ -349,28 +350,30 @@ namespace nana struct treebox_events : public general_events { - basic_event expanded; - basic_event checked; - basic_event selected; - basic_event hovered; + basic_event expanded; ///< a user expands or shrinks a node + basic_event checked; ///< a user checks or unchecks a node + basic_event selected; ///< a user selects or unselects a node + basic_event hovered; ///< a user moves the cursor over a node }; }//end namespace treebox }//end namespace drawerbase - /// Displays a hierarchical list of items, such as the files and directories on a disk. - class treebox + /// \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/help/widgets/treebox.htm) + class treebox :public widget_object < category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events> { public: - /// A type refers to the item and also used to iterate through the node. + /// A type refers to the item and is also used to iterate through the nodes. typedef drawerbase::treebox::item_proxy item_proxy; + /// state images for the node typedef drawerbase::treebox::node_image_tag node_image_type; - /// The interface of treebox item renderer + /// The interface of treebox user-defined item renderer typedef drawerbase::treebox::renderer_interface renderer_interface; - /// The interface of treebox compset_placer + /// The interface of treebox compset_placer to define the position of node components typedef drawerbase::treebox::compset_placer_interface compset_placer_interface; /// The default constructor without creating the widget. @@ -378,7 +381,7 @@ namespace nana /// \brief The construct that creates a widget. /// @param wd A handle to the parent window of the widget being created. - /// @param visible specifying the visible after creating. + /// @param visible specifying the visibility after creating. treebox(window wd, bool visible); /// \brief The construct that creates a widget. @@ -388,16 +391,16 @@ namespace nana treebox(window, const nana::rectangle& = rectangle(), bool visible = true); template - treebox & renderer(const ItemRenderer & rd) + treebox & renderer(const ItemRenderer & rd) ///< set user-defined node renderer { get_drawer_trigger().renderer(::nana::pat::cloneable(rd)); return *this; } - const nana::pat::cloneable & renderer() const; + const nana::pat::cloneable & renderer() const; ///< get user-defined node renderer template - treebox & placer(const Placer & r) + treebox & placer(const Placer & r) ///< location of a node components { get_drawer_trigger().placer(::nana::pat::cloneable(r)); return *this; @@ -406,38 +409,51 @@ namespace nana const nana::pat::cloneable & placer() const; /// \brief Eanble the widget to be draws automatically when it is operated. + /// + /// The treebox automatically redraws after certain operations, but, + /// under some circumstances, it is good to disable the automatic drawing mode, + /// for example, before adding nodes in a loop, disable the mode to avoiding + /// frequent and useless refresh for better performance, and then, after + /// the operations, enable the automatic redraw mode again. /// @param bool whether to enable. void auto_draw(bool); - /// \brief Enable the checkbox for each item of the widget. - /// @param bool wheter to enable. + /// \brief Enable the checkboxs for each item of the widget. + /// @param bool indicates whether to show or hide the checkboxs. treebox & checkable(bool enable); - /// Determinte whether the checkbox is enabled. - bool checkable() const; + + bool checkable() const; ///< Determinte whether the checkboxs are enabled. - node_image_type& icon(const nana::string& id) const; + /// \brief Creates an icon scheme with the specified name. + /// + /// The icon scheme includes 3 images for node states. + /// These states are 'normal', 'hovered' and 'expanded'. + /// If 'hovered' or 'expanded' are not set, it uses 'normal' state image for these 2 states. + /// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm) + node_image_type& icon(const nana::string& id ///< the name of an icon scheme. If the name is not existing, it creates a new scheme for the name. + ) const; void icon_erase(const nana::string& id); item_proxy find(const nana::string& keypath); ///< Find an item though a specified keypath. /// Inserts a new node to treebox, but if the keypath exists returns the existing node. - item_proxy insert(const nana::string& path_key, ///< specifies the node hierarchical + item_proxy insert(const nana::string& path_key, ///< specifies the node hierarchy nana::string title ///< used for displaying ); /// Inserts a new node to treebox, but if the keypath exists returns the existing node. item_proxy insert( item_proxy pos, ///< the parent item node const nana::string& key, ///< specifies the new node - nana::string title ///< used for displaying. + nana::string title ///< title used for displaying in the new node. ); - item_proxy erase(item_proxy i); + item_proxy erase(item_proxy i); ///< Removes the node at pos and return the Item proxy following the removed node - void erase(const nana::string& keypath); + void erase(const nana::string& keypath); ///< Removes the node by the key path. nana::string make_key_path(item_proxy i, const nana::string& splitter) const;/// Date: Tue, 17 Mar 2015 01:52:53 +0100 Subject: [PATCH 13/77] events doxy comments --- include/nana/gui/detail/general_events.hpp | 134 +++++++++++---------- 1 file changed, 73 insertions(+), 61 deletions(-) diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 20dae998..80b4ae1d 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -1,4 +1,4 @@ -/* +/** * Definition of General Events * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -43,11 +43,13 @@ namespace nana void events_operation_cancel(event_handle); }//end namespace detail + /// base clase for all event argument types class event_arg { public: virtual ~event_arg(); + /// ignorable handlers behind the current one in a chain of event handlers will not get called. void stop_propagation() const; bool propagation_stopped() const; private: @@ -56,6 +58,7 @@ namespace nana struct general_events; + /// the type of the members of general_events template class basic_event : public detail::event_interface { @@ -90,6 +93,7 @@ namespace nana } }; public: + /// It will get called firstly, because it is set at the beginning of the chain. template event_handle connect_front(Function && fn) { @@ -112,6 +116,7 @@ namespace nana }); } + /// It will not get called if stop_propagation() was called. template event_handle connect(Function && fn) { @@ -127,13 +132,15 @@ namespace nana return evt; } - template + /// It will not get called if stop_propagation() was called. + template event_handle operator()(Function&& fn) { return connect(std::forward(fn)); } - template + /// It will get called because it is unignorable. + template event_handle connect_unignorable(Function && fn, bool in_front = false) { internal_scope_guard lock; @@ -398,16 +405,19 @@ namespace nana struct arg_mouse : public event_arg { - event_code evt_code; - ::nana::window window_handle; - ::nana::point pos; - bool left_button; - bool mid_button; - bool right_button; - bool shift; - bool ctrl; + event_code evt_code; ///< + ::nana::window window_handle; ///< A handle to the event window + ::nana::point pos; ///< cursor position in the event window + bool left_button; ///< mouse left button is pressed? + bool mid_button; ///< mouse middle button is pressed? + bool right_button; ///< mouse right button is pressed? + bool shift; ///< keyboard Shift is pressed? + bool ctrl; ///< keyboard Ctrl is pressed? }; + /// in arg_wheel event_code is event_code::mouse_wheel + /// The type arg_wheel is derived from arg_mouse, a handler + /// with prototype void(const arg_mouse&) can be set for mouse_wheel. struct arg_wheel : public arg_mouse { enum class wheel{ @@ -415,98 +425,100 @@ namespace nana horizontal }; - wheel which; /// files; + ::nana::window window_handle; ///< A handle to the event window + ::nana::point pos; ///< cursor position in the event window + std::vector files; ///< external filenames }; struct arg_expose : public event_arg { - ::nana::window window_handle; - bool exposed; + ::nana::window window_handle; ///< A handle to the event window + bool exposed; ///< the window is visible? }; struct arg_focus : public event_arg { - ::nana::window window_handle; - ::nana::native_window_type receiver; - bool getting; + ::nana::window window_handle; ///< A handle to the event window + ::nana::native_window_type receiver; ///< it is a native window handle, and specified which window receives focus + bool getting; ///< the window received focus? }; struct arg_keyboard : public event_arg { - event_code evt_code; - ::nana::window window_handle; - mutable nana::char_t key; - mutable bool ignore; - bool ctrl; - bool shift; + event_code evt_code; ///< it is event_code::key_press in current event + ::nana::window window_handle; ///< A handle to the event window + mutable nana::char_t key; ///< the key corresponding to the key pressed + mutable bool ignore; ///< this member is not used + bool ctrl; ///< keyboard Ctrl is pressed? + bool shift; ///< keyboard Shift is pressed }; struct arg_move : public event_arg { - ::nana::window window_handle; - int x; - int y; + ::nana::window window_handle; ///< A handle to the event window + int x; ///< + int y; ///< }; struct arg_resized : public event_arg { - ::nana::window window_handle; - unsigned width; - unsigned height; + ::nana::window window_handle; ///< A handle to the event window + unsigned width; ///< new width in pixels. + unsigned height; ///< new height in pixels. }; struct arg_resizing : public event_arg { - ::nana::window window_handle; - window_border border; - mutable unsigned width; - mutable unsigned height; + ::nana::window window_handle; ///< A handle to the event window + window_border border; ///< the window is being resized by moving border + mutable unsigned width; ///< new width in pixels. If it is modified, the window's width will be the modified value + mutable unsigned height; ///< new height in pixels. If it is modified, the window's height will be the modified value }; struct arg_unload : public event_arg { - ::nana::window window_handle; - mutable bool cancel; + ::nana::window window_handle; ///< A handle to the event window + mutable bool cancel; ///< }; struct arg_destroy : public event_arg { - ::nana::window window_handle; + ::nana::window window_handle; ///< A handle to the event window }; + /// provides some fundamental events that every widget owns. struct general_events { virtual ~general_events(){} - basic_event mouse_enter; - basic_event mouse_move; - basic_event mouse_leave; - basic_event mouse_down; - basic_event mouse_up; - basic_event click; - basic_event dbl_click; - basic_event mouse_wheel; - basic_event mouse_dropfiles; - basic_event expose; - basic_event focus; - basic_event key_press; - basic_event key_release; - basic_event key_char; - basic_event shortkey; + basic_event mouse_enter; ///< the cursor enters the window + basic_event mouse_move; ///< the cursor moves on the window + basic_event mouse_leave; ///< the cursor leaves the window + basic_event mouse_down; ///< the user presses the mouse button + basic_event mouse_up; ///< the user presses the mouse button + basic_event click; ///< the window is clicked, but occurs after mouse_down and before mouse_up + basic_event dbl_click; ///< the window is double clicked + basic_event mouse_wheel; ///< the mouse wheel rotates while the window has focus + basic_event mouse_dropfiles; ///< the mouse drops some external data while the window enable accepting files + basic_event expose; ///< the visibility changes + basic_event focus; ///< the window receives or loses keyboard focus + basic_event key_press; ///< a key is pressed while the window has focus. event code is event_code::key_press + basic_event key_release; ///< a key is released while the window has focus. event code is event_code::key_release + basic_event key_char; ///< a character, whitespace or backspace is pressed. event code is event_code::key_char + basic_event shortkey; ///< a defined short key is pressed. event code is event_code::shortkey - basic_event move; - basic_event resizing; - basic_event resized; + basic_event move; ///< the window changes position + basic_event resizing; ///< the window is changing its size + basic_event resized; ///< the window is changing its size - basic_event destroy; + basic_event destroy; ///< the window is destroyed, but occurs when all children have been destroyed }; namespace detail From 629a66546a270e668e188686d4bab1e8fd163147 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 18 Mar 2015 00:35:39 +0800 Subject: [PATCH 14/77] fix wrong position of splitter wrong splitter position when leaf of splitter is specified with margin --- source/gui/place.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index d9d14665..f3be7d8a 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -1,4 +1,4 @@ -/* +/** * An Implementation of Place for Layout * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) @@ -1565,8 +1565,9 @@ namespace nana auto px_ptr = &nana::rectangle::width; - auto area_left = leaf_left_->margin_area(); - auto area_right = leaf_right_->margin_area(); + //Use field_area of leaf, not margin_area. Otherwise splitter would be at wrong position + auto area_left = leaf_left_->field_area; + auto area_right = leaf_right_->field_area; if (nana::cursor::size_we != splitter_cursor_) { @@ -2151,8 +2152,6 @@ namespace nana if (impl_->root_division && impl_->window_handle) { impl_->root_division->field_area = API::window_size(impl_->window_handle); - if (impl_->root_division->field_area.empty()) return; - impl_->root_division->collocate(impl_->window_handle); for (auto & field : impl_->fields) From ee699c263eaeac8938a484d890713059a9ea94de Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 17 Mar 2015 23:21:17 +0100 Subject: [PATCH 15/77] eliminated unnecessary comments --- include/nana/gui/detail/general_events.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 80b4ae1d..18c20ee5 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -430,8 +430,7 @@ namespace nana unsigned distance; ///< expressed in multiples or divisions of 120 }; - struct arg_dropfiles : public event_arg // It could be from arg_mouse ?? - // Is possible struct arg_drop:arg_mouse {any data;}; ? + struct arg_dropfiles : public event_arg { ::nana::window window_handle; ///< A handle to the event window ::nana::point pos; ///< cursor position in the event window From 5d404774e6257d67168911fffc84789f71531296 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 20 Mar 2015 00:15:39 +0100 Subject: [PATCH 16/77] fix a few minor inconsistencies in item listbox drawing --- include/nana/basic_types.hpp | 2 +- source/gui/widgets/listbox.cpp | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp index 2e8c0929..6e129e89 100644 --- a/include/nana/basic_types.hpp +++ b/include/nana/basic_types.hpp @@ -282,7 +282,7 @@ namespace nana //temporary defintions, these will be replaced by color schema button_face_shadow_start = 0xF5F4F2, button_face_shadow_end = 0xD5D2CA, - button_face = 0xD4D0C8, + button_face = 0xD4D0C8 , //,light_cyan dark_border = 0x404040, gray_border = 0x808080, highlight = 0x1CC4F7 diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 7d1bec1b..6deb2b20 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2613,6 +2613,8 @@ namespace nana for(auto index : seqs) { const auto & header = essence_->header.column(index); + auto it_bgcolor = bgcolor; + //auto it_fgcolor = fgcolor; if ((item.cells.size() > index) && (header.pixels > 5)) { @@ -2622,14 +2624,14 @@ namespace nana if (m_cell.custom_format && (!m_cell.custom_format->bgcolor.invisible())) { - if (!item.flags.selected) - { - if (item_state::highlighted == state) - graph->set_color(m_cell.custom_format->bgcolor.blend(::nana::color(0x99, 0xde, 0xfd), 0.8)); - else - graph->set_color(m_cell.custom_format->bgcolor); - graph->rectangle(rectangle{ item_xpos, y, header.pixels, essence_->item_size }, true); - } + it_bgcolor = m_cell.custom_format->bgcolor; + if (item.flags.selected) + it_bgcolor = it_bgcolor.blend( bgcolor , 0.5) ; + if (item_state::highlighted == state) + it_bgcolor = it_bgcolor.blend(::nana::color(0x99, 0xde, 0xfd), 0.8); + + graph->set_color(it_bgcolor); + graph->rectangle(rectangle{ item_xpos, y, header.pixels, essence_->item_size }, true); cell_txtcolor = m_cell.custom_format->fgcolor; } @@ -2677,15 +2679,17 @@ namespace nana //The text is painted over the next subitem int xpos = item_xpos + header.pixels - essence_->suspension_width; - graph->set_color(bgcolor); + graph->set_color(it_bgcolor); graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true); - graph->set_text_color(fgcolor); + graph->set_text_color(cell_txtcolor); graph->string(point{ xpos, y + 2 }, STR("...")); //Erase the part that over the next subitem. - if (index + 1 >= seqs.size()) - graph->set_color(item.bgcolor); - graph->rectangle(rectangle{item_xpos + static_cast(header.pixels), y + 2, ts.width + ext_w - header.pixels, essence_->item_size - 4}, true); + if (index + 1 <= seqs.size()) + { + graph->set_color(bgcolor); + graph->rectangle(rectangle{item_xpos + static_cast(header.pixels), y + 2, ts.width + ext_w - header.pixels, essence_->item_size - 4}, true); + } } } From e99ebc6e2e14861006365bd260cc1682665879d0 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 20 Mar 2015 14:55:17 +0800 Subject: [PATCH 17/77] fix a crash error it occurs when deleting a window in its certain event --- source/gui/detail/linux_X11/bedrock.cpp | 5 +++-- source/gui/detail/win32/bedrock.cpp | 4 ++++ source/gui/widgets/listbox.cpp | 4 +--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index d6546f08..886f1493 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -719,12 +719,11 @@ namespace detail if(kill_focus != new_focus) brock.wd_manager.do_lazy_refresh(kill_focus, false); } + auto retain = msgwnd->together.event_ptr; msgwnd->root_widget->other.attribute.root->context.focus_changed = false; - context.event_window = msgwnd; pressed_wd = nullptr; - //make_eventinfo(ei, msgwnd, message, xevent); msgwnd->flags.action = mouse_action::pressed; arg_mouse arg; assign_arg(arg, msgwnd, ButtonPress, xevent); @@ -774,6 +773,8 @@ namespace detail msgwnd->flags.action = mouse_action::normal; if(msgwnd->flags.enabled) { + auto retain = msgwnd->together.event_ptr; + arg_mouse arg; assign_arg(arg, msgwnd, message, xevent); diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 7820227c..00968a6a 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -948,6 +948,8 @@ namespace detail arg_mouse arg; assign_arg(arg, msgwnd, message, pmdec); msgwnd->flags.action = mouse_action::pressed; + + auto retain = msgwnd->together.events_ptr; if (brock.emit(event_code::mouse_down, msgwnd, arg, true, &context)) { //If a root_window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. @@ -982,6 +984,8 @@ namespace detail msgwnd->flags.action = mouse_action::normal; if(msgwnd->flags.enabled) { + auto retain = msgwnd->together.events_ptr; + nana::arg_mouse arg; assign_arg(arg, msgwnd, message, pmdec); diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 6deb2b20..ef7a7130 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -8,8 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/listbox.cpp - * @patchs: - * Jan 03 2012, unsigned to std::size_t conversion fail for x64, Hiroshi Seki + * @contributors: Hiroshi Seki, qPCR4vir */ #include @@ -2614,7 +2613,6 @@ namespace nana { const auto & header = essence_->header.column(index); auto it_bgcolor = bgcolor; - //auto it_fgcolor = fgcolor; if ((item.cells.size() > index) && (header.pixels > 5)) { From aa14b3800834e6ecd65522f92dbaf4fe26fc22d1 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 20 Mar 2015 12:12:29 +0100 Subject: [PATCH 18/77] fix: make panel and label have the same bgcolor as the owner --- include/nana/gui/widgets/panel.hpp | 2 ++ source/gui/widgets/label.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp index 248a36eb..2547f157 100644 --- a/include/nana/gui/widgets/panel.hpp +++ b/include/nana/gui/widgets/panel.hpp @@ -44,11 +44,13 @@ namespace nana panel(window wd, bool visible) { this->create(wd, rectangle(), visible); + bgcolor(API::bgcolor(wd)); } panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true) { this->create(wd, r, visible); + bgcolor(API::bgcolor(wd)); } bool transparent() const diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index 8c534c67..b68162d7 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -765,23 +765,27 @@ namespace nana label::label(window wd, bool visible) { create(wd, rectangle(), visible); + bgcolor(API::bgcolor(wd)); } label::label(window wd, const nana::string& text, bool visible) { create(wd, rectangle(), visible); + bgcolor(API::bgcolor(wd)); caption(text); } label::label(window wd, const nana::char_t* text, bool visible) { create(wd, rectangle(), visible); + bgcolor(API::bgcolor(wd)); caption(text); } label::label(window wd, const rectangle& r, bool visible) { create(wd, r, visible); + bgcolor(API::bgcolor(wd)); } label& label::transparent(bool enabled) From 10f35de8f72310ad37ec6922c6464f0a8425a944 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 21 Mar 2015 18:17:50 +0100 Subject: [PATCH 19/77] fix: make checkbox and label have the same bgcolor as the owner --- source/gui/widgets/checkbox.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/gui/widgets/checkbox.cpp b/source/gui/widgets/checkbox.cpp index 1a73f706..8993a8b7 100644 --- a/source/gui/widgets/checkbox.cpp +++ b/source/gui/widgets/checkbox.cpp @@ -129,22 +129,26 @@ namespace checkbox checkbox::checkbox(window wd, bool visible) { create(wd, rectangle(), visible); + bgcolor(API::bgcolor(wd)); } checkbox::checkbox(window wd, const nana::string& text, bool visible) { create(wd, rectangle(), visible); + bgcolor(API::bgcolor(wd)); caption(text); } checkbox::checkbox(window wd, const nana::char_t* text, bool visible) { create(wd, rectangle(), visible); + bgcolor(API::bgcolor(wd)); caption(text); } checkbox::checkbox(window wd, const nana::rectangle& r, bool visible) { + bgcolor(API::bgcolor(wd)); create(wd, r, visible); } From f93c71ed808249a486110a4efd7b3395b3ef259f Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 22 Mar 2015 02:54:18 +0100 Subject: [PATCH 20/77] FIX: minor problem erasing excess text of last cell in selected listbox item --- source/gui/widgets/listbox.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index ef7a7130..cb45040a 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2607,6 +2607,7 @@ namespace nana graph->rectangle(rectangle{ r.x, y, show_w, essence_->item_size }, true); int item_xpos = x; + unsigned extreme_text = x; bool first = true; for(auto index : seqs) @@ -2683,17 +2684,23 @@ namespace nana graph->string(point{ xpos, y + 2 }, STR("...")); //Erase the part that over the next subitem. - if (index + 1 <= seqs.size()) + if (index + 1 < seqs.size()) { graph->set_color(bgcolor); graph->rectangle(rectangle{item_xpos + static_cast(header.pixels), y + 2, ts.width + ext_w - header.pixels, essence_->item_size - 4}, true); } + extreme_text = std::max (extreme_text, item_xpos + ext_w + ts.width); } } graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, { 0xEB, 0xF4, 0xF9 }); item_xpos += header.pixels; + if (index + 1 >= seqs.size() && extreme_text > item_xpos) + { + graph->set_color(item.bgcolor); + graph->rectangle(rectangle{item_xpos , y + 2, extreme_text - item_xpos, essence_->item_size - 4}, true); + } first = false; } From 835b3ce14562542ec49a3563ec603fd8321bc9fd Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 22 Mar 2015 02:56:03 +0100 Subject: [PATCH 21/77] FIX: return self pos (= *i ) --- source/gui/widgets/listbox.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index cb45040a..837af8b3 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -841,8 +841,11 @@ namespace nana if (pos >= catobj.sorted.size()) throw std::out_of_range("listbox: Invalid item position."); - auto i = std::find(catobj.sorted.begin(), catobj.sorted.end(), pos); - return (i != catobj.sorted.end() ? *i : npos); + for (size_type i=0; i Date: Sun, 22 Mar 2015 02:57:50 +0100 Subject: [PATCH 22/77] FIX: select range of items with shift and mouse when list is ordered --- source/gui/widgets/listbox.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 837af8b3..2fdd474a 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1181,6 +1181,21 @@ namespace nana if (to.is_item()) item_proxy(ess_, to).select(sel); } + void select_display_range(index_pair fr_abs, index_pair to_dpl, bool sel) + { + index_pair fr_dpl (fr_abs.cat, this->display_order(fr_abs.cat, fr_abs.item)); + if (fr_dpl > to_dpl) + std::swap(fr_dpl, to_dpl); + + for (; fr_dpl != to_dpl; forward(fr_dpl, 1, fr_dpl)) + { + if (fr_dpl.is_item()) + item_proxy(ess_, index_pair(fr_dpl.cat, absolute( fr_dpl ) )).select(sel); + } + + if (to_dpl.is_item()) + item_proxy(ess_, index_pair(to_dpl.cat, absolute( to_dpl ) )).select(sel); + } bool select_for_all(bool sel) { @@ -2609,7 +2624,7 @@ namespace nana graph->set_color(bgcolor); graph->rectangle(rectangle{ r.x, y, show_w, essence_->item_size }, true); - int item_xpos = x; + int item_xpos = x; unsigned extreme_text = x; bool first = true; @@ -2688,7 +2703,7 @@ namespace nana //Erase the part that over the next subitem. if (index + 1 < seqs.size()) - { + { graph->set_color(bgcolor); graph->rectangle(rectangle{item_xpos + static_cast(header.pixels), y + 2, ts.width + ext_w - header.pixels, essence_->item_size - 4}, true); } @@ -2926,9 +2941,9 @@ namespace nana if (!lister.single_selection()) { if (arg.shift) - lister.select_range(lister.last_selected, item_pos, sel); + lister.select_display_range(lister.last_selected, item_pos, sel); else if (arg.ctrl) - sel = !item_proxy(essence_, item_pos).selected(); + sel = !item_proxy(essence_, item_pos).selected(); else lister.select_for_all(false); } @@ -2938,7 +2953,7 @@ namespace nana if(item_ptr) { item_ptr->flags.selected = sel; - index_pair last_selected(item_pos.cat, lister.absolute(item_pos)); + index_pair last_selected(item_pos.cat, lister.absolute(item_pos)); arg_listbox arg{item_proxy{essence_, last_selected}, sel}; lister.wd_ptr()->events().selected.emit(arg); From 0cbe4534fff56891220458cc64c0828d50c4c844 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 22 Mar 2015 03:07:21 +0100 Subject: [PATCH 23/77] FIX: unselect item with ctrl-click in ordered listbox --- 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 2fdd474a..22b87cf3 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2943,7 +2943,7 @@ namespace nana if (arg.shift) lister.select_display_range(lister.last_selected, item_pos, sel); else if (arg.ctrl) - sel = !item_proxy(essence_, item_pos).selected(); + sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); else lister.select_for_all(false); } From 974e47d59e15cef5ab584cd4111429d5a4b9641d Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 22 Mar 2015 03:12:55 +0100 Subject: [PATCH 24/77] FIX ? : select - unselect item with click in single selection listbox --- 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 22b87cf3..5b2c4ff8 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2948,7 +2948,7 @@ namespace nana lister.select_for_all(false); } else - sel = !item_proxy(essence_, item_pos).selected(); + sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); if(item_ptr) { From e4382239e59a1da1e647a7e9424d765fa67ead23 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 22 Mar 2015 11:19:27 +0800 Subject: [PATCH 25/77] refactor the class screen --- include/nana/gui/screen.hpp | 20 +++- include/nana/gui/widgets/panel.hpp | 6 +- source/gui/screen.cpp | 186 +++++++++++++++-------------- source/gui/tooltip.cpp | 4 +- source/gui/widgets/label.cpp | 8 +- source/gui/widgets/menu.cpp | 2 +- 6 files changed, 124 insertions(+), 102 deletions(-) diff --git a/include/nana/gui/screen.hpp b/include/nana/gui/screen.hpp index ef2aaac1..ef9126e8 100644 --- a/include/nana/gui/screen.hpp +++ b/include/nana/gui/screen.hpp @@ -27,25 +27,37 @@ namespace nana /// The index of monitor. virtual std::size_t get_index() const = 0; + virtual bool is_primary_monitor() const = 0; + /// Returns the positional coordinates and size of the display device in reference to the desktop area virtual const ::nana::rectangle& area() const = 0; + virtual const ::nana::rectangle& workarea() const = 0; }; class screen { + struct implement; public: static ::nana::size desktop_size(); static ::nana::size primary_monitor_size(); - static std::shared_ptr from_point(const point&); - static std::shared_ptr from_window(window); + + screen(); + + /// Reload has no preconditions, it's safe to call on moved-from + void reload(); /// Returns the number of display monitors std::size_t count() const; - std::shared_ptr get_display(std::size_t index) const; - std::shared_ptr get_primary() const; + display& from_point(const point&); + display& from_window(window); + + display& get_display(std::size_t index) const; + display& get_primary() const; void for_each(std::function) const; + private: + std::shared_ptr impl_; }; }//end namespace nana diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp index 2547f157..d5c0bbe7 100644 --- a/include/nana/gui/widgets/panel.hpp +++ b/include/nana/gui/widgets/panel.hpp @@ -8,6 +8,8 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/panel.hpp + * @author: Jinhao + * @contributors: qPCR4vir * * @brief panel is a widget used for placing some widgets. */ @@ -44,13 +46,13 @@ namespace nana panel(window wd, bool visible) { this->create(wd, rectangle(), visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); } panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true) { this->create(wd, r, visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); } bool transparent() const diff --git a/source/gui/screen.cpp b/source/gui/screen.cpp index ef6c8fec..952a17db 100644 --- a/source/gui/screen.cpp +++ b/source/gui/screen.cpp @@ -25,39 +25,22 @@ namespace nana : public display { public: - real_display(std::size_t number) - : index_(number) - { -#if defined(NANA_WINDOWS) - DISPLAY_DEVICE disp; - disp.cb = sizeof disp; - if (::EnumDisplayDevices(nullptr, static_cast(index_), &disp, 0)) - { - DEVMODE mode; - mode.dmSize = sizeof mode; - if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) - { - area_.x = mode.dmPosition.x; - area_.y = mode.dmPosition.y; - area_.width = mode.dmPelsWidth; - area_.height = mode.dmPelsHeight; - return; - } - } -#else - if (0 == index_) - { - area_ = detail::native_interface::primary_monitor_size(); - return; - } -#endif - throw std::invalid_argument("Nana.Screen: Invalid monitor index."); - } + real_display() = default; //For requirement of vector - real_display(std::size_t number, const ::nana::rectangle& r) - : index_(number), area_(r) +#if defined(NANA_WINDOWS) + real_display(std::size_t number, const MONITORINFOEX& mi) + : index_(number), + is_primary_(mi.dwFlags & MONITORINFOF_PRIMARY), + area_(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top), + workarea_(mi.rcWork.left, mi.rcWork.top, mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top) { } +#else + real_display(std::size_t number, const ::nana::rectangle& r) + : index_(number), is_primary_(true), area_(r), workarea_(r) + { + } +#endif public: //Implementation of display std::size_t get_index() const override @@ -65,13 +48,25 @@ namespace nana return index_; } + bool is_primary_monitor() const override + { + return is_primary_; + } + const ::nana::rectangle& area() const override { return area_; } + + const ::nana::rectangle& workarea() const override + { + return workarea_; + } private: - const std::size_t index_; + std::size_t index_; + bool is_primary_; ::nana::rectangle area_; + ::nana::rectangle workarea_; }; //class screen @@ -92,7 +87,58 @@ namespace nana return ::nana::detail::native_interface::primary_monitor_size(); } - std::shared_ptr screen::from_point(const point& pos) + + struct screen::implement + { + std::vector displays; + +#if defined(NANA_WINDOWS) + void load_monitors() + { + std::vector tmp; + ::EnumDisplayMonitors(nullptr, nullptr, implement::enum_proc, reinterpret_cast(&tmp)); + tmp.swap(displays); + } + + static BOOL __stdcall enum_proc(HMONITOR handle, HDC context, LPRECT r, LPARAM self_ptr) + { + auto disp_cont = reinterpret_cast*>(self_ptr); + MONITORINFOEX mi; + mi.cbSize = sizeof(MONITORINFOEX); + if (::GetMonitorInfo(handle, &mi)) + disp_cont->emplace_back(disp_cont->size(), mi); + + return TRUE; + } +#else + void load_monitors() + { + displays.emplace_back(0, primary_monitor_size()); + } +#endif + + }; + + screen::screen() + : impl_(std::make_shared()) + { + impl_->load_monitors(); + } + + + void screen::reload() + { + impl_.reset(std::make_shared()); + impl_->load_monitors(); + } + + std::size_t screen::count() const + { + return impl_->displays.size(); + } + + + display& screen::from_point(const point& pos) { #if defined(NANA_WINDOWS) typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD); @@ -107,87 +153,47 @@ namespace nana mi.cbSize = sizeof mi; if (::GetMonitorInfo(monitor, &mi)) { - DISPLAY_DEVICE disp; - disp.cb = sizeof disp; - - DWORD index = 0; - while (::EnumDisplayDevices(nullptr, index++, &disp, 0)) + for (auto & disp : impl_->displays) { - DEVMODE mode; - mode.dmSize = sizeof mode; - if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) - { - if (mode.dmPosition.x == mi.rcWork.left && mode.dmPosition.y == mi.rcWork.top && - (static_cast(mode.dmPelsWidth) == mi.rcWork.right - mi.rcWork.left) && - (static_cast(mode.dmPelsHeight) == mi.rcWork.bottom - mi.rcWork.top)) - { - return std::make_shared(static_cast(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast(mode.dmPelsWidth), static_cast(mode.dmPelsHeight) }); - } - } + auto & r = disp.area(); + if (r.x == mi.rcMonitor.left && r.y == mi.rcMonitor.top && + r.width == unsigned(mi.rcMonitor.right - mi.rcMonitor.left) && + r.height == unsigned(mi.rcMonitor.bottom - mi.rcMonitor.top) + ) + return disp; } } } #endif - return screen().get_primary(); + return get_primary(); } - std::shared_ptr screen::from_window(window wd) + display& screen::from_window(window wd) { ::nana::point pos; API::calc_screen_point(wd, pos); return from_point(pos); } - std::size_t screen::count() const - { -#if defined(NANA_WINDOWS) - DISPLAY_DEVICE disp; - disp.cb = sizeof disp; - DWORD index = 0; - while (::EnumDisplayDevices(nullptr, index++, &disp, 0)); - return static_cast(index - 1); -#else - return 1; -#endif + display& screen::get_display(std::size_t index) const + { + return impl_->displays.at(index); } - std::shared_ptr screen::get_display(std::size_t index) const + display& screen::get_primary() const { - return std::make_shared(index); - } + for (auto & disp : impl_->displays) + if (disp.is_primary_monitor()) + return disp; - std::shared_ptr screen::get_primary() const - { -#if defined(NANA_WINDOWS) - //return rectangle(mi.rcWork.left, mi.rcWork.top, - // mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top); - DISPLAY_DEVICE disp; - disp.cb = sizeof disp; - - DWORD index = 0; - while (::EnumDisplayDevices(nullptr, index++, &disp, 0)) - { - DEVMODE mode; - mode.dmSize = sizeof mode; - if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) - { - if (mode.dmPosition.x == 0 && mode.dmPosition.y == 0) - return std::make_shared(static_cast(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast(mode.dmPelsWidth), static_cast(mode.dmPelsHeight) }); - } - } -#endif - return std::make_shared(0); + throw std::logic_error("no primary monitor found"); } void screen::for_each(std::function fn) const { - auto n = count(); - for (decltype(n) i = 0; i < n; ++i) - { - real_display disp(i); + for (auto & disp : impl_->displays) fn(disp); - } } //end class screen } diff --git a/source/gui/tooltip.cpp b/source/gui/tooltip.cpp index 02eae44d..45656d01 100644 --- a/source/gui/tooltip.cpp +++ b/source/gui/tooltip.cpp @@ -34,7 +34,7 @@ namespace nana nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed) { - auto scr_area = screen::from_point(pos)->area(); + auto scr_area = screen().from_point(pos).workarea(); if (pos.x + sz.width > scr_area.x + scr_area.width) pos.x = static_cast(scr_area.x + scr_area.width - sz.width); if (pos.x < scr_area.x) @@ -77,7 +77,7 @@ namespace nana void tooltip_text(const nana::string& text) override { label_.caption(text); - auto text_s = label_.measure(screen::from_window(label_)->area().width * 2 / 3); + auto text_s = label_.measure(screen().from_window(label_).workarea().width * 2 / 3); this->size(nana::size{ text_s.width + 10, text_s.height + 10 }); label_.move(rectangle{ 5, 5, text_s.width, text_s.height }); diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index b68162d7..c0cf78c8 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -8,6 +8,8 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: source/gui/widgets/label.cpp + * @author: Jinhao + * @contributors: qPCR4vir */ #include @@ -771,21 +773,21 @@ namespace nana label::label(window wd, const nana::string& text, bool visible) { create(wd, rectangle(), visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); caption(text); } label::label(window wd, const nana::char_t* text, bool visible) { create(wd, rectangle(), visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); caption(text); } label::label(window wd, const rectangle& r, bool visible) { create(wd, r, visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); } label& label::transparent(bool enabled) diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 129cb7bc..2b25810b 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -659,7 +659,7 @@ namespace nana API::calc_screen_point(*widget_, pos); //get the screen coordinates of the widget pos. - auto scr_area = screen::from_point(detail_.monitor_pos)->area(); + auto scr_area = screen().from_point(detail_.monitor_pos).workarea(); if(pos.x + size.width > scr_area.x + scr_area.width) pos.x = static_cast(scr_area.x + scr_area.width - size.width); From 0f4786898a0b4cbb18f0d25be8edb73c720e7bf7 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 22 Mar 2015 22:18:26 +0800 Subject: [PATCH 26/77] fix unexpected window size unexpected window size when the size is equal to display area size or display workarea size --- source/gui/detail/native_window_interface.cpp | 57 +++++++++++-------- source/gui/screen.cpp | 7 ++- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index a862af75..5f67669f 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -13,6 +13,7 @@ #include #include PLATFORM_SPEC_HPP #include +#include #if defined(NANA_WINDOWS) #if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED) #include @@ -35,10 +36,10 @@ namespace nana{ #if defined(NANA_WINDOWS) static HICON icon(const nana::paint::image& img) { - paint::detail::image_ico * ico = dynamic_cast(img.image_ptr_.get()); + auto ico = dynamic_cast(img.image_ptr_.get()); if(ico && ico->ptr()) return *(ico->ptr()); - return 0; + return nullptr; } #endif }; @@ -51,17 +52,13 @@ namespace nana{ { struct window_extra_t { - HICON ico; - - window_extra_t() - : ico(0) - {} + HICON ico{nullptr}; }; typedef std::map map_t; private: - tray_manager(){} + tray_manager() = default; public: typedef window_extra_t extra_t; @@ -205,35 +202,49 @@ namespace nana{ if(owner && (nested == false)) ::ClientToScreen(reinterpret_cast(owner), &pt); - HWND wnd = ::CreateWindowEx(style_ex, STR("NanaWindowInternal"), STR("Nana Window"), + HWND native_wd = ::CreateWindowEx(style_ex, STR("NanaWindowInternal"), STR("Nana Window"), style, pt.x, pt.y, 100, 100, reinterpret_cast(owner), 0, ::GetModuleHandle(0), 0); //A window may have a border, this should be adjusted the client area fit for the specified size. ::RECT client; - ::GetClientRect(wnd, &client); //The right and bottom of client by GetClientRect indicate the width and height of the area + ::GetClientRect(native_wd, &client); //The right and bottom of client by GetClientRect indicate the width and height of the area ::RECT wd_area; - ::GetWindowRect(wnd, &wd_area); - wd_area.right -= wd_area.left; - wd_area.bottom -= wd_area.top; - if(nested) + ::GetWindowRect(native_wd, &wd_area); + + screen scr; + auto & disp = scr.from_point({wd_area.left, wd_area.right}); + + if ((disp.area().width == r.width && disp.area().height == r.height) || + (disp.workarea().width == r.width && disp.workarea().height == r.height)) { - wd_area.left = pt.x; - wd_area.top = pt.y; + ::MoveWindow(native_wd, r.x, r.y, r.width, r.height, true); + } + else + { + //a dimension with borders and caption title + wd_area.right -= wd_area.left; //wd_area.right = width + wd_area.bottom -= wd_area.top; //wd_area.bottom = height + if (nested) + { + wd_area.left = pt.x; + wd_area.top = pt.y; + } + + int delta_w = static_cast(r.width) - client.right; + int delta_h = static_cast(r.height) - client.bottom; + + ::MoveWindow(native_wd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true); } - int delta_w = static_cast(r.width) - client.right; - int delta_h = static_cast(r.height) - client.bottom; + ::GetClientRect(native_wd, &client); + ::GetWindowRect(native_wd, &wd_area); - ::MoveWindow(wnd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true); - - ::GetClientRect(wnd, &client); - ::GetWindowRect(wnd, &wd_area); wd_area.right -= wd_area.left; wd_area.bottom -= wd_area.top; - window_result result = {reinterpret_cast(wnd), + window_result result = { reinterpret_cast(native_wd), static_cast(client.right), static_cast(client.bottom), static_cast(wd_area.right - client.right), static_cast(wd_area.bottom - client.bottom)}; #elif defined(NANA_X11) diff --git a/source/gui/screen.cpp b/source/gui/screen.cpp index 952a17db..b16eb9d8 100644 --- a/source/gui/screen.cpp +++ b/source/gui/screen.cpp @@ -113,6 +113,7 @@ namespace nana #else void load_monitors() { + displays.clear(); displays.emplace_back(0, primary_monitor_size()); } #endif @@ -125,10 +126,12 @@ namespace nana impl_->load_monitors(); } - void screen::reload() { - impl_.reset(std::make_shared()); + //It is only when the screen is a moved-from object that impl_ is empty + if (!impl_) + impl_.swap(std::make_shared()); + impl_->load_monitors(); } From 82ee5706910a8c7277d95b284e66c7608c00394f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 22 Mar 2015 22:23:18 +0800 Subject: [PATCH 27/77] compare between signed and unsigned --- 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 5b2c4ff8..5ae31f61 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2714,7 +2714,7 @@ namespace nana graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, { 0xEB, 0xF4, 0xF9 }); item_xpos += header.pixels; - if (index + 1 >= seqs.size() && extreme_text > item_xpos) + if (index + 1 >= seqs.size() && static_cast(extreme_text) > item_xpos) { graph->set_color(item.bgcolor); graph->rectangle(rectangle{item_xpos , y + 2, extreme_text - item_xpos, essence_->item_size - 4}, true); From 58b206cb931a3376e3e6fb84c453a237cf765c57 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 24 Mar 2015 12:12:36 +0800 Subject: [PATCH 28/77] add new outline size API::window_outline_size changes the window size(not client area size) for a native window --- include/nana/gui/programming_interface.hpp | 8 ++-- include/nana/gui/widgets/widget.hpp | 10 ++++ source/gui/detail/native_window_interface.cpp | 29 ++++-------- source/gui/programming_interface.cpp | 46 +++++++++++++++++-- 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index b65a15fc..7caf038b 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -193,7 +193,7 @@ namespace API return *comp_wdg_colors; } - nana::point window_position(window); + point window_position(window); void move_window(window, int x, int y); void move_window(window wd, const rectangle&); @@ -203,9 +203,11 @@ namespace API void draw_through(window, std::function); void map_through_widgets(window, native_drawable_type); - nana::size window_size(window); + size window_size(window); void window_size(window, const size&); - bool window_rectangle(window, rectangle&); + size window_outline_size(window); + void window_outline_size(window, const size&); + bool get_window_rectangle(window, rectangle&); bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window. void window_enabled(window, bool); bool window_enabled(window); diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index 2a010b55..9d298fbe 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -409,6 +409,16 @@ namespace nana { API::map_through_widgets(handle(), drawable); } + + void outline_size(const ::nana::size& sz) + { + API::window_outline_size(handle(), sz); + } + + ::nana::size outline_size() const + { + return API::window_outline_size(handle()); + } protected: DrawerTrigger& get_drawer_trigger() { diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 5f67669f..0ad45b61 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -213,30 +213,19 @@ namespace nana{ ::RECT wd_area; ::GetWindowRect(native_wd, &wd_area); - screen scr; - auto & disp = scr.from_point({wd_area.left, wd_area.right}); - - if ((disp.area().width == r.width && disp.area().height == r.height) || - (disp.workarea().width == r.width && disp.workarea().height == r.height)) + //a dimension with borders and caption title + wd_area.right -= wd_area.left; //wd_area.right = width + wd_area.bottom -= wd_area.top; //wd_area.bottom = height + if (nested) { - ::MoveWindow(native_wd, r.x, r.y, r.width, r.height, true); + wd_area.left = pt.x; + wd_area.top = pt.y; } - else - { - //a dimension with borders and caption title - wd_area.right -= wd_area.left; //wd_area.right = width - wd_area.bottom -= wd_area.top; //wd_area.bottom = height - if (nested) - { - wd_area.left = pt.x; - wd_area.top = pt.y; - } - int delta_w = static_cast(r.width) - client.right; - int delta_h = static_cast(r.height) - client.bottom; + int delta_w = static_cast(r.width) - client.right; + int delta_h = static_cast(r.height) - client.bottom; - ::MoveWindow(native_wd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true); - } + ::MoveWindow(native_wd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true); ::GetClientRect(native_wd, &client); ::GetWindowRect(native_wd, &wd_area); diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 9ba95f03..6af6945d 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -1,13 +1,14 @@ /* * Nana GUI Programming Interface Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 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/programming_interface.cpp + * @author: Jinhao */ #include @@ -598,7 +599,7 @@ namespace API nana::size window_size(window wd) { nana::rectangle r; - API::window_rectangle(wd, r); + API::get_window_rectangle(wd, r); return{ r.width, r.height }; } @@ -618,7 +619,46 @@ namespace API } } - bool window_rectangle(window wd, rectangle& r) + ::nana::size window_outline_size(window wd) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (!restrict::window_manager.available(iwd)) + return{}; + + auto sz = window_size(wd); + sz.width += iwd->extra_width; + sz.height += iwd->extra_height; + return sz; + } + + void window_outline_size(window wd, const size& sz) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (restrict::window_manager.available(iwd)) + { + if (category::flags::root == iwd->other.category) + { + size inner_size = sz; + if (inner_size.width < iwd->extra_width) + inner_size.width = 0; + else + inner_size.width -= iwd->extra_width; + + if (inner_size.height < iwd->extra_height) + inner_size.height = 0; + else + inner_size.height -= iwd->extra_height; + + window_size(wd, inner_size); + } + else + window_size(wd, sz); + } + } + + bool get_window_rectangle(window wd, rectangle& r) { auto iwd = reinterpret_cast(wd); internal_scope_guard lock; From 9a5dfe7f88d07a45a32542d1f832090796b7f645 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 25 Mar 2015 01:44:56 +0800 Subject: [PATCH 29/77] fix no response of Delete key --- include/nana/gui/widgets/skeletons/text_editor.hpp | 4 ++-- source/gui/widgets/combox.cpp | 12 ++++++++++-- source/gui/widgets/spinbox.cpp | 4 ++-- source/gui/widgets/textbox.cpp | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 7b861606..e8afb9b9 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -157,7 +157,8 @@ namespace nana{ namespace widgets void set_accept(std::function); void set_accept(accepts); - bool respone_keyboard(char_type); + bool respone_char(char_type); + bool respone_key(char_type); void typeface_changed(); @@ -227,7 +228,6 @@ namespace nana{ namespace widgets void del(); void backspace(bool record_undo = true); void undo(bool reverse); - bool move(nana::char_t); void move_ns(bool to_north); //Moves up and down void move_left(); void move_right(); diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index c39c7a83..bf6a03e7 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -677,6 +677,7 @@ namespace nana if(!drawer_->widget_ptr()->enabled()) return; + bool call_other_keys = false; if(drawer_->editable()) { bool is_move_up = false; @@ -684,7 +685,7 @@ namespace nana { case keyboard::os_arrow_left: case keyboard::os_arrow_right: - drawer_->editor()->move(arg.key); + drawer_->editor()->respone_key(arg.key); drawer_->editor()->reset_caret(); break; case keyboard::os_arrow_up: @@ -692,6 +693,8 @@ namespace nana case keyboard::os_arrow_down: drawer_->move_items(is_move_up, true); break; + default: + call_other_keys = true; } } else @@ -706,14 +709,19 @@ namespace nana case keyboard::os_arrow_down: drawer_->move_items(is_move_up, true); break; + default: + call_other_keys = true; } } + if (call_other_keys) + drawer_->editor()->respone_key(arg.key); + API::lazy_refresh(); } void trigger::key_char(graph_reference graph, const arg_keyboard& arg) { - if (drawer_->editor()->respone_keyboard(arg.key)) + if (drawer_->editor()->respone_char(arg.key)) API::lazy_refresh(); } //end class trigger diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index c99367ae..c3720fdc 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -559,7 +559,7 @@ namespace nana void drawer::key_press(graph_reference, const arg_keyboard& arg) { - if (impl_->editor()->move(arg.key)) + if (impl_->editor()->respone_key(arg.key)) { impl_->editor()->reset_caret(); impl_->draw_spins(); @@ -569,7 +569,7 @@ namespace nana void drawer::key_char(graph_reference, const arg_keyboard& arg) { - if (impl_->editor()->respone_keyboard(arg.key)) + if (impl_->editor()->respone_char(arg.key)) { if (!impl_->value(impl_->editor()->text())) impl_->draw_spins(); diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index cd30dafe..e7030baa 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -136,7 +136,7 @@ namespace drawerbase { void drawer::key_press(graph_reference, const arg_keyboard& arg) { - if(editor_->move(arg.key)) + if(editor_->respone_key(arg.key)) { editor_->reset_caret(); API::lazy_refresh(); @@ -145,7 +145,7 @@ namespace drawerbase { void drawer::key_char(graph_reference, const arg_keyboard& arg) { - if (editor_->respone_keyboard(arg.key)) + if (editor_->respone_char(arg.key)) API::lazy_refresh(); } From 6a0fd78595de56f63c02cf7972e260de241666e7 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 25 Mar 2015 01:56:48 +0800 Subject: [PATCH 30/77] fix no response of Delete --- .../gui/widgets/skeletons/text_editor.hpp | 4 +- source/gui/widgets/combox.cpp | 6 +-- source/gui/widgets/skeletons/text_editor.cpp | 39 +++++++++---------- source/gui/widgets/spinbox.cpp | 4 +- source/gui/widgets/textbox.cpp | 4 +- 5 files changed, 28 insertions(+), 29 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index e8afb9b9..976c168d 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -157,8 +157,8 @@ namespace nana{ namespace widgets void set_accept(std::function); void set_accept(accepts); - bool respone_char(char_type); - bool respone_key(char_type); + bool respond_char(char_type); + bool respond_key(char_type); void typeface_changed(); diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index bf6a03e7..b1d401f5 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -685,7 +685,7 @@ namespace nana { case keyboard::os_arrow_left: case keyboard::os_arrow_right: - drawer_->editor()->respone_key(arg.key); + drawer_->editor()->respond_key(arg.key); drawer_->editor()->reset_caret(); break; case keyboard::os_arrow_up: @@ -714,14 +714,14 @@ namespace nana } } if (call_other_keys) - drawer_->editor()->respone_key(arg.key); + drawer_->editor()->respond_key(arg.key); API::lazy_refresh(); } void trigger::key_char(graph_reference graph, const arg_keyboard& arg) { - if (drawer_->editor()->respone_char(arg.key)) + if (drawer_->editor()->respond_char(arg.key)) API::lazy_refresh(); } //end class trigger diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 0cb39750..da01d92e 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1326,7 +1326,7 @@ namespace nana{ namespace widgets attributes_.acceptive = acceptive; } - bool text_editor::respone_keyboard(char_type key) //key is a character of ASCII code + bool text_editor::respond_char(char_type key) //key is a character of ASCII code { switch (key) { @@ -1377,6 +1377,24 @@ namespace nana{ namespace widgets return false; } + bool text_editor::respond_key(char_type key) + { + switch (key) + { + case keyboard::os_arrow_left: move_left(); break; + case keyboard::os_arrow_right: move_right(); break; + case keyboard::os_arrow_up: move_ns(true); break; + case keyboard::os_arrow_down: move_ns(false); break; + case keyboard::os_del: + if (this->attr().editable) + del(); + break; + default: + return false; + } + return true; + } + void text_editor::typeface_changed() { behavior_->pre_calc_lines(width_pixels()); @@ -2105,25 +2123,6 @@ namespace nana{ namespace widgets } - bool text_editor::move(nana::char_t key) - { - switch(key) - { - case keyboard::os_arrow_left: move_left(); break; - case keyboard::os_arrow_right: move_right(); break; - case keyboard::os_arrow_up: move_ns(true); break; - case keyboard::os_arrow_down: move_ns(false); break; - case keyboard::os_del: - if (this->attr().editable) - del(); - break; - default: - return false; - } - return true; - } - - void text_editor::move_ns(bool to_north) { const bool redraw_required = _m_cancel_select(0); diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index c3720fdc..ebbf006e 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -559,7 +559,7 @@ namespace nana void drawer::key_press(graph_reference, const arg_keyboard& arg) { - if (impl_->editor()->respone_key(arg.key)) + if (impl_->editor()->respond_key(arg.key)) { impl_->editor()->reset_caret(); impl_->draw_spins(); @@ -569,7 +569,7 @@ namespace nana void drawer::key_char(graph_reference, const arg_keyboard& arg) { - if (impl_->editor()->respone_char(arg.key)) + if (impl_->editor()->respond_char(arg.key)) { if (!impl_->value(impl_->editor()->text())) impl_->draw_spins(); diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index e7030baa..aabb494e 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -136,7 +136,7 @@ namespace drawerbase { void drawer::key_press(graph_reference, const arg_keyboard& arg) { - if(editor_->respone_key(arg.key)) + if(editor_->respond_key(arg.key)) { editor_->reset_caret(); API::lazy_refresh(); @@ -145,7 +145,7 @@ namespace drawerbase { void drawer::key_char(graph_reference, const arg_keyboard& arg) { - if (editor_->respone_char(arg.key)) + if (editor_->respond_char(arg.key)) API::lazy_refresh(); } From 47695b05034bb225478aae136cc26d9c22fd24ea Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 25 Mar 2015 11:07:19 +0100 Subject: [PATCH 31/77] FIX: find only first keyword in line --- source/gui/widgets/skeletons/text_editor.cpp | 89 ++++++++++---------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index da01d92e..913d858d 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1133,12 +1133,14 @@ namespace nana{ namespace widgets public: void parse(const ::nana::string& text, const keywords* kwptr) { - if (text.empty()) + if ( kwptr->kwbase.empty() || text.empty() ) return; + using index = ::nana::string::size_type; + std::vector entities; - auto test_whole_word = [&text](std::size_t pos, std::size_t len) + auto test_whole_word = [&text](index pos, index len) { if (pos) { @@ -1160,53 +1162,48 @@ namespace nana{ namespace widgets ::nana::cistring cistr; for (auto & ds : kwptr->kwbase) { - std::size_t pos; - const ::nana::char_t* begin; - const ::nana::char_t* end; - if (ds.case_sensitive) - { - pos = text.find(ds.text); - if (pos == text.npos) - continue; + index pos{0} ; + for (index rest{text.size()}; rest >= ds.text.size() ; ++pos, rest = text.size() - pos) + { + if (ds.case_sensitive) + { + pos = text.find(ds.text, pos); + if (pos == text.npos) + break; - if (ds.whole_word_matched) - { - if (!test_whole_word(pos, ds.text.size())) - continue; - } + if (ds.whole_word_matched) + { + if (!test_whole_word(pos, ds.text.size())) + continue; + } + } + else + { + if (cistr.empty()) + cistr.append(text.data(), text.size()); - begin = text.data() + pos; - end = begin + ds.text.size(); - } - else - { - if (cistr.empty()) - cistr.append(text.data(), text.size()); + pos = cistr.find(ds.text.data(), pos); + if (pos == cistr.npos) + break; - pos = cistr.find(ds.text.data()); - if (pos == cistr.npos) - continue; + if (ds.whole_word_matched) + { + if (!test_whole_word(pos, ds.text.size())) + continue; + } + } - if (ds.whole_word_matched) - { - if (!test_whole_word(pos, ds.text.size())) - continue; - } - - begin = text.data() + pos; - end = begin + ds.text.size(); - } - - auto ki = kwptr->schemes.find(ds.scheme); - if (ki != kwptr->schemes.end() && ki->second) - { - schemes_.emplace(ds.scheme, ki->second); - entities.emplace_back(); - auto & last = entities.back(); - last.begin = begin; - last.end = end; - last.scheme = ki->second.get(); - } + auto ki = kwptr->schemes.find(ds.scheme); + if (ki != kwptr->schemes.end() && ki->second) + { + schemes_.emplace(ds.scheme, ki->second); + entities.emplace_back(); + auto & last = entities.back(); + last.begin = text.data() + pos; + last.end = last.begin + ds.text.size(); + last.scheme = ki->second.get(); + } + } } if (!entities.empty()) @@ -1221,7 +1218,7 @@ namespace nana{ namespace widgets while(i != entities.end()) { if (previous->end > i->begin) - i = entities.erase(i); + i = entities.erase(i); // erase overlaping. Left only the first. else ++i; } From 65a66f98884691f35865b3f0da39cf991563c861 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 26 Mar 2015 23:58:04 +0800 Subject: [PATCH 32/77] fix a syntax error --- source/gui/screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/screen.cpp b/source/gui/screen.cpp index b16eb9d8..a5de12a8 100644 --- a/source/gui/screen.cpp +++ b/source/gui/screen.cpp @@ -130,7 +130,7 @@ namespace nana { //It is only when the screen is a moved-from object that impl_ is empty if (!impl_) - impl_.swap(std::make_shared()); + std::make_shared().swap(impl_); impl_->load_monitors(); } From dcead38544cec64d427864f47b5cce8c6dcaa6a0 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 30 Mar 2015 21:42:22 +0800 Subject: [PATCH 33/77] fix wrong positions of menu and tooltip caused by implicit int to unsigned type conversion when a screen starts a neg point --- source/gui/tooltip.cpp | 11 ++++++----- source/gui/widgets/menu.cpp | 4 ++-- source/gui/widgets/menubar.cpp | 29 ++++++++++++++++------------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/source/gui/tooltip.cpp b/source/gui/tooltip.cpp index 45656d01..04e6f258 100644 --- a/source/gui/tooltip.cpp +++ b/source/gui/tooltip.cpp @@ -1,6 +1,7 @@ /* * A Tooltip Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -35,13 +36,13 @@ namespace nana nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed) { auto scr_area = screen().from_point(pos).workarea(); - if (pos.x + sz.width > scr_area.x + scr_area.width) - pos.x = static_cast(scr_area.x + scr_area.width - sz.width); + if (pos.x + static_cast(sz.width) > scr_area.right()) + pos.x = scr_area.right() - static_cast(sz.width); if (pos.x < scr_area.x) pos.x = scr_area.x; - if (pos.y + sz.height >= scr_area.y + scr_area.height) - pos.y = static_cast(scr_area.y + scr_area.height - sz.height); + if (pos.y + static_cast(sz.height) >= scr_area.bottom()) + pos.y = scr_area.bottom() - static_cast(sz.height); else if (!overlap_allowed) pos.y += 20; //Add some pixels to avoid overlapping between cursor and tip window. diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 2b25810b..d8445c0d 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -661,11 +661,11 @@ namespace nana //get the screen coordinates of the widget pos. auto scr_area = screen().from_point(detail_.monitor_pos).workarea(); - if(pos.x + size.width > scr_area.x + scr_area.width) + if(pos.x + static_cast(size.width) > scr_area.right()) pos.x = static_cast(scr_area.x + scr_area.width - size.width); if(pos.x < scr_area.x) pos.x = scr_area.x; - if(pos.y + size.height > scr_area.y + scr_area.height) + if(pos.y + static_cast(size.height) > scr_area.bottom()) pos.y = static_cast(scr_area.y + scr_area.height - size.height); if(pos.y < scr_area.y) pos.y = scr_area.y; diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 3c584a9e..e6d34cb5 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -1,7 +1,7 @@ /* * A Menubar implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2009-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -30,21 +30,21 @@ namespace nana { struct item_type { - item_type(const nana::string& text, unsigned long shortkey) + item_type(const ::nana::string& text, unsigned long shortkey) : text(text), shortkey(shortkey) {} - nana::string text; + ::nana::string text; unsigned long shortkey; - nana::menu menu_obj; - nana::point pos; - nana::size size; + ::nana::menu menu_obj; + ::nana::point pos; + ::nana::size size; }; class trigger::itembase { public: - typedef std::vector container; + using container = std::vector; ~itembase() { @@ -52,7 +52,7 @@ namespace nana delete i; } - void append(const nana::string& text, unsigned long shortkey) + void append(const ::nana::string& text, unsigned long shortkey) { if(shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41); cont_.push_back(new item_type(text, shortkey)); @@ -122,11 +122,13 @@ namespace nana nana::rectangle r(pos, size); graph_.rectangle(r, false, border); + int right = pos.x + static_cast(size.width) - 1; + int bottom = pos.y + static_cast(size.height) - 1; graph_.set_color(corner); graph_.set_pixel(pos.x, pos.y); - graph_.set_pixel(pos.x + size.width - 1, pos.y); - graph_.set_pixel(pos.x, pos.y + size.height - 1); - graph_.set_pixel(pos.x + size.width - 1, pos.y + size.height - 1); + graph_.set_pixel(right, pos.y); + graph_.set_pixel(pos.x, bottom); + graph_.set_pixel(right, bottom); graph_.rectangle(r.pare_off(1), true, body); } @@ -146,9 +148,9 @@ namespace nana delete items_; } - nana::menu* trigger::push_back(const nana::string& text) + nana::menu* trigger::push_back(const ::nana::string& text) { - nana::string::value_type shkey; + ::nana::string::value_type shkey; API::transform_shortkey_text(text, shkey, nullptr); if(shkey) @@ -157,6 +159,7 @@ namespace nana auto i = items_->cont().size(); items_->append(text, shkey); _m_draw(); + API::update_window(*widget_); return items_->get_menu(i); } From 34e2c6b14308d343e1334cbfece3fe09fcd0570e Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 31 Mar 2015 06:08:43 +0800 Subject: [PATCH 34/77] fix issues of textbox and filebox no refresh when calling textbox line_wrapped add filebox overwrite prompt for saving file the first non-* filter to be set default extentsion for filebox --- source/gui/filebox.cpp | 20 ++++++++++++++++++++ source/gui/widgets/textbox.cpp | 6 +++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index 78a40a3f..094793cc 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -972,6 +972,7 @@ namespace nana const nana::char_t * filter; nana::string filter_holder; + nana::string default_extension; if(impl_->filters.size()) { for(auto & f : impl_->filters) @@ -989,6 +990,21 @@ namespace nana } filter_holder += fs; filter_holder += static_cast('\0'); + + //Get the default file extentsion + if (default_extension.empty()) + { + pos = fs.find_last_of('.'); + if (pos != fs.npos) + { + fs = fs.substr(pos + 1); + if (fs != L"*") + { + default_extension = fs; + ofn.lpstrDefExt = default_extension.data(); + } + } + } } filter = filter_holder.data(); } @@ -1001,6 +1017,10 @@ namespace nana ofn.lpstrFileTitle = nullptr; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = (impl_->path.size() ? impl_->path.c_str() : nullptr); + + if (!impl_->open_or_save) + ofn.Flags = OFN_OVERWRITEPROMPT; //Overwrite prompt if it is save mode + if(FALSE == (impl_->open_or_save ? ::GetOpenFileName(&ofn) : ::GetSaveFileName(&ofn))) return false; diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index aabb494e..840a1762 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -314,7 +314,7 @@ namespace drawerbase { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); if (editor->line_wrapped(autl)) - editor->render(API::is_focus_window(handle())); + API::update_window(handle()); return *this; } @@ -389,7 +389,7 @@ namespace drawerbase { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); if(editor && editor->select(yes)) - API::refresh_window(*this); + API::update_window(*this); } void textbox::copy() const @@ -407,7 +407,7 @@ namespace drawerbase { if(editor) { editor->paste(); - API::refresh_window(*this); + API::update_window(*this); } } From 5060c8bab56a260c90b23f842008842dac81517a Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 2 Apr 2015 21:14:25 +0200 Subject: [PATCH 35/77] fixing lookup error from gcc/mingw --- include/nana/gui/widgets/panel.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp index d5c0bbe7..cf732a7d 100644 --- a/include/nana/gui/widgets/panel.hpp +++ b/include/nana/gui/widgets/panel.hpp @@ -46,13 +46,13 @@ namespace nana panel(window wd, bool visible) { this->create(wd, rectangle(), visible); - bgcolor(API::bgcolor(wd)); + this->bgcolor(API::bgcolor(wd)); } panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true) { this->create(wd, r, visible); - bgcolor(API::bgcolor(wd)); + this->bgcolor(API::bgcolor(wd)); } bool transparent() const From 76a2324b5548b7f45d5d87258395c952e14df923 Mon Sep 17 00:00:00 2001 From: beru Date: Sun, 5 Apr 2015 19:37:20 +0900 Subject: [PATCH 36/77] enable MultiProcessorCompilation to decrease build time --- build/vc2013/nana.vcxproj | 501 +++++++++++++++++++------------------- 1 file changed, 252 insertions(+), 249 deletions(-) diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index c8024ba7..5cf7334f 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -1,250 +1,253 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {25B21068-491B-4A9F-B99F-6C27BF31BAAD} - Win32Proj - nana - - - - StaticLibrary - true - v120 - Unicode - - - StaticLibrary - true - v120 - Unicode - - - StaticLibrary - false - v120 - true - Unicode - - - StaticLibrary - false - v120 - true - Unicode - - - - - - - - - - - - - - - - - - - ../bin/vc2013/ - ..\..\include;$(IncludePath) - ..\..\source;$(VC_SourcePath); - - - ..\..\include;$(IncludePath) - ..\..\source;$(VC_SourcePath); - ../bin/vc2013/ - - - ../bin/vc2013/ - ..\..\include;$(IncludePath) - ..\..\source;$(VC_SourcePath); - - - ..\..\include;$(IncludePath) - ..\..\source;$(VC_SourcePath); - ../bin/vc2013/ - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - Windows - true - - - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - Windows - true - - - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - Windows - true - true - true - - - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - Windows - true - true - true - - - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {25B21068-491B-4A9F-B99F-6C27BF31BAAD} + Win32Proj + nana + + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + ../bin/vc2013/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/vc2013/ + + + ../bin/vc2013/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/vc2013/ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + true + false + + + Windows + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + + + Windows + true + true + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + true + true + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 551fa896e7953549bc90a1f0d7b03a742d3d632e Mon Sep 17 00:00:00 2001 From: beru Date: Sun, 5 Apr 2015 19:57:40 +0900 Subject: [PATCH 37/77] fixed line encoding --- build/vc2013/nana.vcxproj | 504 +++++++++++++++++++------------------- 1 file changed, 252 insertions(+), 252 deletions(-) diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 5cf7334f..7e216758 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -1,253 +1,253 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {25B21068-491B-4A9F-B99F-6C27BF31BAAD} - Win32Proj - nana - - - - StaticLibrary - true - v120 - Unicode - - - StaticLibrary - true - v120 - Unicode - - - StaticLibrary - false - v120 - true - Unicode - - - StaticLibrary - false - v120 - true - Unicode - - - - - - - - - - - - - - - - - - - ../bin/vc2013/ - ..\..\include;$(IncludePath) - ..\..\source;$(VC_SourcePath); - - - ..\..\include;$(IncludePath) - ..\..\source;$(VC_SourcePath); - ../bin/vc2013/ - - - ../bin/vc2013/ - ..\..\include;$(IncludePath) - ..\..\source;$(VC_SourcePath); - - - ..\..\include;$(IncludePath) - ..\..\source;$(VC_SourcePath); - ../bin/vc2013/ - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - true - false - - - Windows - true - - - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - Windows - true - - - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - true - - - Windows - true - true - true - - - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreaded - - - Windows - true - true - true - - - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {25B21068-491B-4A9F-B99F-6C27BF31BAAD} + Win32Proj + nana + + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + ../bin/vc2013/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/vc2013/ + + + ../bin/vc2013/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/vc2013/ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + true + false + + + Windows + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + + + Windows + true + true + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + true + true + true + + + $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 0fee5da0a8cc9d83b4f599eb3fb6807acf1634ca Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 9 Apr 2015 00:50:44 +0200 Subject: [PATCH 38/77] fix wrong positions of menu and tooltip in secondary monitor --- source/basic_types.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/basic_types.cpp b/source/basic_types.cpp index 8edc8a0f..c2e1a9aa 100644 --- a/source/basic_types.cpp +++ b/source/basic_types.cpp @@ -739,12 +739,12 @@ namespace nana int rectangle::right() const { - return static_cast(x + width); + return x + static_cast(width); } int rectangle::bottom() const { - return static_cast(y + height); + return y + static_cast(height); } bool rectangle::is_hit(int pos_x, int pos_y) const @@ -756,7 +756,7 @@ namespace nana bool rectangle::is_hit(const point& pos) const { return (x <= pos.x && pos.x < x + static_cast(width)) && - (y <= pos.y && pos.y < y + static_cast(height)); + (y <= pos.y && pos.y < y + static_cast(height)); } bool rectangle::empty() const From 0ebf3dfacb628c56756bac213bf3ba250f406279 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 10 Apr 2015 00:44:49 +0800 Subject: [PATCH 39/77] fix false alarm of event memory leak remove the unnecessary event leak check --- include/nana/gui/detail/events_operation.hpp | 1 - source/gui/detail/events_operation.cpp | 6 ------ source/gui/detail/win32/bedrock.cpp | 6 ------ source/gui/screen.cpp | 2 +- 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/include/nana/gui/detail/events_operation.hpp b/include/nana/gui/detail/events_operation.hpp index 29c65430..418d2fa2 100644 --- a/include/nana/gui/detail/events_operation.hpp +++ b/include/nana/gui/detail/events_operation.hpp @@ -23,7 +23,6 @@ namespace nana void register_evt(event_handle); void cancel(event_handle); void erase(event_handle); - std::size_t size() const; private: mutable std::recursive_mutex mutex_; std::unordered_set register_; diff --git a/source/gui/detail/events_operation.cpp b/source/gui/detail/events_operation.cpp index ea11923b..cb99accd 100644 --- a/source/gui/detail/events_operation.cpp +++ b/source/gui/detail/events_operation.cpp @@ -41,12 +41,6 @@ namespace nana reinterpret_cast(evt)->get_event()->remove(evt); } } - - std::size_t events_operation::size() const - { - lock_guard lock(mutex_); - return register_.size(); - } //end namespace events_operation }//end namespace detail }//end namespace nana \ No newline at end of file diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 00968a6a..376998de 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -266,12 +266,6 @@ namespace detail ::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK); } - if(evt_operation.size()) - { - std::stringstream ss; - ss<<"Nana.GUI detects a memory leaks in events operation, "<(evt_operation.size())<<" event(s) are not uninstalled."; - ::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK); - } delete impl_; delete pi_data_; } diff --git a/source/gui/screen.cpp b/source/gui/screen.cpp index a5de12a8..f94b0dfa 100644 --- a/source/gui/screen.cpp +++ b/source/gui/screen.cpp @@ -30,7 +30,7 @@ namespace nana #if defined(NANA_WINDOWS) real_display(std::size_t number, const MONITORINFOEX& mi) : index_(number), - is_primary_(mi.dwFlags & MONITORINFOF_PRIMARY), + is_primary_(mi.dwFlags & /*MONITORINFOF_PRIMARY*/ 0x1), area_(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top), workarea_(mi.rcWork.left, mi.rcWork.top, mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top) { From 65c9b35455ca7f0c6509edcc714da9c164db249b Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 10 Apr 2015 10:54:31 +0200 Subject: [PATCH 40/77] fix: Scroll don't get trigged in secondary monitor: no scroll in texbox, trebox, listbox, etc. --- source/gui/detail/win32/bedrock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 376998de..1d15b927 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1101,7 +1101,7 @@ namespace detail case WM_MOUSEHWHEEL: { //The focus window receives the message in Windows system, it should be redirected to the hovered window - ::POINT scr_pos{ int(LOWORD(lParam)), int(HIWORD(lParam)) }; //Screen position + ::POINT scr_pos{ pmdec.mouse.x, pmdec.mouse.y}; // int(LOWORD(lParam)), int(HIWORD(lParam)) }; //Screen position auto pointer_wd = ::WindowFromPoint(scr_pos); if (pointer_wd == root_window) { From a72d7b0ce766f32b40d7f73db90efcb914a2f9da Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 10 Apr 2015 15:01:39 +0200 Subject: [PATCH 41/77] cleaning --- source/gui/detail/win32/bedrock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 1d15b927..ec692d36 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1101,7 +1101,7 @@ namespace detail case WM_MOUSEHWHEEL: { //The focus window receives the message in Windows system, it should be redirected to the hovered window - ::POINT scr_pos{ pmdec.mouse.x, pmdec.mouse.y}; // int(LOWORD(lParam)), int(HIWORD(lParam)) }; //Screen position + ::POINT scr_pos{ pmdec.mouse.x, pmdec.mouse.y}; //Screen position auto pointer_wd = ::WindowFromPoint(scr_pos); if (pointer_wd == root_window) { From ed462870e0a60e1e41b2de08885387633cb66fcf Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 12 Apr 2015 03:31:07 +0800 Subject: [PATCH 42/77] update contributor info --- include/nana/gui/place.hpp | 2 +- include/nana/gui/widgets/panel.hpp | 2 +- source/gui/detail/win32/bedrock.cpp | 3 ++- source/gui/widgets/label.cpp | 18 +++++------------- source/gui/widgets/listbox.cpp | 2 +- source/gui/widgets/skeletons/text_editor.cpp | 2 +- 6 files changed, 11 insertions(+), 18 deletions(-) diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index 1459ba56..a7e7e0ea 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -10,7 +10,7 @@ * @file: nana/gui/place.cpp * * @contributions: - * min/max and splitter bar initial weight by qPCR4vir. + * min/max and splitter bar initial weight by Ariel Vina-Rodriguez. */ #ifndef NANA_GUI_PLACE_HPP diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp index cf732a7d..648880ec 100644 --- a/include/nana/gui/widgets/panel.hpp +++ b/include/nana/gui/widgets/panel.hpp @@ -9,7 +9,7 @@ * * @file: nana/gui/widgets/panel.hpp * @author: Jinhao - * @contributors: qPCR4vir + * @contributors: Ariel Vina-Rodriguez * * @brief panel is a widget used for placing some widgets. */ diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index ec692d36..9313a588 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -8,6 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/detail/win32/bedrock.cpp + * @contributors: Ariel Vina-Rodriguez */ #include @@ -1101,7 +1102,7 @@ namespace detail case WM_MOUSEHWHEEL: { //The focus window receives the message in Windows system, it should be redirected to the hovered window - ::POINT scr_pos{ pmdec.mouse.x, pmdec.mouse.y}; //Screen position + ::POINT scr_pos{ int(LOWORD(lParam)), int(HIWORD(lParam)) }; //Screen position auto pointer_wd = ::WindowFromPoint(scr_pos); if (pointer_wd == root_window) { diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index c0cf78c8..ab40bda8 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -9,7 +9,7 @@ * * @file: source/gui/widgets/label.cpp * @author: Jinhao - * @contributors: qPCR4vir + * @contributors: Ariel Vina-Rodriguez */ #include @@ -588,7 +588,7 @@ namespace nana std::pair _m_locate(dstream::linecontainer::iterator& i, std::size_t pos) { - std::pair r; + //std::pair r; //deprecated std::size_t n = i->data_ptr->text().length(); while(pos >= n) @@ -853,24 +853,16 @@ namespace nana label& label::text_align(align th, align_v tv) { - internal_scope_guard isg; + internal_scope_guard lock; auto impl = get_drawer_trigger().impl(); - bool to_update = false; - if(impl->text_align != th) + if (th != impl->text_align || tv != impl->text_align_v) { impl->text_align = th; - to_update = true; - } - - if(impl->text_align_v != tv) - { impl->text_align_v = tv; - to_update = true; + API::refresh_window(*this); } - if(to_update) - API::refresh_window(*this); return *this; } diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 5ae31f61..e81a4859 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -8,7 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/listbox.cpp - * @contributors: Hiroshi Seki, qPCR4vir + * @contributors: Hiroshi Seki, Ariel Vina-Rodriguez */ #include diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 913d858d..bde7e746 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -8,7 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/skeletons/text_editor.cpp - * @contributors: qPCR4vir + * @contributors: Ariel Vina-Rodriguez */ #include #include From 53c36b73636dab820a6d584a9957b721b8b4ae65 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 13 Apr 2015 23:41:42 +0800 Subject: [PATCH 43/77] fix mask textbox highlight with mask --- source/gui/widgets/skeletons/text_editor.cpp | 54 ++++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index bde7e746..eceda23e 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -314,7 +314,13 @@ namespace nana{ namespace widgets if (pos.y > static_cast(textbase.lines())) pos.y = static_cast(textbase.lines()); - pos.x = editor_._m_pixels_by_char(textbase.getline(pos.y), pos.x) + editor_.text_area_.area.x; + std::unique_ptr mask_str; + if (editor_.mask_char_) + mask_str.reset(new nana::string(textbase.getline(pos.y).size(), editor_.mask_char_)); + + auto & lnstr = editor_.mask_char_ ? *mask_str : textbase.getline(pos.y); + + pos.x = editor_._m_pixels_by_char(lnstr, pos.x) + editor_.text_area_.area.x; int pos_y = static_cast((pos.y - editor_.points_.offset.y) * editor_.line_height() + editor_._m_text_top_base()); int pos_x = static_cast(pos.x - editor_.points_.offset.x); @@ -327,7 +333,13 @@ namespace nana{ namespace widgets nana::upoint res{ 0, static_cast(_m_textline_from_screen(scrpos.y)) }; //Convert the screen point to text caret point - const string_type& lnstr = editor_.textbase_.getline(res.y); + const string_type& real_str = editor_.textbase_.getline(res.y); + + std::unique_ptr mask_str; + if (editor_.mask_char_) + mask_str.reset(new nana::string(real_str.size(), editor_.mask_char_)); + + auto & lnstr = (editor_.mask_char_ ? *mask_str : real_str); if (lnstr.size() > 0) { scrpos.x += (editor_.points_.offset.x - editor_.text_area_.area.x); @@ -737,17 +749,24 @@ namespace nana{ namespace widgets nana::point scrpos; if (0 != pos.x) { + nana::string str; for (auto & sec : mtr.line_sections) { std::size_t chsize = sec.end - sec.begin; + str.clear(); + if (editor_.mask_char_) + str.append(chsize, editor_.mask_char_); + else + str.append(sec.begin, sec.end); + if (pos.x < chsize) { - scrpos.x = editor_._m_pixels_by_char(nana::string(sec.begin, sec.end), pos.x); + scrpos.x = editor_._m_pixels_by_char(str, pos.x); break; } else if (pos.x == chsize) { - scrpos.x = editor_._m_text_extent_size(nana::string(sec.begin, sec.end).data(), sec.end - sec.begin).width; + scrpos.x = editor_._m_text_extent_size(str.data(), sec.end - sec.begin).width; break; } else @@ -773,13 +792,19 @@ namespace nana{ namespace widgets return{ 0, static_cast(primary) }; //First of all, find the text of secondary. - auto str = mtr.line_sections[secondary]; + auto real_str = mtr.line_sections[secondary]; + + std::unique_ptr mask_str; + if (editor_.mask_char_) + mask_str.reset(new nana::string(real_str.end - real_str.begin, editor_.mask_char_)); + + const ::nana::char_t * str = (editor_.mask_char_ ? mask_str->data() : real_str.begin); std::vector reordered; unicode_bidi bidi; - bidi.linestr(str.begin, str.end - str.begin, reordered); + bidi.linestr(str, real_str.end - real_str.begin, reordered); - nana::upoint res(static_cast(str.begin - mtr.line_sections.front().begin), static_cast(primary)); + nana::upoint res(static_cast(real_str.begin - mtr.line_sections.front().begin), static_cast(primary)); scrpos.x -= editor_.text_area_.area.x; if (scrpos.x < 0) scrpos.x = 0; @@ -793,7 +818,7 @@ namespace nana{ namespace widgets std::unique_ptr pxbuf(new unsigned[len]); res.x += editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), str_px, scrpos.x, _m_is_right_text(ent)); - res.x += static_cast(ent.begin - str.begin); + res.x += static_cast(ent.begin - str); return res; } scrpos.x -= str_px; @@ -2760,18 +2785,17 @@ namespace nana{ namespace widgets } } - void text_editor::_m_draw_string(int top, const ::nana::color& clr, const nana::upoint& str_pos, const nana::string& linestr, bool if_mask) const + void text_editor::_m_draw_string(int top, const ::nana::color& clr, const nana::upoint& str_pos, const nana::string& str, bool if_mask) const { ::nana::point text_pos{ text_area_.area.x - points_.offset.x, top }; const int xend = text_area_.area.x + static_cast(text_area_.area.width); + std::unique_ptr mask_str; if (if_mask && mask_char_) - { - nana::string maskstr; - maskstr.append(linestr.size(), mask_char_); - graph_.string(text_pos, maskstr, clr); - return; - } + mask_str.reset(new nana::string(str.size(), mask_char_)); + + + auto & linestr = (if_mask && mask_char_ ? *mask_str : str); unicode_bidi bidi; std::vector reordered; From f11e5efe80cdd3a0152887e5871ea26e514e5fe6 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 15 Apr 2015 22:36:24 +0800 Subject: [PATCH 44/77] fix the issue of restoring focus(#37) --- include/nana/gui/widgets/menubar.hpp | 7 +++++- source/gui/detail/window_manager.cpp | 11 ++++++++- source/gui/widgets/menubar.cpp | 36 ++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/include/nana/gui/widgets/menubar.hpp b/include/nana/gui/widgets/menubar.hpp index bec4dd5d..9b736149 100644 --- a/include/nana/gui/widgets/menubar.hpp +++ b/include/nana/gui/widgets/menubar.hpp @@ -59,7 +59,7 @@ namespace nana private: void _m_move(bool to_left); bool _m_popup_menu(); - void _m_total_close(); + void _m_total_close(bool try_restore); bool _m_close_menu(); void _m_unload_menu_window(); std::size_t _m_item_by_pos(const ::nana::point&); @@ -90,6 +90,11 @@ namespace nana nana::menu *menu; nana::point mouse_pos; + + //The menu will restore the focus of taken window. But the restoring during + //key_press and key_release resets the focus to the taken window, it causes + //the taken window to receive a key_char which should be received by menubar. + bool delay_restore; }state_; }; }//end namespace menubar diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index f594e6a0..fb0d0491 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -8,7 +8,8 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/detail/window_manager.cpp - * + * @author: Jinhao + * @contributors: Katsuhisa Yuasa */ #include @@ -875,6 +876,14 @@ namespace detail if (!root_has_been_focused) native_interface::set_focus(root_wd->root); + //A fix by Katsuhisa Yuasa + //The menubar token window will be redirected to the prev focus window when the new + //focus window is a menubar. + //The focus window will be restore to the prev focus which losts the focus becuase of + //memberbar. + if (wd == wd->root_widget->other.attribute.root->menubar) + wd = prev_focus; + brock.set_menubar_taken(wd); } return prev_focus; diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index e6d34cb5..8a19b321 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -232,10 +232,10 @@ namespace nana _m_popup_menu(); } else - _m_total_close(); + _m_total_close(true); } else if(npos == state_.active) - _m_total_close(); + _m_total_close(true); else _m_popup_menu(); @@ -255,7 +255,7 @@ namespace nana else { state_.behavior = state_.behavior_none; - _m_total_close(); + _m_total_close(true); _m_draw(); API::lazy_refresh(); } @@ -305,15 +305,17 @@ namespace nana } break; case keyboard::enter: + state_.delay_restore = true; state_.menu->pick(); break; default: if(2 != state_.menu->send_shortkey(arg.key)) { - if(state_.active != npos) + if (state_.active != npos) { - _m_total_close(); - if(arg.key == 18) //ALT + state_.delay_restore = true; + _m_total_close(false); + if (arg.key == 18) //ALT state_.behavior = state_.behavior_focus; } } @@ -367,6 +369,12 @@ namespace nana _m_draw(); API::lazy_refresh(); } + + if (state_.delay_restore) + { + API::restore_menubar_taken_window(); + state_.delay_restore = false; + } } void trigger::shortkey(graph_reference graph, const arg_keyboard& arg) @@ -440,13 +448,14 @@ namespace nana return false; } - void trigger::_m_total_close() + void trigger::_m_total_close(bool try_restore) { _m_close_menu(); state_.menu_active = false; state_.behavior = state_.behavior_none; - API::restore_menubar_taken_window(); + if (try_restore) + API::restore_menubar_taken_window(); auto pos = API::cursor_position(); API::calc_window_point(widget_->handle(), pos); @@ -471,7 +480,8 @@ namespace nana state_.menu = nullptr; if(state_.passive_close) { - _m_total_close(); + _m_total_close(false); + _m_draw(); API::update_window(widget_->handle()); } @@ -569,7 +579,13 @@ namespace nana //struct state_type trigger::state_type::state_type() - :active(npos), behavior(behavior_none), menu_active(false), passive_close(true), nullify_mouse(false), menu(nullptr) + : active(npos), + behavior(behavior_none), + menu_active(false), + passive_close(true), + nullify_mouse(false), + menu(nullptr), + delay_restore(false) {} //end struct state_type //end class trigger From 3ffbf62958a17464aa1e67702e728d66407b16ff Mon Sep 17 00:00:00 2001 From: beru Date: Sat, 18 Apr 2015 13:52:53 +0900 Subject: [PATCH 45/77] fixes #14 --- source/gui/widgets/menubar.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 8a19b321..2303a493 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -309,8 +309,14 @@ namespace nana state_.menu->pick(); break; default: - if(2 != state_.menu->send_shortkey(arg.key)) + //(as of now...) + //send_shortkey has 3 states, 0 = UNKNOWN KEY, 1 = ITEM, 2 = GOTO SUBMENU + int sk_state = state_.menu->send_shortkey(arg.key); + switch(sk_state) { + case 0: //UNKNOWN KEY + break; + case 1: //ITEM if (state_.active != npos) { state_.delay_restore = true; @@ -318,9 +324,12 @@ namespace nana if (arg.key == 18) //ALT state_.behavior = state_.behavior_focus; } - } - else + break; + case 2: //GOTO SUBMENU state_.menu->goto_submen(); + break; + } + break; } } else @@ -334,6 +343,13 @@ namespace nana case keyboard::os_arrow_left: _m_move(true); break; + case keyboard::os_arrow_up: + case keyboard::os_arrow_down: + case keyboard::enter: + state_.menu_active = true; + if(_m_popup_menu()) + state_.menu->goto_next(true); + break; case keyboard::escape: if(state_.behavior == state_.behavior_focus) { @@ -341,6 +357,17 @@ namespace nana state_.behavior = state_.behavior_none; API::restore_menubar_taken_window(); } + break; + default: + std::size_t index = items_->find(arg.key); + if(index != npos) + { + state_.active = index; + state_.menu_active = true; + if(_m_popup_menu()) + state_.menu->goto_next(true); + } + break; } } From c446c860de2704ebb13e1021b02be0a0d394e061 Mon Sep 17 00:00:00 2001 From: beru Date: Sun, 19 Apr 2015 23:49:27 +0900 Subject: [PATCH 46/77] fixes #4 --- source/gui/detail/win32/bedrock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 9313a588..cff08b94 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1369,7 +1369,7 @@ namespace detail { if((wParam == 9) && (false == (msgwnd->flags.tab & tab_type::eating))) //Tab { - auto the_next = brock.wd_manager.tabstop(msgwnd, true); + auto the_next = brock.wd_manager.tabstop(msgwnd, (::GetKeyState(VK_SHIFT) >= 0)); if(the_next) { brock.wd_manager.set_focus(the_next, false); From 5a34e430f02c2092a6a77073c49b195168a709e0 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 21 Apr 2015 14:24:32 +0200 Subject: [PATCH 47/77] re-fix: Scroll don't get trigged in secondary monitor: no scroll in texbox, trebox, listbox, etc. it was lost in commit: ed462870e0a60e1e41b2de08885387633cb66fcf --- source/gui/detail/win32/bedrock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 9313a588..94e90e23 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1102,7 +1102,7 @@ namespace detail case WM_MOUSEHWHEEL: { //The focus window receives the message in Windows system, it should be redirected to the hovered window - ::POINT scr_pos{ int(LOWORD(lParam)), int(HIWORD(lParam)) }; //Screen position + ::POINT scr_pos{ pmdec.mouse.x, pmdec.mouse.y}; //Screen position auto pointer_wd = ::WindowFromPoint(scr_pos); if (pointer_wd == root_window) { From 3c4f8ae6d98be2e99a491a05bef31e6339481e4b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 21 Apr 2015 22:33:18 +0800 Subject: [PATCH 48/77] fix menubar behavior issue no key_press and key_release after destroying caret under X11 missing some key_press events menu text color issue --- include/nana/gui/detail/basic_window.hpp | 3 +- include/nana/gui/detail/bedrock.hpp | 7 +- include/nana/gui/programming_interface.hpp | 3 +- include/nana/gui/widgets/menubar.hpp | 20 +-- source/detail/linux_X11/platform_spec.cpp | 7 +- source/gui/detail/basic_window.cpp | 1 + source/gui/detail/bedrock_selector.cpp | 2 +- source/gui/detail/linux_X11/bedrock.cpp | 148 +++++++++++----- source/gui/detail/native_window_interface.cpp | 19 ++- source/gui/detail/win32/bedrock.cpp | 108 ++++++++---- source/gui/detail/window_manager.cpp | 3 +- source/gui/programming_interface.cpp | 16 +- source/gui/widgets/float_listbox.cpp | 62 +++---- source/gui/widgets/label.cpp | 2 - source/gui/widgets/menu.cpp | 4 +- source/gui/widgets/menubar.cpp | 159 ++++++++---------- 16 files changed, 315 insertions(+), 249 deletions(-) diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index 2834c870..8016836c 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -166,7 +166,8 @@ namespace detail bool fullscreen :1; //When the window is maximizing whether it fit for fullscreen. bool borderless :1; bool make_bground_declared : 1; //explicitly make bground for bground effects - unsigned Reserved :21; + bool ignore_menubar_focus : 1; //A flag indicates whether the menubar sets the focus. + unsigned Reserved :20; unsigned char tab; //indicate a window that can receive the keyboard TAB mouse_action action; }flags; diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 71a52149..1ae2a41d 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -54,13 +54,14 @@ namespace detail native_window_type root(core_window_t*); void set_menubar_taken(core_window_t*); - core_window_t* get_menubar_taken(); + + //Delay Restores focus when a menu which attached to menubar is closed + void delay_restore(int); bool close_menu_if_focus_other_window(native_window_type focus); void set_menu(native_window_type menu_window, bool is_keyboard_condition); native_window_type get_menu(native_window_type owner, bool is_keyboard_condition); native_window_type get_menu(); - void remove_menu(); - void empty_menu(); + void erase_menu(bool try_destroy); void get_key_state(arg_keyboard&); bool set_keyboard_shortkey(bool yes); diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 7caf038b..09bb1c84 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -77,6 +77,8 @@ namespace API window create_frame(window, const rectangle&, widget* attached); paint::graphics* window_graphics(window); + + void delay_restore(bool); }//end namespace dev @@ -290,7 +292,6 @@ namespace API void register_menu_window(window, bool has_keyboard); bool attach_menubar(window menubar); void detach_menubar(window menubar); - void restore_menubar_taken_window(); bool is_window_zoomed(window, bool ask_for_max); ///input_context_event_mask) == addr->input_context_event_mask) { XSetWindowAttributes new_attr; - new_attr.event_mask = (attr.your_event_mask & ~addr->input_context_event_mask); + + //Don't remove the KeyPress and KeyRelease mask(0x3), otherwise the window will not receive + //Keyboard events after destroying caret + new_attr.event_mask = (attr.your_event_mask & ~(addr->input_context_event_mask & (~0x3))); ::XChangeWindowAttributes(display_, reinterpret_cast(wd), CWEventMask, &new_attr); } } diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index f1bd3c95..4cb500bf 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -347,6 +347,7 @@ namespace nana flags.destroying = false; flags.borderless = false; flags.make_bground_declared = false; + flags.ignore_menubar_focus = false; visible = false; diff --git a/source/gui/detail/bedrock_selector.cpp b/source/gui/detail/bedrock_selector.cpp index 62ca3673..3d10fd7b 100644 --- a/source/gui/detail/bedrock_selector.cpp +++ b/source/gui/detail/bedrock_selector.cpp @@ -1,7 +1,7 @@ /* * Bedrock Selector * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Nana Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 886f1493..94f35223 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -102,27 +102,18 @@ namespace detail { struct thread_context_cache { - unsigned tid; - thread_context *object; + unsigned tid{ 0 }; + thread_context *object{ nullptr }; }tcontext; - - cache_type() - { - tcontext.tid = 0; - tcontext.object = nullptr; - } }cache; struct menu_tag { - menu_tag() - :taken_window(nullptr), window(nullptr), owner(nullptr), has_keyboard(false) - {} - - core_window_t* taken_window; - native_window_type window; - native_window_type owner; - bool has_keyboard; + core_window_t* taken_window{ nullptr }; + bool delay_restore{ false }; + native_window_type window{ nullptr }; + native_window_type owner{ nullptr }; + bool has_keyboard{ false }; }menu; struct keyboard_tracking_state_tag @@ -282,14 +273,39 @@ namespace detail void bedrock::set_menubar_taken(core_window_t* wd) { + auto pre = impl_->menu.taken_window; impl_->menu.taken_window = wd; + + //assigning of a nullptr taken window is to restore the focus of pre taken + if ((!wd) && pre) + { + internal_scope_guard lock; + wd_manager.set_focus(pre, false); + wd_manager.update(pre, true, false); + } } - bedrock::core_window_t* bedrock::get_menubar_taken() + //0:Enable delay, 1:Cancel, 2:Restores, 3: Restores when menu is destroying + void bedrock::delay_restore(int state) { - core_window_t* wd = impl_->menu.taken_window; - impl_->menu.taken_window = nullptr; - return wd; + switch (state) + { + case 0: //Enable + break; + case 1: //Cancel + break; + case 2: //Restore if key released + //restores the focus when menu is closed by pressing keyboard + if (!impl_->menu.window) + set_menubar_taken(nullptr); + break; + case 3: //Restores if destroying + //when the menu is destroying, restores the focus if delay restore is not declared + if (!impl_->menu.delay_restore) + set_menubar_taken(nullptr); + } + + impl_->menu.delay_restore = (0 == state); } bool bedrock::close_menu_if_focus_other_window(native_window_type wd) @@ -304,7 +320,7 @@ namespace detail else return false; } - remove_menu(); + erase_menu(true); return true; } return false; @@ -314,7 +330,7 @@ namespace detail { if(menu_window && impl_->menu.window != menu_window) { - remove_menu(); + erase_menu(true); impl_->menu.window = menu_window; impl_->menu.owner = native_interface::get_owner_window(menu_window); impl_->menu.has_keyboard = has_keyboard; @@ -338,21 +354,13 @@ namespace detail return impl_->menu.window; } - void bedrock::remove_menu() + void bedrock::erase_menu(bool try_destroy) { - if(impl_->menu.window) + if (impl_->menu.window) { - native_window_type delwin = impl_->menu.window; - impl_->menu.window = impl_->menu.owner = nullptr; - impl_->menu.has_keyboard = false; - native_interface::close_window(delwin); - } - } + if (try_destroy) + native_interface::close_window(impl_->menu.window); - void bedrock::empty_menu() - { - if(impl_->menu.window) - { impl_->menu.window = impl_->menu.owner = nullptr; impl_->menu.has_keyboard = false; } @@ -372,6 +380,11 @@ namespace detail return ret; } + bool bedrock::whether_keyboard_shortkey() const + { + return impl_->keyboard_tracking_state.has_shortkey_occured; + } + element_store& bedrock::get_element_store() const { return impl_->estore; @@ -700,8 +713,8 @@ namespace detail msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); if(nullptr == msgwnd) break; - if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) - brock.remove_menu(); + if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) + brock.erase_menu(true); else brock.close_menu_if_focus_other_window(msgwnd->root); @@ -719,7 +732,7 @@ namespace detail if(kill_focus != new_focus) brock.wd_manager.do_lazy_refresh(kill_focus, false); } - auto retain = msgwnd->together.event_ptr; + auto retain = msgwnd->together.events_ptr; msgwnd->root_widget->other.attribute.root->context.focus_changed = false; context.event_window = msgwnd; @@ -773,7 +786,7 @@ namespace detail msgwnd->flags.action = mouse_action::normal; if(msgwnd->flags.enabled) { - auto retain = msgwnd->together.event_ptr; + auto retain = msgwnd->together.events_ptr; arg_mouse arg; assign_arg(arg, msgwnd, message, xevent); @@ -829,8 +842,11 @@ namespace detail if(brock.wd_manager.available(msgwnd)) { //The msgwnd may be destroyed if the window is destroyed by calling native interface of close_window(). - if(msgwnd->root == brock.get_menu()) - brock.empty_menu(); + if (msgwnd->root == brock.get_menu()) + { + brock.erase_menu(false); + brock.delay_restore(3); //Restores if delay_restore not decleared + } spec.remove(native_window); brock.wd_manager.destroy(msgwnd); @@ -929,6 +945,9 @@ namespace detail nana::detail::platform_spec::instance().write_keystate(xevent.xkey); if(msgwnd->flags.enabled) { + if (brock.get_menu()) + brock.delay_restore(0); //Enable delay restore + if(msgwnd->root != brock.get_menu()) msgwnd = brock.focus(); @@ -1011,12 +1030,31 @@ namespace detail else if(keyboard::alt == keychar) { context.is_alt_pressed = true; + if (brock.whether_keyboard_shortkey() == false) + { + msgwnd = msgwnd->root_widget->other.attribute.root->menubar; + if (msgwnd) + { + bool focused = (brock.focus() == msgwnd); + arg_keyboard arg; + arg.evt_code = event_code::key_press; + arg.window_handle = reinterpret_cast(msgwnd); + arg.ignore = false; + arg.key = static_cast(keychar); + brock.get_key_state(arg); + brock.emit(event_code::key_press, msgwnd, arg, true, &context); + + msgwnd->root_widget->flags.ignore_menubar_focus = (focused && (brock.focus() != msgwnd)); + } + else + brock.erase_menu(true); + } } - else if(keychar) + else { arg_keyboard arg; arg.ignore = false; - arg.key = keychar; + arg.key = keychar ? keychar : xevent.xkey.keycode; arg.evt_code = event_code::key_press; brock.get_key_state(arg); arg.window_handle = reinterpret_cast(msgwnd); @@ -1093,11 +1131,35 @@ namespace detail brock.get_key_state(arg); brock.emit(event_code::key_release, msgwnd, arg, true, &context); } + brock.delay_restore(2); //Restores while key release } else { context.is_alt_pressed = false; - brock.set_keyboard_shortkey(false); + if (brock.set_keyboard_shortkey(false) == false) + { + msgwnd = msgwnd->root_widget->other.attribute.root->menubar; + if (msgwnd) + { + bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus); + if (set_focus) + brock.wd_manager.set_focus(msgwnd, false); + + arg_keyboard arg; + arg.evt_code = event_code::key_release; + arg.window_handle = reinterpret_cast(msgwnd); + arg.ignore = false; + arg.key = static_cast(context.platform.keychar); + brock.get_key_state(arg); + brock.emit(event_code::key_release, msgwnd, arg, true, &context); + + if (!set_focus) + { + brock.set_menubar_taken(nullptr); + msgwnd->root_widget->flags.ignore_menubar_focus = false; + } + } + } } break; default: diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 0ad45b61..a01d80b8 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -580,27 +580,30 @@ namespace nana{ //event, when the client receives the event, the specified window has been already //destroyed. This is a feature which is different from Windows. So the following //works should be handled before calling XDestroyWindow. - auto & bedrock = bedrock::instance(); - if(wd == bedrock.get_menu()) - bedrock.empty_menu(); + auto & brock = bedrock::instance(); + if(wd == brock.get_menu()) + { + brock.erase_menu(false); + brock.delay_restore(3); //Restores if delay_restore is not decleard + } Display* disp = restrict::spec.open_display(); restrict::spec.remove(wd); - auto iwd = bedrock.wd_manager.root(wd); + auto iwd = brock.wd_manager.root(wd); if(iwd) { { //Before calling window_manager::destroy, make sure the window is invisible. //It is a behavior like Windows. - nana::detail::platform_scope_guard psg; + nana::detail::platform_scope_guard lock; restrict::spec.set_error_handler(); ::XUnmapWindow(disp, reinterpret_cast(wd)); ::XFlush(disp); restrict::spec.rev_error_handler(); } - bedrock.wd_manager.destroy(iwd); - bedrock.rt_manager.remove_if_exists(iwd); - bedrock.wd_manager.destroy_handle(iwd); + brock.wd_manager.destroy(iwd); + brock.rt_manager.remove_if_exists(iwd); + brock.wd_manager.destroy_handle(iwd); } nana::detail::platform_scope_guard psg; diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 9313a588..78d60e4e 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -185,17 +185,18 @@ namespace detail { struct thread_context_cache { - unsigned tid = 0; - thread_context *object = nullptr; + unsigned tid{ 0 }; + thread_context *object{ nullptr }; }tcontext; }cache; struct menu_tag { - core_window_t* taken_window = nullptr; - native_window_type window = nullptr; - native_window_type owner = nullptr; - bool has_keyboard = false; + core_window_t* taken_window{ nullptr }; + bool delay_restore{ false }; + native_window_type window{ nullptr }; + native_window_type owner{ nullptr }; + bool has_keyboard{false}; }menu; struct keyboard_tracking_state_tag @@ -921,8 +922,8 @@ namespace detail if(nullptr == msgwnd) break; //if event on the menubar, just remove the menu if it is not associating with the menubar - if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) - brock.remove_menu(); + if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) + brock.erase_menu(true); else brock.close_menu_if_focus_other_window(msgwnd->root); @@ -1322,13 +1323,12 @@ namespace detail def_window_proc = true; break; case WM_SYSKEYDOWN: - if(brock.whether_keyboard_shortkey() == false) + if (brock.whether_keyboard_shortkey() == false) { msgwnd = msgwnd->root_widget->other.attribute.root->menubar; - if(msgwnd) + if (msgwnd) { - brock.wd_manager.set_focus(msgwnd, false); - + bool focused = (brock.focus() == msgwnd); arg_keyboard arg; arg.evt_code = event_code::key_press; arg.window_handle = reinterpret_cast(msgwnd); @@ -1336,9 +1336,11 @@ namespace detail arg.key = static_cast(wParam); brock.get_key_state(arg); brock.emit(event_code::key_press, msgwnd, arg, true, &context); + + msgwnd->root_widget->flags.ignore_menubar_focus = (focused && (brock.focus() != msgwnd)); } - else if(brock.get_menu()) - brock.remove_menu(); + else + brock.erase_menu(true); } def_window_proc = true; break; @@ -1348,6 +1350,10 @@ namespace detail msgwnd = msgwnd->root_widget->other.attribute.root->menubar; if(msgwnd) { + bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus); + if (set_focus) + brock.wd_manager.set_focus(msgwnd, false); + arg_keyboard arg; arg.evt_code = event_code::key_release; arg.window_handle = reinterpret_cast(msgwnd); @@ -1355,6 +1361,12 @@ namespace detail arg.key = static_cast(wParam); brock.get_key_state(arg); brock.emit(event_code::key_release, msgwnd, arg, true, &context); + + if (!set_focus) + { + brock.set_menubar_taken(nullptr); + msgwnd->root_widget->flags.ignore_menubar_focus = false; + } } } def_window_proc = true; @@ -1362,6 +1374,9 @@ namespace detail case WM_KEYDOWN: if(msgwnd->flags.enabled) { + if (brock.get_menu()) + brock.delay_restore(0); //Enable delay restore + if(msgwnd->root != brock.get_menu()) msgwnd = brock.focus(); @@ -1431,6 +1446,8 @@ namespace detail } else brock.set_keyboard_shortkey(false); + + brock.delay_restore(2); //Restores while key release break; case WM_CLOSE: { @@ -1448,8 +1465,12 @@ namespace detail break; } case WM_DESTROY: - if(msgwnd->root == brock.get_menu()) - brock.empty_menu(); + if (msgwnd->root == brock.get_menu()) + { + brock.erase_menu(false); + brock.delay_restore(3); //Restores if delay_restore not decleared + } + brock.wd_manager.destroy(msgwnd); nana::detail::platform_spec::instance().release_window_icon(msgwnd->root); @@ -1512,14 +1533,39 @@ namespace detail void bedrock::set_menubar_taken(core_window_t* wd) { + auto pre = impl_->menu.taken_window; impl_->menu.taken_window = wd; + + //assigning of a nullptr taken window is to restore the focus of pre taken + if ((!wd) && pre) + { + internal_scope_guard lock; + wd_manager.set_focus(pre, false); + wd_manager.update(pre, true, false); + } } - bedrock::core_window_t* bedrock::get_menubar_taken() + //0:Enable delay, 1:Cancel, 2:Restores, 3: Restores when menu is destroying + void bedrock::delay_restore(int state) { - core_window_t* wd = impl_->menu.taken_window; - impl_->menu.taken_window = nullptr; - return wd; + switch (state) + { + case 0: //Enable + break; + case 1: //Cancel + break; + case 2: //Restore if key released + //restores the focus when menu is closed by pressing keyboard + if (!impl_->menu.window) + set_menubar_taken(nullptr); + break; + case 3: //Restores if destroying + //when the menu is destroying, restores the focus if delay restore is not declared + if (!impl_->menu.delay_restore) + set_menubar_taken(nullptr); + } + + impl_->menu.delay_restore = (0 == state); } bool bedrock::close_menu_if_focus_other_window(native_window_type wd) @@ -1534,7 +1580,7 @@ namespace detail else return false; } - remove_menu(); + erase_menu(true); return true; } return false; @@ -1544,7 +1590,7 @@ namespace detail { if(menu_wd && impl_->menu.window != menu_wd) { - remove_menu(); + erase_menu(true); impl_->menu.window = menu_wd; impl_->menu.owner = native_interface::get_owner_window(menu_wd); @@ -1568,21 +1614,13 @@ namespace detail return impl_->menu.window; } - void bedrock::remove_menu() + void bedrock::erase_menu(bool try_destroy) { - if(impl_->menu.window) - { - auto delwin = impl_->menu.window; - impl_->menu.window = impl_->menu.owner = nullptr; - impl_->menu.has_keyboard = false; - native_interface::close_window(delwin); - } - } - - void bedrock::empty_menu() - { - if(impl_->menu.window) + if (impl_->menu.window) { + if (try_destroy) + native_interface::close_window(impl_->menu.window); + impl_->menu.window = impl_->menu.owner = nullptr; impl_->menu.has_keyboard = false; } diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index fb0d0491..93186a57 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -884,7 +884,8 @@ namespace detail if (wd == wd->root_widget->other.attribute.root->menubar) wd = prev_focus; - brock.set_menubar_taken(wd); + if (wd != wd->root_widget->other.attribute.root->menubar) + brock.set_menubar_taken(wd); } return prev_focus; } diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 6af6945d..c2db60b8 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -240,6 +240,11 @@ namespace API return &reinterpret_cast(wd)->drawer.graphics; return nullptr; } + + void delay_restore(bool enable) + { + restrict::bedrock.delay_restore(enable ? 0 : 1); + } }//end namespace dev //exit @@ -1203,17 +1208,6 @@ namespace API } } - void restore_menubar_taken_window() - { - auto wd = restrict::bedrock.get_menubar_taken(); - if(wd) - { - internal_scope_guard lock; - restrict::window_manager.set_focus(wd, false); - restrict::window_manager.update(wd, true, false); - } - } - bool is_window_zoomed(window wd, bool ask_for_max) { auto const iwd = reinterpret_cast(wd); diff --git a/source/gui/widgets/float_listbox.cpp b/source/gui/widgets/float_listbox.cpp index 3f569aee..8af19e43 100644 --- a/source/gui/widgets/float_listbox.cpp +++ b/source/gui/widgets/float_listbox.cpp @@ -37,21 +37,25 @@ namespace nana ::nana::color clr{ 0xaf, 0xc7, 0xe3 }; graph.rectangle(r, false, clr); + auto right = r.right() - 1; + auto bottom = r.bottom() - 1; graph.set_color(colors::white); graph.set_pixel(r.x, r.y); - graph.set_pixel(r.x + r.width - 1, r.y); - graph.set_pixel(r.x, r.y + r.height - 1); - graph.set_pixel(r.x + r.width - 1, r.y + r.height - 1); + graph.set_pixel(right, r.y); + graph.set_pixel(r.x, bottom); + graph.set_pixel(right, bottom); + --right; + --bottom; graph.set_color(clr); graph.set_pixel(r.x + 1, r.y + 1); - graph.set_pixel(r.x + r.width - 2, r.y + 1); - graph.set_pixel(r.x + 1, r.y + r.height - 2); - graph.set_pixel(r.x + r.width - 2, r.y + r.height - 2); + graph.set_pixel(right, r.y + 1); + graph.set_pixel(r.x + 1, bottom); + graph.set_pixel(right, bottom); nana::rectangle po_r(r); - graph.rectangle(po_r.pare_off(1), false, { 0xEB, 0xF4, 0xFB }); - graph.gradual_rectangle(po_r.pare_off(1), { 0xDD, 0xEC, 0xFD }, { 0xC2, 0xDC, 0xFD }, true); + graph.rectangle(po_r.pare_off(1), false, static_cast(0xEBF4FB)); + graph.gradual_rectangle(po_r.pare_off(1), static_cast(0xDDECFD), static_cast(0xC2DCFD), true); } else graph.rectangle(r, true, colors::white); @@ -113,13 +117,8 @@ namespace nana class drawer_impl { public: - typedef widget& widget_reference; - typedef nana::paint::graphics& graph_reference; - - drawer_impl() - : widget_(nullptr), graph_(nullptr), image_pixels_(16), - ignore_first_mouseup_(true), module_(nullptr) - {} + using widget_reference = widget&; + using graph_reference = paint::graphics&; void clear_state() { @@ -151,25 +150,19 @@ namespace nana { if(scrollbar_.empty()) return; - bool update = false; + const auto before_change = state_.offset_y; if(upwards) { - if(state_.offset_y) - { + if (before_change) --(state_.offset_y); - update = true; - } } else { - if((state_.offset_y + module_->max_items) < module_->items.size()) - { + if ((before_change + module_->max_items) < module_->items.size()) ++(state_.offset_y); - update = true; - } } - if(update) + if(before_change != state_.offset_y) { draw(); scrollbar_.value(state_.offset_y); @@ -323,8 +316,7 @@ namespace nana state_.renderer->image(_m_image_enabled(), image_pixels_); for(std::size_t i = state_.offset_y; i < items; ++i) { - item_renderer::state_t state = item_renderer::StateNone; - if(i == state_.index) state = item_renderer::StateHighlighted; + auto state = (i != state_.index ? item_renderer::StateNone : item_renderer::StateHighlighted); state_.renderer->render(*widget_, *graph_, item_r, module_->items[i].get(), state); item_r.y += item_pixels; @@ -384,20 +376,20 @@ namespace nana scrollbar_.close(); } private: - widget * widget_; - nana::paint::graphics * graph_; - unsigned image_pixels_; //Define the width pixels of the image area + widget * widget_{nullptr}; + nana::paint::graphics * graph_{nullptr}; + unsigned image_pixels_{16}; //Define the width pixels of the image area - bool ignore_first_mouseup_; + bool ignore_first_mouseup_{true}; struct state_type { - std::size_t offset_y; - std::size_t index; //The index of the selected item. + std::size_t offset_y{0}; + std::size_t index{npos}; //The index of the selected item. item_renderer * const orig_renderer; item_renderer * renderer; - state_type(): offset_y(0), index(npos), orig_renderer(new def_item_renderer), renderer(orig_renderer){} + state_type(): orig_renderer(new def_item_renderer), renderer(orig_renderer){} ~state_type() { delete orig_renderer; @@ -405,7 +397,7 @@ namespace nana }state_; nana::scroll scrollbar_; - const module_def* module_; + const module_def* module_{nullptr}; }; //class drawer_impl; diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index ab40bda8..66e76027 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -588,8 +588,6 @@ namespace nana std::pair _m_locate(dstream::linecontainer::iterator& i, std::size_t pos) { - //std::pair r; //deprecated - std::size_t n = i->data_ptr->text().length(); while(pos >= n) { diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index d8445c0d..c8c8fa03 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -1,7 +1,7 @@ /* * A Menu implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2009-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -151,7 +151,7 @@ namespace nana void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at) { - graph.set_color(at.enabled ? colors::black : colors::gray_border); + graph.set_text_color(at.enabled ? colors::black : colors::gray_border); nana::paint::text_renderer tr(graph); tr.render(pos, text.c_str(), text.length(), text_pixels, true); } diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 8a19b321..63401c0f 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -58,16 +58,6 @@ namespace nana cont_.push_back(new item_type(text, shortkey)); } - nana::menu* get_menu(std::size_t index) const - { - return (index < cont_.size() ? &(cont_[index]->menu_obj) : nullptr); - } - - const item_type& at(std::size_t index) const - { - return *cont_.at(index); - } - std::size_t find(unsigned long shortkey) const { if(shortkey) @@ -98,19 +88,19 @@ namespace nana :handle_(wd), graph_(graph) {} - void item_renderer::background(const nana::point& pos, const nana::size& size, state_t state) + void item_renderer::background(const nana::point& pos, const nana::size& size, state item_state) { auto bground = API::fgcolor(handle_); ::nana::color border, body, corner; - switch(state) + switch (item_state) { - case item_renderer::state_highlight: + case state::highlighted: border = colors::highlight; body.from_rgb(0xC0, 0xDD, 0xFC); corner = body.blend(bground, 0.5); break; - case item_renderer::state_selected: + case state::selected: border = colors::dark_border; body = colors::white; corner = body.blend(bground, 0.5); @@ -132,9 +122,9 @@ namespace nana graph_.rectangle(r.pare_off(1), true, body); } - void item_renderer::caption(int x, int y, const nana::string& text) + void item_renderer::caption(const point& pos, const nana::string& text) { - graph_.string({ x, y }, text, colors::black); + graph_.string(pos, text, colors::black); } //end class item_renderer @@ -150,22 +140,26 @@ namespace nana nana::menu* trigger::push_back(const ::nana::string& text) { - ::nana::string::value_type shkey; + ::nana::char_t shkey; API::transform_shortkey_text(text, shkey, nullptr); if(shkey) API::register_shortkey(widget_->handle(), shkey); - auto i = items_->cont().size(); + auto pos = items_->cont().size(); items_->append(text, shkey); _m_draw(); API::update_window(*widget_); - return items_->get_menu(i); + + return at(pos); } - nana::menu* trigger::at(std::size_t index) const + nana::menu* trigger::at(std::size_t pos) const { - return items_->get_menu(index); + if (pos < items_->cont().size()) + return &(items_->cont()[pos]->menu_obj); + + return nullptr; } std::size_t trigger::size() const @@ -222,22 +216,17 @@ namespace nana void trigger::mouse_down(graph_reference graph, const arg_mouse& arg) { state_.nullify_mouse = false; - state_.active = _m_item_by_pos(arg.pos); - if(state_.menu_active == false) + + if (npos != state_.active) { - if(state_.active != npos) - { + if (!state_.menu_active) state_.menu_active = true; - _m_popup_menu(); - } - else - _m_total_close(true); - } - else if(npos == state_.active) - _m_total_close(true); - else + _m_popup_menu(); + } + else + _m_total_close(); _m_draw(); API::lazy_refresh(); @@ -255,11 +244,10 @@ namespace nana else { state_.behavior = state_.behavior_none; - _m_total_close(true); + _m_total_close(); _m_draw(); API::lazy_refresh(); } - } void trigger::focus(graph_reference, const arg_focus& arg) @@ -284,10 +272,10 @@ namespace nana switch(arg.key) { case keyboard::os_arrow_down: - state_.menu->goto_next(true); break; case keyboard::backspace: case keyboard::os_arrow_up: - state_.menu->goto_next(false); break; + state_.menu->goto_next(keyboard::os_arrow_down == arg.key); + break; case keyboard::os_arrow_right: if(state_.menu->goto_submen() == false) _m_move(false); @@ -305,19 +293,14 @@ namespace nana } break; case keyboard::enter: - state_.delay_restore = true; state_.menu->pick(); break; default: - if(2 != state_.menu->send_shortkey(arg.key)) + if (2 != state_.menu->send_shortkey(arg.key)) { - if (state_.active != npos) - { - state_.delay_restore = true; - _m_total_close(false); - if (arg.key == 18) //ALT - state_.behavior = state_.behavior_focus; - } + _m_total_close(); + if (arg.key == 18) //ALT + state_.behavior = state_.behavior_focus; } else state_.menu->goto_submen(); @@ -328,18 +311,15 @@ namespace nana switch(arg.key) { case keyboard::os_arrow_right: - _m_move(false); - break; case keyboard::backspace: case keyboard::os_arrow_left: - _m_move(true); + _m_move(keyboard::os_arrow_right != arg.key); break; case keyboard::escape: if(state_.behavior == state_.behavior_focus) { state_.active= npos; state_.behavior = state_.behavior_none; - API::restore_menubar_taken_window(); } } } @@ -369,12 +349,6 @@ namespace nana _m_draw(); API::lazy_refresh(); } - - if (state_.delay_restore) - { - API::restore_menubar_taken_window(); - state_.delay_restore = false; - } } void trigger::shortkey(graph_reference graph, const arg_keyboard& arg) @@ -430,33 +404,44 @@ namespace nana bool trigger::_m_popup_menu() { - if(state_.menu_active && (state_.menu != items_->get_menu(state_.active))) - { - std::size_t index = state_.active; - _m_close_menu(); - state_.active = index; + auto& items = items_->cont(); - state_.menu = items_->get_menu(state_.active); - if(state_.menu) + auto pos = state_.active; + if (pos >= items.size()) + return false; + + if(state_.menu_active && (state_.menu != &(items[pos]->menu_obj))) + { + API::dev::delay_restore(true); + _m_close_menu(); + API::dev::delay_restore(false); + state_.active = pos; + + auto & m = items[pos]; + state_.menu = &(m->menu_obj); + state_.menu->destroy_answer([this] { - const item_type &m = items_->at(state_.active); - state_.menu->destroy_answer(std::bind(&trigger::_m_unload_menu_window, this)); - menu_accessor::popup(*state_.menu, widget_->handle(), m.pos.x, m.pos.y + m.size.height); - return true; - } + state_.menu = nullptr; + if (state_.passive_close) + { + _m_total_close(); + + _m_draw(); + API::update_window(widget_->handle()); + } + }); + menu_accessor::popup(*state_.menu, *widget_, m->pos.x, m->pos.y + static_cast(m->size.height)); + return true; } return false; } - void trigger::_m_total_close(bool try_restore) + void trigger::_m_total_close() { _m_close_menu(); state_.menu_active = false; state_.behavior = state_.behavior_none; - if (try_restore) - API::restore_menubar_taken_window(); - auto pos = API::cursor_position(); API::calc_window_point(widget_->handle(), pos); state_.active = _m_item_by_pos(pos); @@ -475,18 +460,6 @@ namespace nana return false; } - void trigger::_m_unload_menu_window() - { - state_.menu = nullptr; - if(state_.passive_close) - { - _m_total_close(false); - - _m_draw(); - API::update_window(widget_->handle()); - } - } - std::size_t trigger::_m_item_by_pos(const ::nana::point& pos) { if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25)) @@ -534,9 +507,9 @@ namespace nana for(auto i : items_->cont()) { //Transform the text if it contains the hotkey character - nana::string::value_type hotkey; - nana::string::size_type hotkey_pos; - nana::string text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos); + ::nana::char_t hotkey; + ::nana::string::size_type hotkey_pos; + auto text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos); nana::size text_s = graph_->text_extent_size(text); @@ -545,10 +518,11 @@ namespace nana i->pos = item_pos; i->size = item_s; - item_renderer::state_t state = (index != state_.active ? ird.state_normal : (state_.menu_active ? ird.state_selected : ird.state_highlight)); - ird.background(item_pos, item_s, state); + using state = item_renderer::state; + state item_state = (index != state_.active ? state::normal : (state_.menu_active ? state::selected : state::highlighted)); + ird.background(item_pos, item_s, item_state); - if(state == ird.state_selected) + if (state::selected == item_state) { int x = item_pos.x + item_s.width; int y1 = item_pos.y + 2, y2 = item_pos.y + item_s.height - 1; @@ -558,7 +532,7 @@ namespace nana //Draw text, the text is transformed from orignal for hotkey character int text_top_off = (item_s.height - text_s.height) / 2; - ird.caption(item_pos.x + 8, item_pos.y + text_top_off, text); + ird.caption({ item_pos.x + 8, item_pos.y + text_top_off }, text); if(hotkey) { @@ -584,8 +558,7 @@ namespace nana menu_active(false), passive_close(true), nullify_mouse(false), - menu(nullptr), - delay_restore(false) + menu(nullptr) {} //end struct state_type //end class trigger From 535ef199778614c6465eccf10038e1d1c8cac0d8 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 23 Apr 2015 02:49:05 +0800 Subject: [PATCH 49/77] fix shift+tab issue --- include/nana/detail/linux_X11/msg_dispatcher.hpp | 2 +- source/gui/detail/linux_X11/bedrock.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/nana/detail/linux_X11/msg_dispatcher.hpp b/include/nana/detail/linux_X11/msg_dispatcher.hpp index a1ca507c..eab77f2f 100644 --- a/include/nana/detail/linux_X11/msg_dispatcher.hpp +++ b/include/nana/detail/linux_X11/msg_dispatcher.hpp @@ -172,7 +172,7 @@ namespace detail { int pending; { - nana::detail::platform_scope_guard psg; + nana::detail::platform_scope_guard lock; pending = ::XPending(display_); if(pending) { diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 94f35223..1add84a6 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -371,6 +371,7 @@ namespace detail XKeyEvent xkey; nana::detail::platform_spec::instance().read_keystate(xkey); arg.ctrl = (xkey.state & ControlMask); + arg.shift = (xkey.state & ShiftMask); } bool bedrock::set_keyboard_shortkey(bool yes) @@ -981,8 +982,8 @@ namespace detail else { nana::detail::platform_scope_guard psg; - status = XLookupBoth; - len = ::XLookupString(&xevent.xkey, keybuf, 32, &keysym, 0); + status = XLookupKeySym; + keysym = ::XLookupKeysym(&xevent.xkey, 0); } keybuf[len] = 0; @@ -1019,7 +1020,9 @@ namespace detail context.platform.keychar = keychar; if(keychar == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab { - auto the_next = brock.wd_manager.tabstop(msgwnd, true); + arg_keyboard argkey; + brock.get_key_state(argkey); + auto the_next = brock.wd_manager.tabstop(msgwnd, !argkey.shift); if(the_next) { brock.wd_manager.set_focus(the_next, false); From c3bf16554cbe658d71c96ca9c8cc93885cac97f2 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 23 Apr 2015 00:32:47 +0200 Subject: [PATCH 50/77] FIX: navigate ordered listbox with keyboard up/down, FEATURE: page up/down, and multi selection with shift + up/down Comments and code review. Original from branch page_scroll unfortunately included code already merged by Jinhao (header_width, etc) --- include/nana/gui/widgets/listbox.hpp | 61 +- include/nana/gui/widgets/scroll.hpp | 54 +- source/gui/widgets/listbox.cpp | 834 +++++++++++++++++---------- source/gui/widgets/scroll.cpp | 4 +- 4 files changed, 607 insertions(+), 346 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 056349cd..1827a585 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -112,7 +112,8 @@ namespace nana std::size_t pos_{0}; }; - struct index_pair + /// usefull for both absolute and display (sorted) positions + struct index_pair { size_type cat; //The pos of category size_type item; //the pos of item in a category. @@ -169,7 +170,8 @@ namespace nana class drawer_header_impl; class drawer_lister_impl; - class trigger: public drawer_trigger + /// mostly works on display positions + class trigger: public drawer_trigger { public: trigger(); @@ -198,13 +200,22 @@ namespace nana drawer_lister_impl *drawer_lister_; };//end class trigger - class item_proxy + /// operate with absolute positions and contain only the position but montain pointers to parts of the real items + /// item_proxy self, it references and iterators are not invalidated by sort() + class item_proxy : public std::iterator { public: item_proxy(essence_t*); item_proxy(essence_t*, const index_pair&); + /// the main porpose of this it to make obvious that item_proxy operate with absolute positions, and dont get moved during sort() + static item_proxy from_display(essence_t *ess, const index_pair &relative) ; + item_proxy from_display(const index_pair &relative) const; + + /// posible use: last_selected_display = last_selected.to_display().item; use with caution, it get invalidated after a sort() + index_pair to_display() const; + bool empty() const; item_proxy & check(bool ck); @@ -318,8 +329,8 @@ namespace nana essence_t * _m_ess() const; private: std::vector & _m_cells() const; - nana::any * _m_value(bool alloc_if_empty); - const nana::any * _m_value() const; + nana::any * _m_value(bool alloc_if_empty); + const nana::any * _m_value() const; private: essence_t * ess_; category_t* cat_{nullptr}; @@ -334,7 +345,7 @@ namespace nana cat_proxy(essence_t*, size_type pos); cat_proxy(essence_t*, category_t*); - /// Append an item at end of the category, set_value determines whether assign T object to the value of item. + /// Append an item at abs end of the category, set_value determines whether assign T object to the value of item. template item_proxy append(T&& t, bool set_value = false) { @@ -367,13 +378,18 @@ namespace nana item_proxy cbegin() const; item_proxy cend() const; - item_proxy at(size_type pos) const; + item_proxy at(size_type pos_abs) const; item_proxy back() const; - /// Returns the index of a item by its display pos, the index of the item isn't changed after sorting. + /// Returns the absolute index of a item by its display pos, the index of the item isn't changed after sorting. + /// convert from display order to absolute (find the real item in that display pos) but without check from current active sorting, in fact using just the last sorting !!! size_type index_by_display_order(size_type disp_order) const; - size_type display_order(size_type pos) const; - size_type position() const; + + /// find display order for the real item but without check from current active sorting, in fact using just the last sorting !!! + size_type display_order(size_type pos) const; + + /// this cat position + size_type position() const; /// Returns the number of items size_type size() const; @@ -410,7 +426,7 @@ namespace nana private: essence_t* ess_{nullptr}; category_t* cat_{nullptr}; - size_type pos_{0}; + size_type pos_{0}; ///< Absolute position, not relative to display, and dont change during sort() }; } }//end namespace drawerbase @@ -446,12 +462,12 @@ namespace nana } }//end namespace drawerbase -/*! \brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain \a items. +/*! \brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain a list of \a items. A category is a text with can be \a selected, \a checked and \a expanded to show the items. An item is formed by \a column-fields, each corresponding to one of the \a headers. An item can be \a selected and \a checked. The user can \a drag the header to \a reisize it or to \a reorganize it. -By \a clicking on a header the list get \a reordered, first up, and then down alternatively, +By \a clicking on a header the list get \a reordered, first up, and then down alternatively. */ class listbox : public widget_object, @@ -474,6 +490,8 @@ By \a clicking on a header the list get \a reordered, first up, and then down al void auto_draw(bool); ///); /// strick_ordering); - void sort_col(size_type col, bool reverse = false); + /// sort() and ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items + void sort_col(size_type col, bool reverse = false); size_type sort_col() const; - void unsort(); + + /// potencially ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items + void unsort(); bool freeze_sort(bool freeze); - selection selected() const; /// - class scroll + class scroll // add a widget scheme? : public widget_object, drawerbase::scroll::scroll_events> { typedef widget_object > base_type; @@ -345,29 +345,29 @@ namespace nana /// \brief The construct that creates a widget. /// @param wd A handle to the parent window of the widget being created. - /// @param visible specifying the visible after creating. + /// @param visible specify the visibility after creation. scroll(window wd, bool visible) { - this->create(wd, rectangle(), visible); + this->create(wd, rectangle(), visible); // add a widget scheme? and take some colors from these wd? } /// \brief The construct that creates a widget. /// @param wd A handle to the parent window of the widget being created. /// @param r the size and position of the widget in its parent window coordinate. - /// @param visible specifying the visible after creating. + /// @param visible specify the visibility after creation. scroll(window wd, const rectangle& r, bool visible = true) { this->create(wd, r, visible); } /// \brief Determines whether it is scrollable. - /// @param for_less whether it can be scrolled for a less value. + /// @param for_less whether it can be scrolled for a less value (backward or "up" if true, forward or "down" if false). bool scrollable(bool for_less) const { auto & m = this->get_drawer_trigger().metrics(); return (for_less ? (0 != m.value) : (m.value < m.peak - m.range)); } - + /// the whole total (peak) size_type amount() const { return this->get_drawer_trigger().metrics().peak; @@ -378,7 +378,7 @@ namespace nana return this->get_drawer_trigger().peak(Max); } - /// Get the range of the widget. + /// Get the range of the widget (how many is shonw on a page, that is, How many to scroll after click on first or second) size_type range() const { return this->get_drawer_trigger().metrics().range; @@ -390,7 +390,7 @@ namespace nana return this->get_drawer_trigger().range(r); } - /// \brief Get the value. + /// \brief Get the value (current offset calculated from the very beginnig) /// @return the value. size_type value() const { @@ -419,12 +419,12 @@ namespace nana return this->get_drawer_trigger().step(s); } - /// \brief Increase/decrease values by a step. + /// \brief Increase/decrease values by a step (alternativelly by some number of steps). /// @param forward it determines whether increase or decrease. /// @return true if the value is changed. - bool make_step(bool forward) + bool make_step(bool forward, unsigned steps=1) { - if(this->get_drawer_trigger().make_step(forward, 1)) + if(this->get_drawer_trigger().make_step(forward, steps)) { API::refresh_window(this->handle()); return true; @@ -437,13 +437,27 @@ namespace nana /// @return true if the vlaue is changed. bool make_scroll(bool forward) { - if(this->get_drawer_trigger().make_step(forward, 3)) + if(this->get_drawer_trigger().make_step(forward, 3)) // set this 3 in the metrics of the widget scheme ? { API::refresh_window(this->handle()); return true; } return false; } + + /// \brief Increase/decrease values by a page as if it is scrolled page up. + /// @param forward it determines whether increase or decrease. + /// @return true if the vlaue is changed. + bool make_page_scroll(bool forward) + { + if(this->get_drawer_trigger().make_step(forward, range()-1)) + { + API::refresh_window(this->handle()); + return true; + } + return false; + } + };//end class scroll }//end namespace nana #endif diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index e81a4859..e47706d2 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace nana { @@ -365,18 +366,28 @@ namespace nana cont_.emplace_back(std::move(text), pixels, static_cast(cont_.size())); } - void item_width(size_type index, unsigned width) + void item_width(size_type pos, unsigned width) { - if (index >= cont_.size()) + if (pos >= cont_.size()) return; for(auto & m : cont_) { - if(m.index == index) + if(m.index == pos) m.pixels = width; } } + unsigned item_width(size_type pos) const + { + for (auto & m : cont_) + { + if (m.index == pos) + return m.pixels; + } + return 0; + } + unsigned pixels() const { unsigned pixels = 0; @@ -571,9 +582,9 @@ namespace nana struct category_t { - typedef std::deque container; + using container = std::deque; - nana::string text; + ::nana::string text; std::vector sorted; container items; bool expand{true}; @@ -583,14 +594,10 @@ namespace nana category_t() = default; - category_t(nana::string&& str) + category_t(nana::string str) :text(std::move(str)) {} - - category_t(const nana::string& str) - :text(str) - {} - + bool selected() const { for (auto & m : items) @@ -604,10 +611,10 @@ namespace nana class es_lister { public: - typedef std::list container; + using container = std::list; - std::function(std::size_t) > fetch_ordering_comparer; + std::function(std::size_t) > fetch_ordering_comparer; es_lister() { @@ -619,8 +626,6 @@ namespace nana { ess_ = ess; widget_ = dynamic_cast(&wd); - if(nullptr == widget_) - throw std::bad_cast(); } nana::listbox* wd_ptr() const @@ -647,11 +652,14 @@ namespace nana return nullptr; } - void sort() + /// each sort() ivalidate any existing reference from display position to absolute item, that is after sort() display offset point to different items + void sort() { if((sorted_index_ == npos) || (!resort_)) return; + + auto weak_ordering_comp = fetch_ordering_comparer(sorted_index_); if(weak_ordering_comp) { @@ -708,13 +716,17 @@ namespace nana }); } } + scroll_refresh(); } + void scroll_refresh(); + /// sort() and ivalidate any existing reference from display position to absolute item, that is after sort() display offset point to different items bool sort_index(size_type index) { if (npos == index) { sorted_index_ = npos; + scroll_refresh(); return false; } @@ -730,11 +742,13 @@ namespace nana return true; } + /// sort() and ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items bool set_sort_index(std::size_t index, bool reverse) { if (npos == index) { sorted_index_ = npos; + scroll_refresh(); return false; } @@ -770,7 +784,7 @@ namespace nana return &list_.back(); } - void create_cat(const std::initializer_list & args) + void create_cat(const std::initializer_list& args) { for (auto & arg : args) list_.emplace_back(arg); @@ -807,7 +821,7 @@ namespace nana return &(*list_.emplace(i, std::move(text))); } - /// Insert before item in "pos" a new item with "text" in column 0 + /// Insert before item in absolute "pos" a new item with "text" in column 0, and place it in last display position of this cat bool insert(const index_pair& pos, nana::string&& text) { auto & catobj = *_m_at(pos.cat); @@ -826,15 +840,17 @@ namespace nana return true; } - size_type index_by_display_order(size_type cat, size_type order_pos) const + /// convert from display order to absolute (find the real item in that display pos) but without check from current active sorting, in fact using just the last sorting !!! + size_type index_by_display_order(size_type cat, size_type display_order_pos) const { auto & catobj = *_m_at(cat); - if (order_pos >= catobj.sorted.size()) + if (display_order_pos >= catobj.sorted.size()) throw std::out_of_range("listbox: Invalid item position."); - return catobj.sorted[order_pos]; + return catobj.sorted[display_order_pos]; } + /// find display order for the real item but without check from current active sorting, in fact using just the last sorting !!! size_type display_order(size_type cat, size_type pos) const { auto & catobj = *_m_at(cat); @@ -848,6 +864,7 @@ namespace nana return npos ; } + /// 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. category_t::container::value_type& at(const index_pair& pos) { auto index = pos.item; @@ -857,15 +874,9 @@ namespace nana return _m_at(pos.cat)->items.at(index); } - const category_t::container::value_type& at(const index_pair& pos) const { - auto index = pos.item; - - if (sorted_index_ != npos) - index = absolute(pos); - - return _m_at(pos.cat)->items.at(index); + return at(pos); } void clear(size_type cat) @@ -884,99 +895,96 @@ namespace nana } } - std::pair advance(size_type categ, size_type index, size_type n) + index_pair advance(index_pair from, size_type offset) // <------------- index { - std::pair dpos(npos, npos); - if(categ >= size_categ() || (index != npos && index >= size_item(categ))) return dpos; + index_pair dpos{npos, npos}; + if(from.cat >= size_categ() || (from.item != npos && from.item >= size_item(from.cat))) + return dpos; - dpos.first = categ; - dpos.second = index; + dpos = from; - while(n) + while(offset) { - if(dpos.second == npos) + if(dpos.item == npos) { - if(expand(dpos.first) == false) + if(expand(dpos.cat) == false) { - if(dpos.first + 1 == size_categ()) + if(dpos.cat + 1 == size_categ()) break; - ++dpos.first; + ++dpos.cat; } else - dpos.second = 0; - --n; + dpos.item = 0; + --offset; } else { - size_type rest = size_item(dpos.first) - dpos.second - 1; + size_type rest = size_item(dpos.cat) - dpos.item - 1; if(rest == 0) { - if(dpos.first + 1 == size_categ()) + if(dpos.cat + 1 == size_categ()) break; - ++dpos.first; - dpos.second = npos; - --n; + ++dpos.cat; + dpos.item = npos; + --offset; } - else if(rest < n) + else if(rest < offset) { - n -= rest; - if(dpos.first + 1 >= size_categ()) + offset -= rest; + if(dpos.cat + 1 >= size_categ()) { - dpos.second += rest; + dpos.item += rest; break; } - dpos.second = npos; - ++dpos.first; + dpos.item = npos; + ++dpos.cat; } else { - dpos.second += n; + dpos.item += offset; break; } } } return dpos; } - - size_type distance(size_type cat, size_type index, size_type to_cat, size_type to_index) const + /// change to index arg + size_type distance(index_pair from, index_pair to) const { - if(cat == to_cat && index == to_index) return 0; + if(from == to ) return 0; - if(to_cat == cat) + if(to.cat == from.cat) { - if(index > to_index && index != npos) - std::swap(index, to_index); + if(from.item > to.item && from.item != npos) + std::swap(from.item, to.item); - return (index == npos ? to_index + 1 : to_index - index); - } - else if(to_cat < cat) - { - std::swap(cat, to_cat); - std::swap(index, to_index); + return (from.item == npos ? to.item + 1 : to.item - from.item); } + else if(to.cat < from.cat) + std::swap(from, to); size_type n = 0; - auto i = _m_at(cat); - if(index == npos) + auto i = _m_at(from.cat); + if(from.item == npos) { if(i->expand) n = i->items.size(); } else - n = i->items.size() - (index + 1); + n = i->items.size() - (from.item + 1); - for(++i, ++cat; i != list_.end(); ++i, ++cat) + for(++i, ++from.cat; i != list_.end(); ++i, ++from.cat) { ++n; //this is a category - if(cat != to_cat) + if(from.cat != to.cat) { if(i->expand) n += i->items.size(); } else { - if(to_index != npos) - n += (to_index + 1); + if(to.item != npos) + n += (to.item + 1); break; } } @@ -1215,9 +1223,9 @@ namespace nana wd_ptr()->events().selected.emit(arg); if (m.flags.selected) - last_selected = i; - else if (last_selected == i) - last_selected.set_both(npos); //make empty + last_selected_abs = i; + else if (last_selected_abs == i) + last_selected_abs.set_both(npos); //make empty } ++i.item; } @@ -1226,22 +1234,41 @@ namespace nana return changed; } - void item_selected(selection& vec) const + /// return absolute positions, no relative to display + void item_selected(selection& vec) const // change to selection item_selected(); { index_pair id; for(auto & cat : list_) { id.item = 0; - for(auto & m : cat.items) + for(auto & m : cat.items) { if(m.flags.selected) - vec.push_back(id); + vec.push_back(id); // absolute positions, no relative to display ++id.item; } ++id.cat; } } + + index_pair find_first_selected() + { + index_pair id; + for(auto & cat : list_) + { + id.item = 0; + for(auto & m : cat.items) + { + if(m.flags.selected) + return id; // absolute positions, no relative to display + ++id.item; + } + ++id.cat; + } + return {npos,npos}; + } + /// return absolute positions, no relative to display bool item_selected_all_checked(selection& vec) const { index_pair id; @@ -1254,7 +1281,7 @@ namespace nana { if (m.flags.selected) { - vec.push_back(id); + vec.push_back(id); // absolute positions, no relative to display ck &= m.flags.checked; } ++id.item; @@ -1266,89 +1293,9 @@ namespace nana return ck; } - void move_select(bool upwards) - { - auto next_selected = last_selected; - if (next_selected.empty()) - { - bool good = false; - for(size_type i = 0, size = list_.size(); i < size; ++i) - { - if(size_item(i)) - { - //The first item which contains at least one item. - next_selected.cat = i; - next_selected.item = 0; - good = true; - break; - } - } - if(good == false) return; // items in listbox : nothing to select (and an empty but visible cat?) - } - - //start moving - while(true) - { - if(upwards == false) - { - if(good(next_selected.cat)) - { - if (size_item(next_selected.cat) > next_selected.item + 1) - { - ++next_selected.item; - } - else - { - next_selected.item = 0; - if (size_categ() > next_selected.cat + 1) - ++next_selected.cat; - else - next_selected.cat = 0; - } - } - else - next_selected.set_both(0); - } - else - { - if (0 == next_selected.item) - { - //there is an item at least definitely, because the start pos is an available item. - do - { - if (0 == next_selected.cat) - next_selected.cat = size_categ() - 1; - else - --next_selected.cat; - - }while (0 == size_item(next_selected.cat)); - - next_selected.item = size_item(next_selected.cat) - 1; - } - else - --next_selected.item; - } - - if (good(next_selected.cat)) - { - expand(next_selected.cat, true); - - if (good(next_selected)) - { - select_for_all(false); - at(next_selected).flags.selected = true; - - arg_listbox arg{ item_proxy(ess_, index_pair(next_selected.cat, absolute(next_selected))), true }; - wd_ptr()->events().selected.emit(arg); - - last_selected = next_selected; - } - break; - } - else break; - } - } - + ///items; @@ -1590,10 +1538,10 @@ namespace nana wd_ptr()->events().selected.emit(arg); changed = true; - if (sel) - last_selected = pos; - else if (last_selected == pos) - last_selected.set_both(npos); + if (sel) // not check for single_selection_ + last_selected_abs = pos; + else if (last_selected_abs == pos) + last_selected_abs.set_both(npos); } ++pos.item; } @@ -1605,7 +1553,8 @@ namespace nana categ_selected(categ, ! categ_selected(categ)); } - index_pair last() const + /// can be used as the absolute position of the last absolute item, or as the display pos of the last displayed item + index_pair last() const { index_pair i{ list_.size() - 1, list_.back().items.size() }; @@ -1622,6 +1571,12 @@ namespace nana return i; } + /// absolute position of the last displayed item + index_pair last_displ() const + { + return absolute ( last_displ() ); + } + bool good(size_type cat) const { return (cat < list_.size()); @@ -1661,12 +1616,35 @@ namespace nana return true; } - //Translate relative position into absolute position - size_type absolute(const index_pair& pos) const + ///Translate relative position (position in display) into absolute position (original data order) + size_type absolute(const index_pair& display_pos) const { - return (sorted_index_ == npos ? pos.item : _m_at(pos.cat)->sorted[pos.item]); + return (sorted_index_ == npos ? display_pos.item : _m_at(display_pos.cat)->sorted[display_pos.item]); + } + index_pair absolute_pair(const index_pair& display_pos) const + { + return {display_pos.cat, absolute( display_pos )}; + } + + ///Translate absolute position (original data order) into relative position (position in display) + size_type relative(const index_pair& pos) const + { + if (sorted_index_ == npos) return pos.item ; + + auto & catobj = *_m_at(pos.cat); + + for (size_type i=0; iexpand) { - std::size_t item_size = icat->items.size() - from.item; - if(offs < item_size) + std::size_t item_left_in_this_cat = icat->items.size() -1- from.item; + if(offs <= item_left_in_this_cat ) { item = from; - item.item += offs; - return true; + item.item += offs; // use absolute to know the real item + return true; // allways return here when we have only one cat. } else - offs -= item_size; + { + offs -= item_left_in_this_cat ; + item = from; + item.item += item_left_in_this_cat ; + } } ++from.cat; ++icat; for(; icat != list_.end(); ++icat, ++from.cat) { + item.cat = from.cat; + item.item = npos; + if(offs-- == 0) { - item.cat = from.cat; - item.item = npos; return true; } @@ -1719,7 +1702,7 @@ namespace nana { if(offs < icat->items.size()) { - item.cat = from.cat; + //item.cat = from.cat; item.item = offs; return true; } @@ -1730,6 +1713,7 @@ namespace nana return false; } + /// all arg are relative to display order, or all are absolute, but not mixed bool backward(index_pair from, size_type offs, index_pair& item) const { if(offs == 0) @@ -1738,7 +1722,7 @@ namespace nana if(good(from.cat)) { auto i = _m_at(from.cat); - size_type n = (from.is_category() ? 1 : from.item + 2); + size_type n = (from.is_category() ? 1 : from.item + 2); // ?? if(n <= offs) { offs -= n; @@ -1772,7 +1756,8 @@ namespace nana return false; } private: - container::iterator _m_at(size_type index) + /// categories iterator + container::iterator _m_at(size_type index) { if(index >= list_.size()) throw std::out_of_range("Nana.GUI.Listbox: invalid category index"); @@ -1792,16 +1777,16 @@ namespace nana return i; } public: - index_pair last_selected; + index_pair last_selected_abs, last_selected_dpl; private: essence_t * ess_{nullptr}; nana::listbox * widget_{nullptr}; std::size_t sorted_index_{npos}; ///< The index of the column used to sort bool resort_{true}; bool sorted_reverse_{false}; - bool ordered_categories_{false}; //A switch indicates whether the categories are ordered. - //The ordered categories always creates a new category at a proper position(before the first one which is larger than it). - container list_; + bool ordered_categories_{false}; ///< A switch indicates whether the categories are ordered. + /// The ordered categories always creates a new category at a proper position(before the first one which is larger than it). + container list_; // rename to categories_ bool single_selection_{ false }; bool single_selection_category_limited_{ false }; @@ -1840,8 +1825,8 @@ namespace nana { static const unsigned scale = 16; int offset_x; - index_pair offset_y; //cat stands for category, item stands for item. "item == npos" means that is a category. - + index_pair offset_y_abs, offset_y_dpl; //cat stands for category, item stands for item. "item == npos" means that is a category. + // need to be abs??? to see the same item after sort() ?? nana::scroll v; nana::scroll h; }scroll; @@ -1853,25 +1838,50 @@ namespace nana lister.fetch_ordering_comparer = std::bind(&es_header::fetch_comp, &header, std::placeholders::_1); } - const index_pair& scroll_y() const + const index_pair& scroll_y_abs() const { - return scroll.offset_y; + return scroll.offset_y_abs; + } + const index_pair& scroll_y_dpl() const + { + return scroll.offset_y_dpl; + } + const index_pair& scroll_y_dpl_refresh() + { + return scroll.offset_y_dpl = lister.relative_pair(scroll.offset_y_abs); } - void scroll_y(const index_pair& pos) + void scroll_y_abs(const index_pair& pos_abs) { - if (!lister.good(pos.cat)) + if (!lister.good(pos_abs.cat)) return; - scroll.offset_y.cat = pos.cat; - size_type number = lister.size_item(pos.cat); - if(pos.item < number) - scroll.offset_y.item = pos.item; + scroll.offset_y_abs.cat = pos_abs.cat; + + size_type number = lister.size_item(pos_abs.cat); + if(pos_abs.item < number) + scroll.offset_y_abs.item = pos_abs.item; else if(number) - scroll.offset_y.item = number - 1; + scroll.offset_y_abs.item = number - 1; else - scroll.offset_y.item = (pos.cat > 0 ? npos : 0); + scroll.offset_y_abs.item = (pos_abs.cat > 0 ? npos : 0); } + void scroll_y_rel(const index_pair& pos_rel) + { + scroll_y_abs(lister.relative_pair(pos_rel) ); + } + void set_scroll_y_abs(const index_pair& pos_abs) + { + scroll.offset_y_abs=pos_abs; + scroll_y_dpl_refresh() ; + } + /// directly set a tested relative display pos + void set_scroll_y_dpl(const index_pair& pos_dpl) + { + scroll.offset_y_dpl=pos_dpl; + scroll.offset_y_abs = lister.absolute_pair(pos_dpl); + } + //number_of_lister_item //@brief: Returns the number of items that are contained in pixels @@ -1882,44 +1892,56 @@ namespace nana return (lister_s / item_size) + (with_rest && (lister_s % item_size) ? 1 : 0); } - //keep the first selected item in the display area - void trace_selected_item() - { - selection svec; - lister.item_selected(svec); - if(svec.empty()) return; //no selected, exit. - - auto & item = svec[0]; - //Same with current scroll offset item. - if(item.item == npos && item.cat == scroll.offset_y.cat && scroll.offset_y.item == npos) - return; - - if(item.cat < scroll.offset_y.cat || ((item.cat == scroll.offset_y.cat) && (scroll.offset_y.item != npos) && (item.item == npos || item.item < scroll.offset_y.item))) - { - scroll.offset_y = item; - if(lister.expand(item.cat) == false) + //keep the first selected item in the display area: the distances are in display positions! + void trace_item_dpl( index_pair dpl_pos ) + { + if( dpl_pos.cat < scroll.offset_y_dpl.cat // in prevoious cat ---------------- up ----> we need to move + || ((dpl_pos.cat == scroll.offset_y_dpl.cat) && ( scroll.offset_y_dpl.item != npos) // is our cat, where we are an item + && (dpl_pos.item == npos || dpl_pos.item < scroll.offset_y_dpl.item))) + // problem!!!!!! + { + if(lister.expand(dpl_pos.cat) == false) { - if(lister.categ_selected(item.cat)) - scroll.offset_y.item = static_cast(npos); + if(lister.categ_selected(dpl_pos.cat)) + dpl_pos.item = static_cast(npos); else - lister.expand(item.cat, true); + lister.expand(dpl_pos.cat, true); } + set_scroll_y_dpl(dpl_pos); // <------------------------- set scroll.offset_y_dpl & scroll.offset_y_abs } else { - size_type numbers = number_of_lister_items(false); - size_type off = lister.distance(scroll.offset_y.cat, scroll.offset_y.item, item.cat, item.item); + size_type numbers = number_of_lister_items(false); // revise ... ok + size_type off = lister.distance(scroll.offset_y_dpl, dpl_pos); if(numbers > off) return; - auto n_off = lister.advance(scroll.offset_y.cat, scroll.offset_y.item, (off - numbers) + 1); - if(n_off.first != npos) - { - scroll.offset_y.cat = static_cast(n_off.first); - scroll.offset_y.item = static_cast(n_off.second); - } + index_pair n_off = lister.advance(scroll.offset_y_dpl, (off - numbers) + 1); + + if(n_off.cat != npos) // <------------------------- set scroll.offset_y_dpl & scroll.offset_y_abs + set_scroll_y_dpl(n_off); } - adjust_scroll_life(); - adjust_scroll_value(); + adjust_scroll_life(); // call adjust_scroll_value(); //adjust_scroll_value(); // again? + } + + void trace_item_abs( index_pair abs_pos ) + { + if(abs_pos.item == npos && abs_pos.cat == scroll.offset_y_abs.cat + && scroll.offset_y_abs.item == npos ) // if item==off y and is a cat + return; + + trace_item_dpl( lister.relative_pair(abs_pos)) ; // ??? scroll_y_dpl_refresh() ; + } + + void trace_last_selected_item( ) + { + trace_item_abs(lister.last_selected_abs); + } + + void trace_first_selected_item() + { + auto fs=lister.find_first_selected(); + if( ! fs.empty() ) + trace_item_abs( fs ); } void update() @@ -1948,12 +1970,12 @@ namespace nana if(height >= graph->width()) return; scroll.v.amount(lister.the_number_of_expanded()); scroll.v.range(number_of_lister_items(false)); - size_type off = lister.distance(0, 0, scroll.offset_y.cat, scroll.offset_y.item); + size_type off = lister.distance({0,0}, scroll.offset_y_dpl ); scroll.v.value(off); } } - - void adjust_scroll_life() + + void adjust_scroll_life() // at end call adjust_scroll_value(); { internal_scope_guard lock; @@ -2002,16 +2024,13 @@ namespace nana if(scroll.v.empty()) { scroll.v.create(wd, r); - API::take_active(scroll.v.handle(), false, wd); - scroll.v.events().mouse_move.connect_unignorable([this](const ::nana::arg_mouse& arg) + API::take_active(scroll.v.handle(), false, wd); // install value_changed() not mouse_move ???? + + scroll.v.events().value_changed([this](const ::nana::arg_scroll& arg) { - _m_answer_scroll(arg); + _m_answer_scroll_value(arg); }); - scroll.v.events().mouse_up.connect_unignorable([this](const ::nana::arg_mouse& arg) - { - _m_answer_scroll(arg); - }); } else scroll.v.move(r); @@ -2020,7 +2039,7 @@ namespace nana else if(!scroll.v.empty()) { scroll.v.close(); - scroll.offset_y.set_both(0); + set_scroll_y_dpl({0,0}); // scroll.offset_y.set_both(0); nana::rectangle r; if(rect_header(r)) @@ -2173,14 +2192,14 @@ namespace nana index_pair target; if(upwards == false) - lister.forward(scroll.offset_y, 1, target); + lister.forward(scroll.offset_y_dpl, 1, target); else - lister.backward(scroll.offset_y, 1, target); + lister.backward(scroll.offset_y_dpl, 1, target); - if (target == scroll.offset_y) + if (target == scroll.offset_y_dpl) return false; - scroll.offset_y = target; + set_scroll_y_dpl ( target ); return true; } @@ -2208,9 +2227,9 @@ namespace nana index_pair item; if(lister.forward(item, scroll.v.value(), item)) { - if (item != scroll.offset_y) + if (item != scroll.offset_y_dpl) { - scroll.offset_y = item; + set_scroll_y_dpl ( item ); update = true; } } @@ -2227,7 +2246,152 @@ namespace nana if(update) API::refresh_window(lister.wd_ptr()->handle()); } - }; + void _m_answer_scroll_value(const ::nana::arg_scroll& arg) + { + index_pair item; + if( !lister.forward(item, scroll.v.value(), item)) return; + + if (item == scroll.offset_y_dpl) + return; + + set_scroll_y_dpl ( item ); + + API::refresh_window(lister.wd_ptr()->handle()); + } + +#if ( 0 ) + void update_selection_range(index_pair to, const arg_mouse& arg) + { + using item_state = essence_t::item_state; + using parts = essence_t::parts; + bool update = false; + index_pair item_pos; + bool sel = true; + if (!lister.single_selection()) + { + if (arg.shift) + lister.select_display_range(lister.last_selected, item_pos, sel); + else if (arg.ctrl) + sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); + else + lister.select_for_all(false); + } + else + sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); + + item_ptr->flags.selected = sel; + index_pair last_selected(item_pos.cat, lister.absolute(item_pos)); + + arg_listbox arg{item_proxy{essence_, last_selected}, sel}; + lister.wd_ptr()->events().selected.emit(arg); + + if (item_ptr->flags.selected) + { + lister.cancel_others_if_single_enabled(true, last_selected); + essence_->lister.last_selected = last_selected; + + } + else if (essence_->lister.last_selected == last_selected) + essence_->lister.last_selected.set_both(npos); + } + else if(!lister.single_selection()) + lister.categ_selected(item_pos.cat, true); + update = true; + + } +#endif + +}; + + void es_lister::scroll_refresh() + { + ess_->scroll_y_dpl_refresh(); + + } + void es_lister::move_select(bool upwards, bool unselect_previous, bool trace_selected) + { + auto next_selected_dpl = relative_pair ( last_selected_abs); // last_selected_dpl; // ?? + if (next_selected_dpl.empty()) // has no cat ? (cat == npos) => beging from first cat + { + bool good = false; + for(size_type i = 0, size = list_.size(); i < size; ++i) // run all cat + { + if(size_item(i)) + { + //The first category which contains at least one item. + next_selected_dpl.cat = i; + next_selected_dpl.item = 0; + good = true; + break; + } + } + if(! good ) return; // items in listbox : nothing to select (and an empty but visible cat?) + } + + //start moving + while(true) + { + if(upwards == false) + { + if(good(next_selected_dpl.cat)) + { + if (size_item(next_selected_dpl.cat) > next_selected_dpl.item + 1) + { + ++next_selected_dpl.item; + } + else + { + next_selected_dpl.item = 0; + if (size_categ() > next_selected_dpl.cat + 1) + ++next_selected_dpl.cat; + else + next_selected_dpl.cat = 0; + } + } + else + next_selected_dpl.set_both(0); + } + else + { + if (0 == next_selected_dpl.item) + { + //there is an item at least definitely, because the start pos is an available item. + do + { + if (0 == next_selected_dpl.cat) + next_selected_dpl.cat = size_categ() - 1; + else + --next_selected_dpl.cat; + + }while (0 == size_item(next_selected_dpl.cat)); + + next_selected_dpl.item = size_item(next_selected_dpl.cat) - 1; + } + else + --next_selected_dpl.item; + } + + if (good(next_selected_dpl.cat)) + { + expand(next_selected_dpl.cat, true); // revise expand + + if (good(next_selected_dpl)) + { + if (unselect_previous && !single_selection_ ) + select_for_all(false); + + /// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected + item_proxy::from_display(ess_, next_selected_dpl).select(true); + + if (trace_selected) + ess_->trace_item_dpl(next_selected_dpl); + } + break; + } + else break; + } + } + class drawer_header_impl { @@ -2464,7 +2628,9 @@ namespace nana void draw(const nana::rectangle& rect) const { - internal_scope_guard lock; + // essence_->scroll_y_dpl_refresh() ; // ???? + + internal_scope_guard lock; size_type n = essence_->number_of_lister_items(true); if(0 == n)return; @@ -2480,9 +2646,11 @@ namespace nana es_lister & lister = essence_->lister; //The Tracker indicates the item where mouse placed. index_pair tracker(npos, npos); - auto & ptr_where = essence_->pointer_where; + auto & ptr_where = essence_->pointer_where; + + //if where == lister || where == checker, 'second' indicates the offset to the relative display-order pos of the scroll offset_y which stands for the first item to be displayed in lister. if((ptr_where.first == parts::lister || ptr_where.first == parts::checker) && ptr_where.second != npos) - lister.forward(essence_->scroll.offset_y, ptr_where.second, tracker); + lister.forward(essence_->scroll.offset_y_dpl, ptr_where.second, tracker); std::vector subitems; essence_->header_seq(subitems, rect.width); @@ -2495,29 +2663,28 @@ namespace nana int txtoff = (essence_->item_size - essence_->text_height) / 2; auto i_categ = lister.cat_container().cbegin(); - std::advance(i_categ, essence_->scroll.offset_y.cat); + std::advance(i_categ, essence_->scroll.offset_y_dpl.cat); - auto idx = essence_->scroll.offset_y; + auto idx = essence_->scroll.offset_y_dpl; auto state = item_state::normal; - const bool sort_enabled = (essence_->lister.sort_index() != npos); //Here draws a root categ or a first drawing is not a categ. if(idx.cat == 0 || !idx.is_category()) { if (idx.cat == 0 && idx.is_category()) { - essence_->scroll.offset_y.item = 0; + essence_->scroll.offset_y_dpl.item = 0; idx.item = 0; } std::size_t size = i_categ->items.size(); - for(std::size_t offs = essence_->scroll.offset_y.item; offs < size; ++offs, ++idx.item) + for(std::size_t offs = essence_->scroll.offset_y_dpl.item; offs < size; ++offs, ++idx.item) { if(n-- == 0) break; state = (tracker == idx ? item_state::highlighted : item_state::normal); - _m_draw_item(i_categ->items[sort_enabled ? lister.absolute(index_pair(idx.cat, offs)) : offs], x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state); + _m_draw_item(i_categ->items[lister.absolute(index_pair(idx.cat, offs)) ], x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state); y += essence_->item_size; } @@ -2544,7 +2711,7 @@ namespace nana if(n-- == 0) break; state = (idx == tracker ? item_state::highlighted : item_state::normal); - _m_draw_item(i_categ->items[sort_enabled ? lister.absolute(index_pair(idx.cat, pos)) : pos], x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); + _m_draw_item(i_categ->items[ lister.absolute(index_pair(idx.cat, pos))], x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); y += essence_->item_size; ++idx.item; } @@ -2932,7 +3099,7 @@ namespace nana { auto & lister = essence_->lister; index_pair item_pos; - if (lister.forward(essence_->scroll.offset_y, ptr_where.second, item_pos)) + if (lister.forward(essence_->scroll.offset_y_dpl, ptr_where.second, item_pos)) { auto * item_ptr = (item_pos.is_item() ? &lister.at(item_pos) : nullptr); if(ptr_where.first == parts::lister) @@ -2941,7 +3108,7 @@ namespace nana if (!lister.single_selection()) { if (arg.shift) - lister.select_display_range(lister.last_selected, item_pos, sel); + lister.select_display_range(lister.last_selected_abs , item_pos, sel); else if (arg.ctrl) sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); else @@ -2961,11 +3128,11 @@ namespace nana if (item_ptr->flags.selected) { lister.cancel_others_if_single_enabled(true, last_selected); - essence_->lister.last_selected = last_selected; + essence_->lister.last_selected_abs = last_selected; } - else if (essence_->lister.last_selected == last_selected) - essence_->lister.last_selected.set_both(npos); + else if (essence_->lister.last_selected_abs == last_selected) + essence_->lister.last_selected_abs.set_both(npos); } else if(!lister.single_selection()) lister.categ_selected(item_pos.cat, true); @@ -3007,6 +3174,7 @@ namespace nana } } + void trigger::mouse_up(graph_reference graph, const arg_mouse& arg) { using item_state = essence_t::item_state; @@ -3021,7 +3189,8 @@ namespace nana { if(essence_->lister.sort_index(essence_->pointer_where.second)) { - draw(); + essence_->trace_item_dpl({0,0}); + draw(); API::lazy_refresh(); } } @@ -3053,7 +3222,7 @@ namespace nana return; index_pair item_pos; - auto & offset_y = essence_->scroll.offset_y; + auto & offset_y = essence_->scroll.offset_y_dpl; auto & lister = essence_->lister; //Get the item which the mouse is placed. if (lister.forward(offset_y, essence_->pointer_where.second, item_pos)) @@ -3093,9 +3262,10 @@ namespace nana case keyboard::os_arrow_up: up = true; case keyboard::os_arrow_down: - essence_->lister.move_select(up); - essence_->trace_selected_item(); + // move_select(bool upwards=true, bool unselect_previous=true, bool trace_selected=false) + essence_->lister.move_select(up, !arg.shift, true); break; + case STR(' ') : { selection s; @@ -3104,6 +3274,28 @@ namespace nana item_proxy(essence_, i).check(ck); } break; + + case keyboard::copy: + { + nana::string str{STR("to_csv()")}; + //nana::system::dataexch().set(str); + return; + } + + case keyboard::os_pageup : + up = true; + case keyboard::os_pagedown: + { + auto& scrl = essence_->scroll.v; + if (! scrl.make_page_scroll(!up)) + return; + essence_->lister.select_for_all(false); + item_proxy {essence_, essence_->scroll_y_abs() } .select(true); + + break; + } + // case keyboard:: + default: return; } @@ -3129,7 +3321,23 @@ namespace nana } } - bool item_proxy::empty() const + /// the main porpose of this it to make obvious that item_proxy operate with absolute positions, and dont get moved during sort() + item_proxy item_proxy::from_display(essence_t *ess, const index_pair &relative) + { + return item_proxy{ess, ess->lister.absolute_pair(relative)}; + } + item_proxy item_proxy::from_display(const index_pair &relative) const + { + return item_proxy{ess_, ess_->lister.absolute_pair(relative)}; + } + + /// posible use: last_selected_display = last_selected.to_display().item; use with caution, it get invalidated after a sort() + index_pair item_proxy::to_display() const + { + return ess_->lister.relative_pair(pos_); + } + + bool item_proxy::empty() const { return !ess_; } @@ -3151,24 +3359,24 @@ namespace nana return cat_->items.at(pos_.item).flags.checked; } - item_proxy & item_proxy::select(bool s) + /// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected + item_proxy & item_proxy::select(bool s) { - auto & m = cat_->items.at(pos_.item); - if(m.flags.selected != s) + auto & m = cat_->items.at(pos_.item); // a ref to the real item + if(m.flags.selected == s) return *this; // ignore if no change + m.flags.selected = s; // actually change selection + + arg_listbox arg{*this, s}; + ess_->lister.wd_ptr()->events().selected.emit(arg); + + if (m.flags.selected) { - m.flags.selected = s; - - arg_listbox arg{*this, s}; - ess_->lister.wd_ptr()->events().selected.emit(arg); - - if (m.flags.selected) - { - ess_->lister.cancel_others_if_single_enabled(true, pos_); //Cancel all selections except pos_ if single_selection is enabled. - ess_->lister.last_selected = pos_; - } - else if (ess_->lister.last_selected == pos_) - ess_->lister.last_selected.set_both(npos); + ess_->lister.cancel_others_if_single_enabled(true, pos_); //Cancel all selections except pos_ if single_selection is enabled. + ess_->lister.last_selected_abs = pos_; } + else if (ess_->lister.last_selected_abs == pos_) + ess_->lister.last_selected_abs.set_both(npos); + return *this; } @@ -3451,11 +3659,11 @@ namespace nana return end(); } - item_proxy cat_proxy::at(size_type pos) const + item_proxy cat_proxy::at(size_type pos_abs) const { - if(pos >= size()) + if(pos_abs >= size()) throw std::out_of_range("listbox.cat_proxy.at() invalid position"); - return item_proxy(ess_, index_pair(pos_, pos)); + return item_proxy(ess_, index_pair(pos_, pos_abs)); } item_proxy cat_proxy::back() const @@ -3466,11 +3674,13 @@ namespace nana return item_proxy(ess_, index_pair(pos_, cat_->items.size() - 1)); } - size_type cat_proxy::index_by_display_order(size_type order_pos) const + /// convert from display order to absolute (find the real item in that display pos) but without check from current active sorting, in fact using just the last sorting !!! + size_type cat_proxy::index_by_display_order(size_type display_order_pos) const { - return ess_->lister.index_by_display_order(pos_, order_pos); + return ess_->lister.index_by_display_order(pos_, display_order_pos); } + /// find display order for the real item but without check from current active sorting, in fact using just the last sorting !!! size_type cat_proxy::display_order(size_type pos) const { return ess_->lister.display_order(pos_, pos); @@ -3635,6 +3845,19 @@ namespace nana ess.update(); } + listbox& listbox::header_width(size_type pos, unsigned pixels) + { + auto & ess = _m_ess(); + ess.header.item_width(pos, pixels); + ess.update(); + return *this; + } + + unsigned listbox::header_width(size_type pos) const + { + return _m_ess().header.item_width(pos); + } + listbox::cat_proxy listbox::append(nana::string s) { internal_scope_guard lock; @@ -3681,9 +3904,10 @@ namespace nana return *this; } - listbox::item_proxy listbox::at(const index_pair& pos) const + /// from abs pos + listbox::item_proxy listbox::at(const index_pair& pos_abs) const { - return at(pos.cat).at(pos.item); + return at(pos_abs.cat).at(pos_abs.item); } void listbox::insert(const index_pair& pos, nana::string text) @@ -3721,11 +3945,11 @@ namespace nana { auto & ess = _m_ess(); ess.lister.clear(cat); - auto pos = ess.scroll_y(); + auto pos = ess.scroll_y_dpl(); if(pos.cat == cat) { pos.item = (pos.cat > 0 ? npos : 0); - ess.scroll_y(pos); + ess.set_scroll_y_dpl(pos); } ess.update(); } @@ -3734,9 +3958,9 @@ namespace nana { auto & ess = _m_ess(); ess.lister.clear(); - auto pos = ess.scroll_y(); + auto pos = ess.scroll_y_dpl(); pos.item = (pos.cat > 0 ? npos : 0); - ess.scroll_y(pos); + ess.set_scroll_y_dpl(pos); ess.update(); } @@ -3746,17 +3970,17 @@ namespace nana ess.lister.erase(cat); if(cat) { - auto pos = ess.scroll_y(); + auto pos = ess.scroll_y_dpl(); if(cat <= pos.cat) { if(pos.cat == ess.lister.size_categ()) --pos.cat; pos.item = npos; - ess.scroll_y(pos); + ess.set_scroll_y_dpl(pos); } } else - ess.scroll_y(index_pair()); + ess.set_scroll_y_dpl(index_pair()); ess.update(); } @@ -3764,7 +3988,7 @@ namespace nana { auto & ess = _m_ess(); ess.lister.erase(); - ess.scroll_y(index_pair()); + ess.scroll_y_abs(index_pair()); ess.update(); } @@ -3776,7 +4000,7 @@ namespace nana auto * ess = ip._m_ess(); auto _where = ip.pos(); ess->lister.erase(_where); - auto pos = ess->scroll_y(); + auto pos = ess->scroll_y_dpl(); if((pos.cat == _where.cat) && (_where.item <= pos.item)) { if(pos.item == 0) @@ -3786,7 +4010,7 @@ namespace nana } else --pos.item; - ess->scroll_y(pos); + ess->set_scroll_y_dpl(pos); } ess->update(); if(_where.item < ess->lister.size_item(_where.cat)) @@ -3799,7 +4023,8 @@ namespace nana _m_ess().header.column(col).weak_ordering = std::move(strick_ordering); } - void listbox::sort_col(size_type col, bool reverse) + /// sort() and ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items + void listbox::sort_col(size_type col, bool reverse) { _m_ess().lister.set_sort_index(col, reverse); } @@ -3809,6 +4034,7 @@ namespace nana return _m_ess().lister.sort_index(); } + /// potencially ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items void listbox::unsort() { _m_ess().lister.set_sort_index(npos, false); @@ -3819,10 +4045,10 @@ namespace nana return !_m_ess().lister.active_sort(!freeze); } - auto listbox::selected() const -> selection + auto listbox::selected() const -> selection // change to: selection selected(); { selection s; - _m_ess().lister.item_selected(s); + _m_ess().lister.item_selected(s); // absolute positions, no relative to display return std::move(s); } @@ -3838,7 +4064,7 @@ namespace nana return _m_ess().header.visible(); } - void listbox::move_select(bool upwards) + void listbox::move_select(bool upwards) /// Date: Fri, 24 Apr 2015 16:47:03 +0200 Subject: [PATCH 51/77] FIX: Listbox doesn't handle Home, End. OK in windows --- include/nana/gui/basis.hpp | 3 ++- source/gui/widgets/listbox.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index 4eb95c88..c0ef0aa5 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -96,7 +96,8 @@ namespace nana //System Code for OS os_pageup = 0x21, os_pagedown, os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down, - os_insert = 0x2D, os_del + os_insert = 0x2D, os_del , + os_end = 0x23 , os_home //Pos 1 }; }; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index e47706d2..75968f93 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3294,7 +3294,16 @@ namespace nana break; } - // case keyboard:: + case keyboard::os_home: + essence_->lister.select_for_all(false); + item_proxy::from_display(essence_, {0,0}).select(true); + essence_->trace_last_selected_item (); + break; + case keyboard::os_end: + essence_->lister.select_for_all(false); + item_proxy::from_display(essence_, essence_->lister.last()).select(true); + essence_->trace_last_selected_item (); + break; default: return; From 0d736db47984ab653fb2448b831bf7946d9a9486 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 24 Apr 2015 17:25:27 +0200 Subject: [PATCH 52/77] FIX: PageDown select last item in page not first --- source/gui/widgets/listbox.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 75968f93..daf9bc2f 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3256,7 +3256,6 @@ namespace nana void trigger::key_press(graph_reference graph, const arg_keyboard& arg) { bool up = false; - switch(arg.key) { case keyboard::os_arrow_up: @@ -3290,8 +3289,14 @@ namespace nana if (! scrl.make_page_scroll(!up)) return; essence_->lister.select_for_all(false); - item_proxy {essence_, essence_->scroll_y_abs() } .select(true); - + if (up) + item_proxy {essence_, essence_->scroll_y_abs()}.select(true); + else + { + index_pair idx{essence_->scroll_y_dpl()}; + essence_->lister.forward(idx, scrl.range()-1, idx); + item_proxy::from_display(essence_,idx).select(true); + } break; } case keyboard::os_home: From c6c910af7328707cc22d961e2d3801f61ff9cec5 Mon Sep 17 00:00:00 2001 From: beru Date: Sat, 25 Apr 2015 16:43:39 +0900 Subject: [PATCH 53/77] trivial fix for compiler warning 1>c:\libs\nana\include\nana\gui\widgets\listbox.hpp(251): warning C4018: '<' : signed/unsigned mismatch (..\form_do_you_even_lift.cpp) 1> c:\projects\bro\form_do_you_even_lift.cpp(646) : see reference to function template instantiation 'nana::drawerbase::listbox::item_proxy &nana::drawerbase::listbox::item_proxy::resolve_from(const T &)' being compiled 1> with 1> [ 1> T=Data 1> ] --- 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 1827a585..cb5ac968 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -248,7 +248,7 @@ namespace nana auto && cells = ores.move_cells(); auto cols = columns(); cells.resize(cols); - for (auto pos = 0; pos < cols; ++pos) + for (auto pos = 0u; pos < cols; ++pos) { auto & el = cells[pos]; if (el.text.size() == 1 && el.text[0] == nana::char_t(0)) From 063968a803ec5daf71311aaab87da85495b6c02b Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 10:16:51 +0200 Subject: [PATCH 54/77] working on listbox export to string CSV: listbox, header, dummy list --- source/gui/widgets/listbox.cpp | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index daf9bc2f..506c7f38 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -333,6 +333,24 @@ namespace nana typedef std::vector container; + nana::string to_string() const + { + nana::string sep{STR(";")}, endl{STR("\n")}, head_str; + bool first{true}; + for(auto & i: cont()) + { + if(i.visible) + { + if(first) + first=false; + else + head_str += sep; + head_str += i.text; + } + } + return head_str; + } + bool visible() const { return visible_; @@ -651,6 +669,39 @@ namespace nana } return nullptr; } + nana::string to_string() const + { + nana::string sep{STR(";")}, endl{STR("\n")}, list_str{STR("Empieza list: ")}; + bool first{true}; + for(auto & cat: cat_container()) + { + list_str += STR("categorias: ") ; + if(first) + first=false; + else + { + //if(cat.selected()) + list_str += (cat.text + STR("categorias 2 ") + endl); + } + list_str += STR("categorias: ") ; + bool first_it{true}; + for (auto i : cat.sorted) + { + auto& it= cat.items[i] ; + if(it.flags.selected) + { + list_str += (it.cells[0].text + endl); + if(first_it) + first_it=false; + else + { + } + } + + } + } + return list_str + STR("Termina: "); + } /// each sort() ivalidate any existing reference from display position to absolute item, that is after sort() display offset point to different items void sort() @@ -1838,6 +1889,13 @@ namespace nana lister.fetch_ordering_comparer = std::bind(&es_header::fetch_comp, &header, std::placeholders::_1); } + nana::string to_string() const + { + nana::string sep{STR(";")}, endl{STR("\n")}; + lister.to_string(); + return header.to_string() + endl + lister.to_string() ; + } + const index_pair& scroll_y_abs() const { return scroll.offset_y_abs; From 1fb363fb72bbcf26f7ef7794daf64237fedc6422 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 10:22:34 +0200 Subject: [PATCH 55/77] listbox override key_char to manage copy: Ctrl-C. --- include/nana/gui/widgets/listbox.hpp | 1 + source/gui/widgets/listbox.cpp | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 1827a585..5e3fc92e 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -194,6 +194,7 @@ namespace nana void dbl_click(graph_reference, const arg_mouse&) override; void resized(graph_reference, const arg_resized&) override; void key_press(graph_reference, const arg_keyboard&) override; + void key_char(graph_reference, const arg_keyboard&) override; private: essence_t * essence_; drawer_header_impl *drawer_header_; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 506c7f38..4a1cd532 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -702,7 +702,7 @@ namespace nana } return list_str + STR("Termina: "); } - + /// each sort() ivalidate any existing reference from display position to absolute item, that is after sort() display offset point to different items void sort() { @@ -1896,7 +1896,7 @@ namespace nana return header.to_string() + endl + lister.to_string() ; } - const index_pair& scroll_y_abs() const + const index_pair& scroll_y_abs() const { return scroll.offset_y_abs; } @@ -3332,13 +3332,6 @@ namespace nana } break; - case keyboard::copy: - { - nana::string str{STR("to_csv()")}; - //nana::system::dataexch().set(str); - return; - } - case keyboard::os_pageup : up = true; case keyboard::os_pagedown: @@ -3374,6 +3367,19 @@ namespace nana draw(); API::lazy_refresh(); } + + void trigger::key_char(graph_reference graph, const arg_keyboard& arg) + { + switch(arg.key) + { + case keyboard::copy: + nana::system::dataexch().set(essence_->to_string()); + return; + default: + return; + } + } + //end class trigger //class item_proxy From f943673d3de9739a563061460607393dafe221f0 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 26 Apr 2015 00:50:28 +0800 Subject: [PATCH 56/77] update scroll.hpp --- include/nana/basic_types.hpp | 6 +- include/nana/gui/widgets/listbox.hpp | 1 + include/nana/gui/widgets/scroll.hpp | 81 ++++++------ source/basic_types.cpp | 28 ++-- source/gui/place.cpp | 22 ++-- source/gui/widgets/scroll.cpp | 185 ++++++++++++--------------- 6 files changed, 144 insertions(+), 179 deletions(-) diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp index 6e129e89..a48d9ece 100644 --- a/include/nana/basic_types.hpp +++ b/include/nana/basic_types.hpp @@ -434,10 +434,10 @@ namespace nana unsigned height; }; - class area_rotator + class rectangle_rotator { public: - area_rotator(bool rotated, const ::nana::rectangle& area); + rectangle_rotator(bool rotated, const ::nana::rectangle& area); int x() const; int & x_ref(); @@ -454,7 +454,7 @@ namespace nana private: bool rotated_; ::nana::rectangle area_; - };//end class area_rotator + };//end class rectangle_rotator enum class arrange { diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 1827a585..1c93bdda 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -8,6 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/listbox.hpp + * @contributors: Ariel Vina-Rodriguez * */ diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index 143836e6..39491da6 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -8,6 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/scroll.hpp + * @contributors: Ariel Vina-Rodriguez */ #ifndef NANA_GUI_WIDGET_SCROLL_HPP #define NANA_GUI_WIDGET_SCROLL_HPP @@ -49,7 +50,7 @@ namespace nana struct metrics_type { - using size_type = std::size_t ; + using size_type = std::size_t; size_type peak; ///< the whole total size_type range; ///< how many is shonw on a page, that is, How many to scroll after click on first or second @@ -70,10 +71,10 @@ namespace nana public: struct states { - enum{none, highlight, actived, selected}; + enum{ none, highlight, actived, selected }; }; - typedef nana::paint::graphics& graph_reference; + using graph_reference = paint::graphics&; const static unsigned fixedsize = 16; // make it part of a new "metric" in the widget_scheme drawer(metrics_type& m); @@ -114,7 +115,7 @@ namespace nana void peak(size_type s) { - if(graph_ && (metrics_.peak != s)) + if (graph_ && (metrics_.peak != s)) { metrics_.peak = s; API::refresh_window(widget_->handle()); @@ -123,10 +124,10 @@ namespace nana void value(size_type s) { - if(s + metrics_.range > metrics_.peak) + if (s + metrics_.range > metrics_.peak) s = metrics_.peak - metrics_.range; - if(graph_ && (metrics_.value != s)) + if (graph_ && (metrics_.value != s)) { metrics_.value = s; _m_emit_value_changed(); @@ -137,7 +138,7 @@ namespace nana void range(size_type s) { - if(graph_ && (metrics_.range != s)) + if (graph_ && (metrics_.range != s)) { metrics_.range = s; API::refresh_window(widget_->handle()); @@ -151,31 +152,31 @@ namespace nana bool make_step(bool forward, unsigned multiple) { - if(graph_) + if (graph_) { size_type step = (multiple > 1 ? metrics_.step * multiple : metrics_.step); size_type value = metrics_.value; - if(forward) + if (forward) { size_type maxv = metrics_.peak - metrics_.range; - if(metrics_.peak > metrics_.range && value < maxv) + if (metrics_.peak > metrics_.range && value < maxv) { - if(maxv - value >= step) + if (maxv - value >= step) value += step; else value = maxv; } } - else if(value) + else if (value) { - if(value > step) + if (value > step) value -= step; else value = 0; } size_type cmpvalue = metrics_.value; metrics_.value = value; - if(value != cmpvalue) + if (value != cmpvalue) { _m_emit_value_changed(); return true; @@ -221,24 +222,24 @@ namespace nana void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override { bool redraw = false; - if(metrics_.pressed && (metrics_.what == buttons::scroll)) + if (metrics_.pressed && (metrics_.what == buttons::scroll)) { size_type cmpvalue = metrics_.value; drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x)); - if(cmpvalue != metrics_.value) + if (cmpvalue != metrics_.value) _m_emit_value_changed(); redraw = true; } else { buttons what = drawer_.what(graph, arg.pos); - if(metrics_.what != what) + if (metrics_.what != what) { redraw = true; metrics_.what = what; } } - if(redraw) + if (redraw) { drawer_.draw(graph, metrics_.what); API::lazy_refresh(); @@ -247,11 +248,11 @@ namespace nana void mouse_down(graph_reference graph, const arg_mouse& arg) override { - if(arg.left_button) + if (arg.left_button) { metrics_.pressed = true; metrics_.what = drawer_.what(graph, arg.pos); - switch(metrics_.what) + switch (metrics_.what) { case buttons::first: case buttons::second: @@ -265,13 +266,13 @@ namespace nana break; case buttons::forward: case buttons::backward: - { - size_type cmpvalue = metrics_.value; - drawer_.auto_scroll(); - if(cmpvalue != metrics_.value) - _m_emit_value_changed(); - } - break; + { + size_type cmpvalue = metrics_.value; + drawer_.auto_scroll(); + if (cmpvalue != metrics_.value) + _m_emit_value_changed(); + } + break; default: //Ignore buttons::none break; } @@ -294,7 +295,7 @@ namespace nana void mouse_leave(graph_reference graph, const arg_mouse&) override { - if(metrics_.pressed) return; + if (metrics_.pressed) return; metrics_.what = buttons::none; drawer_.draw(graph, buttons::none); @@ -303,7 +304,7 @@ namespace nana void mouse_wheel(graph_reference graph, const arg_wheel& arg) override { - if(make_step(arg.upwards == false, 3)) + if (make_step(arg.upwards == false, 3)) { drawer_.draw(graph, metrics_.what); API::lazy_refresh(); @@ -367,7 +368,7 @@ namespace nana auto & m = this->get_drawer_trigger().metrics(); return (for_less ? (0 != m.value) : (m.value < m.peak - m.range)); } - /// the whole total (peak) + /// the whole total (peak) size_type amount() const { return this->get_drawer_trigger().metrics().peak; @@ -422,9 +423,9 @@ namespace nana /// \brief Increase/decrease values by a step (alternativelly by some number of steps). /// @param forward it determines whether increase or decrease. /// @return true if the value is changed. - bool make_step(bool forward, unsigned steps=1) + bool make_step(bool forward, unsigned steps = 1) { - if(this->get_drawer_trigger().make_step(forward, steps)) + if (this->get_drawer_trigger().make_step(forward, steps)) { API::refresh_window(this->handle()); return true; @@ -437,25 +438,15 @@ namespace nana /// @return true if the vlaue is changed. bool make_scroll(bool forward) { - if(this->get_drawer_trigger().make_step(forward, 3)) // set this 3 in the metrics of the widget scheme ? - { - API::refresh_window(this->handle()); - return true; - } - return false; + return this->make_step(forward, 3); // set this 3 in the metrics of the widget scheme ? } - /// \brief Increase/decrease values by a page as if it is scrolled page up. + /// \brief Increase/decrease values by a page as if it is scrolled page up. /// @param forward it determines whether increase or decrease. /// @return true if the vlaue is changed. bool make_page_scroll(bool forward) { - if(this->get_drawer_trigger().make_step(forward, range()-1)) - { - API::refresh_window(this->handle()); - return true; - } - return false; + return this->make_step(forward, range() - 1); } };//end class scroll diff --git a/source/basic_types.cpp b/source/basic_types.cpp index c2e1a9aa..c8bd2c34 100644 --- a/source/basic_types.cpp +++ b/source/basic_types.cpp @@ -765,65 +765,65 @@ namespace nana } //end struct rectangle - //class area_rotator - area_rotator::area_rotator(bool rotated, const ::nana::rectangle& area) + //class rectangle_rotator + rectangle_rotator::rectangle_rotator(bool rotated, const ::nana::rectangle& area) : rotated_(rotated), area_(area) {} - int area_rotator::x() const + int rectangle_rotator::x() const { return (rotated_ ? area_.y : area_.x); } - int & area_rotator::x_ref() + int & rectangle_rotator::x_ref() { return (rotated_ ? area_.y : area_.x); } - int area_rotator::y() const + int rectangle_rotator::y() const { return (rotated_ ? area_.x : area_.y); } - int & area_rotator::y_ref() + int & rectangle_rotator::y_ref() { return (rotated_ ? area_.x : area_.y); } - unsigned area_rotator::w() const + unsigned rectangle_rotator::w() const { return (rotated_ ? area_.height : area_.width); } - unsigned & area_rotator::w_ref() + unsigned & rectangle_rotator::w_ref() { return (rotated_ ? area_.height : area_.width); } - unsigned area_rotator::h() const + unsigned rectangle_rotator::h() const { return (rotated_ ? area_.width : area_.height); } - unsigned & area_rotator::h_ref() + unsigned & rectangle_rotator::h_ref() { return (rotated_ ? area_.width : area_.height); } - int area_rotator::right() const + int rectangle_rotator::right() const { return (rotated_ ? area_.y + static_cast(area_.height) : area_.x + static_cast(area_.width)); } - int area_rotator::bottom() const + int rectangle_rotator::bottom() const { return (rotated_ ? area_.x + static_cast(area_.width) : area_.y + static_cast(area_.height)); } - const ::nana::rectangle& area_rotator::result() const + const ::nana::rectangle& rectangle_rotator::result() const { return area_; } - //end class area_rotator + //end class rectangle_rotator } diff --git a/source/gui/place.cpp b/source/gui/place.cpp index f3be7d8a..c643993a 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -985,7 +985,7 @@ namespace nana const bool vert = (kind::arrange != kind_of_division); auto area_margined = margin_area(); - area_rotator area(vert, area_margined); + rectangle_rotator area(vert, area_margined); auto area_px = area.w(); auto fa = _m_fixed_and_adjustable(kind_of_division, area_px); @@ -1001,7 +1001,7 @@ namespace nana if(!child->display) //Ignore the division if the corresponding field is not displayed. continue; - area_rotator child_area(vert, child->field_area); + rectangle_rotator child_area(vert, child->field_area); child_area.x_ref() = static_cast(position); child_area.y_ref() = area.y(); child_area.h_ref() = area.h(); @@ -1591,7 +1591,7 @@ namespace nana return; const bool vert = (::nana::cursor::size_we != splitter_cursor_); - auto area_px = area_rotator(vert, div_owner->margin_area()).w(); + auto area_px = rectangle_rotator(vert, div_owner->margin_area()).w(); int delta = (vert ? splitter_.pos().y - begin_point_.y : splitter_.pos().x - begin_point_.x); int total_pixels = static_cast(left_pixels_ + right_pixels_); @@ -1632,8 +1632,8 @@ namespace nana { const bool vert = (::nana::cursor::size_we != splitter_cursor_); - area_rotator left(vert, leaf_left_->field_area); - area_rotator right(vert, leaf_right_->field_area); + rectangle_rotator left(vert, leaf_left_->field_area); + rectangle_rotator right(vert, leaf_right_->field_area); auto area_px = right.right() - left.x(); auto right_px = static_cast(limit_px(leaf_right_, init_weight_.get_value(area_px), static_cast(area_px))); @@ -1643,7 +1643,7 @@ namespace nana else if (pos > limited_range.right()) pos = limited_range.right(); - area_rotator sp_r(vert, field_area); + nana::rectangle_rotator sp_r(vert, field_area); sp_r.x_ref() = pos; left.w_ref() = static_cast(pos - left.x()); @@ -1659,7 +1659,7 @@ namespace nana leaf_right_->collocate(wd); //Set the leafs' weight - area_rotator area(vert, div_owner->field_area); + rectangle_rotator area(vert, div_owner->field_area); double imd_rate = 100.0 / static_cast(area.w()); leaf_left_->weight.assign_percent(imd_rate * static_cast(left.w())); @@ -1674,14 +1674,14 @@ namespace nana splitter_.move(this->field_area); } private: - area_rotator _m_update_splitter_range() + rectangle_rotator _m_update_splitter_range() { const bool vert = (cursor::size_ns == splitter_cursor_); - area_rotator area(vert, div_owner->margin_area()); + rectangle_rotator area(vert, div_owner->margin_area()); - area_rotator left(vert, leaf_left_->field_area); - area_rotator right(vert, leaf_right_->field_area); + rectangle_rotator left(vert, leaf_left_->field_area); + rectangle_rotator right(vert, leaf_right_->field_area); const int left_base = left.x(), right_base = right.right(); int pos = left_base; diff --git a/source/gui/widgets/scroll.cpp b/source/gui/widgets/scroll.cpp index 32638261..b6d466fb 100644 --- a/source/gui/widgets/scroll.cpp +++ b/source/gui/widgets/scroll.cpp @@ -52,20 +52,11 @@ namespace nana pos = screen_pos.x; } - if(scale >= fixedsize * 2) - { - if(pos < static_cast(fixedsize)) - return buttons::first; - if(pos > static_cast(scale - fixedsize)) - return buttons::second; - } - else - { - if(pos < static_cast(scale / 2)) - return buttons::first; - if(pos > static_cast(scale / 2)) - return buttons::second; - } + const auto bound_pos = static_cast(scale >= fixedsize * 2 ? fixedsize : scale / 2); + if (pos < bound_pos) + return buttons::first; + if (pos > static_cast(scale) - bound_pos) + return buttons::second; if(metrics_.scroll_length) { @@ -100,7 +91,7 @@ namespace nana metrics_.scroll_pos = pos; auto value_max = metrics_.peak - metrics_.range; metrics_.value = pos * value_max / scroll_area; - if(metrics_.value < metrics_.peak - metrics_.range) + if(metrics_.value < value_max) { int selfpos = static_cast(metrics_.value * scroll_area / value_max); int nextpos = static_cast((metrics_.value + 1) * scroll_area / value_max); @@ -115,22 +106,22 @@ namespace nana void drawer::auto_scroll() { - if(_m_check()) + if (!_m_check()) + return; + + if(buttons::forward == metrics_.what) + { //backward + if(metrics_.value <= metrics_.range) + metrics_.value = 0; + else + metrics_.value -= (metrics_.range-1); + } + else if(buttons::backward == metrics_.what) { - if(buttons::forward == metrics_.what) - { //backward - if(metrics_.value <= metrics_.range) - metrics_.value = 0; - else - metrics_.value -= (metrics_.range-1); - } - else if(buttons::backward == metrics_.what) - { - if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range) - metrics_.value = metrics_.peak - metrics_.range; - else - metrics_.value += (metrics_.range-1); - } + if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range) + metrics_.value = metrics_.peak - metrics_.range; + else + metrics_.value += (metrics_.range-1); } } @@ -141,26 +132,20 @@ namespace nana _m_background(graph); - ::nana::rectangle r(graph.size()); - if(vertical_) - { - r.y = r.height - fixedsize; - r.height = fixedsize; - } - else - { - r.x = r.width - fixedsize; - r.width = fixedsize; - } + rectangle_rotator r(vertical_, graph.size()); + r.x_ref() = static_cast(r.w() - fixedsize); + r.w_ref() = fixedsize; int state = ((_m_check() == false || what == buttons::none) ? states::none : states::highlight); int moused_state = (_m_check() ? (metrics_.pressed ? states::selected : states::actived) : states::none); + auto result = r.result(); + //draw first - _m_draw_button(graph, { 0, 0, r.width, r.height }, buttons::first, (buttons::first == what ? moused_state : state)); + _m_draw_button(graph, { 0, 0, result.width, result.height }, buttons::first, (buttons::first == what ? moused_state : state)); //draw second - _m_draw_button(graph, r, buttons::second, (buttons::second == what ? moused_state : state)); + _m_draw_button(graph, result, buttons::second, (buttons::second == what ? moused_state : state)); //draw scroll _m_draw_scroll(graph, (buttons::scroll == what ? moused_state : states::highlight)); @@ -171,64 +156,61 @@ namespace nana { graph.rectangle(true, {0xf0, 0xf0, 0xf0}); - if(metrics_.pressed && _m_check()) + if (!metrics_.pressed || !_m_check()) + return; + + nana::rectangle_rotator r(vertical_, graph.size()); + if(metrics_.what == buttons::forward) { - int x = 0, y = 0; - unsigned width = graph.width(), height = graph.height(); - - if(metrics_.what == buttons::forward) - { - *(vertical_ ? &y : &x) = fixedsize; - *(vertical_ ? &height: &width) = metrics_.scroll_pos; - } - else if(buttons::backward == metrics_.what) - { - *(vertical_ ? &y : &x) = static_cast(fixedsize + metrics_.scroll_pos + metrics_.scroll_length); - *(vertical_ ? &height: &width) = static_cast((vertical_ ? graph.height() : graph.width()) - (fixedsize * 2 + metrics_.scroll_pos + metrics_.scroll_length)); - } - else - return; - - if(width && height) - graph.rectangle({ x, y, width, height }, true, {0xDC, 0xDC, 0xDC}); + r.x_ref() = static_cast(fixedsize); + r.w_ref() = metrics_.scroll_pos; } + else if(buttons::backward == metrics_.what) + { + r.x_ref() = static_cast(fixedsize + metrics_.scroll_pos + metrics_.scroll_length); + r.w_ref() = static_cast((vertical_ ? graph.height() : graph.width()) - (fixedsize * 2 + metrics_.scroll_pos + metrics_.scroll_length)); + } + else + return; + + auto result = r.result(); + if (!result.empty()) + graph.rectangle(result, true, static_cast(0xDCDCDC)); } void drawer::_m_button_frame(graph_reference graph, rectangle r, int state) { - if(state) + if (!state) + return; + + ::nana::color clr{0x97, 0x97, 0x97}; //highlight + switch(state) { - ::nana::color clr{0x97, 0x97, 0x97}; //highlight - switch(state) - { - case states::actived: - clr.from_rgb(0x86, 0xD5, 0xFD); break; - case states::selected: - clr.from_rgb(0x3C, 0x7F, 0xB1); break; - } - - graph.rectangle(r, false, clr); - - clr = clr.blend(colors::white, 0.5); - graph.set_color(clr); - - r.pare_off(2); - - if(vertical_) - { - unsigned half = r.width / 2; - graph.rectangle({ r.x + static_cast(r.width - half), r.y, half, r.height }, true); - r.width -= half; - } - else - { - unsigned half = r.height / 2; - graph.rectangle({r.x, r.y + static_cast(r.height - half), r.width, half}, true); - r.height -= half; - } - //graph.shadow_rectangle(x, y, width, height, 0xFFFFFF, color_x, !vertical_); - graph.gradual_rectangle(r, colors::white, clr, !vertical_); + case states::actived: + clr.from_rgb(0x86, 0xD5, 0xFD); break; + case states::selected: + clr.from_rgb(0x3C, 0x7F, 0xB1); break; } + + graph.rectangle(r, false, clr); + + clr = clr.blend(colors::white, 0.5); + graph.set_color(clr); + + r.pare_off(2); + if(vertical_) + { + unsigned half = r.width / 2; + graph.rectangle({ r.x + static_cast(r.width - half), r.y, half, r.height }, true); + r.width -= half; + } + else + { + unsigned half = r.height / 2; + graph.rectangle({r.x, r.y + static_cast(r.height - half), r.width, half}, true); + r.height -= half; + } + graph.gradual_rectangle(r, colors::white, clr, !vertical_); } bool drawer::_m_check() const @@ -271,20 +253,11 @@ namespace nana { if(_m_check()) { - ::nana::rectangle r(graph.size()); + rectangle_rotator r(vertical_, graph.size()); + r.x_ref() = static_cast(fixedsize + metrics_.scroll_pos); + r.w_ref() = static_cast(metrics_.scroll_length); - if(vertical_) - { - r.y = fixedsize + metrics_.scroll_pos; - r.height = static_cast(metrics_.scroll_length); - } - else - { - r.x = fixedsize + metrics_.scroll_pos; - r.width = static_cast(metrics_.scroll_length); - } - - _m_button_frame(graph, r, state); + _m_button_frame(graph, r.result(), state); } } From 26bca2cc0843f0e18f7570ae0aa28f05188c32fb Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 17:29:32 +0200 Subject: [PATCH 57/77] listbox: introducing struct export options --- include/nana/gui/widgets/listbox.hpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 5e3fc92e..e38fdbbe 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -429,7 +429,19 @@ namespace nana category_t* cat_{nullptr}; size_type pos_{0}; ///< Absolute position, not relative to display, and dont change during sort() }; - } + + struct export_options + { + nana::string sep = nana::string {STR(";" )}, + endl= nana::string {STR("\n")} ; + bool only_selected_items{true}, + only_checked_items {false}, + only_visible_columns{true}; + + using columns_indexs = std::vector; + columns_indexs columns_order; + }; + } }//end namespace drawerbase struct arg_listbox @@ -482,7 +494,9 @@ By \a clicking on a header the list get \a reordered, first up, and then down al using selection = drawerbase::listbox::selection; /// Date: Sat, 25 Apr 2015 17:44:31 +0200 Subject: [PATCH 58/77] columns_indexs all_headers( only_visibles) --- source/gui/widgets/listbox.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 4a1cd532..524b64f4 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -331,7 +331,18 @@ namespace nana {} }; - typedef std::vector container; + using container = std::vector ; + + export_options::columns_indexs all_headers(bool only_visibles) const + { + export_options::columns_indexs idx; + for(auto hd : cont()) + { + if(!only_visibles || hd.visible) + idx.push_back(hd.index); + } + return idx; + } nana::string to_string() const { From 8fdbb0bf44f71dfba73ae60884fc92bbd5d2dbdb Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 17:45:16 +0200 Subject: [PATCH 59/77] item to string in column order --- source/gui/widgets/listbox.cpp | 71 ++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 524b64f4..a14fe980 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -607,6 +607,21 @@ namespace nana return *this; } + nana::string to_string(const export_options::columns_indexs& col_order) const + { + nana::string sep{STR(";")}, endl{STR("\n")}, item_str; + bool first{true}; + for( size_type idx{}; idxheader.all_headers(true); + bool first{true}; + for(auto & cat: cat_container()) + { + if(first) + first=false; + else + list_str += (cat.text + endl); + + bool first_item{true}; + for (auto i : cat.sorted) + { + auto& it= cat.items[i] ; + if(it.flags.selected) + list_str += (it.to_string(col_order) + endl); + } + } + return list_str ; + } class drawer_header_impl From 2767fa75ca2382110e1e8e4ecfb3956f244ca43f Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 20:53:13 +0200 Subject: [PATCH 60/77] listbox have def_export_options(); --- include/nana/gui/widgets/listbox.hpp | 3 ++- source/gui/widgets/listbox.cpp | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index e38fdbbe..9599a484 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -432,7 +432,7 @@ namespace nana struct export_options { - nana::string sep = nana::string {STR(";" )}, + nana::string sep = nana::string {STR("\t" )}, endl= nana::string {STR("\n")} ; bool only_selected_items{true}, only_checked_items {false}, @@ -591,6 +591,7 @@ By \a clicking on a header the list get \a reordered, first up, and then down al void enable_single(bool for_selection, bool category_limited); void disable_single(bool for_selection); + export_options& def_export_options(); private: drawerbase::listbox::essence_t & _m_ess() const; nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index a14fe980..aa78abee 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1856,6 +1856,13 @@ namespace nana unsigned item_size{24}; unsigned text_height{0}; unsigned suspension_width{0}; + ::nana::listbox::export_options def_exp_options ; + + ::nana::listbox::export_options& def_export_options() + { + return def_exp_options; + } + es_header header; es_lister lister; // we have at least one emty cat. the #0 @@ -4191,6 +4198,11 @@ namespace nana _m_ess().lister.disable_single(for_selection); } + listbox::export_options& listbox::def_export_options() + { + return _m_ess().def_export_options(); + } + drawerbase::listbox::essence_t & listbox::_m_ess() const { return get_drawer_trigger().essence(); From 7fcd38816bc7204714f3bda648a0d9badbdb2ac9 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 20:59:28 +0200 Subject: [PATCH 61/77] to string take (uses) export options --- source/gui/widgets/listbox.cpp | 89 +++++++++------------------------- 1 file changed, 23 insertions(+), 66 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index aa78abee..5888ef81 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace nana { @@ -344,20 +345,21 @@ namespace nana return idx; } - nana::string to_string() const + nana::string to_string(const export_options& exp_opt) const { - nana::string sep{STR(";")}, endl{STR("\n")}, head_str; + nana::string head_str; bool first{true}; - for(auto & i: cont()) - { - if(i.visible) + for( size_type idx{}; idxhandle()); } -#if ( 0 ) - void update_selection_range(index_pair to, const arg_mouse& arg) - { - using item_state = essence_t::item_state; - using parts = essence_t::parts; - bool update = false; - index_pair item_pos; - bool sel = true; - if (!lister.single_selection()) - { - if (arg.shift) - lister.select_display_range(lister.last_selected, item_pos, sel); - else if (arg.ctrl) - sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); - else - lister.select_for_all(false); - } - else - sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); - - item_ptr->flags.selected = sel; - index_pair last_selected(item_pos.cat, lister.absolute(item_pos)); - - arg_listbox arg{item_proxy{essence_, last_selected}, sel}; - lister.wd_ptr()->events().selected.emit(arg); - - if (item_ptr->flags.selected) - { - lister.cancel_others_if_single_enabled(true, last_selected); - essence_->lister.last_selected = last_selected; - - } - else if (essence_->lister.last_selected == last_selected) - essence_->lister.last_selected.set_both(npos); - } - else if(!lister.single_selection()) - lister.categ_selected(item_pos.cat, true); - update = true; - - } -#endif - }; void es_lister::scroll_refresh() @@ -2450,24 +2408,23 @@ namespace nana else break; } } - nana::string es_lister::to_string() const + nana::string es_lister::to_string(const export_options& exp_opt) const { - nana::string sep{STR(";")}, endl{STR("\n")}, list_str; - auto col_order = ess_->header.all_headers(true); + nana::string list_str; bool first{true}; for(auto & cat: cat_container()) { if(first) first=false; else - list_str += (cat.text + endl); + list_str += (cat.text + exp_opt.endl); bool first_item{true}; for (auto i : cat.sorted) { auto& it= cat.items[i] ; - if(it.flags.selected) - list_str += (it.to_string(col_order) + endl); + if(it.flags.selected || !exp_opt.only_selected_items) + list_str += (it.to_string(exp_opt) + exp_opt.endl); } } return list_str ; From 49378469ab5ee6805e48b68436b415c643a55f2b Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 20:59:54 +0200 Subject: [PATCH 62/77] copy base on def export options --- source/gui/widgets/listbox.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 5888ef81..482e8e9c 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3353,8 +3353,13 @@ namespace nana switch(arg.key) { case keyboard::copy: - nana::system::dataexch().set(essence_->to_string()); + { + export_options exp_opt {essence_->def_export_options()}; + exp_opt.columns_order = essence_->header.all_headers(true); + exp_opt.only_selected_items = true; + nana::system::dataexch().set(essence_->to_string(exp_opt)); return; + } default: return; } From db0591a5db53dcb7158df6e6649a06fbf90f595f Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 21:39:09 +0200 Subject: [PATCH 63/77] allow programmatically export an arbitrary set of columns --- source/gui/widgets/listbox.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 482e8e9c..1310c1f8 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -350,16 +350,20 @@ namespace nana nana::string head_str; bool first{true}; for( size_type idx{}; idxvisible || ! exp_opt.only_visible_columns); + + if(first) + first=false; + else head_str += exp_opt.sep; - head_str += cont()[idx].text; + head_str += col->text; } return head_str; } @@ -3358,7 +3362,7 @@ namespace nana exp_opt.columns_order = essence_->header.all_headers(true); exp_opt.only_selected_items = true; nana::system::dataexch().set(essence_->to_string(exp_opt)); - return; + return; } default: return; From 83fa73d11faa3dac8b14ee0835ca94ec941f2ccb Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 25 Apr 2015 22:56:53 +0200 Subject: [PATCH 64/77] listbox select all Now the programs user can "export" the whole list just by pressing ctrl+A-C and pasting into another application, like LibreOffice Calc, Excel, an editor, etc --- source/gui/widgets/listbox.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 1310c1f8..b2fdde1c 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3364,6 +3364,12 @@ namespace nana nana::system::dataexch().set(essence_->to_string(exp_opt)); return; } + case keyboard::select_all : + essence_->lister.select_for_all(true); + draw(); + API::lazy_refresh(); + break; + default: return; } From 585732a497dbbfbea0f1e30bbc571c2ad8ecb974 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 26 Apr 2015 02:32:22 +0200 Subject: [PATCH 65/77] simpler code --- source/gui/widgets/listbox.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index b2fdde1c..88f04699 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -351,19 +351,23 @@ namespace nana bool first{true}; for( size_type idx{}; idxvisible || ! exp_opt.only_visible_columns); - if(first) first=false; else head_str += exp_opt.sep; - head_str += col->text; + size_type index{exp_opt.columns_order[idx]}; + bool bad{true}; + for (auto&col:cont()) + if(col.index == index) + { + bad=false; + head_str += col.text; + break; + } + + if(bad) + throw std::out_of_range("Trying to export from a lisboxt an inexisting column"); } return head_str; } From 575de13cc4c821ded696e6beb82f4eedeb79334f Mon Sep 17 00:00:00 2001 From: beru Date: Sun, 26 Apr 2015 15:40:58 +0900 Subject: [PATCH 66/77] add nana::system::dataexch::set(const nana::paint::graphics& g) method --- include/nana/system/dataexch.hpp | 9 +++- source/system/dataexch.cpp | 88 +++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/include/nana/system/dataexch.hpp b/include/nana/system/dataexch.hpp index a730accb..ecfe9b22 100644 --- a/include/nana/system/dataexch.hpp +++ b/include/nana/system/dataexch.hpp @@ -14,7 +14,13 @@ #define NANA_SYSTEM_DATAEXCH_HPP #include -namespace nana{ namespace system{ +namespace nana{ + +namespace paint{ + class graphics; +} + +namespace system{ /// a data exchange mechanism through Windows Clipboard, X11 Selection. class dataexch { @@ -26,6 +32,7 @@ namespace nana{ namespace system{ void set(const nana::char_t* text); void set(const nana::string& text); + bool set(const nana::paint::graphics& g); void get(nana::string& str); private: bool _m_set(unsigned type, const void* buf, std::size_t size); diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index 926e6f98..a7109a48 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -12,6 +12,10 @@ #include #include +#include +#include +#include + #if defined(NANA_WINDOWS) #include #elif defined(NANA_X11) @@ -33,6 +37,86 @@ namespace nana{ namespace system{ _m_set(std::is_same::value ? format::text : format::unicode, text.c_str(), (text.length() + 1) * sizeof(nana::char_t)); } + bool dataexch::set(const nana::paint::graphics& g) + { +#if defined(NANA_WINDOWS) + size sz = g.size(); + paint::pixel_buffer pbuffer; + rectangle r; + r.x = 0; + r.y = 0; + r.width = sz.width; + r.height = sz.height; + pbuffer.attach(g.handle(), r); + size_t bytes_per_line = pbuffer.bytes_per_line(); + size_t bitmap_bytes = bytes_per_line * r.height; + + struct { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; + } bmi = {0}; + 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); + int err = ::GetLastError(); + ::ReleaseDC(NULL, hDC); + return false; + } + if (!::ReleaseDC(NULL, hDC)) { + return false; + } + + size_t header_size = sizeof(bmi.bmiHeader); + + // Bitmaps are huge, so to avoid unnegligible extra copy, this routine does not use private _m_set method. + HGLOBAL h_gmem = ::GlobalAlloc(GHND | GMEM_SHARE, header_size + bitmap_bytes); + void * gmem = ::GlobalLock(h_gmem); + if (!gmem) { + assert(false); + goto Label_GlobalFree; + } + char* p = (char*)gmem; + // Fix BITMAPINFOHEADER obtained from GetDIBits WinAPI + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biHeight = ::abs(bmi.bmiHeader.biHeight); + memcpy(p, &bmi, header_size); + p += header_size; + // many programs do not support bottom-up DIB, so reversing row order is needed. + for (int y=0; y Date: Mon, 27 Apr 2015 06:18:28 +0900 Subject: [PATCH 67/77] add methods to get/set sortability of listbox --- include/nana/gui/widgets/listbox.hpp | 5 ++++- source/gui/widgets/listbox.cpp | 23 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 1827a585..4ad8d9da 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -552,7 +552,10 @@ By \a clicking on a header the list get \a reordered, first up, and then down al _m_ease_key(&key); } - ///Sets a strict weak ordering comparer for a column + bool sortable() const; + void sortable(bool enable); + + ///Sets a strict weak ordering comparer for a column void set_sort_compare(size_type col, std::function strick_ordering); diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index e47706d2..3f7c6a46 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -348,6 +348,16 @@ namespace nana return false; } + bool sortable() const + { + return sortable_; + } + + void sortable(bool enable) + { + sortable_ = enable; + } + std::function fetch_comp(std::size_t index) const { if(index < cont_.size()) @@ -507,6 +517,7 @@ namespace nana } private: bool visible_{true}; + bool sortable_{true}; container cont_; }; @@ -3183,7 +3194,7 @@ namespace nana auto prev_state = essence_->ptr_state; essence_->ptr_state = item_state::highlighted; //Do sort - if (essence_->pointer_where.first == parts::header && prev_state == item_state::pressed) + if (essence_->header.sortable() && essence_->pointer_where.first == parts::header && prev_state == item_state::pressed) { if(essence_->pointer_where.second < essence_->header.cont().size()) { @@ -4018,6 +4029,16 @@ namespace nana return item_proxy(ess); } + bool listbox::sortable() const + { + return _m_ess().header.sortable(); + } + + void listbox::sortable(bool enable) + { + _m_ess().header.sortable(enable); + } + void listbox::set_sort_compare(size_type col, std::function strick_ordering) { _m_ess().header.column(col).weak_ordering = std::move(strick_ordering); From 4b4843bb7f7fdf8bfac0643226373fde16316fb5 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Mon, 27 Apr 2015 01:00:26 +0200 Subject: [PATCH 68/77] fix necessary copy, add comments and code review --- include/nana/gui/widgets/listbox.hpp | 5 +- source/gui/widgets/listbox.cpp | 90 ++++++++++++++-------------- 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 8d630ea5..d4775fc3 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -17,6 +17,7 @@ #include "widget.hpp" #include #include +//#include #include #include @@ -28,7 +29,7 @@ namespace nana { namespace listbox { - typedef std::size_t size_type; + using size_type = std::size_t ; struct cell { @@ -36,7 +37,7 @@ namespace nana { ::nana::color bgcolor; ::nana::color fgcolor; - + /// ::nana::paint::font font; \todo format() = default; format(const ::nana::color& bgcolor, const ::nana::color& fgcolor); }; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 88f04699..9cc63577 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -313,14 +313,14 @@ namespace nana } //end class iresolver/oresolver - class es_header /// Essence of the columns Header + /// Essence of the columns Header + class es_header { public: - typedef std::size_t size_type; struct column_t { - nana::string text; //< "text" header of the column number "index" with weigth "pixels" + nana::string text; ///< "text" header of the column number "index" with weigth "pixels" unsigned pixels; bool visible{true}; size_type index; @@ -337,10 +337,10 @@ namespace nana export_options::columns_indexs all_headers(bool only_visibles) const { export_options::columns_indexs idx; - for(auto hd : cont()) + for(const auto &header : cont()) { - if(!only_visibles || hd.visible) - idx.push_back(hd.index); + if(header.visible || !only_visibles) + idx.push_back(header.index); } return idx; } @@ -356,18 +356,7 @@ namespace nana else head_str += exp_opt.sep; - size_type index{exp_opt.columns_order[idx]}; - bool bad{true}; - for (auto&col:cont()) - if(col.index == index) - { - bad=false; - head_str += col.text; - break; - } - - if(bad) - throw std::out_of_range("Trying to export from a lisboxt an inexisting column"); + head_str += column_ref(exp_opt.columns_order[idx]).text; } return head_str; } @@ -438,6 +427,7 @@ namespace nana return pixels; } + /// return the original order or index previous to any list reorganization of the current column "n". size_type index(size_type n) const { return (n < cont_.size() ? cont_[n].index : npos); @@ -448,6 +438,7 @@ namespace nana return cont_; } + /// find and return a ref to the column that originaly was at position "pos" previous to any list reorganization. column_t& column(size_type pos) { for(auto & m : cont_) @@ -457,18 +448,29 @@ namespace nana } throw std::out_of_range("Nana.GUI.Listbox: invalid header index."); } + const column_t& column_ref(size_type pos) const + { + for(const auto & m : cont_) + { + if(m.index == pos) + return m; + } + throw std::out_of_range("Nana.GUI.Listbox: invalid header index."); + } + /// return the original index of the current column at x . size_type item_by_x(int x) const { - for(auto & m : cont_) + for(const auto & col : cont_) // in current order { - if(x < static_cast(m.pixels)) - return m.index; - x -= m.pixels; + if(x < static_cast(col.pixels)) + return col.index; + x -= col.pixels; } return npos; } + /// return the left position of the column originaly at index "pos" . int item_pos(size_type pos, unsigned * pixels) const { int left = 0; @@ -486,11 +488,11 @@ namespace nana } return left; } - + /// return the original index of the visible col currently before(in front of) or after the col originaly at index "index" size_type neighbor(size_type index, bool front) const { size_type n = npos; - for(auto i = cont_.cbegin(); i != cont_.cend(); ++i) + for(auto i = cont_.cbegin(); i != cont_.cend(); ++i) // in current order { if(i->index == index) { @@ -506,16 +508,17 @@ namespace nana } return npos; } - + /// return the original index of the currently first visible col size_type begin() const { - for(auto & m : cont_) + for(const auto & m : cont_) { if(m.visible) return m.index; } return npos; } + /// return the original index of the currently last visible col size_type last() const { for(auto i = cont_.rbegin(); i != cont_.rend(); ++i) @@ -524,25 +527,24 @@ namespace nana } return npos; } - + /// move the col originaly at index to the position currently in front (or after) the col originaly at index "to" invalidating some current index void move(size_type index, size_type to, bool front) { - if((index != to) && (index < cont_.size()) && (to < cont_.size())) - { - auto i = std::find_if(cont_.begin(), cont_.end(), [index](container::value_type& m){ - return (index == m.index); - }); + if(index == to) return; + if(index >= cont_.size()) return; + if(to >= cont_.size()) return; - if (i == cont_.end()) - return; + auto i = std::find_if(cont_.begin(), cont_.end(), [index](container::value_type& m){return (index == m.index);}); - auto from = *i; - cont_.erase(i); + if (i == cont_.end()) + return; - i = std::find_if(cont_.begin(), cont_.end(), [to](const container::value_type& m)->bool{ return (to == m.index); } ); - if(i != cont_.end()) - cont_.insert((front ? i : ++i), from); - } + auto from = *i; // a temp copy + cont_.erase(i); + + i = std::find_if(cont_.begin(), cont_.end(), [to](const container::value_type& m)->bool{ return (to == m.index); } ); + if(i != cont_.end()) + cont_.insert((front ? i : ++i), from); } private: bool visible_{true}; @@ -553,7 +555,7 @@ namespace nana struct item_t { - typedef std::vector container; + using container = std::vector; container cells; nana::color bgcolor; @@ -2463,13 +2465,13 @@ namespace nana if(essence_->ptr_state == item_state::highlighted) { x -= (r.x - essence_->scroll.offset_x); - for(auto & hd : essence_->header.cont()) + for(auto & hd : essence_->header.cont()) // in current order { if(hd.visible) { if((static_cast(hd.pixels) - 2 < x) && (x < static_cast(hd.pixels) + 3)) { - item_spliter_ = hd.index; + item_spliter_ = hd.index; // original index return true; } x -= hd.pixels; @@ -3058,7 +3060,7 @@ namespace nana } } - if(essence_->ptr_state == item_state::grabbed) + if(essence_->ptr_state == item_state::grabbed) { nana::point pos = arg.pos; essence_->widget_to_header(pos); From 611d295fc854199badaa008560fb8e3c5d784ff6 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Mon, 27 Apr 2015 13:26:44 +0200 Subject: [PATCH 69/77] comment key use --- include/nana/gui/widgets/listbox.hpp | 3 +++ include/nana/key_type.hpp | 4 ++-- source/gui/widgets/listbox.cpp | 9 +++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index d4775fc3..eacc6857 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -514,8 +514,11 @@ By \a clicking on a header the list get \a reordered, first up, and then down al void append(std::initializer_list); /// cat_proxy operator[](const Key & ck) { diff --git a/include/nana/key_type.hpp b/include/nana/key_type.hpp index 9550f8df..dcfa4f79 100644 --- a/include/nana/key_type.hpp +++ b/include/nana/key_type.hpp @@ -22,10 +22,10 @@ namespace nana virtual ~key_interface(){} virtual bool same_type(const key_interface*) const = 0; - virtual bool compare(const key_interface*) const = 0; + virtual bool compare(const key_interface*) const = 0; ///< is this key less than right key? [call it less(rk), less_than(rk) or compare_less(rk)?: if (lk.less_than(rk )) ] }; //end class key_interface - //Use less compare for equal compare + //Use less compare for equal compare [call it equal_by_less()?] inline bool pred_equal_by_less(const key_interface * left, const key_interface* right) { return (left->compare(right) == false) && (right->compare(left) == false); diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 9cc63577..95c216a9 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -834,20 +834,21 @@ namespace nana return sorted_reverse_; } - ///Append a new category with a specified name. + ///Append a new category with a specified name and return a pointer to it. category_t* create_cat(nana::string&& text) { list_.emplace_back(std::move(text)); return &list_.back(); } - + /// just append a list of new cat. void create_cat(const std::initializer_list& args) { for (auto & arg : args) list_.emplace_back(arg); } - category_t* create_cat(std::shared_ptr ptr) + /// will use the key to insert new cat before the first cat with compare less than the key, or at the end of the list of cat and return a ref to that new cat. ? + category_t* create_cat(std::shared_ptr ptr) { for (auto i = list_.begin(); i != list_.end(); ++i) { @@ -863,7 +864,7 @@ namespace nana list_.back().key_ptr = ptr; return &list_.back(); } - + /// add a new cat created at "pos" and return a ref to it category_t* create_cat(std::size_t pos, nana::string&& text) { #if defined(NANA_LINUX) || defined(NANA_MINGW) From 4fcd2edd54d3f8e346d619c893bdb72a89bdf836 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 29 Apr 2015 12:44:52 +0200 Subject: [PATCH 70/77] FIX: crash when clear an ordered listbox --- source/gui/widgets/listbox.cpp | 50 ++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 95c216a9..f1ebd7d6 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -943,7 +943,7 @@ namespace nana catobj.items.clear(); catobj.sorted.clear(); } - + /// clear all items in all cat, but not the container of cat self. void clear() { for(auto & m : list_) @@ -1677,7 +1677,18 @@ namespace nana ///Translate relative position (position in display) into absolute position (original data order) size_type absolute(const index_pair& display_pos) const { - return (sorted_index_ == npos ? display_pos.item : _m_at(display_pos.cat)->sorted[display_pos.item]); + if(sorted_index_ == npos) + return display_pos.item ; + + auto & catobj = *_m_at(display_pos.cat); + + if(catobj.items.size()==0) + if (display_pos == index_pair{0,0} ) + return 0; + else + return npos; + + return catobj.sorted[display_pos.item] ; } index_pair absolute_pair(const index_pair& display_pos) const { @@ -1687,7 +1698,8 @@ namespace nana ///Translate absolute position (original data order) into relative position (position in display) size_type relative(const index_pair& pos) const { - if (sorted_index_ == npos) return pos.item ; + if (sorted_index_ == npos) + return pos.item ; auto & catobj = *_m_at(pos.cat); @@ -1695,6 +1707,10 @@ namespace nana if (pos.item == catobj.sorted[i]) return i; + if (pos == index_pair{0,0} ) + if(catobj.items.size()==0) + return 0; + return npos ; } index_pair relative_pair(const index_pair& pos) const @@ -1934,7 +1950,12 @@ namespace nana else if(number) scroll.offset_y_abs.item = number - 1; else + { scroll.offset_y_abs.item = (pos_abs.cat > 0 ? npos : 0); + scroll.offset_y_dpl = scroll.offset_y_abs ; + return ; + } + scroll_y_dpl_refresh() ; } void scroll_y_rel(const index_pair& pos_rel) { @@ -4025,12 +4046,13 @@ namespace nana { auto & ess = _m_ess(); ess.lister.clear(cat); - auto pos = ess.scroll_y_dpl(); - if(pos.cat == cat) - { - pos.item = (pos.cat > 0 ? npos : 0); - ess.set_scroll_y_dpl(pos); - } + //unsort(); // ?? + + // from current display position + // move to the cat self if not in first cat + // move to first item ?? if in first cat + ess.scroll_y_abs(ess.scroll_y_abs()); + ess.update(); } @@ -4038,9 +4060,13 @@ namespace nana { auto & ess = _m_ess(); ess.lister.clear(); - auto pos = ess.scroll_y_dpl(); - pos.item = (pos.cat > 0 ? npos : 0); - ess.set_scroll_y_dpl(pos); + unsort(); // apperar to be espected + + // from current display position + // move to the cat self if not in first cat + // move to first item ?? if in first cat + ess.scroll_y_abs(ess.scroll_y_abs()); + ess.update(); } From 97db67b2a445c5d748ff4518348e6cd1079bbfc6 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 29 Apr 2015 12:45:37 +0200 Subject: [PATCH 71/77] FIX: a crash when clear an empty listbox --- source/gui/widgets/listbox.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index f1ebd7d6..488903e8 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1711,7 +1711,7 @@ namespace nana if(catobj.items.size()==0) return 0; - return npos ; + return npos ; } index_pair relative_pair(const index_pair& pos) const { @@ -1951,7 +1951,7 @@ namespace nana scroll.offset_y_abs.item = number - 1; else { - scroll.offset_y_abs.item = (pos_abs.cat > 0 ? npos : 0); + scroll.offset_y_abs.item = (pos_abs.cat > 0 ? npos : 0); scroll.offset_y_dpl = scroll.offset_y_abs ; return ; } @@ -3326,6 +3326,10 @@ namespace nana void trigger::key_press(graph_reference graph, const arg_keyboard& arg) { bool up = false; + + if (essence_->lister.size_categ()==1 && essence_->lister.size_item(0)==0) + return ; + switch(arg.key) { case keyboard::os_arrow_up: From c6df0c4293dee26e1b494e111f4fe62ee26699c4 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 29 Apr 2015 23:05:14 +0200 Subject: [PATCH 72/77] FIX: a draw problem with item in listbox --- source/gui/widgets/listbox.cpp | 57 ++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 488903e8..fef9660b 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2297,7 +2297,7 @@ namespace nana void header_seq(std::vector &seqs, unsigned lister_w)const { int x = - (scroll.offset_x); - for(auto hd : header.cont()) + for(const auto& hd : header.cont()) { if(false == hd.visible) continue; x += hd.pixels; @@ -2711,7 +2711,9 @@ namespace nana unsigned header_w = essence_->header.pixels(); essence_->graph->set_color(bgcolor); if(header_w - essence_->scroll.offset_x < rect.width) - essence_->graph->rectangle(rectangle{ rect.x + static_cast(header_w)-essence_->scroll.offset_x, rect.y, rect.width - (header_w - essence_->scroll.offset_x), rect.height }, true); + essence_->graph->rectangle(rectangle{ point(rect.x + static_cast(header_w)-essence_->scroll.offset_x, rect.y), + size(static_cast(rect.width) + essence_->scroll.offset_x - static_cast(header_w), rect.height) }, + true); es_lister & lister = essence_->lister; //The Tracker indicates the item where mouse placed. @@ -2739,12 +2741,12 @@ namespace nana auto state = item_state::normal; - //Here draws a root categ or a first drawing is not a categ. + //Here we draw the root categ (0) or a first item if the first drawing is not a categ.(item!=npos)) if(idx.cat == 0 || !idx.is_category()) { - if (idx.cat == 0 && idx.is_category()) + if (idx.cat == 0 && idx.is_category()) // the 0 cat { - essence_->scroll.offset_y_dpl.item = 0; + essence_->scroll.offset_y_dpl.item = 0; // no, we draw the first item of cat 0, not the 0 cat itself idx.item = 0; } @@ -2837,7 +2839,7 @@ namespace nana void _m_draw_item(const item_t& item, int x, int y, int txtoff, unsigned width, const nana::rectangle& r, const std::vector& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const { - if (item.flags.selected) + if (item.flags.selected) // fetch the "def" colors bgcolor = essence_->scheme_ptr->item_selected; else if (!item.bgcolor.invisible()) bgcolor = item.bgcolor; @@ -2846,10 +2848,10 @@ namespace nana fgcolor = item.fgcolor; auto graph = essence_->graph; - if (item_state::highlighted == state) + if (item_state::highlighted == state) // and blend it if "highlighted" { if (item.flags.selected) - bgcolor = bgcolor.blend(colors::black, 0.98); + bgcolor = bgcolor.blend(colors::black, 0.98); // or "selected" else bgcolor = bgcolor.blend(essence_->scheme_ptr->item_selected, 0.7); } @@ -2865,20 +2867,22 @@ namespace nana unsigned extreme_text = x; bool first = true; - for(auto index : seqs) + + for(size_type display_order{0}; display_order < seqs.size(); ++display_order) // get the cell (column) index in the order headers are displayed { - const auto & header = essence_->header.column(index); + auto index = seqs[display_order]; + const auto & header = essence_->header.column(index); // deduce the corresponding header which is in a kind of dislay order auto it_bgcolor = bgcolor; - if ((item.cells.size() > index) && (header.pixels > 5)) + if ((item.cells.size() > index) && (header.pixels > 5)) // process only if the cell is visible { auto cell_txtcolor = fgcolor; auto & m_cell = item.cells[index]; - nana::size ts = graph->text_extent_size(m_cell.text); + nana::size ts = graph->text_extent_size(m_cell.text); // precalcule text geometry - if (m_cell.custom_format && (!m_cell.custom_format->bgcolor.invisible())) + if (m_cell.custom_format && (!m_cell.custom_format->bgcolor.invisible())) // adapt to costum format if need { - it_bgcolor = m_cell.custom_format->bgcolor; + it_bgcolor = m_cell.custom_format->bgcolor; if (item.flags.selected) it_bgcolor = it_bgcolor.blend( bgcolor , 0.5) ; if (item_state::highlighted == state) @@ -2891,7 +2895,7 @@ namespace nana } int ext_w = 5; - if(first && essence_->checkable) + if(first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?) { ext_w += 18; @@ -2913,7 +2917,7 @@ namespace nana crook_renderer_.draw(*graph, bgcolor, fgcolor, essence_->checkarea(item_xpos, y), estate); } - if ((0 == index) && essence_->if_image) + if ((0 == index) && essence_->if_image) // draw the image if need, ??only before the first column?? (display_order=0 ?) { if (item.img) { @@ -2926,23 +2930,24 @@ namespace nana } graph->set_text_color(cell_txtcolor); - graph->string(point{ item_xpos + ext_w, y + txtoff }, m_cell.text); + graph->string(point{ item_xpos + ext_w, y + txtoff }, m_cell.text); // draw full text of the cell index (column) - if (ts.width + ext_w > header.pixels) + if (ts.width + ext_w > header.pixels) // it was an excess { - //The text is painted over the next subitem - int xpos = item_xpos + header.pixels - essence_->suspension_width; + //The text is painted over the next subitem // here beging the ... + int xpos = item_xpos + static_cast(header.pixels) - static_cast(essence_->suspension_width); - graph->set_color(it_bgcolor); - graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true); + graph->set_color(it_bgcolor); // litter rect with the item bg end ... + graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true); graph->set_text_color(cell_txtcolor); graph->string(point{ xpos, y + 2 }, STR("...")); //Erase the part that over the next subitem. - if (index + 1 < seqs.size()) + if ( display_order + 1 < seqs.size() ) // this is not the last column { - graph->set_color(bgcolor); - graph->rectangle(rectangle{item_xpos + static_cast(header.pixels), y + 2, ts.width + ext_w - header.pixels, essence_->item_size - 4}, true); + graph->set_color(bgcolor); // we need to erase the excess, because some cell may not draw text over + graph->rectangle(rectangle{item_xpos + static_cast(header.pixels), y + 2, + ts.width + ext_w - header.pixels, essence_->item_size - 4}, true); } extreme_text = std::max (extreme_text, item_xpos + ext_w + ts.width); } @@ -2951,7 +2956,7 @@ namespace nana graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, { 0xEB, 0xF4, 0xF9 }); item_xpos += header.pixels; - if (index + 1 >= seqs.size() && static_cast(extreme_text) > item_xpos) + if (display_order + 1 >= seqs.size() && static_cast(extreme_text) > item_xpos) { graph->set_color(item.bgcolor); graph->rectangle(rectangle{item_xpos , y + 2, extreme_text - item_xpos, essence_->item_size - 4}, true); From a64354900c5cac752beedb698751d5dc65f7693d Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 1 May 2015 16:29:51 +0800 Subject: [PATCH 73/77] fix a crash that caused by double-delete of a event handler --- include/nana/gui/detail/basic_window.hpp | 1 - include/nana/gui/detail/general_events.hpp | 113 ++++++++++++--------- include/nana/gui/detail/handle_manager.hpp | 12 ++- source/gui/detail/basic_window.cpp | 6 +- source/gui/detail/bedrock_pi.cpp | 46 +++++---- source/gui/detail/linux_X11/bedrock.cpp | 16 +-- source/gui/detail/win32/bedrock.cpp | 31 ++++-- source/gui/detail/window_manager.cpp | 15 +-- source/gui/timer.cpp | 6 +- 9 files changed, 144 insertions(+), 102 deletions(-) diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index 8016836c..659f4316 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -176,7 +176,6 @@ namespace detail { caret_descriptor* caret; std::shared_ptr events_ptr; - general_events* attached_events; }together; widget_colors* scheme{ nullptr }; diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 18c20ee5..1a4bf972 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -19,7 +19,6 @@ #include #include #include -#include namespace nana { @@ -63,14 +62,14 @@ namespace nana class basic_event : public detail::event_interface { public: - typedef const typename std::remove_reference::type & arg_reference; + using arg_reference = const typename std::remove_reference::type &; private: struct docker : public detail::docker_interface { basic_event * const event_ptr; std::function invoke; - bool flag_entered{ false }; + bool flag_deleted{ false }; bool unignorable{false}; @@ -92,6 +91,36 @@ namespace nana return event_ptr; } }; + + //class emit_counter is a RAII helper for emitting count + //It is used for avoiding a try{}catch block which is required for some finial works when + //event handlers throw exceptions. + class emit_counter + { + public: + emit_counter(basic_event* evt) + : evt_{evt} + { + ++evt->emitting_count_; + } + + ~emit_counter() + { + if ((0 == --evt_->emitting_count_) && evt_->deleted_flags_) + { + evt_->deleted_flags_ = false; + for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();) + { + if (i->get()->flag_deleted) + i = evt_->dockers_->erase(i); + else + ++i; + } + } + } + private: + basic_event * const evt_; + }; public: /// It will get called firstly, because it is set at the beginning of the chain. template @@ -164,54 +193,37 @@ namespace nana return (nullptr == dockers_ ? 0 : dockers_->size()); } - void emit(arg_reference& arg) const + void emit(arg_reference& arg) { internal_scope_guard lock; if (nullptr == dockers_) return; - //Make a copy to allow create/destroy a new event handler when the call of emit in an event. - const std::size_t fixed_size = 10; - docker* fixed_buffer[fixed_size]; - docker** transitory = fixed_buffer; + emit_counter ec(this); - std::unique_ptr variable_buffer; auto& dockers = *dockers_; - if (dockers.size() > fixed_size) - { - variable_buffer.reset(new docker*[dockers.size()]); - transitory = variable_buffer.get(); - } + const auto dockers_len = dockers.size(); - auto output = transitory; - for (auto & dck : dockers) + //The dockers may resize when a new event handler is created by a calling handler. + //Traverses with position can avaid crash error which caused by a iterator which becomes invalid. + for (std::size_t pos = 0; pos < dockers_len; ++pos) { - (*output++) = dck.get(); - } - - bool stop_propagation = false; - for (; transitory != output; ++transitory) - { - auto docker_ptr = *transitory; - if (stop_propagation && !docker_ptr->unignorable) + auto docker_ptr = dockers[pos].get(); + if (docker_ptr->flag_deleted) continue; - auto i = std::find_if(dockers.begin(), dockers.end(), [docker_ptr](std::unique_ptr& p){ - return (docker_ptr == p.get()); - }); - - if (i != dockers.end()) + docker_ptr->invoke(arg); + if (arg.propagation_stopped()) { - docker_ptr->flag_entered = true; - docker_ptr->invoke(arg); + for (++pos; pos < dockers_len; ++pos) + { + auto docker_ptr = dockers[pos].get(); + if (!docker_ptr->unignorable || docker_ptr->flag_deleted) + continue; - if (arg.propagation_stopped()) - stop_propagation = true; - - docker_ptr->flag_entered = false; - - if (docker_ptr->flag_deleted) - dockers.erase(i); + docker_ptr->invoke(arg); + } + break; } } } @@ -228,17 +240,20 @@ namespace nana internal_scope_guard lock; if (dockers_) { - auto i = std::find_if(dockers_->begin(), dockers_->end(), [evt](const std::unique_ptr& sp) + for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) { - return (reinterpret_cast(evt) == sp.get()); - }); - - if (i != dockers_->end()) - { - if (i->get()->flag_entered) - i->get()->flag_deleted = true; - else - dockers_->erase(i); + if (reinterpret_cast(evt) == i->get()) + { + //Checks whether this event is working now. + if (emitting_count_ > 1) + { + i->get()->flag_deleted = true; + deleted_flags_ = true; + } + else + dockers_->erase(i); + break; + } } } } @@ -399,6 +414,8 @@ namespace nana } }; private: + unsigned emitting_count_{ 0 }; + bool deleted_flags_{ false }; std::unique_ptr>> dockers_; }; diff --git a/include/nana/gui/detail/handle_manager.hpp b/include/nana/gui/detail/handle_manager.hpp index 33bb97a6..91ac70f1 100644 --- a/include/nana/gui/detail/handle_manager.hpp +++ b/include/nana/gui/detail/handle_manager.hpp @@ -25,7 +25,6 @@ #include #include -#include namespace nana { @@ -260,9 +259,14 @@ namespace nana { if(cond_type::is_queue(handle)) { - auto i = std::find(queue.begin(), queue.end(), handle); - if(i != queue.end()) - queue.erase(i); + for (auto i = queue.begin(); i != queue.end(); ++i) + { + if (handle == *i) + { + queue.erase(i); + break; + } + } } } }; diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 4cb500bf..96aec1fa 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -356,7 +356,6 @@ namespace nana effect.bground_fade_rate = 0; together.caret = nullptr; - together.attached_events = nullptr; extra_width = extra_height = 0; @@ -369,16 +368,15 @@ namespace nana bool basic_window::set_events(const std::shared_ptr& p) { - if (together.attached_events) + if (together.events_ptr) return false; together.events_ptr = p; - together.attached_events = p.get(); return true; } general_events * basic_window::get_events() const { - return together.attached_events; + return together.events_ptr.get(); } //end struct basic_window }//end namespace detail diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index be824a0b..76db85ac 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -146,6 +146,9 @@ namespace nana void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg) { + auto retain = wd->together.events_ptr; + auto evts_ptr = retain.get(); + switch (evt_code) { case event_code::click: @@ -162,35 +165,36 @@ namespace nana void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&); ::nana::basic_event* evt_addr; + switch (evt_code) { case event_code::click: drawer_event_fn = &drawer::click; - evt_addr = &wd->together.attached_events->click; + evt_addr = &evts_ptr->click; break; case event_code::dbl_click: drawer_event_fn = &drawer::dbl_click; - evt_addr = &wd->together.attached_events->dbl_click; + evt_addr = &evts_ptr->dbl_click; break; case event_code::mouse_enter: drawer_event_fn = &drawer::mouse_enter; - evt_addr = &wd->together.attached_events->mouse_enter; + evt_addr = &evts_ptr->mouse_enter; break; case event_code::mouse_move: drawer_event_fn = &drawer::mouse_move; - evt_addr = &wd->together.attached_events->mouse_move; + evt_addr = &evts_ptr->mouse_move; break; case event_code::mouse_leave: drawer_event_fn = &drawer::mouse_leave; - evt_addr = &wd->together.attached_events->mouse_leave; + evt_addr = &evts_ptr->mouse_leave; break; case event_code::mouse_down: drawer_event_fn = &drawer::mouse_down; - evt_addr = &wd->together.attached_events->mouse_down; + evt_addr = &evts_ptr->mouse_down; break; case event_code::mouse_up: drawer_event_fn = &drawer::mouse_up; - evt_addr = &wd->together.attached_events->mouse_up; + evt_addr = &evts_ptr->mouse_up; break; default: throw std::runtime_error("Invalid mouse event code"); @@ -209,7 +213,7 @@ namespace nana { wd->drawer.mouse_wheel(*arg); if (!draw_only) - wd->together.attached_events->mouse_wheel.emit(*arg); + evts_ptr->mouse_wheel.emit(*arg); } break; } @@ -229,19 +233,19 @@ namespace nana { case event_code::key_press: drawer_event_fn = &drawer::key_press; - evt_addr = &wd->together.attached_events->key_press; + evt_addr = &evts_ptr->key_press; break; case event_code::key_char: drawer_event_fn = &drawer::key_char; - evt_addr = &wd->together.attached_events->key_char; + evt_addr = &evts_ptr->key_char; break; case event_code::key_release: drawer_event_fn = &drawer::key_release; - evt_addr = &wd->together.attached_events->key_release; + evt_addr = &evts_ptr->key_release; break; case event_code::shortkey: drawer_event_fn = &drawer::shortkey; - evt_addr = &wd->together.attached_events->shortkey; + evt_addr = &evts_ptr->shortkey; break; default: throw std::runtime_error("Invalid keyboard event code"); @@ -256,7 +260,7 @@ namespace nana { auto arg = dynamic_cast(&event_arg); if (arg) - wd->together.attached_events->expose.emit(*arg); + evts_ptr->expose.emit(*arg); } break; case event_code::focus: @@ -266,7 +270,7 @@ namespace nana { wd->drawer.focus(*arg); if (!draw_only) - wd->together.attached_events->focus.emit(*arg); + evts_ptr->focus.emit(*arg); } break; } @@ -277,7 +281,7 @@ namespace nana { wd->drawer.move(*arg); if (!draw_only) - wd->together.attached_events->move.emit(*arg); + evts_ptr->move.emit(*arg); } break; } @@ -288,7 +292,7 @@ namespace nana { wd->drawer.resizing(*arg); if (!draw_only) - wd->together.attached_events->resizing.emit(*arg); + evts_ptr->resizing.emit(*arg); } break; } @@ -299,7 +303,7 @@ namespace nana { wd->drawer.resized(*arg); if (!draw_only) - wd->together.attached_events->resized.emit(*arg); + evts_ptr->resized.emit(*arg); } break; } @@ -309,9 +313,9 @@ namespace nana auto arg = dynamic_cast(&event_arg); if (arg && (wd->other.category == category::flags::root)) { - auto evt_ptr = dynamic_cast(wd->together.attached_events); - if (evt_ptr) - evt_ptr->unload.emit(*arg); + auto evt_root = dynamic_cast(evts_ptr); + if (evt_root) + evt_root->unload.emit(*arg); } } break; @@ -320,7 +324,7 @@ namespace nana { auto arg = dynamic_cast(&event_arg); if (arg) - wd->together.attached_events->destroy.emit(*arg); + evts_ptr->destroy.emit(*arg); } break; default: diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 1add84a6..2e40cc10 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -583,7 +583,7 @@ namespace detail 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->together.attached_events->mouse_dropfiles.emit(arg); + msgwd->together.events_ptr->mouse_dropfiles.emit(arg); brock.wd_manager.do_lazy_refresh(msgwd, false); } break; @@ -766,7 +766,7 @@ namespace detail nana::point mspos{xevent.xbutton.x, xevent.xbutton.y}; while(msgwnd) { - if(msgwnd->together.attached_events->mouse_wheel.length() != 0) + if(msgwnd->together.events_ptr->mouse_wheel.length() != 0) { mspos -= msgwnd->pos_root; arg_wheel arg; @@ -810,27 +810,29 @@ namespace detail { if(hit) msgwnd->flags.action = mouse_action::over; + + auto retain = msgwnd->together.events_ptr; + auto evt_ptr = retain.get(); - auto events_ptr = msgwnd->together.events_ptr; arg.evt_code = event_code::mouse_up; emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); if(fire_click) { arg.evt_code = event_code::click; - msgwnd->together.attached_events->click.emit(arg); + evt_ptr->click.emit(arg); } if (brock.wd_manager.available(msgwnd)) { arg.evt_code = event_code::mouse_up; - msgwnd->together.attached_events->mouse_up.emit(arg); + evt_ptr->mouse_up.emit(arg); } } else if(fire_click) { arg.evt_code = event_code::click; - msgwnd->together.attached_events->click.emit(arg); + msgwnd->together.events_ptr->click.emit(arg); } brock.wd_manager.do_lazy_refresh(msgwnd, false); } @@ -1103,7 +1105,7 @@ namespace detail arg.window_handle = reinterpret_cast(msgwnd); brock.get_key_state(arg); - msgwnd->together.attached_events->key_char.emit(arg); + msgwnd->together.events_ptr->key_char.emit(arg); if(arg.ignore == false && brock.wd_manager.available(msgwnd)) brock.emit_drawer(event_code::key_char, msgwnd, arg, &context); } diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index f0c7eb1c..58c4eb6e 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -663,6 +663,7 @@ namespace detail case WM_SETFOCUS: case WM_KILLFOCUS: case WM_PAINT: + case WM_SYSCOMMAND: case WM_CLOSE: case WM_MOUSEACTIVATE: case WM_GETMINMAXINFO: @@ -851,7 +852,7 @@ namespace detail case WM_WINDOWPOSCHANGED: if ((reinterpret_cast(lParam)->flags & SWP_SHOWWINDOW) && (!msgwnd->visible)) brock.event_expose(msgwnd, true); - else if((reinterpret_cast(lParam)->flags & SWP_HIDEWINDOW) && msgwnd->visible) + else if ((reinterpret_cast(lParam)->flags & SWP_HIDEWINDOW) && msgwnd->visible) brock.event_expose(msgwnd, false); def_window_proc = true; @@ -871,6 +872,7 @@ namespace detail if (!brock.emit(event_code::focus, focus, arg, true, &context)) brock.wd_manager.set_focus(msgwnd, true); } + def_window_proc = true; break; case WM_KILLFOCUS: if(msgwnd->other.attribute.root->focus) @@ -891,10 +893,14 @@ namespace detail //focus_changed means that during an event procedure if the focus is changed if(brock.wd_manager.available(msgwnd)) msgwnd->root_widget->other.attribute.root->context.focus_changed = true; + + def_window_proc = true; break; case WM_MOUSEACTIVATE: if(msgwnd->flags.take_active == false) return MA_NOACTIVATE; + + def_window_proc = true; break; case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: pressed_wd = nullptr; @@ -1011,19 +1017,19 @@ namespace detail if (fire_click) { arg.evt_code = event_code::click; - msgwnd->together.attached_events->click.emit(arg); + retain->click.emit(arg); } if (brock.wd_manager.available(msgwnd)) { arg.evt_code = event_code::mouse_up; - msgwnd->together.attached_events->mouse_up.emit(arg); + retain->mouse_up.emit(arg); } } else if (fire_click) { arg.evt_code = event_code::click; - msgwnd->together.attached_events->click.emit(arg); + retain->click.emit(arg); } brock.wd_manager.do_lazy_refresh(msgwnd, false); } @@ -1114,7 +1120,7 @@ namespace detail auto evt_wd = scrolled_wd; while (evt_wd) { - if (evt_wd->together.attached_events->mouse_wheel.length() != 0) + if (evt_wd->together.events_ptr->mouse_wheel.length() != 0) { def_window_proc = false; nana::point mspos{ scr_pos.x, scr_pos.y }; @@ -1189,7 +1195,7 @@ namespace detail brock.wd_manager.calc_window_point(msgwnd, dropfiles.pos); dropfiles.window_handle = reinterpret_cast(msgwnd); - msgwnd->together.attached_events->mouse_dropfiles.emit(dropfiles); + msgwnd->together.events_ptr->mouse_dropfiles.emit(dropfiles); brock.wd_manager.do_lazy_refresh(msgwnd, false); } } @@ -1419,7 +1425,7 @@ namespace detail brock.get_key_state(arg); arg.ignore = false; - msgwnd->together.attached_events->key_char.emit(arg); + msgwnd->together.events_ptr->key_char.emit(arg); if ((false == arg.ignore) && brock.wd_manager.available(msgwnd)) brock.emit_drawer(event_code::key_char, msgwnd, arg, &context); @@ -1449,6 +1455,14 @@ namespace detail brock.delay_restore(2); //Restores while key release break; + case WM_SYSCOMMAND: + if (SC_TASKLIST == wParam) + { + int debug = 0; + //brock.close_menu_if_focus_other_window() + } + def_window_proc = true; + break; case WM_CLOSE: { arg_unload arg; @@ -1537,7 +1551,8 @@ namespace detail impl_->menu.taken_window = wd; //assigning of a nullptr taken window is to restore the focus of pre taken - if ((!wd) && pre) + //don't restore the focus if pre is a menu. + if ((!wd) && pre && (pre->root != get_menu())) { internal_scope_guard lock; wd_manager.set_focus(pre, false); diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 93186a57..e78da759 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -21,7 +21,6 @@ #include #include #include -#include namespace nana { @@ -192,7 +191,7 @@ namespace detail switch(evtid) { case event_code::mouse_drop: - wd->flags.dropable = (is_make || (0 != wd->together.attached_events->mouse_dropfiles.length())); + wd->flags.dropable = (is_make || (0 != wd->together.events_ptr->mouse_dropfiles.length())); break; default: break; @@ -985,11 +984,15 @@ namespace detail } else { - auto i = std::find_if(attr_cap.begin(), attr_cap.end(), - [wd](const std::pair & x){ return (x.first == wd);}); + for (auto i = attr_cap.begin(), end = attr_cap.end(); i != end; ++i) + { + if (i->first == wd) + { + attr_cap.erase(i); + break; + } + } - if(i != attr_cap.end()) - attr_cap.erase(i); return attr_.capture.window; } return wd; diff --git a/source/gui/timer.cpp b/source/gui/timer.cpp index dc4d53a2..75181a7f 100644 --- a/source/gui/timer.cpp +++ b/source/gui/timer.cpp @@ -109,11 +109,11 @@ namespace nana { public: #if defined(NANA_WINDOWS) - timer_core(timer_identifier tmid, const nana::basic_event& evt_elapse) + timer_core(timer_identifier tmid, basic_event& evt_elapse) : timer_(tmid), evt_elapse_(evt_elapse) {} #else - timer_core(const nana::basic_event& evt_elapse) + timer_core(basic_event& evt_elapse) : timer_(this), evt_elapse_(evt_elapse) {} #endif @@ -138,7 +138,7 @@ namespace nana } private: const timer_identifier timer_; - const nana::basic_event & evt_elapse_; + nana::basic_event & evt_elapse_; }; //end class timer_core #if defined(NANA_WINDOWS) From 4154c8e132046b117f1dfc7aa095fedc3b0bf31c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 1 May 2015 16:36:12 +0800 Subject: [PATCH 74/77] rename API::is_focus_window to API::is_focus_ready --- include/nana/gui/programming_interface.hpp | 2 +- source/gui/programming_interface.cpp | 2 +- source/gui/widgets/skeletons/text_editor.cpp | 13 +++++++------ source/gui/widgets/spinbox.cpp | 5 +++-- source/gui/widgets/textbox.cpp | 2 +- source/gui/widgets/widget.cpp | 2 +- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 09bb1c84..c2430ccd 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -239,7 +239,7 @@ namespace API cursor window_cursor(window); void activate_window(window); - bool is_focus_window(window); + bool is_focus_ready(window); window focus_window(); void focus_window(window); diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index c2db60b8..f9409904 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -796,7 +796,7 @@ namespace API return cursor::arrow; } - bool is_focus_window(window wd) + bool is_focus_ready(window wd) { auto iwd = reinterpret_cast(wd); internal_scope_guard lock; diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index eceda23e..0a2f9261 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace nana{ namespace widgets { @@ -688,7 +689,7 @@ namespace nana{ namespace widgets } } else - editor_.render(API::is_focus_window(editor_.window_)); + editor_.render(API::is_focus_ready(editor_.window_)); } void render(const ::nana::color& fgcolor) override @@ -1447,7 +1448,7 @@ namespace nana{ namespace widgets move_caret(upoint{}); _m_scrollbar(); - render(API::is_focus_window(window_)); + render(API::is_focus_ready(window_)); return true; } return false; @@ -1465,7 +1466,7 @@ namespace nana{ namespace widgets _m_reset(); behavior_->pre_calc_lines(width_pixels()); - render(API::is_focus_window(window_)); + render(API::is_focus_ready(window_)); _m_scrollbar(); return true; } @@ -1716,7 +1717,7 @@ namespace nana{ namespace widgets //Set caret position through text coordinate void text_editor::move_caret(const upoint& crtpos) { - if (!API::is_focus_window(window_)) + if (!API::is_focus_ready(window_)) return; const unsigned line_pixels = line_height(); @@ -1758,7 +1759,7 @@ namespace nana{ namespace widgets void text_editor::show_caret(bool isshow) { - if(isshow == false || API::is_focus_window(window_)) + if(isshow == false || API::is_focus_ready(window_)) API::caret_visible(window_, isshow); } @@ -1923,7 +1924,7 @@ namespace nana{ namespace widgets { behavior_->adjust_caret_into_screen(); reset_caret(); - render(API::is_focus_window(window_)); + render(API::is_focus_ready(window_)); _m_scrollbar(); points_.xpos = points_.caret.x; diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index ebbf006e..6be8deb2 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace nana { @@ -328,7 +329,7 @@ namespace nana void render() { - editor_->render(API::is_focus_window(editor_->window_handle())); + editor_->render(API::is_focus_ready(editor_->window_handle())); _m_draw_spins(spin_stated_); } @@ -420,7 +421,7 @@ namespace nana if (!editor_) return; - if (API::is_focus_window(editor_->window_handle())) + if (API::is_focus_ready(editor_->window_handle())) editor_->text(range_->value()); else editor_->text(modifier_.prefix + range_->value() + modifier_.suffix); diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 840a1762..4bb6a670 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -83,7 +83,7 @@ namespace drawerbase { void drawer::refresh(graph_reference graph) { - editor_->render(API::is_focus_window(*widget_)); + editor_->render(API::is_focus_ready(*widget_)); } void drawer::focus(graph_reference graph, const arg_focus& arg) diff --git a/source/gui/widgets/widget.cpp b/source/gui/widgets/widget.cpp index f573c6b6..07e81946 100644 --- a/source/gui/widgets/widget.cpp +++ b/source/gui/widgets/widget.cpp @@ -101,7 +101,7 @@ namespace nana bool widget::focused() const { - return API::is_focus_window(handle()); + return (API::focus_window() == handle()); } void widget::show() From 99564a91616abf5c2545db249da240829d55d24c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 1 May 2015 16:45:05 +0800 Subject: [PATCH 75/77] refactor functions --- .../nana/gui/detail/inner_fwd_implement.hpp | 16 +- include/nana/gui/widgets/menu.hpp | 21 +- source/gui/detail/drawer.cpp | 15 +- source/gui/detail/native_window_interface.cpp | 1 + source/gui/place.cpp | 3 +- source/gui/programming_interface.cpp | 17 +- source/gui/widgets/menu.cpp | 448 ++++++++---------- 7 files changed, 253 insertions(+), 268 deletions(-) diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/include/nana/gui/detail/inner_fwd_implement.hpp index 9e782092..5384aec4 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/include/nana/gui/detail/inner_fwd_implement.hpp @@ -1,7 +1,7 @@ /* * Implementations of Inner Forward Declaration * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -19,7 +19,6 @@ #include "../../paint/graphics.hpp" #include -#include namespace nana{ namespace detail @@ -62,12 +61,15 @@ namespace nana{ void umake(window wd) { if (wd == nullptr) return; - auto i = std::find_if(keybase_.begin(), keybase_.end(), [wd](const item_type& m){ - return (m.handle == wd); - }); - if (i != keybase_.end()) - keybase_.erase(i); + for (auto i = keybase_.begin(), end = keybase_.end(); i != end; ++i) + { + if (i->handle == wd) + { + keybase_.erase(i); + break; + } + } } std::vector keys(window wd) const diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp index 03e61c9d..883760cf 100644 --- a/include/nana/gui/widgets/menu.hpp +++ b/include/nana/gui/widgets/menu.hpp @@ -139,16 +139,16 @@ namespace nana void clear(); ///< Erases all of the items. /// Closes the menu. It does not destroy the menu; just close the window for the menu. void close(); - void image(std::size_t index, const paint::image& icon); - void check_style(std::size_t index, checks); - void checked(std::size_t index, bool); - bool checked(std::size_t index) const; - void enabled(std::size_t index, bool);///< Enables or disables the mouse or keyboard input for the item. - bool enabled(std::size_t index) const; - void erase(std::size_t index); ///< Removes the item - bool link(std::size_t index, menu& menu_obj);///< Link a menu to the item as a sub menu. - menu * link(std::size_t index); ///< Retrieves a linked sub menu of the item. - menu *create_sub_menu(std::size_t index); + void image(std::size_t pos, const paint::image& icon); + void check_style(std::size_t pos, checks); + void checked(std::size_t pos, bool); + bool checked(std::size_t pos) const; + void enabled(std::size_t pos, bool);///< Enables or disables the mouse or keyboard input for the item. + bool enabled(std::size_t pos) const; + void erase(std::size_t pos); ///< Removes the item + bool link(std::size_t pos, menu& menu_obj);///< Link a menu to the item as a sub menu. + menu * link(std::size_t pos); ///< Retrieves a linked sub menu of the item. + menu *create_sub_menu(std::size_t pos); void popup(window owner, int x, int y); ///< Popup the menu at the owner window. void popup_await(window owner, int x, int y); void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item. @@ -171,7 +171,6 @@ namespace nana const pat::cloneable& renderer() const; private: - void _m_destroy_menu_window(); void _m_popup(window, int x, int y, bool called_by_menubar); private: implement * impl_; diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 7270aa7a..3b9702a3 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -21,8 +21,6 @@ #include #endif -#include - namespace nana { typedef detail::edge_nimbus_renderer edge_nimbus_renderer_t; @@ -351,12 +349,13 @@ namespace nana { if(p) { - auto i = std::find(dynamic_drawing_objects_.begin(), dynamic_drawing_objects_.end(), p); - if (i != dynamic_drawing_objects_.end()) - { - delete (*i); - dynamic_drawing_objects_.erase(i); - } + for (auto i = dynamic_drawing_objects_.begin(); i != dynamic_drawing_objects_.end(); ++i) + if (*i == p) + { + delete (*i); + dynamic_drawing_objects_.erase(i); + break; + } } } diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index a01d80b8..0101a804 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -556,6 +556,7 @@ namespace nana{ { ::EnableWindow(native_wd, true); ::SetActiveWindow(native_wd); + ::SetForegroundWindow(native_wd); } else ::PostMessage(native_wd, nana::detail::messages::async_activate, 0, 0); diff --git a/source/gui/place.cpp b/source/gui/place.cpp index c643993a..d42b6b2c 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -1,7 +1,7 @@ /** * An Implementation of Place for Layout * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -21,6 +21,7 @@ #include #include +#include namespace nana { diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index f9409904..2d27a9a3 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -16,7 +16,6 @@ #include #include #include -#include namespace nana { @@ -54,7 +53,7 @@ namespace API if (!restrict::window_manager.available(reinterpret_cast(wd))) return nullptr; - return reinterpret_cast(wd)->together.attached_events; + return reinterpret_cast(wd)->together.events_ptr.get(); } }//end namespace detail @@ -265,8 +264,20 @@ namespace API if((wd->thread_id == tid) && (wd->root != root)) { root = wd->root; - if(roots.cend() == std::find(roots.cbegin(), roots.cend(), root)) + for (auto i = roots.cbegin(); i != roots.cend(); ++i) + { + if (*i == root) + { + root = nullptr; + break; + } + } + + if (!root) + { + root = wd->root; roots.push_back(root); + } } } diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index c8c8fa03..9f6ec24c 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -106,7 +106,7 @@ namespace nana sz.width -= 30; sz.height -= 2; graph.rectangle(false, colors::gray_border); - graph.rectangle({ 1, 1, 28, sz.height }, true, { 0xf6, 0xf6, 0xf6 }); + graph.rectangle({ 1, 1, 28, sz.height }, true, static_cast(0xf6f6f6)); graph.rectangle({ 29, 1, sz.width, sz.height }, true, colors::white); } @@ -122,17 +122,17 @@ namespace nana nana::point(r.x + r.width - 1, r.y + r.height - 1) }; - graph.set_color({0xc0, 0xdd, 0xfc}); + graph.set_color(static_cast(0xc0ddfc)); for(int i = 0; i < 4; ++i) graph.set_pixel(points[i].x, points[i].y); if(at.enabled) - graph.gradual_rectangle(nana::rectangle(r).pare_off(1), { 0xE8, 0xF0, 0xF4 }, { 0xDB,0xEC,0xF4 }, true); + graph.gradual_rectangle(nana::rectangle(r).pare_off(1), static_cast(0xE8F0F4), static_cast(0xDBECF4), true); } if(at.checked && (checks::none != at.check_style)) { - graph.rectangle(r, false, { 0xCD, 0xD3, 0xE6 }); + graph.rectangle(r, false, static_cast(0xCDD3E6)); ::nana::color clr(0xE6, 0xEF, 0xF4); graph.rectangle(nana::rectangle(r).pare_off(1), true, clr); @@ -363,59 +363,58 @@ namespace nana bool goto_next(bool forword) { state_.nullify_mouse = true; - if(menu_->items.size()) - { - std::size_t index = state_.active; + if (menu_->items.empty()) + return false; - bool end = false; - while(true) + auto pos = state_.active; + const auto lastpos = menu_->items.size() - 1; + + bool end = false; + while(true) + { + if(forword) { - if(forword) + if(pos == lastpos) { - if(index == menu_->items.size() - 1) + if (end) { - if(end == false) - { - end = true; - index = 0; - } - else - { - index = npos; - break; - } + pos = npos; + break; } - else - ++index; + + end = true; + pos = 0; } else - { - if(index == 0 || index == npos) - { - if(end == false) - { - end = true; - index = menu_->items.size() - 1; - } - else - break; - } - else - --index; - } - if(menu_->items.at(index).flags.splitter == false) - break; + ++pos; } - - if(index != npos && index != state_.active) + else { - state_.active = index; - state_.sub_window = false; - - draw(); - return true; + if(pos == 0 || pos == npos) + { + if (end) + break; + + end = true; + pos = lastpos; + } + else + --pos; } + + if(! menu_->items.at(pos).flags.splitter) + break; } + + if(pos != npos && pos != state_.active) + { + state_.active = pos; + state_.sub_window = false; + + draw(); + return true; + } + return false; } @@ -486,30 +485,32 @@ namespace nana std::size_t index = 0; for(auto & m : menu_->items) { - if(std::tolower(m.hotkey) == key) + if (std::tolower(m.hotkey) != key) { - if(!m.flags.splitter) - { - if(m.sub_menu) - { - state_.active = index; - state_.active_timestamp = nana::system::timestamp(); - - draw(); - API::update_window(*widget_); - return 2; - } - else if(m.flags.enabled) - { - std::move(fn_close_tree_)(); - item_proxy ip(index, m); - m.functor.operator()(ip); - return 1; - } - } - break; + ++index; + continue; } - ++index; + + if(!m.flags.splitter) + { + if(m.sub_menu) + { + state_.active = index; + state_.active_timestamp = nana::system::timestamp(); + + draw(); + API::update_window(*widget_); + return 2; + } + else if(m.flags.enabled) + { + std::move(fn_close_tree_)(); + item_proxy ip(index, m); + m.functor.operator()(ip); + return 1; + } + } + break; } return 0; } @@ -529,53 +530,53 @@ namespace nana int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2; - std::size_t index = 0; + std::size_t pos = 0; for(auto & m : menu_->items) { - if(false == m.flags.splitter) - { - renderer_interface::attr attr = _m_make_renderer_attr(index == state_.active, m); - //Draw item background - renderer->item(*graph_, item_r, attr); - - //Draw text, the text is transformed from orignal for hotkey character - nana::char_t hotkey; - nana::string::size_type hotkey_pos; - nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos); - - if(m.image.empty() == false) - renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image); - - renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr); - - if(hotkey) - { - m.hotkey = hotkey; - if(m.flags.enabled) - { - unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast(hotkey_pos)).width : 0); - nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1); - int x = item_r.x + 40 + off_w; - int y = item_r.y + text_top_off + hotkey_size.height; - - graph_->set_color(colors::black); - graph_->line({ x, y }, { x + static_cast(hotkey_size.width) - 1, y }); - } - } - - if(m.sub_menu) - renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr); - - item_r.y += item_r.height + 1; - } - else + if(m.flags.splitter) { graph_->set_color(colors::gray_border); graph_->line({ item_r.x + 40, item_r.y }, { static_cast(graph_->width()) - 1, item_r.y }); item_r.y += 2; + ++pos; + continue; + } + + renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m); + //Draw item background + renderer->item(*graph_, item_r, attr); + + //Draw text, the text is transformed from orignal for hotkey character + nana::char_t hotkey; + nana::string::size_type hotkey_pos; + nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos); + + if(m.image.empty() == false) + renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image); + + renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr); + + if(hotkey) + { + m.hotkey = hotkey; + if(m.flags.enabled) + { + unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast(hotkey_pos)).width : 0); + nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1); + int x = item_r.x + 40 + off_w; + int y = item_r.y + text_top_off + hotkey_size.height; + + graph_->set_color(colors::black); + graph_->line({ x, y }, { x + static_cast(hotkey_size.width) - 1, y }); + } } - ++index; + if(m.sub_menu) + renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr); + + item_r.y += item_r.height + 1; + + ++pos; } } private: @@ -592,9 +593,9 @@ namespace nana std::size_t _m_get_index_by_pos(int x, int y) const { if( (x < static_cast(detail_.border.x)) || - (x > static_cast(graph_->width() - detail_.border.x)) || + (x > static_cast(graph_->width()) - static_cast(detail_.border.x)) || (y < static_cast(detail_.border.y)) || - (y > static_cast(graph_->height() - detail_.border.y))) + (y > static_cast(graph_->height()) - static_cast(detail_.border.y))) return npos; int pos = detail_.border.y; @@ -662,11 +663,11 @@ namespace nana auto scr_area = screen().from_point(detail_.monitor_pos).workarea(); if(pos.x + static_cast(size.width) > scr_area.right()) - pos.x = static_cast(scr_area.x + scr_area.width - size.width); + pos.x = scr_area.right() - static_cast(size.width); if(pos.x < scr_area.x) pos.x = scr_area.x; if(pos.y + static_cast(size.height) > scr_area.bottom()) - pos.y = static_cast(scr_area.y + scr_area.height - size.height); + pos.y = scr_area.bottom() - static_cast(size.height); if(pos.y < scr_area.y) pos.y = scr_area.y; auto owner = API::get_owner_window(*widget_); @@ -705,7 +706,7 @@ namespace nana menu_window(window wd, const point& pos, renderer_interface * rdptr) : base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald()), - want_focus_(nullptr == wd), + want_focus_(nullptr == wd || (API::focus_window() != wd)), event_focus_(nullptr) { caption(STR("nana menu window")); @@ -729,11 +730,6 @@ namespace nana API::activate_window(this->parent()); API::take_active(this->handle(), false, nullptr); } - else - { - activate(); - focus(); - } if(submenu_.parent == nullptr) { @@ -753,14 +749,6 @@ namespace nana pick(); }); - if (want_focus_) - { - event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg) - { - _m_focus_changed(arg); - }); - } - timer_.interval(100); timer_.elapse([this]{ this->_m_check_repeatly(); @@ -768,6 +756,30 @@ namespace nana timer_.start(); show(); + + if (want_focus_) + { + event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg) + { + //when the focus of the menu window is losing, close the menu. + //But here is not every menu window may have focus event installed, + //It is only installed when the owner of window is the desktop window. + + if (false == arg.getting && (arg.receiver != API::root(*this))) + { + for (auto child = submenu_.child; child; child = child->submenu_.child) + { + if (API::root(child->handle()) == arg.receiver) + return; + } + + _m_close_all(); + } + }); + + focus(); + activate(); + } } void goto_next(bool forward) @@ -783,39 +795,33 @@ namespace nana API::update_window(object->handle()); } - bool goto_submenu() + bool submenu(bool enter) { menu_window * object = this; - while(object->submenu_.child) + while (object->submenu_.child) object = object->submenu_.child; state_.auto_popup_submenu = false; + if (enter) + { + if (object->submenu_.parent) + { + auto & sub = object->submenu_.parent->submenu_; + sub.child = nullptr; + sub.object = nullptr; + + object->close(); + return true; + } + return false; + } + nana::point pos; menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0); return object->_m_show_submenu(sbm, pos, true); } - bool exit_submenu() - { - menu_window * object =this; - while(object->submenu_.child) - object = object->submenu_.child; - - state_.auto_popup_submenu = false; - - if (object->submenu_.parent) - { - auto & sub = object->submenu_.parent->submenu_; - sub.child = nullptr; - sub.object = nullptr; - - object->close(); - return true; - } - return false; - } - int send_shortkey(nana::char_t key) { menu_window * object = this; @@ -832,62 +838,52 @@ namespace nana object = object->submenu_.child; auto active = object->get_drawer_trigger().active(); - if (active != npos) + auto * menu = object->get_drawer_trigger().data(); + if ((npos == active) || !menu) + return; + + menu_item_type & item = menu->items.at(active); + if (item.flags.splitter == false && item.sub_menu == nullptr) { - auto * menu = object->get_drawer_trigger().data(); - if (menu) + //There is a situation that menu will not call functor if the item style is check_option + //and it is checked before clicking. + bool call_functor = true; + + if (checks::highlight == item.style) { - menu_item_type & item = menu->items.at(active); - if (item.flags.splitter == false && item.sub_menu == nullptr) + item.flags.checked = !item.flags.checked; + } + else if (checks::option == item.style) + { + //Forward Looks for a splitter + auto pos = active; + while (pos) { - //There is a situation that menu will not call functor if the item style is check_option - //and it is checked before clicking. - bool call_functor = true; - - if (checks::highlight == item.style) - { - item.flags.checked = !item.flags.checked; - } - else if (checks::option == item.style) - { - if (active > 0) - { - //clear the checked state in front of active if it is check_option. - auto i = active; - do - { - --i; - menu_item_type & im = menu->items.at(i); - if (im.flags.splitter) break; - - if (checks::option == im.style && im.flags.checked) - im.flags.checked = false; - } while (i); - } - - for (auto i = active + 1; i < menu->items.size(); ++i) - { - menu_item_type & im = menu->items.at(i); - if (im.flags.splitter) break; - - if ((checks::option == im.style) && im.flags.checked) - im.flags.checked = false; - } - - item.flags.checked = true; - } - - this->_m_close_all(); //means deleting this; - //The deleting operation has moved here, because item.functor.operator()(ip) - //may create a window, which make a killing focus for menu window, if so the close_all - //operation preformences after item.functor.operator()(ip), that would be deleting this object twice! - - if (call_functor && item.flags.enabled && item.functor) - { - item_type::item_proxy ip(active, item); - item.functor.operator()(ip); - } + if (menu->items.at(--pos).flags.splitter) + break; } + + for (; pos < menu->items.size(); ++pos) + { + menu_item_type & im = menu->items.at(pos); + if (im.flags.splitter) break; + + if ((checks::option == im.style) && im.flags.checked) + im.flags.checked = false; + } + + item.flags.checked = true; + } + + this->_m_close_all(); //means deleting this; + //The deleting operation has moved here, because item.functor.operator()(ip) + //may create a window, which make a killing focus for menu window, if so the close_all + //operation preformences after item.functor.operator()(ip), that would be deleting this object twice! + + if (call_functor && item.flags.enabled && item.functor) + { + item_type::item_proxy ip(active, item); + item.functor.operator()(ip); } } } @@ -943,50 +939,29 @@ namespace nana } } - //when the focus of the menu window is losing, close the menu. - //But here is not every menu window may have focus event installed, - //It is only installed when the owner of window is the desktop window. - void _m_focus_changed(const arg_focus& arg) - { - if (false == arg.getting) - { - for (auto child = submenu_.child; child; child = child->submenu_.child) - { - if (API::root(child->handle()) == arg.receiver) - return; - } - - _m_close_all(); - } - } - void _m_key_down(const arg_keyboard& arg) { switch(arg.key) { case keyboard::os_arrow_up: - this->goto_next(false); - break; case keyboard::os_arrow_down: - this->goto_next(true); + this->goto_next(keyboard::os_arrow_down == arg.key); break; case keyboard::os_arrow_left: - this->exit_submenu(); - break; case keyboard::os_arrow_right: - this->goto_submenu(); + this->submenu(keyboard::os_arrow_right == arg.key); break; case keyboard::enter: this->pick(); break; default: - if(2 != send_shortkey(arg.key)) + if (2 != send_shortkey(arg.key)) { - if(API::empty_window(*this) == false) + if (API::empty_window(*this) == false) close(); } else - goto_submenu(); + this->submenu(true); } } @@ -1165,7 +1140,7 @@ namespace nana { if(impl_->mbuilder.set_sub_menu(index, menu_obj.impl_->mbuilder.data())) { - implement::info& minfo = impl_->sub_container[index]; + auto& minfo = impl_->sub_container[index]; minfo.handle = &menu_obj; minfo.kill = false; return true; @@ -1184,9 +1159,10 @@ namespace nana menu *menu::create_sub_menu(std::size_t index) { menu * sub = new menu; - if(link(index, *sub)) + + if (this->link(index, *sub)) { - implement::info& minfo = impl_->sub_container[index]; + auto& minfo = impl_->sub_container[index]; minfo.handle = sub; minfo.kill = true; return sub; @@ -1255,12 +1231,12 @@ namespace nana bool menu::goto_submen() { - return (impl_->uiobj ? impl_->uiobj->goto_submenu() : false); + return (impl_->uiobj ? impl_->uiobj->submenu(true) : false); } bool menu::exit_submenu() { - return (impl_->uiobj ? impl_->uiobj->exit_submenu() : false); + return (impl_->uiobj ? impl_->uiobj->submenu(false) : false); } std::size_t menu::size() const @@ -1311,21 +1287,17 @@ namespace nana impl_->mbuilder.renderer(rd); } - void menu::_m_destroy_menu_window() - { - impl_->uiobj = nullptr; - if(impl_->destroy_answer) - impl_->destroy_answer(); - } - void menu::_m_popup(window wd, int x, int y, bool called_by_menubar) { if (impl_->mbuilder.data().items.size()) { close(); + impl_->uiobj = &(form_loader()(wd, point(x, y), &(*impl_->mbuilder.renderer()))); impl_->uiobj->events().destroy.connect_unignorable([this]{ - _m_destroy_menu_window(); + impl_->uiobj = nullptr; + if (impl_->destroy_answer) + impl_->destroy_answer(); }); impl_->uiobj->popup(impl_->mbuilder.data(), called_by_menubar); } From e720866a94f6c55c29ccda45cc99b845c1426bbb Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 1 May 2015 18:01:32 +0800 Subject: [PATCH 76/77] refactor class place --- source/gui/place.cpp | 128 +++++++++++++++---------------------------- 1 file changed, 43 insertions(+), 85 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index d42b6b2c..e7294ce9 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -559,18 +559,22 @@ namespace nana return token::identifier; } - std::string err = "an invalid character '"; - err += *sp_; - err += "'"; - - _m_throw_error(err); + _m_throw_error(*sp_); return token::error; //Useless, just for syntax correction. } private: void _m_throw_error(char err_char) + { + std::string str = "place: invalid character '"; + str += err_char; + str += '\''; + _m_throw_error(str); + } + + void _m_throw_error(const std::string& err) { std::stringstream ss; - ss << "place: invalid character '" << err_char << "' at " << static_cast(sp_ - divstr_); + ss << "place: " << err << " at " << static_cast(sp_ - divstr_); throw std::runtime_error(ss.str()); } @@ -579,8 +583,7 @@ namespace nana if (token::equal != read()) _m_throw_error("an equal sign is required after '" + idstr_ + "'"); - const char* p = sp_; - for (; *p == ' '; ++p); + const char* p = _m_eat_whitespace(sp_); auto neg_ptr = p; if ('-' == *p) @@ -599,8 +602,7 @@ namespace nana if (token::equal != read()) _m_throw_error("an equal sign is required after '" + idstr + "'"); - const char* p = sp_; - for (; *p == ' ' || *p == '\t'; ++p); + const char* p = _m_eat_whitespace(sp_); reparray_.reset(); auto tk = read(); @@ -620,14 +622,7 @@ namespace nana } } - void _m_throw_error(const std::string& err) - { - std::stringstream ss; - ss << "place: " << err << " at " << static_cast(sp_ - divstr_); - throw std::runtime_error(ss.str()); - } - - const char* _m_eat_whitespace(const char* sp) + static const char* _m_eat_whitespace(const char* sp) { while (*sp && !isgraph(*sp)) ++sp; @@ -678,7 +673,7 @@ namespace nana if (gotcha) { - for (; *sp == ' ' || *sp == '\t'; ++sp); + sp = _m_eat_whitespace(sp); if ('%' == *sp) { if (number_t::kind::integer == number_.kind_of()) @@ -758,6 +753,20 @@ namespace nana for (auto & e : fastened) API::show_window(e.handle, vsb); } + + static event_handle erase_element(std::vector& elements, window handle) + { + for (auto i = elements.begin(), end = elements.end(); i != end; ++i) + { + if (i->handle == handle) + { + auto evt_destroy = i->evt_destroy; + elements.erase(i); + return evt_destroy; + } + } + return nullptr; + } private: //The defintion is moved after the definition of class division template @@ -769,15 +778,8 @@ namespace nana { return API::events(wd).destroy.connect([this](const arg_destroy& arg) { - for (auto i = elements.begin(), end = elements.end(); i != end; ++i) - { - if (arg.window_handle == i->handle) - { - elements.erase(i); - break; - } - } - place_ptr_->collocate(); + if (erase_element(elements, arg.window_handle)) + place_ptr_->collocate(); }); } @@ -816,13 +818,7 @@ namespace nana //does not change the layout. auto evt = API::events(wd).destroy([this](const arg_destroy& arg) { - auto destroyed_wd = arg.window_handle; - auto i = std::find_if(fastened.begin(), fastened.end(), [destroyed_wd](element_t& e){ - return (e.handle == destroyed_wd); - }); - - if (i != fastened.end()) - fastened.erase(i); + erase_element(fastened, arg.window_handle); }); fastened.emplace_back(wd, evt); @@ -930,16 +926,9 @@ namespace nana { for (auto & child : div->children) { - if (child->field) - { - if (vsb) - { - if (child->visible) - child->field->visible(true); - } - else - child->field->visible(false); - } + if (child->field && (!vsb || child->visible)) + child->field->visible(vsb); + _m_visible_for_child(child.get(), vsb); } } @@ -1511,17 +1500,6 @@ namespace nana class place::implement::div_splitter : public division { - struct div_block - { - division * div; - int pixels; - double scale; - - div_block(division* d, int px) - : div(d), pixels(px) - {} - }; - enum{splitter_px = 4}; public: div_splitter(place_parts::number_t init_weight) @@ -1534,14 +1512,9 @@ namespace nana this->weight.assign(splitter_px); } - void leaf_left(division * d) + void set_leaf(bool is_left, division * d) { - leaf_left_ = d; - } - - void leaf_right(division * d) - { - leaf_right_ = d; + (is_left ? leaf_left_ : leaf_right_) = d; } void direction(bool horizontal) @@ -1787,7 +1760,7 @@ namespace nana if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division)) { auto splitter = new div_splitter(tknizer.number()); - splitter->leaf_left(children.back().get()); + splitter->set_leaf(true, children.back().get()); children.back()->div_next = splitter; children.emplace_back(splitter); } @@ -1799,7 +1772,7 @@ namespace nana { children.back()->div_next = div.get(); if (division::kind::splitter == children.back()->kind_of_division) - dynamic_cast(*children.back()).leaf_right(div.get()); + dynamic_cast(*children.back()).set_leaf(false, div.get()); } children.emplace_back(div.release()); } @@ -2184,29 +2157,14 @@ namespace nana bool recollocate = false; for (auto & fld : impl_->fields) { - auto & elements = fld.second->elements; - for (auto i = elements.begin(); i != elements.end();) + auto evt = fld.second->erase_element(fld.second->elements, handle); + if (evt) { - if (i->handle == handle) - { - API::umake_event(i->evt_destroy); - i = elements.erase(i); - recollocate |= (nullptr != fld.second->attached); - } - else - ++i; + API::umake_event(evt); + recollocate |= (nullptr != fld.second->attached); } - auto i = std::find_if(fld.second->fastened.begin(), fld.second->fastened.end(), [handle](implement::field_impl::element_t& e) - { - return (e.handle == handle); - }); - - if (i != fld.second->fastened.end()) - { - API::umake_event(i->evt_destroy); - fld.second->fastened.erase(i); - } + API::umake_event( fld.second->erase_element(fld.second->fastened, handle)); } if (recollocate) From 0267367f3fa8ff15eeb5381c2e9eb1d34f23ba02 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 2 May 2015 02:25:04 +0800 Subject: [PATCH 77/77] fix menu ESC issues --- source/gui/detail/win32/bedrock.cpp | 36 +++++++++++++++++------------ source/gui/widgets/menubar.cpp | 3 +++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 58c4eb6e..71ae2f02 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -663,7 +663,6 @@ namespace detail case WM_SETFOCUS: case WM_KILLFOCUS: case WM_PAINT: - case WM_SYSCOMMAND: case WM_CLOSE: case WM_MOUSEACTIVATE: case WM_GETMINMAXINFO: @@ -1314,6 +1313,7 @@ namespace detail } break; case WM_SYSCHAR: + def_window_proc = true; brock.set_keyboard_shortkey(true); msgwnd = brock.wd_manager.find_shortkey(native_window, static_cast(wParam)); if(msgwnd) @@ -1325,10 +1325,11 @@ namespace detail arg.window_handle = reinterpret_cast(msgwnd); arg.ignore = false; brock.emit(event_code::shortkey, msgwnd, arg, true, &context); + def_window_proc = false; } - def_window_proc = true; break; case WM_SYSKEYDOWN: + def_window_proc = true; if (brock.whether_keyboard_shortkey() == false) { msgwnd = msgwnd->root_widget->other.attribute.root->menubar; @@ -1348,14 +1349,16 @@ namespace detail else brock.erase_menu(true); } - def_window_proc = true; break; case WM_SYSKEYUP: + def_window_proc = true; if(brock.set_keyboard_shortkey(false) == false) { msgwnd = msgwnd->root_widget->other.attribute.root->menubar; if(msgwnd) { + //Don't call default window proc to avoid popuping system menu. + def_window_proc = false; bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus); if (set_focus) brock.wd_manager.set_focus(msgwnd, false); @@ -1375,15 +1378,15 @@ namespace detail } } } - def_window_proc = true; break; case WM_KEYDOWN: if(msgwnd->flags.enabled) { - if (brock.get_menu()) + auto menu_wd = brock.get_menu(); + if (menu_wd) brock.delay_restore(0); //Enable delay restore - if(msgwnd->root != brock.get_menu()) + if (msgwnd->root != menu_wd) msgwnd = brock.focus(); if(msgwnd) @@ -1408,6 +1411,17 @@ namespace detail arg.key = static_cast(wParam); brock.get_key_state(arg); brock.emit(event_code::key_press, msgwnd, arg, true, &context); + + if (msgwnd->root_widget->other.attribute.root->menubar == msgwnd) + { + //In order to keep the focus on the menubar, cancel the delay_restore + //when pressing ESC to close the menu which is popuped by the menubar. + //If no menu popuped by the menubar, it should enable delay restore to + //restore the focus for taken window. + + int cmd = (menu_wd && (keyboard::escape == static_cast(wParam)) ? 1 : 0); + brock.delay_restore(cmd); + } } } } @@ -1455,14 +1469,6 @@ namespace detail brock.delay_restore(2); //Restores while key release break; - case WM_SYSCOMMAND: - if (SC_TASKLIST == wParam) - { - int debug = 0; - //brock.close_menu_if_focus_other_window() - } - def_window_proc = true; - break; case WM_CLOSE: { arg_unload arg; @@ -1571,7 +1577,7 @@ namespace detail break; case 2: //Restore if key released //restores the focus when menu is closed by pressing keyboard - if (!impl_->menu.window) + if ((!impl_->menu.window) && impl_->menu.delay_restore) set_menubar_taken(nullptr); break; case 3: //Restores if destroying diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 0be611c5..2c1de33d 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -460,6 +460,9 @@ namespace nana API::update_window(widget_->handle()); } }); + + if (API::focus_window() != this->widget_->handle()) + API::focus_window(widget_->handle()); menu_accessor::popup(*state_.menu, *widget_, m->pos.x, m->pos.y + static_cast(m->size.height)); return true; }