diff --git a/.gitignore b/.gitignore
index 6580f35b..0972b5ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@ lib/
*.ninja*
CMakeCache.txt
CMakeFiles/
+cmake-build-debug/
.idea/
cmake_install.cmake
*.DS_Store
diff --git a/.travis.yml b/.travis.yml
index 4543e6b3..d6805b1e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,6 +35,9 @@ matrix:
- libx11-dev
- libxft-dev
- libboost-filesystem-dev
+ - libboost-system-dev
+ - libboost-thread-dev
+ - libboost-chrono-dev
sources:
- ubuntu-toolchain-r-test
@@ -56,7 +59,7 @@ matrix:
- llvm-toolchain-precise
before_install:
- - git clone --depth=1 --branch=develop https://github.com/qPCR4vir/nana-demo.git ../nana-demo
+ - git clone --depth=1 --branch=hotfix-1.5 https://github.com/qPCR4vir/nana-demo.git ../nana-demo
- export PATH="$HOME/bin:$PATH"
#- mkdir ~/bin #it seemd that a bin already exists from 20170901
- wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.4/cmake-3.4.0-rc3-Linux-x86_64.sh || true
@@ -84,7 +87,7 @@ script:
# we are in "... nana/../nana_lib/bin/" we need "../../nana" to get the CMakeList.txt of nana.
# Thus, make install will put the nana.lib in "... nana/../nana_lib/lib/"
# and the includes in "... nana/../nana_lib/include/"
- - cmake -G"Unix Makefiles" ../../nana -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_ENABLE_PNG=OFF -DNANA_CMAKE_BUILD_DEMOS=ON -DNANA_CMAKE_ENABLE_AUDIO=OFF -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=ON -DNANA_CMAKE_BOOST_FILESYSTEM_FORCE=OFF -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON
+ - cmake -G"Unix Makefiles" ../../nana -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_ENABLE_PNG=OFF -DNANA_CMAKE_ENABLE_AUDIO=OFF -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=ON -DNANA_CMAKE_BOOST_FILESYSTEM_FORCE=OFF -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON
- make install
- ls
- cd ..
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7f89337e..2cdeb93d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,10 +1,12 @@
# CMake configuration for Nana
# Author: Andrew Kornilov(https://github.com/ierofant)
# Contributors:
-# Jinhao
+# Jinhao
# Robert Hauck - Enable support for PNG/Freetype
# Qiangqiang Wu - Add biicode support
-# Ariel Vina-Rodriguez (qPCR4vir)
+# Ariel Vina-Rodriguez (qPCR4vir)
+# Pavel O. - fix compilation with boost::filesystem (#281)
+# Frostbane - Add option for compiling a shared library (#263,#265)
#
# Nana uses some build systems: MS-VS solution, MAKE, bakefile, codeblock, etc. manually optimized.
# In the future CMake could be the prefered, and maybe will be used to generate the others and the central nana repo
@@ -30,9 +32,11 @@ option(NANA_CMAKE_LIBPNG_FROM_OS "Use libpng from operating system." ON)
option(NANA_CMAKE_ENABLE_JPEG "Enable the use of JPEG" OFF)
option(NANA_CMAKE_LIBJPEG_FROM_OS "Use libjpeg from operating system." ON)
option(NANA_CMAKE_ENABLE_AUDIO "Enable class audio::play for PCM playback." OFF)
+option(NANA_CMAKE_SHARED_LIB "Compile nana as a shared library." OFF)
option(NANA_CMAKE_VERBOSE_PREPROCESSOR "Show annoying debug messages during compilation." ON)
option(NANA_CMAKE_STOP_VERBOSE_PREPROCESSOR "Stop compilation after showing the annoying debug messages." OFF)
option(NANA_CMAKE_AUTOMATIC_GUI_TESTING "Activate automatic GUI testing?" OFF)
+option(NANA_CLION "Activate some CLion specific workarounds" OFF)
# The ISO C++ File System Technical Specification (ISO-TS, or STD) is optional.
# http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf
@@ -45,7 +49,7 @@ option(NANA_CMAKE_AUTOMATIC_GUI_TESTING "Activate automatic GUI testing?" OFF)
# By default Nana will try to use the STD. If STD is not available and NANA_CMAKE_FIND_BOOST_FILESYSTEM
# is set to ON nana will try to use boost if available. Nana own implementation will be use if none of
# the previus were selected or available.
-# You can change that default if you change one of the following
+# You can change that default if you change one of the following
# (please don't define more than one of the _XX_FORCE options):
option(NANA_CMAKE_FIND_BOOST_FILESYSTEM "Search: Is Boost filesystem available?" OFF)
option(NANA_CMAKE_NANA_FILESYSTEM_FORCE "Force nana filesystem over ISO and boost?" OFF)
@@ -62,11 +66,12 @@ if(POLICY CMP0004) # ignore leading space
cmake_policy(SET CMP0004 OLD)
endif()
+set(CMAKE_DEBUG_POSTFIX "_d")
+
########### OS
if(WIN32)
add_definitions(-DWIN32)
- set(CMAKE_DEBUG_POSTFIX "_d")
#Global MSVC definitions. You may prefer the hand-tuned sln and projects from the nana repository.
if(MSVC)
option(MSVC_USE_MP "Set to ON to build nana with the /MP option (Visual Studio 2005 and above)." ON)
@@ -96,8 +101,24 @@ if(WIN32)
add_definitions(-DNANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ)
endif(NANA_CMAKE_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ)
endif(MINGW)
+
+ if (MSVC)
+ set (DLLTOOL OFF)
+ else ()
+ # mingw: If dlltool is found the def and lib file will be created
+ message (STATUS "Detecting dlltool")
+ find_program (DLLTOOL dlltool)
+ if (DLLTOOL)
+ message (STATUS "Found dlltool: ${DLLTOOL}")
+ else ()
+ message (WARNING "dlltool not found. Skipping import library generation.")
+ endif (DLLTOOL)
+ endif (MSVC)
+
endif(WIN32)
+
+
if(APPLE)
add_definitions(-DAPPLE)
include_directories(/opt/X11/include/)
@@ -105,7 +126,7 @@ if(APPLE)
set(ENABLE_AUDIO OFF)
elseif(UNIX)
add_definitions(-Dlinux)
- message("added -D linux")
+ message("added -D linux")
endif(APPLE)
if(UNIX)
@@ -121,35 +142,47 @@ endif(UNIX)
########### Compilers
#
# Using gcc: gcc 4.8 don't support C++14 and make_unique. You may want to update at least to 4.9.
-# In Windows, the gcc which come with CLion was 4.8 from MinGW. You may want to install MinGW-w64 from the
-# TDM-GCC Compiler Suite for Windows which will update you to gcc 5.1.
# gcc 5.3 and 5.4 include filesytem, but you need to add the link flag: -lstdc++fs
#
+# In Windows, the gcc which come with CLion was 4.8 from MinGW.
+# CLion was updated to MinGW with gcc 6.3 ? Allways check this in File/Settings.../toolchains
+# You could install MinGW-w64 from the TDM-GCC Compiler Suite for Windows which will update you to gcc 5.1.
+# It is posible to follow https://computingabdn.com/softech/mingw-howto-install-gcc-for-windows/
+# and install MinGW with gcc 7.1 with has STD_THREADS and fs, from: https://sourceforge.net/projects/mingw-w64/files/
+#
+#
# see at end of: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dynamic_or_shared.html
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # Clang || GNU
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14 -Wall -g") # Clang
-
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14 -Wall -g") # Clang
+
else ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -g") # GNU
-
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -g") # GNU
+
endif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
# enable static linkage # GNU || CLang not MinGW
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW
- # set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread")
- list(APPEND NANA_LINKS -static-libgcc -static-libstdc++ -pthread)
- # message("Setting NANA_LINKS to -static-libgcc -static-libstdc++ -pthread or ${NANA_LINKS}")
+
+ if(NANA_CMAKE_SHARED_LIB)
+ list(APPEND NANA_LINKS -lgcc -lstdc++ -pthread)
+ else()
+ set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread")
+ # message("Setting NANA_LINKS to -static-libgcc -static-libstdc++ -pthread or ${NANA_LINKS}")
+ endif(NANA_CMAKE_SHARED_LIB)
+
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3)
- # IS_GNUCXX < 5.3
+ # IS_GNUCXX < 5.3
else(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3)
- # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lstdc++fs") # IS_GNUCXX 5.3 or more
- list(APPEND NANA_LINKS -lstdc++fs)
+
+ # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lstdc++fs") # IS_GNUCXX 5.3 or more
+ list(APPEND NANA_LINKS -lstdc++fs)
+
endif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3)
-
+
endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW
@@ -163,14 +196,16 @@ endif ()
# Find PNG
if(NANA_CMAKE_ENABLE_PNG)
- add_definitions(-DNANA_ENABLE_PNG)
if(NANA_CMAKE_LIBPNG_FROM_OS)
find_package(PNG)
if (PNG_FOUND)
include_directories( ${PNG_INCLUDE_DIRS})
list(APPEND NANA_LINKS ${PNG_LIBRARIES})
- add_definitions(-DUSE_LIBPNG_FROM_OS)
+ add_definitions("-DNANA_ENABLE_PNG"
+ "-DUSE_LIBPNG_FROM_OS")
endif(PNG_FOUND)
+ else()
+ add_definitions(-DNANA_ENABLE_PNG)
endif(NANA_CMAKE_LIBPNG_FROM_OS)
endif(NANA_CMAKE_ENABLE_PNG)
@@ -182,8 +217,11 @@ if(NANA_CMAKE_ENABLE_JPEG)
if (JPEG_FOUND)
include_directories( ${JPEG_INCLUDE_DIR})
list(APPEND NANA_LINKS ${JPEG_LIBRARY})
- add_definitions(-DUSE_LIBJPEG_FROM_OS)
+ add_definitions("-DNANA_ENABLE_JPEG"
+ "-DUSE_LIBJPEG_FROM_OS")
endif(JPEG_FOUND)
+ else()
+ add_definitions(-DNANA_ENABLE_JPEG)
endif(NANA_CMAKE_LIBJPEG_FROM_OS)
endif(NANA_CMAKE_ENABLE_JPEG)
@@ -208,7 +246,7 @@ elseif (NANA_CMAKE_STD_FILESYSTEM_FORCE)
add_definitions(-DSTD_FILESYSTEM_FORCE)
elseif (NANA_CMAKE_FIND_BOOST_FILESYSTEM OR NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
if (NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
- add_definitions(-DNANA_BOOST_FILESYSTEM_FORCE)
+ add_definitions(-DBOOST_FILESYSTEM_FORCE)
endif(NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
# https://cmake.org/cmake/help/git-master/module/FindBoost.html
# Implicit dependencies such as Boost::filesystem requiring Boost::system will be automatically detected and satisfied,
@@ -216,7 +254,7 @@ elseif (NANA_CMAKE_FIND_BOOST_FILESYSTEM OR NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
# If using Boost::thread, then Thread::Thread will also be added automatically.
find_package(Boost COMPONENTS filesystem)
if (Boost_FOUND)
- add_definitions(-DNANA_BOOST_FILESYSTEM_AVAILABLE)
+ add_definitions(-DBOOST_FILESYSTEM_AVAILABLE)
include_directories(SYSTEM "${Boost_INCLUDE_DIR}")
list(APPEND NANA_LINKS ${Boost_LIBRARIES}) ###### FIRST !!!!!!!!!!!!!!!!! add is not first
endif (Boost_FOUND)
@@ -232,8 +270,8 @@ if(NANA_CMAKE_VERBOSE_PREPROCESSOR)
add_definitions(-DVERBOSE_PREPROCESSOR)
endif(NANA_CMAKE_VERBOSE_PREPROCESSOR)
if(NANA_CMAKE_AUTOMATIC_GUI_TESTING)
- add_definitions(-DNANA_AUTOMATIC_GUI_TESTING)
- enable_testing ()
+ add_definitions(-DNANA_AUTOMATIC_GUI_TESTING)
+ enable_testing ()
endif(NANA_CMAKE_AUTOMATIC_GUI_TESTING)
@@ -266,7 +304,16 @@ foreach(subdir ${NANA_SOURCE_SUBDIRS})
# message("Subir: ${subdir}") # message("Files: ${sources}")
endforeach(subdir ${NANA_SOURCE_SUBDIRS})
-add_library(${PROJECT_NAME} ${sources} )
+if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
+ add_definitions(-fmax-errors=3)
+endif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
+
+if(NANA_CMAKE_SHARED_LIB)
+ add_library(${PROJECT_NAME} SHARED ${sources} )
+else()
+ add_library(${PROJECT_NAME} STATIC ${sources} )
+endif(NANA_CMAKE_SHARED_LIB)
+
target_include_directories(${PROJECT_NAME} PUBLIC ${NANA_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${NANA_LINKS})
@@ -275,33 +322,79 @@ target_link_libraries(${PROJECT_NAME} ${NANA_LINKS})
# Installing: the static "nana lib" will be in DESTDIR/CMAKE_INSTALL_PREFIX/lib/
# and the includes files "include/nana/" in DESTDIR/CMAKE_INSTALL_PREFIX/include/nana/
+# unfortunatelly install() is still ignored by CLion:
+# https://intellij-support.jetbrains.com/hc/en-us/community/posts/205822949-CMake-install-isn-t-supported-
install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION lib
- LIBRARY DESTINATION lib)
-message("The compiled Nana library will be installed in ${CMAKE_INSTALL_PREFIX}/lib")
-# Install the include directories too.
-if(NANA_CMAKE_INSTALL_INCLUDES)
- install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include )
- message("The Nana include files will be installed in ${CMAKE_INSTALL_PREFIX}/include")
-endif(NANA_CMAKE_INSTALL_INCLUDES)
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION bin)
+
+# http://stackoverflow.com/questions/33788729/how-do-i-get-clion-to-run-an-install-target
+if(NANA_CLION) # the Clion IDE don't reconize the install target
+ add_custom_target(install_${PROJECT_NAME}
+ $(MAKE) install
+ DEPENDS ${PROJECT_NAME}
+ COMMENT "Installing ${PROJECT_NAME}")
+endif()
set_property( TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14 )
+if (NANA_CMAKE_SHARED_LIB)
+ if (WIN32)
+ set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+
+ if (DLLTOOL)
+ #message(STATUS "CMAKE_CURRENT_BINARY_DIR = ${CMAKE_CURRENT_BINARY_DIR}")
+
+ #generate the lib and def files needed by msvc
+ set_target_properties (${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}"
+ ARCHIVE_OUTPUT_NAME "${PROJECT_NAME}"
+ LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS_INIT} -Wl,--output-def=${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}.def")
+
+ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMAND echo " Generating import library"
+ COMMAND "${DLLTOOL}" --dllname "lib${PROJECT_NAME}.dll"
+ --input-def "lib${PROJECT_NAME}.def"
+ --output-lib "lib${PROJECT_NAME}.lib")
+
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}.def"
+ "${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}.lib" DESTINATION lib)
+ endif ()
+
+ endif (WIN32)
+endif (NANA_CMAKE_SHARED_LIB)
+
+message ("")
+
+message("The compiled Nana library will be installed in ${CMAKE_INSTALL_PREFIX}/lib")
+# Install the include directories too.
+if(NANA_CMAKE_INSTALL_INCLUDES)
+ install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include )
+ message("The Nana include files will be installed in ${CMAKE_INSTALL_PREFIX}/include")
+endif(NANA_CMAKE_INSTALL_INCLUDES)
+
+
# Just for information:
-message ( "CMAKE_CXX_COMPILER_ID = " ${CMAKE_CXX_COMPILER_ID})
-message ( "COMPILER_IS_CLANG = " ${COMPILER_IS_CLANG})
-message ( "CMAKE_COMPILER_IS_GNUCXX= " ${CMAKE_COMPILER_IS_GNUCXX})
-message ( "CMAKE_CXX_FLAGS = " ${CMAKE_CXX_FLAGS})
-message ( "CMAKE_EXE_LINKER_FLAGS = " ${CMAKE_EXE_LINKER_FLAGS})
-message ( "CMAKE_STATIC_LINKER_FLAGS=" ${CMAKE_STATIC_LINKER_FLAGS})
-message ( "NANA_LINKS = " ${NANA_LINKS})
-message ( "DESTDIR = " ${DESTDIR})
-message ( "CMAKE_INSTALL_PREFIX = " ${CMAKE_INSTALL_PREFIX})
-message ( "NANA_INCLUDE_DIR = " ${NANA_INCLUDE_DIR})
-message ( "CMAKE_CURRENT_SOURCE_DIR= " ${CMAKE_CURRENT_SOURCE_DIR})
-message ( "NANA_CMAKE_ENABLE_AUDIO = " ${NANA_CMAKE_ENABLE_AUDIO})
+message ("")
+message ( "CMAKE_CXX_COMPILER_ID = " ${CMAKE_CXX_COMPILER_ID})
+message ( "COMPILER_IS_CLANG = " ${COMPILER_IS_CLANG})
+message ( "CMAKE_COMPILER_IS_GNUCXX = " ${CMAKE_COMPILER_IS_GNUCXX})
+message ( "CMAKE_CXX_FLAGS = " ${CMAKE_CXX_FLAGS})
+message ( "CMAKE_EXE_LINKER_FLAGS = " ${CMAKE_EXE_LINKER_FLAGS})
+message ( "CMAKE_STATIC_LINKER_FLAGS = " ${CMAKE_STATIC_LINKER_FLAGS})
+message ( "NANA_LINKS = " ${NANA_LINKS})
+message ( "DESTDIR = " ${DESTDIR})
+message ( "CMAKE_INSTALL_PREFIX = " ${CMAKE_INSTALL_PREFIX})
+message ( "NANA_INCLUDE_DIR = " ${NANA_INCLUDE_DIR})
+message ( "CMAKE_CURRENT_SOURCE_DIR = " ${CMAKE_CURRENT_SOURCE_DIR})
+message ( "NANA_CMAKE_ENABLE_AUDIO = " ${NANA_CMAKE_ENABLE_AUDIO})
+message ( "NANA_CMAKE_SHARED_LIB = " ${NANA_CMAKE_SHARED_LIB})
+message ( "NANA_CLION = " ${NANA_CLION})
+message ( "CMAKE_MAKE_PROGRAM = " ${CMAKE_MAKE_PROGRAM})
+
message ( "NANA_CMAKE_FIND_BOOST_FILESYSTEM = " ${NANA_CMAKE_FIND_BOOST_FILESYSTEM})
message ( "NANA_CMAKE_BOOST_FILESYSTEM_FORCE = " ${NANA_CMAKE_BOOST_FILESYSTEM_FORCE})
message ( "NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT = " ${NANA_CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT})
message ( "NANA_CMAKE_BOOST_FILESYSTEM_LIB = " ${NANA_CMAKE_BOOST_FILESYSTEM_LIB})
message ( "NANA_CMAKE_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_AUTOMATIC_GUI_TESTING})
-message ( "NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING})
\ No newline at end of file
+message ( "NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING = " ${NANA_CMAKE_ADD_DEF_AUTOMATIC_GUI_TESTING})
diff --git a/build/codeblocks/nana.cbp b/build/codeblocks/nana.cbp
index c598a95d..18c78755 100644
--- a/build/codeblocks/nana.cbp
+++ b/build/codeblocks/nana.cbp
@@ -50,6 +50,7 @@
+
diff --git a/build/vc2015/nana.vcxproj b/build/vc2015/nana.vcxproj
index 9dd9c3bc..3ec4cf7d 100644
--- a/build/vc2015/nana.vcxproj
+++ b/build/vc2015/nana.vcxproj
@@ -252,6 +252,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/vc2015/nana.vcxproj.filters b/build/vc2015/nana.vcxproj.filters
index 32f7afd6..d1d7ba78 100644
--- a/build/vc2015/nana.vcxproj.filters
+++ b/build/vc2015/nana.vcxproj.filters
@@ -292,4 +292,74 @@
Source Files\detail
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
\ No newline at end of file
diff --git a/build/vc2017/nana.vcxproj b/build/vc2017/nana.vcxproj
index 818d6cf8..cc3c70dc 100644
--- a/build/vc2017/nana.vcxproj
+++ b/build/vc2017/nana.vcxproj
@@ -101,6 +101,7 @@
Level3
Disabled
WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ MultiThreadedDebug
Windows
@@ -113,6 +114,7 @@
Level3
Disabled
_DEBUG;_LIB;%(PreprocessorDefinitions)
+ MultiThreadedDebug
Windows
@@ -127,6 +129,7 @@
true
true
WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ MultiThreaded
Windows
@@ -143,6 +146,7 @@
true
true
NDEBUG;_LIB;%(PreprocessorDefinitions)
+ MultiThreaded
Windows
@@ -232,6 +236,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/vc2017/nana.vcxproj.filters b/build/vc2017/nana.vcxproj.filters
index ef973d0c..10e92180 100644
--- a/build/vc2017/nana.vcxproj.filters
+++ b/build/vc2017/nana.vcxproj.filters
@@ -41,6 +41,15 @@
{c1cdf46a-519f-422a-947f-39e173045414}
+
+ {d68bd89c-170f-445f-b79f-aa03c881ab6b}
+
+
+ {a5d87649-2cd1-4a8f-a1f9-7151eaf6c772}
+
+
+ {0e6a58ab-652c-45d7-b9aa-8d9f2fa80ea1}
+
@@ -284,4 +293,197 @@
Sources\gui
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui\widgets
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include\gui
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+ Include
+
+
+
+
+ Include
+
+
+ Include
+
+
\ No newline at end of file
diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp
index b190ea42..a041279b 100644
--- a/include/nana/basic_types.hpp
+++ b/include/nana/basic_types.hpp
@@ -312,7 +312,14 @@ namespace nana
/// @param lightness in range of [0, 1]
color& from_hsl(double hue, double saturation, double lightness); ///< immutable alpha channel
- color blend(const color& blending_color, double alpha) const;
+ /// Blends color
+ /**
+ * Returns a color which is blended as this * (1 - fade_rate) + blending_color * fade_rate
+ * @param blending_color Color to blend
+ * @param fade_rate Blending rate for blending_color
+ * @return a blended color
+ */
+ color blend(const color& blending_color, double fade_rate) const;
/// Determines whether the color is completely transparent.
bool invisible() const;
diff --git a/include/nana/c++defines.hpp b/include/nana/c++defines.hpp
index 4c7a244e..04b5113f 100644
--- a/include/nana/c++defines.hpp
+++ b/include/nana/c++defines.hpp
@@ -173,6 +173,7 @@
//Assume the std::thread is not implement on MinGW
//But some toolchains may implement std::thread.
+// it seems that MinGW 6.3 and 7.1 have std::thread
#ifdef NANA_MINGW
# ifndef STD_THREAD_NOT_SUPPORTED
# define STD_THREAD_NOT_SUPPORTED
@@ -220,6 +221,9 @@
# if __has_include()
# undef STD_FILESYSTEM_NOT_SUPPORTED
# endif
+# if __has_include()
+# undef STD_THREAD_NOT_SUPPORTED
+# endif
#endif
#endif // NANA_CXX_DEFINES_INCLUDED
diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp
index 59020d68..067586f5 100644
--- a/include/nana/filesystem/filesystem.hpp
+++ b/include/nana/filesystem/filesystem.hpp
@@ -53,6 +53,7 @@
#undef NANA_USING_BOOST_FILESYSTEM
#define NANA_USING_BOOST_FILESYSTEM 1
+# include
# include
// add boost::filesystem into std::experimental::filesystem
@@ -60,6 +61,20 @@ namespace std {
namespace experimental {
namespace filesystem {
using namespace boost::filesystem;
+ using file_time_type = std::chrono::time_point;
+
+ enum class file_type {
+ none = boost::filesystem::file_type::status_unknown,
+ not_found = boost::filesystem::file_type::file_not_found,
+ regular = boost::filesystem::file_type::regular_file,
+ directory = boost::filesystem::file_type::directory_file,
+ symlink = boost::filesystem::file_type::symlink_file,
+ block = boost::filesystem::file_type::block_file,
+ character = boost::filesystem::file_type::character_file,
+ fifo = boost::filesystem::file_type::fifo_file,
+ socket = boost::filesystem::file_type::socket_file,
+ unknown = boost::filesystem::file_type::type_unknown,
+ };
} // filesystem
} // experimental
} // std
diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp
index a13b3bac..2cc656ca 100644
--- a/include/nana/gui/basis.hpp
+++ b/include/nana/gui/basis.hpp
@@ -91,6 +91,8 @@ namespace nana
substitute = 0x1A, //Ctrl+Z
escape = 0x1B,
space = 0x20, //Space
+ del = 0x7F, //Delete
+ os_del = del, //Deprecated
//The following names are intuitive name of ASCII control codes
select_all = start_of_headline,
@@ -106,8 +108,8 @@ namespace nana
os_ctrl = 0x11,
os_pageup = 0x21, os_pagedown,
os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down,
- os_insert = 0x2D, os_del ,
- os_end = 0x23 , os_home //Pos 1
+ os_insert = 0x2D,
+ os_end = 0x23, os_home //Pos 1
};
};
@@ -271,6 +273,7 @@ that return a corresponding nana::appearance with predefined values.
public:
virtual ~caret_interface() = default;
+ virtual bool activated() const = 0;
virtual void disable_throw() noexcept = 0;
virtual void effective_range(const rectangle& range) = 0;
diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp
index c686f889..3f90c300 100644
--- a/include/nana/gui/detail/basic_window.hpp
+++ b/include/nana/gui/detail/basic_window.hpp
@@ -55,6 +55,7 @@ namespace detail
void dimension(const size& s) override;
void visible(bool visibility) override;
bool visible() const override;
+ bool activated() const override;
private:
basic_window * owner_;
point position_;
diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp
index c80d51f1..25b2fc7f 100644
--- a/include/nana/gui/detail/native_window_interface.hpp
+++ b/include/nana/gui/detail/native_window_interface.hpp
@@ -1,7 +1,7 @@
/*
* Platform Implementation
* Nana C++ Library(http://www.nanapro.org)
- * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
+ * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -66,11 +66,11 @@ namespace detail
static nana::point window_position(native_window_type);
static void move_window(native_window_type, int x, int y);
- static void move_window(native_window_type, const rectangle&);
+ static bool move_window(native_window_type, const rectangle&);
static void bring_top(native_window_type, bool activated);
static void set_window_z_order(native_window_type, native_window_type wd_after, z_order_action action_if_no_wd_after);
- static void window_size(native_window_type, const size&);
+ static bool window_size(native_window_type, const size&);
static void get_window_rect(native_window_type, rectangle&);
static void window_caption(native_window_type, const native_string_type&);
static native_string_type window_caption(native_window_type);
diff --git a/include/nana/gui/widgets/float_listbox.hpp b/include/nana/gui/widgets/float_listbox.hpp
index 590479fd..97670410 100644
--- a/include/nana/gui/widgets/float_listbox.hpp
+++ b/include/nana/gui/widgets/float_listbox.hpp
@@ -38,9 +38,9 @@ namespace nana
{
std::vector> items;
- std::size_t max_items{10}; // the number of items display.
- mutable std::size_t index{::nana::npos}; // the result of the selection.
- mutable bool have_selected;
+ std::size_t max_items{ 10 }; // the number of items display.
+ mutable std::size_t index{ ::nana::npos }; // the result of the selection.
+ mutable bool have_selected{ false };
};
class item_renderer
diff --git a/include/nana/gui/widgets/picture.hpp b/include/nana/gui/widgets/picture.hpp
index 9050f8be..d4805662 100644
--- a/include/nana/gui/widgets/picture.hpp
+++ b/include/nana/gui/widgets/picture.hpp
@@ -36,7 +36,6 @@ namespace nana
void attached(widget_reference, graph_reference) override;
private:
void refresh(graph_reference) override;
- void _m_draw_background(unsigned,unsigned);
private:
implement * const impl_;
};
diff --git a/include/nana/gui/widgets/spinbox.hpp b/include/nana/gui/widgets/spinbox.hpp
index 2ecabc78..15cbc694 100644
--- a/include/nana/gui/widgets/spinbox.hpp
+++ b/include/nana/gui/widgets/spinbox.hpp
@@ -61,6 +61,7 @@ namespace nana
void focus(graph_reference, const arg_focus&) override;
void mouse_wheel(graph_reference, const arg_wheel&) override;
+ void dbl_click(graph_reference, const arg_mouse&) override;
void mouse_down(graph_reference, const arg_mouse&) override;
void mouse_move(graph_reference, const arg_mouse&) override;
void mouse_up(graph_reference, const arg_mouse& arg) override;
diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp
index d0ac2f67..5f6dbc91 100644
--- a/include/nana/gui/widgets/textbox.hpp
+++ b/include/nana/gui/widgets/textbox.hpp
@@ -185,7 +185,7 @@ namespace nana
/// Appends an string. If `at_caret` is `true`, the string is inserted at the position of caret, otherwise, it is appended at end of the textbox.
textbox& append(const std::string& text, bool at_caret);
-
+ textbox& append(const std::wstring& text, bool at_caret);
/// Determines whether the text is line wrapped.
bool line_wrapped() const;
textbox& line_wrapped(bool);
diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp
index 1ddb448d..08548dd4 100644
--- a/include/nana/gui/widgets/treebox.hpp
+++ b/include/nana/gui/widgets/treebox.hpp
@@ -4,10 +4,10 @@
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or copy at
+ * (See accompanying file LICENSE or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
- * @file: nana/gui/widgets/treebox.hpp
+ * @file nana/gui/widgets/treebox.hpp
* @brief
* The treebox organizes the nodes by a key string.
* The treebox would have a vertical scrollbar if there are too many nodes
@@ -344,7 +344,7 @@ namespace nana
}//end namespace drawerbase
/// \brief Displays a hierarchical list of items, such as the files and directories on a disk.
- /// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm)
+ /// See also in [documentation](http://nanapro.org/en-us/documentation/widgets/treebox.htm)
class treebox
:public widget_object < category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events>
{
@@ -372,7 +372,7 @@ namespace nana
/// \brief The construct that creates a widget.
/// @param wd A handle to the parent window of the widget being created.
/// @param r the size and position of the widget in its parent window coordinate.
- /// @param visible specifying the visible after creating.
+ /// @param visible specifying if visible after creating.
treebox(window, const nana::rectangle& = rectangle(), bool visible = true);
template
@@ -397,18 +397,18 @@ namespace nana
///
/// The treebox automatically redraws after certain operations, but,
/// under some circumstances, it is good to disable the automatic drawing mode,
- /// for example, before adding nodes in a loop, disable the mode to avoiding
+ /// for example, before adding nodes in a loop, disable the mode avoiding
/// frequent and useless refresh for better performance, and then, after
/// the operations, enable the automatic redraw mode again.
- /// @param bool whether to enable.
- void auto_draw(bool);
+ /// @param enable bool whether to enable.
+ void auto_draw(bool enable);
/// \brief Enable the checkboxs for each item of the widget.
- /// @param bool indicates whether to show or hide the checkboxs.
+ /// @param enable bool indicates whether to show or hide the checkboxs.
treebox & checkable(bool enable);
- bool checkable() const; ///< Determinte whether the checkboxs are enabled.
+ bool checkable() const; ///< Are the checkboxs are enabled?
/// Clears the contents
void clear();
@@ -424,26 +424,30 @@ namespace nana
void icon_erase(const ::std::string& id);
- item_proxy find(const ::std::string& keypath); ///< Find an item though a specified keypath.
+ item_proxy find(const ::std::string& keypath); ///< Find an item through a specified keypath.
- /// Inserts a new node to treebox, but if the keypath exists returns the existing node.
+ /// Inserts a new node to treebox, but if the keypath exists change and returns the existing node.
item_proxy insert(const ::std::string& path_key, ///< specifies the node hierarchy
::std::string title ///< used for displaying
);
- /// Inserts a new node to treebox, but if the keypath exists returns the existing node.
+ /// Inserts a new node to treebox, but if the keypath exists change and returns the existing node.
item_proxy insert( item_proxy pos, ///< the parent item node
const ::std::string& key, ///< specifies the new node
::std::string title ///< title used for displaying in the new node.
);
- item_proxy erase(item_proxy i); ///< Removes the node at pos and return the Item proxy following the removed node
+
+ item_proxy erase(item_proxy i); ///< Removes the node at i and return the Item proxy following the removed node
void erase(const ::std::string& keypath); ///< Removes the node by the key path.
::std::string make_key_path(item_proxy i, const ::std::string& splitter) const;///
#endif
diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp
index 8843a03f..9ce35704 100644
--- a/include/nana/paint/graphics.hpp
+++ b/include/nana/paint/graphics.hpp
@@ -85,12 +85,14 @@ namespace nana
bool changed() const; ///< Returns true if the graphics object is operated
bool empty() const; ///< Returns true if the graphics object does not refer to any resource.
- operator const void*() const;
+ explicit operator bool() const noexcept;
drawable_type handle() const;
const void* pixmap() const;
const void* context() const;
+ void swap(graphics& other) noexcept;
+
/// Creates a graphics/drawable resource
/**
* @param sz The dimension of the graphics to be requested. If sz is empty, it performs as release().
diff --git a/include/nana/std_mutex.hpp b/include/nana/std_mutex.hpp
index 38c07aaf..55f486e4 100644
--- a/include/nana/std_mutex.hpp
+++ b/include/nana/std_mutex.hpp
@@ -14,8 +14,12 @@
#include
// http://lxr.free-electrons.com/source/include/uapi/asm-generic/errno.h#L53
//#define EPROTO 71 /* Protocol error */
+#ifdef _GLIBCXX_HAS_GTHREADS
+# include
+#else
#include
#include
+#endif
#else
#include
#include
diff --git a/include/nana/std_thread.hpp b/include/nana/std_thread.hpp
index e1df7ef7..87db1e5a 100644
--- a/include/nana/std_thread.hpp
+++ b/include/nana/std_thread.hpp
@@ -6,7 +6,11 @@
#if defined(NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ)
-#include
+#ifdef _GLIBCXX_HAS_GTHREADS
+# include
+#else
+# include
+#endif
#else
#include
namespace std
diff --git a/include/nana/stdc++.hpp b/include/nana/stdc++.hpp
index 4d8bbef9..fc2d6568 100644
--- a/include/nana/stdc++.hpp
+++ b/include/nana/stdc++.hpp
@@ -12,6 +12,9 @@
* @brief Implement the lack support of standard library.
*/
+#ifndef NANA_STDCXX_INCLUDED
+#define NANA_STDCXX_INCLUDED
+
#include "c++defines.hpp"
//Implement workarounds for GCC/MinGW which version is below 4.8.2
@@ -153,4 +156,6 @@ namespace std
return (v < lo ? lo : (hi < v ? hi : v));
}
}
-#endif
\ No newline at end of file
+#endif
+
+#endif // NANA_STDCXX_INCLUDED
diff --git a/source/detail/mswin/platform_spec.hpp b/source/detail/mswin/platform_spec.hpp
index 30bc8b84..5eb6df45 100644
--- a/source/detail/mswin/platform_spec.hpp
+++ b/source/detail/mswin/platform_spec.hpp
@@ -47,16 +47,6 @@ namespace detail
bool visible;
};
- struct move_window
- {
- enum { Pos = 1, Size = 2};
- int x;
- int y;
- unsigned width;
- unsigned height;
- unsigned ignore; //determinate that pos or size would be ignored.
- };
-
struct map_thread
{
rectangle update_area;
@@ -77,7 +67,6 @@ namespace detail
async_set_focus,
remote_flush_surface,
remote_thread_destroy_window,
- remote_thread_move_window,
operate_caret, //wParam: 1=Destroy, 2=SetPos
remote_thread_set_window_pos,
remote_thread_set_window_text,
diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp
index e495cf7d..7f825395 100644
--- a/source/detail/platform_spec_posix.cpp
+++ b/source/detail/platform_spec_posix.cpp
@@ -835,6 +835,19 @@ namespace detail
i->second->reinstate();
i->second->pos = pos;
}
+ auto addr = i->second;
+ if(addr && addr->input_context) {
+ XPoint spot;
+ XVaNestedList list;
+ spot.x = pos.x;
+ spot.y = pos.y + addr->size.height;
+ list = ::XVaCreateNestedList(0, XNSpotLocation, &spot,
+ XNForeground, 0,
+ XNBackground, 0,
+ (void *)0);
+ ::XSetICValues(addr->input_context, XNPreeditAttributes, list, NULL);
+ ::XFree(list);
+ }
}
void platform_spec::caret_visible(native_window_type wd, bool vis)
diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp
index 4613ca7a..fa5a8cb8 100644
--- a/source/filesystem/filesystem.cpp
+++ b/source/filesystem/filesystem.cpp
@@ -14,7 +14,13 @@
#include
#include
#include
-#include //put_time
+
+#include
+#ifdef _enable_std_put_time
+ #include
+#else
+ #include
+#endif
#if defined(NANA_WINDOWS)
#include
@@ -97,7 +103,13 @@ namespace nana
std::string pretty_file_date(const fs::path& path) // todo: move to .cpp
{
try {
+#if NANA_USING_BOOST_FILESYSTEM
+ // The return type of boost::filesystem::last_write_time isn't
+ // the same as in nana and std implementations of this function
+ auto ftime = std::chrono::system_clock::from_time_t(fs::last_write_time(path));
+#else
auto ftime = fs::last_write_time(path);
+#endif
// crash: VS2015 will not read the time for some files (for example: C:/hiberfil.sys)
// and will return file_time_type(-1) without throwing
diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp
index 67b24139..dc072370 100644
--- a/source/gui/detail/basic_window.cpp
+++ b/source/gui/detail/basic_window.cpp
@@ -204,6 +204,11 @@ namespace nana
{
return (visible_state::invisible != visibility_);
}
+
+ bool caret::activated() const
+ {
+ return (visible_state::displayed == visibility_);
+ }
//end class caret
//struct basic_window
@@ -329,24 +334,18 @@ 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->annex.caret_ptr)
- 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);
+ for (auto child : children) {
+ //Only return the child who has activated caret.
+ if (child->annex.caret_ptr && child->annex.caret_ptr->activated())
+ return child;
+
+ auto caret = child->child_caret();
+ if (caret)
+ return caret;
+ }
+ return nullptr;
}
bool basic_window::is_draw_through() const
diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp
index ec27ac07..3422beaa 100644
--- a/source/gui/detail/bedrock_pi.cpp
+++ b/source/gui/detail/bedrock_pi.cpp
@@ -151,7 +151,8 @@ 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->annex.caret_ptr ? wd : wd->child_caret());
+ //Get the window who has the activated caret
+ const core_window_t * caret_wd = ((wd->annex.caret_ptr && wd->annex.caret_ptr->activated()) ? wd : wd->child_caret());
if (caret_wd)
{
if (exposed)
diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp
index 9b0e24e0..5f4fa1fa 100644
--- a/source/gui/detail/bedrock_posix.cpp
+++ b/source/gui/detail/bedrock_posix.cpp
@@ -245,22 +245,31 @@ namespace detail
_m_event_filter(evt_code, wd, thrd);
}
- if(wd->other.upd_state == core_window_t::update_state::none)
- wd->other.upd_state = core_window_t::update_state::lazy;
+ using update_state = basic_window::update_state;
+
+ if(wd->other.upd_state == update_state::none)
+ wd->other.upd_state = update_state::lazy;
_m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal);
- //A child of wd may not be drawn if it was out of wd's range before wd resized,
- //so refresh all children of wd when a resized occurs.
- if(ask_update || (event_code::resized == evt_code))
+ bool good_wd = false;
+ if(wd_manager().available(wd))
{
- wd_manager().do_lazy_refresh(wd, false, (event_code::resized == evt_code));
+ //A child of wd may not be drawn if it was out of wd's range before wd resized,
+ //so refresh all children of wd when a resized occurs.
+ if(ask_update || (event_code::resized == evt_code) || (update_state::refreshed == wd->other.upd_state))
+ {
+ wd_manager().do_lazy_refresh(wd, false, (event_code::resized == evt_code));
+ }
+ else
+ wd->other.upd_state = update_state::none;
+
+ good_wd = true;
}
- else if(wd_manager().available(wd))
- wd->other.upd_state = core_window_t::update_state::none;
+
if(thrd) thrd->event_window = prev_wd;
- return true;
+ return good_wd;
}
void assign_arg(arg_mouse& arg, basic_window* wd, unsigned msg, const XEvent& evt)
@@ -438,8 +447,8 @@ namespace detail
keysym = keyboard::os_arrow_left + (keysym - XK_Left); break;
case XK_Insert:
keysym = keyboard::os_insert; break;
- case XK_Delete:
- keysym = keyboard::os_del; break;
+ case XK_Delete: case XK_KP_Delete:
+ keysym = keyboard::del; break;
case XK_Shift_L: case XK_Shift_R: //shift
keysym = keyboard::os_shift; break;
case XK_Control_L: case XK_Control_R: //ctrl
diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp
index ebf32705..2d75e7d4 100644
--- a/source/gui/detail/bedrock_windows.cpp
+++ b/source/gui/detail/bedrock_windows.cpp
@@ -601,40 +601,6 @@ namespace detail
::HeapFree(::GetProcessHeap(), 0, stru);
}
return true;
- case nana::detail::messages::remote_thread_move_window:
- {
- auto * mw = reinterpret_cast(wParam);
-
- ::RECT r;
- ::GetWindowRect(wd, &r);
- if(mw->ignore & mw->Pos)
- {
- mw->x = r.left;
- mw->y = r.top;
- }
- else
- {
- HWND owner = ::GetWindow(wd, GW_OWNER);
- if(owner)
- {
- ::RECT owr;
- ::GetWindowRect(owner, &owr);
- ::POINT pos = {owr.left, owr.top};
- ::ScreenToClient(owner, &pos);
- mw->x += (owr.left - pos.x);
- mw->y += (owr.top - pos.y);
- }
- }
-
- if(mw->ignore & mw->Size)
- {
- mw->width = r.right - r.left;
- mw->height = r.bottom - r.top;
- }
- ::MoveWindow(wd, mw->x, mw->y, mw->width, mw->height, true);
- delete mw;
- }
- return true;
case nana::detail::messages::remote_thread_set_window_pos:
::SetWindowPos(wd, reinterpret_cast(wParam), 0, 0, 0, 0, static_cast(lParam));
return true;
@@ -775,6 +741,19 @@ namespace detail
if (thrd) thrd->event_window = prev_event_wd;
}
+ //Translate OS Virtual-Key into ASCII code
+ wchar_t translate_virtual_key(WPARAM vkey)
+ {
+ switch (vkey)
+ {
+ case VK_DELETE:
+ return 127;
+ case VK_DECIMAL:
+ return 46;
+ }
+ return static_cast(vkey);
+ }
+
LRESULT CALLBACK Bedrock_WIN32_WindowProc(HWND root_window, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT window_proc_value = 0;
@@ -1436,7 +1415,7 @@ namespace detail
arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast(msgwnd);
arg.ignore = false;
- arg.key = static_cast(wParam);
+ arg.key = translate_virtual_key(wParam);
brock.get_key_state(arg);
brock.emit(event_code::key_press, msgwnd, arg, true, &context);
@@ -1522,7 +1501,7 @@ namespace detail
arg_keyboard arg;
arg.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast(msgwnd);
- arg.key = static_cast(wParam);
+ arg.key = translate_virtual_key(wParam);
brock.get_key_state(arg);
arg.ignore = false;
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
@@ -1639,18 +1618,21 @@ namespace detail
_m_event_filter(evt_code, wd, thrd);
}
- if (wd->other.upd_state == core_window_t::update_state::none)
- wd->other.upd_state = core_window_t::update_state::lazy;
+ using update_state = basic_window::update_state;
+
+ if (update_state::none == wd->other.upd_state)
+ wd->other.upd_state = update_state::lazy;
_m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal);
bool good_wd = false;
if (wd_manager().available(wd))
{
- if (ask_update)
+ //Ignore ask_update if update state is refreshed.
+ if (ask_update || (update_state::refreshed == wd->other.upd_state))
wd_manager().do_lazy_refresh(wd, false);
else
- wd->other.upd_state = basic_window::update_state::none;
+ wd->other.upd_state = update_state::none;
good_wd = true;
}
diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp
index 821296c1..a054dba7 100644
--- a/source/gui/detail/native_window_interface.cpp
+++ b/source/gui/detail/native_window_interface.cpp
@@ -863,30 +863,27 @@ namespace nana{
void native_interface::move_window(native_window_type wd, int x, int y)
{
#if defined(NANA_WINDOWS)
- if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId())
+ ::RECT r;
+ ::GetWindowRect(reinterpret_cast(wd), &r);
+ HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER);
+ if(owner)
{
- nana::detail::messages::move_window * mw = new nana::detail::messages::move_window;
- mw->x = x;
- mw->y = y;
- mw->ignore = mw->Size;
- ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0);
+ ::RECT owner_rect;
+ ::GetWindowRect(owner, &owner_rect);
+ ::POINT pos = {owner_rect.left, owner_rect.top};
+ ::ScreenToClient(owner, &pos);
+ x += (owner_rect.left - pos.x);
+ y += (owner_rect.top - pos.y);
}
- else
+
+
+ if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId())
{
- ::RECT r;
- ::GetWindowRect(reinterpret_cast(wd), &r);
- HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER);
- if(owner)
- {
- ::RECT owner_rect;
- ::GetWindowRect(owner, &owner_rect);
- ::POINT pos = {owner_rect.left, owner_rect.top};
- ::ScreenToClient(owner, &pos);
- x += (owner_rect.left - pos.x);
- y += (owner_rect.top - pos.y);
- }
+ nana::internal_revert_guard irg;
::MoveWindow(reinterpret_cast(wd), x, y, r.right - r.left, r.bottom - r.top, true);
}
+ else
+ ::MoveWindow(reinterpret_cast(wd), x, y, r.right - r.left, r.bottom - r.top, true);
#elif defined(NANA_X11)
Display * disp = restrict::spec.open_display();
@@ -908,41 +905,36 @@ namespace nana{
#endif
}
- void native_interface::move_window(native_window_type wd, const rectangle& r)
+ bool native_interface::move_window(native_window_type wd, const rectangle& r)
{
#if defined(NANA_WINDOWS)
- if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId())
+
+ int x = r.x;
+ int y = r.y;
+ HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER);
+ if(owner)
{
- auto * mw = new nana::detail::messages::move_window;
- mw->x = r.x;
- mw->y = r.y;
- mw->width = r.width;
- mw->height = r.height;
- mw->ignore = 0;
- ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0);
+ ::RECT owner_rect;
+ ::GetWindowRect(owner, &owner_rect);
+ ::POINT pos = {owner_rect.left, owner_rect.top};
+ ::ScreenToClient(owner, &pos);
+ x += (owner_rect.left - pos.x);
+ y += (owner_rect.top - pos.y);
}
- else
- {
- int x = r.x;
- int y = r.y;
- HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER);
- if(owner)
- {
- ::RECT owner_rect;
- ::GetWindowRect(owner, &owner_rect);
- ::POINT pos = {owner_rect.left, owner_rect.top};
- ::ScreenToClient(owner, &pos);
- x += (owner_rect.left - pos.x);
- y += (owner_rect.top - pos.y);
- }
- RECT client, wd_area;
- ::GetClientRect(reinterpret_cast(wd), &client);
- ::GetWindowRect(reinterpret_cast(wd), &wd_area);
- unsigned ext_w = (wd_area.right - wd_area.left) - client.right;
- unsigned ext_h = (wd_area.bottom - wd_area.top) - client.bottom;
- ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true);
+ RECT client, wd_area;
+ ::GetClientRect(reinterpret_cast(wd), &client);
+ ::GetWindowRect(reinterpret_cast(wd), &wd_area);
+ unsigned ext_w = (wd_area.right - wd_area.left) - client.right;
+ unsigned ext_h = (wd_area.bottom - wd_area.top) - client.bottom;
+
+ if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId())
+ {
+ nana::internal_revert_guard irg;
+ return (FALSE != ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true));
}
+
+ return (FALSE != ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true));
#elif defined(NANA_X11)
Display * disp = restrict::spec.open_display();
long supplied;
@@ -984,6 +976,7 @@ namespace nana{
::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints);
::XMoveResizeWindow(disp, reinterpret_cast(wd), x, y, r.width, r.height);
+ return true;
#endif
}
@@ -1062,32 +1055,28 @@ namespace nana{
#endif
}
- void native_interface::window_size(native_window_type wd, const size& sz)
+ bool native_interface::window_size(native_window_type wd, const size& sz)
{
#if defined(NANA_WINDOWS)
- if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId())
+ ::RECT r;
+ ::GetWindowRect(reinterpret_cast(wd), &r);
+ HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER);
+ HWND parent = ::GetParent(reinterpret_cast(wd));
+ if(parent && (parent != owner))
{
- auto * mw = new nana::detail::messages::move_window;
- mw->width = sz.width;
- mw->height = sz.height;
- mw->ignore = mw->Pos;
- ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0);
+ ::POINT pos = {r.left, r.top};
+ ::ScreenToClient(parent, &pos);
+ r.left = pos.x;
+ r.top = pos.y;
}
- else
+
+ if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId())
{
- ::RECT r;
- ::GetWindowRect(reinterpret_cast(wd), &r);
- HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER);
- HWND parent = ::GetParent(reinterpret_cast(wd));
- if(parent && (parent != owner))
- {
- ::POINT pos = {r.left, r.top};
- ::ScreenToClient(parent, &pos);
- r.left = pos.x;
- r.top = pos.y;
- }
- ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true);
+ nana::internal_revert_guard irg;
+ return (FALSE != ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true));
}
+
+ return (FALSE != ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true));
#elif defined(NANA_X11)
auto disp = restrict::spec.open_display();
nana::detail::platform_scope_guard psg;
@@ -1104,6 +1093,7 @@ namespace nana{
::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints);
}
::XResizeWindow(disp, reinterpret_cast(wd), sz.width, sz.height);
+ return true;
#endif
}
diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp
index 6c3b7578..27357217 100644
--- a/source/gui/detail/window_layout.cpp
+++ b/source/gui/detail/window_layout.cpp
@@ -149,33 +149,34 @@ namespace nana
// reads the overlaps that are overlapped a rectangular block
bool window_layout::read_overlaps(core_window_t* wd, const nana::rectangle& vis_rect, std::vector& blocks)
{
+ auto const is_wd_root = (category::flags::root == wd->other.category);
wd_rectangle block;
while (wd->parent)
{
- auto & siblings = wd->parent->children;
- //It should be checked that whether the window is still a chlid of its parent.
- if (siblings.size())
+ auto i = std::find(wd->parent->children.cbegin(), wd->parent->children.cend(), wd);
+ if (i != wd->parent->children.cend())
{
- auto i = &(siblings[0]);
- auto *end = i + siblings.size();
- i = std::find(i, end, wd);
- if (i != end)
+ for (++i; i != wd->parent->children.cend(); ++i)
{
- //find the widget that next to wd.
- for (++i; i < end; ++i)
+ core_window_t* cover = *i;
+
+ if (!cover->visible)
+ continue;
+
+ if (is_wd_root ?
+ (category::flags::root == cover->other.category)
+ :
+ ((category::flags::root != cover->other.category) && (nullptr == cover->effect.bground)))
{
- core_window_t* cover = *i;
- if ((category::flags::root != cover->other.category) && cover->visible && (nullptr == cover->effect.bground))
+ if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r))
{
- if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r))
- {
- block.window = cover;
- blocks.push_back(block);
- }
+ block.window = cover;
+ blocks.push_back(block);
}
}
}
}
+
wd = wd->parent;
}
return (!blocks.empty());
diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp
index 701eb530..4bfd1900 100644
--- a/source/gui/detail/window_manager.cpp
+++ b/source/gui/detail/window_manager.cpp
@@ -219,8 +219,6 @@ namespace detail
Key first;
Value second;
- key_value_rep() = default;
-
key_value_rep(const Key& k)
: first(k), second{}
{
@@ -258,15 +256,7 @@ namespace detail
std::vector table_;
};
- //class window_manager
- struct window_handle_deleter
- {
- void operator()(basic_window* wd) const
- {
- delete wd;
- }
- };
-
+ //class window_manager
//struct wdm_private_impl
struct window_manager::wdm_private_impl
{
@@ -506,7 +496,7 @@ namespace detail
if (impl_->wd_register.available(owner))
{
if (owner->flags.destroying)
- throw std::runtime_error("the specified owner is destory");
+ throw std::runtime_error("the specified owner is destoryed");
#ifndef WIDGET_FRAME_DEPRECATED
native = (category::flags::frame == owner->other.category ?
@@ -953,24 +943,46 @@ namespace detail
if (wd->dimension == sz)
return false;
+ //Before resiz the window, creates the new graphics
+ paint::graphics graph;
+ paint::graphics root_graph;
+ if (category::flags::lite_widget != wd->other.category)
+ {
+ //If allocation fails, here throws std::bad_alloc.
+ graph.make(sz);
+ graph.typeface(wd->drawer.graphics.typeface());
+ if (category::flags::root == wd->other.category)
+ root_graph.make(sz);
+ }
+
+ auto pre_sz = wd->dimension;
+
wd->dimension = sz;
if(category::flags::lite_widget != wd->other.category)
{
bool graph_state = wd->drawer.graphics.empty();
- wd->drawer.graphics.make(sz);
+ wd->drawer.graphics.swap(graph);
//It shall make a typeface_changed() call when the graphics state is changing.
- //Because when a widget is created with zero-size, it may get some wrong result in typeface_changed() call
+ //Because when a widget is created with zero-size, it may get some wrong results in typeface_changed() call
//due to the invaliable graphics object.
if(graph_state != wd->drawer.graphics.empty())
wd->drawer.typeface_changed();
if(category::flags::root == wd->other.category)
{
- wd->root_graph->make(sz);
+ //wd->root_graph->make(sz);
+ wd->root_graph->swap(root_graph);
if(false == passive)
- native_interface::window_size(wd->root, sz + nana::size(wd->extra_width, wd->extra_height));
+ if (!native_interface::window_size(wd->root, sz + nana::size(wd->extra_width, wd->extra_height)))
+ {
+ wd->dimension = pre_sz;
+ wd->drawer.graphics.swap(graph);
+ wd->root_graph->swap(root_graph);
+ wd->drawer.typeface_changed();
+ return false;
+ }
}
#ifndef WIDGET_FRAME_DEPRECATED
else if(category::flags::frame == wd->other.category)
diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp
index c3fa7fb0..b31653cc 100644
--- a/source/gui/filebox.cpp
+++ b/source/gui/filebox.cpp
@@ -435,20 +435,20 @@ namespace nana
nodes_.filesystem = tree_.insert("FS.ROOT", "Filesystem");
nodes_.filesystem.value(kind::filesystem);
- std::vector paths;
- paths.emplace_back(fs_ext::path_user().native());
- paths.emplace_back("/");
+ std::vector> paths;
+ paths.emplace_back(fs_ext::path_user().native(), nodes_.home);
+ paths.emplace_back("/", nodes_.filesystem);
fs::directory_iterator end;
for (auto & p : paths)
{
- for (fs::directory_iterator i(p); i != end; ++i)
+ for (fs::directory_iterator i{p.first}; i != end; ++i)
{
auto name = i->path().filename().native();
if (!is_directory(i->status()) || (name.size() && name[0] == '.'))
continue;
- item_proxy node = tree_.insert(nodes_.filesystem, name, name);
+ item_proxy node = tree_.insert(p.second, name, name);
if (false == node.empty())
{
node.value(kind::filesystem);
@@ -505,21 +505,18 @@ namespace nana
auto fpath = i->path().native();
auto fattr = fs::status(fpath);
+ auto ftype = static_cast(fattr.type());
item_fs m;
m.name = name;
m.directory = fs::is_directory(fattr);
- switch(fattr.type())
- {
- case fs::file_type::not_found:
- case fs::file_type::unknown:
- case fs::file_type::directory:
+ if (ftype == fs::file_type::not_found ||
+ ftype == fs::file_type::unknown ||
+ ftype == fs::file_type::directory)
m.bytes = 0;
- break;
- default:
+ else
m.bytes = fs::file_size(fpath);
- }
fs_ext::modified_file_time(fpath, m.modified_time);
@@ -569,28 +566,63 @@ namespace nana
if(cat_path.size() && cat_path[cat_path.size() - 1] != '/')
cat_path += '/';
+
auto beg = head.size();
while(true)
{
auto pos = path.find('/', beg);
auto folder = path.substr(beg, pos != path.npos ? pos - beg: path.npos);
- if(folder.size() == 0) break;
+
+ if(folder.empty())
+ break;
+
(cat_path += folder) += '/';
(head += folder) += '/';
path_.caption(cat_path);
- for(fs::directory_iterator i(head); i != end; ++i)
+ try
{
- if (is_directory(*i))
- path_.childset(i->path().filename().native(), 0);
+ for(fs::directory_iterator i(head); i != end; ++i)
+ {
+ if (is_directory(*i))
+ path_.childset(i->path().filename().native(), 0);
+ }
+ }
+ catch(fs::filesystem_error&)
+ {
+ //The directory iterator may throw filesystem_error when
+ //the user doesn't have permission to access the directory.
+
+ //It just loads the sub-directories
+ //to the category path.
}
if(pos == path.npos)
break;
beg = pos + 1;
}
- _m_load_path(path);
- _m_list_fs();
+
+ try
+ {
+ _m_load_path(path);
+ _m_list_fs();
+ }
+ catch(fs::filesystem_error&)
+ {
+ file_container_.clear();
+
+ drawing dw{ls_file_};
+ dw.clear();
+ dw.draw([](paint::graphics& graph){
+ std::string text = "Permission denied to access the directory";
+ auto txt_sz = graph.text_extent_size(text);
+ auto sz = graph.size();
+
+ graph.string({static_cast(sz.width - txt_sz.width) / 2, static_cast(sz.height - txt_sz.height) / 2}, text, colors::dark_gray);
+ });
+
+ ls_file_.clear();
+ }
}
bool _m_filter_allowed(const std::string& name, bool is_dir, const std::string& filter, const std::vector* extension) const
@@ -611,6 +643,8 @@ namespace nana
void _m_list_fs()
{
+ drawing{ls_file_}.clear();
+
auto filter = filter_.caption();
ls_file_.auto_draw(false);
@@ -655,13 +689,12 @@ namespace nana
return;
}
- using file_type = fs::file_type;
-
fs::path fspath(fb_.addr_.filesystem + path);
- auto fst = fs::status(fspath);
+ auto fattr = fs::status(fspath);
+ auto ftype = static_cast(fattr.type());
- if(fst.type() != file_type::not_found && fst.type() != file_type::none)
+ if(ftype != fs::file_type::not_found && ftype != fs::file_type::none)
{
mb<(fattr.type());
//Check if the selected name is a directory
auto is_dir = fs::is_directory(fattr);
@@ -771,6 +805,7 @@ namespace nana
{
//Add the extension, then check if it is a directory again.
fattr = fs::status(tar);
+ ftype = static_cast(fattr.type());
is_dir = fs::is_directory(fattr);
}
@@ -783,7 +818,7 @@ namespace nana
if(io_read_)
{
- if(fs::file_type::not_found == fattr.type())
+ if(fs::file_type::not_found == ftype)
{
msgbox mb(*this, caption());
mb.icon(msgbox::icon_information);
@@ -795,7 +830,7 @@ namespace nana
}
else
{
- if(fs::file_type::not_found != fattr.type())
+ if(fs::file_type::not_found != ftype)
{
msgbox mb(*this, caption(), msgbox::yes_no);
mb.icon(msgbox::icon_question);
@@ -829,14 +864,28 @@ namespace nana
auto child = node.append(name, name, kind::filesystem);
if(!child.empty())
{
- for(fs::directory_iterator u(i->path()); u != end; ++u)
+ //The try-catch can be eleminated by using
+ //directory_iterator( const std::filesystem::path& p, std::error_code& ec ) noexcept;
+ //in C++17
+ try
{
- auto uname = i->path().filename().native();
- if ((!is_directory(*i)) || (uname.size() && uname[0] == '.'))
- continue;
+ for(fs::directory_iterator u(i->path()); u != end; ++u)
+ {
+ auto uname = u->path().filename().native();
+ if ((!is_directory(*u)) || (uname.size() && uname[0] == '.'))
+ continue;
- child.append(uname, uname, kind::filesystem);
- break;
+ child.append(uname, uname, kind::filesystem);
+ break;
+ }
+ }
+ catch(fs::filesystem_error&)
+ {
+ //The directory iterator may throw filesystem_error when
+ //the user doesn't have permission to access the directory.
+
+ //Catch the error without any process, because the loop is just
+ //to peak whether the directory(i->path) has a sub-directory.
}
}
}
diff --git a/source/gui/place.cpp b/source/gui/place.cpp
index 257e4656..f243fcf0 100644
--- a/source/gui/place.cpp
+++ b/source/gui/place.cpp
@@ -58,7 +58,7 @@ namespace nana
{
div_start, div_end, splitter,
identifier, dock, fit, hfit, vfit, vert, grid, number, array, reparray,
- weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, undisplayed, invisible,
+ weight, width, height, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, undisplayed, invisible,
collapse, parameters,
equal,
eof, error
@@ -235,15 +235,21 @@ namespace nana
idstr_.assign(idstart, sp_);
- if ("weight" == idstr_ || "min" == idstr_ || "max" == idstr_)
+ if ( "weight" == idstr_
+ || "min" == idstr_
+ || "max" == idstr_
+ || "width" == idstr_
+ || "height" == idstr_
+ )
{
- auto ch = idstr_[1];
+ auto c3 = idstr_[2], c1 =idstr_[0];
_m_attr_number_value();
- switch (ch)
+ switch (c3)
{
- case 'e': return token::weight;
- case 'i': return token::min_px;
- case 'a': return token::max_px;
+ case 'i': return c1=='w'? token::weight : token::height;
+ case 'n': return token::min_px;
+ case 'x': return token::max_px;
+ case 'd': return token::width;
}
}
else if ("dock" == idstr_)
@@ -742,6 +748,7 @@ namespace nana
{
public:
enum class kind{ arrange, vertical_arrange, grid, splitter, dock, dockpane};
+ using token = place_parts::tokenizer::token;
division(kind k, std::string&& n) noexcept
: kind_of_division(k),
@@ -1082,6 +1089,7 @@ namespace nana
::nana::rectangle field_area;
number_t weight;
+ token weigth_type=token::weight;
number_t min_px, max_px;
place_parts::margin margin;
@@ -2616,10 +2624,10 @@ namespace nana
auto place::implement::scan_div(place_parts::tokenizer& tknizer) -> std::unique_ptr
{
- typedef place_parts::tokenizer::token token;
+ using token = place_parts::tokenizer::token ;
std::unique_ptr div;
- token div_type = token::eof;
+ token div_type = token::eof , weight_type=token::weight;
auto fit = fit_policy::none;
place_parts::repeated_array fit_parameters;
@@ -2726,7 +2734,7 @@ namespace nana
}
}
break;
- case token::weight: case token::min_px: case token::max_px:
+ case token::weight: case token::min_px: case token::max_px: case token::width: case token::height:
{
auto n = tknizer.number();
//If n is the type of real, convert it to integer.
@@ -2736,7 +2744,9 @@ namespace nana
switch (tk)
{
- case token::weight: weight = n; break;
+ case token::weight: weight = n; weight_type = token::weight; break; // we could detect errors here (redefinitions and duplicates)
+ case token::width : weight = n; weight_type = token::width ; break;
+ case token::height: weight = n; weight_type = token::height; break;
case token::min_px: min_px = n; break;
case token::max_px: max_px = n; break;
default: break; //Useless
@@ -2805,10 +2815,16 @@ namespace nana
}
}
+ token unmatch = token::width;
switch (div_type)
{
- case token::eof:
- case token::vert:
+ case token::eof: unmatch = token::height; // "horitontal" div
+ case token::vert: // "vertical" div
+ for (auto& ch : children)
+ if (ch->weigth_type == unmatch)
+ throw std::invalid_argument("nana.place: unmatch vertical-heigth/horizontal-width betwen division '"
+ +name+"' and children division '" + ch->name);
+
div.reset(new div_arrange(token::vert == div_type, std::move(name), std::move(arrange)));
break;
case token::grid:
@@ -2837,6 +2853,7 @@ namespace nana
default:
throw std::invalid_argument("nana.place: invalid division type.");
}
+ div->weigth_type = weight_type;
//Requirements for min/max
//1, min and max != negative
diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp
index 1fd7d158..22e22cac 100644
--- a/source/gui/programming_interface.cpp
+++ b/source/gui/programming_interface.cpp
@@ -1183,6 +1183,13 @@ namespace API
auto caret = _m_caret();
return (caret && caret->visible());
}
+
+ bool activated() const override
+ {
+ internal_scope_guard lock;
+ auto caret = _m_caret();
+ return (caret && caret->activated());
+ }
private:
caret_interface* _m_caret() const
{
diff --git a/source/gui/widgets/float_listbox.cpp b/source/gui/widgets/float_listbox.cpp
index 2b2d9180..7613b5bb 100644
--- a/source/gui/widgets/float_listbox.cpp
+++ b/source/gui/widgets/float_listbox.cpp
@@ -14,6 +14,7 @@
#include
#include
+#include
namespace nana
{
@@ -198,16 +199,14 @@ namespace nana
return widget_;
}
- void attach(widget* wd, nana::paint::graphics* graph)
+ void attach(widget& wd, nana::paint::graphics& graph)
{
- if(wd)
- {
- widget_ = wd;
- wd->events().mouse_wheel.connect_unignorable([this](const arg_wheel& arg){
- scroll_items(arg.upwards);
- });
- }
- if(graph) graph_ = graph;
+ widget_ = &wd;
+ wd.events().mouse_wheel.connect_unignorable([this](const arg_wheel& arg){
+ scroll_items(arg.upwards);
+ });
+
+ graph_ = &graph;
}
void detach()
@@ -219,9 +218,46 @@ namespace nana
{
if(module_)
{
- std::size_t items = (module_->max_items <= module_->items.size() ? module_->max_items : module_->items.size());
- std::size_t h = items * state_.renderer->item_pixels(*graph_);
- widget_->size(size{ widget_->size().width, static_cast(h + 4) });
+
+ auto const items = (module_->max_items <= module_->items.size() ? module_->max_items : module_->items.size());
+
+ rectangle list_r{
+ 0, 0,
+ widget_->size().width,
+ static_cast(items * state_.renderer->item_pixels(*graph_)) + 4
+ };
+
+ //Test if the listbox excesses the screen
+
+ screen scr;
+ auto & disp = scr.from_window(*widget_);
+
+ auto disp_r = disp.area();
+
+ point pos;
+ API::calc_screen_point(*widget_, pos);
+ list_r.position(pos);
+
+ if (widget_->size().width >= disp_r.width)
+ {
+ pos.x = 0;
+ list_r.width = disp_r.width;
+ }
+ else if (list_r.right() > disp_r.right())
+ pos.x = disp_r.right() - static_cast(list_r.width);
+
+ if (list_r.height >= disp_r.height)
+ {
+ pos.y = 0;
+ list_r.height = disp_r.height;
+ }
+ else if (list_r.bottom() > disp_r.bottom())
+ pos.y = disp_r.bottom() - static_cast(list_r.height);
+
+ API::calc_window_point(API::get_owner_window(*widget_), pos);
+ list_r.position(pos);
+
+ widget_->move(list_r);
}
}
@@ -312,36 +348,37 @@ namespace nana
void _m_open_scrollbar(widget_reference wd, bool v)
{
- if(v)
+ if (!v)
{
- if(scrollbar_.empty() && module_)
- {
- scrollbar_.create(wd, rectangle(static_cast(wd.size().width - 18), 2, 16, wd.size().height - 4));
- scrollbar_.amount(module_->items.size());
- scrollbar_.range(module_->max_items);
- scrollbar_.value(state_.offset_y);
-
- auto & events = scrollbar_.events();
- events.mouse_wheel.connect([this](const arg_wheel& arg)
- {
- scroll_items(arg.upwards);
- });
-
- auto fn = [this](const arg_mouse& arg)
- {
- if (arg.is_left_button() && (scrollbar_.value() != state_.offset_y))
- {
- state_.offset_y = static_cast(scrollbar_.value());
- draw();
- API::update_window(*widget_);
- }
- };
- events.mouse_move.connect(fn);
- events.mouse_up.connect(fn);
- }
- }
- else
scrollbar_.close();
+ return;
+ }
+
+ if(scrollbar_.empty() && module_)
+ {
+ scrollbar_.create(wd, rectangle(static_cast(wd.size().width - 18), 2, 16, wd.size().height - 4));
+ scrollbar_.amount(module_->items.size());
+ scrollbar_.range(module_->max_items);
+ scrollbar_.value(state_.offset_y);
+
+ auto & events = scrollbar_.events();
+ events.mouse_wheel.connect([this](const arg_wheel& arg)
+ {
+ scroll_items(arg.upwards);
+ });
+
+ auto fn = [this](const arg_mouse& arg)
+ {
+ if (arg.is_left_button() && (scrollbar_.value() != state_.offset_y))
+ {
+ state_.offset_y = static_cast(scrollbar_.value());
+ draw();
+ API::update_window(*widget_);
+ }
+ };
+ events.mouse_move.connect(fn);
+ events.mouse_up.connect(fn);
+ }
}
private:
widget * widget_{nullptr};
@@ -393,7 +430,7 @@ namespace nana
void trigger::attached(widget_reference widget, graph_reference graph)
{
- drawer_->attach(&widget, &graph);
+ drawer_->attach(widget, graph);
}
void trigger::detached()
diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp
index c49841c5..e473a080 100644
--- a/source/gui/widgets/listbox.cpp
+++ b/source/gui/widgets/listbox.cpp
@@ -3931,6 +3931,11 @@ namespace nana
essence_->content_view.reset(new widgets::skeletons::content_view{ widget.handle() });
essence_->resize_disp_area();
+ //Set the content_view wheel speed with the listbox scheme.
+ essence_->content_view->set_wheel_speed([this] {
+ return essence_->scheme_ptr->mouse_wheel.lines;
+ });
+
essence_->content_view->events().hover_outside = [this](const point& cur_pos) {
essence_->update_mouse_selection(cur_pos);
};
@@ -4166,16 +4171,17 @@ namespace nana
{
if (item_ptr->flags.selected != sel)
{
- item_ptr->flags.selected = sel;
- lister.emit_cs(abs_item_pos, true);
-
- if (item_ptr->flags.selected)
+ if (sel)
{
+ //Deselects the previously selected item.
lister.cancel_others_if_single_enabled(true, abs_item_pos);
essence_->lister.latest_selected_abs = abs_item_pos;
}
else if (essence_->lister.latest_selected_abs == abs_item_pos)
essence_->lister.latest_selected_abs.set_both(npos);
+
+ item_ptr->flags.selected = sel;
+ lister.emit_cs(abs_item_pos, true);
}
}
else
diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp
index a83c3d86..5071c094 100644
--- a/source/gui/widgets/menubar.cpp
+++ b/source/gui/widgets/menubar.cpp
@@ -403,8 +403,15 @@ namespace nana
ess_->state.nullify_mouse = true;
auto & menu_ptr = ess_->state.menu;
+
+ //menu_wd will be assigned with the handle of a menu window,
+ //It is used for checking whether the menu is closed. A menu handler
+ //may close the form, checking with the data member of this trigger
+ //is invalid, because the form is closed, the object of menubar may not exist.
+ window menu_wd = nullptr;
if(ess_->state.menu)
{
+ menu_wd = menu_ptr->handle();
switch(arg.key)
{
case keyboard::os_arrow_down:
@@ -466,8 +473,11 @@ namespace nana
case keyboard::os_arrow_up:
case keyboard::os_arrow_down:
case keyboard::enter:
- if(ess_->open_menu(true))
+ if (ess_->open_menu(true))
+ {
+ menu_wd = menu_ptr->handle();
menu_ptr->goto_next(true);
+ }
break;
case keyboard::escape:
if(essence::behavior::focus == ess_->state.behave)
@@ -481,15 +491,21 @@ namespace nana
if(index != npos)
{
ess_->state.active = index;
- if(ess_->open_menu(true))
+ if (ess_->open_menu(true))
+ {
+ menu_wd = menu_ptr->handle();
menu_ptr->goto_next(true);
+ }
}
break;
}
}
- refresh(graph);
- API::dev::lazy_refresh();
+ if (API::is_window(menu_wd))
+ {
+ refresh(graph);
+ API::dev::lazy_refresh();
+ }
}
void trigger::key_release(graph_reference graph, const arg_keyboard& arg)
diff --git a/source/gui/widgets/picture.cpp b/source/gui/widgets/picture.cpp
index b1e40aae..356072b9 100644
--- a/source/gui/widgets/picture.cpp
+++ b/source/gui/widgets/picture.cpp
@@ -29,7 +29,6 @@ namespace nana
struct implement
{
widget* wdg_ptr{nullptr};
- paint::graphics* graph_ptr{nullptr};
std::unique_ptr measurer;
struct gradual_bground_tag
@@ -48,6 +47,23 @@ namespace nana
std::unique_ptr bground; //If it is not a null ptr, the widget is stretchable mode
bool stretchable{ false }; //If it is true, the widget is stretchable mode without changing aspect ratio.
}backimg;
+
+ void draw_background(paint::graphics& graph, const size& dimension)
+ {
+ if (!API::dev::copy_transparent_background(*wdg_ptr, graph))
+ {
+ auto const graph_size = graph.size();
+ if (dimension.width < graph_size.width || dimension.height < graph_size.height || backimg.image.alpha())
+ {
+ if (gradual_bground.gradual_from.invisible() || gradual_bground.gradual_to.invisible())
+ graph.rectangle(true, wdg_ptr->bgcolor());
+ else if (gradual_bground.gradual_from == gradual_bground.gradual_to)
+ graph.rectangle(true, gradual_bground.gradual_from);
+ else
+ graph.gradual_rectangle(::nana::rectangle{graph_size }, gradual_bground.gradual_from, gradual_bground.gradual_to, !gradual_bground.horizontal);
+ }
+ }
+ }
};
class content_measurer
@@ -88,32 +104,36 @@ namespace nana
delete impl_;
}
- void drawer::attached(widget_reference& wdg, graph_reference graph)
+ void drawer::attached(widget_reference& wdg, graph_reference)
{
impl_->wdg_ptr = &wdg;
- impl_->graph_ptr = &graph;
API::dev::set_measurer(wdg, impl_->measurer.get());
}
void drawer::refresh(graph_reference graph)
{
- if (!graph.changed())
- return;
-
- auto graphsize = graph.size();
+ auto const graphsize = graph.size();
auto & backimg = impl_->backimg;
if (!backimg.bground)
{
+ if (backimg.image.empty())
+ {
+ impl_->draw_background(graph, {});
+ return;
+ }
+
auto valid_area = backimg.valid_area;
if (valid_area.empty())
valid_area.dimension(backimg.image.size());
+ //The position where the image to be drawn.
+ ::nana::point pos;
+
if (backimg.stretchable)
{
- auto fit_size = fit_zoom({ valid_area.width, valid_area.height }, graphsize);
- ::nana::point pos;
+ auto fit_size = fit_zoom(valid_area.dimension(), graphsize);
if (fit_size.width != graphsize.width)
{
@@ -142,15 +162,12 @@ namespace nana
}
}
- _m_draw_background(fit_size.width, fit_size.height);
+ impl_->draw_background(graph, fit_size);
backimg.image.stretch(valid_area, graph, ::nana::rectangle{ pos, fit_size });
}
else
{
- //The point in which position the image to be drawn.
- ::nana::point pos;
-
switch (backimg.align_horz)
{
case ::nana::align::left: break;
@@ -173,15 +190,14 @@ namespace nana
break;
}
- _m_draw_background(valid_area.width, valid_area.height);
+ impl_->draw_background(graph, valid_area.dimension());
- if ( ! backimg.image.empty())
- backimg.image.paste(valid_area, graph, pos);
+ backimg.image.paste(valid_area, graph, pos);
}
}
else
{
- _m_draw_background(graphsize.width, graphsize.height);
+ impl_->draw_background(graph, graphsize);
color invalid_clr_for_call;
backimg.bground->draw(graph, invalid_clr_for_call, invalid_clr_for_call, rectangle{ graphsize }, element_state::normal);
@@ -189,25 +205,6 @@ namespace nana
graph.setsta();
}
-
- void drawer::_m_draw_background(unsigned w, unsigned h)
- {
- auto graph = impl_->graph_ptr;
-
- if (graph && (!API::dev::copy_transparent_background(*impl_->wdg_ptr, *graph)))
- {
- if (w < graph->size().width || h < graph->size().height || impl_->backimg.image.alpha())
- {
- auto & bground = impl_->gradual_bground;
- if (bground.gradual_from.invisible() || bground.gradual_to.invisible())
- graph->rectangle(true, impl_->wdg_ptr->bgcolor());
- else if (bground.gradual_from == bground.gradual_to)
- graph->rectangle(true, bground.gradual_from);
- else
- graph->gradual_rectangle(::nana::rectangle{ graph->size() }, bground.gradual_from, bground.gradual_to, !bground.horizontal);
- }
- }
- }
//end class drawer
}//end namespace picture
}//end namespace drawerbase
@@ -233,11 +230,7 @@ namespace nana
if (backimg.bground)
backimg.bground->image(backimg.image, true, valid_area);
- if (handle())
- {
- get_drawer_trigger().impl_->graph_ptr->set_changed();
- API::refresh_window(*this);
- }
+ API::refresh_window(*this);
}
void picture::align(::nana::align horz, align_v vert)
@@ -252,18 +245,11 @@ namespace nana
backimg.align_horz = horz;
backimg.align_vert = vert;
- if (handle())
- {
- get_drawer_trigger().impl_->graph_ptr->set_changed();
- API::refresh_window(*this);
- }
+ API::refresh_window(*this);
}
void picture::stretchable(unsigned left, unsigned top, unsigned right, unsigned bottom)
{
- if (!handle())
- return;
-
internal_scope_guard lock;
auto & backimg = get_drawer_trigger().impl_->backimg;
if (!backimg.bground)
@@ -275,11 +261,8 @@ namespace nana
backimg.bground->stretch_parts(left, top, right, bottom);
backimg.stretchable = false;
- if (handle())
- {
- get_drawer_trigger().impl_->graph_ptr->set_changed();
- API::refresh_window(*this);
- }
+
+ API::refresh_window(*this);
}
void picture::stretchable(bool enables)
@@ -290,11 +273,7 @@ namespace nana
backimg.bground.reset();
backimg.stretchable = enables;
- if (handle())
- {
- get_drawer_trigger().impl_->graph_ptr->set_changed();
- API::refresh_window(*this);
- }
+ API::refresh_window(*this);
}
void picture::set_gradual_background(const ::nana::color& from, const ::nana::color& to, bool horizontal)
@@ -303,11 +282,8 @@ namespace nana
bground.gradual_from = from;
bground.gradual_to = to;
bground.horizontal = horizontal;
- if (handle())
- {
- get_drawer_trigger().impl_->graph_ptr->set_changed();
- API::refresh_window(*this);
- }
+
+ API::refresh_window(*this);
}
void picture::transparent(bool enabled)
diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp
index 20b46ddc..2c498f7c 100644
--- a/source/gui/widgets/progress.cpp
+++ b/source/gui/widgets/progress.cpp
@@ -91,19 +91,26 @@ namespace nana
{
return value_px_;
}
+
+ bool value_px_sync()
+ {
+ if (widget_)
+ {
+ auto value_px = (widget_->size().width - border_px * 2) * value_ / max_;
+
+ if (value_px != value_px_)
+ {
+ value_px_ = value_px;
+ return true;
+ }
+ }
+ return false;
+ }
private:
void _m_try_refresh()
{
- if (nullptr == widget_)
- return;
-
- auto value_px = (widget_->size().width - border_px * 2) * value_ / max_;
-
- if (value_px != value_px_)
- {
- value_px_ = value_px;
+ if (value_px_sync())
API::refresh_window(*widget_);
- }
}
private:
nana::progress * widget_{ nullptr };
@@ -144,6 +151,9 @@ namespace nana
auto rt_bground = rt_val;
if (false == progress_->unknown(nullptr))
{
+ //Sync the value_px otherwise the progress is incorrect when it is resized.
+ progress_->value_px_sync();
+
rt_bground.x = static_cast(progress_->value_px()) + static_cast(border_px);
rt_bground.width -= progress_->value_px();
diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp
index f39638b2..fefaf1ed 100644
--- a/source/gui/widgets/skeletons/text_editor.cpp
+++ b/source/gui/widgets/skeletons/text_editor.cpp
@@ -556,6 +556,7 @@ namespace nana{ namespace widgets
virtual void merge_lines(std::size_t first, std::size_t second) = 0;
//Calculates how many lines the specified line of text takes with a specified pixels of width.
virtual void add_lines(std::size_t pos, std::size_t lines) = 0;
+ virtual void prepare() = 0;
virtual void pre_calc_line(std::size_t line, unsigned pixels) = 0;
virtual void pre_calc_lines(unsigned pixels) = 0;
virtual std::size_t take_lines() const = 0;
@@ -668,6 +669,12 @@ namespace nana{ namespace widgets
}
}
+ void prepare() override
+ {
+ auto const line_count = editor_.textbase().lines();
+ this->sections_.resize(line_count);
+ }
+
void pre_calc_line(std::size_t pos, unsigned) override
{
auto const & text = editor_.textbase().getline(pos);
@@ -781,6 +788,12 @@ namespace nana{ namespace widgets
}
}
+ void prepare() override
+ {
+ auto const lines = editor_.textbase().lines();
+ linemtr_.resize(lines);
+ }
+
void pre_calc_line(std::size_t line, unsigned pixels) override
{
const string_type& lnstr = editor_.textbase().getline(line);
@@ -1220,7 +1233,7 @@ namespace nana{ namespace widgets
case keyboard::os_pagedown:
_m_handle_move_key(arg);
break;
- case keyboard::os_del:
+ case keyboard::del:
// send delete to set_accept function
if (this->attr().editable && (!impl_->capacities.pred_acceptive || impl_->capacities.pred_acceptive(key)))
del();
@@ -1234,7 +1247,7 @@ namespace nana{ namespace widgets
void text_editor::typeface_changed()
{
- impl_->capacities.behavior->pre_calc_lines(width_pixels());
+ _m_reset_content_size(true);
}
void text_editor::indent(bool enb, std::function generator)
@@ -1676,7 +1689,7 @@ namespace nana{ namespace widgets
impl_->try_refresh = sync_graph::refresh;
//_m_put calcs the lines
- _m_reset_content_size(false);
+ _m_reset_content_size(true);
impl_->cview->sync(false);
}
}
@@ -2886,10 +2899,14 @@ namespace nana{ namespace widgets
auto text_lines = textbase().lines();
if (text_lines <= max_lines)
{
+ impl_->capacities.behavior->prepare();
+
+ auto const width_px = _m_width_px(true);
+
std::size_t lines = 0;
for (std::size_t i = 0; i < text_lines; ++i)
{
- impl_->capacities.behavior->pre_calc_line(i, csize.width);
+ impl_->capacities.behavior->pre_calc_line(i, width_px);
lines += impl_->capacities.behavior->take_lines(i);
if (lines > max_lines)
diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp
index 2fad022f..41b592f3 100644
--- a/source/gui/widgets/spinbox.cpp
+++ b/source/gui/widgets/spinbox.cpp
@@ -560,6 +560,12 @@ namespace nana
impl_->editor()->reset_caret();
API::dev::lazy_refresh();
}
+
+ void drawer::dbl_click(graph_reference, const arg_mouse& arg)
+ {
+ if (impl_->mouse_button(arg, true))
+ API::dev::lazy_refresh();
+ }
void drawer::mouse_down(graph_reference, const arg_mouse& arg)
{
@@ -599,7 +605,10 @@ namespace nana
{
impl_->editor()->respond_char(arg);
if (impl_->editor()->try_refresh())
+ {
+ impl_->draw_spins();
API::dev::lazy_refresh();
+ }
}
void drawer::resized(graph_reference, const arg_resized&)
diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp
index e29b0d88..de6e2dd9 100644
--- a/source/gui/widgets/textbox.cpp
+++ b/source/gui/widgets/textbox.cpp
@@ -435,7 +435,23 @@ namespace drawerbase {
}
return *this;
}
+ //a native wstring version textbox::append
+ textbox& textbox::append(const std::wstring& text, bool at_caret)
+ {
+ internal_scope_guard lock;
+ auto editor = get_drawer_trigger().editor();
+ if(editor)
+ {
+ if(at_caret == false)
+ editor->move_caret_end(false);
+ editor->put(text);
+
+ editor->try_refresh();
+ API::update_window(this->handle());
+ }
+ return *this;
+ }
/// Determine wheter the text is auto-line changed.
bool textbox::line_wrapped() const
{
diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp
index 906bd969..88468861 100644
--- a/source/gui/widgets/treebox.cpp
+++ b/source/gui/widgets/treebox.cpp
@@ -1825,7 +1825,6 @@ namespace nana
item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y);
impl_->attr.tree_cont.for_each(shape.first, nl);
- bool has_redraw = false;
auto & node_state = impl_->node_state;
node_state.pressed_node = nl.node();
@@ -1834,21 +1833,17 @@ namespace nana
{
if(impl_->set_expanded(node_state.pressed_node, !node_state.pressed_node->value.second.expanded))
impl_->make_adjust(node_state.pressed_node, 0);
-
- has_redraw = true; //btw, don't select the node
}
-
- if ((!has_redraw) && (node_state.selected != node_state.pressed_node))
+ else if (node_state.selected != node_state.pressed_node)
{
impl_->set_selected(node_state.pressed_node);
- has_redraw = true;
}
+ else
+ return;
- if(has_redraw)
- {
- impl_->draw(true);
- API::dev::lazy_refresh();
- }
+
+ impl_->draw(true);
+ API::dev::lazy_refresh();
}
void trigger::mouse_up(graph_reference, const arg_mouse& arg)
diff --git a/source/gui/wvl.cpp b/source/gui/wvl.cpp
index 820a8ba7..610484cd 100644
--- a/source/gui/wvl.cpp
+++ b/source/gui/wvl.cpp
@@ -15,7 +15,12 @@
#include
#include
#include
-#include
+
+#ifdef STD_THREAD_NOT_SUPPORTED
+# include
+#else
+# include
+#endif
//#define NANA_AUTOMATIC_GUI_TESTING
namespace nana
diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp
index b7dd3426..62f74016 100644
--- a/source/paint/graphics.cpp
+++ b/source/paint/graphics.cpp
@@ -240,12 +240,16 @@ namespace paint
graphics::graphics(graphics&& other)
: impl_(std::move(other.impl_))
{
+ other.impl_.reset(new implementation);
}
graphics& graphics::operator=(graphics&& other)
{
if (this != &other)
+ {
impl_ = std::move(other.impl_);
+ other.impl_.reset(new implementation);
+ }
return *this;
}
@@ -265,9 +269,9 @@ namespace paint
return (!impl_->handle);
}
- graphics::operator const void *() const
+ graphics::operator bool() const noexcept
{
- return impl_->handle;
+ return (impl_->handle != nullptr);
}
drawable_type graphics::handle() const
@@ -287,9 +291,15 @@ namespace paint
return (impl_->handle ? impl_->handle->context : nullptr);
}
+ void graphics::swap(graphics& other) noexcept
+ {
+ if (context() != other.context())
+ impl_.swap(other.impl_);
+ }
+
void graphics::make(const ::nana::size& sz)
{
- if(impl_->handle == nullptr || impl_->size != sz)
+ if (impl_->handle == nullptr || impl_->size != sz)
{
if (sz.empty())
{
@@ -298,9 +308,10 @@ namespace paint
}
//The object will be delete while dwptr_ is performing a release.
- drawable_type dw = new nana::detail::drawable_impl_type;
+ std::shared_ptr dw{ new nana::detail::drawable_impl_type, detail::drawable_deleter{} };
+
//Reuse the old font
- if(impl_->platform_drawable)
+ if (impl_->platform_drawable)
{
drawable_type reuse = impl_->platform_drawable.get();
dw->font = reuse->font;
@@ -310,8 +321,13 @@ namespace paint
dw->font = impl_->font_shadow.impl_->real_font;
#if defined(NANA_WINDOWS)
- HDC hdc = ::GetDC(0);
+ HDC hdc = ::GetDC(nullptr);
HDC cdc = ::CreateCompatibleDC(hdc);
+ if (nullptr == cdc)
+ {
+ ::ReleaseDC(nullptr, hdc);
+ throw std::bad_alloc{};
+ }
BITMAPINFO bmi;
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
@@ -324,34 +340,60 @@ namespace paint
HBITMAP bmp = ::CreateDIBSection(cdc, &bmi, DIB_RGB_COLORS, reinterpret_cast(&(dw->pixbuf_ptr)), 0, 0);
- if(bmp)
- {
- ::DeleteObject((HBITMAP)::SelectObject(cdc, bmp));
- ::DeleteObject(::SelectObject(cdc, dw->font->native_handle()));
-
- dw->context = cdc;
- dw->pixmap = bmp;
- ::SetBkMode(cdc, TRANSPARENT);
- }
- else
+ if (nullptr == bmp)
{
::DeleteDC(cdc);
- delete dw;
- dw = nullptr;
- release();
+ ::ReleaseDC(nullptr, hdc);
+ throw std::bad_alloc{};
}
+ ::DeleteObject((HBITMAP)::SelectObject(cdc, bmp));
+ ::DeleteObject(::SelectObject(cdc, dw->font->native_handle()));
+
+ dw->context = cdc;
+ dw->pixmap = bmp;
+ ::SetBkMode(cdc, TRANSPARENT);
+
::ReleaseDC(0, hdc);
#elif defined(NANA_X11)
auto & spec = nana::detail::platform_spec::instance();
- Display* disp = spec.open_display();
- int screen = DefaultScreen(disp);
- Window root = ::XRootWindow(disp, screen);
- dw->pixmap = ::XCreatePixmap(disp, root, sz.width, sz.height, DefaultDepth(disp, screen));
- dw->context = ::XCreateGC(disp, dw->pixmap, 0, 0);
- #if defined(NANA_USE_XFT)
- dw->xftdraw = ::XftDrawCreate(disp, dw->pixmap, spec.screen_visual(), spec.colormap());
- #endif
+ {
+ nana::detail::platform_scope_guard psg;
+
+ spec.set_error_handler();
+
+ Display* disp = spec.open_display();
+ int screen = DefaultScreen(disp);
+ Window root = ::XRootWindow(disp, screen);
+ auto pixmap = ::XCreatePixmap(disp, root, sz.width, sz.height, DefaultDepth(disp, screen));
+ if(spec.error_code)
+ {
+ spec.rev_error_handler();
+ throw std::bad_alloc();
+ }
+ auto context = ::XCreateGC(disp, pixmap, 0, 0);
+ if (spec.error_code)
+ {
+ ::XFreePixmap(disp, pixmap);
+ spec.rev_error_handler();
+ throw std::bad_alloc();
+ }
+# if defined(NANA_USE_XFT)
+ auto xftdraw = ::XftDrawCreate(disp, pixmap, spec.screen_visual(), spec.colormap());
+ if (spec.error_code)
+ {
+ ::XFreeGC(disp, context);
+ ::XFreePixmap(disp, pixmap);
+
+ spec.rev_error_handler();
+ throw std::bad_alloc();
+ }
+
+ dw->xftdraw = xftdraw;
+# endif
+ dw->pixmap = pixmap;
+ dw->context = context;
+ }
#endif
if(dw)
{
@@ -362,8 +404,8 @@ namespace paint
#else
dw->update_text_color();
#endif
- impl_->platform_drawable.reset(dw, detail::drawable_deleter{});
- impl_->handle = dw;
+ impl_->platform_drawable = dw;
+ impl_->handle = dw.get();
impl_->size = sz;
impl_->handle->string.tab_pixels = detail::raw_text_extent_size(impl_->handle, L"\t", 1).width;