diff --git a/CMakeLists.txt b/CMakeLists.txt
index dba9e2c9..242a1ea2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -123,7 +123,7 @@ execute_process(COMMAND ${CMAKE_COMMAND}
${CMAKE_CURRENT_SOURCE_DIR}/include/nana/)
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(NANA_SOURCE_DIR ${CMAKE_SOURCE_DIR}/source)
@@ -161,3 +161,5 @@ install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib)
install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include)
+
+set_property( TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14 )
diff --git a/README.md b/README.md
index 0b034cf6..dcd10fe6 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,10 @@ Run it! All dependencies will be resovled automatically by biicode! Amazing, isn
The best way to get help with Nana library is by visiting http://nanapro.org/help.htm
+## Sending a Pull Request ?
+
+This project is encourage you to contribute it through sending a pull request! There is a simple rule, please **don't** directly commit your contributions to the **master** branch. According to your commits, please choose the **hotfixes** branch or the **develop** branch. Thank you!
+
## Introduction to the Repository
There are two main branches with an infinite lifetime:
diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj
index 7e216758..9cdc46b0 100644
--- a/build/vc2013/nana.vcxproj
+++ b/build/vc2013/nana.vcxproj
@@ -67,24 +67,32 @@
- ../bin/vc2013/
+ ../bin/
..\..\include;$(IncludePath)
..\..\source;$(VC_SourcePath);
+ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)
+ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\
..\..\include;$(IncludePath)
..\..\source;$(VC_SourcePath);
- ../bin/vc2013/
+ ../bin/
+ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)
+ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\
- ../bin/vc2013/
+ ../bin/
..\..\include;$(IncludePath)
..\..\source;$(VC_SourcePath);
+ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)
+ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\
..\..\include;$(IncludePath)
..\..\source;$(VC_SourcePath);
- ../bin/vc2013/
+ ../bin/
+ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)
+ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\
@@ -102,7 +110,7 @@
true
- $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib
+ $(TargetPath)
@@ -119,7 +127,7 @@
true
- $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib
+ $(TargetPath)
@@ -141,7 +149,7 @@
true
- $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib
+ $(TargetPath)
@@ -162,7 +170,7 @@
true
- $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib
+ $(TargetPath)
@@ -177,6 +185,7 @@
+
@@ -247,6 +256,9 @@
+
+
+
diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters
index f0f82981..ac073316 100644
--- a/build/vc2013/nana.vcxproj.filters
+++ b/build/vc2013/nana.vcxproj.filters
@@ -300,5 +300,18 @@
Source Files\nana\gui\widgets
+
+ Source Files\nana\filesystem
+
+
+
+
+ Header Files
+
+
+
+
+ Header Files
+
\ No newline at end of file
diff --git a/build/vc2015/nana.sln b/build/vc2015/nana.sln
new file mode 100644
index 00000000..eab31ab5
--- /dev/null
+++ b/build/vc2015/nana.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.22823.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{25B21068-491B-4A9F-B99F-6C27BF31BAAD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {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}.Debug|x86.ActiveCfg = Debug|Win32
+ {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x86.Build.0 = Debug|Win32
+ {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.ActiveCfg = Release|x64
+ {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.Build.0 = Release|x64
+ {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x86.ActiveCfg = Release|Win32
+ {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/build/vc2015/nana.vcxproj b/build/vc2015/nana.vcxproj
new file mode 100644
index 00000000..94b72562
--- /dev/null
+++ b/build/vc2015/nana.vcxproj
@@ -0,0 +1,266 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {25B21068-491B-4A9F-B99F-6C27BF31BAAD}
+ Win32Proj
+ nana
+ 8.1
+
+
+
+ StaticLibrary
+ true
+ v140
+ Unicode
+
+
+ StaticLibrary
+ true
+ v140
+ Unicode
+
+
+ StaticLibrary
+ false
+ v140
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v140
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ../bin/
+ ..\..\include;$(IncludePath)
+ ..\..\source;$(VC_SourcePath);
+ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)
+ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\
+
+
+ ..\..\include;$(IncludePath)
+ ..\..\source;$(VC_SourcePath);
+ ../bin/
+ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)
+ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\
+
+
+ ../bin/
+ ..\..\include;$(IncludePath)
+ ..\..\source;$(VC_SourcePath);
+ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)
+ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\
+
+
+ ..\..\include;$(IncludePath)
+ ..\..\source;$(VC_SourcePath);
+ ../bin/
+ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)
+ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ MultiThreadedDebug
+ true
+ false
+
+
+ Windows
+ true
+
+
+ $(TargetPath)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ MultiThreadedDebug
+
+
+ Windows
+ true
+
+
+ $(TargetPath)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ MultiThreaded
+ true
+
+
+ Windows
+ true
+ true
+ true
+
+
+ $(TargetPath)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+ true
+
+
+ $(TargetPath)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/vc2015/nana.vcxproj.filters b/build/vc2015/nana.vcxproj.filters
new file mode 100644
index 00000000..cb51dab8
--- /dev/null
+++ b/build/vc2015/nana.vcxproj.filters
@@ -0,0 +1,312 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {b0bd11b1-bcbb-4e05-885e-44295bc1a7bb}
+
+
+ {aab16aa3-c8d4-4495-8606-1b21ae739ee5}
+
+
+ {c395f107-7102-415b-a019-54e7cf3575af}
+
+
+ {e2569be2-9e68-477d-8b59-e248595de6c7}
+
+
+ {52ed7f8e-fa48-495e-af1f-4df013205a35}
+
+
+ {87d14798-9015-4162-b9ab-72c741cff063}
+
+
+ {4f8e7d23-9fe1-4409-bb03-2bd0809e606b}
+
+
+ {85c9c1bb-d87b-4481-bf3c-7425f680a12d}
+
+
+ {8058b530-86ec-4d72-890d-345aa30db056}
+
+
+ {87b124cb-408d-460b-a81b-8a788bbae0d9}
+
+
+ {b10db2f1-0542-421a-9e1d-4357e3be5f68}
+
+
+ {59f186c8-f5f8-4499-8e19-f278d4754220}
+
+
+ {5acf1733-47b2-4872-a105-66c7ad15cd39}
+
+
+ {a81fa10e-1274-44e0-92a0-434fa28f89ae}
+
+
+ {e95b4a72-643f-4416-af95-b0bbaf7f0c57}
+
+
+
+
+ Source Files\nana\audio\detail
+
+
+ Source Files\nana\audio\detail
+
+
+ Source Files\nana\audio\detail
+
+
+ Source Files\nana\audio
+
+
+ Source Files\nana\detail\win32
+
+
+ Source Files\nana\filesystem
+
+
+ Source Files\nana\filesystem
+
+
+ Source Files\nana\gui\detail\win32
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui\widgets\skeletons
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\paint\detail
+
+
+ Source Files\nana\paint\detail
+
+
+ Source Files\nana\paint
+
+
+ Source Files\nana\paint
+
+
+ Source Files\nana\paint
+
+
+ Source Files\nana\paint
+
+
+ Source Files\nana\paint
+
+
+ Source Files\nana\paint
+
+
+ Source Files\nana\system
+
+
+ Source Files\nana\system
+
+
+ Source Files\nana\system
+
+
+ Source Files\nana\system
+
+
+ Source Files\nana\threads
+
+
+ Source Files\nana
+
+
+ Source Files\nana
+
+
+ Source Files\nana
+
+
+ Source Files\nana
+
+
+ Source Files\nana
+
+
+ Source Files\nana
+
+
+ Source Files\nana
+
+
+ Source Files\nana
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana
+
+
+ Source Files\nana\gui\detail
+
+
+ Source Files\nana\gui
+
+
+ Source Files\nana\gui\widgets
+
+
+ Source Files\nana\filesystem
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/include/nana/audio/player.hpp b/include/nana/audio/player.hpp
index 278e0ecc..24378214 100644
--- a/include/nana/audio/player.hpp
+++ b/include/nana/audio/player.hpp
@@ -4,7 +4,10 @@
#include
namespace nana{ namespace audio
-{ /// play an audio file in Windows WAV format
+{ /// class player
+ /// \brief play an audio file in PCM Windows WAV format
+ ///
+ /// \include audio_player.cpp
class player
: private nana::noncopyable
{
diff --git a/include/nana/config.hpp b/include/nana/config.hpp
index 77b9005c..6d2cf836 100644
--- a/include/nana/config.hpp
+++ b/include/nana/config.hpp
@@ -13,6 +13,26 @@
#ifndef NANA_CONFIG_HPP
#define NANA_CONFIG_HPP
+
+#if defined(_MSC_VER)
+ #define _SCL_SECURE_NO_WARNINGS
+ #define _CRT_SECURE_NO_DEPRECATE
+ #pragma warning(disable : 4996)
+
+ #if (_MSC_VER < 1900)
+ // is this a good idea?
+ #define NOT_IMPLEMENTED_KEYWORD_noexcept
+ #endif // _MSC_VER < 1900
+ #if (_MSC_VER == 1900)
+ // google: break any code that tries to use codecvt or codecvt.
+ // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support.
+ // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively.
+ // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all.
+ // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources.
+ #define STD_CODECVT_NOT_SUPPORTED
+ #endif // _MSC_VER == 1900
+#endif // _MSVC
+
//Select platform automatically
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
//Windows:
@@ -35,7 +55,7 @@
#define PLATFORM_SPEC_HPP
#define STD_CODECVT_NOT_SUPPORTED
#else
-# static_assert(false, "Only Windows and Unix are support now");
+# static_assert(false, "Only Windows and Unix are supported now");
#endif
#if defined(NANA_MINGW) || defined(NANA_LINUX)
diff --git a/include/nana/detail/win32/platform_spec.hpp b/include/nana/detail/win32/platform_spec.hpp
index 9e735f99..39f21366 100644
--- a/include/nana/detail/win32/platform_spec.hpp
+++ b/include/nana/detail/win32/platform_spec.hpp
@@ -55,6 +55,13 @@ namespace detail
unsigned ignore; //determinate that pos or size would be ignored.
};
+ struct map_thread
+ {
+ rectangle update_area;
+ bool ignore_update_area;
+ bool forced;
+ };
+
enum
{
tray = 0x501,
diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp
new file mode 100644
index 00000000..b00760d2
--- /dev/null
+++ b/include/nana/filesystem/filesystem.hpp
@@ -0,0 +1,469 @@
+/*
+ * A filesystem Implementation
+ * Copyright(C) 2003 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: stdex/filesystem/filesystem.hpp
+ * @description:
+ * file_iterator is a toolkit for applying each file and directory in a
+ * specified path.
+ * Modiffied by Ariel Vina-Rodriguez:
+ * Now mimic std::experimental::filesystem::v1 (boost v3)
+ * and need VC2015 or a C++11 compiler. With a few correction will be compiler by VC2013
+ */
+
+// http://en.cppreference.com/w/cpp/experimental/fs
+// http://cpprocks.com/introduction-to-tr2-filesystem-library-in-vs2012/ --- TR2 filesystem in VS2012
+// https://msdn.microsoft.com/en-us/library/hh874694%28v=vs.140%29.aspx --- C++ 14, the header VS2015
+// https://msdn.microsoft.com/en-us/library/hh874694%28v=vs.120%29.aspx --- header VS2013
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf --- last pdf of std draft N4100 2014-07-04
+// http://cplusplus.github.io/filesystem-ts/working-draft.html --- in html format
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4099.html --- in html format
+// http://article.gmane.org/gmane.comp.lib.boost.devel/256220 --- The filesystem TS unanimously approved by ISO.
+// http://theboostcpplibraries.com/boost.filesystem --- Boost docs
+// http://www.boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm ---
+// http://www.boost.org/doc/libs/1_34_0/libs/filesystem/doc/index.htm
+// http://www.boost.org/doc/libs/1_58_0/boost/filesystem.hpp
+// https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.200x --- Table 1.4. g++ C++ Technical Specifications Implementation Status
+
+#ifndef NANA_FILESYSTEM_HPP
+#define NANA_FILESYSTEM_HPP
+#include
+#include
+#include
+
+#include
+
+#ifdef NANA_WINDOWS
+ #include
+ typedef HANDLE find_handle_t;
+#elif defined(NANA_LINUX)
+ #include
+ #include
+ #include
+ typedef DIR* find_handle_t;
+#endif
+
+ // namespace std { namespace experimental { namespace filesystem { inline namespace v1 {
+
+namespace nana { namespace experimental
+{
+namespace filesystem
+{
+ enum class file_type
+ {
+ none = 0, ///< has not been determined or an error occurred while trying to determine
+ not_found = -1, ///< Pseudo-type: file was not found. Is not considered an error
+ regular = 1,
+ directory = 2 ,
+ symlink =3, ///< Symbolic link file
+ block =4, ///< Block special file
+ character= 5 , ///< Character special file
+ fifo = 6 , ///< FIFO or pipe file
+ socket =7,
+ unknown= 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other
+ };
+
+ enum class perms
+ {
+ none =0, ///< There are no permissions set for the file.
+ unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions
+ };
+ //enum class copy_options;
+ //enum class directory_options;
+
+ // class filesystem_error;
+ enum class error { none = 0 }; // deprecate ??
+
+ struct attribute // deprecate ??
+ {
+ uintmax_t size {};
+ bool directory{};
+ tm modified {};
+
+ attribute() {} ;
+ attribute( uintmax_t size, bool is_directory) :size{size}, directory{is_directory} {}
+ };
+
+ struct space_info
+ {
+ uintmax_t capacity;
+ uintmax_t free;
+ uintmax_t available;
+ };
+ using file_time_type = std::chrono::time_point< std::chrono::system_clock>;// trivial-clock> ;
+
+ class file_status
+ {
+ file_type m_ft = file_type::none;
+ perms m_prms = perms::unknown;
+
+ public:
+ explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown)
+ :m_ft{ft}, m_prms{prms}
+ {}
+
+ file_status(const file_status& fs) : m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default;
+ file_status(file_status&& fs) : m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default;
+
+ ~file_status(){};
+ file_status& operator=(const file_status&) = default;
+ file_status& operator=(file_status&&fs) // = default;
+ {
+ m_ft=fs.m_ft; m_prms = fs.m_prms;
+ return *this;
+ }
+ // observers
+ file_type type() const { return m_ft;}
+ perms permissions() const { return m_prms;}
+ // modifiers
+ void type (file_type ft) { m_ft=ft ;}
+ void permissions(perms prms) { m_prms = prms; }
+ };
+
+ /// concerned only with lexical and syntactic aspects and does not necessarily exist in
+ /// external storage, and the pathname is not necessarily valid for the current operating system
+ /// or for a particular file system
+ /// A sequence of elements that identify the location of a file within a filesystem.
+ /// The elements are the:
+ /// rootname (opt), root-directory (opt), and an optional sequence of filenames.
+ /// The maximum number of elements in the sequence is operating system dependent.
+ class path
+ {
+ public:
+ path();
+ path(const nana::string&);
+
+ bool empty() const;
+ path root() const;
+ file_type what() const;
+
+ nana::string filename() const;
+#if defined(NANA_WINDOWS)
+ public:
+ nana::string to_string() const { return text_; }
+ operator nana::string() const { return text_; }
+ private:
+ nana::string text_;
+#else
+ public:
+ std::string to_string() const { return text_; }
+ operator std::string() const { return text_; }
+ private:
+ std::string text_;
+#endif
+ };
+
+ struct directory_entry
+ {
+ path m_path;
+
+ attribute attr{};
+ //file_status m_status;
+
+ directory_entry(){}
+ directory_entry(const nana::string& filename_, bool is_directory, uintmax_t size)
+ :m_path{filename_}, attr{size, is_directory}
+ {}
+
+ void assign (const path& p){ m_path=p;}
+ void replace_filename(const path& p){ m_path=p;}
+
+ //file_status status() const;
+
+ operator const path&() const {return m_path;};
+ const path& path() const {return m_path;}
+
+ };
+
+ /// an iterator for a sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator
+ //template
+ class directory_iterator :public std::iterator
+ {
+ public:
+ using value_type = directory_entry ;
+ typedef ptrdiff_t difference_type;
+ typedef const directory_entry* pointer;
+ typedef const directory_entry& reference;
+ typedef std::input_iterator_tag iterator_category;
+
+ directory_iterator():end_(true), handle_(nullptr){}
+
+ directory_iterator(const nana::string& file_path) { _m_prepare(file_path); }
+ //directory_iterator(const path& file_path) { _m_prepare(file_path.filename()); }
+
+ const value_type&
+ operator*() const { return value_; }
+
+ const value_type*
+ operator->() const { return &(operator*()); }
+
+ directory_iterator& operator++()
+ { _m_read(); return *this; }
+
+ directory_iterator operator++(int)
+ {
+ directory_iterator tmp = *this;
+ _m_read();
+ return tmp;
+ }
+
+ bool equal(const directory_iterator& x) const
+ {
+ if(end_ && (end_ == x.end_)) return true;
+ return (value_.path().filename() == x.value_.path().filename());
+ }
+
+
+ // enable directory_iterator range-based for statements
+ directory_iterator begin( ) { return *this; }
+ directory_iterator end( ) { return {}; }
+
+ private:
+ template
+ static bool _m_ignore(const Char * p)
+ {
+ while(*p == '.')
+ ++p;
+ return (*p == 0);
+ }
+
+ void _m_prepare(const nana::string& file_path)
+ {
+ #if defined(NANA_WINDOWS)
+ path_ = file_path;
+ auto pat = file_path;
+ DWORD attr = ::GetFileAttributes(pat.data());
+ if((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY))
+ pat += STR("\\*");
+
+ ::HANDLE handle = ::FindFirstFile(pat.data(), &wfd_);
+
+ if(handle == INVALID_HANDLE_VALUE)
+ {
+ end_ = true;
+ return;
+ }
+
+ while(_m_ignore(wfd_.cFileName))
+ {
+ if(::FindNextFile(handle, &wfd_) == 0)
+ {
+ end_ = true;
+ ::FindClose(handle);
+ return;
+ }
+ }
+
+ value_ = value_type(wfd_.cFileName,
+ (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY,
+ wfd_.nFileSizeLow);
+
+ #elif defined(NANA_LINUX)
+ path_ = nana::charset(file_path);
+ if(path_.size() && (path_[path_.size() - 1] != '/'))
+ path_ += '/';
+ find_handle_t handle = opendir(path_.c_str());
+ end_ = true;
+ if(handle)
+ {
+ struct dirent * dnt = readdir(handle);
+ if(dnt)
+ {
+ while(_m_ignore(dnt->d_name))
+ {
+ dnt = readdir(handle);
+ if(dnt == 0)
+ {
+ closedir(handle);
+ return;
+ }
+ }
+
+ struct stat fst;
+ if(stat((path_ + dnt->d_name).c_str(), &fst) == 0)
+ {
+ value_ = value_type(nana::charset(dnt->d_name), 0 != S_ISDIR(fst.st_mode), fst.st_size);
+ }
+ else
+ {
+ value_.m_path = nana::charset(dnt->d_name);
+ value_.size = 0;
+ value_.directory = false;
+ }
+ end_ = false;
+ }
+ }
+ #endif
+ if(false == end_)
+ {
+ find_ptr_ = std::shared_ptr(new find_handle_t(handle), inner_handle_deleter());
+ handle_ = handle;
+ }
+ }
+
+ void _m_read()
+ {
+ if(handle_)
+ {
+ #if defined(NANA_WINDOWS)
+ if(::FindNextFile(handle_, &wfd_) != 0)
+ {
+ while(_m_ignore(wfd_.cFileName))
+ {
+ if(::FindNextFile(handle_, &wfd_) == 0)
+ {
+ end_ = true;
+ return;
+ }
+ }
+ value_ = value_type(wfd_.cFileName,
+ (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY,
+ wfd_.nFileSizeLow);
+ }
+ else
+ end_ = true;
+ #elif defined(NANA_LINUX)
+ struct dirent * dnt = readdir(handle_);
+ if(dnt)
+ {
+ while(_m_ignore(dnt->d_name))
+ {
+ dnt = readdir(handle_);
+ if(dnt == 0)
+ {
+ end_ = true;
+ return;
+ }
+ }
+ struct stat fst;
+ if(stat((path_ + "/" + dnt->d_name).c_str(), &fst) == 0)
+ value_ = value_type(wfd_.cFileName,
+ (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY,
+ wfd_.nFileSizeLow);
+ else
+ value_.m_path = nana::charset(dnt->d_name);
+ }
+ else
+ end_ = true;
+ #endif
+ }
+ }
+ private:
+ struct inner_handle_deleter
+ {
+ void operator()(find_handle_t * handle)
+ {
+ if(handle && *handle)
+ {
+ #if defined(NANA_WINDOWS)
+ ::FindClose(*handle);
+ #elif defined(NANA_LINUX)
+ ::closedir(*handle);
+ #endif
+ }
+ delete handle;
+ }
+ };
+ private:
+ bool end_{false};
+
+#if defined(NANA_WINDOWS)
+ WIN32_FIND_DATA wfd_;
+ nana::string path_;
+#elif defined(NANA_LINUX)
+ std::string path_;
+#endif
+ std::shared_ptr find_ptr_;
+
+ find_handle_t handle_{nullptr};
+ value_type value_;
+ };
+
+
+ //class recursive_directory_iterator;
+ //// enable recursive_directory_iterator range-based for statements
+ //recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
+ //recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;
+
+ //template
+ inline bool operator==(const directory_iterator/**/ & x, const directory_iterator/**/ & y)
+ {
+ return x.equal(y);
+ }
+
+ //template
+ inline bool operator!=(const directory_iterator/**/ & x, const directory_iterator/**/ & y)
+ {
+ return !x.equal(y);
+ }
+
+
+ // file_status status(const path& p);
+ bool file_attrib(const nana::string& file, attribute&);
+
+ inline bool is_directory(file_status s) { return s.type() == file_type::directory ;}
+ inline bool is_directory(const path& p) { return directory_iterator{ p }->attr.directory; }//works??
+ inline bool is_directory(const directory_entry& d) { return d.attr.directory; }
+ //bool is_directory(const path& p, error_code& ec) noexcept;
+
+ //bool is_regular_file(file_status s) noexcept;
+
+ inline bool is_empty(const path& p)
+ {
+ directory_iterator d(p) ;
+ return d->attr.directory ? d == directory_iterator()
+ : d->attr.size == 0;
+ }
+ //bool is_empty(const path& p, error_code& ec) noexcept;
+
+ uintmax_t file_size(const nana::string& file); // deprecate?
+ inline uintmax_t file_size(const path& p){return file_size(p.filename());}
+ //uintmax_t file_size(const path& p, error_code& ec) noexcept;
+ //long long filesize(const nana::string& file);
+
+
+ bool create_directories(const path& p);
+ //bool create_directories(const path& p, error_code& ec) noexcept;
+ bool create_directory(const path& p);
+ //bool create_directory(const path& p, error_code& ec) noexcept;
+ bool create_directory(const path& p, const path& attributes);
+ //bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept;
+ bool create_directory(const nana::string& dir, bool & if_exist);
+ inline bool create_directory(const path& p, bool & if_exist)
+ {
+ return create_directory(p.filename(), if_exist);
+ };
+
+
+ bool modified_file_time(const nana::string& file, struct tm&);
+
+
+ nana::string path_user();
+
+
+ path current_path();
+ //path current_path(error_code& ec);
+ void current_path(const path& p);
+ //void current_path(const path& p, error_code& ec) noexcept;
+ //nana::string path_current();
+
+
+ //bool remove(const path& p);
+ //bool remove(const path& p, error_code& ec) noexcept;
+ bool rmfile(const nana::char_t* file);
+
+ //uintmax_t remove_all(const path& p);
+ //uintmax_t remove_all(const path& p, error_code& ec) noexcept;
+ bool rmdir(const nana::char_t* dir, bool fails_if_not_empty);
+ nana::string root(const nana::string& path);
+
+
+}//end namespace filesystem
+} //end namespace experimental
+}//end namespace nana
+
+#endif
diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp
index c0ef0aa5..789ab5c3 100644
--- a/include/nana/gui/basis.hpp
+++ b/include/nana/gui/basis.hpp
@@ -84,6 +84,7 @@ namespace nana
end_of_medium = 0x19, //Ctrl+Y
substitute = 0x1A, //Ctrl+Z
escape = 0x1B,
+ space = 0x20, //Space
//The following names are intuitive name of ASCII control codes
select_all = start_of_headline,
diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp
index 9be7aa26..599ee379 100644
--- a/include/nana/gui/detail/basic_window.hpp
+++ b/include/nana/gui/detail/basic_window.hpp
@@ -25,6 +25,11 @@ namespace detail
{
struct basic_window;
+ enum class visible_state
+ {
+ invisible, visible, displayed
+ };
+
class caret_descriptor
{
public:
@@ -43,15 +48,16 @@ namespace detail
void size(const ::nana::size&);
void update();
- private:
- void _m_visible(bool isshow);
+ //private:
+ //void _m_visible(bool isshow); //deprecated
private:
core_window_t* wd_;
::nana::point point_;
::nana::size size_;
::nana::size paint_size_;
- bool visible_;
- bool real_visible_state_;
+ visible_state visible_state_;
+ //bool visible_;
+ //bool real_visible_state_; //deprecated
bool out_of_range_;
::nana::rectangle effective_range_;
};//end class caret_descriptor
@@ -112,7 +118,9 @@ namespace detail
bool is_ancestor_of(const basic_window* wd) const;
bool visible_parents() const;
+ bool displayed() const;
bool belong_to_lazy() const;
+ const basic_window * child_caret() const; //Returns a child which owns a caret
bool is_draw_through() const; ///< Determines whether it is a draw-through window.
diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp
index ebf53dbd..91bc71ed 100644
--- a/include/nana/gui/detail/bedrock.hpp
+++ b/include/nana/gui/detail/bedrock.hpp
@@ -44,7 +44,7 @@ namespace detail
~bedrock();
void pump_event(window, bool is_modal);
- void map_thread_root_buffer(core_window_t*, bool forced);
+ void map_thread_root_buffer(core_window_t*, bool forced, const rectangle* update_area = nullptr);
static int inc_window(unsigned tid = 0);
thread_context* open_thread_context(unsigned tid = 0);
thread_context* get_thread_context(unsigned tid = 0);
diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp
index f6948a45..fa62974b 100644
--- a/include/nana/gui/detail/drawer.hpp
+++ b/include/nana/gui/detail/drawer.hpp
@@ -23,12 +23,18 @@ namespace nana
{
class widget;
+ namespace detail
+ {
+ class drawer;
+ }
+
class drawer_trigger
: ::nana::noncopyable, ::nana::nonmovable
{
+ friend class detail::drawer;
public:
- typedef widget& widget_reference;
- typedef paint::graphics& graph_reference;
+ using widget_reference = widget&;
+ using graph_reference = paint::graphics&;
virtual ~drawer_trigger();
virtual void attached(widget_reference, graph_reference); //none-const
@@ -56,10 +62,11 @@ namespace nana
virtual void key_release(graph_reference, const arg_keyboard&);
virtual void shortkey(graph_reference, const arg_keyboard&);
- void _m_reset_overrided();
- bool _m_overrided() const;
private:
- bool overrided_{false};
+ void _m_reset_overrided();
+ bool _m_overrided(event_code) const;
+ private:
+ unsigned overrided_{ 0xFFFFFFFF };
};
namespace detail
@@ -83,7 +90,7 @@ namespace nana
enum class method_state
{
- unknown,
+ pending,
overrided,
not_overrided
};
@@ -110,7 +117,7 @@ namespace nana
void key_char(const arg_keyboard&);
void key_release(const arg_keyboard&);
void shortkey(const arg_keyboard&);
- void map(window, bool forced); //Copy the root buffer to screen
+ void map(window, bool forced, const rectangle* update_area = nullptr); //Copy the root buffer to screen
void refresh();
drawer_trigger* realizer() const;
void attached(widget&, drawer_trigger&);
@@ -128,31 +135,27 @@ namespace nana
template
void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr)
{
- if (realizer_)
+ const int pos = static_cast(evt_code);
+ if (realizer_ && (method_state::not_overrided != mth_state_[pos]))
{
- const int pos = static_cast(evt_code);
- if (method_state::not_overrided != mth_state_[pos])
+ _m_bground_pre();
+
+ if (method_state::pending == mth_state_[pos])
{
- _m_bground_pre();
+ (realizer_->*mfptr)(graphics, arg);
+
+ //Check realizer, when the window is closed in that event handler, the drawer will be
+ //detached and realizer will be a nullptr
+ if(realizer_)
+ mth_state_[pos] = (realizer_->_m_overrided(evt_code) ? method_state::overrided : method_state::not_overrided);
+ }
+ else
+ (realizer_->*mfptr)(graphics, arg);
- if (method_state::unknown == mth_state_[pos])
- {
- realizer_->_m_reset_overrided();
- (realizer_->*mfptr)(graphics, arg);
-
- //Check realizer, when the window is closed in that event handler, the drawer will be
- //detached and realizer will be a nullptr
- if(realizer_)
- mth_state_[pos] = (realizer_->_m_overrided() ? method_state::overrided : method_state::not_overrided);
- }
- else
- (realizer_->*mfptr)(graphics, arg);
-
- if (_m_lazy_decleared())
- {
- _m_draw_dynamic_drawing_object();
- _m_bground_end();
- }
+ if (_m_lazy_decleared())
+ {
+ _m_draw_dynamic_drawing_object();
+ _m_bground_end();
}
}
}
diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp
index f44ceb93..2937a1d5 100644
--- a/include/nana/gui/detail/effects_renderer.hpp
+++ b/include/nana/gui/detail/effects_renderer.hpp
@@ -13,9 +13,9 @@ namespace nana{
{
edge_nimbus_renderer() = default;
public:
- typedef CoreWindow core_window_t;
- typedef window_layout window_layer;
- typedef nana::paint::graphics & graph_reference;
+ using core_window_t = CoreWindow;
+ using window_layer = window_layout;
+ using graph_reference = ::nana::paint::graphics&;
static edge_nimbus_renderer& instance()
{
@@ -23,37 +23,69 @@ namespace nana{
return object;
}
- std::size_t weight() const
+ unsigned weight() const
{
return 2;
}
- bool render(core_window_t * wd, bool forced)
+ void erase(core_window_t* wd)
{
- bool rendered = false;
+ if (effects::edge_nimbus::none == wd->effect.edge_nimbus)
+ return;
+
core_window_t * root_wd = wd->root_widget;
auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
- if(nimbus.size())
+ for (auto i = nimbus.cbegin(); i != nimbus.cend(); ++i)
{
- core_window_t * focused = root_wd->other.attribute.root->focus;
- native_window_type native = root_wd->root;
- std::size_t pixels = weight();
+ if (i->window == wd)
+ {
+ auto pixels = weight();
+ rectangle r{wd->pos_root, wd->dimension};
+ r.x -= static_cast(pixels);
+ r.y -= static_cast(pixels);
+ r.width += static_cast(pixels << 1);
+ r.height += static_cast(pixels << 1);
+
+ root_wd->root_graph->paste(root_wd->root, r, r.x, r.y);
+
+ nimbus.erase(i);
+ break;
+ }
+ }
+ }
+
+ void render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr)
+ {
+ bool copy_separately = true;
+ std::vector> rd_set;
+
+ if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size())
+ {
+ auto root_wd = wd->root_widget;
+
+ auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
+
+ auto focused = root_wd->other.attribute.root->focus;
+
+ const unsigned pixels = weight();
auto graph = root_wd->root_graph;
- std::vector erase;
- std::vector> rd_set;
nana::rectangle r;
for(auto & action : nimbus)
{
if(_m_edge_nimbus(focused, action.window) && window_layer::read_visual_rectangle(action.window, r))
{
- if(action.window == wd)
- rendered = true;
+ if (action.window == wd)
+ {
+ if (update_area)
+ ::nana::overlap(*update_area, rectangle(r), r);
+ copy_separately = false;
+ }
//Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered.
- if ((forced && (action.window == wd)) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh))
+ if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh))
{
rd_set.emplace_back(r, action.window);
action.rendered = true;
@@ -62,29 +94,36 @@ namespace nana{
else if(action.rendered)
{
action.rendered = false;
- erase.push_back(action.window);
+
+ if (action.window == wd)
+ copy_separately = false;
+
+ ::nana::rectangle erase_r(
+ action.window->pos_root.x - static_cast(pixels),
+ action.window->pos_root.y - static_cast(pixels),
+ static_cast(action.window->dimension.width + (pixels << 1)),
+ static_cast(action.window->dimension.height + (pixels << 1))
+ );
+
+ graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y);
}
}
-
- //Erase
- for(auto el : erase)
- {
- if(el == wd)
- rendered = true;
-
- r.x = el->pos_root.x - static_cast(pixels);
- r.y = el->pos_root.y - static_cast(pixels);
- r.width = static_cast(el->dimension.width + (pixels << 1));
- r.height = static_cast(el->dimension.height + (pixels << 1));
-
- graph->paste(native, r, r.x, r.y);
- }
-
- //Render
- for (auto & rd : rd_set)
- _m_render_edge_nimbus(rd.second, rd.first);
}
- return rendered;
+
+ if (copy_separately)
+ {
+ rectangle vr;
+ if (window_layer::read_visual_rectangle(wd, vr))
+ {
+ if (update_area)
+ ::nana::overlap(*update_area, rectangle(vr), vr);
+ wd->root_graph->paste(wd->root, vr, vr.x, vr.y);
+ }
+ }
+
+ //Render
+ for (auto & rd : rd_set)
+ _m_render_edge_nimbus(rd.second, rd.first);
}
private:
static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd)
@@ -103,8 +142,8 @@ namespace nana{
rectangle good_r;
if (overlap(r, rectangle{ wd->root_graph->size() }, good_r))
{
- if( (good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) ||
- (good_r.x + good_r.width > visual.x + visual.width) || (good_r.y + good_r.height > visual.y + visual.height))
+ if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) ||
+ (good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom()))
{
auto graph = wd->root_graph;
nana::paint::pixel_buffer pixbuf(graph->handle(), r);
diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/include/nana/gui/detail/inner_fwd_implement.hpp
index 30de2c71..e420c554 100644
--- a/include/nana/gui/detail/inner_fwd_implement.hpp
+++ b/include/nana/gui/detail/inner_fwd_implement.hpp
@@ -121,7 +121,6 @@ namespace nana{
{
core_window_t* pressed{nullptr}; //The handle to a window which is being pressed
core_window_t* hovered{nullptr}; //the latest window that mouse moved
- bool tabstop_focus_changed{false}; //KeyDown may set it true, if it is true KeyChar will ignore the message
}condition;
root_misc(core_window_t * wd, unsigned width, unsigned height)
diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp
index c86dd821..c4dfb59e 100644
--- a/include/nana/gui/detail/window_manager.hpp
+++ b/include/nana/gui/detail/window_manager.hpp
@@ -70,13 +70,11 @@ namespace detail
std::vector stack_;
};
public:
- typedef native_window_type native_window;
- typedef revertible_mutex mutex_type;
+ using native_window = native_window_type;
+ using mutex_type = revertible_mutex;
- typedef basic_window core_window_t;
- typedef std::vector cont_type;
-
- typedef window_layout wndlayout_type;
+ using core_window_t = basic_window;
+ using window_layer = window_layout;
window_manager();
~window_manager();
@@ -126,9 +124,9 @@ namespace detail
core_window_t* root(native_window_type) const;
//Copy the root buffer that wnd specified into DeviceContext
- void map(core_window_t*, bool forced);
+ void map(core_window_t*, bool forced, const rectangle* update_area = nullptr);
- bool update(core_window_t*, bool redraw, bool force);
+ bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr);
void refresh_tree(core_window_t*);
bool do_lazy_refresh(core_window_t*, bool force_copy_to_screen);
diff --git a/include/nana/gui/screen.hpp b/include/nana/gui/screen.hpp
index ef9126e8..06c344ee 100644
--- a/include/nana/gui/screen.hpp
+++ b/include/nana/gui/screen.hpp
@@ -34,27 +34,38 @@ namespace nana
virtual const ::nana::rectangle& workarea() const = 0;
};
+ /// Provides some functions to get the metrics of the monitors \include screen.cpp
class screen
{
struct implement;
public:
- static ::nana::size desktop_size();
- static ::nana::size primary_monitor_size();
+ /// gets the size in pixel of the whole virtual desktop
+ static ::nana::size desktop_size();
+
+ /// gets the resolution in pixel of the primary monitor,
+ /// if there is only one monitor installed in the system,
+ /// the return value of primary_monitor_size is equal to desktop_size's.
+ static ::nana::size primary_monitor_size();
+
screen();
/// Reload has no preconditions, it's safe to call on moved-from
void reload();
- /// Returns the number of display monitors
+ /// Returns the number of display monitors installed in the system
std::size_t count() const;
+ /// gets the display monitor that contains the specified point
display& from_point(const point&);
+
+ /// gets the display monitor that contains the specified window
display& from_window(window);
display& get_display(std::size_t index) const;
display& get_primary() const;
+ /// applies a given function to all display monitors
void for_each(std::function) const;
private:
std::shared_ptr impl_;
diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp
index eac5ec29..3661b8a3 100644
--- a/include/nana/gui/widgets/listbox.hpp
+++ b/include/nana/gui/widgets/listbox.hpp
@@ -166,9 +166,13 @@ namespace nana
std::size_t pos_{0};
};
- //struct essence_t
- //@brief: this struct gives many data for listbox,
- // the state of the struct does not effect on member funcions, therefore all data members are public.
+
+
+ typedef std::vector selection;
+
+ /// struct essence_t
+ ///@brief: this struct gives many data for listbox,
+ /// the state of the struct does not effect on member funcions, therefore all data members are public.
struct essence_t;
struct category_t;
@@ -371,13 +375,17 @@ namespace nana
return iter;
}
- void append(std::initializer_list);
+ /// Appends one item at the end of this category with the specifies text in the column fields
+ void append(std::initializer_list);
size_type columns() const;
cat_proxy& text(nana::string);
nana::string text() const;
+ cat_proxy & select(bool);
+ bool selected() const;
+
/// Behavior of a container
void push_back(nana::string);
@@ -480,16 +488,54 @@ namespace nana
color_proxy header_grabbed{ static_cast(0x8BD6F6)};
color_proxy header_floated{ static_cast(0xBABBBC)};
color_proxy item_selected{ static_cast(0xD5EFFC) };
+
+ unsigned max_header_width{3000}, /// \todo how to implement some geometrical parameters ??
+ ext_w = 5;
};
}
}//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 list of \a items.
+/*! \class listbox
+\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.
+The user can \a drag the header to \a resize it or to \a reorganize it.
+By \a clicking on one header the list get \a reordered, first up, and then down alternatively.
+
+1. The resolver is used to resolute an object of the specified type for a listbox item.
+3. nana::listbox creates the category 0 by default. The member functions without the categ parameter operate the items that belong to category 0.
+4. A sort compare is used for sorting the items. It is a strict weak ordering comparer that must meet the requirement:
+ Irreflexivity (comp(x, x) returns false)
+ and
+ antisymmetry(comp(a, b) != comp(b, a) returns true)
+ A simple example.
+ bool sort_compare( const nana::string& s1, nana::any*,
+ const nana::string& s2, nana::any*, bool reverse)
+ {
+ return (reverse ? s1 > s2 : s1 < s2);
+ }
+ listbox.set_sort_compare(0, sort_compare);
+ The listbox supports attaching a customer's object for each item, therefore the items can be
+ sorted by comparing these customer's object.
+ bool sort_compare( const nana::string&, nana::any* o1,
+ const nana::string&, nana::any* o2, bool reverse)
+ {
+ if(o1 && o2) //some items may not attach a customer object.
+ {
+ int * i1 = o1->get();
+ int * i2 = o2->get();
+ return (i1 && i2 && (reverse ? *i1 > *i2 : *i1 < *i2));
+ ;//some types may not be int.
+ }
+ return false;
+ }
+ listbox.anyobj(0, 0, 10); //the type of customer's object is int.
+ listbox.anyobj(0, 0, 20);
+\todo doc: actualize this example listbox.at(0)...
+\see nana::drawerbase::listbox::cat_proxy
+\see nana::drawerbase::listbox::item_proxy
+\example listbox_Resolver.cpp
*/
class listbox
: public widget_object,
@@ -512,14 +558,17 @@ By \a clicking on a header the list get \a reordered, first up, and then down al
listbox(window, bool visible);
listbox(window, const rectangle& = {}, bool visible = true);
- void auto_draw(bool); ///); ///); ///< Appends categories at the end
cat_proxy insert(cat_proxy, nana::string);
cat_proxy at(size_type pos) const;
diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp
index 883760cf..512d30d7 100644
--- a/include/nana/gui/widgets/menu.hpp
+++ b/include/nana/gui/widgets/menu.hpp
@@ -108,7 +108,7 @@ namespace nana
virtual void background(graph_reference, window) = 0;
virtual void item(graph_reference, const nana::rectangle&, const attr&) = 0;
- virtual void item_image(graph_reference, const nana::point&, const paint::image&) = 0;
+ virtual void item_image(graph_reference, const nana::point&, unsigned image_px, const paint::image&) = 0;
virtual void item_text(graph_reference, const nana::point&, const nana::string&, unsigned text_pixels, const attr&) = 0;
virtual void sub_arrow(graph_reference, const nana::point&, unsigned item_pixels, const attr&) = 0;
};
diff --git a/include/nana/gui/widgets/progress.hpp b/include/nana/gui/widgets/progress.hpp
index 91e58ab7..f7697d7e 100644
--- a/include/nana/gui/widgets/progress.hpp
+++ b/include/nana/gui/widgets/progress.hpp
@@ -30,6 +30,8 @@ namespace nana
unsigned Max(unsigned);
void unknown(bool);
bool unknown() const;
+ bool stop(bool s = true);
+ bool stoped() const;
private:
void attached(widget_reference, graph_reference) override;
void refresh(graph_reference) override;
@@ -45,6 +47,7 @@ namespace nana
nana::paint::graphics* graph_{nullptr};
unsigned draw_width_{static_cast(-1)};
bool unknown_{false};
+ bool stop_{false};
unsigned max_{100};
unsigned value_{0};
}; //end class drawer
@@ -67,6 +70,8 @@ namespace nana
unsigned amount(unsigned value);
void unknown(bool);
bool unknown() const;
+ bool stop(bool s=true); ///< request stop or cancel and return previus stop status
+ bool stoped() const;
};
}//end namespace nana
#endif
diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp
index efb8af74..0b097676 100644
--- a/include/nana/gui/widgets/toolbar.hpp
+++ b/include/nana/gui/widgets/toolbar.hpp
@@ -14,7 +14,6 @@
#define NANA_GUI_WIDGET_TOOLBAR_HPP
#include "widget.hpp"
-#include
namespace nana
{
@@ -39,10 +38,10 @@ namespace nana
basic_event selected; ///< A mouse click on a control button.
basic_event enter; ///< The mouse enters a control button.
basic_event leave; ///< The mouse leaves a control button.
-
};
struct item_type;
+ class item_container;
class drawer
: public drawer_trigger
@@ -50,15 +49,12 @@ namespace nana
struct drawer_impl_type;
public:
- typedef std::size_t size_type;
+ using size_type = std::size_t;
drawer();
~drawer();
- void append(const nana::string&, const nana::paint::image&);
- void append();
- bool enable(size_type) const;
- bool enable(size_type, bool);
+ item_container& items() const;
void scale(unsigned);
private:
void refresh(graph_reference) override;
@@ -69,32 +65,28 @@ namespace nana
void mouse_down(graph_reference, const arg_mouse&) override;
void mouse_up(graph_reference, const arg_mouse&) override;
private:
- size_type _m_which(int x, int y, bool want_if_disabled) const;
- void _m_draw_background(const ::nana::color&);
- void _m_draw();
- void _m_owner_sized(const arg_resized&);
- private:
- void _m_fill_pixels(item_type*, bool force);
+ size_type _m_which(point, bool want_if_disabled) const;
+ void _m_calc_pixels(item_type*, bool force);
private:
::nana::toolbar* widget_;
- ::nana::paint::graphics* graph_;
drawer_impl_type* impl_;
};
}//end namespace toolbar
}//end namespace drawerbase
+
/// Control bar that contains buttons for controlling
class toolbar
: public widget_object
{
public:
- typedef std::size_t size_type; ///< A type to count the number of elements.
+ using size_type = std::size_t; ///< A type to count the number of elements.
toolbar() = default;
toolbar(window, bool visible);
toolbar(window, const rectangle& = rectangle(), bool visible = true);
- void append(); ///< Adds a separator.
+ void separate(); ///< Adds a separator.
void append(const nana::string& text, const nana::paint::image& img); ///< Adds a control button.
void append(const nana::string& text); ///< Adds a control button.
bool enable(size_type index) const;
diff --git a/source/audio/detail/audio_stream.cpp b/source/audio/detail/audio_stream.cpp
index 96def3d9..998b85bf 100644
--- a/source/audio/detail/audio_stream.cpp
+++ b/source/audio/detail/audio_stream.cpp
@@ -8,7 +8,8 @@ namespace nana{ namespace audio
//class audio_stream
bool audio_stream::open(const nana::string& file)
{
- fs_.open(static_cast(nana::charset(file)), std::ios::binary);
+ std::string fname{nana::charset(file)};//static_cast()
+ fs_.open(fname, std::ios::binary);
if(fs_)
{
wave_spec::master_riff_chunk riff;
diff --git a/source/charset.cpp b/source/charset.cpp
index c4a0f256..7e952503 100644
--- a/source/charset.cpp
+++ b/source/charset.cpp
@@ -799,7 +799,7 @@ namespace nana
switch(utf_x_)
{
case unicode::utf8:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
strbuf = detail::utf8_to_utf16(data_, true);
detail::put_utf16char(strbuf, 0, true);
#else
@@ -808,7 +808,7 @@ namespace nana
#endif
break;
case unicode::utf16:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
strbuf = data_;
detail::put_utf16char(strbuf, 0, true);
#else
@@ -817,7 +817,7 @@ namespace nana
#endif
break;
case unicode::utf32:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
strbuf = detail::utf32_to_utf16(data_);
detail::put_utf16char(strbuf, 0, true);
#else
@@ -907,21 +907,21 @@ namespace nana
switch(utf_x_)
{
case unicode::utf8:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
bytes = detail::utf8_to_utf16(data_, true);
#else
bytes = detail::utf8_to_utf32(data_, true);
#endif
break;
case unicode::utf16:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
bytes = data_;
#else
bytes = detail::utf16_to_utf32(data_);
#endif
break;
case unicode::utf32:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
bytes = detail::utf32_to_utf16(data_);
#else
bytes = data_;
@@ -984,19 +984,19 @@ namespace nana
switch(encoding)
{
case unicode::utf8:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
return detail::utf16_to_utf8(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)));
#else
return detail::utf32_to_utf8(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)));
#endif
case unicode::utf16:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
return std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t));
#else
return detail::utf32_to_utf16(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)));
#endif
case unicode::utf32:
-#if defined(NANA_MINGW)
+#if defined(NANA_WINDOWS)
return detail::utf16_to_utf32(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)));
#else
return std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t));
diff --git a/source/detail/linux_X11/platform_spec.cpp b/source/detail/linux_X11/platform_spec.cpp
index f53c046b..c8ccf682 100644
--- a/source/detail/linux_X11/platform_spec.cpp
+++ b/source/detail/linux_X11/platform_spec.cpp
@@ -44,7 +44,7 @@ namespace detail
bool conf::open(const char* file)
{
ifs_.open(file);
- return static_cast(ifs_ != 0);
+ return static_cast(ifs_);
}
std::string conf::value(const char* key)
diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp
new file mode 100644
index 00000000..4c6e8d22
--- /dev/null
+++ b/source/filesystem/filesystem.cpp
@@ -0,0 +1,444 @@
+/*
+ * A FileSystem Utility Implementation
+ * Copyright(C) 2003-2013 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/filesystem/filesystem.cpp
+ * @description:
+ * provide some interface for file managment
+ */
+
+#include
+#include
+#if defined(NANA_WINDOWS)
+ #include
+
+ #if defined(NANA_MINGW)
+ #ifndef _WIN32_IE
+ #define _WIN32_IE 0x0500
+ #endif
+ #endif
+
+ #include
+ #include
+#elif defined(NANA_LINUX)
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+#endif
+
+namespace nana {
+ namespace experimental
+ {
+ namespace filesystem
+ {
+ //Because of No wide character version of POSIX
+#if defined(NANA_LINUX)
+ typedef std::string string_t;
+ const char* splstr = "/\\";
+#else
+ typedef nana::string string_t;
+ const nana::char_t* splstr = STR("/\\");
+#endif
+ //class path
+ path::path() {}
+
+ path::path(const nana::string& text)
+#if defined(NANA_WINDOWS)
+ : text_(text)
+ {
+#else
+ :text_(nana::charset(text))
+ {
+#endif
+ auto pos = text_.find_last_of(splstr);
+ for (; (pos != string_t::npos) && (pos + 1 == text_.size()); pos = text_.find_last_of(splstr))
+ text_.erase(pos);
+ }
+
+ bool path::empty() const
+ {
+#if defined(NANA_WINDOWS)
+ return (::GetFileAttributes(text_.c_str()) == INVALID_FILE_ATTRIBUTES);
+#elif defined(NANA_LINUX)
+ struct stat sta;
+ return (::stat(text_.c_str(), &sta) == -1);
+#endif
+ }
+
+ path path::root() const
+ {
+#if defined(NANA_WINDOWS)
+ return path(filesystem::root(text_));
+#elif defined(NANA_LINUX)
+ return path(filesystem::root(nana::charset(text_)));
+#endif
+ }
+
+ file_type path::what() const
+ {
+#if defined(NANA_WINDOWS)
+ unsigned long attr = ::GetFileAttributes(text_.c_str());
+ if (INVALID_FILE_ATTRIBUTES == attr)
+ return file_type::not_found; //??
+
+ if (FILE_ATTRIBUTE_DIRECTORY & attr)
+ return file_type::directory;
+
+ return file_type::regular;
+#elif defined(NANA_LINUX)
+ struct stat sta;
+ if (-1 == ::stat(text_.c_str(), &sta))
+ return file_type::not_found; //??
+
+ if ((S_IFDIR & sta.st_mode) == S_IFDIR)
+ return file_type::directory;
+
+ if ((S_IFREG & sta.st_mode) == S_IFREG)
+ return file_type::regular;
+
+ return file_type::none;
+#endif
+ }
+
+ nana::string path::filename() const
+ {
+ string_t::size_type pos = text_.find_last_of(splstr);
+#if defined(NANA_WINDOWS)
+ return text_.substr(pos + 1);
+#else
+ return nana::charset(text_.substr(pos + 1));
+#endif
+ }
+ //end class path
+
+ namespace detail
+ {
+ //rm_dir_recursive
+ //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories
+ bool rm_dir_recursive(nana::string&& dir)
+ {
+ std::vector files;
+ nana::string path = dir;
+ path += '\\';
+
+ std::copy(directory_iterator(dir), directory_iterator(), std::back_inserter(files));
+
+ for (auto & f : files)
+ {
+ if (f.attr.directory)
+ rm_dir_recursive(path + f.path().filename());
+ else
+ rmfile((path + f.path().filename()).c_str());
+ }
+
+ return rmdir(dir.c_str(), true);
+ }
+
+ bool mkdir_helper(const nana::string& dir, bool & if_exist)
+ {
+#if defined(NANA_WINDOWS)
+ if (::CreateDirectory(dir.c_str(), 0))
+ {
+ if_exist = false;
+ return true;
+ }
+
+ if_exist = (::GetLastError() == ERROR_ALREADY_EXISTS);
+#elif defined(NANA_LINUX)
+ if (0 == ::mkdir(static_cast(nana::charset(dir)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH))
+ {
+ if_exist = false;
+ return true;
+ }
+
+ if_exist = (errno == EEXIST);
+#endif
+ return false;
+ }
+
+#if defined(NANA_WINDOWS)
+ void filetime_to_c_tm(FILETIME& ft, struct tm& t)
+ {
+ FILETIME local_file_time;
+ if (::FileTimeToLocalFileTime(&ft, &local_file_time))
+ {
+ SYSTEMTIME st;
+ ::FileTimeToSystemTime(&local_file_time, &st);
+ t.tm_year = st.wYear - 1900;
+ t.tm_mon = st.wMonth - 1;
+ t.tm_mday = st.wDay;
+ t.tm_wday = st.wDayOfWeek - 1;
+ t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay);
+
+ t.tm_hour = st.wHour;
+ t.tm_min = st.wMinute;
+ t.tm_sec = st.wSecond;
+ }
+ }
+#endif
+ }//end namespace detail
+
+ bool file_attrib(const nana::string& file, attribute& attr)
+ {
+#if defined(NANA_WINDOWS)
+ WIN32_FILE_ATTRIBUTE_DATA fad;
+ if (::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &fad))
+ {
+ LARGE_INTEGER li;
+ li.u.LowPart = fad.nFileSizeLow;
+ li.u.HighPart = fad.nFileSizeHigh;
+ attr.size = li.QuadPart;
+ attr.directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
+ detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified);
+ return true;
+ }
+#elif defined(NANA_LINUX)
+ struct stat fst;
+ if (0 == ::stat(static_cast(nana::charset(file)).c_str(), &fst))
+ {
+ attr.bytes = fst.st_size;
+ attr.is_directory = (0 != (040000 & fst.st_mode));
+ attr.modified = *(::localtime(&fst.st_ctime));
+ return true;
+ }
+#endif
+ return false;
+ }
+
+ uintmax_t file_size(const nana::string& file)
+ {
+#if defined(NANA_WINDOWS)
+ //Some compilation environment may fail to link to GetFileSizeEx
+ typedef BOOL(__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER);
+ GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx"));
+ if (get_file_size_ex)
+ {
+ HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (INVALID_HANDLE_VALUE != handle)
+ {
+ LARGE_INTEGER li;
+ if (!get_file_size_ex(handle, &li))
+ li.QuadPart = 0;
+
+ ::CloseHandle(handle);
+ return li.QuadPart;
+ }
+ }
+ return 0;
+#elif defined(NANA_LINUX)
+ FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb");
+ long long size = 0;
+ if (stream)
+ {
+ fseeko64(stream, 0, SEEK_END);
+ size = ftello64(stream);
+ fclose(stream);
+ }
+ return size;
+#endif
+ }
+
+ bool modified_file_time(const nana::string& file, struct tm& t)
+ {
+#if defined(NANA_WINDOWS)
+ WIN32_FILE_ATTRIBUTE_DATA attr;
+ if (::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &attr))
+ {
+ FILETIME local_file_time;
+ if (::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &local_file_time))
+ {
+ SYSTEMTIME st;
+ ::FileTimeToSystemTime(&local_file_time, &st);
+ t.tm_year = st.wYear - 1900;
+ t.tm_mon = st.wMonth - 1;
+ t.tm_mday = st.wDay;
+ t.tm_wday = st.wDayOfWeek - 1;
+ t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay);
+
+ t.tm_hour = st.wHour;
+ t.tm_min = st.wMinute;
+ t.tm_sec = st.wSecond;
+ return true;
+ }
+ }
+#elif defined(NANA_LINUX)
+ struct stat attr;
+ if (0 == ::stat(static_cast(nana::charset(file)).c_str(), &attr))
+ {
+ t = *(::localtime(&attr.st_ctime));
+ return true;
+ }
+#endif
+ return false;
+ }
+
+ bool create_directory(const nana::string& path, bool & if_exist)
+ {
+ if_exist = false;
+ if (path.size() == 0) return false;
+
+ nana::string root;
+#if defined(NANA_WINDOWS)
+ if (path.size() > 3 && path[1] == STR(':'))
+ root = path.substr(0, 3);
+#elif defined(NANA_LINUX)
+ if (path[0] == STR('/'))
+ root = '/';
+#endif
+ bool mkstat = false;
+ std::size_t beg = root.size();
+
+ while (true)
+ {
+ beg = path.find_first_not_of(STR("/\\"), beg);
+ if (beg == path.npos)
+ break;
+
+ std::size_t pos = path.find_first_of(STR("/\\"), beg + 1);
+ if (pos != path.npos)
+ {
+ root += path.substr(beg, pos - beg);
+
+ mkstat = detail::mkdir_helper(root, if_exist);
+ if (mkstat == false && if_exist == false)
+ return false;
+
+#if defined(NANA_WINDOWS)
+ root += STR('\\');
+#elif defined(NANA_LINUX)
+ root += STR('/');
+#endif
+ }
+ else
+ {
+ if (beg + 1 < path.size())
+ {
+ root += path.substr(beg);
+ mkstat = detail::mkdir_helper(root, if_exist);
+ }
+ break;
+ }
+ beg = pos + 1;
+ }
+ return mkstat;
+ }
+
+ bool rmfile(const nana::char_t* file)
+ {
+#if defined(NANA_WINDOWS)
+ bool ret = false;
+ if (file)
+ {
+ ret = (::DeleteFile(file) == TRUE);
+ if (!ret)
+ ret = (ERROR_FILE_NOT_FOUND == ::GetLastError());
+ }
+
+ return ret;
+#elif defined(NANA_LINUX)
+ if (std::remove(static_cast(nana::charset(file)).c_str()))
+ return (errno == ENOENT);
+ return true;
+#endif
+ }
+
+ bool rmdir(const nana::char_t* dir, bool fails_if_not_empty)
+ {
+ bool ret = false;
+ if (dir)
+ {
+#if defined(NANA_WINDOWS)
+ ret = (::RemoveDirectory(dir) == TRUE);
+ if (!fails_if_not_empty && (::GetLastError() == ERROR_DIR_NOT_EMPTY))
+ ret = detail::rm_dir_recursive(dir);
+#elif defined(NANA_LINUX)
+ std::string mbstr = nana::charset(dir);
+ if (::rmdir(mbstr.c_str()))
+ {
+ if (!fails_if_not_empty && (errno == EEXIST || errno == ENOTEMPTY))
+ ret = detail::rm_dir_recursive(dir);
+ }
+ else
+ ret = true;
+#endif
+ }
+ return ret;
+ }
+
+ nana::string root(const nana::string& path)
+ {
+ std::size_t index = path.size();
+
+ if (index)
+ {
+ const nana::char_t * str = path.c_str();
+
+ for (--index; index > 0; --index)
+ {
+ nana::char_t c = str[index];
+ if (c != '\\' && c != '/')
+ break;
+ }
+
+ for (--index; index > 0; --index)
+ {
+ nana::char_t c = str[index];
+ if (c == '\\' || c == '/')
+ break;
+ }
+ }
+
+ return index ? path.substr(0, index + 1) : nana::string();
+ }
+
+ nana::string path_user()
+ {
+#if defined(NANA_WINDOWS)
+ nana::char_t path[MAX_PATH];
+ if (SUCCEEDED(SHGetFolderPath(0, CSIDL_PROFILE, 0, SHGFP_TYPE_CURRENT, path)))
+ return path;
+#elif defined(NANA_LINUX)
+ const char * s = ::getenv("HOME");
+ if (s)
+ return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8);
+#endif
+ return nana::string();
+ }
+
+ path current_path()
+ {
+#if defined(NANA_WINDOWS)
+ nana::char_t buf[MAX_PATH];
+ DWORD len = ::GetCurrentDirectory(MAX_PATH, buf);
+ if (len)
+ {
+ if (len > MAX_PATH)
+ {
+ nana::char_t * p = new nana::char_t[len + 1];
+ ::GetCurrentDirectory(len + 1, p);
+ nana::string s = p;
+ delete[] p;
+ return s;
+ }
+ return buf;
+ }
+#elif defined(NANA_LINUX)
+ const char * s = ::getenv("PWD");
+ if (s)
+ return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8);
+#endif
+ return nana::string();
+ }
+ }//end namespace filesystem
+ } //end namespace experimental
+}//end namespace nana
diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp
index 7948564b..4b6e1ecd 100644
--- a/source/gui/detail/basic_window.cpp
+++ b/source/gui/detail/basic_window.cpp
@@ -7,7 +7,7 @@ namespace nana
{
//class caret_descriptor
caret_descriptor::caret_descriptor(core_window_t* wd, unsigned width, unsigned height)
- :wd_(wd), size_(width, height), visible_(false), real_visible_state_(false), out_of_range_(false)
+ :wd_(wd), size_(width, height), visible_state_(visible_state::invisible), out_of_range_(false)
{}
caret_descriptor::~caret_descriptor()
@@ -22,8 +22,9 @@ namespace nana
if(active)
{
native_interface::caret_create(wd_->root, size_);
- real_visible_state_ = false;
- visible_ = false;
+ //real_visible_state_ = false;
+ //visible_ = false;
+ visible_state_ = visible_state::invisible;
this->position(point_.x, point_.y);
}
else
@@ -76,19 +77,36 @@ namespace nana
return point_;
}
- void caret_descriptor::visible(bool isshow)
+ void caret_descriptor::visible(bool is_show)
{
- if(visible_ != isshow)
+ /*
+ if(visible_ != isshow) //deprecated
{
visible_ = isshow;
if(visible_ == false || false == out_of_range_)
_m_visible(isshow);
}
+ */
+
+ auto pre_displayed = (visible_state::displayed == visible_state_);
+
+ if (is_show)
+ {
+ visible_state_ = visible_state::visible;
+ if (wd_->displayed() && (! out_of_range_))
+ visible_state_ = visible_state::displayed;
+ }
+ else
+ visible_state_ = visible_state::invisible;
+
+ if (pre_displayed != (visible_state::displayed == visible_state_))
+ native_interface::caret_visible(wd_->root, !pre_displayed);
}
bool caret_descriptor::visible() const
{
- return visible_;
+ //return visible_; //deprecated
+ return (visible_state::invisible != visible_state_);
}
nana::size caret_descriptor::size() const
@@ -101,17 +119,21 @@ namespace nana
size_ = s;
update();
- if(visible_) this->visible(true);
+ //if(visible_) this->visible(true); //deprecated
+ if (visible_state::invisible != visible_state_)
+ visible(true);
}
+ /*
void caret_descriptor::_m_visible(bool isshow)
{
- if(real_visible_state_ != isshow)
+ if(real_visible_state_ != isshow) //deprecated
{
real_visible_state_ = isshow;
- native_interface::caret_visible(wd_->root, isshow);
+ native_interface::caret_visible(wd_->root, isshow && wd_->displayed());
}
}
+ */
void caret_descriptor::update()
{
@@ -138,8 +160,10 @@ namespace nana
{
out_of_range_ = true;
- if(visible_)
- _m_visible(false);
+ //if(visible_)
+ // _m_visible(false); //deprecated
+ if (visible_state::invisible != visible_state_)
+ visible(false);
}
}
else
@@ -164,19 +188,27 @@ namespace nana
if(out_of_range_)
{
- if(paint_size_ == size)
- _m_visible(true);
+ //if(paint_size_ == size) //deprecated
+ // _m_visible(true);
+ if (paint_size_ == size)
+ visible(true);
out_of_range_ = false;
}
if(paint_size_ != size)
{
+ bool vs = (visible_state::invisible != visible_state_);
native_interface::caret_destroy(wd_->root);
native_interface::caret_create(wd_->root, size);
- real_visible_state_ = false;
- if(visible_)
- _m_visible(true);
+ //real_visible_state_ = false; //deprecated
+ //if(visible_)
+ // _m_visible(true);
+
+ visible_state_ = visible_state::invisible;
+ if (vs)
+ visible(true);
+
paint_size_ = size;
}
@@ -281,6 +313,11 @@ namespace nana
return true;
}
+ bool basic_window::displayed() const
+ {
+ return (visible && visible_parents());
+ }
+
bool basic_window::belong_to_lazy() const
{
for (auto wd = this; wd; wd = wd->parent)
@@ -291,6 +328,26 @@ namespace nana
return false;
}
+ const basic_window* get_child_caret(const basic_window* wd, bool this_is_a_child)
+ {
+ if (this_is_a_child && wd->together.caret)
+ return wd;
+
+ for (auto child : wd->children)
+ {
+ auto caret_wd = get_child_caret(child, true);
+ if (caret_wd)
+ return caret_wd;
+ }
+
+ return nullptr;
+ }
+
+ const basic_window * basic_window::child_caret() const
+ {
+ return get_child_caret(this, false);
+ }
+
bool basic_window::is_draw_through() const
{
if (::nana::category::flags::root == this->other.category)
diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp
index c102c20a..64d1d354 100644
--- a/source/gui/detail/bedrock_pi.cpp
+++ b/source/gui/detail/bedrock_pi.cpp
@@ -93,6 +93,18 @@ namespace nana
arg.window_handle = reinterpret_cast(wd);
if (emit(event_code::expose, wd, arg, false, get_thread_context()))
{
+ const core_window_t * caret_wd = (wd->together.caret ? wd : wd->child_caret());
+ if (caret_wd)
+ {
+ if (exposed)
+ {
+ if (wd->root_widget->other.attribute.root->focus == caret_wd)
+ caret_wd->together.caret->visible(true);
+ }
+ else
+ caret_wd->together.caret->visible(false);
+ }
+
if (!exposed)
{
if (category::flags::root != wd->other.category)
@@ -118,7 +130,7 @@ namespace nana
arg.x = x;
arg.y = y;
if (emit(event_code::move, wd, arg, false, get_thread_context()))
- wd_manager.update(wd, true, true);
+ wd_manager.update(wd, false, true);
}
}
diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp
index fe5695b7..084219d0 100644
--- a/source/gui/detail/drawer.cpp
+++ b/source/gui/detail/drawer.cpp
@@ -34,99 +34,99 @@ namespace nana
void drawer_trigger::resizing(graph_reference, const arg_resizing&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::resizing));
}
void drawer_trigger::resized(graph_reference graph, const arg_resized&)
{
- overrided_ = true;
+ overrided_ |= (1 << static_cast(event_code::resized));
this->refresh(graph);
detail::bedrock::instance().thread_context_lazy_refresh();
}
void drawer_trigger::move(graph_reference, const arg_move&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::move));
}
void drawer_trigger::click(graph_reference, const arg_mouse&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::click));
}
void drawer_trigger::dbl_click(graph_reference, const arg_mouse&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::dbl_click));
}
void drawer_trigger::mouse_enter(graph_reference, const arg_mouse&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::mouse_enter));
}
void drawer_trigger::mouse_move(graph_reference, const arg_mouse&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::mouse_move));
}
void drawer_trigger::mouse_leave(graph_reference, const arg_mouse&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::mouse_leave));
}
void drawer_trigger::mouse_down(graph_reference, const arg_mouse&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::mouse_down));
}
void drawer_trigger::mouse_up(graph_reference, const arg_mouse&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::mouse_up));
}
void drawer_trigger::mouse_wheel(graph_reference, const arg_wheel&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::mouse_wheel));
}
void drawer_trigger::mouse_dropfiles(graph_reference, const arg_dropfiles&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::mouse_drop));
}
void drawer_trigger::focus(graph_reference, const arg_focus&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::focus));
}
void drawer_trigger::key_press(graph_reference, const arg_keyboard&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::key_press));
}
void drawer_trigger::key_char(graph_reference, const arg_keyboard&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::key_char));
}
void drawer_trigger::key_release(graph_reference, const arg_keyboard&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::key_release));
}
void drawer_trigger::shortkey(graph_reference, const arg_keyboard&)
{
- overrided_ = false;
+ overrided_ &= ~(1 << static_cast(event_code::shortkey));
}
void drawer_trigger::_m_reset_overrided()
{
- overrided_ = true;
+ overrided_ = 0xFFFFFFFF;
}
- bool drawer_trigger::_m_overrided() const
+ bool drawer_trigger::_m_overrided(event_code evt_code) const
{
- return overrided_;
+ return 0 != (overrided_ & (1 << static_cast(evt_code)));
}
//end class drawer_trigger
@@ -240,12 +240,12 @@ namespace nana
_m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey);
}
- void drawer::map(window wd, bool forced) //Copy the root buffer to screen
+ void drawer::map(window wd, bool forced, const rectangle* update_area) //Copy the root buffer to screen
{
if(wd)
{
- bedrock_type::core_window_t* iwd = reinterpret_cast(wd);
- bedrock_type::core_window_t * caret_wd = iwd->root_widget->other.attribute.root->focus;
+ auto iwd = reinterpret_cast(wd);
+ auto caret_wd = iwd->root_widget->other.attribute.root->focus;
bool owns_caret = (caret_wd && (caret_wd->together.caret) && (caret_wd->together.caret->visible()));
@@ -262,12 +262,7 @@ namespace nana
#endif
}
- if (false == edge_nimbus_renderer_t::instance().render(iwd, forced))
- {
- nana::rectangle vr;
- if(bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr))
- iwd->root_graph->paste(iwd->root, vr, vr.x, vr.y);
- }
+ edge_nimbus_renderer_t::instance().render(iwd, forced, update_area);
if(owns_caret)
{
@@ -302,9 +297,10 @@ namespace nana
void drawer::attached(widget& wd, drawer_trigger& realizer)
{
for (auto i = std::begin(mth_state_), end = std::end(mth_state_); i != end; ++i)
- *i = method_state::unknown;
+ *i = method_state::pending;
realizer_ = &realizer;
+ realizer._m_reset_overrided();
realizer.attached(wd, graphics);
}
diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp
index a8df88ac..cedd1a41 100644
--- a/source/gui/detail/linux_X11/bedrock.cpp
+++ b/source/gui/detail/linux_X11/bedrock.cpp
@@ -152,7 +152,7 @@ namespace detail
delete impl_;
}
- void bedrock::map_thread_root_buffer(core_window_t*, bool forced)
+ void bedrock::map_thread_root_buffer(core_window_t*, bool forced, const rectangle*)
{
//GUI in X11 is thread-independent, so no implementation.
}
@@ -921,11 +921,10 @@ namespace detail
if(msgwnd->visible && (msgwnd->root_graph->empty() == false))
{
nana::detail::platform_scope_guard psg;
- nana::detail::drawable_impl_type* drawer_impl = msgwnd->root_graph->handle();
- ::XCopyArea(display, drawer_impl->pixmap, reinterpret_cast(native_window), drawer_impl->context,
- xevent.xexpose.x, xevent.xexpose.y,
- xevent.xexpose.width, xevent.xexpose.height,
- xevent.xexpose.x, xevent.xexpose.y);
+ //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
+ ::nana::rectangle update_area(xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height);
+ if (!update_area.empty())
+ msgwnd->drawer.map(reinterpret_cast(msgwnd), true, &update_area);
}
break;
case KeyPress:
@@ -1011,13 +1010,11 @@ namespace detail
{
arg_keyboard argkey;
brock.get_key_state(argkey);
- auto tstop_wd = brock.wd_manager.tabstop(msgwnd, argkey.shift);
+ auto tstop_wd = brock.wd_manager.tabstop(msgwnd, !argkey.shift);
if (tstop_wd)
{
brock.wd_manager.set_focus(tstop_wd, false);
- brock.wd_manager.do_lazy_refresh(msgwnd, false);
brock.wd_manager.do_lazy_refresh(tstop_wd, true);
- root_runtime->condition.tabstop_focus_changed = true;
}
}
else if(keyboard::alt == keychar)
@@ -1066,6 +1063,7 @@ namespace detail
break;
}
case XLookupChars:
+ if (msgwnd->flags.enabled)
{
const ::nana::char_t* charbuf;
#if defined(NANA_UNICODE)
@@ -1082,6 +1080,10 @@ namespace detail
arg.ignore = false;
arg.key = charbuf[i];
+ // When tab is pressed, only tab-eating mode is allowed
+ if ((keyboard::tab == arg.key) && !(msgwnd->flags.tab & tab_type::eating))
+ continue;
+
if(context.is_alt_pressed)
{
arg.ctrl = arg.shift = false;
@@ -1130,7 +1132,9 @@ 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
+
+ if (context.platform.keychar < keyboard::os_arrow_left || keyboard::os_arrow_down < wParam)
+ brock.delay_restore(2); //Restores while key release
}
else
{
diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp
index 994bd7f4..78609ac0 100644
--- a/source/gui/detail/win32/bedrock.cpp
+++ b/source/gui/detail/win32/bedrock.cpp
@@ -328,9 +328,14 @@ namespace detail
return bedrock_object;
}
- void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced)
+ void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced, const rectangle* update_area)
{
- ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), static_cast(forced ? TRUE : FALSE));
+ auto stru = reinterpret_cast(::HeapAlloc(::GetProcessHeap(), 0, sizeof(detail::messages::map_thread)));
+ if (stru)
+ {
+ if (FALSE == ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), reinterpret_cast(stru)))
+ ::HeapFree(::GetProcessHeap(), 0, stru);
+ }
}
void interior_helper_for_menu(MSG& msg, native_window_type menu_window)
@@ -348,7 +353,7 @@ namespace detail
void bedrock::pump_event(window modal_window, bool is_modal)
{
const unsigned tid = ::GetCurrentThreadId();
- thread_context * context = this->open_thread_context(tid);
+ auto context = this->open_thread_context(tid);
if(0 == context->window_count)
{
//test if there is not a window
@@ -581,8 +586,12 @@ namespace detail
}
return true;
case nana::detail::messages::map_thread_root_buffer:
- bedrock.wd_manager.map(reinterpret_cast(wParam), (TRUE == lParam));
- ::UpdateWindow(wd);
+ {
+ auto stru = reinterpret_cast(lParam);
+ bedrock.wd_manager.map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area));
+ ::UpdateWindow(wd);
+ ::HeapFree(::GetProcessHeap(), 0, stru);
+ }
return true;
case nana::detail::messages::remote_thread_move_window:
{
@@ -1282,13 +1291,11 @@ namespace detail
::PAINTSTRUCT ps;
::HDC dc = ::BeginPaint(root_window, &ps);
- if((ps.rcPaint.left != ps.rcPaint.right) && (ps.rcPaint.bottom != ps.rcPaint.top))
- {
- ::BitBlt(dc,
- ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
- reinterpret_cast(msgwnd->root_graph->handle()->context),
- ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
- }
+ //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
+ ::nana::rectangle update_area(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
+ if (!update_area.empty())
+ msgwnd->drawer.map(reinterpret_cast(msgwnd), true, &update_area);
+
::EndPaint(root_window, &ps);
}
break;
@@ -1372,7 +1379,7 @@ namespace detail
if(msgwnd)
{
- if((wParam == 9) && (false == (msgwnd->flags.tab & tab_type::eating))) //Tab
+ if((wParam == 9) && (!msgwnd->visible || (false == (msgwnd->flags.tab & tab_type::eating)))) //Tab
{
bool is_forward = (::GetKeyState(VK_SHIFT) >= 0);
@@ -1382,7 +1389,6 @@ namespace detail
brock.wd_manager.set_focus(tstop_wd, false);
brock.wd_manager.do_lazy_refresh(msgwnd, false);
brock.wd_manager.do_lazy_refresh(tstop_wd, true);
- root_runtime->condition.tabstop_focus_changed = true;
}
}
else
@@ -1411,9 +1417,10 @@ namespace detail
break;
case WM_CHAR:
msgwnd = brock.focus();
- if(false == root_runtime->condition.tabstop_focus_changed)
+ if (msgwnd && msgwnd->flags.enabled)
{
- if(msgwnd && msgwnd->flags.enabled)
+ // When tab is pressed, only tab-eating mode is allowed
+ if ((9 != wParam) || (msgwnd->flags.tab & tab_type::eating))
{
arg_keyboard arg;
arg.evt_code = event_code::key_char;
@@ -1429,8 +1436,6 @@ namespace detail
brock.wd_manager.do_lazy_refresh(msgwnd, false);
}
}
- else
- root_runtime->condition.tabstop_focus_changed = false;
return 0;
case WM_KEYUP:
if(wParam != 18) //MUST NOT BE AN ALT
@@ -1450,7 +1455,10 @@ namespace detail
else
brock.set_keyboard_shortkey(false);
- brock.delay_restore(2); //Restores while key release
+ //Do delay restore if key is not arrow_left/right/up/down, otherwise
+ //A menubar will be restored if the item is empty(not have a menu item)
+ if (wParam < 37 || 40 < wParam)
+ brock.delay_restore(2); //Restores while key release
break;
case WM_CLOSE:
{
diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp
index e8cd1f60..c2edb173 100644
--- a/source/gui/detail/window_layout.cpp
+++ b/source/gui/detail/window_layout.cpp
@@ -24,7 +24,7 @@ namespace nana
//class window_layout
void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed)
{
- if (wd->flags.refreshing)
+ if (wd->flags.refreshing || wd->drawer.graphics.empty())
return;
if (nullptr == wd->effect.bground)
@@ -61,7 +61,6 @@ namespace nana
if (wd->parent)
{
std::vector blocks;
- blocks.reserve(10);
if (read_overlaps(wd, vr, blocks))
{
nana::point p_src;
@@ -101,7 +100,7 @@ namespace nana
// The result is a rectangle that is a visible area for its ancesters.
bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual)
{
- if (false == wd->visible) return false;
+ if (! wd->displayed()) return false;
visual = rectangle{ wd->pos_root, wd->dimension };
@@ -356,7 +355,7 @@ namespace nana
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
for (auto wd : data_sect.effects_bground_windows)
{
- if (wd == sigwd || !wd->visible || !wd->visible_parents() ||
+ if (wd == sigwd || !wd->displayed() ||
(false == overlap(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd)))
continue;
diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp
index f6053bce..d87168ef 100644
--- a/source/gui/detail/window_manager.cpp
+++ b/source/gui/detail/window_manager.cpp
@@ -357,21 +357,26 @@ namespace detail
//@brief: Delete the window handle
void window_manager::destroy(core_window_t* wd)
{
- core_window_t* parent = nullptr;
+ //Thread-Safe Required!
+ std::lock_guard lock(mutex_);
+ if (impl_->wd_register.available(wd) == false) return;
+
+ rectangle update_area(wd->pos_owner, wd->dimension);
+
+ auto parent = wd->parent;
+ if (parent)
+ utl::erase(parent->children, wd);
+
+ _m_destroy(wd);
+
+ while (parent && (parent->other.category == ::nana::category::flags::lite_widget))
{
- //Thread-Safe Required!
- std::lock_guard lock(mutex_);
- if (impl_->wd_register.available(wd) == false) return;
-
- if (wd->parent)
- {
- parent = wd->parent;
- utl::erase(wd->parent->children, wd);
- }
-
- _m_destroy(wd);
+ update_area.x += parent->pos_owner.x;
+ update_area.y += parent->pos_owner.y;
+ parent = parent->parent;
}
- update(parent, false, false);
+
+ update(parent, false, false, &update_area);
}
//destroy_handle
@@ -408,35 +413,34 @@ namespace detail
{
//Thread-Safe Required!
std::lock_guard lock(mutex_);
- if (impl_->wd_register.available(wd))
+ if (!impl_->wd_register.available(wd))
+ return false;
+
+ if(visible != wd->visible)
{
- if(visible != wd->visible)
+ native_window_type nv = nullptr;
+ switch(wd->other.category)
{
- native_window_type nv = nullptr;
- switch(wd->other.category)
- {
- case category::root_tag::value:
- nv = wd->root; break;
- case category::frame_tag::value:
- nv = wd->other.attribute.frame->container; break;
- default: //category::widget_tag, category::lite_widget_tag
- break;
- }
-
- if(visible && wd->effect.bground)
- wndlayout_type::make_bground(wd);
-
- //Don't set the visible attr of a window if it is a root.
- //The visible attr of a root will be set in the expose event.
- if(category::root_tag::value != wd->other.category)
- bedrock::instance().event_expose(wd, visible);
-
- if(nv)
- native_interface::show_window(nv, visible, wd->flags.take_active);
+ case category::root_tag::value:
+ nv = wd->root; break;
+ case category::frame_tag::value:
+ nv = wd->other.attribute.frame->container; break;
+ default: //category::widget_tag, category::lite_widget_tag
+ break;
}
- return true;
+
+ if(visible && wd->effect.bground)
+ window_layer::make_bground(wd);
+
+ //Don't set the visible attr of a window if it is a root.
+ //The visible attr of a root will be set in the expose event.
+ if(category::flags::root != wd->other.category)
+ bedrock::instance().event_expose(wd, visible);
+
+ if(nv)
+ native_interface::show_window(nv, visible, wd->flags.take_active);
}
- return false;
+ return true;
}
window_manager::core_window_t* window_manager::find_window(native_window_type root, int x, int y)
@@ -474,9 +478,6 @@ namespace detail
wd->pos_owner.y = y;
_m_move_core(wd, delta);
- if(wd->together.caret && wd->together.caret->visible())
- wd->together.caret->update();
-
auto &brock = bedrock::instance();
arg_move arg;
arg.window_handle = reinterpret_cast(wd);
@@ -503,7 +504,7 @@ namespace detail
auto & brock = bedrock::instance();
bool moved = false;
const bool size_changed = (r.width != wd->dimension.width || r.height != wd->dimension.height);
- if(wd->other.category != category::root_tag::value)
+ if(category::flags::root != wd->other.category)
{
//Move child widgets
if(r.x != wd->pos_owner.x || r.y != wd->pos_owner.y)
@@ -514,9 +515,6 @@ namespace detail
_m_move_core(wd, delta);
moved = true;
- if(wd->together.caret && wd->together.caret->visible())
- wd->together.caret->update();
-
arg_move arg;
arg.window_handle = reinterpret_cast(wd);
arg.x = r.x;
@@ -625,7 +623,7 @@ namespace detail
if(wd->effect.bground && wd->parent)
{
wd->other.glass_buffer.make(sz);
- wndlayout_type::make_bground(wd);
+ window_layer::make_bground(wd);
}
}
}
@@ -657,7 +655,7 @@ namespace detail
}
//Copy the root buffer that wnd specified into DeviceContext
- void window_manager::map(core_window_t* wd, bool forced)
+ void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area)
{
//Thread-Safe Required!
std::lock_guard lock(mutex_);
@@ -665,12 +663,12 @@ namespace detail
{
//Copy the root buffer that wd specified into DeviceContext
#if defined(NANA_LINUX)
- wd->drawer.map(reinterpret_cast(wd), forced);
+ wd->drawer.map(reinterpret_cast(wd), forced, update_area);
#elif defined(NANA_WINDOWS)
if(nana::system::this_thread_id() == wd->thread_id)
- wd->drawer.map(reinterpret_cast(wd), forced);
+ wd->drawer.map(reinterpret_cast(wd), forced, update_area);
else
- bedrock::instance().map_thread_root_buffer(wd, forced);
+ bedrock::instance().map_thread_root_buffer(wd, forced, update_area);
#endif
}
}
@@ -679,25 +677,25 @@ namespace detail
//@brief: update is used for displaying the screen-off buffer.
// Because of a good efficiency, if it is called in an event procedure and the event procedure window is the
// same as update's, update would not map the screen-off buffer and just set the window for lazy refresh
- bool window_manager::update(core_window_t* wd, bool redraw, bool forced)
+ bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area)
{
//Thread-Safe Required!
std::lock_guard lock(mutex_);
if (impl_->wd_register.available(wd) == false) return false;
- if (wd->visible && wd->visible_parents())
+ if (wd->displayed())
{
if(forced || (false == wd->belong_to_lazy()))
{
if (!wd->flags.refreshing)
{
- wndlayout_type::paint(wd, redraw, false);
- this->map(wd, forced);
+ window_layer::paint(wd, redraw, false);
+ this->map(wd, forced, update_area);
return true;
}
}
- else if(redraw)
- wndlayout_type::paint(wd, true, false);
+ else if (redraw)
+ window_layer::paint(wd, true, false);
if (wd->other.upd_state == core_window_t::update_state::lazy)
wd->other.upd_state = core_window_t::update_state::refresh;
@@ -711,8 +709,8 @@ namespace detail
std::lock_guard lock(mutex_);
//It's not worthy to redraw if visible is false
- if (impl_->wd_register.available(wd) && wd->visible && wd->visible_parents())
- wndlayout_type::paint(wd, true, true);
+ if (impl_->wd_register.available(wd) && wd->displayed())
+ window_layer::paint(wd, true, true);
}
//do_lazy_refresh
@@ -733,18 +731,19 @@ namespace detail
{
if ((wd->other.upd_state == core_window_t::update_state::refresh) || force_copy_to_screen)
{
- wndlayout_type::paint(wd, false, false);
+ window_layer::paint(wd, false, false);
this->map(wd, force_copy_to_screen);
}
else if (effects::edge_nimbus::none != wd->effect.edge_nimbus)
{
//Update the nimbus effect
- using nimbus_renderer = detail::edge_nimbus_renderer;
- nimbus_renderer::instance().render(wd, force_copy_to_screen);
+ //using nimbus_renderer = detail::edge_nimbus_renderer; //deprecated
+ //nimbus_renderer::instance().render(wd, true);
+ this->map(wd, true);
}
}
else
- wndlayout_type::paint(wd, true, false); //only refreshing if it has an invisible parent
+ window_layer::paint(wd, true, false); //only refreshing if it has an invisible parent
}
wd->other.upd_state = core_window_t::update_state::none;
return true;
@@ -764,7 +763,7 @@ namespace detail
result.make(wd->drawer.graphics.size());
result.bitblt(0, 0, wd->drawer.graphics);
- wndlayout_type::paste_children_to_graphics(wd, result);
+ window_layer::paste_children_to_graphics(wd, result);
return true;
}
@@ -773,7 +772,7 @@ namespace detail
//Thread-Safe Required!
std::lock_guard lock(mutex_);
return (impl_->wd_register.available(wd) ?
- wndlayout_type::read_visual_rectangle(wd, r) :
+ window_layer::read_visual_rectangle(wd, r) :
false);
}
@@ -1002,6 +1001,39 @@ namespace detail
}
}
+
+ // preconditions of get_tabstop: tabstop is not empty and at least one window is visible
+ window_manager::core_window_t* get_tabstop(window_manager::core_window_t* wd, bool forward)
+ {
+ auto & tabs = wd->root_widget->other.attribute.root->tabstop;
+
+ if (forward)
+ {
+ if (detail::tab_type::none == wd->flags.tab)
+ return (tabs.front());
+ else if (detail::tab_type::tabstop & wd->flags.tab)
+ {
+ auto end = tabs.cend();
+ auto i = std::find(tabs.cbegin(), end, wd);
+ if (i != end)
+ {
+ ++i;
+ window_manager::core_window_t* ts = (i != end ? (*i) : tabs.front());
+ return (ts != wd ? ts : 0);
+ }
+ else
+ return tabs.front();
+ }
+ }
+ else if (tabs.size() > 1) //at least 2 elments in tabs are required when moving backward.
+ {
+ auto i = std::find(tabs.cbegin(), tabs.cend(), wd);
+ if (i != tabs.cend())
+ return (tabs.cbegin() == i ? tabs.back() : *(i - 1));
+ }
+ return nullptr;
+ }
+
auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t*
{
//Thread-Safe Required!
@@ -1013,21 +1045,30 @@ namespace detail
if (tabs.empty())
return nullptr;
- if ((detail::tab_type::none == wd->flags.tab) || !(detail::tab_type::tabstop & wd->flags.tab))
- return (forward ? tabs.front() : tabs.back());
-
- auto i = std::find(tabs.cbegin(), tabs.cend(), wd);
- if (tabs.cend() == i)
- return (forward ? tabs.front() : tabs.back());
-
- if (forward)
+ bool precondition = false;
+ for (auto & tab_wd : tabs)
{
- ++i;
- core_window_t* ts = (i != tabs.cend() ? (*i) : tabs.front());
- return (ts != wd ? ts : nullptr);
+ if (tab_wd->displayed())
+ {
+ precondition = true;
+ break;
+ }
}
-
- return (tabs.cbegin() == i ? tabs.back() : *(i - 1));
+
+ if (precondition)
+ {
+ auto new_stop = get_tabstop(wd, forward);
+
+ while (new_stop && (wd != new_stop))
+ {
+ if (new_stop->flags.enabled && new_stop->displayed())
+ return new_stop;
+
+ new_stop = get_tabstop(new_stop, forward);
+ }
+ }
+
+ return nullptr;
}
void window_manager::remove_trash_handle(unsigned tid)
@@ -1040,7 +1081,7 @@ namespace detail
//Thread-Safe Required!
std::lock_guard lock(mutex_);
if (impl_->wd_register.available(wd))
- return wndlayout_type::enable_effects_bground(wd, enabled);
+ return window_layer::enable_effects_bground(wd, enabled);
return false;
}
@@ -1224,18 +1265,9 @@ namespace detail
if (!established)
{
- if (effects::edge_nimbus::none != wd->effect.edge_nimbus)
- {
- auto & cont = root_attr->effects_edge_nimbus;
- for (auto i = cont.begin(); i != cont.end(); ++i)
- {
- if (i->window == wd)
- {
- cont.erase(i);
- break;
- }
- }
- }
+ //remove the window from edge nimbus effect when it is destroying
+ using edge_nimbus = detail::edge_nimbus_renderer;
+ edge_nimbus::instance().erase(wd);
}
else if (pa_root_attr != root_attr)
{
@@ -1347,7 +1379,7 @@ namespace detail
_m_disengage(wd, nullptr);
- wndlayout_type::enable_effects_bground(wd, false);
+ window_layer::enable_effects_bground(wd, false);
wd->drawer.detached();
wd->widget_notifier->destroy();
@@ -1371,7 +1403,12 @@ namespace detail
if(wd->other.category != category::root_tag::value) //A root widget always starts at (0, 0) and its childs are not to be changed
{
wd->pos_root += delta;
- if(wd->other.category == category::frame_tag::value)
+ if (category::flags::frame != wd->other.category)
+ {
+ if (wd->together.caret && wd->together.caret->visible())
+ wd->together.caret->update();
+ }
+ else
native_interface::move_window(wd->other.attribute.frame->container, wd->pos_root.x, wd->pos_root.y);
for (auto child : wd->children)
diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp
index 1ed89214..327ffff9 100644
--- a/source/gui/programming_interface.cpp
+++ b/source/gui/programming_interface.cpp
@@ -722,7 +722,7 @@ namespace API
if(restrict::window_manager.available(iwd) && (iwd->flags.enabled != enabled))
{
iwd->flags.enabled = enabled;
- restrict::window_manager.update(iwd, true, false);
+ restrict::window_manager.update(iwd, true, true);
if(category::flags::root == iwd->other.category)
restrict::interface_type::enable_window(iwd->root, enabled);
}
diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp
index f1c24564..a43c47b4 100644
--- a/source/gui/widgets/button.cpp
+++ b/source/gui/widgets/button.cpp
@@ -151,7 +151,7 @@ namespace nana{ namespace drawerbase
void trigger::key_char(graph_reference, const arg_keyboard& arg)
{
- if(arg.key == static_cast(keyboard::enter))
+ if (static_cast(keyboard::enter) == arg.key || static_cast(keyboard::space) == arg.key)
emit_click();
}
diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp
index 5f8498f7..9dd59ad1 100644
--- a/source/gui/widgets/combox.cpp
+++ b/source/gui/widgets/combox.cpp
@@ -18,6 +18,8 @@
#include
#include
+#include
+
namespace nana
{
arg_combox::arg_combox(combox& wdg): widget(wdg)
diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp
index a83485bf..2507c2e7 100644
--- a/source/gui/widgets/listbox.cpp
+++ b/source/gui/widgets/listbox.cpp
@@ -402,18 +402,20 @@ namespace nana
return{};
}
- void create(nana::string&& text, unsigned pixels)
+ size_type create(nana::string&& text, unsigned pixels)
{
cont_.emplace_back(std::move(text), pixels, static_cast(cont_.size()));
+ return cont_.back().index;
}
void item_width(size_type pos, unsigned width)
{
for(auto & m : cont_)
- {
if(m.index == pos)
+ {
m.pixels = width;
- }
+ return;
+ }
}
unsigned item_width(size_type pos) const
@@ -1606,31 +1608,7 @@ namespace nana
}
/// set all items in cat to selection sel, emiting events, actualizing last_selected_abs, but not check for single_selection_
- bool categ_selected(size_type cat, bool sel)
- {
- bool changed = false;
- auto & items = _m_at(cat)->items;
-
- index_pair pos(cat, 0);
- for(auto & m : items)
- {
- if(m.flags.selected != sel)
- {
- m.flags.selected = sel;
-
- arg_listbox arg{ item_proxy(ess_, pos), sel };
- wd_ptr()->events().selected.emit(arg);
- changed = true;
-
- 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;
- }
- return changed;
- }
+ void categ_selected(size_type cat, bool sel);
void reverse_categ_selected(size_type categ)
{
@@ -1658,9 +1636,22 @@ namespace nana
/// absolute position of the last displayed item
index_pair last_displ() const
{
- return absolute ( last_displ() );
+ return absolute ( last() );
}
+ /// can be used as the absolute position of the first absolute item, or as the display pos of the first displayed item
+ index_pair first() const
+ {
+ index_pair fst{0,npos};
+ good_item(fst,fst);
+ return fst;
+ }
+ /// absolute position of the first displayed item
+ index_pair first_displ() const
+ {
+ return absolute ( first() );
+ }
+
bool good(size_type cat) const
{
return (cat < list_.size());
@@ -1670,32 +1661,32 @@ namespace nana
{
return ((pos.cat < list_.size()) && (pos.item < size_item(pos.cat)));
}
-
+ /// if good return the same item (in arg item), or just the next cat and true, but If fail return false
bool good_item(index_pair pos, index_pair& item) const
{
if (!good(pos.cat))
- return false;
+ return false; // cat out of range
if (pos.is_category())
{
- item = pos;
- if (0 == pos.cat)
- item.item = 0;
-
- return true;
+ item = pos; // return the cat self
+ if (0 == pos.cat) // but for cat 0 return first item
+ item.item = 0; // let check this is good
+ else
+ return true;
}
- auto i = _m_at(pos.cat);
+ auto i = _m_at(pos.cat); // pos is not a cat and i point to it cat
if (pos.item < i->items.size())
{
- item = pos;
+ item = pos; // good item, return it
return true;
}
- if (++i == list_.end())
+ if (++i == list_.end()) // item out of range and no more cat
return false;
- item.cat = pos.cat + 1;
+ item.cat = pos.cat + 1; // select the next cat
item.item = npos;
return true;
}
@@ -1703,7 +1694,7 @@ namespace nana
///Translate relative position (position in display) into absolute position (original data order)
size_type absolute(const index_pair& display_pos) const
{
- if(sorted_index_ == npos)
+ if(sorted_index_ == npos || display_pos.item == npos)
return display_pos.item ;
auto & catobj = *_m_at(display_pos.cat);
@@ -2202,7 +2193,7 @@ namespace nana
}
else
{
- new_where.second = (y - header_visible_px() + 1) / item_size;
+ new_where.second = ((y + 1) - header_visible_px()) / item_size; // y>1 !
new_where.first = parts::lister;
if(checkable)
{
@@ -2324,6 +2315,27 @@ namespace nana
}
}
+ unsigned auto_width(size_type pos, unsigned max = 3000) /// \todo introduce parametr max_header_width
+ {
+ unsigned max_w{ 0 };
+ for (const auto &cat : lister.cat_container())
+ for (const auto &it : cat.items)
+ {
+ if (pos >= it.cells.size()) continue;
+ // precalcule text geometry
+ unsigned ts = static_cast (graph->text_extent_size(it.cells[pos].text).width);
+ if (max_w < ts)
+ max_w = ts;
+ }
+ if (!max_w) return 0;
+
+ unsigned ext_w = scheme_ptr->ext_w;
+ if (pos == 0 && checkable) // only before the first column (display_order=0 ?)
+ ext_w += 18;
+ header.item_width(pos, max_w + ext_w + 1 < max ? max_w + ext_w + 1 : max);
+ return max_w;
+ }
+
inline_pane * open_inline(pat::abstract_factory* factory, inline_indicator* indicator)
{
std::unique_ptr pane_ptr;
@@ -2494,7 +2506,7 @@ namespace nana
}
}
- nana::string es_lister::to_string(const export_options& exp_opt) const
+ nana::string es_lister::to_string(const export_options& exp_opt) const
{
nana::string list_str;
bool first{true};
@@ -2515,6 +2527,17 @@ namespace nana
return list_str ;
}
+ void es_lister::categ_selected(size_type cat, bool sel)
+ {
+ cat_proxy cpx{ess_,cat};
+ for (item_proxy &it : cpx )
+ {
+ if (it.selected() != sel)
+ it.select(sel);
+ }
+
+ last_selected_abs = last_selected_dpl = index_pair {cat, npos};
+ }
class drawer_header_impl
{
@@ -3450,6 +3473,14 @@ namespace nana
void trigger::dbl_click(graph_reference graph, const arg_mouse&)
{
+ if (essence_->pointer_where.first == essence_t::parts::header)
+ if (cursor::size_we == essence_->lister.wd_ptr()->cursor())
+ {
+ if (essence(). auto_width(drawer_header_->item_spliter() )) // ? in order
+ essence().update();
+ return;
+ }
+
if (essence_->pointer_where.first != essence_t::parts::lister)
return;
@@ -3518,21 +3549,35 @@ namespace nana
if (! scrl.make_page_scroll(!up))
return;
essence_->lister.select_for_all(false);
- if (up)
- item_proxy {essence_, essence_->scroll_y_abs()}.select(true);
- else
- {
- index_pair idx{essence_->scroll_y_dpl()};
+
+ index_pair idx{essence_->scroll_y_dpl()};
+ if (!up)
essence_->lister.forward(idx, scrl.range()-1, idx);
- item_proxy::from_display(essence_,idx).select(true);
- }
+
+ if (idx.is_item())
+ item_proxy::from_display(essence_, idx).select(true);
+ else
+ if(!essence_->lister.single_selection())
+ essence_->lister.categ_selected(idx.cat, true);
+
+ essence_->trace_last_selected_item ();
+
break;
}
case keyboard::os_home:
+ {
essence_->lister.select_for_all(false);
- item_proxy::from_display(essence_, {0,0}).select(true);
+
+ index_pair frst{essence_->lister.first()};
+ if (frst.is_item())
+ item_proxy::from_display(essence_, frst).select(true);
+ else
+ if(!essence_->lister.single_selection())
+ essence_->lister.categ_selected(frst.cat, 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);
@@ -3584,7 +3629,7 @@ namespace nana
{
auto i = ess_->lister.cat_container().begin();
std::advance(i, pos.cat);
- cat_ = &(*i);
+ cat_ = &(*i); // what is pos is a cat?
}
}
@@ -3617,6 +3662,7 @@ namespace nana
m.flags.checked = ck;
arg_listbox arg{*this, ck};
ess_->lister.wd_ptr()->events().checked.emit(arg);
+ ess_->update();
}
return *this;
}
@@ -3629,7 +3675,7 @@ namespace nana
/// 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); // a ref to the real item
+ auto & m = cat_->items.at(pos_.item); // a ref to the real item // what is pos is a cat?
if(m.flags.selected == s) return *this; // ignore if no change
m.flags.selected = s; // actually change selection
@@ -3646,6 +3692,7 @@ namespace nana
ess_->update();
+ ess_->update();
return *this;
}
@@ -3865,6 +3912,24 @@ namespace nana
}
}
+ cat_proxy & cat_proxy::select(bool sel)
+ {
+ for (item_proxy &it : *this )
+ it.select(sel);
+
+ ess_->lister.last_selected_abs =
+ ess_->lister.last_selected_dpl = index_pair {this->pos_, npos};
+
+ return *this;
+ }
+ bool cat_proxy::selected() const
+ {
+ for (item_proxy &it : *this )
+ if (!it.selected())
+ return false;
+ return true;
+ }
+
auto cat_proxy::columns() const -> size_type
{
return ess_->header.cont().size();
@@ -3907,6 +3972,11 @@ namespace nana
//Behavior of a container
item_proxy cat_proxy::begin() const
{
+ auto i = ess_->lister.cat_container().begin();
+ std::advance(i, pos_);
+ if (i->items.empty())
+ return end();
+
return item_proxy(ess_, index_pair(pos_, 0));
}
@@ -4121,11 +4191,12 @@ namespace nana
_m_ess().set_auto_draw(ad);
}
- void listbox::append_header(nana::string text, unsigned width)
+ listbox::size_type listbox::append_header(nana::string text, unsigned width)
{
auto & ess = _m_ess();
- ess.header.create(std::move(text), width);
+ listbox::size_type index = ess.header.create(std::move(text), width);
ess.update();
+ return index;
}
listbox& listbox::header_width(size_type pos, unsigned pixels)
@@ -4135,6 +4206,13 @@ namespace nana
ess.update();
return *this;
}
+ unsigned listbox::auto_width(size_type pos, unsigned max)
+ {
+ auto & ess = _m_ess();
+ unsigned max_w = ess.auto_width(pos, max);
+ ess.update();
+ return max_w;
+ }
unsigned listbox::header_width(size_type pos) const
{
diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp
index 9f6ec24c..8691c67f 100644
--- a/source/gui/widgets/menu.cpp
+++ b/source/gui/widgets/menu.cpp
@@ -114,7 +114,7 @@ namespace nana
{
if(at.item_state == state::active)
{
- graph.rectangle(r, false, {0xa8, 0xd8, 0xeb});
+ graph.rectangle(r, false, static_cast(0xa8d8eb));
nana::point points[4] = {
nana::point(r.x, r.y),
nana::point(r.x + r.width - 1, r.y),
@@ -144,9 +144,9 @@ namespace nana
}
}
- void item_image(graph_reference graph, const nana::point& pos, const paint::image& img)
+ void item_image(graph_reference graph, const nana::point& pos, unsigned image_px, const paint::image& img)
{
- img.paste(graph, pos.x, pos.y);
+ img.stretch(rectangle{ img.size() }, graph, rectangle{ pos, ::nana::size(image_px, image_px) });
}
void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at)
@@ -200,35 +200,35 @@ namespace nana
void checked(std::size_t index, bool check)
{
- if(root_.items.size() > index)
+ if (root_.items.size() <= index)
+ return;
+
+ item_type & m = root_.items[index];
+ if(check && (checks::option == m.style))
{
- item_type & m = root_.items[index];
- if(check && (checks::option == m.style))
+ if(index)
{
- if(index)
+ std::size_t i = index;
+ do
{
- std::size_t i = index;
- do
- {
- item_type& el = root_.items[--i];
- if(el.flags.splitter) break;
-
- if(checks::option == el.style)
- el.flags.checked = false;
- }while(i);
- }
-
- for(std::size_t i = index + 1; i < root_.items.size(); ++i)
- {
- item_type & el = root_.items[i];
+ item_type& el = root_.items[--i];
if(el.flags.splitter) break;
if(checks::option == el.style)
el.flags.checked = false;
- }
+ }while(i);
+ }
+
+ for(std::size_t i = index + 1; i < root_.items.size(); ++i)
+ {
+ item_type & el = root_.items[i];
+ if(el.flags.splitter) break;
+
+ if(checks::option == el.style)
+ el.flags.checked = false;
}
- m.flags.checked = check;
}
+ m.flags.checked = check;
}
menu_type& data()
@@ -304,7 +304,7 @@ namespace nana
: public drawer_trigger
{
public:
- typedef menu_item_type::item_proxy item_proxy;
+ using item_proxy = menu_item_type::item_proxy;
renderer_interface * renderer;
@@ -330,12 +330,12 @@ namespace nana
detail_.monitor_pos = API::cursor_position();
}
- void mouse_move(graph_reference, const arg_mouse& arg)
+ void mouse_move(graph_reference graph, const arg_mouse& arg)
{
state_.nullify_mouse = false;
- if(track_mouse(arg.pos.x, arg.pos.y))
+ if(track_mouse(arg.pos))
{
- draw();
+ refresh(graph);
API::lazy_refresh();
}
}
@@ -350,9 +350,70 @@ namespace nana
state_.nullify_mouse = false;
}
- void refresh(graph_reference)
+ void refresh(graph_reference graph)
{
- draw();
+ if (nullptr == menu_) return;
+
+ _m_adjust_window_size();
+
+ renderer->background(graph, *widget_);
+
+ const unsigned item_h_px = _m_item_height();
+ const unsigned image_px = item_h_px - 2;
+ nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px);
+
+ unsigned strpixels = item_r.width - 60;
+
+ int text_top_off = (item_h_px - graph.text_extent_size(STR("jh({[")).height) / 2;
+
+ std::size_t pos = 0;
+ for (auto & m : menu_->items)
+ {
+ 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 + static_cast(item_h_px - image_px) / 2 - 1), image_px, 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;
+
+ ++pos;
+ }
}
std::size_t active() const
@@ -411,21 +472,21 @@ namespace nana
state_.active = pos;
state_.sub_window = false;
- draw();
+ refresh(*graph_);
return true;
}
return false;
}
- bool track_mouse(int x, int y)
+ bool track_mouse(const ::nana::point& pos)
{
- if(state_.nullify_mouse == false)
+ if (!state_.nullify_mouse)
{
- std::size_t index = _m_get_index_by_pos(x, y);
- if(index != state_.active)
+ std::size_t index = _m_get_index_by_pos(pos.x, pos.y);
+ if (index != state_.active)
{
- if((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window)
+ if ((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window)
return false;
state_.active = (index != npos && menu_->items.at(index).flags.splitter) ? npos : index;
@@ -433,6 +494,7 @@ namespace nana
return true;
}
}
+
return false;
}
@@ -451,29 +513,35 @@ namespace nana
state_.sub_window = subw;
}
- menu_type* retrive_sub_menu(nana::point& pos, std::size_t interval) const
+ menu_type* get_sub(nana::point& pos, unsigned long& tmstamp) const
{
- if(state_.active != npos && (nana::system::timestamp() - state_.active_timestamp >= interval))
+ if (npos == state_.active)
+ return nullptr;
+
+ auto sub = menu_->items.at(state_.active).sub_menu;
+ if (sub)
{
- pos.x = graph_->width() - 2;
+ pos.x = static_cast(graph_->width()) - 2;
pos.y = 2;
- std::size_t index = 0;
- for(auto & m : menu_->items)
+ auto index = state_.active;
+ for (auto & m : menu_->items)
{
- if(false == m.flags.splitter)
+ if (m.flags.splitter)
{
- if(index == state_.active)
- break;
-
- pos.y += _m_item_height() + 1;
- }
- else
pos.y += 2;
+ continue;
+ }
- ++index;
+ if (0 == index)
+ break;
+
+ pos.y += _m_item_height() + 1;
+ --index;
}
- return (menu_->items.at(state_.active).sub_menu);
+
+ tmstamp = state_.active_timestamp;
+ return sub;
}
return nullptr;
}
@@ -498,8 +566,7 @@ namespace nana
state_.active = index;
state_.active_timestamp = nana::system::timestamp();
- draw();
- API::update_window(*widget_);
+ API::refresh_window(*widget_);
return 2;
}
else if(m.flags.enabled)
@@ -514,71 +581,6 @@ namespace nana
}
return 0;
}
-
- void draw() const
- {
- if(nullptr == menu_) return;
-
- _m_adjust_window_size();
-
- renderer->background(*graph_, *widget_);
-
- const unsigned item_h_px = _m_item_height();
- nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px);
-
- unsigned strpixels = item_r.width - 60;
-
- int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2;
-
- std::size_t pos = 0;
- for(auto & m : menu_->items)
- {
- 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 });
- }
- }
-
- 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:
static renderer_interface::attr _m_make_renderer_attr(bool active, const menu_item_type & m)
{
@@ -683,10 +685,10 @@ namespace nana
struct state
{
- std::size_t active;
- unsigned long active_timestamp;
- unsigned long sub_window: 1;
- unsigned long nullify_mouse: 1;
+ std::size_t active;
+ unsigned active_timestamp;
+ bool sub_window: 1;
+ bool nullify_mouse: 1;
}state_;
struct widget_detail
@@ -699,15 +701,18 @@ namespace nana
class menu_window
: public widget_object
{
- typedef menu_drawer drawer_type;
- typedef widget_object base_type;
+ using drawer_type = menu_drawer;
+ using base_type = widget_object;
public:
- typedef menu_builder::item_type item_type;
+ using item_type = menu_builder::item_type;
- menu_window(window wd, const point& pos, renderer_interface * rdptr)
+
+ menu_window(window wd, bool is_wd_parent_menu, const point& pos, renderer_interface * rdptr)
+ //add a is_wd_parent_menu to determine whether the menu wants the focus.
+ //if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed
: base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald()),
- want_focus_(nullptr == wd || (API::focus_window() != wd)),
- event_focus_(nullptr)
+ want_focus_{ (!wd) || ((!is_wd_parent_menu) && (API::focus_window() != wd)) },
+ event_focus_{ nullptr }
{
caption(STR("nana menu window"));
get_drawer_trigger().close_menu_tree([this]{ this->_m_close_all(); });
@@ -718,7 +723,19 @@ namespace nana
submenu_.child = submenu_.parent = nullptr;
submenu_.object = nullptr;
- _m_make_mouse_event();
+ state_.mouse_pos = API::cursor_position();
+ events().mouse_move.connect_unignorable([this]{
+ nana::point pos = API::cursor_position();
+ if (pos != state_.mouse_pos)
+ {
+ menu_window * root = this;
+ while (root->submenu_.parent)
+ root = root->submenu_.parent;
+ root->state_.auto_popup_submenu = true;
+
+ state_.mouse_pos = pos;
+ }
+ });
}
void popup(menu_type& menu, bool owner_menubar)
@@ -745,13 +762,19 @@ namespace nana
_m_key_down(arg);
});
- events().mouse_up.connect_unignorable([this]{
- pick();
+ events().mouse_down.connect_unignorable([this](const arg_mouse& arg)
+ {
+ this->_m_open_sub(0); //Try to open submenu immediately
+ });
+
+ events().mouse_up.connect_unignorable([this](const arg_mouse& arg){
+ if (arg.left_button)
+ pick();
});
timer_.interval(100);
timer_.elapse([this]{
- this->_m_check_repeatly();
+ this->_m_open_sub(500); //Try to open submenu
});
timer_.start();
@@ -797,29 +820,27 @@ namespace nana
bool submenu(bool enter)
{
- menu_window * object = this;
- while (object->submenu_.child)
- object = object->submenu_.child;
+ menu_window * menu_wd = this;
+ while (menu_wd->submenu_.child)
+ menu_wd = menu_wd->submenu_.child;
state_.auto_popup_submenu = false;
- if (enter)
+ if (!enter)
{
- if (object->submenu_.parent)
+ if (menu_wd->submenu_.parent)
{
- auto & sub = object->submenu_.parent->submenu_;
+ auto & sub = menu_wd->submenu_.parent->submenu_;
sub.child = nullptr;
sub.object = nullptr;
- object->close();
+ menu_wd->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);
+ return menu_wd->_m_manipulate_sub(0, true);
}
int send_shortkey(nana::char_t key)
@@ -965,63 +986,51 @@ namespace nana
}
}
- void _m_make_mouse_event()
+ bool _m_manipulate_sub(unsigned long delay_ms, bool forced)
{
- state_.mouse_pos = API::cursor_position();
- events().mouse_move.connect_unignorable([this]{
- _m_mouse_event();
- });
- }
+ auto & drawer = get_drawer_trigger();
+ ::nana::point pos;
+ unsigned long tmstamp;
- void _m_mouse_event()
- {
- nana::point pos = API::cursor_position();
- if(pos != state_.mouse_pos)
+ auto menu_ptr = drawer.get_sub(pos, tmstamp);
+
+ if (menu_ptr == submenu_.object)
+ return false;
+
+ if (menu_ptr && (::nana::system::timestamp() - tmstamp < delay_ms))
+ return false;
+
+ if (submenu_.object && (menu_ptr != submenu_.object))
{
- menu_window * root = this;
- while(root->submenu_.parent)
- root = root->submenu_.parent;
- root->state_.auto_popup_submenu = true;
-
- state_.mouse_pos = pos;
- }
- }
-
- bool _m_show_submenu(menu_type* sbm, nana::point pos, bool forced)
- {
- auto & mdtrigger = get_drawer_trigger();
- if(submenu_.object && (sbm != submenu_.object))
- {
- mdtrigger.set_sub_window(false);
+ drawer.set_sub_window(false);
submenu_.child->close();
submenu_.child = nullptr;
submenu_.object = nullptr;
}
- if(sbm)
+ if (menu_ptr)
{
menu_window * root = this;
- while(root->submenu_.parent)
+ while (root->submenu_.parent)
root = root->submenu_.parent;
- if((submenu_.object == nullptr) && sbm && (forced || root->state_.auto_popup_submenu))
+ if ((submenu_.object == nullptr) && menu_ptr && (forced || root->state_.auto_popup_submenu))
{
- sbm->item_pixels = mdtrigger.data()->item_pixels;
- sbm->gaps = mdtrigger.data()->gaps;
- pos.x += sbm->gaps.x;
- pos.y += sbm->gaps.y;
+ menu_ptr->item_pixels = drawer.data()->item_pixels;
+ menu_ptr->gaps = drawer.data()->gaps;
+ pos += menu_ptr->gaps;
- menu_window & mwnd = form_loader()(handle(), pos, mdtrigger.renderer);
+ menu_window & mwnd = form_loader()(handle(), true, pos, drawer.renderer);
mwnd.state_.self_submenu = true;
- submenu_.child = & mwnd;
+ submenu_.child = &mwnd;
submenu_.child->submenu_.parent = this;
- submenu_.object = sbm;
+ submenu_.object = menu_ptr;
API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none);
- mwnd.popup(*sbm, state_.owner_menubar);
- mdtrigger.set_sub_window(true);
- if(forced)
+ mwnd.popup(*menu_ptr, state_.owner_menubar);
+ drawer.set_sub_window(true);
+ if (forced)
mwnd.goto_next(true);
return true;
@@ -1030,17 +1039,16 @@ namespace nana
return false;
}
- void _m_check_repeatly()
+ void _m_open_sub(unsigned delay_ms) //check_repeatly
{
if(state_.auto_popup_submenu)
{
- nana::point pos = API::cursor_position();
+ auto pos = API::cursor_position();
- drawer_type& drawer = get_drawer_trigger();
API::calc_window_point(handle(), pos);
- drawer.track_mouse(pos.x, pos.y);
- menu_type* sbm = drawer.retrive_sub_menu(pos, 500);
- _m_show_submenu(sbm, pos, false);
+ get_drawer_trigger().track_mouse(pos);
+
+ _m_manipulate_sub(delay_ms, false);
}
}
private:
@@ -1293,7 +1301,7 @@ namespace nana
{
close();
- impl_->uiobj = &(form_loader()(wd, point(x, y), &(*impl_->mbuilder.renderer())));
+ impl_->uiobj = &(form_loader()(wd, false, point(x, y), &(*impl_->mbuilder.renderer())));
impl_->uiobj->events().destroy.connect_unignorable([this]{
impl_->uiobj = nullptr;
if (impl_->destroy_answer)
diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp
index 3baaf0d0..7ad4584a 100644
--- a/source/gui/widgets/progress.cpp
+++ b/source/gui/widgets/progress.cpp
@@ -89,6 +89,15 @@ namespace nana
{
return unknown_;
}
+ bool trigger::stoped() const
+ {
+ return stop_;
+ }
+ bool trigger::stop(bool s)
+ {
+ std::swap(s,stop_);
+ return s;
+ }
void trigger::refresh(graph_reference)
{
@@ -197,5 +206,13 @@ namespace nana
{
return get_drawer_trigger().unknown();
}
+ bool progress::stop(bool s)
+ {
+ return get_drawer_trigger().stop(s);
+ }
+ bool progress::stoped() const
+ {
+ return get_drawer_trigger().stoped();
+ }
//end class progress
}//end namespace nana
diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp
index a7f05a56..6cc33b51 100644
--- a/source/gui/widgets/skeletons/text_editor.cpp
+++ b/source/gui/widgets/skeletons/text_editor.cpp
@@ -1482,6 +1482,8 @@ namespace nana{ namespace widgets
behavior_->pre_calc_lines(width_pixels());
_m_scrollbar();
+
+ move_caret(points_.caret);
return true;
}
diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp
index 81b75c7f..980a80ac 100644
--- a/source/gui/widgets/toolbar.cpp
+++ b/source/gui/widgets/toolbar.cpp
@@ -11,10 +11,10 @@
*/
#include
-#include
-#include
#include
+#include
+
namespace nana
{
arg_toolbar::arg_toolbar(toolbar& tbar, std::size_t btn)
@@ -25,13 +25,6 @@ namespace nana
{
namespace toolbar
{
- struct listitem
- {
- nana::string text;
- nana::paint::image image;
- bool enable;
- };
-
struct item_type
{
enum kind{ button, container};
@@ -43,28 +36,23 @@ namespace nana
unsigned pixels{0};
nana::size textsize;
bool enable{true};
- window other{nullptr};
kind type;
- std::function answer;
- std::vector children;
item_type(const nana::string& text, const nana::paint::image& img, kind type)
:text(text), image(img), type(type)
{}
};
- class container
- {
- container(const container&) = delete;
- container& operator=(const container&) = delete;
- public:
- typedef std::vector::size_type size_type;
- typedef std::vector::iterator iterator;
- typedef std::vector::const_iterator const_iterator;
- container() = default;
- ~container()
+
+ class item_container
+ {
+ public:
+ using container_type = std::vector;
+ using size_type = container_type::size_type;
+
+ ~item_container()
{
for(auto ptr : cont_)
delete ptr;
@@ -98,7 +86,7 @@ namespace nana
cont_.push_back(nullptr);
}
- void push_back()
+ void separate()
{
cont_.push_back(nullptr);
}
@@ -108,35 +96,17 @@ namespace nana
return cont_.size();
}
- item_type* at(size_type n)
+ container_type& container()
{
- if(n < cont_.size())
- return cont_[n];
-
- throw std::out_of_range("toolbar: bad index!");
+ return cont_;
}
- iterator begin()
+ item_type * at(size_type pos)
{
- return cont_.begin();
- }
-
- iterator end()
- {
- return cont_.end();
- }
-
- const_iterator begin() const
- {
- return cont_.cbegin();
- }
-
- const_iterator end() const
- {
- return cont_.cend();
+ return cont_.at(pos);
}
private:
- std::vector cont_;
+ container_type cont_;
};
class item_renderer
@@ -152,38 +122,36 @@ namespace nana
void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state)
{
//draw background
- if(state != state_t::normal)
- graph.rectangle({ x, y, width, height }, false, { 0x33, 0x99, 0xFF });
- switch(state)
+ if (state != state_t::normal)
{
- case state_t::highlighted:
- graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0xC0, 0xDD, 0xFC }, true);
- break;
- case state_t::selected:
- graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0x99, 0xCC, 0xFF }, true);
- default: break;
+ nana::rectangle background_r(x, y, width, height);
+ graph.rectangle(background_r, false, static_cast(0x3399FF));
+
+ if (state_t::highlighted == state || state_t::selected == state)
+ graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast(state_t::selected == state ? 0x99CCFF : 0xC0DDFC), true);
}
- if(item.image.empty() == false)
+ if(!item.image.empty())
{
- nana::size size = item.image.size();
- if(size.width > scale) size.width = scale;
- if(size.height > scale) size.height = scale;
+ auto imgsize = item.image.size();
+
+ if (imgsize.width > scale) imgsize.width = scale;
+ if (imgsize.height > scale) imgsize.height = scale;
nana::point pos(x, y);
- pos.x += static_cast(scale + extra_size - size.width) / 2;
- pos.y += static_cast(height - size.height) / 2;
+ pos.x += static_cast(scale + extra_size - imgsize.width) / 2;
+ pos.y += static_cast(height - imgsize.height) / 2;
- item.image.paste(::nana::rectangle{ size }, graph, pos);
+ item.image.paste(::nana::rectangle{ imgsize }, graph, pos);
if(item.enable == false)
{
- nana::paint::graphics gh(size);
- gh.bitblt(::nana::rectangle{ size }, graph, pos);
+ nana::paint::graphics gh(imgsize);
+ gh.bitblt(::nana::rectangle{ imgsize }, graph, pos);
gh.rgb_to_wb();
gh.paste(graph, pos.x, pos.y);
}
else if(state == state_t::normal)
- graph.blend(nana::rectangle(pos, size), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25);
+ graph.blend(nana::rectangle(pos, imgsize), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25);
x += scale;
width -= scale;
@@ -204,13 +172,15 @@ namespace nana
struct drawer::drawer_impl_type
{
- event_handle event_size{nullptr};
+ event_handle event_size{ nullptr };
+ paint::graphics* graph_ptr{ nullptr };
+
unsigned scale{16};
bool textout{false};
size_type which{npos};
item_renderer::state_t state{item_renderer::state_t::normal};
- container cont;
+ item_container items;
::nana::tooltip tooltip;
};
@@ -225,116 +195,118 @@ namespace nana
delete impl_;
}
- void drawer::append(const nana::string& text, const nana::paint::image& img)
+ item_container& drawer::items() const
{
- impl_->cont.push_back(text, img);
- }
-
- void drawer::append()
- {
- impl_->cont.push_back();
- }
-
- bool drawer::enable(drawer::size_type n) const
- {
- if(impl_->cont.size() > n)
- {
- auto item = impl_->cont.at(n);
- return (item && item->enable);
- }
- return false;
- }
-
- bool drawer::enable(size_type n, bool eb)
- {
- if(impl_->cont.size() > n)
- {
- item_type * item = impl_->cont.at(n);
- if(item && (item->enable != eb))
- {
- item->enable = eb;
- return true;
- }
- }
- return false;
+ return impl_->items;
}
void drawer::scale(unsigned s)
{
impl_->scale = s;
- for(auto m : impl_->cont)
- _m_fill_pixels(m, true);
+ for(auto m : impl_->items.container())
+ _m_calc_pixels(m, true);
}
- void drawer::refresh(graph_reference)
+ void drawer::refresh(graph_reference graph)
{
- _m_draw();
+ int x = 2, y = 2;
+
+ auto bgcolor = API::bgcolor(widget_->handle());
+ graph.set_text_color(bgcolor);
+ graph.gradual_rectangle(rectangle{ graph.size() }, bgcolor.blend(colors::white, 0.9), bgcolor.blend(colors::black, 0.95), true);
+
+ item_renderer ir(graph, impl_->textout, impl_->scale, bgcolor);
+ size_type index = 0;
+
+ for (auto item : impl_->items.container())
+ {
+ if (item)
+ {
+ _m_calc_pixels(item, false);
+ ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal));
+ x += item->pixels;
+ }
+ else
+ {
+ x += 2;
+ graph.line({ x, y + 2 }, { x, y + static_cast(impl_->scale + ir.extra_size) - 4 }, static_cast(0x808080));
+ x += 4;
+ }
+ ++index;
+ }
}
void drawer::attached(widget_reference widget, graph_reference graph)
{
- graph_ = &graph;
+ impl_->graph_ptr = &graph;
widget_ = static_cast< ::nana::toolbar*>(&widget);
- widget.caption(STR("Nana Toolbar"));
- impl_->event_size = widget.events().resized.connect_unignorable(std::bind(&drawer::_m_owner_sized, this, std::placeholders::_1));
+ widget.caption(L"Nana Toolbar");
+ impl_->event_size = API::events(widget.parent()).resized.connect_unignorable([this](const arg_resized& arg)
+ {
+ auto wd = widget_->handle();
+ API::window_size(wd, nana::size(arg.width, widget_->size().height));
+ API::update_window(wd);
+ });
}
void drawer::detached()
{
API::umake_event(impl_->event_size);
impl_->event_size = nullptr;
+ impl_->graph_ptr = nullptr;
}
void drawer::mouse_move(graph_reference graph, const arg_mouse& arg)
{
- if(arg.left_button == false)
+ if (arg.left_button)
+ return;
+
+ size_type which = _m_which(arg.pos, true);
+ if(impl_->which != which)
{
- size_type which = _m_which(arg.pos.x, arg.pos.y, true);
- if(impl_->which != which)
+ auto & container = impl_->items.container();
+ if (impl_->which != npos && container.at(impl_->which)->enable)
{
- if (impl_->which != npos && impl_->cont.at(impl_->which)->enable)
- {
- ::nana::arg_toolbar arg{ *widget_, impl_->which };
- widget_->events().leave.emit(arg);
- }
-
- impl_->which = which;
- if(which == npos || impl_->cont.at(which)->enable)
- {
- impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted);
-
- _m_draw();
- API::lazy_refresh();
-
- if (impl_->state == item_renderer::state_t::highlighted)
- {
- ::nana::arg_toolbar arg{ *widget_, which };
- widget_->events().enter.emit(arg);
- }
- }
-
- if(which != npos)
- impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(impl_->cont.begin() + which))->text, 0);
- else
- impl_->tooltip.close();
+ ::nana::arg_toolbar arg{ *widget_, impl_->which };
+ widget_->events().leave.emit(arg);
}
+
+ impl_->which = which;
+ if (which == npos || container.at(which)->enable)
+ {
+ impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted);
+
+ refresh(graph);
+ API::lazy_refresh();
+
+ if (impl_->state == item_renderer::state_t::highlighted)
+ {
+ ::nana::arg_toolbar arg{ *widget_, which };
+ widget_->events().enter.emit(arg);
+ }
+ }
+
+ if(which != npos)
+ impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(container.begin() + which))->text, 0);
+ else
+ impl_->tooltip.close();
}
}
- void drawer::mouse_leave(graph_reference, const arg_mouse&)
+ void drawer::mouse_leave(graph_reference graph, const arg_mouse&)
{
if(impl_->which != npos)
{
size_type which = impl_->which;
impl_->which = npos;
- _m_draw();
+ refresh(graph);
API::lazy_refresh();
- if (which != npos && impl_->cont.at(which)->enable)
+ if (which != npos && impl_->items.at(which)->enable)
{
::nana::arg_toolbar arg{ *widget_, which };
widget_->events().leave.emit(arg);
@@ -343,22 +315,22 @@ namespace nana
impl_->tooltip.close();
}
- void drawer::mouse_down(graph_reference, const arg_mouse&)
+ void drawer::mouse_down(graph_reference graph, const arg_mouse&)
{
impl_->tooltip.close();
- if(impl_->which != npos && (impl_->cont.at(impl_->which)->enable))
+ if(impl_->which != npos && (impl_->items.at(impl_->which)->enable))
{
impl_->state = item_renderer::state_t::selected;
- _m_draw();
+ refresh(graph);
API::lazy_refresh();
}
}
- void drawer::mouse_up(graph_reference, const arg_mouse& arg)
+ void drawer::mouse_up(graph_reference graph, const arg_mouse& arg)
{
if(impl_->which != npos)
{
- size_type which = _m_which(arg.pos.x, arg.pos.y, false);
+ size_type which = _m_which(arg.pos, false);
if(impl_->which == which)
{
::nana::arg_toolbar arg{ *widget_, which };
@@ -372,89 +344,47 @@ namespace nana
impl_->state = (which == npos ? item_renderer::state_t::normal : item_renderer::state_t::highlighted);
}
- _m_draw();
+ refresh(graph);
API::lazy_refresh();
}
}
- drawer::size_type drawer::_m_which(int x, int y, bool want_if_disabled) const
+ drawer::size_type drawer::_m_which(point pos, bool want_if_disabled) const
{
- if(x < 2 || y < 2 || y >= static_cast(impl_->scale + item_renderer::extra_size + 2)) return npos;
+ if (pos.x < 2 || pos.y < 2 || pos.y >= static_cast(impl_->scale + item_renderer::extra_size + 2)) return npos;
- x -= 2;
+ pos.x -= 2;
- size_type pos = 0;
- for(auto m: impl_->cont)
+ std::size_t index = 0;
+ for(auto m: impl_->items.container())
{
- bool compart = (nullptr == m);
+ auto px = static_cast(m ? m->pixels : 3);
- if(x < static_cast(compart ? 3 : m->pixels))
- return ((compart || (m->enable == false && want_if_disabled == false)) ? npos : pos);
+ if(pos.x < px)
+ return (((!m) || (!m->enable && !want_if_disabled)) ? npos : index);
- x -= (compart ? 3 : m->pixels);
+ pos.x -= px;
- ++pos;
+ ++index;
}
return npos;
}
- void drawer::_m_draw_background(const ::nana::color& clr)
+ void drawer::_m_calc_pixels(item_type* item, bool force)
{
- graph_->gradual_rectangle(::nana::rectangle{ graph_->size() }, clr.blend(colors::white, 0.9), clr.blend(colors::black, 0.95), true);
- }
-
- void drawer::_m_draw()
- {
- int x = 2, y = 2;
-
- auto bgcolor = API::bgcolor(widget_->handle());
- graph_->set_text_color(bgcolor);
- _m_draw_background(bgcolor);
-
- item_renderer ir(*graph_, impl_->textout, impl_->scale, bgcolor);
- size_type index = 0;
-
- for(auto item : impl_->cont)
+ if (item && (force || (0 == item->pixels)))
{
- if(item)
- {
- _m_fill_pixels(item, false);
- ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal));
- x += item->pixels;
- }
- else
- {
- graph_->line({ x + 2, y + 2 }, { x + 2, y + static_cast(impl_->scale + ir.extra_size) - 4 }, { 0x80, 0x80, 0x80 });
- x += 6;
- }
- ++index;
- }
- }
+ if (item->text.size())
+ item->textsize = impl_->graph_ptr->text_extent_size(item->text);
- void drawer::_m_owner_sized(const arg_resized& arg)
- {
- auto wd = widget_->handle();
- API::window_size(wd, nana::size(arg.width, widget_->size().height));
- _m_draw();
- API::update_window(wd);
- }
-
- void drawer::_m_fill_pixels(item_type* item, bool force)
- {
- if(item && (force || (0 == item->pixels)))
- {
- if(item->text.size())
- item->textsize = graph_->text_extent_size(item->text);
-
- if(item->image.empty() == false)
+ if (item->image.empty() == false)
item->pixels = impl_->scale + item_renderer::extra_size;
- if(item->textsize.width && impl_->textout)
+ if (item->textsize.width && impl_->textout)
item->pixels += item->textsize.width + 8;
}
}
- //};//class drawer
-
+ //class drawer
}//end namespace toolbar
}//end namespace drawerbase
@@ -469,33 +399,48 @@ namespace nana
create(wd, r, visible);
}
- void toolbar::append()
+ void toolbar::separate()
{
- get_drawer_trigger().append();
+ get_drawer_trigger().items().separate();
API::refresh_window(handle());
}
void toolbar::append(const nana::string& text, const nana::paint::image& img)
{
- get_drawer_trigger().append(text, img);
+ get_drawer_trigger().items().push_back(text, img);
API::refresh_window(handle());
}
void toolbar::append(const nana::string& text)
{
- get_drawer_trigger().append(text, nana::paint::image());
+ get_drawer_trigger().items().push_back(text, {});
API::refresh_window(this->handle());
}
- bool toolbar::enable(size_type n) const
+ bool toolbar::enable(size_type pos) const
{
- return get_drawer_trigger().enable(n);
+ auto & items = get_drawer_trigger().items();
+
+ if (items.size() <= pos)
+ return false;
+
+ auto m = items.at(pos);
+ return (m && m->enable);
}
- void toolbar::enable(size_type n, bool eb)
+ void toolbar::enable(size_type pos, bool eb)
{
- if(get_drawer_trigger().enable(n, eb))
- API::refresh_window(this->handle());
+ auto & items = get_drawer_trigger().items();
+
+ if (items.size() > pos)
+ {
+ auto m = items.at(pos);
+ if (m && (m->enable != eb))
+ {
+ m->enable = eb;
+ API::refresh_window(this->handle());
+ }
+ }
}
void toolbar::scale(unsigned s)
@@ -503,5 +448,5 @@ namespace nana
get_drawer_trigger().scale(s);
API::refresh_window(handle());
}
- //}; class toolbar
+ //end class toolbar
}//end namespace nana
diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp
index 3aea449d..05b66977 100644
--- a/source/paint/detail/native_paint_interface.cpp
+++ b/source/paint/detail/native_paint_interface.cpp
@@ -156,6 +156,9 @@ namespace detail
nana::size text_extent_size(drawable_type dw, const nana::char_t * text, std::size_t len)
{
+ if (nullptr == dw || nullptr == text || 0 == len)
+ return{};
+
nana::size extents = raw_text_extent_size(dw, text, len);
const nana::char_t* const end = text + len;