Merge branch 'develop-1.7'
This commit is contained in:
commit
beb87fe45b
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal 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
1
.gitignore
vendored
@ -42,6 +42,7 @@ lib/
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake-build-debug/
|
||||
cmake-build-*/
|
||||
.idea/
|
||||
cmake_install.cmake
|
||||
*.DS_Store
|
||||
|
32
.travis.yml
32
.travis.yml
@ -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
|
||||
|
457
CMakeLists.txt
457
CMakeLists.txt
@ -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})
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -1,2 +0,0 @@
|
||||
cmake: {generator: MinGW Makefiles}
|
||||
os: {arch: 32bit, family: Windows, subfamily: '7', version: 6.1.7601}
|
49
biicode.conf
49
biicode.conf
@ -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")
|
||||
|
@ -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
|
||||
|
69
build/cmake/Modules/FindFontconfig.cmake
Normal file
69
build/cmake/Modules/FindFontconfig.cmake
Normal 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
70
build/cmake/OS.cmake
Normal 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)
|
48
build/cmake/compilers.cmake
Normal file
48
build/cmake/compilers.cmake
Normal 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()
|
||||
|
15
build/cmake/enable_audio.cmake
Normal file
15
build/cmake/enable_audio.cmake
Normal 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()
|
24
build/cmake/enable_jpeg.cmake
Normal file
24
build/cmake/enable_jpeg.cmake
Normal 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()
|
20
build/cmake/enable_png.cmake
Normal file
20
build/cmake/enable_png.cmake
Normal 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()
|
23
build/cmake/install_nana.cmake
Normal file
23
build/cmake/install_nana.cmake
Normal 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()
|
||||
|
55
build/cmake/select_filesystem.cmake
Normal file
55
build/cmake/select_filesystem.cmake
Normal 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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
51
build/cmake/shared_libs.cmake
Normal file
51
build/cmake/shared_libs.cmake
Normal 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
57
build/cmake/verbose.cmake
Normal 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)
|
@ -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" />
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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" />
|
||||
|
@ -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">
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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*;
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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();
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Definition of General Events
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -17,6 +17,7 @@
|
||||
#include <nana/gui/basis.hpp>
|
||||
#include "event_code.hpp"
|
||||
#include "internal_scope_guard.hpp"
|
||||
#include "../../filesystem/filesystem.hpp"
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
@ -46,12 +47,11 @@ namespace nana
|
||||
struct docker_base
|
||||
: public docker_interface
|
||||
{
|
||||
event_interface * event_ptr;
|
||||
bool flag_deleted{ false };
|
||||
event_interface * const event_ptr;
|
||||
bool flag_deleted;
|
||||
const bool unignorable;
|
||||
|
||||
docker_base(event_interface*, bool unignorable_flag);
|
||||
|
||||
detail::event_interface * get_event() const override;
|
||||
};
|
||||
|
||||
@ -220,33 +220,16 @@ namespace nana
|
||||
|
||||
//The dockers may resize when a new event handler is created by a calling handler.
|
||||
//Traverses with position can avaid crash error which caused by a iterator which becomes invalid.
|
||||
|
||||
auto i = dockers_->data();
|
||||
auto const end = i + dockers_->size();
|
||||
|
||||
for (; i != end; ++i)
|
||||
for (std::size_t i = 0; i < dockers_->size(); ++i)
|
||||
{
|
||||
if (static_cast<docker*>(*i)->flag_deleted)
|
||||
auto d = static_cast<docker*>(dockers_->data()[i]);
|
||||
if (d->flag_deleted || (arg.propagation_stopped() && !d->unignorable))
|
||||
continue;
|
||||
|
||||
static_cast<docker*>(*i)->invoke(arg);
|
||||
d->invoke(arg);
|
||||
|
||||
if (window_handle && (!detail::check_window(window_handle)))
|
||||
break;
|
||||
|
||||
if (arg.propagation_stopped())
|
||||
{
|
||||
for (++i; i != end; ++i)
|
||||
{
|
||||
if (!static_cast<docker*>(*i)->unignorable || static_cast<docker*>(*i)->flag_deleted)
|
||||
continue;
|
||||
|
||||
static_cast<docker*>(*i)->invoke(arg);
|
||||
if (window_handle && (!detail::check_window(window_handle)))
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
@ -297,34 +280,16 @@ namespace nana
|
||||
};
|
||||
}
|
||||
|
||||
static std::function<void(arg_reference)> build_second(fn_type&& fn, void(fn_type::*)(arg_reference))
|
||||
template<typename Tfn, typename Ret>
|
||||
static std::function<void(arg_reference)> build_second(Tfn&& fn, Ret(fn_type::*)(arg_reference))
|
||||
{
|
||||
return std::move(fn);
|
||||
return std::forward<Tfn>(fn);
|
||||
}
|
||||
|
||||
static std::function<void(arg_reference)> build_second(fn_type&& fn, void(fn_type::*)(arg_reference) const)
|
||||
template<typename Tfn, typename Ret>
|
||||
static std::function<void(arg_reference)> build_second(Tfn&& fn, Ret(fn_type::*)(arg_reference)const)
|
||||
{
|
||||
return std::move(fn);
|
||||
}
|
||||
|
||||
static std::function<void(arg_reference)> build_second(fn_type& fn, void(fn_type::*)(arg_reference))
|
||||
{
|
||||
return fn;
|
||||
}
|
||||
|
||||
static std::function<void(arg_reference)> build_second(fn_type& fn, void(fn_type::*)(arg_reference) const)
|
||||
{
|
||||
return fn;
|
||||
}
|
||||
|
||||
static std::function<void(arg_reference)> build_second(const fn_type& fn, void(fn_type::*)(arg_reference))
|
||||
{
|
||||
return fn;
|
||||
}
|
||||
|
||||
static std::function<void(arg_reference)> build_second(const fn_type& fn, void(fn_type::*)(arg_reference) const)
|
||||
{
|
||||
return fn;
|
||||
return std::forward<Tfn>(fn);
|
||||
}
|
||||
|
||||
template<typename Tfn, typename Ret, typename Arg2>
|
||||
@ -420,7 +385,7 @@ namespace nana
|
||||
typedef typename std::remove_reference<arg_reference>::type arg_type;
|
||||
static_assert(std::is_convertible<arg_type, Arg2>::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function.");
|
||||
|
||||
static std::function<void(arg_reference)> build(Ret(*fn)(Arg))
|
||||
static std::function<void(arg_reference)> build(Ret(*fn)(Arg2))
|
||||
{
|
||||
return[fn](arg_reference arg){
|
||||
fn(arg);
|
||||
@ -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
|
||||
|
@ -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_;
|
||||
|
@ -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:
|
||||
|
129
include/nana/gui/dragdrop.hpp
Normal file
129
include/nana/gui/dragdrop.hpp
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Filebox
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -9,14 +9,13 @@
|
||||
*
|
||||
* @file nana/gui/filebox.hpp
|
||||
* @author Jinhao
|
||||
* @brief a dialog to chose file(s), implemented "native" in windows but using nana for X11
|
||||
* @brief dialogs to chose file(s) or a directory, implemented "native" in windows but using nana for X11
|
||||
*/
|
||||
|
||||
#ifndef NANA_GUI_FILEBOX_HPP
|
||||
#define NANA_GUI_FILEBOX_HPP
|
||||
#include <nana/gui/basis.hpp>
|
||||
#include <nana/filesystem/filesystem.hpp>
|
||||
#include <nana/optional.hpp>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
@ -29,9 +28,8 @@ namespace nana
|
||||
filebox(filebox&&) = delete;
|
||||
filebox& operator=(filebox&&) = delete;
|
||||
public:
|
||||
using filters = std::vector<std::pair< ::std::string, ::std::string>>;
|
||||
using path_type = std::filesystem::path;
|
||||
|
||||
filebox(bool is_open_mode);
|
||||
filebox(window owner, bool is_open_mode);
|
||||
filebox(const filebox&);
|
||||
~filebox();
|
||||
@ -39,43 +37,54 @@ namespace nana
|
||||
filebox& operator=(const filebox&);
|
||||
|
||||
/// Change owner window
|
||||
void owner(window);
|
||||
|
||||
/// Set a new title for the dialog
|
||||
/// @param string a text for title
|
||||
/// @return the old title.
|
||||
::std::string title( ::std::string new_title);
|
||||
|
||||
/** @brief Suggest initial path used to locate a directory when the filebox starts.
|
||||
* @param string initial_directory a path of initial directory
|
||||
* @note the behavior of init_path is different between Win7 and Win2K/XP/Vista, but its behavior under Linux is conformed with Win7.
|
||||
/**
|
||||
* Changes the owner window for the filebox. When #show()/operator()# are invoked, the dialog of filebox will be created with the specified owner.
|
||||
* @param handle A handle to a window which will be used for the owner of filebox
|
||||
*/
|
||||
filebox& init_path(const ::std::string& initial_directory);
|
||||
void owner(window handle);
|
||||
|
||||
filebox& init_file(const ::std::string&); ///< Init file, if it contains a path, the init path is replaced by the path of init file.
|
||||
/// Changes new title
|
||||
/**
|
||||
* Changes the title. When #show()/operator()# are invoked, the dialog of filebox will be created with the specified title.
|
||||
* @param text Text of title
|
||||
* @return the reference of *this.
|
||||
*/
|
||||
filebox& title( ::std::string text);
|
||||
|
||||
/// Sets a initial path
|
||||
/**
|
||||
* Suggest initial path used to locate a directory when the filebox starts.
|
||||
* @note the behavior of init_path is different between Win7 and Win2K/XP/Vista, but its behavior under Linux is conformed with Win7.
|
||||
* @param path a path of initial directory
|
||||
* @return reference of *this.
|
||||
*/
|
||||
filebox& init_path(const path_type& path);
|
||||
|
||||
/// Sets a initial filename
|
||||
/**
|
||||
* Suggest a filename when filebox starts. If the filename contains a path, the initial path will be replaced with the path presents in initial filename.
|
||||
* @param filename a filename used for a initial filename when filebox starts.
|
||||
* @return reference of *this.
|
||||
*/
|
||||
filebox& init_file(const ::std::string& filename); ///< Init file, if it contains a path, the init path is replaced by the path of init file.
|
||||
|
||||
/// \brief Add a filetype filter.
|
||||
/// To specify multiple filter in a single description, use a semicolon to separate the patterns(for example,"*.TXT;*.DOC;*.BAK").
|
||||
filebox& add_filter(const ::std::string& description, ///< for example. "Text File"
|
||||
const ::std::string& filetype ///< filter pattern(for example, "*.TXT")
|
||||
filebox& add_filter(const ::std::string& description, ///< for example: "Text File"
|
||||
const ::std::string& filetype ///< filter pattern(for example: "*.TXT")
|
||||
);
|
||||
|
||||
filebox& add_filter(const filters &ftres)
|
||||
{
|
||||
for (auto &f : ftres)
|
||||
add_filter(f.first, f.second);
|
||||
return *this;
|
||||
};
|
||||
filebox& add_filter(const std::vector<std::pair<std::string, std::string>> &filters);
|
||||
|
||||
const path_type& path() const;
|
||||
|
||||
::std::string path() const;
|
||||
::std::string file() const;
|
||||
filebox& allow_multi_select(bool allow);
|
||||
|
||||
/// Display the filebox dialog
|
||||
bool show() const;
|
||||
std::vector<path_type> show() const;
|
||||
|
||||
/// a function object method alternative to show() to display the filebox dialog,
|
||||
bool operator()() const
|
||||
std::vector<path_type> operator()() const
|
||||
{
|
||||
return show();
|
||||
}
|
||||
@ -92,17 +101,26 @@ namespace nana
|
||||
folderbox(folderbox&&) = delete;
|
||||
folderbox& operator=(folderbox&&) = delete;
|
||||
public:
|
||||
using path_type = std::experimental::filesystem::path;
|
||||
using path_type = std::filesystem::path;
|
||||
|
||||
folderbox(window owner = nullptr, const path_type& init_path = {});
|
||||
explicit folderbox(window owner = nullptr, const path_type& init_path = {}, std::string title={});
|
||||
~folderbox();
|
||||
|
||||
std::optional<path_type> show() const;
|
||||
/// Enables/disables multi select
|
||||
folderbox& allow_multi_select(bool allow);
|
||||
|
||||
std::optional<path_type> operator()() const
|
||||
std::vector<path_type> show() const;
|
||||
|
||||
std::vector<path_type> operator()() const
|
||||
{
|
||||
return show();
|
||||
}
|
||||
|
||||
/// Changes title
|
||||
/**
|
||||
* @param text Text of title
|
||||
*/
|
||||
folderbox& title(std::string text);
|
||||
private:
|
||||
implement* impl_;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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();
|
||||
|
||||
|
@ -682,7 +682,6 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
{
|
||||
return lines_.end();
|
||||
}
|
||||
|
||||
private:
|
||||
void _m_parse_format(tokenizer & tknizer, std::stack<fblock*> & fbstack)
|
||||
{
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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_;
|
||||
|
326
source/detail/posix/theme.cpp
Normal file
326
source/detail/posix/theme.cpp
Normal 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
|
31
source/detail/posix/theme.hpp
Normal file
31
source/detail/posix/theme.hpp
Normal 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
|
303
source/detail/posix/xdnd_protocol.hpp
Normal file
303
source/detail/posix/xdnd_protocol.hpp
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Bedrock Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -12,7 +12,6 @@
|
||||
|
||||
#include "../../detail/platform_spec_selector.hpp"
|
||||
#if defined(NANA_POSIX) && defined(NANA_X11)
|
||||
#include <nana/gui/detail/bedrock_pi_data.hpp>
|
||||
#include <nana/gui/detail/event_code.hpp>
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <nana/gui/detail/native_window_interface.hpp>
|
||||
@ -22,6 +21,8 @@
|
||||
#include <errno.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "bedrock_types.hpp"
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace detail
|
||||
@ -52,38 +53,6 @@ namespace detail
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
struct bedrock::thread_context
|
||||
{
|
||||
unsigned event_pump_ref_count{0};
|
||||
|
||||
int window_count{0}; //The number of windows
|
||||
core_window_t* event_window{nullptr};
|
||||
bool is_alt_pressed{false};
|
||||
bool is_ctrl_pressed{false};
|
||||
|
||||
struct platform_detail_tag
|
||||
{
|
||||
native_window_type motion_window;
|
||||
nana::point motion_pointer_pos;
|
||||
}platform;
|
||||
|
||||
struct cursor_tag
|
||||
{
|
||||
core_window_t * window;
|
||||
native_window_type native_handle;
|
||||
nana::cursor predef_cursor;
|
||||
Cursor handle;
|
||||
}cursor;
|
||||
|
||||
thread_context()
|
||||
{
|
||||
cursor.window = nullptr;
|
||||
cursor.native_handle = nullptr;
|
||||
cursor.predef_cursor = nana::cursor::arrow;
|
||||
cursor.handle = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct bedrock::private_impl
|
||||
{
|
||||
typedef std::map<unsigned, thread_context> thr_context_container;
|
||||
@ -247,12 +216,6 @@ namespace detail
|
||||
return bedrock_object;
|
||||
}
|
||||
|
||||
bedrock::core_window_t* bedrock::focus()
|
||||
{
|
||||
core_window_t* wd = wd_manager().root(native_interface::get_focus_window());
|
||||
return (wd ? wd->other.attribute.root->focus : 0);
|
||||
}
|
||||
|
||||
void bedrock::get_key_state(arg_keyboard& arg)
|
||||
{
|
||||
XKeyEvent xkey;
|
||||
@ -289,46 +252,6 @@ namespace detail
|
||||
//No implementation for Linux
|
||||
}
|
||||
|
||||
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal)
|
||||
{
|
||||
if(wd_manager().available(wd) == false)
|
||||
return false;
|
||||
|
||||
core_window_t * prev_wd = nullptr;
|
||||
if(thrd)
|
||||
{
|
||||
prev_wd = thrd->event_window;
|
||||
thrd->event_window = wd;
|
||||
_m_event_filter(evt_code, wd, thrd);
|
||||
}
|
||||
|
||||
using update_state = basic_window::update_state;
|
||||
|
||||
if(wd->other.upd_state == update_state::none)
|
||||
wd->other.upd_state = update_state::lazy;
|
||||
|
||||
_m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal);
|
||||
|
||||
bool good_wd = false;
|
||||
if(wd_manager().available(wd))
|
||||
{
|
||||
//A child of wd may not be drawn if it was out of wd's range before wd resized,
|
||||
//so refresh all children of wd when a resized occurs.
|
||||
if(ask_update || (event_code::resized == evt_code) || (update_state::refreshed == wd->other.upd_state))
|
||||
{
|
||||
wd_manager().do_lazy_refresh(wd, false, (event_code::resized == evt_code));
|
||||
}
|
||||
else
|
||||
wd->other.upd_state = update_state::none;
|
||||
|
||||
good_wd = true;
|
||||
}
|
||||
|
||||
|
||||
if(thrd) thrd->event_window = prev_wd;
|
||||
return good_wd;
|
||||
}
|
||||
|
||||
void assign_arg(arg_mouse& arg, basic_window* wd, unsigned msg, const XEvent& evt)
|
||||
{
|
||||
arg.window_handle = reinterpret_cast<window>(wd);
|
||||
@ -418,10 +341,10 @@ namespace detail
|
||||
{
|
||||
switch(msg.kind)
|
||||
{
|
||||
case nana::detail::msg_packet_tag::kind_xevent:
|
||||
case nana::detail::msg_packet_tag::pkt_family::xevent:
|
||||
window_proc_for_xevent(display, msg.u.xevent);
|
||||
break;
|
||||
case nana::detail::msg_packet_tag::kind_mouse_drop:
|
||||
case nana::detail::msg_packet_tag::pkt_family::mouse_drop:
|
||||
window_proc_for_packet(display, msg);
|
||||
break;
|
||||
default: break;
|
||||
@ -441,8 +364,9 @@ namespace detail
|
||||
|
||||
switch(msg.kind)
|
||||
{
|
||||
case nana::detail::msg_packet_tag::kind_mouse_drop:
|
||||
case nana::detail::msg_packet_tag::pkt_family::mouse_drop:
|
||||
msgwd = brock.wd_manager().find_window(native_window, {msg.u.mouse_drop.x, msg.u.mouse_drop.y});
|
||||
|
||||
if(msgwd)
|
||||
{
|
||||
arg_dropfiles arg;
|
||||
@ -973,7 +897,12 @@ namespace detail
|
||||
case Expose:
|
||||
if(msgwnd->visible && (msgwnd->root_graph->empty() == false))
|
||||
{
|
||||
nana::detail::platform_scope_guard lock;
|
||||
nana::internal_scope_guard lock;
|
||||
//Don't lock this scope using platform-scope-guard. Because it would cause the platform-scope-lock to be locked
|
||||
//before the internal-scope-guard, and the order of locking would cause dead-lock.
|
||||
//
|
||||
//Locks this scope using internal-scope-guard is correct and safe. In the scope, the Xlib functions aren't called
|
||||
//directly.
|
||||
if(msgwnd->is_draw_through())
|
||||
{
|
||||
msgwnd->other.attribute.root->draw_through();
|
||||
@ -1243,10 +1172,12 @@ namespace detail
|
||||
default:
|
||||
if(message == ClientMessage)
|
||||
{
|
||||
auto & atoms = nana::detail::platform_spec::instance().atombase();
|
||||
if(atoms.wm_protocols == xevent.xclient.message_type)
|
||||
auto & spec = ::nana::detail::platform_spec::instance();
|
||||
auto & xclient = xevent.xclient;
|
||||
auto & atoms = spec.atombase();
|
||||
if(atoms.wm_protocols == xclient.message_type)
|
||||
{
|
||||
if(msgwnd->flags.enabled && (atoms.wm_delete_window == static_cast<Atom>(xevent.xclient.data.l[0])))
|
||||
if(msgwnd->flags.enabled && (atoms.wm_delete_window == static_cast<Atom>(xclient.data.l[0])))
|
||||
{
|
||||
arg_unload arg;
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
@ -1338,20 +1269,6 @@ namespace detail
|
||||
|
||||
}//end bedrock::event_loop
|
||||
|
||||
void bedrock::thread_context_destroy(core_window_t * wd)
|
||||
{
|
||||
bedrock::thread_context * thr = get_thread_context(0);
|
||||
if(thr && thr->event_window == wd)
|
||||
thr->event_window = nullptr;
|
||||
}
|
||||
|
||||
void bedrock::thread_context_lazy_refresh()
|
||||
{
|
||||
thread_context* thrd = get_thread_context(0);
|
||||
if(thrd && thrd->event_window)
|
||||
thrd->event_window->other.upd_state = core_window_t::update_state::refreshed;
|
||||
}
|
||||
|
||||
//Dynamically set a cursor for a window
|
||||
void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd)
|
||||
{
|
||||
@ -1421,32 +1338,6 @@ namespace detail
|
||||
if (rev_wd)
|
||||
set_cursor(rev_wd, rev_wd->predef_cursor, thrd);
|
||||
}
|
||||
|
||||
void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd)
|
||||
{
|
||||
auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow);
|
||||
|
||||
switch(event_id)
|
||||
{
|
||||
case event_code::mouse_enter:
|
||||
if (not_state_cur)
|
||||
set_cursor(wd, wd->predef_cursor, thrd);
|
||||
break;
|
||||
case event_code::mouse_leave:
|
||||
if (not_state_cur && (wd->predef_cursor != cursor::arrow))
|
||||
set_cursor(wd, nana::cursor::arrow, thrd);
|
||||
break;
|
||||
case event_code::destroy:
|
||||
if (wd->root_widget->other.attribute.root->state_cursor_window == wd)
|
||||
undefine_state_cursor(wd, thrd);
|
||||
|
||||
if(wd == thrd->cursor.window)
|
||||
set_cursor(wd, cursor::arrow, thrd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}//end namespace detail
|
||||
}//end namespace nana
|
||||
#endif //NANA_POSIX && NANA_X11
|
||||
|
101
source/gui/detail/bedrock_types.hpp
Normal file
101
source/gui/detail/bedrock_types.hpp
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Platform Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -29,6 +29,7 @@
|
||||
|
||||
#include "../../paint/image_accessor.hpp"
|
||||
|
||||
|
||||
namespace nana{
|
||||
namespace detail{
|
||||
|
||||
@ -371,6 +372,8 @@ namespace nana{
|
||||
}
|
||||
|
||||
Window parent = (owner ? reinterpret_cast<Window>(owner) : restrict::spec.root_window());
|
||||
|
||||
//The position passed to XCreateWindow is a screen coordinate.
|
||||
nana::point pos(r.x, r.y);
|
||||
if((false == nested) && owner)
|
||||
{
|
||||
@ -396,7 +399,9 @@ namespace nana{
|
||||
{
|
||||
auto origin_owner = (owner ? owner : reinterpret_cast<native_window_type>(restrict::spec.root_window()));
|
||||
restrict::spec.make_owner(origin_owner, reinterpret_cast<native_window_type>(handle));
|
||||
exposed_positions[handle] = pos;
|
||||
|
||||
//The exposed_position is a relative position to its owner/parent.
|
||||
exposed_positions[handle] = r.position();
|
||||
}
|
||||
|
||||
XChangeWindowAttributes(disp, handle, attr_mask, &win_attr);
|
||||
@ -844,12 +849,17 @@ namespace nana{
|
||||
#endif
|
||||
}
|
||||
|
||||
void native_interface::refresh_window(native_window_type wd)
|
||||
void native_interface::refresh_window(native_window_type native_wd)
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
::InvalidateRect(reinterpret_cast<HWND>(wd), nullptr, true);
|
||||
auto wd = reinterpret_cast<HWND>(native_wd);
|
||||
RECT r;
|
||||
::GetClientRect(wd, &r);
|
||||
::InvalidateRect(wd, &r, FALSE);
|
||||
#elif defined(NANA_X11)
|
||||
static_cast<void>(wd); //eliminate unused parameter compiler warning.
|
||||
Display * disp = restrict::spec.open_display();
|
||||
::XClearArea(disp, reinterpret_cast<Window>(native_wd), 0, 0, 1, 1, true);
|
||||
::XFlush(disp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -945,13 +955,6 @@ namespace nana{
|
||||
auto fm_extents = window_frame_extents(wd);
|
||||
origin.x = -fm_extents.left;
|
||||
origin.y = -fm_extents.top;
|
||||
|
||||
if(reinterpret_cast<Window>(coord_wd) != restrict::spec.root_window())
|
||||
{
|
||||
fm_extents = window_frame_extents(coord_wd);
|
||||
origin.x += fm_extents.left;
|
||||
origin.y += fm_extents.top;
|
||||
}
|
||||
}
|
||||
else
|
||||
coord_wd = get_window(wd, window_relationship::parent);
|
||||
@ -1009,9 +1012,11 @@ namespace nana{
|
||||
auto const owner = restrict::spec.get_owner(wd);
|
||||
if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window())))
|
||||
{
|
||||
auto origin = window_position(owner);
|
||||
x += origin.x;
|
||||
y += origin.y;
|
||||
int origin_x, origin_y;
|
||||
Window child_useless_for_API;
|
||||
::XTranslateCoordinates(disp, reinterpret_cast<Window>(owner), restrict::spec.root_window(), 0, 0, &origin_x, &origin_y, &child_useless_for_API);
|
||||
x += origin_x;
|
||||
y += origin_y;
|
||||
}
|
||||
|
||||
::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y);
|
||||
@ -1058,7 +1063,6 @@ namespace nana{
|
||||
XSizeHints hints;
|
||||
nana::detail::platform_scope_guard psg;
|
||||
|
||||
|
||||
//Returns if the requested rectangle is same with the current rectangle.
|
||||
//In some X-Server versions/implementations, XMapWindow() doesn't generate
|
||||
//a ConfigureNotify if the requested rectangle is same with the current rectangle.
|
||||
@ -1098,9 +1102,11 @@ namespace nana{
|
||||
auto const owner = restrict::spec.get_owner(wd);
|
||||
if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window())))
|
||||
{
|
||||
auto origin = window_position(owner);
|
||||
x += origin.x;
|
||||
y += origin.y;
|
||||
int origin_x, origin_y;
|
||||
Window child_useless_for_API;
|
||||
::XTranslateCoordinates(disp, reinterpret_cast<Window>(owner), restrict::spec.root_window(), 0, 0, &origin_x, &origin_y, &child_useless_for_API);
|
||||
x += origin_x;
|
||||
y += origin_y;
|
||||
}
|
||||
|
||||
::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height);
|
||||
@ -1438,6 +1444,8 @@ namespace nana{
|
||||
{
|
||||
if(owner)
|
||||
return owner;
|
||||
|
||||
return x11_parent_window(wd);
|
||||
}
|
||||
else if(window_relationship::owner == rsp)
|
||||
return owner;
|
||||
@ -1580,14 +1588,17 @@ namespace nana{
|
||||
pos.y = point.y;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#elif defined(NANA_X11)
|
||||
nana::detail::platform_scope_guard psg;
|
||||
int x = pos.x, y = pos.y;
|
||||
Window child;
|
||||
return (True == ::XTranslateCoordinates(restrict::spec.open_display(),
|
||||
reinterpret_cast<Window>(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child));
|
||||
if(True == ::XTranslateCoordinates(restrict::spec.open_display(),
|
||||
reinterpret_cast<Window>(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool native_interface::calc_window_point(native_window_type wd, nana::point& pos)
|
||||
@ -1600,14 +1611,16 @@ namespace nana{
|
||||
pos.y = point.y;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#elif defined(NANA_X11)
|
||||
nana::detail::platform_scope_guard psg;
|
||||
int x = pos.x, y = pos.y;
|
||||
Window child;
|
||||
return (True == ::XTranslateCoordinates(restrict::spec.open_display(),
|
||||
restrict::spec.root_window(), reinterpret_cast<Window>(wd), x, y, &pos.x, &pos.y, &child));
|
||||
if(True == ::XTranslateCoordinates(restrict::spec.open_display(), restrict::spec.root_window(), reinterpret_cast<Window>(wd), x, y, &pos.x, &pos.y, &child))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
native_window_type native_interface::find_window(int x, int y)
|
||||
|
@ -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{});
|
||||
}
|
||||
|
@ -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
1203
source/gui/dragdrop.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
{
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user