Merge branch 'develop-1.7'

This commit is contained in:
Jinhao 2019-03-11 22:52:19 +08:00
commit beb87fe45b
120 changed files with 9493 additions and 6263 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,381 +1,140 @@
# 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
set(NANA_SOURCE_SUBDIRS
/.
/detail
/detail/posix
/filesystem
/gui
/gui/detail
/gui/widgets
/gui/widgets/skeletons
/paint
/paint/detail
/system
/threads
)
if(NANA_CMAKE_ENABLE_AUDIO)
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()
list(APPEND NANA_SOURCE_SUBDIRS
/audio
/audio/detail
)
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)
# collect all source files in the source-sub-dir
foreach(subdir ${NANA_SOURCE_SUBDIRS})
aux_source_directory(${NANA_SOURCE_DIR}${subdir} SOURCES) # todo: use GLOB to add headers too ??
endforeach()
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()
foreach(subdir ${NANA_INCLUDE_SUBDIRS})
aux_source_directory(${NANA_INCLUDE_DIR}/nana${subdir} HEADERS) # todo: use GLOB to add headers too !!!!!!!
endforeach()
### 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
add_definitions(-DNANA_IGNORE_CONF)
if(NANA_CMAKE_VERBOSE_PREPROCESSOR)
add_definitions(-DVERBOSE_PREPROCESSOR)
endif()
target_compile_definitions(nana PRIVATE NANA_IGNORE_CONF) # really ?
if(NANA_CMAKE_AUTOMATIC_GUI_TESTING)
add_definitions(-DNANA_AUTOMATIC_GUI_TESTING)
enable_testing()
target_compile_definitions(nana PUBLIC NANA_AUTOMATIC_GUI_TESTING)
# todo: enable_testing() # ??
endif()
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
####################### Main setting of Nana sources, targets and install
############# 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
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 /.
/detail
/filesystem
/gui
/gui/detail
/gui/widgets
/gui/widgets/skeletons
/paint
/paint/detail
/system
/threads
)
if(NANA_CMAKE_ENABLE_AUDIO)
list(APPEND NANA_SOURCE_SUBDIRS /audio
/audio/detail
)
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)
endforeach()
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
add_definitions(-fmax-errors=3)
endif()
set(CMAKE_DEBUG_POSTFIX "_d")
if(NANA_CMAKE_SHARED_LIB)
add_library(${PROJECT_NAME} SHARED ${SOURCES})
else()
add_library(${PROJECT_NAME} STATIC ${SOURCES})
endif()
target_include_directories(${PROJECT_NAME} PUBLIC ${NANA_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${NANA_LINKS})
# Headers: use INCLUDE_DIRECTORIES
# Libraries: use FIND_LIBRARY and link with the result of it (try to avoid LINK_DIRECTORIES)
# 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

@ -62,7 +62,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,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
# include <experimental/filesystem>
# 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;
};
@ -117,7 +117,7 @@ namespace nana
private:
struct docker
: public detail::docker_base
{
{
/// the callback/response function taking the typed argument
std::function<void(arg_reference)> invoke;
@ -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);
@ -470,9 +435,9 @@ namespace nana
struct arg_dropfiles : public event_arg
{
::nana::window window_handle; ///< A handle to the event window
::nana::point pos; ///< cursor position in the event window
std::vector<std::string> files; ///< external filenames
::nana::window window_handle; ///< A handle to the event window
::nana::point pos; ///< cursor position in the event window
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);
::std::string path() const;
::std::string file() const;
const path_type& path() 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)
{
beg = next;
end = key.find_first_of("\\/", beg);
}
else
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);
}
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

@ -3,8 +3,8 @@
* Nana C++ Library(http://www.nanaro.org)
* Copyright(C) 2015-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* 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/group.hpp
@ -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;
@ -86,7 +104,7 @@ namespace nana{
void field_display(const char* field_name, bool display); ///<Displays/Discards an existing field.
bool field_display(const char* field_name) const; ///<Determines whether the specified field is displayed.
void erase(window handle); ///< Erases a window from field.
template<typename Widget, typename ...Args>
Widget* create_child(const char* field, Args && ... args)
{

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,47 +204,42 @@ 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 (redraw)
{
drawer_.draw(graph, metrics_.what);
API::dev::lazy_refresh();
if (drawer_.metrics.what == what)
return; //no change, don't redraw
drawer_.metrics.what = 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((bytes >= 4) && (ifs.get() == 0 && ifs.get() == 0))
{
if(ifs.get() == 0 && ifs.get() == 0)
{
ifs.close();
return load(file_utf8, nana::unicode::utf32);
}
ifs.close();
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()
void reset_status(bool remain_saved_filename)
{
changed_ = false;
}
if(!remain_saved_filename)
filename_.clear();
void reset()
{
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)
{
#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,17 +170,10 @@ namespace nana
caret_wd->annex.caret_ptr->visible(false);
}
if (!exposed)
if ((!exposed) && (category::flags::root != wd->other.category))
{
if (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
//find an ancestor until it is not a lite_widget
wd = wd->seek_non_lite_widget_ancestor();
}
wd_manager().refresh_tree(wd);
@ -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;
@ -246,13 +215,7 @@ 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{
@ -199,7 +200,7 @@ namespace nana{
namespace x11_wait
{
static Bool configure(Display *disp, XEvent *evt, char *arg)
{
{
return disp && evt && arg && (evt->type == ConfigureNotify) && (evt->xconfigure.window == *reinterpret_cast<Window*>(arg));
}
@ -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);
}
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,22 +935,11 @@ 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);
}
wd->other.glass_buffer.make(sz);
window_layer::make_bground(wd);
}
}
@ -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;
return;
wd->other.mapping_requester.clear();
}
//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)
void window_manager::map_requester(core_window_t* wd)
{
//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;
}
if (false == impl_->wd_register.available(wd))
return;
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);
}
if (wd->visible_parents())
{
for(auto requestor : wd->other.mapping_requester)
this->map(requestor, true);
}
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;
auto children = restrict::wd_manager().get_children(reinterpret_cast<basic_window*>(wd));
for (auto child : children)
if (restrict::wd_manager().available(iwd))
{
auto widget_ptr = API::get_widget(reinterpret_cast<window>(child));
if (widget_ptr)
//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;
for (auto child : children)
{
auto widget_ptr = API::get_widget(reinterpret_cast<window>(child));
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

@ -3,8 +3,8 @@
* Nana C++ Library(http://www.nanaro.org)
* Copyright(C) 2015-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* 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/group.cpp
@ -14,7 +14,7 @@
* @brief group is a widget used to visually group and layout other widgets.
*
* @contributor:
* dankan1890(https://github.com/dankan1890)
* dankan1890(https://github.com/dankan1890)
*/
@ -27,121 +27,124 @@
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;
nana::size caption_dimension;
nana::size caption_dimension;
std::vector<std::unique_ptr<checkbox>> options;
radio_group * radio_logic{nullptr};
std::vector<std::unique_ptr<checkbox>> options;
radio_group * radio_logic{nullptr};
implement() = default;
implement() = default;
implement(window grp_panel, ::std::string titel, bool vsb, unsigned gap=2)
: caption (grp_panel, std::move(titel), vsb),
place_content{grp_panel},
gap{gap}
{
}
implement(window grp_panel, ::std::string titel, bool vsb, unsigned gap=2)
: caption (grp_panel, std::move(titel), vsb),
place_content{grp_panel},
gap{gap}
{
}
void create(window pnl)
{
caption.create(pnl);
caption.caption("");
place_content.bind(pnl);
void create(window pnl)
{
caption.create(pnl);
caption.caption("");
place_content.bind(pnl);
if (!radio_logic)
radio_logic = new radio_group;
}
if (!radio_logic)
radio_logic = new radio_group;
}
void update_div()
{
const std::size_t padding = 10;
caption_dimension = caption.measure(1000);
caption_dimension.width += 1;
void update_div()
{
const std::size_t padding = 10;
caption_dimension = caption.measure(1000);
caption_dimension.width += 1;
std::string div = "vert margin=[0," + std::to_string(gap) + "," + std::to_string(gap + 5) + "," + std::to_string(gap) + "]";
std::string div = "vert margin=[0," + std::to_string(gap) + "," + std::to_string(gap + 5) + "," + std::to_string(gap) + "]";
div += "<weight=" + std::to_string(caption_dimension.height) + " ";
div += "<weight=" + std::to_string(caption_dimension.height) + " ";
if (align::left == caption_align)
div += "<weight=" + std::to_string(padding) + ">";
else
div += "<>"; //right or center
if (align::left == caption_align)
div += "<weight=" + std::to_string(padding) + ">";
else
div += "<>"; //right or center
div += "<" + std::string{ field_title } + " weight=" + std::to_string(caption_dimension.width) + ">";
div += "<" + std::string{ field_title } + " weight=" + std::to_string(caption_dimension.width) + ">";
if (align::right == caption_align)
div += "<weight=" + std::to_string(padding) + ">";
else if (align::center == caption_align)
div += "<>";
if (align::right == caption_align)
div += "<weight=" + std::to_string(padding) + ">";
else if (align::center == caption_align)
div += "<>";
div += "><<vert margin=5 " + std::string(field_options) + ">";
div += "><<vert margin=5 " + std::string(field_options) + ">";
if (!usr_div_str.empty())
div += "<" + usr_div_str + ">>";
else
div += ">";
if (!usr_div_str.empty())
div += "<" + usr_div_str + ">>";
else
div += ">";
place_content.div(div.c_str());
place_content.div(div.c_str());
if (options.empty())
place_content.field_display(field_options, false);
if (options.empty())
place_content.field_display(field_options, false);
if (caption.caption().empty())
place_content.field_display(field_title, false);
}
};
if (caption.caption().empty())
place_content.field_display(field_title, false);
}
};
group::group()
: impl_(new implement)
{
}
group::group()
: impl_(new implement)
{
}
group::group(window parent, const rectangle& r, bool vsb)
: group()
{
create(parent, r, 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(parent, r, vsb)
{
this->bgcolor(API::bgcolor(parent));
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_.reset(new implement(*this, std::move(titel), vsb, gap));
impl_->caption.format(formatted);
_m_init();
}
impl_->caption.format(formatted);
_m_init();
}
group::~group()
{
delete impl_->radio_logic;
}
group::~group()
{
delete impl_->radio_logic;
}
checkbox& group::add_option(std::string text)
{
_THROW_IF_EMPTY()
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();
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,17 +332,20 @@ namespace nana{
),
3, 3, this->scheme().border, true, this->bgcolor());
auto opt_r = API::window_rectangle(impl_->caption);
if (opt_r)
if (background_mode::blending == impl_->caption_mode)
{
rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width + 4, static_cast<unsigned>(top_round_line - opt_r->y) } };
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.x -= 2;
grad_r.y += top_round_line * 2 / 3;
grad_r.x -= 2;
graph.gradual_rectangle(grad_r,
API::bgcolor(this->parent()), this->bgcolor(), true
);
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

View File

@ -20,6 +20,7 @@
#include <stdexcept>
#include <sstream>
namespace nana
{
namespace drawerbase
@ -82,7 +83,7 @@ namespace nana
dstream_.parse(s, format_enabled_);
}
bool format(bool fm)
bool format(bool fm) noexcept
{
if (fm == format_enabled_)
return false;
@ -95,80 +96,56 @@ namespace nana
{
traceable_.clear();
auto pre_font = graph.typeface(); //used for restoring the font
#ifdef _nana_std_has_string_view
const unsigned def_line_pixels = graph.text_extent_size(std::wstring_view{ L" ", 1 }).height;
#else
const unsigned def_line_pixels = graph.text_extent_size(L" ", 1).height;
#endif
font_ = pre_font;
fblock_ = nullptr;
_m_set_default(pre_font, fgcolor);
_m_measure(graph);
render_status rs;
rs.allowed_width = graph.size().width;
rs.text_align = th;
rs.text_align_v = tv;
::nana::size extent_size;
//All visual lines data of whole text.
std::deque<std::vector<visual_line>> content_lines;
auto content_lines = _m_measure_extent_size(graph, th, tv, true, graph.size().width, extent_size);
std::size_t extent_v_pixels = 0; //the pixels, in height, that text will be painted.
for (auto & line : dstream_)
if ((tv != align_v::top) && extent_size.height < graph.height())
{
_m_prepare_visual_lines(graph, line, def_line_pixels, rs);
rs.pos.y = static_cast<int>(graph.height() - extent_size.height);
for (auto & vsline : rs.vslines)
extent_v_pixels += vsline.extent_height_px;
content_lines.emplace_back(std::move(rs.vslines));
if(extent_v_pixels >= graph.height())
break;
}
if((tv != align_v::top) && extent_v_pixels < graph.height())
{
rs.pos.y = static_cast<int>(graph.height() - extent_v_pixels);
if(align_v::center == tv)
if (align_v::center == tv)
rs.pos.y >>= 1;
}
else
rs.pos.y = 0;
auto vsline_iterator = content_lines.begin();
for (auto & line : dstream_)
{
if (rs.pos.y >= static_cast<int>(graph.height()))
break;
auto pre_font = graph.typeface(); //used for restoring the font
_m_set_default(pre_font, fgcolor);
for (auto & line : content_lines)
{
rs.index = 0;
rs.vslines.clear();
rs.vslines.swap(*vsline_iterator++);
rs.vslines.swap(line);
rs.pos.x = rs.vslines.front().x_base;
if (!_m_foreach_visual_line(graph, rs))
break;
rs.pos.y += static_cast<int>(rs.vslines.back().extent_height_px);
//Now the y-position of rs has been modified to next line.
}
graph.typeface(pre_font);
if (transient_.current_font != pre_font)
{
graph.typeface(pre_font);
transient_.current_font.release();
transient_.current_fblock = nullptr;
}
}
bool find(int x, int y, std::wstring& target, std::wstring& url) const noexcept
bool find(const point& mouse_pos, std::wstring& target, std::wstring& url) const
{
for (auto & t : traceable_)
{
if(t.r.is_hit(x, y))
if(t.r.is_hit(mouse_pos))
{
target = t.target;
url = t.url;
@ -181,44 +158,10 @@ namespace nana
::nana::size measure(graph_reference graph, unsigned limited, align th, align_v tv)
{
::nana::size retsize;
::nana::size extent_size;
_m_measure_extent_size(graph, th, tv, false, limited, extent_size);
auto ft = graph.typeface(); //used for restoring the font
#ifdef _nana_std_has_string_view
const unsigned def_line_pixels = graph.text_extent_size(std::wstring_view(L" ", 1)).height;
#else
const unsigned def_line_pixels = graph.text_extent_size(L" ", 1).height;
#endif
font_ = ft;
fblock_ = nullptr;
_m_set_default(ft, colors::black);
_m_measure(graph);
render_status rs;
rs.allowed_width = limited;
rs.text_align = th;
rs.text_align_v = tv;
for(auto & line: dstream_)
{
rs.vslines.clear();
auto w = _m_prepare_visual_lines(graph, line, def_line_pixels, rs);
if(limited && (w > limited))
w = limited;
if(retsize.width < w)
retsize.width = w;
for (auto& vsline : rs.vslines)
retsize.height += static_cast<unsigned>(vsline.extent_height_px);
}
return retsize;
return extent_size;
}
private:
//Manage the fblock for a specified rectangle if it is a traceable fblock.
@ -246,6 +189,9 @@ namespace nana
def_.font_size = ft.size();
def_.font_bold = ft.bold();
def_.fgcolor = fgcolor;
transient_.current_font = ft;
transient_.current_fblock = nullptr;
}
const ::nana::color& _m_fgcolor(nana::widgets::skeletons::fblock* fp) noexcept
@ -294,39 +240,20 @@ namespace nana
void _m_change_font(graph_reference graph, nana::widgets::skeletons::fblock* fp)
{
if(fp != fblock_)
if (fp != transient_.current_fblock)
{
auto& name = _m_fontname(fp);
auto fontsize = _m_font_size(fp);
bool bold = _m_bold(fp);
if((fontsize != font_.size()) || bold != font_.bold() || name != font_.name())
if((fontsize != transient_.current_font.size()) || bold != transient_.current_font.bold() || name != transient_.current_font.name())
{
paint::font::font_style fs;
fs.weight = (bold ? 800 : 400);
font_ = paint::font{ name, fontsize, fs };
graph.typeface(font_);
transient_.current_font = paint::font{ name, fontsize, fs };
graph.typeface(transient_.current_font);
}
fblock_ = fp;
}
}
void _m_measure(graph_reference graph)
{
nana::paint::font ft = font_;
for (auto & line : dstream_)
{
for (auto & value : line)
{
_m_change_font(graph, value.fblock_ptr);
value.data_ptr->measure(graph);
}
}
if(font_ != ft)
{
font_ = ft;
graph.typeface(ft);
fblock_ = nullptr;
transient_.current_fblock = fp;
}
}
@ -346,6 +273,58 @@ namespace nana
}
}
std::deque<std::vector<visual_line>> _m_measure_extent_size(graph_reference graph, nana::align text_align, nana::align_v text_align_v, bool only_screen, unsigned allowed_width_px, nana::size & extent_size)
{
auto pre_font = graph.typeface(); //used for restoring the font
unsigned text_ascent, text_descent, text_ileading;
graph.text_metrics(text_ascent, text_descent, text_ileading);
auto const def_line_pixels = text_ascent + text_descent;
_m_set_default(pre_font, colors::black);
render_status rs;
rs.allowed_width = allowed_width_px;
rs.text_align = text_align;
rs.text_align_v = text_align_v;
//All visual lines data of whole text.
std::deque<std::vector<visual_line>> content_lines;
extent_size.width = extent_size.height = 0;
for (auto & line : dstream_)
{
auto width_px = _m_prepare_visual_lines(graph, line, def_line_pixels, rs);
if (width_px > extent_size.width)
extent_size.width = width_px;
for (auto & vsline : rs.vslines)
extent_size.height += static_cast<size::value_type>(vsline.extent_height_px);
content_lines.emplace_back(std::move(rs.vslines));
if (only_screen && (extent_size.height >= graph.height()))
break;
}
//The width is not restricted if the allowed_width_px is zero.
if (allowed_width_px && (allowed_width_px < extent_size.width))
extent_size.width = allowed_width_px;
if (transient_.current_font != pre_font)
{
graph.typeface(pre_font);
transient_.current_font.release();
transient_.current_fblock = nullptr;
}
return content_lines;
}
/**
* prepare data for rendering a line of text.
*/
@ -359,11 +338,11 @@ namespace nana
#else
rs.vslines.emplace_back();
auto & vsline = rs.vslines.back();
#endif
vsline.baseline = 0;
vsline.extent_height_px = def_line_px;
vsline.x_base = 0;
#endif
return 0;
}
@ -379,7 +358,10 @@ namespace nana
for (auto i = line.cbegin(); i != line.cend(); ++i)
{
auto const data = i->data_ptr;
auto fblock = i->fblock_ptr;
auto const fblock = i->fblock_ptr;
_m_change_font(graph, fblock);
data->measure(graph);
abs_text_px += data->size().width;
@ -457,15 +439,17 @@ namespace nana
if (data->is_text())
{
_m_change_font(graph, fblock);
//Split a text into multiple lines
auto rest_extent_size = extent_size.width;
std::size_t text_begin = 0;
while (text_begin < data->text().size())
{
unsigned sub_text_px = 0;
auto sub_text_len = _m_fit_text(graph, data->text().substr(text_begin), rs.allowed_width, sub_text_px);
//At least one character must be displayed no matter whether the width is enough or not.
if (0 == sub_text_len)
sub_text_len = 1;
if (text_begin + sub_text_len < data->text().size())
{
//make a new visual line
@ -547,10 +531,6 @@ namespace nana
bool _m_foreach_visual_line(graph_reference graph, render_status& rs)
{
std::wstring text;
content_element_iterator block_start;
auto const bottom = static_cast<int>(graph.height()) - 1;
for (auto & vsline : rs.vslines)
@ -593,8 +573,7 @@ namespace nana
if (data->is_text())
{
auto const text = data->text().c_str() + vsline_elm.range.first;
auto const reordered = unicode_reorder(text, vsline_elm.range.second);
auto const reordered = unicode_reorder(data->text().c_str() + vsline_elm.range.first, vsline_elm.range.second);
_m_change_font(graph, fblock);
for (auto & bidi : reordered)
@ -628,25 +607,18 @@ namespace nana
rs.pos.x += static_cast<int>(data->size().width);
}
}
static std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos)
{
std::size_t n = i->data_ptr->text().length();
while(pos >= n)
{
pos -= n;
n = (++i)->data_ptr->text().length();
}
return{ pos, n - pos };
}
private:
dstream dstream_;
bool format_enabled_ = false;
::nana::widgets::skeletons::fblock * fblock_ = nullptr;
::std::deque<traceable> traceable_;
::nana::paint::font font_;
struct transient
{
widgets::skeletons::fblock * current_fblock{ nullptr };
paint::font current_font;
}transient_;
struct def_font_tag
{
::std::string font_name;
@ -744,7 +716,7 @@ namespace nana
{
std::wstring target, url;
if(impl_->renderer.find(arg.pos.x, arg.pos.y, target, url))
if(impl_->renderer.find(arg.pos, target, url))
{
int cur_state = 0;
if(target != impl_->target)
@ -915,7 +887,8 @@ namespace nana
if(graph_ptr->empty())
{
graph_ptr = &substitute;
graph_ptr->make({ 10, 10 });
substitute.make({ 10, 10 });
substitute.typeface(this->typeface());
}
return impl->renderer.measure(*graph_ptr, limited, impl->text_align, impl->text_align_v);

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