Merge pull request #3 from cnjinhao/hotfix-1.7

Hotfix 1.7 sync
This commit is contained in:
ErrorFlynn 2019-03-12 11:21:49 -04:00 committed by GitHub
commit 40085f24cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
121 changed files with 9504 additions and 6266 deletions

6
.gitattributes vendored Normal file
View File

@ -0,0 +1,6 @@
*.sln text eol=crlf
*.vcxproj text eol=crlf
*.vcxproj.filters text eol=crlf
*.vcxproj.user text eol=crlf
*.bat text eol=crlf
Makefile text eolf=lf

1
.gitignore vendored
View File

@ -42,6 +42,7 @@ lib/
CMakeCache.txt
CMakeFiles/
cmake-build-debug/
cmake-build-*/
.idea/
cmake_install.cmake
*.DS_Store

View File

@ -20,6 +20,7 @@ matrix:
- alsa-oss
- libx11-dev
- libxft-dev
- libxcursor-dev
sources:
- ubuntu-toolchain-r-test
@ -36,15 +37,18 @@ matrix:
- alsa-oss
- libx11-dev
- libxft-dev
- libxcursor-dev
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise
before_install:
- git clone --depth=1 --branch=develop https://github.com/qPCR4vir/nana-demo.git ../nana-demo
- cd ..
- git clone --depth=1 --branch=cmake-dev 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
- wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.12/cmake-3.12.0-rc3-Linux-x86_64.sh || true
- chmod -R +x /tmp/tools
install:
@ -57,31 +61,15 @@ before_script :
- sleep 3 # give xvfb some time to start
# we have: qPCR4vir/nana/../nana-demo and now we are in: qPCR4vir/nana/ our executable tests will access: ../nana-demo/Examples/*.bmp etc.(need to be in parallel with nana-demo/Examples)
#- cd ../nana-demo
- mkdir ../nana_lib
- mkdir ../nana_demo_bin
- cd ../nana_lib
- mkdir bin
- cd bin
- mkdir demo-build
- cd demo-build
script:
# Installing: the static "nana lib" will be in DESTDIR/CMAKE_INSTALL_PREFIX/lib/
# and the includes files "nana" in DESTDIR/CMAKE_INSTALL_PREFIX/include/
# 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
- make install
- ls
- cd ..
- ls
- cd ..
- ls
- cd nana_demo_bin
- cmake -G"Unix Makefiles" ../nana-demo -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_INCLUDE_EXPERIMENTAL_DEMOS=OFF -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON
- cmake -G"Unix Makefiles" ../nana-demo -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=ON -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON
- make install
# todo: separate resources from sources (a directory for images)
- ls
- cd ../bin
- cd ../nana-test/bin
- ls
- ./a_group_impl
- ./animate-bmp

View File

@ -1,272 +1,65 @@
# CMake configuration for Nana
# Author: Andrew Kornilov(https://github.com/ierofant)
# Contributors:
# Andrew Kornilov (ierofant) - original version
# Jinhao
# Robert Hauck - Enable support for PNG/Freetype
# Qiangqiang Wu - Add biicode support
# Ariel Vina-Rodriguez (qPCR4vir)
# (King_DuckZ)
# Robert Hauck - Enable support for PNG/Freetype
# Pavel O. - fix compilation with boost::filesystem (#281)
# Frostbane - Add option for compiling a shared library (#263,#265)
# Qiangqiang Wu - Add biicode support: todo migrate to https://conan.io/
#
# 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
# will distribute all of them. But by now CMake is just one of them and all the other distributed build system
# files/projects are manually write. This current CMakeList.txt reflect this fact and that is why we don't
# Maybe CMake will be used in the future to generate some of them in the central nana repository.
# But by now CMake is just one option and all the other build system
# files/projects distributed are manually writen. This current CMakeList.txt reflect this fact and that is why we don't
# generate here configurated *.h files or explicitly enumerate the sources files: anyway this CM-list
# will be "touched" to force a re-run of cmake.
#https://cmake.org/cmake-tutorial/
#https://cmake.org/cmake/help/v3.3/module/CMakeDependentOption.html?highlight=cmakedependentoption
# use CACHE FORCE or set(ENABLE_MINGW_STD_THREADS_WITH_MEGANZ ON) or delete CMakecache.txt or the entirely build dir
# if your changes don't execute
# It seems that project() defines essential system variables like CMAKE_FIND_LIBRARY_PREFIXES.
# https://bbs.archlinux.org/viewtopic.php?id=84967
# https://cliutils.gitlab.io/modern-cmake/
# https://cmake.org/cmake-tutorial/
# https://cmake.org/cmake/help/v3.12/module/CMakeDependentOption.html?highlight=cmakedependentoption
# cmake 3.12 have more better modern c++ support
project(nana)
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(nana VERSION 1.6.2
DESCRIPTION "C++ GUI library"
HOMEPAGE_URL http://nanapro.org
LANGUAGES CXX )
option(NANA_CMAKE_INSTALL_INCLUDES "Install nana includes when compile the library" ON)
option(NANA_CMAKE_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ "replaced boost.thread with meganz's mingw-std-threads." OFF)
option(NANA_CMAKE_ENABLE_PNG "Enable the use of PNG" OFF)
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)
####################### Main setting of Nana targets, sources and installs #####################
# 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
# This is not a workaround, but an user option.
# The library maybe available in the std library in use or from Boost (almost compatible)
# http://www.boost.org/doc/libs/1_60_0/libs/filesystem/doc/index.htm
# or you can choose to use the (partial, but functional) implementation provided by nana.
# If you include the file <nana/filesystem/filesystem.hpp> or <nana/filesystem/filesystem_ext.hpp>
# the selected option will be set by nana into std::experimental::filesystem
# By default Nana will try to use the STD. If STD is not available and NANA_CMAKE_FIND_BOOST_FILESYSTEM
# is set to ON nana will try to use boost if available. Nana own implementation will be use if none of
# the previus were selected or available.
# 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)
option(NANA_CMAKE_STD_FILESYSTEM_FORCE "Use of STD filesystem?(a compilation error will ocurre if not available)" OFF)
option(NANA_CMAKE_BOOST_FILESYSTEM_FORCE "Force use of Boost filesystem if available (over STD)?" OFF)
add_library(nana)
target_compile_features(nana PUBLIC cxx_std_17)
########### Compatibility with CMake 3.1
if(POLICY CMP0054)
# http://www.cmake.org/cmake/help/v3.1/policy/CMP0054.html
cmake_policy(SET CMP0054 NEW)
endif()
# need after cxx_std_14 or cxx_std_17 ??
target_compile_features(nana
PUBLIC cxx_nullptr
PUBLIC cxx_range_for
PUBLIC cxx_lambdas
PUBLIC cxx_decltype_auto
PUBLIC cxx_defaulted_functions
PUBLIC cxx_deleted_functions
PUBLIC cxx_auto_type
PUBLIC cxx_decltype_incomplete_return_types
PUBLIC cxx_defaulted_move_initializers
PUBLIC cxx_noexcept
PUBLIC cxx_rvalue_references
)
########### OS
### collect all source sub-directories in a list to avoid duplication ###
if(WIN32)
add_definitions(-DWIN32)
# 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)
option(MSVC_USE_STATIC_RUNTIME "Set to ON to build nana with the /MT(d) option." ON)
# By using CMAKE_CURRENT_LIST_DIR here you can compile and consume nana by just:
# add_subdirectory(../nana ../cmake-nana-build-${CONFIG} ) or simmilar
# in your own CMakeLists.txt, and them :
# target_link_libraries(yourApp PRIVATE nana )
# Change the MSVC Compiler flags
if(MSVC_USE_MP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
endif()
set(NANA_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source)
if(MSVC_USE_STATIC_RUNTIME)
foreach(flag
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
endif()
endforeach()
endif()
endif()
if(MINGW)
if(NANA_CMAKE_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ)
add_definitions(-DSTD_THREAD_NOT_SUPPORTED)
add_definitions(-DNANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ)
endif()
endif()
if(MSVC)
set(DLLTOOL OFF)
else()
# mingw: If dlltool is found the def and lib file will be created
find_program (DLLTOOL dlltool)
if(NOT DLLTOOL)
message(WARNING "dlltool not found. Skipping import library generation.")
endif()
endif()
endif()
if(APPLE)
add_definitions(-DAPPLE)
include_directories(/opt/X11/include/)
list(APPEND NANA_LINKS -L/opt/X11/lib/ -liconv)
set(ENABLE_AUDIO OFF)
elseif(UNIX)
add_definitions(-Dlinux)
endif()
if(UNIX)
list(APPEND NANA_LINKS -lX11)
include(FindFreetype)
if(FREETYPE_FOUND)
include_directories( ${FREETYPE_INCLUDE_DIRS})
list(APPEND NANA_LINKS -lXft -lfontconfig)
endif()
endif()
########### Compilers
#
# Using gcc: gcc 4.8 don't support C++14 and make_unique. You may want to update at least to 4.9.
# 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")
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
set(CMAKE_CXX_FLAGS "-std=gnu++14 -Wall -I/usr/local/include")
else()
set(CMAKE_CXX_FLAGS "-std=gnu++14 -Wall")
endif()
else()
set(CMAKE_CXX_FLAGS "-std=c++14 -Wall")
endif()
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if(NANA_CMAKE_SHARED_LIB)
list(APPEND NANA_LINKS -lgcc -lstdc++ -pthread)
else()
if(MINGW)
set(CMAKE_EXE_LINKER_FLAGS "-static -pthread")
else()
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread")
endif()
endif(NANA_CMAKE_SHARED_LIB)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
# GCC 4.9
list(APPEND NANA_LINKS "-lboost_system -lboost_thread")
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3)
# IS_GNUCXX < 5.3
else()
list(APPEND NANA_LINKS -lstdc++fs)
endif()
endif()
if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # APPLE Clang
list(APPEND NANA_LINKS -stdlib=libstdc++)
endif ()
############# Optional libraries
# Find PNG
if(NANA_CMAKE_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(-DNANA_ENABLE_PNG -DUSE_LIBPNG_FROM_OS)
endif()
else()
add_definitions(-DNANA_ENABLE_PNG)
endif()
endif()
# Find JPEG
if(NANA_CMAKE_ENABLE_JPEG)
add_definitions(-DNANA_ENABLE_JPEG)
if(NANA_CMAKE_LIBJPEG_FROM_OS)
find_package(JPEG)
if(JPEG_FOUND)
include_directories( ${JPEG_INCLUDE_DIR})
list(APPEND NANA_LINKS ${JPEG_LIBRARY})
add_definitions(-DNANA_ENABLE_JPEG -DUSE_LIBJPEG_FROM_OS)
endif()
else()
add_definitions(-DNANA_ENABLE_JPEG)
endif()
endif()
# Find ASOUND
if(NANA_CMAKE_ENABLE_AUDIO)
add_definitions(-DNANA_ENABLE_AUDIO)
if(UNIX)
find_package(ASOUND)
if(ASOUND_FOUND)
include_directories(${ASOUND_INCLUDE_DIRS})
list(APPEND NANA_LINKS -lasound)
else()
message(FATAL_ERROR "libasound is not found")
endif()
endif()
endif()
# Find/Select filesystem
if(NANA_CMAKE_NANA_FILESYSTEM_FORCE)
add_definitions(-DNANA_FILESYSTEM_FORCE)
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(-DBOOST_FILESYSTEM_FORCE)
endif()
# 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,
# even if system is not specified when using find_package and if Boost::system is not added to target_link_libraries.
# If using Boost::thread, then Thread::Thread will also be added automatically.
find_package(Boost COMPONENTS filesystem)
if(Boost_FOUND)
add_definitions(-DBOOST_FILESYSTEM_AVAILABLE)
include_directories(SYSTEM "${Boost_INCLUDE_DIR}")
list(APPEND NANA_LINKS ${Boost_LIBRARIES})
endif()
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
endif()
######## Nana options
add_definitions(-DNANA_IGNORE_CONF)
if(NANA_CMAKE_VERBOSE_PREPROCESSOR)
add_definitions(-DVERBOSE_PREPROCESSOR)
endif()
if(NANA_CMAKE_AUTOMATIC_GUI_TESTING)
add_definitions(-DNANA_AUTOMATIC_GUI_TESTING)
enable_testing()
endif()
####################### Main setting of Nana sources, targets and install
set(NANA_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/source)
set(NANA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
# collect all source sub-directories in a list to avoid duplication here
set(NANA_SOURCE_SUBDIRS /.
set(NANA_SOURCE_SUBDIRS
/.
/detail
/detail/posix
/filesystem
/gui
/gui/detail
@ -278,104 +71,70 @@ set(NANA_SOURCE_SUBDIRS /.
/threads
)
if(NANA_CMAKE_ENABLE_AUDIO)
list(APPEND NANA_SOURCE_SUBDIRS /audio
list(APPEND NANA_SOURCE_SUBDIRS
/audio
/audio/detail
)
endif()
# collect all source files in the source-sub-dir
# To show .h files in Visual Studio, add them to the list of sources in add_executable / add_library
# and Use SOURCE_GROUP if all your sources are in the same directory
foreach(subdir ${NANA_SOURCE_SUBDIRS})
aux_source_directory(${NANA_SOURCE_DIR}${subdir} SOURCES)
aux_source_directory(${NANA_SOURCE_DIR}${subdir} SOURCES) # todo: use GLOB to add headers too ??
endforeach()
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
add_definitions(-fmax-errors=3)
target_sources(nana PRIVATE ${SOURCES})
### collect all headers sub-directories in a list to avoid duplication ###
# To show .h files in Visual Studio, add them to the list of sources in add_executable / add_library / target_sources
# and Use SOURCE_GROUP if all your sources are in the same directory
set(NANA_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include)
set(NANA_INCLUDE_SUBDIRS
/.
/filesystem
/gui
/gui/detail
/gui/widgets
/gui/widgets/skeletons
/paint
/paint/detail
/pat
/system
/threads
)
if(NANA_CMAKE_ENABLE_AUDIO)
list(APPEND NANA_INCLUDE_SUBDIRS
/audio
/audio/detail
)
endif()
set(CMAKE_DEBUG_POSTFIX "_d")
foreach(subdir ${NANA_INCLUDE_SUBDIRS})
aux_source_directory(${NANA_INCLUDE_DIR}/nana${subdir} HEADERS) # todo: use GLOB to add headers too !!!!!!!
endforeach()
if(NANA_CMAKE_SHARED_LIB)
add_library(${PROJECT_NAME} SHARED ${SOURCES})
else()
add_library(${PROJECT_NAME} STATIC ${SOURCES})
### Some nana compilation options ###
option(NANA_CMAKE_AUTOMATIC_GUI_TESTING "Activate automatic GUI testing?" OFF)
option(NANA_CMAKE_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ "replaced boost.thread with meganz's mingw-std-threads." OFF) # deprecate?
######## Nana options
target_compile_definitions(nana PRIVATE NANA_IGNORE_CONF) # really ?
if(NANA_CMAKE_AUTOMATIC_GUI_TESTING)
target_compile_definitions(nana PUBLIC NANA_AUTOMATIC_GUI_TESTING)
# todo: enable_testing() # ??
endif()
target_include_directories(${PROJECT_NAME} PUBLIC ${NANA_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${NANA_LINKS})
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/build/cmake/Modules)
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/install_nana.cmake) # includes and libs, or just expose the nana target
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/OS.cmake) # windows, unix, linux, apple, ...
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/shared_libs.cmake) # static vs shared
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/compilers.cmake) # VC, gcc, clang
# Headers: use INCLUDE_DIRECTORIES
# Libraries: use FIND_LIBRARY and link with the result of it (try to avoid LINK_DIRECTORIES)
############# Optional libraries #####################
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/enable_png.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/enable_jpeg.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/enable_audio.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/select_filesystem.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/build/cmake/verbose.cmake) # Just for information
# 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
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()
if(NANA_CMAKE_SHARED_LIB)
if(WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
if(DLLTOOL)
#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()
endif()
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()
# Just for information:
message ("")
message ( "CMAKE_CXX_COMPILER_ID = " ${CMAKE_CXX_COMPILER_ID})
message ( "COMPILER_IS_CLANG = " ${COMPILER_IS_CLANG})
message ( "CMAKE_COMPILER_IS_GNUCXX = " ${CMAKE_COMPILER_IS_GNUCXX})
message ( "CMAKE_CXX_FLAGS = " ${CMAKE_CXX_FLAGS})
message ( "CMAKE_EXE_LINKER_FLAGS = " ${CMAKE_EXE_LINKER_FLAGS})
message ( "CMAKE_STATIC_LINKER_FLAGS = " ${CMAKE_STATIC_LINKER_FLAGS})
message ( "NANA_LINKS = " ${NANA_LINKS})
message ( "DESTDIR = " ${DESTDIR})
message ( "CMAKE_INSTALL_PREFIX = " ${CMAKE_INSTALL_PREFIX})
message ( "NANA_INCLUDE_DIR = " ${NANA_INCLUDE_DIR})
message ( "CMAKE_CURRENT_SOURCE_DIR = " ${CMAKE_CURRENT_SOURCE_DIR})
message ( "NANA_CMAKE_ENABLE_AUDIO = " ${NANA_CMAKE_ENABLE_AUDIO})
message ( "NANA_CMAKE_SHARED_LIB = " ${NANA_CMAKE_SHARED_LIB})
message ( "NANA_CLION = " ${NANA_CLION})
message ( "CMAKE_MAKE_PROGRAM = " ${CMAKE_MAKE_PROGRAM})
message ( "CMAKE_CXX_COMPILER_VERSION = " ${CMAKE_CXX_COMPILER_VERSION})
message ( "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})

View File

@ -1,12 +0,0 @@
# Minimal layout, with all auxiliary folders inside "bii" and
# The binary "bin" folder as is, and enabled code edition in the project root
cmake: bii/cmake
lib: bii/lib
build: bii/build
deps: bii/deps
# Setting this to True enables directly editing in the project root
# instead of blocks/youruser/yourblock
# the block will be named as your project folder
auto-root-block: True
root-block: qiangwu/nana

View File

@ -1,11 +0,0 @@
# This file configures your finds of dependencies.
#
# It is an ordered list of rules, which will be evaluated in order, of the form:
# block_pattern: TAG
#
# For each possible block that could resolve your dependencies,
# only versions with tag >= TAG will be accepted
qiangwu/* : DEV
* : STABLE

View File

@ -1,2 +0,0 @@
cmake: {generator: MinGW Makefiles}
os: {arch: 32bit, family: Windows, subfamily: '7', version: 6.1.7601}

View File

@ -1,49 +0,0 @@
# Biicode configuration file
[requirements]
glenn/png: 6
[parent]
# The parent version of this block. Must match folder name. E.g.
# user/block # No version number means not published yet
# You can change it to publish to a different track, and change version, e.g.
# user/block(track): 7
qiangwu/nana: 0
[paths]
# Local directories to look for headers (within block)
# /
include
[dependencies]
# Manual adjust file implicit dependencies, add (+), remove (-), or overwrite (=)
# hello.h + hello_imp.cpp hello_imp2.cpp
# *.h + *.cpp
include/nana/config.hpp + include/*
include/nana/config.hpp + source/*
[mains]
# Manual adjust of files that define an executable
# !main.cpp # Do not build executable from this file
# main2.cpp # Build it (it doesnt have a main() function, but maybe it includes it)
[tests]
# Manual adjust of files that define a CTest test
# test/* pattern to evaluate this test/ folder sources like tests
[hooks]
# These are defined equal to [dependencies],files names matching bii*stage*hook.py
# will be launched as python scripts at stage = {post_process, clean}
# CMakeLists.txt + bii/my_post_process1_hook.py bii_clean_hook.py
[includes]
# Mapping of include patterns to external blocks
# hello*.h: user3/depblock # includes will be processed as user3/depblock/hello*.h
png.h: glenn/png
[data]
# Manually define data files dependencies, that will be copied to bin for execution
# By default they are copied to bin/user/block/... which should be taken into account
# when loading from disk such data
# image.cpp + image.jpg # code should write open("user/block/image.jpg")

View File

@ -30,6 +30,7 @@ library nana {
detail/platform_spec_selector.cpp
gui/animation.cpp
gui/basis.cpp
gui/dragdrop.cpp
gui/dragger.cpp
gui/drawing.cpp
gui/effects.cpp
@ -62,7 +63,6 @@ library nana {
gui/widgets/date_chooser.cpp
gui/widgets/float_listbox.cpp
gui/widgets/form.cpp
gui/widgets/frame.cpp
gui/widgets/label.cpp
gui/widgets/listbox.cpp
gui/widgets/menubar.cpp

View File

@ -0,0 +1,69 @@
# - Try to find the Fontconfig
# Once done this will define
#
# FONTCONFIG_FOUND - system has Fontconfig
# FONTCONFIG_INCLUDE_DIR - The include directory to use for the fontconfig headers
# FONTCONFIG_LIBRARIES - Link these to use FONTCONFIG
# FONTCONFIG_DEFINITIONS - Compiler switches required for using FONTCONFIG
# Copyright (c) 2006,2007 Laurent Montel, <montel@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
if (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR)
# in cache already
set(FONTCONFIG_FOUND TRUE)
else (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR)
if (NOT WIN32)
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
pkg_check_modules(PC_FONTCONFIG fontconfig)
set(FONTCONFIG_DEFINITIONS ${PC_FONTCONFIG_CFLAGS_OTHER})
endif (NOT WIN32)
find_path(FONTCONFIG_INCLUDE_DIR fontconfig/fontconfig.h
PATHS
${PC_FONTCONFIG_INCLUDEDIR}
${PC_FONTCONFIG_INCLUDE_DIRS}
/usr/X11/include
)
find_library(FONTCONFIG_LIBRARIES NAMES fontconfig
PATHS
${PC_FONTCONFIG_LIBDIR}
${PC_FONTCONFIG_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Fontconfig DEFAULT_MSG FONTCONFIG_LIBRARIES FONTCONFIG_INCLUDE_DIR )
mark_as_advanced(FONTCONFIG_LIBRARIES FONTCONFIG_INCLUDE_DIR)
endif (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR)

70
build/cmake/OS.cmake Normal file
View File

@ -0,0 +1,70 @@
########### OS
# https://blog.kowalczyk.info/article/j/guide-to-predefined-macros-in-c-compilers-gcc-clang-msvc-etc..html
# http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
if(WIN32)
target_compile_definitions(nana PUBLIC WIN32) # todo: why not simple test for _WIN32 in code??
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)
option(MSVC_USE_STATIC_RUNTIME "Set to ON to build nana with the /MT(d) option." ON)
# Change the MSVC Compiler flags
if(MSVC_USE_MP)
target_compile_options(nana PUBLIC "/MP" )
endif()
if(MSVC_USE_STATIC_RUNTIME)
foreach(flag
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
endif()
endforeach()
endif()
endif()
if(MINGW)
if(NANA_CMAKE_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ) # deprecated ?????
target_compile_definitions(nana PUBLIC STD_THREAD_NOT_SUPPORTED
PUBLIC NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ )
endif()
endif()
endif()
if(APPLE)
target_compile_definitions(nana PUBLIC APPLE) # ??? not added by compilers? use __APPLE__ ?
target_include_directories(nana PUBLIC /opt/X11/include/)
target_link_libraries(nana PRIVATE iconv)
set(ENABLE_AUDIO OFF)
endif()
if(UNIX)
find_package(X11 REQUIRED) # X11 - todo test PRIVATE
target_link_libraries(nana
PUBLIC ${X11_LIBRARIES}
PUBLIC ${X11_Xft_LIB}
)
target_include_directories(nana SYSTEM
PUBLIC ${X11_Xft_INCLUDE_PATH}
PUBLIC ${X11_INCLUDE_DIR}
)
find_package(Freetype) # Freetype - todo test PRIVATE
if (FREETYPE_FOUND)
find_package(Fontconfig REQUIRED)
target_include_directories(nana SYSTEM
PUBLIC ${FREETYPE_INCLUDE_DIRS}
PUBLIC ${FONTCONFIG_INCLUDE_DIR}
)
target_link_libraries(nana
PUBLIC ${FREETYPE_LIBRARIES}
PUBLIC ${FONTCONFIG_LIBRARIES}
)
endif(FREETYPE_FOUND)
endif(UNIX)

View File

@ -0,0 +1,48 @@
########### Compilers
#
# Using gcc: gcc 4.8 don't support C++14 and make_unique. You may want to update at least to 4.9.
# gcc 5.3 and 5.4 include filesytem, but you need to add the link flag: -lstdc++fs
#
# In Windows, with CLion Allways check 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") # AND NOT MINGW??
target_compile_options(nana PRIVATE -Wall
PUBLIC -g )
set(THREADS_PREFER_PTHREAD_FLAG ON) # todo - test this
find_package(Threads REQUIRED)
target_link_libraries(nana PRIVATE Threads::Threads)
# target_compile_options(nana PUBLIC -pthread)
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
target_compile_options(nana PUBLIC -I/usr/local/include)
endif()
endif()
# target_link_libraries(nana PRIVATE stdc++fs) # ??
endif()
if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # APPLE Clang
target_compile_options(nana PUBLIC -stdlib=libstdc++)
endif ()
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
target_compile_options(nana PRIVATE -fmax-errors=3)
endif()

View File

@ -0,0 +1,15 @@
option(NANA_CMAKE_ENABLE_AUDIO "Enable class audio::play for PCM playback." OFF)
# todo: decide - PUBLIC vs PRIVATE
if(NANA_CMAKE_ENABLE_AUDIO)
target_compile_definitions(nana PUBLIC NANA_ENABLE_AUDIO)
if(UNIX)
find_package(ASOUND) # ? https://github.com/hintjens/demidi/blob/master/Findasound.cmake
if(ASOUND_FOUND)
target_include_directories(nana PUBLIC ${ASOUND_INCLUDE_DIRS})
target_link_libraries(nana PUBLIC ${ASOUND_LIBRARIES})
else()
message(FATAL_ERROR "libasound is not found")
endif()
endif()
endif()

View File

@ -0,0 +1,24 @@
option(NANA_CMAKE_ENABLE_JPEG "Enable the use of JPEG" OFF)
option(NANA_CMAKE_LIBJPEG_FROM_OS "Use libjpeg from operating system." ON)
option(JPEG_HAVE_BOOLEAN "Defining HAVE_BOOLEAN before including jpeglib.h" OFF)
# todo: decide - PUBLIC vs PRIVATE
if(NANA_CMAKE_ENABLE_JPEG)
target_compile_definitions(nana PUBLIC NANA_ENABLE_JPEG)
if(NANA_CMAKE_LIBJPEG_FROM_OS)
find_package(JPEG)
if(JPEG_FOUND)
target_include_directories(nana PUBLIC ${JPEG_INCLUDE_DIRS})
target_link_libraries (nana PUBLIC ${JPEG_LIBRARIES})
target_compile_definitions(nana PUBLIC USE_LIBJPEG_FROM_OS)
endif()
else()
target_compile_definitions(nana PUBLIC -ljpeg)
endif()
if(JPEG_HAVE_BOOLEAN)
# ... Defining HAVE_BOOLEAN before including jpeglib.h should make it work...
target_compile_definitions(nana PUBLIC HAVE_BOOLEAN)
endif()
endif()

View File

@ -0,0 +1,20 @@
option(NANA_CMAKE_ENABLE_PNG "Enable the use of PNG" OFF)
option(NANA_CMAKE_LIBPNG_FROM_OS "Use libpng from operating system." ON)
# todo: decide - PUBLIC vs PRIVATE
if(NANA_CMAKE_ENABLE_PNG)
target_compile_definitions(nana PUBLIC NANA_ENABLE_PNG)
if(NANA_CMAKE_LIBPNG_FROM_OS)
find_package(PNG)
if(PNG_FOUND)
target_include_directories(nana PUBLIC ${PNG_INCLUDE_DIRS})
target_link_libraries (nana PUBLIC ${PNG_LIBRARIES})
target_compile_definitions(nana PUBLIC USE_LIBPNG_FROM_OS ${PNG_DEFINITIONS})
# target_include_directories (nana SYSTEM PUBLIC PNG::PNG) # ??
# target_compile_definitions (nana PUBLIC USE_LIBPNG_FROM_OS)
endif()
else()
target_link_libraries(nana PUBLIC png) # provided by nana?
endif()
endif()

View File

@ -0,0 +1,23 @@
option(NANA_CMAKE_INSTALL "Install nana when compile the library (to be consumed without cmake)" OFF)
# Install the include directories too.
if(NANA_CMAKE_INSTALL)
# this is the prefered method to consume nana directly with some specific bulid system
# Is your responsability to ensure all compiler options are compatible with the compilation
# of the project linking to the nana lib here generated
target_sources(nana PRIVATE ${HEADERS})
target_include_directories(nana PRIVATE ${NANA_INCLUDE_DIR})
message("The compiled Nana library will be installed in ${CMAKE_INSTALL_PREFIX}/lib")
# Actually in DESTDIR/CMAKE_INSTALL_PREFIX/lib but in windows there is no DESTDIR/ part.
install(TARGETS nana
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include) # in ${CMAKE_INSTALL_PREFIX}/include/nana
message("The Nana include files will be installed in ${CMAKE_INSTALL_PREFIX}/include")
else()
# this is the prefered method to consume nana with cmake
target_sources(nana PUBLIC ${HEADERS})
target_include_directories(nana PUBLIC ${NANA_INCLUDE_DIR})
endif()

View File

@ -0,0 +1,55 @@
# 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
# This is not a workaround, but an user option.
# The library maybe available in the std library in use or from Boost (almost compatible)
# http://www.boost.org/doc/libs/1_60_0/libs/filesystem/doc/index.htm
# or you can choose to use the (partial, but functional) implementation provided by nana.
# If you include the file <nana/filesystem/filesystem.hpp> or <nana/filesystem/filesystem_ext.hpp>
# the selected option will be set by nana into std::experimental::filesystem
# By default Nana will try to use the STD. If STD is not available and NANA_CMAKE_FIND_BOOST_FILESYSTEM
# is set to ON nana will try to use boost if available. Nana own implementation will be use if none of
# the previus were selected or available.
# 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_NANA_FILESYSTEM_FORCE "Force nana filesystem over ISO and boost?" OFF)
option(NANA_CMAKE_STD_FILESYSTEM_FORCE "Use of STD filesystem?(a compilation error will ocurre if not available)" OFF)
option(NANA_CMAKE_BOOST_FILESYSTEM_FORCE "Force use of Boost filesystem if available (over STD)?" OFF)
option(NANA_CMAKE_FIND_BOOST_FILESYSTEM "Search: Is Boost filesystem available?" OFF)
if(NANA_CMAKE_NANA_FILESYSTEM_FORCE)
target_compile_definitions(nana PUBLIC NANA_FILESYSTEM_FORCE)
elseif(NANA_CMAKE_STD_FILESYSTEM_FORCE)
target_compile_definitions(nana PUBLIC STD_FILESYSTEM_FORCE)
target_link_libraries (nana PUBLIC stdc++fs)
elseif(NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
target_compile_definitions(nana PUBLIC 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,
# even if system is not specified when using find_package and if Boost::system is not added to target_link_libraries.
# If using Boost::thread, then Thread::Thread will also be added automatically.
find_package(Boost REQUIRED COMPONENTS filesystem)
if(Boost_FOUND)
target_compile_definitions(nana PUBLIC BOOST_FILESYSTEM_AVAILABLE)
# SYSTEM - ignore warnings from here
target_include_directories(nana SYSTEM PUBLIC "${Boost_INCLUDE_DIR}") # ?? SYSTEM
target_link_libraries (nana PUBLIC ${Boost_LIBRARIES})
# target_include_directories (nana SYSTEM PUBLIC Boost::Boost)
# message("boost found true")
endif()
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
else()
# todo test for std (for now just force nana or boost if there no std)
target_link_libraries (nana PUBLIC stdc++fs)
# todo if not test for boost
# if not add nana filesystem
endif()

View File

@ -0,0 +1,51 @@
option(BUILD_SHARED_LIBS "Compile nana as a shared library." OFF)
if(BUILD_SHARED_LIBS) # todo test
if(WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
if(MSVC)
set(DLLTOOL OFF)
else()
# mingw: If dlltool is found the def and lib file will be created
find_program (DLLTOOL dlltool)
if(NOT DLLTOOL)
message(WARNING "dlltool not found. Skipping import library generation.")
endif()
endif()
if(DLLTOOL)
#generate the lib and def files needed by msvc
set_target_properties (nana PROPERTIES
OUTPUT_NAME nana
ARCHIVE_OUTPUT_NAME nana
LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS_INIT} -Wl,--output-def=${CMAKE_CURRENT_BINARY_DIR}/libnana.def"
)
add_custom_command(TARGET nana POST_BUILD
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMAND echo " Generating import library"
COMMAND "${DLLTOOL}" --dllname "libnana.dll"
--input-def "libnana.def"
--output-lib "libnana.lib")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnana.def"
"${CMAKE_CURRENT_BINARY_DIR}/libnana.lib" DESTINATION lib)
endif()
endif()
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW??
if(BUILD_SHARED_LIBS)
target_compile_options(nana PUBLIC -lgcc -lstdc++)
else()
if(MINGW)
target_compile_options(nana PUBLIC -static) # -static ?? cmake knows BUILD_SHARED_LIBS
else()
target_compile_options(nana PUBLIC -static-libgcc -static-libstdc++)
endif()
endif(BUILD_SHARED_LIBS)
endif()

57
build/cmake/verbose.cmake Normal file
View File

@ -0,0 +1,57 @@
option(NANA_CMAKE_VERBOSE_PREPROCESSOR "Show annoying debug messages during compilation." OFF)
option(NANA_CMAKE_STOP_VERBOSE_PREPROCESSOR "Stop compilation after showing the annoying debug messages." OFF)
if (NANA_CMAKE_VERBOSE_PREPROCESSOR)
target_compile_definitions(nana PRIVATE VERBOSE_PREPROCESSOR)
### Just for information: ########################################
include(CMakePrintHelpers)
# see: https://cmake.org/cmake/help/v3.12/manual/cmake-properties.7.html#properties-on-targets
cmake_print_properties(TARGETS nana PROPERTIES
COMPILE_DEFINITIONS COMPILE_OPTIONS COMPILE_FLAGS LINK_LIBRARIES
INCLUDE_DIRECTORIES INSTALL_NAME_DIR LINK_FLAGS VERSION
)
#message ("")
# cmake_print_variables(SOURCES)
cmake_print_variables(HEADERS)
cmake_print_variables(PUBLIC_HEADERS)
cmake_print_variables(NANA_CMAKE_INSTALL)
cmake_print_variables(Boost_INCLUDE_DIR)
cmake_print_variables(Boost_LIBRARIES)
cmake_print_variables(Boost::filesystem)
cmake_print_variables(PNG_INCLUDE_DIRS)
cmake_print_variables(PNG_LIBRARIES)
cmake_print_variables(PNG::PNG)
cmake_print_variables(CMAKE_BUILD_TYPE)
cmake_print_variables(CMAKE_CONFIGURATION_TYPES)
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 ( "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 ( "CMAKE_MAKE_PROGRAM = " ${CMAKE_MAKE_PROGRAM})
message ( "CMAKE_CXX_COMPILER_VERSION = " ${CMAKE_CXX_COMPILER_VERSION})
message ( "NANA_CMAKE_NANA_FILESYSTEM_FORCE = " ${NANA_CMAKE_NANA_FILESYSTEM_FORCE})
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})
endif(NANA_CMAKE_VERBOSE_PREPROCESSOR)

View File

@ -66,6 +66,7 @@
<Unit filename="../../source/gui/detail/native_window_interface.cpp" />
<Unit filename="../../source/gui/detail/window_layout.cpp" />
<Unit filename="../../source/gui/detail/window_manager.cpp" />
<Unit filename="../../source/gui/dragdrop.cpp" />
<Unit filename="../../source/gui/dragger.cpp" />
<Unit filename="../../source/gui/drawing.cpp" />
<Unit filename="../../source/gui/effects.cpp" />
@ -87,7 +88,6 @@
<Unit filename="../../source/gui/widgets/date_chooser.cpp" />
<Unit filename="../../source/gui/widgets/float_listbox.cpp" />
<Unit filename="../../source/gui/widgets/form.cpp" />
<Unit filename="../../source/gui/widgets/frame.cpp" />
<Unit filename="../../source/gui/widgets/group.cpp" />
<Unit filename="../../source/gui/widgets/label.cpp" />
<Unit filename="../../source/gui/widgets/listbox.cpp" />

View File

@ -202,6 +202,7 @@
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
<ClCompile Include="..\..\source\gui\dragdrop.cpp" />
<ClCompile Include="..\..\source\gui\dragger.cpp" />
<ClCompile Include="..\..\source\gui\drawing.cpp" />
<ClCompile Include="..\..\source\gui\effects.cpp" />
@ -223,7 +224,6 @@
<ClCompile Include="..\..\source\gui\widgets\date_chooser.cpp" />
<ClCompile Include="..\..\source\gui\widgets\float_listbox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\form.cpp" />
<ClCompile Include="..\..\source\gui\widgets\frame.cpp" />
<ClCompile Include="..\..\source\gui\widgets\group.cpp" />
<ClCompile Include="..\..\source\gui\widgets\label.cpp" />
<ClCompile Include="..\..\source\gui\widgets\listbox.cpp" />
@ -324,7 +324,6 @@
<ClInclude Include="..\..\include\nana\gui\widgets\detail\tree_cont.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\float_listbox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\form.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\frame.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\group.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\label.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\listbox.hpp" />

View File

@ -147,9 +147,6 @@
<ClCompile Include="..\..\source\gui\widgets\form.cpp">
<Filter>Source Files\nana\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\frame.cpp">
<Filter>Source Files\nana\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\label.cpp">
<Filter>Source Files\nana\gui\widgets</Filter>
</ClCompile>
@ -333,6 +330,9 @@
<ClCompile Include="..\..\source\detail\platform_abstraction.cpp">
<Filter>Source Files\nana\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\dragdrop.cpp">
<Filter>Source Files\nana\gui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\source\gui\widgets\group.cpp">
@ -361,9 +361,6 @@
<ClInclude Include="..\..\include\nana\gui\widgets\form.hpp">
<Filter>Header Files\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\frame.hpp">
<Filter>Header Files\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\label.hpp">
<Filter>Header Files\gui\widgets</Filter>
</ClInclude>

View File

@ -196,6 +196,7 @@
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
<ClCompile Include="..\..\source\gui\dragdrop.cpp" />
<ClCompile Include="..\..\source\gui\dragger.cpp" />
<ClCompile Include="..\..\source\gui\drawing.cpp" />
<ClCompile Include="..\..\source\gui\effects.cpp" />
@ -217,7 +218,6 @@
<ClCompile Include="..\..\source\gui\widgets\date_chooser.cpp" />
<ClCompile Include="..\..\source\gui\widgets\float_listbox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\form.cpp" />
<ClCompile Include="..\..\source\gui\widgets\frame.cpp" />
<ClCompile Include="..\..\source\gui\widgets\group.cpp" />
<ClCompile Include="..\..\source\gui\widgets\label.cpp" />
<ClCompile Include="..\..\source\gui\widgets\listbox.cpp" />

View File

@ -141,9 +141,6 @@
<ClCompile Include="..\..\source\gui\widgets\form.cpp">
<Filter>Source Files\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\frame.cpp">
<Filter>Source Files\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\group.cpp">
<Filter>Source Files\gui\widgets</Filter>
</ClCompile>
@ -291,6 +288,9 @@
<ClCompile Include="..\..\source\detail\platform_abstraction.cpp">
<Filter>Source Files\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\dragdrop.cpp">
<Filter>Source Files\gui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\nana\any.hpp">

View File

@ -23,7 +23,6 @@
<ProjectGuid>{42D0520F-EFA5-4831-84FE-2B9085301C5D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>nana</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -102,6 +101,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -115,6 +115,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -130,6 +131,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -147,6 +149,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -179,6 +182,7 @@
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
<ClCompile Include="..\..\source\gui\dragdrop.cpp" />
<ClCompile Include="..\..\source\gui\dragger.cpp" />
<ClCompile Include="..\..\source\gui\drawing.cpp" />
<ClCompile Include="..\..\source\gui\effects.cpp" />
@ -200,7 +204,6 @@
<ClCompile Include="..\..\source\gui\widgets\date_chooser.cpp" />
<ClCompile Include="..\..\source\gui\widgets\float_listbox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\form.cpp" />
<ClCompile Include="..\..\source\gui\widgets\frame.cpp" />
<ClCompile Include="..\..\source\gui\widgets\group.cpp" />
<ClCompile Include="..\..\source\gui\widgets\label.cpp" />
<ClCompile Include="..\..\source\gui\widgets\listbox.cpp" />
@ -270,7 +273,6 @@
<ClInclude Include="..\..\include\nana\gui\widgets\date_chooser.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\float_listbox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\form.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\frame.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\group.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\label.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\listbox.hpp" />

View File

@ -151,9 +151,6 @@
<ClCompile Include="..\..\source\gui\widgets\form.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\frame.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\group.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
@ -292,6 +289,9 @@
<ClCompile Include="..\..\source\gui\wvl.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\dragdrop.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\nana\gui\widgets\spinbox.hpp">
@ -363,9 +363,6 @@
<ClInclude Include="..\..\include\nana\gui\widgets\form.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\frame.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\animation.hpp">
<Filter>Include\gui</Filter>
</ClInclude>

View File

@ -1,7 +1,14 @@
Please refer to the Library Installation Documentation for the detailed installation instructions.
http://nanapro.org/en-us/help/instl_lib_doc.htm
https://github.com/qPCR4vir/nana-docs/wiki/Installation
NOTE: The method of library installation for VC2003/2005/2008/2010/2012 is only for the version older than 0.8. Since version 0.8, the library only works in VC2013 and later. If you have not VC2013 installed, please choose the latest Codeblocks instead.
Using Clang
https://github.com/cnjinhao/nana/wiki/Compiling-Nana-with-Clang-8.0
请参考库安装文档获取详细的安装步骤。
http://nanapro.org/zh-cn/help/instl_lib_doc.htm
https://github.com/qPCR4vir/nana-docs/wiki/Installation
注意: 针对VC2003/2005/2008/2010/2012的安装方法只适用于低于0.8的版本。从0.8版起该库对Visual C++的最低版本要求是2013。如果您没有安装VC2013可以使用最新版的CodeBlocks代替。
使用 Clang
https://github.com/cnjinhao/nana/wiki/Compiling-Nana-with-Clang-8.0

View File

@ -1,13 +1,13 @@
/*
/**
* Basic Types definition
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/basic_types.hpp
* @file nana/basic_types.hpp
*/
#ifndef NANA_BASIC_TYPES_HPP

View File

@ -211,10 +211,10 @@
#undef _nana_std_optional
#if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703))) || \
((__cplusplus < 201703L) || \
#if ((defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703))) || \
((!defined(_MSC_VER)) && ((__cplusplus < 201703L) || \
(defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ < 400)) || \
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 701)) \
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 701))) \
)
# define _nana_std_optional
#endif

View File

@ -1,7 +1,7 @@
/**
* Nana Configuration
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -25,10 +25,6 @@
#include "c++defines.hpp"
//This marco is defined since 1.4 and until 1.5 for deprecating frame widget.
//This marco and class frame will be removed in version 1.5
#define WIDGET_FRAME_DEPRECATED
//The following basic configurations are ignored when NANA_IGNORE_CONF is defined.
//The NANA_IGNORE_CONF may be specified by CMake generated makefile.
#ifndef NANA_IGNORE_CONF
@ -71,7 +67,7 @@
///////////////////
// Support of PCM playback
//
#define NANA_ENABLE_AUDIO
//#define NANA_ENABLE_AUDIO
///////////////////
// Support for PNG

View File

@ -1,6 +1,6 @@
/*
* A Date Time Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -27,7 +27,7 @@ namespace nana
};
date(); ///< the initialized date is today.
date(const std::tm&);
explicit date(const std::tm&);
date(int year, int month, int day);
date operator - (int off) const;
@ -44,8 +44,8 @@ namespace nana
void set(const std::tm&);
static int day_of_week(int year, int month, int day);
static unsigned year_days(unsigned year); ///< the number of days in the specified year.
static unsigned month_days(unsigned year, unsigned month); ///< the number of days in the specified month.
static unsigned year_days(const unsigned year); ///< the number of days in the specified year.
static unsigned month_days(const unsigned year, const unsigned month); ///< the number of days in the specified month.
static unsigned day_in_year(unsigned y, unsigned m, unsigned d); ///< Returns the index of the specified day in this year, at range[1, 365] or [1, 366]
private:
date _m_add(unsigned x) const;

View File

@ -1,7 +1,7 @@
/**
* A ISO C++ filesystem Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -13,7 +13,7 @@
* and need VC2015 or a C++11 compiler. With a few correction can be compiler by VC2013
*/
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf --- last pdf of std draft N4100 <filesystem> 2014-07-04
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf --- pdf of std draft N4100 <filesystem> 2014-07-04
// 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 <filesystem> header VS2015
@ -55,36 +55,6 @@
#define NANA_USING_BOOST_FILESYSTEM 1
# include <chrono>
# include <boost/filesystem.hpp>
// dont include generic_u8string
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp
// enable directory_iterator C++11 range-base for
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp
// but travis come with an oooold version of boost
// NOT enable directory_iterator C++11 range-base for
// http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp
namespace boost
{
namespace filesystem
{
// enable directory_iterator C++11 range-base for statement use --------------------//
// begin() and end() are only used by a range-based for statement in the context of
// auto - thus the top-level const is stripped - so returning const is harmless and
// emphasizes begin() is just a pass through.
inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT
{
return iter;
}
inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT
{
return directory_iterator();
}
} // namespace filesystem
}
// add boost::filesystem into std::experimental::filesystem
namespace std {
@ -105,24 +75,57 @@ namespace std {
socket = boost::filesystem::file_type::socket_file,
unknown = boost::filesystem::file_type::type_unknown,
};
/// enable directory_iterator range-based for statements
//inline directory_iterator begin(directory_iterator iter) noexcept
//{
// return iter;
//}
// Boost dont include generic_u8string
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp
//
// Boost versions: 1.67.0, 1.66.0, ... 1.56.0 enable directory_iterator C++11 range-base for
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp
// but travis come with an oooold version of boost
// 1.55.0 NOT enable directory_iterator C++11 range-base for
// http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp
#if BOOST_VERSION < 105600
namespace boost
// enable directory_iterator C++11 range-base for statement use --------------------//
// begin() and end() are only used by a range-based for statement in the context of
// auto - thus the top-level const is stripped - so returning const is harmless and
// emphasizes begin() is just a pass through.
inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT
{
return iter;
}
inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT
{
return directory_iterator();
}
#endif
//inline directory_iterator end(const directory_iterator&) noexcept
//{
// return {};
//}
} // filesystem
} // experimental
namespace filesystem
{
using namespace experimental::filesystem;
}
} // std
#else
# undef NANA_USING_STD_FILESYSTEM
# define NANA_USING_STD_FILESYSTEM 1
# if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && defined(_MSVC_LANG) && _MSVC_LANG >= 201703)) || \
((__cplusplus >= 201703L) && \
(defined(__clang__) && (__clang_major__ >= 7) || \
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 8))) )
# include <filesystem>
# else
# include <experimental/filesystem>
namespace std{
namespace filesystem{
using namespace std::experimental::filesystem;
}
}
# endif
#endif
@ -172,7 +175,13 @@ namespace nana { namespace experimental { namespace filesystem
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;
enum class directory_options
{
none,
follow_directory_symlink,
skip_permission_denied
};
struct space_info
{
@ -231,7 +240,7 @@ namespace nana { namespace experimental { namespace filesystem
}
// modifiers
//void clear() noexcept;
void clear() noexcept;
path& make_preferred();
path& remove_filename();
//path& replace_filename(const path& replacement);
@ -239,10 +248,10 @@ namespace nana { namespace experimental { namespace filesystem
//void swap(path& rhs) noexcept;
// decomposition
//path root_name() const;
//path root_directory() const;
//path root_path() const;
//path relative_path() const;
path root_name() const;
path root_directory() const;
path root_path() const;
path relative_path() const;
path parent_path() const;
path filename() const;
//path stem() const;
@ -250,16 +259,16 @@ namespace nana { namespace experimental { namespace filesystem
// query
bool empty() const noexcept;
//bool has_root_name() const;
//bool has_root_directory() const;
//bool has_root_path() const;
//bool has_relative_path() const;
bool has_parent_path() const { return !parent_path().string().empty(); }; // temp;;
bool has_filename() const { return !filename().string().empty(); }; // temp;
bool has_root_name() const { return !root_name().empty(); }
bool has_root_directory() const { return !root_directory().empty(); }
bool has_root_path() const { return !root_path().empty(); }
bool has_relative_path() const { return !relative_path().empty(); }
bool has_parent_path() const { return !parent_path().empty(); }; // temp;;
bool has_filename() const { return !filename().empty(); }; // temp;
//bool has_stem() const;
bool has_extension() const { return !extension().string().empty(); }; // temp
//bool is_absolute() const;
//bool is_relative() const;
bool has_extension() const { return !extension().empty(); }; // temp
bool is_absolute() const;
bool is_relative() const;
int compare(const path& other) const;
@ -354,7 +363,8 @@ namespace nana { namespace experimental { namespace filesystem
public:
directory_iterator() noexcept;
explicit directory_iterator(const path& dir);
explicit directory_iterator(const path& p);
directory_iterator(const path& p, directory_options opt);
const value_type& operator*() const;
const value_type* operator->() const;
@ -378,6 +388,7 @@ namespace nana { namespace experimental { namespace filesystem
private:
bool end_{false};
path::string_type path_;
directory_options option_{ directory_options::none };
std::shared_ptr<find_handle> find_ptr_;
find_handle handle_{nullptr};
@ -417,14 +428,13 @@ namespace nana { namespace experimental { namespace filesystem
file_status status(const path& p, std::error_code&);
std::uintmax_t file_size(const path& p);
//uintmax_t file_size(const path& p, error_code& ec) noexcept;
std::uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
inline bool is_directory(file_status s) noexcept
{ return s.type() == file_type::directory ;}
bool is_directory(const path& p);
//bool is_directory(const path& p, error_code& ec) noexcept;
bool is_directory(const path& p, std::error_code& ec) noexcept;
inline bool is_regular_file(file_status s) noexcept
{
@ -520,10 +530,31 @@ namespace std {
# else
using namespace nana::experimental::filesystem::v1;
# endif
} // filesystem
} // experimental
namespace filesystem {
using namespace std::experimental::filesystem;
#if defined(NANA_FILESYSTEM_FORCE) || \
(defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)))
path absolute(const path& p);
path absolute(const path& p, std::error_code& err);
path canonical(const path& p);
path canonical(const path& p, std::error_code& err);
#endif
#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW)
bool exists( std::filesystem::file_status s ) noexcept;
bool exists( const std::filesystem::path& p );
bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept;
#endif
}
} // std
#endif //NANA_USING_NANA_FILESYSTEM
#include <nana/pop_ignore_diagnostic>

View File

@ -33,10 +33,10 @@ namespace filesystem_ext
constexpr auto const def_rootname = "Root/";
#endif
std::experimental::filesystem::path path_user(); ///< extention ?
std::filesystem::path path_user(); ///< extention ?
/// workaround Boost not having path.generic_u8string() - a good point for http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0251r0.pdf
inline std::string generic_u8string(const std::experimental::filesystem::path& p)
inline std::string generic_u8string(const std::filesystem::path& p)
{
#if NANA_USING_BOOST_FILESYSTEM
return nana::to_utf8(p.generic_wstring());
@ -45,15 +45,15 @@ inline std::string generic_u8string(const std::experimental::filesystem::path& p
#endif
}
inline bool is_directory(const std::experimental::filesystem::directory_entry& dir) noexcept
inline bool is_directory(const std::filesystem::directory_entry& dir) noexcept
{
return is_directory(dir.status());
}
//template<class DI> // DI = directory_iterator from std, boost, or nana : return directory_entry
class directory_only_iterator : public std::experimental::filesystem::directory_iterator
class directory_only_iterator : public std::filesystem::directory_iterator
{
using directory_iterator = std::experimental::filesystem::directory_iterator;
using directory_iterator = std::filesystem::directory_iterator;
directory_only_iterator& find_first()
{
@ -93,9 +93,9 @@ inline directory_only_iterator end(const directory_only_iterator&) noexcept
}
//template<class DI> // DI = directory_iterator from std, boost, or nana : value_type directory_entry
class regular_file_only_iterator : public std::experimental::filesystem::directory_iterator
class regular_file_only_iterator : public std::filesystem::directory_iterator
{
using directory_iterator = std::experimental::filesystem::directory_iterator;
using directory_iterator = std::filesystem::directory_iterator;
regular_file_only_iterator& find_first()
{
while (((*this) != directory_iterator{}) && !is_regular_file((**this).status()))
@ -128,11 +128,11 @@ inline regular_file_only_iterator end(const regular_file_only_iterator&) noexcep
return{};
}
std::string pretty_file_size(const std::experimental::filesystem::path& path);
std::string pretty_file_size(const std::filesystem::path& path);
std::string pretty_file_date(const std::experimental::filesystem::path& path);
std::string pretty_file_date(const std::filesystem::path& path);
bool modified_file_time(const std::experimental::filesystem::path& p, struct tm&); ///< extention ?
bool modified_file_time(const std::filesystem::path& p, struct tm&); ///< extention ?
} // filesystem_ext
} // nana

View File

@ -1,7 +1,7 @@
/*
* An Animation Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -49,24 +49,18 @@ namespace nana
struct impl;
class performance_manager;
/// Non-copyable
animation(const animation&) = delete;
animation& operator=(const animation&) = delete;
public:
animation(std::size_t fps = 23);
~animation();
void push_back(frameset frms);
/*
void branch(const std::string& name, const frameset& frms)
{
impl_->branches[name].frames = frms;
}
animation(animation&&);
animation& operator=(animation&&);
void branch(const std::string& name, const frameset& frms, std::function<std::size_t(const std::string&, std::size_t, std::size_t&)> condition)
{
auto & br = impl_->branches[name];
br.frames = frms;
br.condition = condition;
}
*/
void push_back(frameset frms);
void looped(bool enable); ///< Enables or disables the animation repeating playback.

View File

@ -4,7 +4,7 @@
*
* Basis Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -65,6 +65,13 @@ namespace nana
blend
};
enum class dragdrop_status
{
not_ready,
ready,
in_progress
};
namespace category
{
enum class flags
@ -73,17 +80,11 @@ namespace nana
widget = 0x1,
lite_widget = 0x3,
root = 0x5
#ifndef WIDGET_FRAME_DEPRECATED
,frame = 0x9
#endif
};
//wait for constexpr
struct widget_tag{ static const flags value = flags::widget; };
struct lite_widget_tag : public widget_tag{ static const flags value = flags::lite_widget; };
struct root_tag : public widget_tag{ static const flags value = flags::root; };
#ifndef WIDGET_FRAME_DEPRECATED
struct frame_tag : public widget_tag{ static const flags value = flags::frame; };
#endif
}// end namespace category
using native_window_type = detail::native_window_handle_impl*;

View File

@ -1,7 +1,7 @@
/**
* A Basic Window Widget Definition
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -116,10 +116,6 @@ namespace detail
/// bind a native window and baisc_window
void bind_native_window(native_window_type, unsigned width, unsigned height, unsigned extra_width, unsigned extra_height, paint::graphics&);
#ifndef WIDGET_FRAME_DEPRECATED
void frame_window(native_window_type);
#endif
bool is_ancestor_of(const basic_window* wd) const;
bool visible_parents() const;
bool displayed() const;
@ -179,7 +175,9 @@ namespace detail
bool ignore_menubar_focus : 1; ///< A flag indicates whether the menubar sets the focus.
bool ignore_mouse_focus : 1; ///< A flag indicates whether the widget accepts focus when clicking on it
bool space_click_enabled : 1; ///< A flag indicates whether enable mouse_down/click/mouse_up when pressing and releasing whitespace key.
unsigned Reserved :18;
bool draggable : 1;
bool ignore_child_mapping : 1;
unsigned Reserved :16;
unsigned char tab; ///< indicate a window that can receive the keyboard TAB
mouse_action action;
mouse_action action_before;
@ -205,19 +203,8 @@ namespace detail
struct other_tag
{
#ifndef WIDGET_FRAME_DEPRECATED
struct attr_frame_tag
{
native_window_type container{nullptr};
std::vector<native_window_type> attach;
};
#endif
struct attr_root_tag
{
#ifndef WIDGET_FRAME_DEPRECATED
container frames; ///< initialization is null, it will be created while creating a frame widget. Refer to WindowManager::create_frame
#endif
container tabstop;
std::vector<edge_nimbus_action> effects_edge_nimbus;
basic_window* focus{nullptr};
@ -234,13 +221,13 @@ namespace detail
///< if the active_window is null, the parent of this window keeps focus.
paint::graphics glass_buffer; ///< if effect.bground is avaiable. Refer to window_layout::make_bground.
update_state upd_state;
dragdrop_status dnd_state{ dragdrop_status::not_ready };
container mapping_requester; ///< Children which are ignored to mapping
union
{
attr_root_tag * root;
#ifndef WIDGET_FRAME_DEPRECATED
attr_frame_tag * frame;
#endif
}attribute;
other_tag(category::flags);

View File

@ -1,38 +0,0 @@
#ifndef NANA_DETAIL_BEDROCK_PI_DATA_HPP
#define NANA_DETAIL_BEDROCK_PI_DATA_HPP
#include <nana/push_ignore_diagnostic>
#include <nana/gui/detail/bedrock.hpp>
#include "color_schemes.hpp"
#include "events_operation.hpp"
#include "window_manager.hpp"
#include <set>
namespace nana
{
namespace detail
{
struct bedrock::pi_data
{
color_schemes scheme;
events_operation evt_operation;
window_manager wd_manager;
std::set<core_window_t*> auto_form_set;
bool shortkey_occurred{ false };
struct menu_rep
{
core_window_t* taken_window{ nullptr };
bool delay_restore{ false };
native_window_type window{ nullptr };
native_window_type owner{ nullptr };
bool has_keyboard{ false };
}menu;
};
}
}
#include <nana/pop_ignore_diagnostic>
#endif

View File

@ -91,7 +91,7 @@ namespace nana
virtual void shortkey(graph_reference, const arg_keyboard&);
void filter_event(const event_code evt_code, const bool bDisabled);
void filter_event(const std::vector<event_code> evt_codes, const bool bDisabled);
void filter_event(const std::vector<event_code>& evt_codes, const bool bDisabled);
void filter_event(const event_filter_status& evt_all_states);
bool filter_event(const event_code evt_code);
event_filter_status filter_event();

View File

@ -1,7 +1,7 @@
/**
* Definition of General Events
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -17,6 +17,7 @@
#include <nana/gui/basis.hpp>
#include "event_code.hpp"
#include "internal_scope_guard.hpp"
#include "../../filesystem/filesystem.hpp"
#include <type_traits>
#include <functional>
#include <vector>
@ -46,12 +47,11 @@ namespace nana
struct docker_base
: public docker_interface
{
event_interface * event_ptr;
bool flag_deleted{ false };
event_interface * const event_ptr;
bool flag_deleted;
const bool unignorable;
docker_base(event_interface*, bool unignorable_flag);
detail::event_interface * get_event() const override;
};
@ -220,33 +220,16 @@ namespace nana
//The dockers may resize when a new event handler is created by a calling handler.
//Traverses with position can avaid crash error which caused by a iterator which becomes invalid.
auto i = dockers_->data();
auto const end = i + dockers_->size();
for (; i != end; ++i)
for (std::size_t i = 0; i < dockers_->size(); ++i)
{
if (static_cast<docker*>(*i)->flag_deleted)
auto d = static_cast<docker*>(dockers_->data()[i]);
if (d->flag_deleted || (arg.propagation_stopped() && !d->unignorable))
continue;
static_cast<docker*>(*i)->invoke(arg);
d->invoke(arg);
if (window_handle && (!detail::check_window(window_handle)))
break;
if (arg.propagation_stopped())
{
for (++i; i != end; ++i)
{
if (!static_cast<docker*>(*i)->unignorable || static_cast<docker*>(*i)->flag_deleted)
continue;
static_cast<docker*>(*i)->invoke(arg);
if (window_handle && (!detail::check_window(window_handle)))
break;
}
break;
}
}
}
private:
@ -297,34 +280,16 @@ namespace nana
};
}
static std::function<void(arg_reference)> build_second(fn_type&& fn, void(fn_type::*)(arg_reference))
template<typename Tfn, typename Ret>
static std::function<void(arg_reference)> build_second(Tfn&& fn, Ret(fn_type::*)(arg_reference))
{
return std::move(fn);
return std::forward<Tfn>(fn);
}
static std::function<void(arg_reference)> build_second(fn_type&& fn, void(fn_type::*)(arg_reference) const)
template<typename Tfn, typename Ret>
static std::function<void(arg_reference)> build_second(Tfn&& fn, Ret(fn_type::*)(arg_reference)const)
{
return std::move(fn);
}
static std::function<void(arg_reference)> build_second(fn_type& fn, void(fn_type::*)(arg_reference))
{
return fn;
}
static std::function<void(arg_reference)> build_second(fn_type& fn, void(fn_type::*)(arg_reference) const)
{
return fn;
}
static std::function<void(arg_reference)> build_second(const fn_type& fn, void(fn_type::*)(arg_reference))
{
return fn;
}
static std::function<void(arg_reference)> build_second(const fn_type& fn, void(fn_type::*)(arg_reference) const)
{
return fn;
return std::forward<Tfn>(fn);
}
template<typename Tfn, typename Ret, typename Arg2>
@ -420,7 +385,7 @@ namespace nana
typedef typename std::remove_reference<arg_reference>::type arg_type;
static_assert(std::is_convertible<arg_type, Arg2>::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function.");
static std::function<void(arg_reference)> build(Ret(*fn)(Arg))
static std::function<void(arg_reference)> build(Ret(*fn)(Arg2))
{
return[fn](arg_reference arg){
fn(arg);
@ -472,7 +437,7 @@ namespace nana
{
::nana::window window_handle; ///< A handle to the event window
::nana::point pos; ///< cursor position in the event window
std::vector<std::string> files; ///< external filenames
std::vector<std::filesystem::path> files; ///< external filenames
};
struct arg_expose : public event_arg

View File

@ -1,7 +1,7 @@
/*
* Widget Geometrics
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -22,12 +22,17 @@ namespace nana
public:
color_proxy(const color_proxy&);
color_proxy(color_rgb);
color_proxy(color_argb);
color_proxy(color_rgba);
color_proxy(colors);
color_proxy& operator=(const color_proxy&);
color_proxy& operator=(const ::nana::color&);
color_proxy& operator=(color_rgb);
color_proxy& operator=(color_argb);
color_proxy& operator=(color_rgba);
color_proxy& operator=(colors);
color get_color() const;
color get(const color& default_color) const;
operator color() const;
private:
std::shared_ptr<color> color_;

View File

@ -1,7 +1,7 @@
/**
* Window Manager Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -83,12 +83,6 @@ namespace detail
core_window_t* create_root(core_window_t*, bool nested, rectangle, const appearance&, widget*);
core_window_t* create_widget(core_window_t*, const rectangle&, bool is_lite, widget*);
#ifndef WIDGET_FRAME_DEPRECATED
core_window_t* create_frame(core_window_t*, const rectangle&, widget*);
bool insert_frame(core_window_t* frame, native_window);
bool insert_frame(core_window_t* frame, core_window_t*);
#endif
void close(core_window_t*);
//destroy
@ -122,11 +116,8 @@ namespace detail
void refresh_tree(core_window_t*);
void do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false);
void map_requester(core_window_t*);
bool get_graphics(core_window_t*, nana::paint::graphics&);
bool get_visual_rectangle(core_window_t*, nana::rectangle&);
std::vector<core_window_t*> get_children(core_window_t*) const;
bool set_parent(core_window_t* wd, core_window_t* new_parent);
core_window_t* set_focus(core_window_t*, bool root_has_been_focused, arg_focus::reason);
@ -149,7 +140,6 @@ namespace detail
bool register_shortkey(core_window_t*, unsigned long key);
void unregister_shortkey(core_window_t*, bool with_children);
std::vector<std::pair<core_window_t*, unsigned long>> shortkeys(core_window_t*, bool with_children);
core_window_t* find_shortkey(native_window_type, unsigned long key);
@ -159,6 +149,7 @@ namespace detail
void _m_disengage(core_window_t*, core_window_t* for_new);
void _m_destroy(core_window_t*);
void _m_move_core(core_window_t*, const point& delta);
void _m_shortkeys(core_window_t*, bool with_chlidren, std::vector<std::pair<core_window_t*, unsigned long>>& keys) const;
core_window_t* _m_find(core_window_t*, const point&);
static bool _m_effective(core_window_t*, const point& root_pos);
private:

View File

@ -0,0 +1,129 @@
/**
* Drag and Drop Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2018-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/dragdrop.hpp
* @author: Jinhao(cnjinhao@hotmail.com)
*/
#ifndef NANA_GUI_DRAGDROP_INCLUDED
#define NANA_GUI_DRAGDROP_INCLUDED
#include <nana/push_ignore_diagnostic>
#include <functional>
#include "basis.hpp"
#include <memory>
#include <nana/filesystem/filesystem.hpp>
namespace nana
{
/// Drag and drop actions
enum class dnd_action
{
copy, ///< Copy the data to target.
move, ///< Move the data to target.
link ///< Create a link from source data to target.
};
class simple_dragdrop
{
struct implementation;
simple_dragdrop(const simple_dragdrop&) = delete;
simple_dragdrop& operator=(const simple_dragdrop&) = delete;
simple_dragdrop(simple_dragdrop&&) = delete;
simple_dragdrop& operator=(simple_dragdrop&&) = delete;
public:
simple_dragdrop(window source);
~simple_dragdrop();
/// Condition checker
/**
* Sets a condition checker that determines whether the drag-and-drop operation can start. If a condition checker is not set, it always start drag-and-drop operation.
* @param predicate_fn Unary predicate which returns #true# for starting drag-and-drop operation.
*/
void condition(std::function<bool()> predicate_fn);
void make_drop(window target, std::function<void()> drop_fn);
private:
implementation* const impl_;
};
namespace detail
{
struct dragdrop_data;
}
class dragdrop
{
struct implementation;
/// Non-copyable
dragdrop(const dragdrop&) = delete;
dragdrop& operator=(const dragdrop&) = delete;
/// Non-movable
dragdrop(dragdrop&&) = delete;
dragdrop& operator=(dragdrop&&) = delete;
public:
class data
{
friend struct dragdrop::implementation;
/// Non-copyable
data(const data&) = delete;
data& operator=(const data&) = delete;
public:
/// Constructor
/**
* Constructs a data object used for drag and drop
* @param requested_action Indicates how the data to be transferred.
*/
data(dnd_action requested_action = dnd_action::copy);
data(data&&);
~data();
data& operator=(data&& rhs);
void insert(std::filesystem::path);
private:
detail::dragdrop_data* real_data_;
};
dragdrop(window source);
~dragdrop();
/// Condition checker
/***
* Sets a condition checker that determines whether the drag-and-drop operation can start. If a condition checker is not set, it always start drag-and-drop operation.
* @param predicate_fn A predicate function to be set.
*/
void condition(std::function<bool()> predicate_fn);
/// Transferred data
/**
* Set a data generator. When drag begins, it is called to generate a data object for transferring.
* @param generator It returns the data for transferring.
*/
void prepare_data(std::function<data()> generator);
/// Drop handler
/**
* The drop handler is called when the drop operation is completed. There are 3 parameters for the handler
* dropped Indicates whether the data is accepted by a target window.
* executed_action Indicates the action returned by target window. Ignore if dropped is false.
* data_transferred The data object which is generated by the generator.
* @param finish_fn The drop handling function.
*/
void drop_finished(std::function<void(bool dropped, dnd_action executed_action, data& data_transferred)> finish_fn);
private:
implementation* const impl_;
};
}
#endif

View File

@ -23,9 +23,10 @@ namespace nana
class drawing
:private nana::noncopyable
{
struct draw_fn_handle;
public:
typedef struct{}* diehard_t; ///< A handle to a drawing method
typedef std::function<void(paint::graphics&)> draw_fn_t; ///< A function to draw
using diehard_t = draw_fn_handle * ; ///< A handle to a drawing method
using draw_fn_t = std::function<void(paint::graphics&)>; ///< A function to draw
drawing(window w); ///< Create a drawing object for a widget w

View File

@ -1,6 +1,6 @@
/*
* Background Effects Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -45,7 +45,7 @@ namespace nana
: public bground_factory_interface
{
public:
bground_transparent(std::size_t percent);
explicit bground_transparent(std::size_t percent);
private:
bground_interface* create() const override;
private:

View File

@ -1,7 +1,7 @@
/**
* Filebox
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -9,14 +9,13 @@
*
* @file nana/gui/filebox.hpp
* @author Jinhao
* @brief a dialog to chose file(s), implemented "native" in windows but using nana for X11
* @brief dialogs to chose file(s) or a directory, implemented "native" in windows but using nana for X11
*/
#ifndef NANA_GUI_FILEBOX_HPP
#define NANA_GUI_FILEBOX_HPP
#include <nana/gui/basis.hpp>
#include <nana/filesystem/filesystem.hpp>
#include <nana/optional.hpp>
#include <vector>
#include <utility>
@ -29,9 +28,8 @@ namespace nana
filebox(filebox&&) = delete;
filebox& operator=(filebox&&) = delete;
public:
using filters = std::vector<std::pair< ::std::string, ::std::string>>;
using path_type = std::filesystem::path;
filebox(bool is_open_mode);
filebox(window owner, bool is_open_mode);
filebox(const filebox&);
~filebox();
@ -39,43 +37,54 @@ namespace nana
filebox& operator=(const filebox&);
/// Change owner window
void owner(window);
/// Set a new title for the dialog
/// @param string a text for title
/// @return the old title.
::std::string title( ::std::string new_title);
/** @brief Suggest initial path used to locate a directory when the filebox starts.
* @param string initial_directory a path of initial directory
* @note the behavior of init_path is different between Win7 and Win2K/XP/Vista, but its behavior under Linux is conformed with Win7.
/**
* Changes the owner window for the filebox. When #show()/operator()# are invoked, the dialog of filebox will be created with the specified owner.
* @param handle A handle to a window which will be used for the owner of filebox
*/
filebox& init_path(const ::std::string& initial_directory);
void owner(window handle);
filebox& init_file(const ::std::string&); ///< Init file, if it contains a path, the init path is replaced by the path of init file.
/// Changes new title
/**
* Changes the title. When #show()/operator()# are invoked, the dialog of filebox will be created with the specified title.
* @param text Text of title
* @return the reference of *this.
*/
filebox& title( ::std::string text);
/// Sets a initial path
/**
* Suggest initial path used to locate a directory when the filebox starts.
* @note the behavior of init_path is different between Win7 and Win2K/XP/Vista, but its behavior under Linux is conformed with Win7.
* @param path a path of initial directory
* @return reference of *this.
*/
filebox& init_path(const path_type& path);
/// Sets a initial filename
/**
* Suggest a filename when filebox starts. If the filename contains a path, the initial path will be replaced with the path presents in initial filename.
* @param filename a filename used for a initial filename when filebox starts.
* @return reference of *this.
*/
filebox& init_file(const ::std::string& filename); ///< Init file, if it contains a path, the init path is replaced by the path of init file.
/// \brief Add a filetype filter.
/// To specify multiple filter in a single description, use a semicolon to separate the patterns(for example,"*.TXT;*.DOC;*.BAK").
filebox& add_filter(const ::std::string& description, ///< for example. "Text File"
const ::std::string& filetype ///< filter pattern(for example, "*.TXT")
filebox& add_filter(const ::std::string& description, ///< for example: "Text File"
const ::std::string& filetype ///< filter pattern(for example: "*.TXT")
);
filebox& add_filter(const filters &ftres)
{
for (auto &f : ftres)
add_filter(f.first, f.second);
return *this;
};
filebox& add_filter(const std::vector<std::pair<std::string, std::string>> &filters);
const path_type& path() const;
::std::string path() const;
::std::string file() const;
filebox& allow_multi_select(bool allow);
/// Display the filebox dialog
bool show() const;
std::vector<path_type> show() const;
/// a function object method alternative to show() to display the filebox dialog,
bool operator()() const
std::vector<path_type> operator()() const
{
return show();
}
@ -92,17 +101,26 @@ namespace nana
folderbox(folderbox&&) = delete;
folderbox& operator=(folderbox&&) = delete;
public:
using path_type = std::experimental::filesystem::path;
using path_type = std::filesystem::path;
folderbox(window owner = nullptr, const path_type& init_path = {});
explicit folderbox(window owner = nullptr, const path_type& init_path = {}, std::string title={});
~folderbox();
std::optional<path_type> show() const;
/// Enables/disables multi select
folderbox& allow_multi_select(bool allow);
std::optional<path_type> operator()() const
std::vector<path_type> show() const;
std::vector<path_type> operator()() const
{
return show();
}
/// Changes title
/**
* @param text Text of title
*/
folderbox& title(std::string text);
private:
implement* impl_;
};

View File

@ -1,7 +1,7 @@
/*
* Nana GUI Programming Interface Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -95,9 +95,7 @@ namespace API
window create_window(window, bool nested, const rectangle&, const appearance&, widget* attached);
window create_widget(window, const rectangle&, widget* attached);
window create_lite_widget(window, const rectangle&, widget* attached);
#ifndef WIDGET_FRAME_DEPRECATED
window create_frame(window, const rectangle&, widget* attached);
#endif
paint::graphics* window_graphics(window);
void delay_restore(bool);
@ -117,6 +115,9 @@ namespace API
void lazy_refresh();
void draw_shortkey_underline(paint::graphics&, const std::string& text, wchar_t shortkey, std::size_t shortkey_position, const point& text_pos, const color&);
void window_draggable(window, bool enabled);
bool window_draggable(window);
}//end namespace dev
@ -229,13 +230,7 @@ namespace API
window root(native_window_type); ///< Retrieves the native window of a Nana.GUI window.
void fullscreen(window, bool);
bool enabled_double_click(window, bool);
#ifndef WIDGET_FRAME_DEPRECATED
bool insert_frame(window frame, native_window_type);
native_window_type frame_container(window frame);
native_window_type frame_element(window frame, unsigned index);
#endif
void close_window(window);
void show_window(window, bool show); ///< Sets a window visible state.
void restore_window(window);
@ -243,6 +238,7 @@ namespace API
bool visible(window);
window get_parent_window(window);
window get_owner_window(window);
bool set_parent_window(window, window new_parent);
template<typename Widget=::nana::widget>
@ -439,6 +435,7 @@ namespace API
/// Sets the window active state. If a window active state is false, the window will not obtain the focus when a mouse clicks on it wich will be obteined by take_if_has_active_false.
void take_active(window, bool has_active, window take_if_has_active_false);
/// Copies the graphics of a specified to a new graphics object.
bool window_graphics(window, nana::paint::graphics&);
bool root_graphics(window, nana::paint::graphics&);
bool get_visual_rectangle(window, nana::rectangle&);
@ -476,6 +473,8 @@ namespace API
::std::optional<std::pair<::nana::size, ::nana::size>> content_extent(window wd, unsigned limited_px, bool limit_width);
unsigned screen_dpi(bool x_requested);
dragdrop_status window_dragdrop_status(::nana::window);
}//end namespace API
}//end namespace nana

View File

@ -1,13 +1,15 @@
/**
* A Button Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/widgets/button.hpp
* @contributor
* besh81(pr#361)
*/
#ifndef NANA_GUI_WIDGET_BUTTON_HPP
@ -90,7 +92,12 @@ namespace nana{
button(window, const char* caption, bool visible = true);
button(window, const nana::rectangle& = rectangle(), bool visible = true);
button& icon(const nana::paint::image&);
/// Shows an icon in front of caption
/**
* @param image Icon to be shown. If image is empty, the current icon is erased from the button.
* @return the reference of *this.
*/
button& icon(const nana::paint::image& image);
button& enable_pushed(bool);
bool pushed() const;
button& pushed(bool);

View File

@ -37,6 +37,13 @@ namespace drawerbase
{
namespace checkbox
{
struct scheme
: public widget_geometrics
{
color_proxy square_bgcolor{ static_cast<color_argb>(0x0) };
color_proxy square_border_color{ colors::black };
};
struct events_type
: public general_events
{
@ -67,7 +74,7 @@ namespace drawerbase
class checkbox
: public widget_object<category::widget_tag, drawerbase::checkbox::drawer, drawerbase::checkbox::events_type>
: public widget_object<category::widget_tag, drawerbase::checkbox::drawer, drawerbase::checkbox::events_type, drawerbase::checkbox::scheme>
{
public:
checkbox();
@ -97,6 +104,7 @@ namespace drawerbase
struct element_tag
{
checkbox * uiobj;
event_handle eh_clicked;
event_handle eh_checked;
event_handle eh_destroy;
event_handle eh_keyboard;

View File

@ -1,6 +1,6 @@
/*
* Concept of Component Set
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -46,7 +46,7 @@ namespace nana{ namespace widgets{ namespace detail
};
/// A component set placer used for specifying component position and size.
template<typename Component, typename ItemAttribute>
template<typename Component, typename ItemAttribute, typename WidgetScheme>
class compset_placer
{
public:
@ -56,8 +56,11 @@ namespace nana{ namespace widgets{ namespace detail
/// A type of widget-defined item attribute.
typedef ItemAttribute item_attribute_t;
/// Widget scheme.
typedef WidgetScheme widget_scheme_t;
public:
/// The destrcutor.
/// The destructor.
virtual ~compset_placer(){}
/// Enable/Disable the specified component.

View File

@ -1,6 +1,6 @@
/*
* A Tree Container class implementation
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -63,7 +63,7 @@ namespace detail
{
while (child)
{
if (child->owner == this)
if (child == this)
return true;
child = child->owner;
@ -357,12 +357,12 @@ namespace detail
}
template<typename PredAllowChild>
unsigned distance_if(const node_type * node, PredAllowChild pac) const
std::size_t distance_if(const node_type * node, PredAllowChild pac) const
{
if(nullptr == node) return 0;
const node_type * iterator = root_.child;
unsigned off = 0;
std::size_t off = 0;
std::stack<const node_type* > stack;
while(iterator && iterator != node)
@ -479,6 +479,8 @@ namespace detail
return nullptr;
}
// foreach elements of key.
// the root name "/" and "\\" are treated as a node. This is a feature that can easily support the UNIX-like path.
template<typename Function>
void _m_for_each(const ::std::string& key, Function function) const
{
@ -491,18 +493,24 @@ namespace detail
{
if(beg != end)
{
if(function(key.substr(beg, end - beg)) == false)
if(!function(key.substr(beg, end - beg)))
return;
}
auto next = key.find_first_not_of("\\/", end);
if(next != ::std::string::npos)
if ((next == ::std::string::npos) && end)
return;
if (0 == end)
{
if ((!function(key.substr(0, 1))) || (next == ::std::string::npos))
return;
}
beg = next;
end = key.find_first_of("\\/", beg);
}
else
return;
}
function(key.substr(beg, key.size() - beg));

View File

@ -1,56 +0,0 @@
/**
* A Frame Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/widgets/frame.hpp
*
* @brief A frame provides a way to contain the platform window in a stdex GUI Window
*/
#ifndef NANA_GUI_WIDGET_FRAME_HPP
#define NANA_GUI_WIDGET_FRAME_HPP
#include "widget.hpp"
#ifndef WIDGET_FRAME_DEPRECATED
namespace nana
{
/**
\brief Container for system native windows. Provides an approach to
display a control that is not written with Nana.GUI in a Nana.GUI window.
Notes:
1. nana::native_window_type is a type of system handle of windows.
2. all the children windows of a nana::frame is topmost to Nana.GUI windows.
3. a simple example. Displaying a Windows Edit Control.
nana::frame frame(parent, 0, 0 200, 100);
HWND frame_handle = reinterpret_cast<HWND>(frame.container());
HWND edit = ::CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"Test",
WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 200, 100,
frame_handle, 0, ::GetModuleHandle(0), 0);
if(edit)
frame.insert(edit);
*/
class frame: public widget_object<category::frame_tag, int, nana::general_events>
{
typedef widget_object<category::frame_tag, int> base_type;
public:
frame();
frame(window, bool visible);
frame(window, const rectangle& = rectangle(), bool visible = true);
bool insert(native_window_type); ///< Inserts a platform native window.
native_window_type element(unsigned index); ///< Returns the child window through index.
native_window_type container() const; ///< Returns the frame container native window handle.
};
}//end namespace nana
#endif
#endif

View File

@ -42,6 +42,13 @@ namespace nana{
using field_reference = place::field_reference;
constexpr static const std::size_t npos = static_cast<std::size_t>(-1);
enum class background_mode
{
none,
transparent,
blending
};
/// The default construction
group();
@ -66,17 +73,28 @@ namespace nana{
checkbox& add_option(::std::string);
/// Modifies the alignment of the title
void caption_align(align position);
group& caption_align(align position);
group& caption_background_mode(background_mode mode);
/// Enables/disables the radio mode which is single selection
group& radio_mode(bool);
/// Returns the index of option in radio_mode, it throws a logic_error if radio_mode is false.
/// Returns the index of selected option in radio_mode, it throws a logic_error if radio_mode is false.
std::size_t option() const;
/** Set check/unchecked status of specified option
@param[in] pos zero-based index of option to set
@param[in] check status required, defaults to checked
throws an out_of_range if !(pos < number of options)
*/
void option_check( std::size_t pos, bool check = true );
/// Determines whether a specified option is checked, it throws an out_of_range if !(pos < number of options)
bool option_checked(std::size_t pos) const;
/// Change typeface of caption label ( does not effect child widgets )
void typeface( const nana::paint::font& font );
group& enable_format_caption(bool format);
group& collocate() noexcept;

View File

@ -1,7 +1,7 @@
/**
* A List Box Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -1461,6 +1461,23 @@ the nana::detail::basic_window member pointer scheme
/// Returns the number of columns
size_type column_size() const;
/// Move column to view_position
void move_column(size_type abs_pos, size_type view_pos);
/// Sort columns in range first_col to last_col inclusive using the values from a row
void reorder_columns(size_type first_col,
size_type last_col,
index_pair row, bool reverse,
std::function<bool(const std::string &cell1, size_type col1,
const std::string &cell2, size_type col2,
const nana::any *rowval,
bool reverse)> comp);
void column_resizable(bool resizable);
bool column_resizable() const;
void column_movable(bool);
bool column_movable() const;
/// Returns a rectangle in where the content is drawn.
rectangle content_area() const;
@ -1481,9 +1498,19 @@ the nana::detail::basic_window member pointer scheme
*/
void insert_item(const index_pair& abs_pos, const ::std::wstring& text);
void insert_item(index_pair abs_pos, const listbox& rhs, const index_pairs& indexes);
/// Returns an index of item which contains the specified point.
index_pair cast(const point & screen_pos) const;
/// Returns the item which is hovered
/**
* @param return_end Indicates whether to return an end position instead of empty position if an item is not hovered.
* @return The position of the hovered item. If return_end is true, it returns the position next to the last item of last category if an item is not hovered.
*/
index_pair hovered(bool return_end) const;
/// Returns the absolute position of column which contains the specified point.
size_type column_from_pos(const point & pos) const;
@ -1502,7 +1529,8 @@ the nana::detail::basic_window member pointer scheme
///Sets a strict weak ordering comparer for a column
void set_sort_compare( size_type col,
std::function<bool(const std::string&, nana::any*, const std::string&, nana::any*, bool reverse)> strick_ordering);
std::function<bool(const std::string&, nana::any*,
const std::string&, nana::any*, bool reverse)> strick_ordering);
/// sort() and ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items
void sort_col(size_type col, bool reverse = false);
@ -1523,6 +1551,7 @@ the nana::detail::basic_window member pointer scheme
void enable_single(bool for_selection, bool category_limited);
void disable_single(bool for_selection);
bool is_single_enabled(bool for_selection) const noexcept; ///< Determines whether the single selection/check is enabled.
export_options& def_export_options();
@ -1540,6 +1569,27 @@ the nana::detail::basic_window member pointer scheme
* @return the reference of *this.
*/
listbox& category_icon(const paint::image& img_expanded, const paint::image&& img_collapsed);
/// Returns first visible element
/**
* It may return an item or a category item.
* @return the index of first visible element.
*/
index_pair first_visible() const;
/// Returns last visible element
/**
* It may return an item or a category item.
* @return the index of last visible element.
*/
index_pair last_visible() const;
/// Returns all visible items
/**
* It returns all visible items that are displayed in listbox window.
* @return index_pairs containing all visible items.
*/
index_pairs visibles() const;
private:
drawerbase::listbox::essence & _m_ess() const;
nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const override;

View File

@ -1,7 +1,7 @@
/*
* A Menubar implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2009-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -34,26 +34,6 @@ namespace nana
color_proxy border_highlight{ colors::highlight };
};
class item_renderer
{
public:
enum class state
{
normal, highlighted, selected
};
using graph_reference = paint::graphics&;
using scheme = ::nana::drawerbase::menubar::scheme;
item_renderer(window, graph_reference);
virtual void background(const point&, const ::nana::size&, state);
virtual void caption(const point&, const native_string_type&);
scheme *scheme_ptr() const { return scheme_ptr_; };
private:
graph_reference graph_;
scheme *scheme_ptr_;
};
class trigger
: public drawer_trigger
{

View File

@ -67,30 +67,30 @@ namespace nana
class drawer
{
public:
struct states
enum class states
{
enum{ none, highlight, actived, selected };
none, highlight, actived, selected
};
using graph_reference = paint::graphics&;
const static unsigned fixedsize = 16; // make it part of a new "metric" in the widget_scheme
drawer(metrics_type& m);
void set_vertical(bool);
drawer(bool vert);
buttons what(graph_reference, const point&);
void scroll_delta_pos(graph_reference, int);
void auto_scroll();
void draw(graph_reference, buttons);
void draw(graph_reference);
private:
bool _m_check() const;
void _m_adjust_scroll(graph_reference);
void _m_background(graph_reference);
void _m_button_frame(graph_reference, ::nana::rectangle, int state);
void _m_draw_scroll(graph_reference, int state);
void _m_draw_button(graph_reference, ::nana::rectangle, buttons what, int state);
private:
metrics_type &metrics_;
bool vertical_;
void _m_button_frame(graph_reference, ::nana::rectangle, states state);
void _m_draw_scroll(graph_reference, states state);
void _m_draw_button(graph_reference, ::nana::rectangle, buttons what, states state);
public:
metrics_type metrics;
bool const vert;
};
template<bool Vertical>
@ -101,35 +101,34 @@ namespace nana
typedef metrics_type::size_type size_type;
trigger()
: graph_(nullptr), drawer_(metrics_)
: graph_(nullptr), drawer_(Vertical)
{
drawer_.set_vertical(Vertical);
}
const metrics_type& metrics() const
{
return metrics_;
return drawer_.metrics;
}
void peak(size_type s)
{
if (graph_ && (metrics_.peak != s))
if (graph_ && (drawer_.metrics.peak != s))
{
metrics_.peak = s;
drawer_.metrics.peak = s;
API::refresh_window(widget_->handle());
}
}
void value(size_type s)
{
if (metrics_.range > metrics_.peak)
if (drawer_.metrics.range > drawer_.metrics.peak)
s = 0;
else if (s + metrics_.range > metrics_.peak)
s = metrics_.peak - metrics_.range;
else if (s + drawer_.metrics.range > drawer_.metrics.peak)
s = drawer_.metrics.peak - drawer_.metrics.range;
if (graph_ && (metrics_.value != s))
if (graph_ && (drawer_.metrics.value != s))
{
metrics_.value = s;
drawer_.metrics.value = s;
_m_emit_value_changed();
API::refresh_window(*widget_);
@ -138,16 +137,16 @@ namespace nana
void range(size_type s)
{
if (graph_ && (metrics_.range != s))
if (graph_ && (drawer_.metrics.range != s))
{
metrics_.range = s;
drawer_.metrics.range = s;
API::refresh_window(widget_->handle());
}
}
void step(size_type s)
{
metrics_.step = (s ? s : 1);
drawer_.metrics.step = (s ? s : 1);
}
bool make_step(bool forward, unsigned multiple)
@ -155,12 +154,12 @@ namespace nana
if (!graph_)
return false;
size_type step = (multiple > 1 ? metrics_.step * multiple : metrics_.step);
size_type value = metrics_.value;
size_type step = (multiple > 1 ? drawer_.metrics.step * multiple : drawer_.metrics.step);
size_type value = drawer_.metrics.value;
if (forward)
{
size_type maxv = metrics_.peak - metrics_.range;
if (metrics_.peak > metrics_.range && value < maxv)
size_type maxv = drawer_.metrics.peak - drawer_.metrics.range;
if (drawer_.metrics.peak > drawer_.metrics.range && value < maxv)
{
if (maxv - value >= step)
value += step;
@ -175,8 +174,8 @@ namespace nana
else
value = 0;
}
size_type cmpvalue = metrics_.value;
metrics_.value = value;
size_type cmpvalue = drawer_.metrics.value;
drawer_.metrics.value = value;
if (value != cmpvalue)
{
_m_emit_value_changed();
@ -191,6 +190,9 @@ namespace nana
widget_ = static_cast< ::nana::scroll<Vertical>*>(&widget);
widget.caption("nana scroll");
//scroll doesn't want the keyboard focus.
API::take_active(widget, false, widget.parent());
timer_.stop();
timer_.elapse(std::bind(&trigger::_m_tick, this));
}
@ -202,48 +204,43 @@ namespace nana
void refresh(graph_reference graph) override
{
drawer_.draw(graph, metrics_.what);
drawer_.draw(graph);
}
void resized(graph_reference graph, const ::nana::arg_resized&) override
{
drawer_.draw(graph, metrics_.what);
drawer_.draw(graph);
API::dev::lazy_refresh();
}
void mouse_enter(graph_reference graph, const ::nana::arg_mouse& arg) override
{
metrics_.what = drawer_.what(graph, arg.pos);
drawer_.draw(graph, metrics_.what);
drawer_.metrics.what = drawer_.what(graph, arg.pos);
drawer_.draw(graph);
API::dev::lazy_refresh();
}
void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override
{
bool redraw = false;
if (metrics_.pressed && (metrics_.what == buttons::scroll))
if (drawer_.metrics.pressed && (drawer_.metrics.what == buttons::scroll))
{
size_type cmpvalue = metrics_.value;
size_type cmpvalue = drawer_.metrics.value;
drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x));
if (cmpvalue != metrics_.value)
if (cmpvalue != drawer_.metrics.value)
_m_emit_value_changed();
redraw = true;
}
else
{
buttons what = drawer_.what(graph, arg.pos);
if (metrics_.what != what)
{
redraw = true;
metrics_.what = what;
if (drawer_.metrics.what == what)
return; //no change, don't redraw
drawer_.metrics.what = what;
}
}
if (redraw)
{
drawer_.draw(graph, metrics_.what);
drawer_.draw(graph);
API::dev::lazy_refresh();
}
}
void dbl_click(graph_reference graph, const arg_mouse& arg) override
{
@ -254,33 +251,33 @@ namespace nana
{
if (arg.left_button)
{
metrics_.pressed = true;
metrics_.what = drawer_.what(graph, arg.pos);
switch (metrics_.what)
drawer_.metrics.pressed = true;
drawer_.metrics.what = drawer_.what(graph, arg.pos);
switch (drawer_.metrics.what)
{
case buttons::first:
case buttons::second:
make_step(metrics_.what == buttons::second, 1);
make_step(drawer_.metrics.what == buttons::second, 1);
timer_.interval(1000);
timer_.start();
break;
case buttons::scroll:
widget_->set_capture(true);
metrics_.scroll_mouse_offset = (Vertical ? arg.pos.y : arg.pos.x) - metrics_.scroll_pos;
drawer_.metrics.scroll_mouse_offset = (Vertical ? arg.pos.y : arg.pos.x) - drawer_.metrics.scroll_pos;
break;
case buttons::forward:
case buttons::backward:
{
size_type cmpvalue = metrics_.value;
size_type cmpvalue = drawer_.metrics.value;
drawer_.auto_scroll();
if (cmpvalue != metrics_.value)
if (cmpvalue != drawer_.metrics.value)
_m_emit_value_changed();
}
break;
default: //Ignore buttons::none
break;
}
drawer_.draw(graph, metrics_.what);
drawer_.draw(graph);
API::dev::lazy_refresh();
}
}
@ -291,18 +288,18 @@ namespace nana
widget_->release_capture();
metrics_.pressed = false;
metrics_.what = drawer_.what(graph, arg.pos);
drawer_.draw(graph, metrics_.what);
drawer_.metrics.pressed = false;
drawer_.metrics.what = drawer_.what(graph, arg.pos);
drawer_.draw(graph);
API::dev::lazy_refresh();
}
void mouse_leave(graph_reference graph, const arg_mouse&) override
{
if (metrics_.pressed) return;
if (drawer_.metrics.pressed) return;
metrics_.what = buttons::none;
drawer_.draw(graph, buttons::none);
drawer_.metrics.what = buttons::none;
drawer_.draw(graph);
API::dev::lazy_refresh();
}
@ -310,7 +307,7 @@ namespace nana
{
if (make_step(arg.upwards == false, 3))
{
drawer_.draw(graph, metrics_.what);
drawer_.draw(graph);
API::dev::lazy_refresh();
}
}
@ -322,14 +319,13 @@ namespace nana
void _m_tick()
{
make_step(metrics_.what == buttons::second, 1);
make_step(drawer_.metrics.what == buttons::second, 1);
API::refresh_window(widget_->handle());
timer_.interval(100);
}
private:
::nana::scroll<Vertical> * widget_;
nana::paint::graphics * graph_;
metrics_type metrics_;
drawer drawer_;
timer timer_;
};

View File

@ -1,7 +1,7 @@
/*
* A text editor implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -66,6 +66,7 @@ namespace nana{ namespace widgets
using char_type = wchar_t;
using size_type = textbase<char_type>::size_type;
using string_type = textbase<char_type>::string_type;
using path_type = std::filesystem::path;
using event_interface = text_editor_event_interface;
@ -105,7 +106,7 @@ namespace nana{ namespace widgets
void indent(bool, std::function<std::string()> generator);
void set_event(event_interface*);
bool load(const char*);
bool load(const path_type& file);
void text_align(::nana::align alignment);
@ -135,13 +136,11 @@ namespace nana{ namespace widgets
void enable_background(bool);
void enable_background_counterpart(bool);
void undo_enabled(bool);
bool undo_enabled() const;
void undo_clear();
void undo_max_steps(std::size_t);
std::size_t undo_max_steps() const;
renderers& customized_renderers();
void clear_undo(); ///< same with undo_max_steps(0)
unsigned line_height() const;
unsigned screen_lines(bool completed_line = false) const;
@ -167,6 +166,8 @@ namespace nana{ namespace widgets
bool select(bool);
bool select_points(nana::upoint arg_a, nana::upoint arg_b);
/// Sets the end position of a selected string.
void set_end_caret(bool stay_in_view);
@ -200,12 +201,11 @@ namespace nana{ namespace widgets
void del();
void backspace(bool record_undo, bool perform_event);
void undo(bool reverse);
void set_undo_queue_length(std::size_t len);
void move_ns(bool to_north); //Moves up and down
void move_left();
void move_right();
const upoint& mouse_caret(const point& screen_pos, bool stay_in_view);
const upoint& caret() const;
const upoint& caret() const noexcept;
point caret_screen_pos() const;
bool scroll(bool upwards, bool vertical);
@ -215,8 +215,8 @@ namespace nana{ namespace widgets
void mouse_pressed(const arg_mouse& arg);
bool select_word(const arg_mouse& arg);
skeletons::textbase<char_type>& textbase();
const skeletons::textbase<char_type>& textbase() const;
skeletons::textbase<char_type>& textbase() noexcept;
const skeletons::textbase<char_type>& textbase() const noexcept;
bool try_refresh();

View File

@ -682,7 +682,6 @@ namespace nana{ namespace widgets{ namespace skeletons
{
return lines_.end();
}
private:
void _m_parse_format(tokenizer & tknizer, std::stack<fblock*> & fbstack)
{

View File

@ -1,7 +1,7 @@
/*
* A textbase class implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -18,10 +18,11 @@
#include <nana/charset.hpp>
#include <nana/basic_types.hpp>
#include <nana/traits.hpp>
#include <nana/filesystem/filesystem.hpp>
#include "textbase_export_interface.hpp"
#include <deque>
#include <memory>
#include <fstream>
#include <stdexcept>
@ -36,15 +37,16 @@ namespace skeletons
: public ::nana::noncopyable
{
public:
typedef CharT char_type;
typedef std::basic_string<CharT> string_type;
typedef typename string_type::size_type size_type;
using char_type = CharT;
using string_type = std::basic_string<CharT>;
using size_type = typename string_type::size_type;
using path_type = std::filesystem::path;
textbase()
{
attr_max_.reset();
//Insert an empty string for the first line of empty text.
text_cont_.emplace_back(new string_type);
text_cont_.emplace_back();
}
void set_event_agent(textbase_event_agent_interface * evt)
@ -55,21 +57,19 @@ namespace skeletons
bool empty() const
{
return (text_cont_.empty() ||
((text_cont_.size() == 1) && (text_cont_.front()->empty())));
((text_cont_.size() == 1) && text_cont_.front().empty()));
}
bool load(const char* file_utf8)
bool load(const path_type& file)
{
if (!file_utf8)
return false;
std::ifstream ifs(to_osmbstr(file_utf8));
std::ifstream ifs{ file.string() };
if (!ifs)
return false;
ifs.seekg(0, std::ios::end);
std::size_t bytes = static_cast<std::size_t>(ifs.tellg());
ifs.seekg(0, std::ios::beg);
std::error_code err;
auto const bytes = file_size(file, err);
if (err)
return false;
if(bytes >= 2)
{
@ -81,7 +81,7 @@ namespace skeletons
if(0xBB == ch && 0xBF == ifs.get())
{
ifs.close();
return load(file_utf8, nana::unicode::utf8);
return load(file, nana::unicode::utf8);
}
}
else if(0xFF == ch)
@ -89,16 +89,13 @@ namespace skeletons
if(0xFE == ifs.get())
{
//UTF16,UTF32
if(bytes >= 4)
{
if(ifs.get() == 0 && ifs.get() == 0)
if((bytes >= 4) && (ifs.get() == 0 && ifs.get() == 0))
{
ifs.close();
return load(file_utf8, nana::unicode::utf32);
}
return load(file, nana::unicode::utf32);
}
ifs.close();
return load(file_utf8, nana::unicode::utf16);
return load(file, nana::unicode::utf16);
}
}
else if(0xFE == ch)
@ -107,7 +104,7 @@ namespace skeletons
{
//UTF16(big-endian)
ifs.close();
return load(file_utf8, nana::unicode::utf16);
return load(file, nana::unicode::utf16);
}
}
else if(0 == ch)
@ -119,7 +116,7 @@ namespace skeletons
{
//UTF32(big_endian)
ifs.close();
return load(file_utf8, nana::unicode::utf32);
return load(file, nana::unicode::utf32);
}
}
}
@ -135,15 +132,15 @@ namespace skeletons
while(ifs.good())
{
std::getline(ifs, str_mbs);
text_cont_.emplace_back(new string_type(static_cast<string_type&&>(nana::charset{ str_mbs })));
if(text_cont_.back()->size() > attr_max_.size)
text_cont_.emplace_back(static_cast<string_type&&>(nana::charset{ str_mbs }));
if (text_cont_.back().size() > attr_max_.size)
{
attr_max_.size = text_cont_.back()->size();
attr_max_.size = text_cont_.back().size();
attr_max_.line = text_cont_.size() - 1;
}
}
_m_saved(file_utf8);
_m_saved(file);
return true;
}
@ -175,12 +172,9 @@ namespace skeletons
}
}
bool load(const char* file_utf8, nana::unicode encoding)
bool load(const path_type& file, nana::unicode encoding)
{
if (!file_utf8)
return false;
std::ifstream ifs(to_osmbstr(file_utf8));
std::ifstream ifs{ file.string() };
if (!ifs)
return false;
@ -218,9 +212,8 @@ namespace skeletons
byte_order_translate_4bytes(str);
}
text_cont_.emplace_back(new string_type(static_cast<string_type&&>(nana::charset{ str, encoding })));
attr_max_.size = text_cont_.back()->size();
text_cont_.emplace_back(static_cast<string_type&&>(nana::charset{ str, encoding }));
attr_max_.size = text_cont_.back().size();
attr_max_.line = 0;
}
@ -236,21 +229,21 @@ namespace skeletons
byte_order_translate_4bytes(str);
}
text_cont_.emplace_back(new string_type(static_cast<string_type&&>(nana::charset{ str, encoding })));
if(text_cont_.back()->size() > attr_max_.size)
text_cont_.emplace_back(static_cast<string_type&&>(nana::charset{ str, encoding }));
if (text_cont_.back().size() > attr_max_.size)
{
attr_max_.size = text_cont_.back()->size();
attr_max_.size = text_cont_.back().size();
attr_max_.line = text_cont_.size() - 1;
}
}
_m_saved(file_utf8);
_m_saved(file);
return true;
}
void store(std::string fs, bool is_unicode, ::nana::unicode encoding) const
void store(const path_type& filename, bool is_unicode, ::nana::unicode encoding) const
{
std::ofstream ofs(to_osmbstr(fs), std::ios::binary);
std::ofstream ofs(filename.string(), std::ios::binary);
if(ofs && text_cont_.size())
{
auto i = text_cont_.cbegin();
@ -277,27 +270,26 @@ namespace skeletons
for (std::size_t pos = 0; pos < count; ++pos)
{
auto mbs = nana::charset(**(i++)).to_bytes(encoding);
auto mbs = nana::charset(*(i++)).to_bytes(encoding);
ofs.write(mbs.c_str(), static_cast<std::streamsize>(mbs.size()));
ofs.write("\r\n", 2);
}
last_mbs = nana::charset(*text_cont_.back()).to_bytes(encoding);
last_mbs = nana::charset(text_cont_.back()).to_bytes(encoding);
}
else
{
for (std::size_t pos = 0; pos < count; ++pos)
{
std::string mbs = nana::charset(**(i++));
std::string mbs = nana::charset(*(i++));
ofs.write(mbs.c_str(), mbs.size());
ofs.write("\r\n", 2);
}
last_mbs = nana::charset(*text_cont_.back());
last_mbs = nana::charset(text_cont_.back());
}
ofs.write(last_mbs.c_str(), static_cast<std::streamsize>(last_mbs.size()));
_m_saved(std::move(fs));
_m_saved(filename);
}
}
@ -311,7 +303,7 @@ namespace skeletons
{
if (!changed_)
{
_m_first_change();
_m_emit_first_change();
changed_ = true;
}
@ -332,8 +324,7 @@ namespace skeletons
const string_type& getline(size_type pos) const
{
if (pos < text_cont_.size())
return *text_cont_[pos];
return text_cont_[pos];
return nullstr_;
}
@ -346,7 +337,7 @@ namespace skeletons
{
if (text_cont_.size() <= pos)
{
text_cont_.emplace_back(new string_type(std::move(text)));
text_cont_.emplace_back(std::move(text));
pos = text_cont_.size() - 1;
}
else
@ -369,7 +360,7 @@ namespace skeletons
}
else
{
text_cont_.emplace_back(new string_type(std::move(str)));
text_cont_.emplace_back(std::move(str));
pos.y = static_cast<unsigned>(text_cont_.size() - 1);
}
@ -380,9 +371,9 @@ namespace skeletons
void insertln(size_type pos, string_type&& str)
{
if (pos < text_cont_.size())
text_cont_.emplace(_m_iat(pos), new string_type(std::move(str)));
text_cont_.emplace(_m_iat(pos), std::move(str));
else
text_cont_.emplace_back(new string_type(std::move(str)));
text_cont_.emplace_back(std::move(str));
_m_make_max(pos);
edited_ = true;
@ -429,9 +420,9 @@ namespace skeletons
{
text_cont_.clear();
attr_max_.reset();
text_cont_.emplace_back(new string_type); //text_cont_ must not be empty
text_cont_.emplace_back(); //text_cont_ must not be empty
_m_saved(std::string());
_m_saved({});
}
void merge(size_type pos)
@ -439,7 +430,8 @@ namespace skeletons
if(pos + 1 < text_cont_.size())
{
auto i = _m_iat(pos + 1);
_m_at(pos) += **i;
_m_at(pos) += *i;
text_cont_.erase(i);
_m_make_max(pos);
@ -453,7 +445,7 @@ namespace skeletons
}
}
const std::string& filename() const
const path_type& filename() const
{
return filename_;
}
@ -463,33 +455,25 @@ namespace skeletons
return changed_;
}
void edited_reset()
{
changed_ = false;
}
void reset()
void reset_status(bool remain_saved_filename)
{
if(!remain_saved_filename)
filename_.clear();
changed_ = false;
}
bool saved() const
{
return ! not_saved();
}
bool not_saved() const
{
return edited() || filename_.empty();
return !(changed_ || filename_.empty());
}
private:
string_type& _m_at(size_type pos)
{
return **_m_iat(pos);
return *_m_iat(pos);
}
typename std::deque<std::unique_ptr<string_type>>::iterator _m_iat(size_type pos)
typename std::deque<string_type>::iterator _m_iat(size_type pos)
{
return text_cont_.begin() + pos;
}
@ -506,50 +490,40 @@ namespace skeletons
void _m_scan_for_max()
{
attr_max_.size = 0;
std::size_t n = 0;
for(auto & p : text_cont_)
{
if(p->size() > attr_max_.size)
{
attr_max_.size = p->size();
attr_max_.line = n;
}
++n;
}
attr_max_.reset();
for (std::size_t i = 0; i < text_cont_.size(); ++i)
_m_make_max(i);
}
void _m_first_change() const
void _m_emit_first_change() const
{
if (evt_agent_)
evt_agent_->first_change();
}
void _m_saved(std::string && filename) const
void _m_saved(const path_type& filename) const
{
if(filename_ != filename)
if((filename_ != filename) || changed_)
{
filename_ = std::move(filename);
_m_first_change();
filename_ = filename;
_m_emit_first_change();
}
else if(changed_)
_m_first_change();
changed_ = false;
}
private:
std::deque<std::unique_ptr<string_type>> text_cont_;
std::deque<string_type> text_cont_;
textbase_event_agent_interface* evt_agent_{ nullptr };
mutable bool changed_{ false };
mutable bool edited_{ false };
mutable std::string filename_; //A string for the saved filename.
mutable path_type filename_; ///< The saved filename
const string_type nullstr_;
struct attr_max
{
std::size_t line;
std::size_t size;
std::size_t line; ///< The line number of max line
std::size_t size; ///< The number of characters in max line
void reset()
{

View File

@ -151,7 +151,13 @@ namespace nana
bool vertical() const;
void maximum(unsigned);
unsigned maximum() const;
void value(unsigned);
/** Set slider value
@param[in] v new value for slider.
v will be clipped to the range 0 to maximum
*/
void value(int );
unsigned value() const;
unsigned move_step(bool forward); ///< Increase or decrease the value of slider.
unsigned adorn() const;

View File

@ -29,17 +29,56 @@ namespace nana
{
tabbar<T> & widget;
T & value;
std::size_t item_pos; ///< position of the item
arg_tabbar(tabbar<T>& wdg, T& v)
: widget(wdg), value{ v }
arg_tabbar(tabbar<T>& wdg, T& v, std::size_t p)
: widget(wdg), value{ v }, item_pos(p)
{}
};
template<typename T>
struct arg_tabbar_click : public arg_tabbar<T>
{
arg_tabbar_click(tabbar<T>& wdg, T& v, std::size_t p)
: arg_tabbar<T>({wdg, v, p})
{}
bool left_button = false; ///< true if mouse left button is pressed
bool mid_button = false; ///< true if mouse middle button is pressed
bool right_button = false; ///< true if mouse right button is pressed
};
template<typename T>
struct arg_tabbar_mouse
: public arg_mouse
{
arg_tabbar_mouse(const arg_mouse& arg, tabbar<T>& wdg, T& v, std::size_t p)
: arg_mouse{ arg }, widget(wdg), value{ v }, item_pos(p)
{}
tabbar<T> & widget;
T & value;
std::size_t item_pos; ///< position of the item
};
template<typename T>
struct arg_tabbar_adding
: public event_arg
{
arg_tabbar_adding(tabbar<T>& wdg, std::size_t p)
: widget(wdg), where(p)
{}
tabbar<T> & widget;
mutable bool add = true; ///< determines whether to add the item
std::size_t where; ///< position where to add the item
};
template<typename T>
struct arg_tabbar_removed : public arg_tabbar<T>
{
arg_tabbar_removed(tabbar<T>& wdg, T& v)
: arg_tabbar<T>({wdg, v})
arg_tabbar_removed(tabbar<T>& wdg, T& v, std::size_t p)
: arg_tabbar<T>({wdg, v, p})
{}
mutable bool remove = true; ///< determines whether to remove the item
@ -56,7 +95,9 @@ namespace nana
{
using value_type = T;
basic_event<arg_tabbar_adding<value_type>> adding;
basic_event<arg_tabbar<value_type>> added;
basic_event<arg_tabbar_mouse<value_type>> tab_click;
basic_event<arg_tabbar<value_type>> activated;
basic_event<arg_tabbar_removed<value_type>> removed;
};
@ -65,7 +106,9 @@ namespace nana
{
public:
virtual ~event_agent_interface() = default;
virtual bool adding(std::size_t) = 0;
virtual void added(std::size_t) = 0;
virtual bool click(const arg_mouse&, std::size_t) = 0;
virtual void activated(std::size_t) = 0;
virtual bool removed(std::size_t, bool & close_attached) = 0;
};
@ -107,26 +150,40 @@ namespace nana
: tabbar_(tb), drawer_trigger_(dtr)
{}
bool adding(std::size_t pos) override
{
::nana::arg_tabbar_adding<T> arg_ta(tabbar_, pos);
tabbar_.events().adding.emit(arg_ta, tabbar_);
return arg_ta.add;
}
void added(std::size_t pos) override
{
if(pos != npos)
{
drawer_trigger_.at_no_bound_check(pos) = T();
tabbar_.events().added.emit(arg_tabbar({ tabbar_, tabbar_[pos] }), tabbar_);
tabbar_.events().added.emit(arg_tabbar({ tabbar_, tabbar_[pos], pos }), tabbar_);
}
}
bool click(const arg_mouse& arg, std::size_t pos) override
{
::nana::arg_tabbar_mouse<T> arg_tm(arg, tabbar_, tabbar_[pos], pos);
tabbar_.events().tab_click.emit(arg_tm, tabbar_);
return arg_tm.propagation_stopped();
}
void activated(std::size_t pos) override
{
if(pos != npos)
tabbar_.events().activated.emit(arg_tabbar({ tabbar_, tabbar_[pos]}), tabbar_);
tabbar_.events().activated.emit(arg_tabbar({ tabbar_, tabbar_[pos], pos}), tabbar_);
}
bool removed(std::size_t pos, bool & close_attach) override
{
if (pos != npos)
if(pos != npos)
{
::nana::arg_tabbar_removed<T> arg(tabbar_, tabbar_[pos]);
::nana::arg_tabbar_removed<T> arg(tabbar_, tabbar_[pos], pos);
tabbar_.events().removed.emit(arg, tabbar_);
close_attach = arg.close_attach_window;
return arg.remove;

View File

@ -1,7 +1,7 @@
/**
* A Textbox Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -109,6 +109,8 @@ namespace nana
using text_focus_behavior = widgets::skeletons::text_focus_behavior;
using text_positions = std::vector<upoint>;
using path_type = std::filesystem::path;
/// The default constructor without creating the widget.
textbox();
@ -136,9 +138,9 @@ namespace nana
textbox(window, const rectangle& = rectangle(), bool visible = true);
/// \brief Loads a text file. When attempt to load a unicode encoded text file, be sure the file have a BOM header.
void load(std::string file);
void store(std::string file);
void store(std::string file, nana::unicode encoding);
void load(const path_type& file);
void store(const path_type& file);
void store(const path_type& file, nana::unicode encoding);
colored_area_access_interface* colored_area_access();
@ -158,7 +160,7 @@ namespace nana
textbox& reset(const std::string& text = std::string(), bool end_caret = true); ///< discard the old text and set a new text
/// The file of last store operation.
std::string filename() const;
path_type filename() const;
/// Determine whether the text was edited.
bool edited() const;
@ -224,6 +226,8 @@ namespace nana
/// Selects/unselects all text.
void select(bool);
void select_points(nana::upoint arg_a, nana::upoint arg_b);
/// Returns the bounds of a text selection
/**
* @return no selection if pair.first == pair.second.

View File

@ -1,7 +1,7 @@
/**
* A Tree Box Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at
@ -60,8 +60,26 @@ namespace nana
::std::string text;
};
struct scheme
: public widget_geometrics
{
color_proxy item_bg_selected{ static_cast<color_rgb>(0xD5EFFC) }; ///< item selected: background color
color_proxy item_fg_selected{ static_cast<color_rgb>(0x99DEFD) }; ///< item selected: foreground color
color_proxy item_bg_highlighted{ static_cast<color_rgb>(0xE8F5FD) }; ///< item highlighted: background color
color_proxy item_fg_highlighted{ static_cast<color_rgb>(0xD8F0FA) }; ///< item highlighted: foreground color
color_proxy item_bg_selected_and_highlighted{ static_cast<color_rgb>(0xC4E8FA) }; ///< item selected and highlighted: background color
color_proxy item_fg_selected_and_highlighted{ static_cast<color_rgb>(0xB6E6FB) }; ///< item selected and highlighted: foreground color
unsigned item_offset{ 16 }; ///< item position displacement in pixels
unsigned text_offset{ 4 }; ///< text position displacement in pixels
unsigned icon_size{ 16 }; ///< icon size in pixels
unsigned crook_size{ 16 }; ///< crook size in pixels (TODO: the function that draw the crook doesn't scale the shape)
unsigned indent_displacement{ 18 }; ///< children position displacement in pixels (def=18 (before was 10))
};
typedef widgets::detail::compset<component, node_attribute> compset_interface;
typedef widgets::detail::compset_placer<component, node_attribute> compset_placer_interface;
typedef widgets::detail::compset_placer<component, node_attribute, scheme> compset_placer_interface;
class renderer_interface
{
@ -87,13 +105,8 @@ namespace nana
class trigger
:public drawer_trigger
{
template<typename Renderer>
struct basic_implement;
class item_renderer;
class implementation;
class item_locator;
typedef basic_implement<item_renderer> implement;
public:
struct treebox_node_type
{
@ -116,27 +129,25 @@ namespace nana
trigger();
~trigger();
implement * impl() const;
implementation * impl() const;
void check(node_type*, checkstate);
void renderer(::nana::pat::cloneable<renderer_interface>&&);
const ::nana::pat::cloneable<renderer_interface>& renderer() const;
pat::cloneable<renderer_interface>& renderer() const;
void placer(::nana::pat::cloneable<compset_placer_interface>&&);
const ::nana::pat::cloneable<compset_placer_interface>& placer() const;
node_type* insert(node_type*, const std::string& key, std::string&&);
node_type* insert(const std::string& path, std::string&&);
node_type * selected() const;
void selected(node_type*);
node_image_tag& icon(const ::std::string&) const;
node_image_tag& icon(const ::std::string&);
void icon_erase(const ::std::string&);
void node_icon(node_type*, const ::std::string& id);
unsigned node_width(const node_type*) const;
bool rename(node_type*, const char* key, const char* name);
private:
//Overrides drawer_trigger methods
void attached(widget_reference, graph_reference) override;
@ -152,7 +163,7 @@ namespace nana
void key_press(graph_reference, const arg_keyboard&) override;
void key_char(graph_reference, const arg_keyboard&) override;
private:
implement * const impl_;
implementation * const impl_;
}; //end class trigger
@ -171,11 +182,11 @@ namespace nana
/// Append a child with a specified value (user object.).
template<typename T>
item_proxy append(const ::std::string& key, ::std::string name, const T&t)
item_proxy append(const ::std::string& key, ::std::string name, T&& t)
{
item_proxy ip = append(key, std::move(name));
if(false == ip.empty())
ip.value(t);
ip.value(std::forward<T>(t));
return ip;
}
@ -291,17 +302,10 @@ namespace nana
return *p;
}
template<typename T>
item_proxy & value(const T& t)
{
_m_value() = t;
return *this;
}
template<typename T>
item_proxy & value(T&& t)
{
_m_value() = std::move(t);
_m_value() = std::forward<T>(t);
return *this;
}
@ -346,7 +350,7 @@ namespace nana
/// \brief Displays a hierarchical list of items, such as the files and directories on a disk.
/// See also in [documentation](http://nanapro.org/en-us/documentation/widgets/treebox.htm)
class treebox
:public widget_object < category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events>
:public widget_object <category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events, drawerbase::treebox::scheme>
{
public:
/// A type refers to the item and is also used to iterate through the nodes.
@ -378,7 +382,7 @@ namespace nana
template<typename ItemRenderer>
treebox & renderer(const ItemRenderer & rd) ///< set user-defined node renderer
{
get_drawer_trigger().renderer(::nana::pat::cloneable<renderer_interface>(rd));
get_drawer_trigger().renderer() = ::nana::pat::cloneable<renderer_interface>{rd};
return *this;
}
@ -403,6 +407,23 @@ namespace nana
/// @param enable bool whether to enable.
void auto_draw(bool enable);
/// Prevents drawing during execution.
template<typename Function>
void avoid_drawing(Function fn)
{
this->auto_draw(false);
try
{
fn();
}
catch (...)
{
this->auto_draw(true);
throw;
}
this->auto_draw(true);
}
/// \brief Enable the checkboxs for each item of the widget.
/// @param enable bool indicates whether to show or hide the checkboxs.
treebox & checkable(bool enable);
@ -419,8 +440,9 @@ namespace nana
/// These states are 'normal', 'hovered' and 'expanded'.
/// If 'hovered' or 'expanded' are not set, it uses 'normal' state image for these 2 states.
/// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm)
node_image_type& icon(const ::std::string& id ///< the name of an icon scheme. If the name is not existing, it creates a new scheme for the name.
) const;
/// @param id The name of an icon scheme. If the name is not existing, it creates a new scheme for the name.
/// @return The reference of node image scheme correspending with the specified id.
node_image_type& icon(const ::std::string& id);
void icon_erase(const ::std::string& id);
@ -445,6 +467,19 @@ namespace nana
item_proxy selected() const; ///< returns the selected node
/// Scrolls a specified item into view.
/**
* @param item An item to be requested.
* @param bearing The position where the item to be positioned in the view.
*/
void scroll_into_view(item_proxy item, align_v bearing);
/// Scrolls a specified item into view.
/**
* @param item An item to be requested.
*/
void scroll_into_view(item_proxy item);
private:
std::shared_ptr<scroll_operation_interface> _m_scroll_operation() override;

View File

@ -1,7 +1,7 @@
/**
* The fundamental widget class implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -499,72 +499,6 @@ namespace nana
std::unique_ptr<scheme_type> scheme_;
};//end class widget_object<root_tag>
#ifndef WIDGET_FRAME_DEPRECATED
/// Base class of all the classes defined as a frame window. \see nana::frame
template<typename Drawer, typename Events, typename Scheme>
class widget_object<category::frame_tag, Drawer, Events, Scheme>: public widget{};
/// Especialization. Base class of all the classes defined as a frame window. \see nana::frame
template<typename Events, typename Scheme>
class widget_object<category::frame_tag, int, Events, Scheme>: public detail::widget_base
{
protected:
typedef int drawer_trigger_t;
public:
using scheme_type = Scheme;
using event_type = Events;
widget_object()
: events_{ std::make_shared<Events>() }, scheme_{ API::dev::make_scheme<scheme_type>() }
{}
~widget_object()
{
API::close_window(handle());
}
event_type& events() const
{
return *events_;
}
bool create(window parent_wd, bool visible) ///< Creates a no-size (zero-size) widget. in a widget/root window specified by parent_wd.
{
return create(parent_wd, rectangle(), visible);
}
/// Creates in a widget/root window specified by parent_wd.
bool create(window parent_wd, const rectangle& r = rectangle(), bool visible = true)
{
if(parent_wd && this->empty())
{
handle_ = API::dev::create_frame(parent_wd, r, this);
API::dev::set_events(handle_, events_);
API::dev::set_scheme(handle_, scheme_.get());
API::show_window(handle_, visible);
this->_m_complete_creation();
}
return (this->empty() == false);
}
scheme_type& scheme() const
{
return *scheme_;
}
private:
virtual drawer_trigger* get_drawer_trigger()
{
return nullptr;
}
general_events& _m_get_general_events() const override
{
return *events_;
}
private:
std::shared_ptr<Events> events_;
std::unique_ptr<scheme_type> scheme_;
};//end class widget_object<category::frame_tag>
#endif
}//end namespace nana
#include <nana/pop_ignore_diagnostic>

View File

@ -16,7 +16,7 @@ namespace nana{ namespace paint{
public:
using graph_reference = nana::paint::graphics&;
virtual ~image_impl_interface() = 0; //The destructor is defined in ../image.cpp
virtual bool open(const std::experimental::filesystem::path& file) = 0;
virtual bool open(const std::filesystem::path& file) = 0;
virtual bool open(const void* data, std::size_t bytes) = 0; // reads image from memory
virtual bool alpha_channel() const = 0;
virtual bool empty() const = 0;

View File

@ -33,7 +33,7 @@ namespace nana
{
friend class graphics;
public:
using path_type = ::std::experimental::filesystem::path;
using path_type = ::std::filesystem::path;
using font_style = ::nana::detail::font_style;

View File

@ -15,6 +15,7 @@
#include <windows.h>
#endif
#include <cassert>
#include <array>
namespace {
std::tm localtime()
@ -239,18 +240,20 @@ namespace nana
return days + d;
}
unsigned date::month_days(unsigned year, unsigned month)
unsigned date::month_days(const unsigned year, const unsigned month)
{
unsigned num[] = {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(month != 2)
return num[month - 1];
if (month != 2)
{
constexpr std::array<unsigned, 12> days_in_month = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
return days_in_month[month - 1];
}
if(((year % 4 == 0) && (year % 100)) || (year % 400 == 0))
return 29;
return 28;
}
unsigned date::year_days(unsigned year)
unsigned date::year_days(const unsigned year)
{
if(((year % 4 == 0) && (year % 100)) || (year % 400 == 0))
return 366;

View File

@ -1,4 +1,4 @@
/*
/**
* Platform Specification Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
@ -7,7 +7,7 @@
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/detail/platform_spec.hpp
* @file nana/detail/platform_spec.hpp
*
* This file provides basis class and data structrue that required by nana
* This file should not be included by any header files.

View File

@ -158,7 +158,7 @@ namespace nana
: public font_interface
{
public:
using path_type = std::experimental::filesystem::path;
using path_type = std::filesystem::path;
internal_font(const path_type& ttf, const std::string& font_family, double font_size, const font_style& fs, native_font_type native_font):
ttf_(ttf),

View File

@ -28,7 +28,7 @@ namespace nana
public:
using font = font_interface;
using path_type = ::std::experimental::filesystem::path;
using path_type = ::std::filesystem::path;
static void initialize();
/// Shutdown before destruction of platform_spec

View File

@ -500,20 +500,23 @@ namespace detail
atombase_.net_wm_window_type_dialog = ::XInternAtom(display_, "_NET_WM_WINDOW_TYPE_DIALOG", False);
atombase_.motif_wm_hints = ::XInternAtom(display_, "_MOTIF_WM_HINTS", False);
atombase_.clipboard = ::XInternAtom(display_, "CLIPBOARD", True);
atombase_.text = ::XInternAtom(display_, "TEXT", True);
atombase_.text_uri_list = ::XInternAtom(display_, "text/uri-list", True);
atombase_.utf8_string = ::XInternAtom(display_, "UTF8_STRING", True);
atombase_.targets = ::XInternAtom(display_, "TARGETS", True);
atombase_.clipboard = ::XInternAtom(display_, "CLIPBOARD", False);
atombase_.text = ::XInternAtom(display_, "TEXT", False);
atombase_.text_uri_list = ::XInternAtom(display_, "text/uri-list", False);
atombase_.utf8_string = ::XInternAtom(display_, "UTF8_STRING", False);
atombase_.targets = ::XInternAtom(display_, "TARGETS", False);
atombase_.xdnd_aware = ::XInternAtom(display_, "XdndAware", False);
atombase_.xdnd_enter = ::XInternAtom(display_, "XdndEnter", False);
atombase_.xdnd_position = ::XInternAtom(display_, "XdndPosition", False);
atombase_.xdnd_status = ::XInternAtom(display_, "XdndStatus", False);
atombase_.xdnd_action_copy = ::XInternAtom(display_, "XdndActionCopy", False);
atombase_.xdnd_action_move = ::XInternAtom(display_, "XdndActionMove", False);
atombase_.xdnd_action_link = ::XInternAtom(display_, "XdndActionLink", False);
atombase_.xdnd_drop = ::XInternAtom(display_, "XdndDrop", False);
atombase_.xdnd_selection = ::XInternAtom(display_, "XdndSelection", False);
atombase_.xdnd_typelist = ::XInternAtom(display_, "XdndTypeList", False);
atombase_.xdnd_leave = ::XInternAtom(display_, "XdndLeave", False);
atombase_.xdnd_finished = ::XInternAtom(display_, "XdndFinished", False);
msg_dispatcher_ = new msg_dispatcher(display_);
@ -658,21 +661,31 @@ namespace detail
platform_scope_guard lock;
if(umake_owner(wd))
{
auto & wd_manager = detail::bedrock::instance().wd_manager();
std::vector<native_window_type> owned_children;
auto i = wincontext_.find(wd);
if(i != wincontext_.end())
{
if(i->second.owned)
{
set_error_handler();
auto & wd_manager = detail::bedrock::instance().wd_manager();
for(auto u = i->second.owned->rbegin(); u != i->second.owned->rend(); ++u)
wd_manager.close(wd_manager.root(*u));
rev_error_handler();
delete i->second.owned;
for(auto child : *i->second.owned)
owned_children.push_back(child);
}
}
//Closing a child will erase the wd from the table wincontext_, so the
//iterator i can't be reused after children closed.
set_error_handler();
for(auto u = owned_children.rbegin(); u != owned_children.rend(); ++u)
wd_manager.close(wd_manager.root(*u));
rev_error_handler();
i = wincontext_.find(wd);
if(i != wincontext_.end())
{
delete i->second.owned;
wincontext_.erase(i);
}
}
@ -1031,6 +1044,12 @@ namespace detail
msg_dispatcher_->dispatch(reinterpret_cast<Window>(modal));
}
void platform_spec::msg_dispatch(std::function<propagation_chain(const msg_packet_tag&)> msg_filter_fn)
{
msg_dispatcher_->dispatch(msg_filter_fn);
}
void* platform_spec::request_selection(native_window_type requestor, Atom type, size_t& size)
{
if(requestor)
@ -1094,6 +1113,62 @@ namespace detail
return graph;
}
bool platform_spec::register_dragdrop(native_window_type wd, x11_dragdrop_interface* ddrop)
{
platform_scope_guard lock;
if(0 != xdnd_.dragdrop.count(wd))
return false;
xdnd_.dragdrop[wd] = ddrop;
return true;
}
std::size_t platform_spec::dragdrop_target(native_window_type wd, bool insert, std::size_t count)
{
std::size_t new_val = 0;
platform_scope_guard lock;
if(insert)
{
new_val = (xdnd_.targets[wd] += count);
if(1 == new_val)
{
int dndver = 5;
::XChangeProperty(display_, reinterpret_cast<Window>(wd), atombase_.xdnd_aware, XA_ATOM, sizeof(int) * 8,
PropModeReplace, reinterpret_cast<unsigned char*>(&dndver), 1);
}
}
else
{
auto i = xdnd_.targets.find(wd);
if(i == xdnd_.targets.end())
return 0;
new_val = (i->second > count ? i->second - count : 0);
if(0 == new_val)
{
xdnd_.targets.erase(wd);
::XDeleteProperty(display_, reinterpret_cast<Window>(wd), atombase_.xdnd_aware);
}
else
i->second = new_val;
}
return new_val;
}
x11_dragdrop_interface* platform_spec::remove_dragdrop(native_window_type wd)
{
platform_scope_guard lock;
auto i = xdnd_.dragdrop.find(wd);
if(i == xdnd_.dragdrop.end())
return nullptr;
auto ddrop = i->second;
xdnd_.dragdrop.erase(i);
return ddrop;
}
//_m_msg_filter
//@return: _m_msg_filter returns three states
// 0 = msg_dispatcher dispatches the XEvent
@ -1153,7 +1228,7 @@ namespace detail
else if(evt.xselection.property == self.atombase_.xdnd_selection)
{
bool accepted = false;
msg.kind = msg.kind_mouse_drop;
msg.kind = msg_packet_tag::pkt_family::mouse_drop;
msg.u.mouse_drop.window = 0;
if(bytes_left > 0 && type == self.xdnd_.good_type)
{
@ -1163,8 +1238,9 @@ namespace detail
0, AnyPropertyType, &type, &format, &len,
&dummy_bytes_left, &data))
{
auto files = new std::vector<std::string>;
auto files = new std::vector<std::filesystem::path>;
std::stringstream ss(reinterpret_cast<char*>(data));
while(true)
{
std::string file;
@ -1182,8 +1258,9 @@ namespace detail
break;
}
files->push_back(file);
files->emplace_back(file);
}
if(files->size())
{
msg.u.mouse_drop.window = evt.xselection.requestor;
@ -1198,8 +1275,9 @@ namespace detail
::XFree(data);
}
}
XEvent respond;
::XEvent respond;
::memset(respond.xclient.data.l, 0, sizeof(respond.xclient.data.l));
respond.xany.type = ClientMessage;
respond.xclient.display = self.display_;
respond.xclient.window = self.xdnd_.wd_src;
respond.xclient.message_type = self.atombase_.xdnd_finished;
@ -1222,6 +1300,10 @@ namespace detail
}
else if(SelectionRequest == evt.type)
{
//Skip if it is requested by XDND, it will be processed by dragdrop's xdnd_protocol
if(self.atombase_.xdnd_selection == evt.xselectionrequest.selection)
return 0;
auto disp = evt.xselectionrequest.display;
XEvent respond;
@ -1286,24 +1368,56 @@ namespace detail
::XGetWindowProperty(self.display_, self.xdnd_.wd_src, self.atombase_.xdnd_typelist,
0, bytes_left, False, XA_ATOM,
&type, &format, &len, &bytes_left, &data);
if(XA_ATOM == type && len > 0)
atoms = reinterpret_cast<const Atom*>(data);
}
}
#define DEBUG_XdndDirectSave
#ifdef DEBUG_XdndDirectSave
Atom XdndDirectSave = 0;
#endif
self.xdnd_.good_type = None;
for(unsigned long i = 0; i < len; ++i)
{
auto name = XGetAtomName(self.display_, atoms[i]); //debug
if(name)
{
#ifdef DEBUG_XdndDirectSave
if(strstr(name, "XdndDirectSave"))
XdndDirectSave = atoms[i];
#endif
::XFree(name);
}
if(atoms[i] == self.atombase_.text_uri_list)
{
self.xdnd_.good_type = self.atombase_.text_uri_list;
break;
//break;
}
}
if(data)
::XFree(data);
#ifdef DEBUG_XdndDirectSave //debug
if(XdndDirectSave)
{
Atom type;
int format;
unsigned long bytes_left;
::XGetWindowProperty(self.display_, self.xdnd_.wd_src, XdndDirectSave, 0, 0, False, XA_ATOM, &type, &format, &len, &bytes_left, &data);
if(bytes_left > 0)
{
::XGetWindowProperty(self.display_, self.xdnd_.wd_src, XdndDirectSave,
0, bytes_left, False, type,
&type, &format, &len, &bytes_left, &data);
}
}
#endif
return 2;
}
else if(self.atombase_.xdnd_position == evt.xclient.message_type)
@ -1312,7 +1426,7 @@ namespace detail
int x = (evt.xclient.data.l[2] >> 16);
int y = (evt.xclient.data.l[2] & 0xFFFF);
bool accepted = false;
int accepted = 0; //0 means refusing, 1 means accpeting
//We have got the type what we want.
if(self.xdnd_.good_type != None)
{
@ -1322,9 +1436,10 @@ namespace detail
auto wd = bedrock.wd_manager().find_window(reinterpret_cast<native_window_type>(evt.xclient.window), self.xdnd_.pos);
if(wd && wd->flags.dropable)
{
accepted = true;
//Cache the time stamp in XdndPosition, and the time stamp must be passed to XConvertSelection for requesting selection
self.xdnd_.timestamp = evt.xclient.data.l[3];
self.xdnd_.pos = wd->pos_root;
accepted = 1;
}
}
@ -1339,7 +1454,7 @@ namespace detail
//Target window
respond.xclient.data.l[0] = evt.xclient.window;
//Accept set
respond.xclient.data.l[1] = (accepted ? 1 : 0);
respond.xclient.data.l[1] = accepted;
respond.xclient.data.l[2] = 0;
respond.xclient.data.l[3] = 0;
respond.xclient.data.l[4] = self.atombase_.xdnd_action_copy;
@ -1347,10 +1462,15 @@ namespace detail
::XSendEvent(self.display_, wd_src, True, NoEventMask, &respond);
return 2;
}
else if(self.atombase_.xdnd_status == evt.xclient.message_type)
{
//Platform Recv XdndStatus
}
else if(self.atombase_.xdnd_drop == evt.xclient.message_type)
{
::XConvertSelection(self.display_, self.atombase_.xdnd_selection, self.xdnd_.good_type, self.atombase_.xdnd_selection,
evt.xclient.window, self.xdnd_.timestamp);
//The XdndDrop should send a XdndFinished to source window.
//This operation is implemented in SelectionNotify, because
//XdndFinished should be sent after retrieving data.

View File

@ -143,7 +143,7 @@ namespace detail
{
//Make a cleanup msg packet to infor the dispatcher the window is closed.
msg_packet_tag msg;
msg.kind = msg.kind_cleanup;
msg.kind = msg_packet_tag::pkt_family::cleanup;
msg.u.packet_window = wd;
thr->msg_queue.push_back(msg);
}
@ -171,6 +171,37 @@ namespace detail
}
}
}
template<typename MsgFilter>
void dispatch(MsgFilter msg_filter_fn)
{
auto tid = nana::system::this_thread_id();
msg_packet_tag msg;
int qstate;
//Test whether the thread is registered for window, and retrieve the queue state for event
while((qstate = _m_read_queue(tid, msg, 0)))
{
//the queue is empty
if(-1 == qstate)
{
if(false == _m_wait_for_queue(tid))
proc_.timer_proc(tid);
}
else
{
switch(msg_filter_fn(msg))
{
case propagation_chain::exit:
return;
case propagation_chain::stop:
break;
case propagation_chain::pass:
proc_.event_proc(display_, msg);
}
}
}
}
private:
void _m_msg_driver()
{
@ -220,7 +251,7 @@ namespace detail
switch(proc_.filter_proc(event, msg_pack))
{
case 0:
msg_pack.kind = msg_pack.kind_xevent;
msg_pack.kind = msg_packet_tag::pkt_family::xevent;
msg_pack.u.xevent = event;
_m_msg_dispatch(msg_pack);
break;
@ -246,9 +277,9 @@ namespace detail
{
switch(pack.kind)
{
case msg_packet_tag::kind_xevent:
case msg_packet_tag::pkt_family::xevent:
return _m_event_window(pack.u.xevent);
case msg_packet_tag::kind_mouse_drop:
case msg_packet_tag::pkt_family::mouse_drop:
return pack.u.mouse_drop.window;
default:
break;
@ -294,7 +325,7 @@ namespace detail
//Check whether the event dispatcher is used for the modal window
//and when the modal window is closing, the event dispatcher would
//stop event pumping.
if((modal == msg.u.packet_window) && (msg.kind == msg.kind_cleanup))
if((modal == msg.u.packet_window) && (msg.kind == msg_packet_tag::pkt_family::cleanup))
return 0;
return 1;

View File

@ -3,15 +3,23 @@
#include <X11/Xlib.h>
#include <vector>
#include <nana/deploy.hpp>
#include <nana/filesystem/filesystem.hpp>
namespace nana
{
namespace detail
{
enum class propagation_chain
{
exit, //Exit the chain
stop, //Stop propagating
pass //propagate
};
struct msg_packet_tag
{
enum kind_t{kind_xevent, kind_mouse_drop, kind_cleanup};
kind_t kind;
enum class pkt_family{xevent, mouse_drop, cleanup};
pkt_family kind;
union
{
XEvent xevent;
@ -22,7 +30,7 @@ namespace detail
Window window;
int x;
int y;
std::vector<std::string> * files;
std::vector<std::filesystem::path> * files;
}mouse_drop;
}u;
};

View File

@ -36,6 +36,7 @@
#include <vector>
#include <map>
#include <functional>
#include "msg_packet.hpp"
#include "../platform_abstraction_types.hpp"
@ -158,9 +159,12 @@ namespace detail
Atom xdnd_position;
Atom xdnd_status;
Atom xdnd_action_copy;
Atom xdnd_action_move;
Atom xdnd_action_link;
Atom xdnd_drop;
Atom xdnd_selection;
Atom xdnd_typelist;
Atom xdnd_leave;
Atom xdnd_finished;
};
@ -176,6 +180,15 @@ namespace detail
~platform_scope_guard();
};
class x11_dragdrop_interface
{
public:
virtual ~x11_dragdrop_interface() = default;
virtual void add_ref() = 0;
virtual std::size_t release() = 0;
};
class platform_spec
{
typedef platform_spec self_type;
@ -246,6 +259,7 @@ namespace detail
void msg_insert(native_window_type);
void msg_set(timer_proc_type, event_proc_type);
void msg_dispatch(native_window_type modal);
void msg_dispatch(std::function<propagation_chain(const msg_packet_tag&)>);
//X Selections
void* request_selection(native_window_type requester, Atom type, size_t & bufsize);
@ -255,6 +269,10 @@ namespace detail
//@biref: The image object should be kept for a long time till the window is closed,
// the image object is release in remove() method.
const nana::paint::graphics& keep_window_icon(native_window_type, const nana::paint::image&);
bool register_dragdrop(native_window_type, x11_dragdrop_interface*);
std::size_t dragdrop_target(native_window_type, bool insert, std::size_t count);
x11_dragdrop_interface* remove_dragdrop(native_window_type);
private:
static int _m_msg_filter(XEvent&, msg_packet_tag&);
void _m_caret_routine();
@ -311,6 +329,9 @@ namespace detail
int timestamp;
Window wd_src;
nana::point pos;
std::map<native_window_type, x11_dragdrop_interface*> dragdrop;
std::map<native_window_type, std::size_t> targets;
}xdnd_;
msg_dispatcher * msg_dispatcher_;

View File

@ -0,0 +1,326 @@
#include <nana/c++defines.hpp>
#if defined(NANA_POSIX) && defined(NANA_X11)
#include "theme.hpp"
#include <nana/filesystem/filesystem.hpp>
#include <algorithm>
#include <vector>
namespace nana
{
namespace detail
{
static int gschema_override_priority(const std::string& filename)
{
if(filename.size() < 3)
return -1;
auto str = filename.substr(0, 2);
if('0' <= str[0] && str[0] <= '9' && '0' <= str[1] && str[1] <= '9')
return std::stoi(str);
return 0;
}
//Removes the wrap of ' and " character.
std::string remove_decoration(const std::string& primitive_value)
{
auto pos = primitive_value.find_first_of("'\"");
if(pos == primitive_value.npos)
return primitive_value;
auto endpos = primitive_value.find(primitive_value[pos], pos + 1);
if(endpos == primitive_value.npos)
return primitive_value;
return primitive_value.substr(pos + 1, endpos - pos - 1);
}
std::string find_value(std::ifstream& ifs, const std::string& category, const std::string& key)
{
ifs.seekg(0, std::ios::beg);
std::string dec_categ = "[" + category + "]";
bool found_cat = false;
while(ifs.good())
{
std::string text;
std::getline(ifs, text);
if((text.size() > 2) && ('[' == text[0]))
{
if(found_cat)
break;
found_cat = (text == dec_categ);
}
else if(found_cat && (text.find(key + "=") == 0))
{
return remove_decoration(text.substr(key.size() + 1));
}
}
return {};
}
std::vector<std::string> split_value(const std::string& value_string)
{
std::vector<std::string> values;
std::size_t start_pos = 0;
while(start_pos != value_string.npos)
{
auto pos = value_string.find(',', start_pos);
if(value_string.npos == pos)
{
if(start_pos < value_string.size())
values.emplace_back(value_string.substr(start_pos));
break;
}
values.emplace_back(value_string.substr(start_pos, pos - start_pos));
start_pos = value_string.find_first_not_of(',', pos);
}
return values;
}
namespace fs = std::filesystem;
std::string find_gnome_theme_name()
{
try
{
//Searches all the gschema override files
std::vector<std::string> overrides;
for(fs::directory_iterator i{"/usr/share/glib-2.0/schemas"}, end; i != end; ++i)
{
auto filename = i->path().filename().string();
if(filename.size() > 17 && filename.substr(filename.size() - 17) == ".gschema.override")
{
auto priority = gschema_override_priority(filename);
if(priority < 0)
continue;
auto i = std::find_if(overrides.cbegin(), overrides.cend(), [priority](const std::string& ovrd){
return (priority > gschema_override_priority(ovrd));
});
overrides.emplace(i, std::move(filename));
//overrides.insert(i, filename);
}
}
//Searches the org.gnome.desktop.interface in override files.
for(auto & gschema_override : overrides)
{
std::ifstream ifs{"/usr/share/glib-2.0/schemas/" + gschema_override};
auto value = find_value(ifs, "org.gnome.desktop.interface", "icon-theme");
if(!value.empty())
return value;
}
//Return the value from org.gnome.desktop.interface.gschema.xml
fs::path xml = "/usr/share/glib-2.0/schemas/org.gnome.desktop.interface.gschema.xml";
auto bytes = fs::file_size(xml);
if(0 == bytes)
return {};
std::ifstream xml_ifs{"/usr/share/glib-2.0/schemas/org.gnome.desktop.interface.gschema.xml", std::ios::binary};
if(xml_ifs)
{
std::string data;
data.resize(bytes);
xml_ifs.read(&data.front(), bytes);
auto pos = data.find("\"icon-theme\"");
if(pos != data.npos)
{
pos = data.find("<default>", pos + 22);
if(pos != data.npos)
{
pos += 9;
auto endpos = data.find("</default>", pos);
if(endpos != data.npos)
{
return remove_decoration(data.substr(pos, endpos - pos));
}
}
}
}
}
catch(...){}
return {};
}
std::string find_kde_theme_name()
{
auto home = getenv("HOME");
if(home)
{
fs::path kdeglobals{home};
kdeglobals /= ".kde/share/config/kdeglobals";
std::error_code err;
if(fs::exists(kdeglobals, err))
{
std::ifstream ifs{kdeglobals};
return find_value(ifs, "Icons", "Theme");
}
}
return {};
}
std::string find_theme_name()
{
auto name = find_kde_theme_name();
if(name.empty())
return find_gnome_theme_name();
return name;
}
class icon_theme
{
public:
icon_theme(const std::string& name):
theme_name_(name),
ifs_("/usr/share/icons/" + name + "/index.theme")
{
//First of all, read the Inherits and Directories
inherits_ = split_value(find_value(ifs_, "Icon Theme", "Inherits"));
directories_ = split_value(find_value(ifs_, "Icon Theme", "Directories"));
}
std::string find(const std::string& name, std::size_t size_wanted) const
{
namespace fs = std::filesystem;
//candidates
std::vector<std::pair<std::string,int>> first, second, third;
fs::path theme_path = "/usr/share/icons/" + theme_name_;
std::string base_path = "/usr/share/icons/" + theme_name_ + "/";
std::string filename = "/" + name + ".png";
std::error_code err;
for(auto & dir : directories_)
{
if(!fs::exists(theme_path / dir / (name + ".png"), err))
continue;
auto size = find_value(ifs_, dir, "Size");
auto type = find_value(ifs_, dir, "Type");
auto scaled = find_value(ifs_, dir, "Scale");
if(size.empty() || ("Fixed" != type))
continue;
int int_size = std::stoi(size);
if(!scaled.empty())
int_size *= std::stoi(scaled);
auto distance = std::abs(static_cast<int>(size_wanted) - int_size);
if(0 == distance)
{
if(scaled.empty() || scaled == "1")
return base_path + dir + filename;
else
first.emplace_back(dir, 0);
}
else
{
if(scaled.empty() || scaled == "1")
second.emplace_back(dir, distance);
else
third.emplace_back(dir, distance);
}
}
using pair_type = std::pair<std::string,int>;
auto comp = [](const pair_type& a, const pair_type& b){
return a.second < b.second;
};
std::sort(first.begin(), first.end(), comp);
std::sort(second.begin(), second.end(), comp);
std::sort(third.begin(), third.end(), comp);
std::string closer_dir;
if(!first.empty())
closer_dir = first.front().first;
else if(!second.empty())
closer_dir = second.front().first;
else if(!third.empty())
closer_dir = third.front().first;
if(closer_dir.empty())
{
for(auto & inh : inherits_)
{
auto dir = icon_theme{inh}.find(name, size_wanted);
if(!dir.empty())
return dir;
}
//Avoid recursively traverse directory for hicolor if current theme name is hicolor
if("hicolor" == theme_name_)
return {};
return icon_theme{"hicolor"}.find(name, size_wanted);
}
return base_path + closer_dir + filename;
}
private:
const std::string theme_name_;
mutable std::ifstream ifs_;
std::vector<std::string> inherits_;
std::vector<std::string> directories_;
};
theme::theme():
path_("/usr/share/icons/"),
ifs_("/usr/share/icons/default/index.theme")
{
}
std::string theme::cursor(const std::string& name) const
{
auto theme = find_value(ifs_, "Icon Theme", "Inherits");
return path_ + theme + "/cursors/" + name;
}
std::string theme::icon(const std::string& name, std::size_t size_wanted) const
{
//Lookup in cache
auto i = iconcache_.find(name);
if(i != iconcache_.end())
{
for(auto & p : i->second)
{
if(p.first == size_wanted)
return p.second;
}
}
//Cache is missed.
auto file = icon_theme{find_theme_name()}.find(name, size_wanted);
if(!file.empty())
iconcache_[name].emplace_back(size_wanted, file);
return file;
}
}
}
#endif

View File

@ -0,0 +1,31 @@
#ifndef NANA_DETAIL_THEME_INCLUDED
#define NANA_DETAIL_THEME_INCLUDED
#include <string>
#include <map>
#include <vector>
#include <fstream>
namespace nana
{
namespace detail
{
class theme
{
public:
theme();
std::string cursor(const std::string& name) const;
std::string icon(const std::string& name, std::size_t size_wanted) const;
private:
std::string path_;
mutable std::ifstream ifs_;
mutable std::map<std::string, std::vector<std::pair<std::size_t, std::string>>> iconcache_;
};
}//end namespace detail
}//end namespace nana
#endif

View File

@ -0,0 +1,303 @@
/*
* X-Window XDND Protocol Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2018-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/detail/posix/xdnd_protocol.hpp
*
* The XDS is not supported.
*/
#ifndef NANA_DETAIL_POSIX_XDND_PROTOCOL_INCLUDED
#define NANA_DETAIL_POSIX_XDND_PROTOCOL_INCLUDED
#include "platform_spec.hpp"
#include <nana/filesystem/filesystem.hpp>
#include "theme.hpp"
#include <X11/Xcursor/Xcursor.h>
#include <vector>
namespace nana{
namespace detail
{
struct xdnd_data
{
Atom requested_action;
std::vector<std::filesystem::path> files;
};
class xdnd_protocol
{
public:
enum class xdnd_status_state
{
normal,
position,
drop, //Use the 'accept' flag of XdndStatus when mouse has released(XdndDrop has been sent).
status_ignore
};
xdnd_protocol(Window source):
spec_(nana::detail::platform_spec::instance()),
source_(source)
{
auto disp = spec_.open_display();
detail::platform_scope_guard lock;
::XSetSelectionOwner(disp, spec_.atombase().xdnd_selection, source, CurrentTime);
cursor_.dnd_copy = ::XcursorLibraryLoadCursor(disp, "dnd-copy");
cursor_.dnd_move = ::XcursorLibraryLoadCursor(disp, "dnd-move");
cursor_.dnd_none = ::XcursorLibraryLoadCursor(disp, "dnd-none");
}
~xdnd_protocol()
{
auto disp = spec_.open_display();
::XFreeCursor(disp, cursor_.dnd_copy);
::XFreeCursor(disp, cursor_.dnd_move);
::XFreeCursor(disp, cursor_.dnd_none);
}
void mouse_move(Window wd, const nana::point& pos, Atom requested_action)
{
if(wd != target_)
{
_m_xdnd_leave();
if(_m_xdnd_enter(wd))
_m_xdnd_position(pos, requested_action);
}
else
_m_xdnd_position(pos, requested_action);
}
void mouse_leave()
{
_m_xdnd_leave();
}
bool mouse_release()
{
return _m_xdnd_drop();
}
Atom executed_action() const
{
return executed_action_;
}
//Return true to exit xdnd_protocol event handler
bool client_message(const ::XClientMessageEvent& xclient)
{
auto & atombase = spec_.atombase();
if(atombase.xdnd_status == xclient.message_type)
{
if(xdnd_status_state::position != xstate_ && xdnd_status_state::drop != xstate_)
return false;
Window target_wd = static_cast<Window>(xclient.data.l[0]);
bool is_accepted_by_target = (xclient.data.l[1] & 1);
if(xclient.data.l[1] & 0x2)
{
rectangle rct{
static_cast<int>(xclient.data.l[2] >> 16),
static_cast<int>(xclient.data.l[2] & 0xFFFF),
static_cast<unsigned>(xclient.data.l[3] >> 16),
static_cast<unsigned>(xclient.data.l[3] & 0xFFFF)
};
if(!rct.empty())
mvout_table_[target_wd] = rct;
}
_m_cursor(is_accepted_by_target);
if((!is_accepted_by_target) && (xdnd_status_state::drop == xstate_))
{
_m_xdnd_leave();
return true;
}
executed_action_ = xclient.data.l[4];
xstate_ = xdnd_status_state::normal;
}
else if(atombase.xdnd_finished == xclient.message_type)
return true;
return false;
}
void selection_request(const ::XSelectionRequestEvent& xselectionrequest, const xdnd_data& data)
{
if(spec_.atombase().xdnd_selection == xselectionrequest.selection)
{
::XEvent evt;
evt.xselection.type = SelectionNotify;
evt.xselection.display = xselectionrequest.display;
evt.xselection.requestor = xselectionrequest.requestor;
evt.xselection.selection = xselectionrequest.selection;
evt.xselection.target = 0;
evt.xselection.property = 0;
evt.xselection.time = xselectionrequest.time;
if(xselectionrequest.target == spec_.atombase().text_uri_list)
{
if(data.files.size())
{
std::string uri_list;
for(auto& file : data.files)
{
uri_list += "file://";
uri_list += file.u8string();
uri_list += "\r\n";
}
::XChangeProperty (spec_.open_display(),
xselectionrequest.requestor,
xselectionrequest.property,
xselectionrequest.target,
8, PropModeReplace,
reinterpret_cast<unsigned char*>(&uri_list.front()), uri_list.size() + 1);
evt.xselection.property = xselectionrequest.property;
evt.xselection.target = xselectionrequest.target;
}
}
platform_scope_guard lock;
::XSendEvent(spec_.open_display(), xselectionrequest.requestor, False, 0, &evt);
::XFlush(spec_.open_display());
if(0 == evt.xselection.target)
_m_xdnd_leave();
}
}
private:
bool _m_xdnd_enter(Window wd)
{
//xdnd version of the window
auto xdnd_ver = _m_xdnd_aware(wd);
if(0 == xdnd_ver)
return false;
target_ = wd;
_m_client_msg(spec_.atombase().xdnd_enter, (xdnd_ver << 24), spec_.atombase().text_uri_list, XA_STRING);
return true;
}
void _m_xdnd_position(const nana::point& pos, Atom requested_action)
{
if(xdnd_status_state::normal != xstate_)
return;
auto i = mvout_table_.find(target_);
if(i != mvout_table_.end() && i->second.is_hit(pos))
return;
xstate_ = xdnd_status_state::position;
//Send XdndPosition
long position = (pos.x << 16 | pos.y);
_m_client_msg(spec_.atombase().xdnd_position, 0, position, CurrentTime, requested_action);
}
void _m_xdnd_leave()
{
::XUndefineCursor(spec_.open_display(), source_);
if(target_)
{
_m_client_msg(spec_.atombase().xdnd_leave, 0, 0, 0);
target_ = 0;
executed_action_ = 0;
}
}
bool _m_xdnd_drop()
{
::XUndefineCursor(spec_.open_display(), source_);
xstate_ = xdnd_status_state::drop;
if(executed_action_)
_m_client_msg(spec_.atombase().xdnd_drop, 0, CurrentTime, 0);
target_ = 0;
return (executed_action_ != 0);
}
private:
//dndversion<<24, fl_XdndURIList, XA_STRING, 0
void _m_client_msg(Atom xdnd_atom, long data1, long data2, long data3, long data4 = 0)
{
auto const display = spec_.open_display();
XEvent evt;
::memset(&evt, 0, sizeof evt);
evt.xany.type = ClientMessage;
evt.xany.display = display;
evt.xclient.window = target_;
evt.xclient.message_type = xdnd_atom;
evt.xclient.format = 32;
//Target window
evt.xclient.data.l[0] = source_;
evt.xclient.data.l[1] = data1;
evt.xclient.data.l[2] = data2;
evt.xclient.data.l[3] = data3;
evt.xclient.data.l[4] = data4;
::XSendEvent(display, target_, True, NoEventMask, &evt);
}
// Returns the XDND version of specified window
//@return the XDND version. If the specified window does not have property XdndAware, it returns 0
int _m_xdnd_aware(Window wd)
{
Atom actual; int format; unsigned long count, remaining;
unsigned char *data = 0;
::XGetWindowProperty(spec_.open_display(), wd, spec_.atombase().xdnd_aware,
0, 4, False, XA_ATOM, &actual, &format, &count, &remaining, &data);
int version = 0;
if (data)
{
if ((actual == XA_ATOM) && (format==32) && count)
version = int(*(Atom*)data);
::XFree(data);
}
return version;
}
void _m_cursor(bool accepted)
{
::XDefineCursor(spec_.open_display(), source_, (accepted ? cursor_.dnd_move : cursor_.dnd_none));
}
private:
nana::detail::platform_spec& spec_;
Window const source_;
Window target_{ 0 };
Atom executed_action_{ 0 };
xdnd_status_state xstate_{xdnd_status_state::normal};
std::map<Window, nana::rectangle> mvout_table_;
struct cursor_rep
{
Cursor dnd_copy{ 0 };
Cursor dnd_move{ 0 };
Cursor dnd_none{ 0 };
}cursor_;
}; //end class xdnd_protocol
}
}
#endif

View File

@ -1,6 +1,6 @@
/*
* A ISO C++ FileSystem Implementation
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -45,7 +45,7 @@
#include <stdlib.h>
#endif
namespace fs = std::experimental::filesystem;
namespace fs = std::filesystem;
namespace nana
{
@ -102,6 +102,22 @@ namespace nana
std::string pretty_file_date(const fs::path& path) // todo: move to .cpp
{
struct tm t;
if (modified_file_time(path, t))
{
std::stringstream tm;
tm << std::put_time(&t, "%Y-%m-%d, %H:%M:%S");
return tm.str();
}
return {};
/*
// Deprecated
//Windows stores file times using the FILETIME structure, which is a 64 bit value of 100ns intervals from January 1, 1601.
//What's worse is that this 1601 date is fairly common to see given that it's the all zeroes value, and it is far before the
//earliest date representable with time_t.std::filesystem can't change the reality of the underlying platform.
try {
#if NANA_USING_BOOST_FILESYSTEM
// The return type of boost::filesystem::last_write_time isn't
@ -117,11 +133,8 @@ namespace nana
if (ftime == ((fs::file_time_type::min)())) return{};
//std::time_t cftime = decltype(ftime)::clock::to_time_t(ftime);
//A workaround for VC2013
using time_point = decltype(ftime);
auto cftime = time_point::clock::to_time_t(ftime);
std::stringstream tm;
@ -131,6 +144,8 @@ namespace nana
catch (...) {
return{};
}
#endif
*/
}
bool modified_file_time(const fs::path& p, struct tm& t)
@ -209,9 +224,9 @@ namespace nana { namespace experimental { namespace filesystem
//Because of No wide character version of POSIX
#if defined(NANA_POSIX)
const char* splstr = "/";
const char* separators = "/";
#else
const wchar_t* splstr = L"/\\";
const wchar_t* separators = L"/\\";
#endif
//class file_status
@ -249,14 +264,23 @@ namespace nana { namespace experimental { namespace filesystem
/// true if the path is empty, false otherwise. ??
bool path::empty() const noexcept
{
#if defined(NANA_WINDOWS)
return (::GetFileAttributes(pathstr_.c_str()) == INVALID_FILE_ATTRIBUTES);
#elif defined(NANA_POSIX)
struct stat sta;
return (::stat(pathstr_.c_str(), &sta) == -1);
return pathstr_.empty();
}
bool path::is_absolute() const
{
#ifdef NANA_WINDOWS
return has_root_name() && has_root_directory();
#else
return has_root_directory();
#endif
}
bool path::is_relative() const
{
return !is_absolute();
}
path path::extension() const
{
// todo: make more globlal
@ -277,6 +301,107 @@ namespace nana { namespace experimental { namespace filesystem
return path(pathstr_.substr(pos));
}
bool is_directory_separator(path::value_type ch)
{
return (ch == '/')
#ifdef NANA_WINDOWS
|| (ch == path::preferred_separator)
#endif
;
}
path path::root_name() const
{
auto pos = pathstr_.find_first_not_of(separators);
if (pathstr_.npos != pos)
{
pos = pathstr_.find_first_of(separators, pos + 1);
if (pathstr_.npos != pos)
{
if ((is_directory_separator(pathstr_[0]) && is_directory_separator(pathstr_[1]))
#ifdef NANA_WINDOWS
|| (pathstr_[pos - 1] == ':')
#endif
)
return pathstr_.substr(0, pos);
}
}
return path{};
}
std::size_t root_directory_pos(const path::string_type& str)
{
#ifdef NANA_WINDOWS
// case "c:/"
if (str.size() > 2
&& str[1] == ':'
&& is_directory_separator(str[2])) return 2;
#endif
// case "//"
if (str.size() == 2
&& is_directory_separator(str[0])
&& is_directory_separator(str[1])) return path::string_type::npos;
#ifdef NANA_WINDOWS
// case "\\?\"
if (str.size() > 4
&& is_directory_separator(str[0])
&& is_directory_separator(str[1])
&& str[2] == '?'
&& is_directory_separator(str[3]))
{
auto pos = str.find_first_of(separators, 4);
return pos < str.size() ? pos : str.npos;
}
#endif
// case "//net {/}"
if (str.size() > 3
&& is_directory_separator(str[0])
&& is_directory_separator(str[1])
&& !is_directory_separator(str[2]))
{
auto pos = str.find_first_of(separators, 2);
return pos < str.size() ? pos : str.npos;
}
// case "/"
if (str.size() > 0 && is_directory_separator(str[0])) return 0;
return str.npos;
}
path path::root_directory() const
{
auto pos = root_directory_pos(pathstr_);
return pos == string_type::npos
? path()
: path(pathstr_.substr(pos, 1));
}
path path::root_path() const
{
return root_name().pathstr_ + root_directory().pathstr_;
}
path path::relative_path() const
{
if (!empty())
{
auto pos = root_directory_pos(pathstr_);
pos = pathstr_.find_first_not_of(separators, pos);
if (pathstr_.npos != pos)
return path{ pathstr_.substr(pos) };
}
return{};
}
path path::parent_path() const
{
return{nana_fs::parent_path(pathstr_)};
@ -310,14 +435,14 @@ namespace nana { namespace experimental { namespace filesystem
path path::filename() const
{
auto pos = pathstr_.find_last_of(splstr);
auto pos = pathstr_.find_last_of(separators);
if (pos != pathstr_.npos)
{
if (pos + 1 == pathstr_.size())
{
value_type tmp[2] = {preferred_separator, 0};
if (pathstr_.npos != pathstr_.find_last_not_of(splstr, pos))
if (pathstr_.npos != pathstr_.find_last_not_of(separators, pos))
tmp[0] = '.';
return{ tmp };
@ -328,6 +453,21 @@ namespace nana { namespace experimental { namespace filesystem
return{ pathstr_ };
}
void path::clear() noexcept
{
pathstr_.clear();
}
path& path::make_preferred()
{
#ifdef NANA_WINDOWS
std::replace(pathstr_.begin(), pathstr_.end(), L'/', L'\\');
#else
std::replace(pathstr_.begin(), pathstr_.end(), '\\', '/');
#endif
return *this;
}
path& path::remove_filename()
{
#ifdef NANA_WINDOWS
@ -418,10 +558,10 @@ namespace nana { namespace experimental { namespace filesystem
if (this == &p)
{
auto other = p.pathstr_;
if ((other.front() != '/') && (other.front() == path::preferred_separator))
if (!is_directory_separator(other.front()))
{
if (!this->pathstr_.empty() && (pathstr_.back() != '/' && pathstr_.back() == path::preferred_separator))
pathstr_.append(path::preferred_separator, 1);
if (!pathstr_.empty() && !is_directory_separator(pathstr_.back()))
pathstr_.append(1, path::preferred_separator);
}
pathstr_ += other;
@ -429,10 +569,10 @@ namespace nana { namespace experimental { namespace filesystem
else
{
auto & other = p.pathstr_;
if ((other.front() != '/') && (other.front() == path::preferred_separator))
if (!is_directory_separator(other.front()))
{
if (!this->pathstr_.empty() && (pathstr_.back() != '/' && pathstr_.back() == path::preferred_separator))
pathstr_.append(path::preferred_separator, 1);
if (!pathstr_.empty() && !is_directory_separator(pathstr_.back()))
pathstr_.append(1, path::preferred_separator);
}
pathstr_ += p.pathstr_;
@ -534,6 +674,12 @@ namespace nana { namespace experimental { namespace filesystem
_m_prepare(file_path);
}
directory_iterator::directory_iterator(const path& p, directory_options opt):
option_(opt)
{
_m_prepare(p);
}
const directory_iterator::value_type& directory_iterator::operator*() const { return value_; }
const directory_iterator::value_type*
@ -790,7 +936,7 @@ namespace nana { namespace experimental { namespace filesystem
auto stat = status(p, err);
if (err != std::error_code())
throw filesystem_error("nana::experimental::filesystem::status", p, err);
throw filesystem_error("nana::filesystem::status", p, err);
return stat;
}
@ -849,8 +995,23 @@ namespace nana { namespace experimental { namespace filesystem
return (status(p).type() == file_type::directory);
}
bool is_directory(const path& p, std::error_code& ec) noexcept
{
return (status(p, ec).type() == file_type::directory);
}
std::uintmax_t file_size(const path& p)
{
std::error_code err;
auto bytes = file_size(p, err);
if (err)
throw filesystem_error("nana::filesystem::status", p, err);
return bytes;
}
std::uintmax_t file_size(const path& p, std::error_code& ec) noexcept
{
#if defined(NANA_WINDOWS)
//Some compilation environment may fail to link to GetFileSizeEx
typedef BOOL(__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER);
@ -868,23 +1029,25 @@ namespace nana { namespace experimental { namespace filesystem
return li.QuadPart;
}
}
return 0;
ec.assign(static_cast<int>(::GetLastError()), std::generic_category());
#elif defined(NANA_POSIX)
FILE * stream = ::fopen(p.c_str(), "rb");
long long size = 0;
if (stream)
{
long long bytes = 0;
# if defined(NANA_LINUX)
fseeko64(stream, 0, SEEK_END);
size = ftello64(stream);
bytes = ftello64(stream);
# elif defined(NANA_POSIX)
fseeko(stream, 0, SEEK_END);
size = ftello(stream);
bytes = ftello(stream);
# endif
::fclose(stream);
return bytes;
}
return size;
ec.assign(static_cast<int>(::errno), std::generic_category());
#endif
return static_cast<std::uintmax_t>(-1);
}
@ -976,5 +1139,141 @@ namespace nana { namespace experimental { namespace filesystem
}//end namespace filesystem
} //end namespace experimental
}//end namespace nana
namespace std
{
namespace filesystem
{
#if defined(NANA_FILESYSTEM_FORCE) || \
(defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)))
path absolute(const path& p)
{
if (p.empty())
return p;
auto abs_base = current_path();
// store expensive to compute values that are needed multiple times
path p_root_name(p.root_name());
path base_root_name(abs_base.root_name());
path p_root_directory(p.root_directory());
if (!p_root_name.empty()) // p.has_root_name()
{
if (p_root_directory.empty()) // !p.has_root_directory()
return p_root_name / abs_base.root_directory()
/ abs_base.relative_path() / p.relative_path();
// p is absolute, so fall through to return p at end of block
}
else if (!p_root_directory.empty()) // p.has_root_directory()
{
#ifdef NANA_POSIX
// POSIX can have root name it it is a network path
if (base_root_name.empty()) // !abs_base.has_root_name()
return p;
#endif
return base_root_name / p;
}
else
return abs_base / p;
return p; // p.is_absolute() is true
}
path absolute(const path& p, std::error_code& err)
{
return absolute(p);
}
path canonical(const path& p, std::error_code* err)
{
path source(p.is_absolute() ? p : absolute(p));
path root(source.root_path());
path result;
std::error_code local_ec;
file_status stat(status(source, local_ec));
if (stat.type() == file_type::not_found)
{
if (nullptr == err)
throw (filesystem_error(
"nana::filesystem::canonical", source,
error_code(static_cast<int>(errc::no_such_file_or_directory), generic_category())));
err->assign(static_cast<int>(errc::no_such_file_or_directory), generic_category());
return result;
}
else if (local_ec)
{
if (nullptr == err)
throw (filesystem_error(
"nana::filesystem::canonical", source, local_ec));
*err = local_ec;
return result;
}
auto tmp_p = source;
std::vector<path> source_elements;
while (tmp_p != root)
{
source_elements.emplace(source_elements.begin(), tmp_p.filename());
tmp_p.remove_filename();
}
result = root;
for(auto & e : source_elements)
{
auto str = e.string();
if("." == str)
continue;
else if(".." == str)
{
if(result != root)
result.remove_filename();
continue;
}
result /= e;
}
if (err)
err->clear();
return result;
}
path canonical(const path& p)
{
return canonical(p, nullptr);
}
path canonical(const path& p, std::error_code& err)
{
return canonical(p, &err);
}
#endif
#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW)
bool exists( std::filesystem::file_status s ) noexcept
{
return s.type() != file_type::not_found;
}
bool exists( const std::filesystem::path& p )
{
return exists(status(p));
}
bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept
{
return exists(status(p, ec));
}
#endif
}//end namespace filesystem
}//end namespace std
#endif

View File

@ -1,7 +1,7 @@
/*
* An Animation Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -571,6 +571,25 @@ namespace nana
delete impl_;
}
animation::animation(animation&& rhs)
: impl_(rhs.impl_)
{
rhs.impl_ = new impl(23);
}
animation& animation::operator=(animation&& rhs)
{
if (this != &rhs)
{
auto imp = new impl{ 23 };
delete impl_;
impl_ = rhs.impl_;
rhs.impl_ = imp;
}
return *this;
}
void animation::push_back(frameset frms)
{
impl_->framesets.emplace_back(std::move(frms));

View File

@ -1,7 +1,7 @@
/*
* A Basic Window Widget Definition
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -216,40 +216,14 @@ namespace nana
basic_window::other_tag::other_tag(category::flags categ)
: category(categ), active_window(nullptr), upd_state(update_state::none)
{
#ifndef WIDGET_FRAME_DEPRECATED
switch(categ)
{
case category::flags::root:
attribute.root = new attr_root_tag;
break;
case category::flags::frame:
attribute.frame = new attr_frame_tag;
break;
default:
attribute.root = nullptr;
}
#else
if (category::flags::root == categ)
attribute.root = new attr_root_tag;
else
attribute.root = nullptr;
#endif
}
basic_window::other_tag::~other_tag()
{
#ifndef WIDGET_FRAME_DEPRECATED
switch(category)
{
case category::flags::root:
delete attribute.root;
break;
case category::flags::frame:
delete attribute.frame;
break;
default: break;
}
#endif
if (category::flags::root == category)
delete attribute.root;
}
@ -290,14 +264,6 @@ namespace nana
}
}
#ifndef WIDGET_FRAME_DEPRECATED
void basic_window::frame_window(native_window_type wd)
{
if(category::flags::frame == this->other.category)
other.attribute.frame->container = wd;
}
#endif
bool basic_window::is_ancestor_of(const basic_window* wd) const
{
while (wd)
@ -410,6 +376,7 @@ namespace nana
flags.enabled = true;
flags.modal = false;
flags.take_active = true;
flags.draggable = false;
flags.dropable = false;
flags.fullscreen = false;
flags.tab = nana::detail::tab_type::none;
@ -423,6 +390,7 @@ namespace nana
flags.ignore_menubar_focus = false;
flags.ignore_mouse_focus = false;
flags.space_click_enabled = false;
flags.ignore_child_mapping = false;
visible = false;

View File

@ -1,7 +1,7 @@
/*
* A Bedrock Platform-Independent Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -11,7 +11,7 @@
*/
#include "../../detail/platform_spec_selector.hpp"
#include <nana/gui/detail/bedrock_pi_data.hpp>
#include "bedrock_types.hpp"
#include <nana/gui/detail/event_code.hpp>
#include <nana/system/platform.hpp>
#include <sstream>
@ -94,6 +94,12 @@ namespace nana
};
bedrock::core_window_t* bedrock::focus()
{
auto wd = wd_manager().root(native_interface::get_focus_window());
return (wd ? wd->other.attribute.root->focus : nullptr);
}
events_operation& bedrock::evt_operation()
{
return pi_data_->evt_operation;
@ -164,18 +170,11 @@ namespace nana
caret_wd->annex.caret_ptr->visible(false);
}
if (!exposed)
{
if (category::flags::root != wd->other.category)
if ((!exposed) && (category::flags::root != wd->other.category))
{
//find an ancestor until it is not a lite_widget
wd = wd->seek_non_lite_widget_ancestor();
}
#ifndef WIDGET_FRAME_DEPRECATED
else if (category::flags::frame == wd->other.category)
wd = wd_manager().find_window(wd->root, wd->pos_root.x, wd->pos_root.y);
#endif
}
wd_manager().refresh_tree(wd);
wd_manager().map(wd, false);
@ -609,5 +608,93 @@ namespace nana
throw std::runtime_error("Invalid event code");
}
}
void bedrock::thread_context_destroy(core_window_t * wd)
{
auto ctx = get_thread_context(0);
if(ctx && ctx->event_window == wd)
ctx->event_window = nullptr;
}
void bedrock::thread_context_lazy_refresh()
{
auto ctx = get_thread_context(0);
if(ctx && ctx->event_window)
ctx->event_window->other.upd_state = core_window_t::update_state::refreshed;
}
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal)
{
if(wd_manager().available(wd) == false)
return false;
core_window_t * prev_wd = nullptr;
if(thrd)
{
prev_wd = thrd->event_window;
thrd->event_window = wd;
_m_event_filter(evt_code, wd, thrd);
}
using update_state = basic_window::update_state;
if (update_state::none == wd->other.upd_state)
wd->other.upd_state = update_state::lazy;
auto ignore_mapping_value = wd->flags.ignore_child_mapping;
wd->flags.ignore_child_mapping = true;
_m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal);
wd->flags.ignore_child_mapping = ignore_mapping_value;
bool good_wd = false;
if(wd_manager().available(wd))
{
//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_manager().map_requester(wd);
wd->other.upd_state = update_state::none;
}
good_wd = true;
}
if(thrd) thrd->event_window = prev_wd;
return good_wd;
}
void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd)
{
auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow);
switch(event_id)
{
case event_code::mouse_enter:
if (not_state_cur)
set_cursor(wd, wd->predef_cursor, thrd);
break;
case event_code::mouse_leave:
if (not_state_cur && (wd->predef_cursor != cursor::arrow))
set_cursor(wd, nana::cursor::arrow, thrd);
break;
case event_code::destroy:
if (wd->root_widget->other.attribute.root->state_cursor_window == wd)
undefine_state_cursor(wd, thrd);
if(wd == thrd->cursor.window)
set_cursor(wd, cursor::arrow, thrd);
break;
default:
break;
}
}
}//end namespace detail
}//end namespace nana

View File

@ -1,7 +1,7 @@
/*
* A Bedrock Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -12,7 +12,6 @@
#include "../../detail/platform_spec_selector.hpp"
#if defined(NANA_POSIX) && defined(NANA_X11)
#include <nana/gui/detail/bedrock_pi_data.hpp>
#include <nana/gui/detail/event_code.hpp>
#include <nana/system/platform.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
@ -22,6 +21,8 @@
#include <errno.h>
#include <algorithm>
#include "bedrock_types.hpp"
namespace nana
{
namespace detail
@ -52,38 +53,6 @@ namespace detail
};
#pragma pack()
struct bedrock::thread_context
{
unsigned event_pump_ref_count{0};
int window_count{0}; //The number of windows
core_window_t* event_window{nullptr};
bool is_alt_pressed{false};
bool is_ctrl_pressed{false};
struct platform_detail_tag
{
native_window_type motion_window;
nana::point motion_pointer_pos;
}platform;
struct cursor_tag
{
core_window_t * window;
native_window_type native_handle;
nana::cursor predef_cursor;
Cursor handle;
}cursor;
thread_context()
{
cursor.window = nullptr;
cursor.native_handle = nullptr;
cursor.predef_cursor = nana::cursor::arrow;
cursor.handle = 0;
}
};
struct bedrock::private_impl
{
typedef std::map<unsigned, thread_context> thr_context_container;
@ -247,12 +216,6 @@ namespace detail
return bedrock_object;
}
bedrock::core_window_t* bedrock::focus()
{
core_window_t* wd = wd_manager().root(native_interface::get_focus_window());
return (wd ? wd->other.attribute.root->focus : 0);
}
void bedrock::get_key_state(arg_keyboard& arg)
{
XKeyEvent xkey;
@ -289,46 +252,6 @@ namespace detail
//No implementation for Linux
}
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal)
{
if(wd_manager().available(wd) == false)
return false;
core_window_t * prev_wd = nullptr;
if(thrd)
{
prev_wd = thrd->event_window;
thrd->event_window = wd;
_m_event_filter(evt_code, wd, thrd);
}
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);
bool good_wd = false;
if(wd_manager().available(wd))
{
//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;
}
if(thrd) thrd->event_window = prev_wd;
return good_wd;
}
void assign_arg(arg_mouse& arg, basic_window* wd, unsigned msg, const XEvent& evt)
{
arg.window_handle = reinterpret_cast<window>(wd);
@ -418,10 +341,10 @@ namespace detail
{
switch(msg.kind)
{
case nana::detail::msg_packet_tag::kind_xevent:
case nana::detail::msg_packet_tag::pkt_family::xevent:
window_proc_for_xevent(display, msg.u.xevent);
break;
case nana::detail::msg_packet_tag::kind_mouse_drop:
case nana::detail::msg_packet_tag::pkt_family::mouse_drop:
window_proc_for_packet(display, msg);
break;
default: break;
@ -441,8 +364,9 @@ namespace detail
switch(msg.kind)
{
case nana::detail::msg_packet_tag::kind_mouse_drop:
case nana::detail::msg_packet_tag::pkt_family::mouse_drop:
msgwd = brock.wd_manager().find_window(native_window, {msg.u.mouse_drop.x, msg.u.mouse_drop.y});
if(msgwd)
{
arg_dropfiles arg;
@ -973,7 +897,12 @@ namespace detail
case Expose:
if(msgwnd->visible && (msgwnd->root_graph->empty() == false))
{
nana::detail::platform_scope_guard lock;
nana::internal_scope_guard lock;
//Don't lock this scope using platform-scope-guard. Because it would cause the platform-scope-lock to be locked
//before the internal-scope-guard, and the order of locking would cause dead-lock.
//
//Locks this scope using internal-scope-guard is correct and safe. In the scope, the Xlib functions aren't called
//directly.
if(msgwnd->is_draw_through())
{
msgwnd->other.attribute.root->draw_through();
@ -1243,10 +1172,12 @@ namespace detail
default:
if(message == ClientMessage)
{
auto & atoms = nana::detail::platform_spec::instance().atombase();
if(atoms.wm_protocols == xevent.xclient.message_type)
auto & spec = ::nana::detail::platform_spec::instance();
auto & xclient = xevent.xclient;
auto & atoms = spec.atombase();
if(atoms.wm_protocols == xclient.message_type)
{
if(msgwnd->flags.enabled && (atoms.wm_delete_window == static_cast<Atom>(xevent.xclient.data.l[0])))
if(msgwnd->flags.enabled && (atoms.wm_delete_window == static_cast<Atom>(xclient.data.l[0])))
{
arg_unload arg;
arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1338,20 +1269,6 @@ namespace detail
}//end bedrock::event_loop
void bedrock::thread_context_destroy(core_window_t * wd)
{
bedrock::thread_context * thr = get_thread_context(0);
if(thr && thr->event_window == wd)
thr->event_window = nullptr;
}
void bedrock::thread_context_lazy_refresh()
{
thread_context* thrd = get_thread_context(0);
if(thrd && thrd->event_window)
thrd->event_window->other.upd_state = core_window_t::update_state::refreshed;
}
//Dynamically set a cursor for a window
void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd)
{
@ -1421,32 +1338,6 @@ namespace detail
if (rev_wd)
set_cursor(rev_wd, rev_wd->predef_cursor, thrd);
}
void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd)
{
auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow);
switch(event_id)
{
case event_code::mouse_enter:
if (not_state_cur)
set_cursor(wd, wd->predef_cursor, thrd);
break;
case event_code::mouse_leave:
if (not_state_cur && (wd->predef_cursor != cursor::arrow))
set_cursor(wd, nana::cursor::arrow, thrd);
break;
case event_code::destroy:
if (wd->root_widget->other.attribute.root->state_cursor_window == wd)
undefine_state_cursor(wd, thrd);
if(wd == thrd->cursor.window)
set_cursor(wd, cursor::arrow, thrd);
break;
default:
break;
}
}
}//end namespace detail
}//end namespace nana
#endif //NANA_POSIX && NANA_X11

View File

@ -0,0 +1,101 @@
#ifndef NANA_GUI_DETAIL_BEDROCK_TYPES_INCLUDED
#define NANA_GUI_DETAIL_BEDROCK_TYPES_INCLUDED
#include <nana/push_ignore_diagnostic>
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/color_schemes.hpp>
#include <nana/gui/detail/events_operation.hpp>
#include <nana/gui/detail/window_manager.hpp>
#include <set>
namespace nana
{
namespace detail
{
struct bedrock::pi_data
{
color_schemes scheme;
events_operation evt_operation;
window_manager wd_manager;
std::set<core_window_t*> auto_form_set;
bool shortkey_occurred{ false };
struct menu_rep
{
core_window_t* taken_window{ nullptr };
bool delay_restore{ false };
native_window_type window{ nullptr };
native_window_type owner{ nullptr };
bool has_keyboard{ false };
}menu;
};
#ifdef NANA_WINDOWS
struct bedrock::thread_context
{
unsigned event_pump_ref_count{0};
int window_count{0}; //The number of windows
core_window_t* event_window{nullptr};
struct platform_detail_tag
{
wchar_t keychar;
}platform;
struct cursor_tag
{
core_window_t * window;
native_window_type native_handle;
nana::cursor predef_cursor;
HCURSOR handle;
}cursor;
thread_context()
{
cursor.window = nullptr;
cursor.native_handle = nullptr;
cursor.predef_cursor = nana::cursor::arrow;
cursor.handle = nullptr;
}
};
#else
struct bedrock::thread_context
{
unsigned event_pump_ref_count{0};
int window_count{0}; //The number of windows
core_window_t* event_window{nullptr};
bool is_alt_pressed{false};
bool is_ctrl_pressed{false};
struct platform_detail_tag
{
native_window_type motion_window;
nana::point motion_pointer_pos;
}platform;
struct cursor_tag
{
core_window_t * window;
native_window_type native_handle;
nana::cursor predef_cursor;
Cursor handle;
}cursor;
thread_context()
{
cursor.window = nullptr;
cursor.native_handle = nullptr;
cursor.predef_cursor = nana::cursor::arrow;
cursor.handle = 0;
}
};
#endif
}
}
#include <nana/pop_ignore_diagnostic>
#endif

View File

@ -1,7 +1,7 @@
/**
* A Bedrock Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -14,8 +14,7 @@
#include "../../detail/platform_spec_selector.hpp"
#if defined(NANA_WINDOWS)
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/bedrock_pi_data.hpp>
#include "bedrock_types.hpp"
#include <nana/gui/detail/event_code.hpp>
#include <nana/system/platform.hpp>
#include <nana/system/timepiece.hpp>
@ -36,6 +35,8 @@
#define WM_MOUSEHWHEEL 0x020E
#endif
#include "bedrock_types.hpp"
typedef void (CALLBACK *win_event_proc_t)(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime);
namespace nana
@ -135,34 +136,6 @@ namespace detail
};
#pragma pack()
struct bedrock::thread_context
{
unsigned event_pump_ref_count{0};
int window_count{0}; //The number of windows
core_window_t* event_window{nullptr};
struct platform_detail_tag
{
wchar_t keychar;
}platform;
struct cursor_tag
{
core_window_t * window;
native_window_type native_handle;
nana::cursor predef_cursor;
HCURSOR handle;
}cursor;
thread_context()
{
cursor.window = nullptr;
cursor.native_handle = nullptr;
cursor.predef_cursor = nana::cursor::arrow;
cursor.handle = nullptr;
}
};
struct bedrock::private_impl
{
typedef std::map<unsigned, thread_context> thr_context_container;
@ -1176,10 +1149,10 @@ namespace detail
std::unique_ptr<wchar_t[]> varbuf;
std::size_t bufsize = 0;
unsigned size = ::DragQueryFile(drop, 0xFFFFFFFF, 0, 0);
unsigned size = ::DragQueryFile(drop, 0xFFFFFFFF, nullptr, 0);
for(unsigned i = 0; i < size; ++i)
{
unsigned reqlen = ::DragQueryFile(drop, i, 0, 0) + 1;
unsigned reqlen = ::DragQueryFile(drop, i, nullptr, 0) + 1;
if(bufsize < reqlen)
{
varbuf.reset(new wchar_t[reqlen]);
@ -1187,8 +1160,7 @@ namespace detail
}
::DragQueryFile(drop, i, varbuf.get(), reqlen);
dropfiles.files.emplace_back(to_utf8(varbuf.get()));
dropfiles.files.emplace_back(varbuf.get());
}
while(msgwnd && (msgwnd->flags.dropable == false))
@ -1594,12 +1566,6 @@ namespace detail
return ::DefWindowProc(root_window, message, wParam, lParam);
}
auto bedrock::focus() ->core_window_t*
{
core_window_t* wd = wd_manager().root(native_interface::get_focus_window());
return (wd ? wd->other.attribute.root->focus : nullptr);
}
void bedrock::get_key_state(arg_keyboard& kb)
{
kb.alt = (0 != (::GetKeyState(VK_MENU) & 0x80));
@ -1677,42 +1643,6 @@ namespace detail
}
}
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal)
{
if (wd_manager().available(wd) == false)
return false;
basic_window* prev_event_wd = nullptr;
if (thrd)
{
prev_event_wd = thrd->event_window;
thrd->event_window = wd;
_m_event_filter(evt_code, wd, thrd);
}
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))
{
//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 = update_state::none;
good_wd = true;
}
if (thrd) thrd->event_window = prev_event_wd;
return good_wd;
}
const wchar_t* translate(cursor id)
{
const wchar_t* name = IDC_ARROW;
@ -1741,20 +1671,6 @@ namespace detail
return name;
}
void bedrock::thread_context_destroy(core_window_t * wd)
{
auto * thr = get_thread_context(0);
if (thr && thr->event_window == wd)
thr->event_window = nullptr;
}
void bedrock::thread_context_lazy_refresh()
{
auto* thrd = get_thread_context(0);
if (thrd && thrd->event_window)
thrd->event_window->other.upd_state = core_window_t::update_state::refreshed;
}
//Dynamically set a cursor for a window
void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd)
{
@ -1847,32 +1763,6 @@ namespace detail
::ShowCursor(FALSE);
::SetCursor(rev_handle);
}
void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd)
{
auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow);
switch(event_id)
{
case event_code::mouse_enter:
if (not_state_cur)
set_cursor(wd, wd->predef_cursor, thrd);
break;
case event_code::mouse_leave:
if (not_state_cur && (wd->predef_cursor != cursor::arrow))
set_cursor(wd, cursor::arrow, thrd);
break;
case event_code::destroy:
if (wd->root_widget->other.attribute.root->state_cursor_window == wd)
undefine_state_cursor(wd, thrd);
if(wd == thrd->cursor.window)
set_cursor(wd, cursor::arrow, thrd);
break;
default:
break;
}
}
}//end namespace detail
}//end namespace nana
#endif //NANA_WINDOWS

View File

@ -1,7 +1,7 @@
/*
* Color Schemes
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -24,6 +24,14 @@ namespace nana
: color_(std::make_shared<color>(clr))
{}
color_proxy::color_proxy(color_argb clr)
: color_(std::make_shared<color>(clr))
{}
color_proxy::color_proxy(color_rgba clr)
: color_(std::make_shared<color>(clr))
{}
color_proxy::color_proxy(colors clr)
: color_(std::make_shared<color>(clr))
{}
@ -47,6 +55,18 @@ namespace nana
return *this;
}
color_proxy& color_proxy::operator = (color_argb clr)
{
color_ = std::make_shared<::nana::color>(clr);
return *this;
}
color_proxy& color_proxy::operator = (color_rgba clr)
{
color_ = std::make_shared<::nana::color>(clr);
return *this;
}
color_proxy& color_proxy::operator = (colors clr)
{
color_ = std::make_shared<::nana::color>(clr);
@ -58,9 +78,16 @@ namespace nana
return *color_;
}
color color_proxy::get(const color& default_color) const
{
if (color_ && !color_->invisible())
return *color_;
return default_color;
}
color_proxy::operator color() const
{
return *color_;
return (color_ ? *color_ : color{});
}
//end class color_proxy

View File

@ -136,11 +136,12 @@ namespace nana
evt_disabled_ &= ~(1 << static_cast<int>(evt_code)); // clear
}
void drawer_trigger::filter_event(const std::vector<event_code> evt_codes, const bool bDisabled)
void drawer_trigger::filter_event(const std::vector<event_code>& evt_codes, const bool bDisabled)
{
const auto it_end = evt_codes.end();
for (auto it = evt_codes.begin(); it != it_end; it++)
filter_event(*it, bDisabled);
for (auto evt_code : evt_codes)
{
filter_event(evt_code, bDisabled);
}
}
void drawer_trigger::filter_event(const event_filter_status& evt_all_states)

View File

@ -34,8 +34,10 @@ namespace nana
//class docker_base
docker_base::docker_base(event_interface* evt, bool unignorable_flag)
: event_ptr(evt), unignorable(unignorable_flag)
docker_base::docker_base(event_interface* evt, bool unignorable_flag):
event_ptr(evt),
flag_deleted(false),
unignorable(unignorable_flag)
{}
detail::event_interface * docker_base::get_event() const

View File

@ -46,7 +46,7 @@ namespace nana{
void umake(window wd);
std::vector<unsigned long> keys(window wd) const;
const std::vector<unsigned long>* keys(window wd) const;
window find(unsigned long key) const;
private:

View File

@ -1,7 +1,7 @@
/*
* Platform Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -29,6 +29,7 @@
#include "../../paint/image_accessor.hpp"
namespace nana{
namespace detail{
@ -371,6 +372,8 @@ namespace nana{
}
Window parent = (owner ? reinterpret_cast<Window>(owner) : restrict::spec.root_window());
//The position passed to XCreateWindow is a screen coordinate.
nana::point pos(r.x, r.y);
if((false == nested) && owner)
{
@ -396,7 +399,9 @@ namespace nana{
{
auto origin_owner = (owner ? owner : reinterpret_cast<native_window_type>(restrict::spec.root_window()));
restrict::spec.make_owner(origin_owner, reinterpret_cast<native_window_type>(handle));
exposed_positions[handle] = pos;
//The exposed_position is a relative position to its owner/parent.
exposed_positions[handle] = r.position();
}
XChangeWindowAttributes(disp, handle, attr_mask, &win_attr);
@ -844,12 +849,17 @@ namespace nana{
#endif
}
void native_interface::refresh_window(native_window_type wd)
void native_interface::refresh_window(native_window_type native_wd)
{
#if defined(NANA_WINDOWS)
::InvalidateRect(reinterpret_cast<HWND>(wd), nullptr, true);
auto wd = reinterpret_cast<HWND>(native_wd);
RECT r;
::GetClientRect(wd, &r);
::InvalidateRect(wd, &r, FALSE);
#elif defined(NANA_X11)
static_cast<void>(wd); //eliminate unused parameter compiler warning.
Display * disp = restrict::spec.open_display();
::XClearArea(disp, reinterpret_cast<Window>(native_wd), 0, 0, 1, 1, true);
::XFlush(disp);
#endif
}
@ -945,13 +955,6 @@ namespace nana{
auto fm_extents = window_frame_extents(wd);
origin.x = -fm_extents.left;
origin.y = -fm_extents.top;
if(reinterpret_cast<Window>(coord_wd) != restrict::spec.root_window())
{
fm_extents = window_frame_extents(coord_wd);
origin.x += fm_extents.left;
origin.y += fm_extents.top;
}
}
else
coord_wd = get_window(wd, window_relationship::parent);
@ -1009,9 +1012,11 @@ namespace nana{
auto const owner = restrict::spec.get_owner(wd);
if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window())))
{
auto origin = window_position(owner);
x += origin.x;
y += origin.y;
int origin_x, origin_y;
Window child_useless_for_API;
::XTranslateCoordinates(disp, reinterpret_cast<Window>(owner), restrict::spec.root_window(), 0, 0, &origin_x, &origin_y, &child_useless_for_API);
x += origin_x;
y += origin_y;
}
::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y);
@ -1058,7 +1063,6 @@ namespace nana{
XSizeHints hints;
nana::detail::platform_scope_guard psg;
//Returns if the requested rectangle is same with the current rectangle.
//In some X-Server versions/implementations, XMapWindow() doesn't generate
//a ConfigureNotify if the requested rectangle is same with the current rectangle.
@ -1098,9 +1102,11 @@ namespace nana{
auto const owner = restrict::spec.get_owner(wd);
if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window())))
{
auto origin = window_position(owner);
x += origin.x;
y += origin.y;
int origin_x, origin_y;
Window child_useless_for_API;
::XTranslateCoordinates(disp, reinterpret_cast<Window>(owner), restrict::spec.root_window(), 0, 0, &origin_x, &origin_y, &child_useless_for_API);
x += origin_x;
y += origin_y;
}
::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height);
@ -1438,6 +1444,8 @@ namespace nana{
{
if(owner)
return owner;
return x11_parent_window(wd);
}
else if(window_relationship::owner == rsp)
return owner;
@ -1580,14 +1588,17 @@ namespace nana{
pos.y = point.y;
return true;
}
return false;
#elif defined(NANA_X11)
nana::detail::platform_scope_guard psg;
int x = pos.x, y = pos.y;
Window child;
return (True == ::XTranslateCoordinates(restrict::spec.open_display(),
reinterpret_cast<Window>(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child));
if(True == ::XTranslateCoordinates(restrict::spec.open_display(),
reinterpret_cast<Window>(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child))
{
return true;
}
#endif
return false;
}
bool native_interface::calc_window_point(native_window_type wd, nana::point& pos)
@ -1600,14 +1611,16 @@ namespace nana{
pos.y = point.y;
return true;
}
return false;
#elif defined(NANA_X11)
nana::detail::platform_scope_guard psg;
int x = pos.x, y = pos.y;
Window child;
return (True == ::XTranslateCoordinates(restrict::spec.open_display(),
restrict::spec.root_window(), reinterpret_cast<Window>(wd), x, y, &pos.x, &pos.y, &child));
if(True == ::XTranslateCoordinates(restrict::spec.open_display(), restrict::spec.root_window(), reinterpret_cast<Window>(wd), x, y, &pos.x, &pos.y, &child))
{
return true;
}
#endif
return false;
}
native_window_type native_interface::find_window(int x, int y)

View File

@ -1,7 +1,7 @@
/*
* Window Layout Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -66,20 +66,9 @@ namespace nana
nana::point p_src;
for (auto & el : blocks)
{
#ifndef WIDGET_FRAME_DEPRECATED
if (category::flags::frame == el.window->other.category)
{
native_window_type container = el.window->other.attribute.frame->container;
native_interface::refresh_window(container);
graph.bitblt(el.r, container);
}
else
#endif
{
p_src.x = el.r.x - el.window->pos_root.x;
p_src.y = el.r.y - el.window->pos_root.y;
graph.bitblt(el.r, (el.window->drawer.graphics), p_src);
}
_m_paste_children(el.window, false, req_refresh_children, el.r, graph, nana::point{});
}

View File

@ -1,7 +1,7 @@
/*
* Window Manager Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -111,17 +111,17 @@ namespace nana
}
}
std::vector<unsigned long> shortkey_container::keys(window wd) const
const std::vector<unsigned long>* shortkey_container::keys(window wd) const
{
if (wd)
{
for (auto & m : impl_->base)
{
if (m.handle == wd)
return m.keys;
return &m.keys;
}
}
return{};
return nullptr;
}
window shortkey_container::find(unsigned long key) const
@ -513,12 +513,7 @@ namespace detail
if (owner->flags.destroying)
throw std::runtime_error("the specified owner is destoryed");
#ifndef WIDGET_FRAME_DEPRECATED
native = (category::flags::frame == owner->other.category ?
owner->other.attribute.frame->container : owner->root_widget->root);
#else
native = owner->root_widget->root;
#endif
r.x += owner->pos_root.x;
r.y += owner->pos_root.y;
}
@ -550,11 +545,6 @@ namespace detail
wd->bind_native_window(result.native_handle, result.width, result.height, result.extra_width, result.extra_height, value->root_graph);
impl_->wd_register.insert(wd);
#ifndef WIDGET_FRAME_DEPRECATED
if (owner && (category::flags::frame == owner->other.category))
insert_frame(owner, wd);
#endif
bedrock::inc_window(wd->thread_id);
this->icon(wd, impl_->default_icon_small, impl_->default_icon_big);
return wd;
@ -562,56 +552,6 @@ namespace detail
return nullptr;
}
#ifndef WIDGET_FRAME_DEPRECATED
window_manager::core_window_t* window_manager::create_frame(core_window_t* parent, const rectangle& r, widget* wdg)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(parent) == false) return nullptr;
core_window_t * wd = new core_window_t(parent, widget_notifier_interface::get_notifier(wdg), r, (category::frame_tag**)nullptr);
wd->frame_window(native_interface::create_child_window(parent->root, rectangle(wd->pos_root.x, wd->pos_root.y, r.width, r.height)));
impl_->wd_register.insert(wd, wd->thread_id);
//Insert the frame_widget into its root frames container.
wd->root_widget->other.attribute.root->frames.push_back(wd);
return (wd);
}
bool window_manager::insert_frame(core_window_t* frame, native_window wd)
{
if(frame)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if(category::flags::frame == frame->other.category)
frame->other.attribute.frame->attach.push_back(wd);
return true;
}
return false;
}
bool window_manager::insert_frame(core_window_t* frame, core_window_t* wd)
{
if(frame)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if(category::flags::frame == frame->other.category)
{
if (impl_->wd_register.available(wd) && (category::flags::root == wd->other.category) && wd->root != frame->root)
{
frame->other.attribute.frame->attach.push_back(wd->root);
return true;
}
}
}
return false;
}
#endif
window_manager::core_window_t* window_manager::create_widget(core_window_t* parent, const rectangle& r, bool is_lite, widget* wdg)
{
//Thread-Safe Required!
@ -706,11 +646,7 @@ namespace detail
std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) == false) return;
#ifndef WIDGET_FRAME_DEPRECATED
if((category::flags::root == wd->other.category) || (category::flags::frame != wd->other.category))
#else
if (category::flags::root == wd->other.category)
#endif
{
impl_->misc_register.erase(wd->root);
impl_->wd_register.remove(wd);
@ -749,20 +685,7 @@ namespace detail
if(visible != wd->visible)
{
#ifndef WIDGET_FRAME_DEPRECATED
native_window_type nv = nullptr;
switch(wd->other.category)
{
case category::flags::root:
nv = wd->root; break;
case category::flags::frame:
nv = wd->other.attribute.frame->container; break;
default: //category::widget_tag, category::lite_widget_tag
break;
}
#else
auto nv = (category::flags::root == wd->other.category ? wd->root : nullptr);
#endif
if(visible && wd->effect.bground)
window_layer::make_bground(wd);
@ -1012,24 +935,13 @@ namespace detail
return false;
}
}
#ifndef WIDGET_FRAME_DEPRECATED
else if(category::flags::frame == wd->other.category)
{
native_interface::window_size(wd->other.attribute.frame->container, sz);
for(auto natwd : wd->other.attribute.frame->attach)
native_interface::window_size(natwd, sz);
}
#endif
else
else if(wd->effect.bground && wd->parent)
{
//update the bground buffer of glass window.
if(wd->effect.bground && wd->parent)
{
wd->other.glass_buffer.make(sz);
window_layer::make_bground(wd);
}
}
}
for (auto child : presence)
{
@ -1072,8 +984,19 @@ namespace detail
auto parent = wd->parent;
while (parent)
{
if (parent->flags.refreshing)
if(parent->flags.ignore_child_mapping || parent->flags.refreshing)
{
auto top = parent;
while(parent->parent)
{
parent = parent->parent;
if(parent->flags.ignore_child_mapping || parent->flags.refreshing)
top = parent;
}
top->other.mapping_requester.push_back(wd);
return;
}
parent = parent->parent;
}
@ -1091,6 +1014,12 @@ namespace detail
std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) == false) return false;
if ((wd->other.category == category::flags::root) && wd->is_draw_through())
{
native_interface::refresh_window(wd->root);
return true;
}
if (wd->displayed())
{
using paint_operation = window_layer::paint_operation;
@ -1162,42 +1091,24 @@ namespace detail
window_layer::paint(wd, paint_operation::try_refresh, refresh_tree); //only refreshing if it has an invisible parent
}
wd->other.upd_state = core_window_t::update_state::none;
wd->other.mapping_requester.clear();
}
void window_manager::map_requester(core_window_t* wd)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if (false == impl_->wd_register.available(wd))
return;
if (wd->visible_parents())
{
for(auto requestor : wd->other.mapping_requester)
this->map(requestor, true);
}
//get_graphics
//@brief: Get a copy of the graphics object of a window.
// the copy of the graphics object has a same buf handle with the graphics object's, they are count-refered
// here returns a reference that because the framework does not guarantee the wnd's
// graphics object available after a get_graphics call.
bool window_manager::get_graphics(core_window_t* wd, nana::paint::graphics& result)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if (!impl_->wd_register.available(wd))
return false;
result.make(wd->drawer.graphics.size());
result.bitblt(0, 0, wd->drawer.graphics);
window_layer::paste_children_to_graphics(wd, result);
return true;
}
bool window_manager::get_visual_rectangle(core_window_t* wd, nana::rectangle& r)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
return (impl_->wd_register.available(wd) ?
window_layer::read_visual_rectangle(wd, r) :
false);
}
std::vector<window_manager::core_window_t*> window_manager::get_children(core_window_t* wd) const
{
std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd))
return wd->children;
return{};
wd->other.mapping_requester.clear();
}
bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa)
@ -1405,7 +1316,6 @@ 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)
{
@ -1518,9 +1428,8 @@ namespace detail
std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd))
{
auto object = root_runtime(wd->root);
if(object)
return object->shortkeys.make(reinterpret_cast<window>(wd), key);
//the root runtime must exist, because the wd is valid. Otherse, it's bug of library
return root_runtime(wd->root)->shortkeys.make(reinterpret_cast<window>(wd), key);
}
return false;
}
@ -1543,35 +1452,6 @@ namespace detail
}
}
auto window_manager::shortkeys(core_window_t* wd, bool with_children) -> std::vector<std::pair<core_window_t*, unsigned long>>
{
std::vector<std::pair<core_window_t*, unsigned long>> result;
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd))
{
auto root_rt = root_runtime(wd->root);
if (root_rt)
{
auto keys = root_rt->shortkeys.keys(reinterpret_cast<window>(wd));
for (auto key : keys)
result.emplace_back(wd, key);
if (with_children)
{
for (auto child : wd->children)
{
auto child_keys = shortkeys(child, true);
std::copy(child_keys.begin(), child_keys.end(), std::back_inserter(result));
}
}
}
}
return result;
}
window_manager::core_window_t* window_manager::find_shortkey(native_window_type native_window, unsigned long key)
{
if(native_window)
@ -1631,7 +1511,6 @@ namespace detail
{
auto * const wdpa = wd->parent;
bool established = (for_new && (wdpa != for_new));
decltype(for_new->root_widget->other.attribute.root) pa_root_attr = nullptr;
@ -1657,7 +1536,7 @@ namespace detail
if (root_attr->menubar && check_tree(wd, root_attr->menubar))
root_attr->menubar = nullptr;
sk_holder = shortkeys(wd, true);
_m_shortkeys(wd, true, sk_holder);
}
else
{
@ -1752,17 +1631,6 @@ namespace detail
}
}
#ifndef WIDGET_FRAME_DEPRECATED
if (category::flags::frame == wd->other.category)
{
//remove the frame handle from the WM frames manager.
utl::erase(root_attr->frames, wd);
if (established)
pa_root_attr->frames.push_back(wd);
}
#endif
if (established)
{
wd->parent = for_new;
@ -1851,18 +1719,6 @@ namespace detail
wd->drawer.detached();
wd->widget_notifier->destroy();
#ifndef WIDGET_FRAME_DEPRECATED
if(category::flags::frame == wd->other.category)
{
//The frame widget does not have an owner, and close their element windows without activating owner.
//close the frame container window, it's a native window.
for(auto i : wd->other.attribute.frame->attach)
native_interface::close_window(i);
native_interface::close_window(wd->other.attribute.frame->container);
}
#endif
if(wd->other.category != category::flags::root) //Not a root window
impl_->wd_register.remove(wd);
@ -1875,18 +1731,9 @@ namespace detail
if(category::flags::root != wd->other.category) //A root widget always starts at (0, 0) and its childs are not to be changed
{
wd->pos_root += delta;
#ifndef WIDGET_FRAME_DEPRECATED
if (category::flags::frame != wd->other.category)
{
if (wd->annex.caret_ptr && wd->annex.caret_ptr->visible())
wd->annex.caret_ptr->update();
}
else
native_interface::move_window(wd->other.attribute.frame->container, wd->pos_root.x, wd->pos_root.y);
#else
if (wd->annex.caret_ptr && wd->annex.caret_ptr->visible())
wd->annex.caret_ptr->update();
#endif
if (wd->displayed() && wd->effect.bground)
window_layer::make_bground(wd);
@ -1901,6 +1748,28 @@ namespace detail
}
}
void window_manager::_m_shortkeys(core_window_t* wd, bool with_children, std::vector<std::pair<core_window_t*, unsigned long>>& keys) const
{
if (impl_->wd_register.available(wd))
{
//The root_rt must exist, because wd is valid. Otherwise, it's a bug of the library.
auto root_rt = root_runtime(wd->root);
auto pkeys = root_rt->shortkeys.keys(reinterpret_cast<window>(wd));
if (pkeys)
{
for (auto key : *pkeys)
keys.emplace_back(wd, key);
}
if (with_children)
{
for (auto child : wd->children)
_m_shortkeys(child, true, keys);
}
}
}
//_m_find
//@brief: find a window on root window through a given root coordinate.
// the given root coordinate must be in the rectangle of wnd.

1203
source/gui/dragdrop.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* A Dragger Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -93,9 +93,7 @@ namespace nana
for (auto & t : targets_)
{
t.origin = API::window_position(t.wd);
window owner = API::get_owner_window(t.wd);
if (owner)
API::calc_screen_point(owner, t.origin);
API::calc_screen_point(API::get_owner_window(t.wd), t.origin);
}
break;
case event_code::mouse_move:
@ -108,10 +106,8 @@ namespace nana
{
if (API::is_window_zoomed(t.wd, true) == false)
{
auto owner = API::get_owner_window(t.wd);
auto wdps = t.origin;
if (owner)
API::calc_window_point(owner, wdps);
API::calc_window_point(API::get_owner_window(t.wd), wdps);
switch (t.move_direction)
{

View File

@ -163,7 +163,8 @@ namespace nana
bld_fgcolor = fgcolor.blend(highlighted, 0.6);
break;
case element_state::disabled:
bld_bgcolor = bld_fgcolor = static_cast<color_rgb>(0xb2b7bc);
bld_bgcolor = static_cast<color_rgb>(0xE0E0E0);
bld_fgcolor = static_cast<color_rgb>(0x999A9E);
break;
default:
//Leave things as they are

File diff suppressed because it is too large Load Diff

View File

@ -1228,9 +1228,10 @@ namespace nana
impl->browse.events().click.connect_unignorable([wd, impl](const arg_click&)
{
impl->fbox.owner(wd);
if (impl->fbox.show())
auto files = impl->fbox.show();
if(!files.empty())
{
impl->value = impl->fbox.file();
impl->value = files.front().u8string();
impl->path_edit.caption(impl->value);
}
});

View File

@ -1,7 +1,7 @@
/*
* Nana GUI Programming Interface Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -15,6 +15,7 @@
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/window_manager.hpp>
#include <nana/gui/detail/window_layout.hpp>
#include <nana/system/platform.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/widgets/widget.hpp>
@ -90,16 +91,21 @@ namespace API
void enum_widgets_function_base::enum_widgets(window wd, bool recursive)
{
using basic_window = ::nana::detail::basic_window;
auto iwd = reinterpret_cast<nana::detail::basic_window*>(wd);
internal_scope_guard lock;
if (restrict::wd_manager().available(iwd))
{
//Use a copy, because enum function may close a child window and the original children container would be changed,
//in the situation, the walking thorugh directly to the iwd->children would cause error.
auto children = iwd->children;
auto children = restrict::wd_manager().get_children(reinterpret_cast<basic_window*>(wd));
for (auto child : children)
{
auto widget_ptr = API::get_widget(reinterpret_cast<window>(child));
if (widget_ptr)
{
if (!widget_ptr)
continue;
_m_enum_fn(widget_ptr);
if (recursive)
enum_widgets(reinterpret_cast<window>(child), recursive);
@ -303,13 +309,6 @@ namespace API
return reinterpret_cast<window>(restrict::wd_manager().create_widget(reinterpret_cast<basic_window*>(parent), r, true, wdg));
}
#ifndef WIDGET_FRAME_DEPRECATED
window create_frame(window parent, const rectangle& r, widget* wdg)
{
return reinterpret_cast<window>(restrict::wd_manager().create_frame(reinterpret_cast<basic_window*>(parent), r, wdg));
}
#endif
paint::graphics* window_graphics(window wd)
{
internal_scope_guard isg;
@ -411,6 +410,26 @@ namespace API
}
}
void window_draggable(window wd, bool enabled)
{
auto real_wd = reinterpret_cast<basic_window*>(wd);
internal_scope_guard lock;
if (restrict::wd_manager().available(real_wd))
real_wd->flags.draggable = enabled;
}
bool window_draggable(window wd)
{
auto real_wd = reinterpret_cast<basic_window*>(wd);
internal_scope_guard lock;
if (restrict::wd_manager().available(real_wd))
return real_wd->flags.draggable;
return false;
}
}//end namespace dev
widget* get_widget(window wd)
@ -580,34 +599,6 @@ namespace API
reinterpret_cast<basic_window*>(wd)->flags.fullscreen = v;
}
#ifndef WIDGET_FRAME_DEPRECATED
bool insert_frame(window frame, native_window_type native_window)
{
return restrict::wd_manager().insert_frame(reinterpret_cast<basic_window*>(frame), native_window);
}
native_window_type frame_container(window frame)
{
auto frm = reinterpret_cast<basic_window*>(frame);
internal_scope_guard lock;
if (restrict::wd_manager().available(frm) && (frm->other.category == category::flags::frame))
return frm->other.attribute.frame->container;
return nullptr;
}
native_window_type frame_element(window frame, unsigned index)
{
auto frm = reinterpret_cast<basic_window*>(frame);
internal_scope_guard lock;
if (restrict::wd_manager().available(frm) && (frm->other.category == category::flags::frame))
{
if (index < frm->other.attribute.frame->attach.size())
return frm->other.attribute.frame->attach.at(index);
}
return nullptr;
}
#endif
void close_window(window wd)
{
restrict::wd_manager().close(reinterpret_cast<basic_window*>(wd));
@ -658,7 +649,15 @@ namespace API
auto iwd = reinterpret_cast<basic_window*>(wd);
internal_scope_guard lock;
if (restrict::wd_manager().available(iwd))
{
if (category::flags::root == iwd->other.category)
{
return reinterpret_cast<window>(restrict::wd_manager().root(
interface_type::get_window(iwd->root, window_relationship::parent)
));
}
return reinterpret_cast<window>(iwd->parent);
}
return nullptr;
}
@ -942,7 +941,6 @@ namespace API
restrict::wd_manager().update(reinterpret_cast<basic_window*>(wd), false, true);
}
void window_caption(window wd, const std::string& title_utf8)
{
throw_not_utf8(title_utf8);
@ -1324,7 +1322,16 @@ namespace API
bool window_graphics(window wd, nana::paint::graphics& graph)
{
return restrict::wd_manager().get_graphics(reinterpret_cast<basic_window*>(wd), graph);
auto iwd = reinterpret_cast<basic_window*>(wd);
internal_scope_guard lock;
if (!restrict::wd_manager().available(iwd))
return false;
graph.make(iwd->drawer.graphics.size());
graph.bitblt(0, 0, iwd->drawer.graphics);
nana::detail::window_layout::paste_children_to_graphics(iwd, graph);
return true;
}
bool root_graphics(window wd, nana::paint::graphics& graph)
@ -1341,7 +1348,12 @@ namespace API
bool get_visual_rectangle(window wd, nana::rectangle& r)
{
return restrict::wd_manager().get_visual_rectangle(reinterpret_cast<basic_window*>(wd), r);
auto iwd = reinterpret_cast<basic_window*>(wd);
internal_scope_guard lock;
if (restrict::wd_manager().available(iwd))
return nana::detail::window_layout::read_visual_rectangle(iwd, r);
return false;
}
void typeface(window wd, const nana::paint::font& font)
@ -1518,5 +1530,16 @@ namespace API
{
return ::nana::platform_abstraction::screen_dpi(x_requested);
}
dragdrop_status window_dragdrop_status(::nana::window wd)
{
auto real_wd = reinterpret_cast<basic_window*>(wd);
internal_scope_guard lock;
if (restrict::wd_manager().available(real_wd))
return real_wd->other.dnd_state;
return dragdrop_status::not_ready;
}
}//end namespace API
}//end namespace nana

View File

@ -379,7 +379,12 @@ namespace nana{ namespace drawerbase
void trigger::icon(const nana::paint::image& img)
{
if(img.empty()) return;
if(img.empty())
{
delete attr_.icon;
attr_.icon = nullptr;
return;
}
if(nullptr == attr_.icon)
attr_.icon = new paint::image;

View File

@ -1,7 +1,7 @@
/*
* A CheckBox Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -24,6 +24,7 @@ namespace nana{ namespace drawerbase
struct drawer::implement
{
widget * widget_ptr;
scheme * scheme_ptr;
bool react;
bool radio;
facade<element::crook> crook;
@ -47,6 +48,7 @@ namespace nana{ namespace drawerbase
void drawer::attached(widget_reference widget, graph_reference)
{
impl_->widget_ptr = &widget;
impl_->scheme_ptr =static_cast<scheme*>(API::dev::get_scheme(widget));
API::dev::enable_space_click(widget, true);
}
@ -78,12 +80,18 @@ namespace nana{ namespace drawerbase
}
//draw crook
#ifdef _nana_std_has_string_view
auto txt_px = graph.text_extent_size(std::wstring_view( L"jN", 2 )).height + 2;
#else
auto txt_px = graph.text_extent_size(L"jN", 2).height + 2;
#endif
impl_->crook.draw(graph, wdg->bgcolor(), wdg->fgcolor(), rectangle(0, txt_px > 16 ? (txt_px - 16) / 2 : 0, 16, 16), API::element_state(*wdg));
unsigned txt_px = 0, descent = 0, ileading = 0;
graph.text_metrics(txt_px, descent, ileading);
txt_px += (descent + 2);
auto e_state = API::element_state(*wdg);
if(!wdg->enabled())
e_state = element_state::disabled;
impl_->crook.draw(graph,
impl_->scheme_ptr->square_bgcolor.get(wdg->bgcolor()), impl_->scheme_ptr->square_border_color.get(wdg->fgcolor()),
rectangle(0, txt_px > 16 ? (txt_px - 16) / 2 : 0, 16, 16), e_state);
}
void drawer::mouse_down(graph_reference graph, const arg_mouse&)
@ -208,6 +216,7 @@ namespace nana{ namespace drawerbase
{
e.uiobj->radio(false);
e.uiobj->react(true);
API::umake_event(e.eh_clicked);
API::umake_event(e.eh_checked);
API::umake_event(e.eh_destroy);
API::umake_event(e.eh_keyboard);
@ -224,7 +233,7 @@ namespace nana{ namespace drawerbase
el.uiobj = &uiobj;
uiobj.events().checked.connect_unignorable([this](const arg_checkbox& arg)
el.eh_checked = uiobj.events().checked.connect_unignorable([this](const arg_checkbox& arg)
{
if (arg.widget->checked())
{
@ -236,7 +245,7 @@ namespace nana{ namespace drawerbase
}
}, true);
el.eh_checked = uiobj.events().click.connect_unignorable([this](const arg_click& arg)
el.eh_clicked = uiobj.events().click.connect_unignorable([this](const arg_click& arg)
{
for (auto & i : ui_container_)
i.uiobj->check(arg.window_handle == i.uiobj->handle());

View File

@ -1,51 +0,0 @@
/*
* A Frame 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/gui/widgets/frame.cpp
*
* A frame provides a way to contain the platform window in a stdex GUI Window
*/
#include <nana/gui/widgets/frame.hpp>
#ifndef WIDGET_FRAME_DEPRECATED
namespace nana
{
//class frame:: public widget_object<category::frame_tag>
frame::frame(){}
frame::frame(window wd, bool visible)
{
create(wd, rectangle(), visible);
}
frame::frame(window wd, const nana::rectangle& r, bool visible)
{
create(wd, r, visible);
}
bool frame::insert(native_window_type wd)
{
return API::insert_frame(handle(), wd);
}
native_window_type frame::element(unsigned index)
{
return API::frame_element(handle(), index);
}
native_window_type frame::container() const
{
return API::frame_container(handle());
}
//end class frame
}//end namespace nana
#endif

View File

@ -27,15 +27,17 @@
if(empty()) \
throw std::logic_error("the group is invalid");
namespace nana{
namespace nana
{
static const char* field_title = "__nana_group_title__";
static const char* field_options = "__nana_group_options__";
static const char* field_title = "__nana_group_title__";
static const char* field_options = "__nana_group_options__";
struct group::implement
{
label caption;
align caption_align{ align::left };
background_mode caption_mode{ background_mode::blending };
place place_content;
unsigned gap{2};
std::string usr_div_str;
@ -101,47 +103,48 @@ namespace nana{
if (caption.caption().empty())
place_content.field_display(field_title, false);
}
};
};
group::group()
group::group()
: impl_(new implement)
{
}
{
}
group::group(window parent, const rectangle& r, bool vsb)
group::group(window parent, const rectangle& r, bool vsb)
: group()
{
{
create(parent, r, vsb);
}
}
using groupbase_type = widget_object<category::widget_tag, drawerbase::panel::drawer, general_events, drawerbase::group::scheme>;
using groupbase_type = widget_object<category::widget_tag, drawerbase::panel::drawer, general_events, drawerbase::group::scheme>;
group::group(window parent, ::std::string titel, bool formatted, unsigned gap, const rectangle& r, bool vsb)
group::group(window parent, ::std::string titel, bool formatted, unsigned gap, const rectangle& r, bool vsb)
: group(parent, r, vsb)
{
{
this->bgcolor(API::bgcolor(parent));
impl_.reset(new implement(*this, std::move(titel), vsb, gap));
impl_->caption.format(formatted);
_m_init();
}
}
group::~group()
{
group::~group()
{
delete impl_->radio_logic;
}
}
checkbox& group::add_option(std::string text)
{
checkbox& group::add_option(std::string text)
{
_THROW_IF_EMPTY()
#ifdef _nana_std_has_emplace_return_type
auto & opt = impl_->options.emplace_back(new checkbox{ handle() });
auto & opt = impl_->options.emplace_back(new checkbox { handle() });
#else
impl_->options.emplace_back(new checkbox(handle()));
auto & opt = impl_->options.back();
#endif
opt->transparent(true);
opt->caption(std::move(text));
impl_->place_content[field_options] << *opt;
@ -154,7 +157,7 @@ namespace nana{
return *impl_->options.back();
}
void group::caption_align(align position)
group& group::caption_align(align position)
{
if (position != impl_->caption_align)
{
@ -163,6 +166,32 @@ namespace nana{
impl_->place_content.collocate();
API::refresh_window(*this);
}
return *this;
}
group& group::caption_background_mode(background_mode mode)
{
if (mode != impl_->caption_mode)
{
impl_->caption_mode = mode;
switch (mode)
{
case background_mode::none:
impl_->caption.bgcolor(this->bgcolor());
impl_->caption.transparent(false);
break;
case background_mode::blending:
impl_->caption.transparent(true);
impl_->caption.bgcolor(API::bgcolor(this->parent()).blend(colors::black, 0.025));
break;
case background_mode::transparent:
impl_->caption.transparent(true);
impl_->caption.bgcolor(API::bgcolor(this->parent()).blend(colors::black, 0.025));
break;
}
API::refresh_window(*this);
}
return *this;
}
group& group::radio_mode(bool enable)
@ -197,6 +226,12 @@ namespace nana{
throw std::logic_error("the radio_mode of the group is disabled");
}
void group::option_check( std::size_t pos, bool check )
{
_THROW_IF_EMPTY();
return impl_->options.at(pos)->check( check );
}
bool group::option_checked(std::size_t pos) const
{
_THROW_IF_EMPTY();
@ -206,6 +241,14 @@ namespace nana{
group& group::enable_format_caption(bool format)
{
impl_->caption.format(format);
// if the caption is already set, make sure the layout is updated
if(!caption().empty())
{
impl_->update_div();
impl_->place_content.collocate();
API::refresh_window(*this);
}
return *this;
}
@ -289,18 +332,21 @@ namespace nana{
),
3, 3, this->scheme().border, true, this->bgcolor());
if (background_mode::blending == impl_->caption_mode)
{
auto opt_r = API::window_rectangle(impl_->caption);
if (opt_r)
{
rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width + 4, static_cast<unsigned>(top_round_line - opt_r->y) } };
grad_r.y += top_round_line*2 / 3;
grad_r.y += top_round_line * 2 / 3;
grad_r.x -= 2;
graph.gradual_rectangle(grad_r,
API::bgcolor(this->parent()), this->bgcolor(), true
);
}
}
});
}
@ -322,5 +368,6 @@ namespace nana{
impl_->update_div();
impl_->place_content.collocate();
}
}//end namespace nana

Some files were not shown because too many files have changed in this diff Show More