Merge branch 'develop'

This commit is contained in:
Jinhao 2020-02-11 05:57:19 +08:00
commit b72490f8b6
54 changed files with 1858 additions and 1053 deletions

View File

@ -43,8 +43,12 @@ matrix:
- llvm-toolchain-precise - llvm-toolchain-precise
before_install: before_install:
# donwload nana-demo first
# we are in: 'user'/nana/
- cd .. - cd ..
# we are in: 'user'/
- git clone --depth=1 --branch=master https://github.com/qPCR4vir/nana-demo.git nana-demo - git clone --depth=1 --branch=master https://github.com/qPCR4vir/nana-demo.git nana-demo
# now we have 'user'/nana-demo, 'user'/nana/ and we are in: 'user'/
- export PATH="$HOME/bin:$PATH" - export PATH="$HOME/bin:$PATH"
- 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 - 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 - chmod -R +x /tmp/tools
@ -53,76 +57,24 @@ install:
- /tmp/tools/cmake --prefix="$HOME" --exclude-subdir - /tmp/tools/cmake --prefix="$HOME" --exclude-subdir
before_script : before_script :
# travis don't have a physical monitor. We need to install an emulator: https://docs.travis-ci.com/user/gui-and-headless-browsers/ - mkdir demo-build
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- 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 demo-build
- cd demo-build - cd demo-build
# now we have 'user'/nana-demo, 'user'/nana/ , 'user'/demo-build/ and we are in: 'user'/demo-build/
services:
# travis don't have a physical monitor. We need to install an emulator:
# https://docs.travis-ci.com/user/gui-and-headless-browsers/
- xvfb
script: script:
- cmake -G"Unix Makefiles" ../nana-demo -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=OFF -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON -DNANA_CMAKE_INSTALL=OFF - cmake -G"Unix Makefiles" ../nana-demo -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=OFF -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON -DNANA_CMAKE_INSTALL=OFF
- make install - make install
- ctest --verbose # todo set correct working directory, and show output
# we have installed in 'user'/ ('user'/demo-build/..), and cmake created 'user'/nana-test/
# todo: separate resources from sources (a directory for images) # todo: separate resources from sources (a directory for images)
- ls - ls
# we were still in: 'user'/demo-build/
- cd ../nana-test/bin - cd ../nana-test/bin
- ls - ls -lh
- ./a_group_impl
- ./animate-bmp
- ./audio_player
- ./background-effects
#- ./calculator # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1159
- ./categ
- ./clicked
- ./decore
- ./dock
- ./drag-button
- ./draw
- ./file_explorer
#- ./example_menu # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1348
- ./example_listbox
#- ./example_combox # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1378
- ./example.button
#- ./filebox-txt # https://travis-ci.org/qPCR4vir/nana/jobs/140250744#L1393
- ./folder_tree
#- ./folder_tree_nana # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1408
#- ./folder_tree_std # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1421
- ./framework_design_1
- ./framework_design_2
- ./framework_design_3
- ./group
- ./HelloWord
#- ./helloword_quit # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1572
#- ./inputbox # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1585
- ./label_listener
- ./lambda_event.Cpp11
- ./listbox_inline_widget
- ./listbox_Resolver
- ./loader_1
#- ./loader_2 # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1732
- ./mbox
- ./main
- ./menu_debug
#- ./modal_form # https://travis-ci.org/qPCR4vir/nana/jobs/140250744#L1736
#- ./MontiHall # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1775
#- ./helloworld_demo # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1786
#- ./notepad # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1799
- ./menu_debug
- ./menu_popuper
#- ./modal_form # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1846
#- ./widget_show2 # https://travis-ci.org/qPCR4vir/nana/jobs/140245437#L1730
#- ./widget_show # https://travis-ci.org/qPCR4vir/nana/jobs/140245437#L1740
- ./place_login
- ./png
#- ./screen # https://travis-ci.org/qPCR4vir/nana/jobs/140238537#L1909
- ./stretch_image
#- ./threading # https://travis-ci.org/qPCR4vir/nana/jobs/140245437#L1826 ?
#- ./thread-pool # https://travis-ci.org/qPCR4vir/nana/jobs/140247564#L1782
- ./various_events
#- ./window-dragger # https://travis-ci.org/qPCR4vir/nana/jobs/140245438#L1820
- ./windows-subclassing
- ./textbox_line_number

View File

@ -22,7 +22,7 @@
# cmake 3.12 have more better modern c++ support # cmake 3.12 have more better modern c++ support
cmake_minimum_required(VERSION 3.12 FATAL_ERROR) cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(nana VERSION 1.7.1 project(nana VERSION 1.7.3
DESCRIPTION "C++ GUI library" DESCRIPTION "C++ GUI library"
HOMEPAGE_URL http://nanapro.org HOMEPAGE_URL http://nanapro.org
LANGUAGES CXX ) LANGUAGES CXX )
@ -32,6 +32,7 @@ project(nana VERSION 1.7.1
add_library(nana) add_library(nana)
add_library(nana::nana ALIAS nana) add_library(nana::nana ALIAS nana)
target_compile_features(nana PUBLIC cxx_std_17) target_compile_features(nana PUBLIC cxx_std_17)
# set(CMAKE_CXX_STANDARD 17)
# need after cxx_std_14 or cxx_std_17 ?? # need after cxx_std_14 or cxx_std_17 ??
target_compile_features(nana target_compile_features(nana
@ -116,7 +117,7 @@ option(NANA_CMAKE_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ "replaced boost.thread wi
######## Nana options ######## Nana options
target_compile_definitions(nana PRIVATE NANA_IGNORE_CONF) # really ? target_compile_definitions(nana PRIVATE NANA_IGNORE_CONF) # really ??
if(NANA_CMAKE_AUTOMATIC_GUI_TESTING) if(NANA_CMAKE_AUTOMATIC_GUI_TESTING)
target_compile_definitions(nana PUBLIC NANA_AUTOMATIC_GUI_TESTING) target_compile_definitions(nana PUBLIC NANA_AUTOMATIC_GUI_TESTING)
# todo: enable_testing() # ?? # todo: enable_testing() # ??

View File

@ -1,12 +1,12 @@
# Nana C++ Library # Nana C++ Library
[Linux (gcc 5.4.0 and 4.9.2)![TravisCI build status](https://travis-ci.org/cnjinhao/nana.svg)](https://travis-ci.org/cnjinhao/nana) including [(nana-demos)](https://github.com/qPCR4vir/nana-demo) [Linux (gcc 8.3.0 and 9.2)![TravisCI build status](https://travis-ci.org/cnjinhao/nana.svg)](https://travis-ci.org/cnjinhao/nana) including [(nana-demos)](https://github.com/qPCR4vir/nana-demo)
[Windows (Microsoft (R) Build Engine version 14.0.24720.0) ![AppVeyor build status](https://ci.appveyor.com/api/projects/status/5j79p9fi887usv7h?svg=true)](https://ci.appveyor.com/project/qPCR4vir/nana) [Windows (Microsoft (R) Build Engine version 15.9.21) ![AppVeyor build status](https://ci.appveyor.com/api/projects/status/5j79p9fi887usv7h?svg=true)](https://ci.appveyor.com/project/qPCR4vir/nana)
[![Licence](https://img.shields.io/badge/license-BSL-blue.svg?style=flat)](LICENSE) [![Licence](https://img.shields.io/badge/license-BSL-blue.svg?style=flat)](LICENSE)
Nana is a C++ library designed to allow developers to easily create cross-platform GUI applications with modern C++11 style. Currently it can work on Linux(X11) and Windows. The [nana repository](https://github.com/cnjinhao/nana) contains the entire source of the library. You can browse the source code and submit your pull request for contributing. Nana is a C++ standard-like GUI library designed to allow developers to easily create cross-platform GUI applications with modern C++ style. Currently it is regularly tested on Linux(X11) and Windows, and experimentally on macOS and FreeBSD. The [nana repository](https://github.com/cnjinhao/nana) contains the entire source of the library. You can browse the source code and submit your pull request for contributing.
## License ## License

View File

@ -38,13 +38,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AN
endif() 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") if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
target_compile_options(nana PRIVATE -fmax-errors=3) target_compile_options(nana PRIVATE -fmax-errors=3)
endif() endif()

View File

@ -1,4 +1,4 @@
option(NANA_CMAKE_INSTALL "Install nana when compile the library (to be consumed without cmake)" ON) option(NANA_CMAKE_INSTALL "Install nana after compiling the library (to be consumed WITHOUT cmake!!)" OFF)
# Install the include directories too. # Install the include directories too.
if(NANA_CMAKE_INSTALL) if(NANA_CMAKE_INSTALL)
@ -6,8 +6,11 @@ if(NANA_CMAKE_INSTALL)
# Is your responsability to ensure all compiler options are compatible with the compilation # Is your responsability to ensure all compiler options are compatible with the compilation
# of the project linking to the nana lib here generated # of the project linking to the nana lib here generated
target_sources(nana PRIVATE ${HEADERS}) 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") message("The compiled Nana library will be installed in ${CMAKE_INSTALL_PREFIX}/lib")
message("WARNING !!! You are using the 'installed' nana! Not recommended! ")
message("If this was not your intention, please tern OFF option NANA_CMAKE_INSTALL ")
message("for example by adding: -DNANA_CMAKE_INSTALL=OFF to your call to cmake. ")
# Actually in DESTDIR/CMAKE_INSTALL_PREFIX/lib but in windows there is no DESTDIR/ part. # Actually in DESTDIR/CMAKE_INSTALL_PREFIX/lib but in windows there is no DESTDIR/ part.
install(TARGETS nana install(TARGETS nana
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
@ -15,8 +18,13 @@ if(NANA_CMAKE_INSTALL)
RUNTIME DESTINATION bin) RUNTIME DESTINATION bin)
install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include) # in ${CMAKE_INSTALL_PREFIX}/include/nana 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") message("The Nana include files will be installed in ${CMAKE_INSTALL_PREFIX}/include")
target_include_directories(nana PUBLIC $<BUILD_INTERFACE:${NANA_INCLUDE_DIR}>
$<INSTALL_INTERFACE:include> )
else() else()
# this is the prefered method to consume nana with cmake # this is the prefered method to consume nana with cmake
message("You are using nana directly from original sources. (Recommended!) "
"If this was not your intention, and what you want is to install precomplied nana first, then "
"please tern ON option NANA_CMAKE_INSTALL ")
target_sources(nana PUBLIC ${HEADERS}) target_sources(nana PUBLIC ${HEADERS})
target_include_directories(nana PUBLIC ${NANA_INCLUDE_DIR}) target_include_directories(nana PUBLIC ${NANA_INCLUDE_DIR})
endif() endif()

View File

@ -1,30 +1,36 @@
# The ISO C++ File System Technical Specification (ISO-TS, or STD) was optional. # The ISO C++ File System Technical Specification (ISO-TS, or STD) was optional.
# http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf # http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf
# It is part of c++17. # It is part of c++17.
# The library may be not available or working correctly in the std library in use. As a workaround we may try # The library may be not available or working correctly in the std library you use.
# to "implement" it (ab)using Boost (almost compatible) # As a workaround we will use Nana own partial, but functional implementation.
# You may opt to try to "implement" the std filesystem it (ab)using Boost (almost compatible)
# http://www.boost.org/doc/libs/1_60_0/libs/filesystem/doc/index.htm # 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. # By ncluding the file <nana/filesystem/filesystem.hpp> or <nana/filesystem/filesystem_ext.hpp>
# If you include the file <nana/filesystem/filesystem.hpp> or <nana/filesystem/filesystem_ext.hpp> # the selected option is inlined by nana into std::filesystem.
# the selected option will be set by nana into std::filesystem # By default Nana will try to use the STD. If STD is not available Nana own implementation will be used.
# By default Nana will try to use the STD. If STD is not available and NANA_CMAKE_FIND_BOOST_FILESYSTEM
# is set to ON nana will try to use boost if available. Nana own implementation will be use if none of
# the previus were selected or available.
# You can change that default if you change one of the following # You can change that default if you change one of the following
# (please don't define more than one of the _XX_FORCE options): # (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_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_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_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) set (TEST_FS_LIB OFF)
if(NANA_CMAKE_NANA_FILESYSTEM_FORCE) if(NANA_CMAKE_NANA_FILESYSTEM_FORCE)
if(NANA_CMAKE_STD_FILESYSTEM_FORCE)
message (FATAL_ERROR "Defined NANA_CMAKE_NANA_FILESYSTEM_FORCE and NANA_CMAKE_STD_FILESYSTEM_FORCE")
endif()
if(NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
message (FATAL_ERROR "Defined NANA_CMAKE_NANA_FILESYSTEM_FORCE and NANA_CMAKE_BOOST_FILESYSTEM_FORCE")
endif()
target_compile_definitions(nana PUBLIC 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) elseif(NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
if(NANA_CMAKE_STD_FILESYSTEM_FORCE)
message (FATAL_ERROR "Defined NANA_CMAKE_BOOST_FILESYSTEM_FORCE and NANA_CMAKE_STD_FILESYSTEM_FORCE")
endif()
target_compile_definitions(nana PUBLIC BOOST_FILESYSTEM_FORCE) target_compile_definitions(nana PUBLIC BOOST_FILESYSTEM_FORCE)
# https://cmake.org/cmake/help/git-master/module/FindBoost.html # 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, # Implicit dependencies such as Boost::filesystem requiring Boost::system will be automatically detected and satisfied,
@ -43,14 +49,131 @@ elseif(NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
set(Boost_USE_STATIC_RUNTIME ON) set(Boost_USE_STATIC_RUNTIME ON)
else() 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()
if(NANA_CMAKE_STD_FILESYSTEM_FORCE)
target_compile_definitions(nana PUBLIC STD_FILESYSTEM_FORCE)
endif()
check_include_file_cxx (filesystem NANA_HAVE_FILESYSTEM)
if (NANA_HAVE_FILESYSTEM)
message (STATUS "C++ Filesystem header: <filesystem>")
set (TEST_FS_LIB ON)
set (CXXSTD_FS_TEST_SOURCE
"#include <filesystem>
int main()
{
std::filesystem::path p{\"\tmp/\"};
throw std::filesystem::filesystem_error(\"Empty file name!\", std::make_error_code(std::errc::invalid_argument));
}")
else()
check_include_file_cxx (experimental/filesystem NANA_HAVE_EXP_FILESYSTEM)
if (NANA_HAVE_EXP_FILESYSTEM)
message (STATUS "C++ Filesystem header: <experimental/filesystem>")
set (TEST_FS_LIB ON)
set (CXXSTD_FS_TEST_SOURCE
"#include <experimental/filesystem>
int main()
{
std::experimental::filesystem::path p{\"/tmp/\"};
throw std::experimental::filesystem::filesystem_error(\"Empty file name!\", std::make_error_code(std::errc::invalid_argument));
}")
else ()
message (WARNING "No std::filesystem include file found: nana::filesystem will be used.
Set NANA_CMAKE_NANA_FILESYSTEM_FORCE to ON to avoid this warning.")
target_compile_definitions(nana PUBLIC STD_FILESYSTEM_NOT_SUPPORTED)
set (TEST_FS_LIB OFF)
endif ()
endif ()
if (TEST_FS_LIB)
include (FindPackageMessage)
include (CheckIncludeFileCXX)
include (CheckCXXSourceCompiles)
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
set (CMAKE_REQUIRED_INCLUDES ${CMAKE_INCLUDE_PATH})
set (CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS})
set (CMAKE_REQUIRED_FLAGS_ORIGINAL ${CMAKE_REQUIRED_FLAGS})
set (CMAKE_REQUIRED_LIBRARIES_ORIGINAL ${CMAKE_REQUIRED_LIBRARIES})
# c++: builtin
set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_ORIGINAL}")
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_ORIGINAL})
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXXBuiltIn_FS_BuiltIn)
if (CXXBuiltIn_FS_BuiltIn)
message (STATUS "C++ Filesystem library: builtin")
else()
set (CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_ORIGINAL} stdc++fs")
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXXBuiltIn_FS_stdcppfs)
if (CXXBuiltIn_FS_stdcppfs)
message (STATUS "C++ Filesystem library: stdc++fs")
target_link_libraries (nana PUBLIC stdc++fs)
else()
set (CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_ORIGINAL} c++fs")
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXXBuiltIn_FS_cppfs)
if (CXXBuiltIn_FS_cppfs)
message (STATUS "C++ Filesystem library: c++fs")
target_link_libraries (nana PUBLIC c++fs)
else()
# c++: -std=c++17
set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_ORIGINAL} -std=c++17")
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_ORIGINAL})
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXX_std__cpp17_FS_BuiltIn)
if (CXX_std__cpp17_FS_BuiltIn)
message (STATUS "C++: -std=c++17; Filesystem library: builtin")
else()
set (CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_ORIGINAL} stdc++fs")
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXX_std__cpp17_FS_stdcppfs)
if (CXX_std__cpp17_FS_stdcppfs)
message (STATUS "C++: -std=c++17; Filesystem library: stdc++fs")
target_link_libraries (nana PUBLIC stdc++fs)
else()
set (CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_ORIGINAL} c++fs")
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXX_std__cpp17_FS_cppfs)
if (CXX_std__cpp17_FS_cppfs)
message (STATUS "C++: -std=c++17; Filesystem library: c++fs")
target_link_libraries (nana PUBLIC c++fs)
else()
# c++: /std:c++17
set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_ORIGINAL} /std:c++17")
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_ORIGINAL})
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXX_std_cpp17_FS_BuiltIn)
if (CXX_std_cpp17_FS_BuiltIn)
message (STATUS "C++: /std:c++17; Filesystem library: builtin")
else()
set (CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_ORIGINAL} stdc++fs")
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXX_std_cpp17_FS_stdcppfs)
if (CXX_std_cpp17_FS_stdcppfs)
message (STATUS "C++: /std:c++17; Filesystem library: stdc++fs")
target_link_libraries (nana PUBLIC stdc++fs)
else()
set (CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_ORIGINAL} c++fs")
check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" CXX_std_cpp17_FS_cppfs)
if (CXX_std_cpp17_FS_cppfs)
message (STATUS "C++: /std:c++17; Filesystem library: c++fs")
target_link_libraries (nana PUBLIC c++fs)
else ()
message (WARNING "No std::filesystem library found: nana::filesystem will be used.
Set NANA_CMAKE_NANA_FILESYSTEM_FORCE to ON to avoid this warning.")
target_compile_definitions(nana PUBLIC STD_FILESYSTEM_NOT_SUPPORTED)
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_ORIGINAL})
set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_ORIGINAL}")
endif ()
endif ()
endif ()
endif ()
endif ()
endif ()
endif ()
endif ()
endif ()
endif (TEST_FS_LIB)
endif ()

View File

@ -1,5 +1,6 @@
option(BUILD_SHARED_LIBS "Compile nana as a shared library." OFF) option(BUILD_SHARED_LIBS "Compile nana as a shared library." OFF)
option(NANA_STATIC_STDLIB "Link nana statically to C++ standard library" ON)
if(BUILD_SHARED_LIBS) # todo test if(BUILD_SHARED_LIBS) # todo test
@ -35,12 +36,11 @@ if(BUILD_SHARED_LIBS) # todo test
endif() endif()
endif() endif()
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW?? if(NANA_STATIC_STDLIB)
target_link_libraries(nana
PUBLIC
$<$<CXX_COMPILER_ID:GNU>:-static-libgcc -static-libstdc++>
$<$<CXX_COMPILER_ID:Clang>:-static-libgcc -static-libstdc++>
)
endif()
if(BUILD_SHARED_LIBS)
target_compile_options(nana PUBLIC -lgcc -lstdc++)
else()
target_link_libraries(nana PUBLIC -static-libgcc -static-libstdc++)
endif(BUILD_SHARED_LIBS)
endif()

View File

@ -14,8 +14,8 @@
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-std=c++11" />
<Add option="-Wall" /> <Add option="-Wall" />
<Add option="-std=c++11" />
<Add option="-g" /> <Add option="-g" />
<Add directory="../../include" /> <Add directory="../../include" />
<Add directory="../../extrlib/mingw" /> <Add directory="../../extrlib/mingw" />

View File

@ -16,6 +16,7 @@
#define NANA_ANY_HPP #define NANA_ANY_HPP
#include <typeinfo> #include <typeinfo>
#include <type_traits> #include <type_traits>
#include <utility>
#include "c++defines.hpp" #include "c++defines.hpp"
@ -74,7 +75,7 @@ namespace nana
any(Value && value, any(Value && value,
typename std::enable_if<!std::is_same<any&, Value>::value>::type * = nullptr, typename std::enable_if<!std::is_same<any&, Value>::value>::type * = nullptr,
typename std::enable_if<!std::is_const<Value>::value>::type* = nullptr) typename std::enable_if<!std::is_const<Value>::value>::type* = nullptr)
: content_(new holder<typename std::decay<Value>::type>(static_cast<Value&&>(value))) : content_(new holder<typename std::decay<Value>::type>(std::forward<Value>(value)))
{ {
} }
@ -87,7 +88,7 @@ namespace nana
template<class Value> template<class Value>
any& operator=(Value&& other) any& operator=(Value&& other)
{ {
any(other).swap(*this); any(std::forward<Value>(other)).swap(*this);
return *this; return *this;
} }

View File

@ -1,7 +1,7 @@
/** /**
* Predefined Symbols for C++ * Predefined Symbols for C++
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2016-2018 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2016-2019 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -48,14 +48,15 @@
#ifndef NANA_CXX_DEFINES_INCLUDED #ifndef NANA_CXX_DEFINES_INCLUDED
#define NANA_CXX_DEFINES_INCLUDED #define NANA_CXX_DEFINES_INCLUDED
#define STD_FILESYSTEM_NOT_SUPPORTED // #define STD_FILESYSTEM_NOT_SUPPORTED
//C++ language //C++ language
#if defined(_MSC_VER) #if defined(_MSC_VER)
# if (_MSC_VER < 1900) # if (_MSC_VER < 1900) // VC2013
# //About std.experimental.filesystem. # //About std.experimental.filesystem.
# //Through VC2013 has provided <filesystem>, but all the names are given in namespace std. It's hard to alias these names into std::experimental, # //Through VC2013 has provided <filesystem>, but all the names are given in namespace std. It's hard to alias these names into std::experimental,
# //So Nana use nana.filesystem implement instead for VC2013 # //So Nana use nana.filesystem implement instead for VC2013
# define STD_FILESYSTEM_NOT_SUPPORTED
# #
# //Nana defines some macros for lack of support of keywords # //Nana defines some macros for lack of support of keywords
# define _ALLOW_KEYWORD_MACROS # define _ALLOW_KEYWORD_MACROS
@ -64,8 +65,6 @@
# define noexcept //no support of noexcept until Visual C++ 2015 # define noexcept //no support of noexcept until Visual C++ 2015
# define constexpr //no support of constexpr until Visual C++ 2015 ? const ?? # define constexpr //no support of constexpr until Visual C++ 2015 ? const ??
# else
# undef STD_FILESYSTEM_NOT_SUPPORTED
# endif # endif
#elif defined(__GNUC__) && not defined(__clang__) #elif defined(__GNUC__) && not defined(__clang__)
# if (__GNUC__ == 4 && __GNUC_MINOR__ < 6) # if (__GNUC__ == 4 && __GNUC_MINOR__ < 6)
@ -89,7 +88,7 @@
#define NANA_MINGW #define NANA_MINGW
#endif // MINGW #endif // MINGW
#elif defined(APPLE) //Mac OS X #elif defined(__APPLE__) || defined(APPLE) //Mac OS X
//Symbols for MACOS //Symbols for MACOS
#define NANA_MACOS #define NANA_MACOS
#define NANA_POSIX #define NANA_POSIX
@ -125,16 +124,16 @@
#elif defined(__clang__) //Clang #elif defined(__clang__) //Clang
#include <iosfwd> //Introduces some implement-specific flags of ISO C++ Library #include <iosfwd> // Introduces some implement-specific flags of ISO C++ Library
#if defined(__GLIBCPP__) || defined(__GLIBCXX__) #if defined(__GLIBCPP__) || defined(__GLIBCXX__)
//<codecvt> is a known issue on libstdc++, it works on libc++ //<codecvt> is a known issue on libstdc++, it works on libc++
#define STD_CODECVT_NOT_SUPPORTED #define STD_CODECVT_NOT_SUPPORTED
#endif #endif
#elif defined(__GNUC__) //GCC #elif defined(__GNUC__) // GCC
#include <iosfwd> //Introduces some implement-specific flags of ISO C++ Library #include <iosfwd> // Introduces some implementation-specific flags of ISO C++ Library
#if defined(__GLIBCPP__) || defined(__GLIBCXX__) #if defined(__GLIBCPP__) || defined(__GLIBCXX__)
//<codecvt> is a known issue on libstdc++, it works on libc++ //<codecvt> is a known issue on libstdc++, it works on libc++ todo review !
#define STD_CODECVT_NOT_SUPPORTED #define STD_CODECVT_NOT_SUPPORTED
//It's a known issue of libstdc++ on MinGW //It's a known issue of libstdc++ on MinGW
@ -155,6 +154,8 @@
# if ((__GNUC__ > 5) || ((__GNUC__ == 5) && (__GNUC_MINOR__ >= 3 ) ) ) # if ((__GNUC__ > 5) || ((__GNUC__ == 5) && (__GNUC_MINOR__ >= 3 ) ) )
# undef STD_FILESYSTEM_NOT_SUPPORTED # undef STD_FILESYSTEM_NOT_SUPPORTED
# else
# define STD_FILESYSTEM_NOT_SUPPORTED
# endif # endif
#if (__GNUC__ == 4) #if (__GNUC__ == 4)
@ -252,7 +253,7 @@
# if __has_include(<filesystem>) # if __has_include(<filesystem>)
# undef STD_FILESYSTEM_NOT_SUPPORTED # undef STD_FILESYSTEM_NOT_SUPPORTED
# endif # endif
# if __has_include(<mutex>) # if __has_include(<mutex>)
# if !(defined(NANA_MINGW) && !defined(_GLIBCXX_HAS_GTHREADS)) # if !(defined(NANA_MINGW) && !defined(_GLIBCXX_HAS_GTHREADS))
//See the comment above regarding MinGW's threading support //See the comment above regarding MinGW's threading support
# undef STD_THREAD_NOT_SUPPORTED # undef STD_THREAD_NOT_SUPPORTED

View File

@ -9,7 +9,7 @@
* *
* @file nana/filesystem/filesystem.hpp * @file nana/filesystem/filesystem.hpp
* @author Ariel Vina-Rodriguez, Jinhao * @author Ariel Vina-Rodriguez, Jinhao
* @brief Mimic std::experimental::filesystem::v1 (boost v3) * @brief Mimic std::filesystem
* and need VC2015 or a C++11 compiler. With a few correction can be compiler by VC2013 * and need VC2015 or a C++11 compiler. With a few correction can be compiler by VC2013
*/ */
@ -34,32 +34,26 @@
//Filesystem Selection //Filesystem Selection
#include <nana/config.hpp> #include <nana/config.hpp>
#if defined(NANA_USING_NANA_FILESYSTEM) || defined(NANA_USING_STD_FILESYSTEM) || defined(NANA_USING_BOOST_FILESYSTEM)
#undef NANA_USING_NANA_FILESYSTEM
#undef NANA_USING_STD_FILESYSTEM
#undef NANA_USING_BOOST_FILESYSTEM
#endif
#define NANA_USING_NANA_FILESYSTEM 0 #define NANA_USING_NANA_FILESYSTEM 0
#define NANA_USING_STD_FILESYSTEM 0 #define NANA_USING_STD_FILESYSTEM 0
#define NANA_USING_BOOST_FILESYSTEM 0 #define NANA_USING_BOOST_FILESYSTEM 0
#if (defined(NANA_FILESYSTEM_FORCE) || ( (defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(BOOST_FILESYSTEM_AVAILABLE)) && !(defined(BOOST_FILESYSTEM_FORCE) || defined(STD_FILESYSTEM_FORCE)) ) ) //#define NANA_FILESYSTEM_FORCE 1
#if (defined(NANA_FILESYSTEM_FORCE) || ( (defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(BOOST_FILESYSTEM_AVAILABLE)) && !(defined(BOOST_FILESYSTEM_FORCE) || defined(STD_FILESYSTEM_FORCE)) ) )
#undef NANA_USING_NANA_FILESYSTEM #undef NANA_USING_NANA_FILESYSTEM
#define NANA_USING_NANA_FILESYSTEM 1 #define NANA_USING_NANA_FILESYSTEM 1
#elif (defined(BOOST_FILESYSTEM_AVAILABLE) && ( defined(BOOST_FILESYSTEM_FORCE) || ( defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(STD_FILESYSTEM_FORCE) ) )) #elif (defined(BOOST_FILESYSTEM_AVAILABLE) && ( defined(BOOST_FILESYSTEM_FORCE) || ( defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(STD_FILESYSTEM_FORCE) ) ))
#undef NANA_USING_BOOST_FILESYSTEM #undef NANA_USING_BOOST_FILESYSTEM
#define NANA_USING_BOOST_FILESYSTEM 1 #define NANA_USING_BOOST_FILESYSTEM 1
# include <chrono> # include <chrono>
# include <boost/filesystem.hpp> # include <boost/filesystem.hpp>
// add boost::filesystem into std::experimental::filesystem // inline boost::filesystem into std::filesystem
namespace std { namespace std {
namespace experimental { namespace filesystem {
namespace filesystem { inline namespace boost_filesystem {
using namespace boost::filesystem; using namespace boost::filesystem;
using file_time_type = std::chrono::time_point<std::chrono::system_clock>; using file_time_type = std::chrono::time_point<std::chrono::system_clock>;
@ -75,43 +69,34 @@ namespace std {
socket = boost::filesystem::file_type::socket_file, socket = boost::filesystem::file_type::socket_file,
unknown = boost::filesystem::file_type::type_unknown, unknown = boost::filesystem::file_type::type_unknown,
}; };
// Boost dont include generic_u8string // Boost dont include generic_u8string
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp // 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 // 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 // http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp
// but travis come with an oooold version of boost // but travis come with an oooold version of boost
// 1.55.0 NOT enable directory_iterator C++11 range-base for // 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 // http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp
#if BOOST_VERSION < 105600 #if BOOST_VERSION < 105600
namespace boost namespace boost { // todo ??
// enable directory_iterator C++11 range-base for statement use --------------------// // 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 // 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 // auto - thus the top-level const is stripped - so returning const is harmless and
// emphasizes begin() is just a pass through. // emphasizes begin() is just a pass through.
inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT
{ {
return iter; return iter;
} }
inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT
{ {
return directory_iterator(); return directory_iterator();
} }
#endif }
#endif
} // filesystem } // boost_filesystem
} // experimental } // filesystem
namespace filesystem
{
using namespace experimental::filesystem;
}
#ifndef __cpp_lib_experimental_filesystem
# define __cpp_lib_experimental_filesystem 201406
#endif
} // std } // std
#else #else
@ -133,7 +118,7 @@ namespace std {
# undef NANA_USING_STD_EXPERIMENTAL_FILESYSTEM # undef NANA_USING_STD_EXPERIMENTAL_FILESYSTEM
# define NANA_USING_STD_EXPERIMENTAL_FILESYSTEM # define NANA_USING_STD_EXPERIMENTAL_FILESYSTEM
# endif # endif
#endif #endif // BOOST_FILESYSTEM and NANA_FILESYSTEM
#if NANA_USING_NANA_FILESYSTEM #if NANA_USING_NANA_FILESYSTEM
@ -148,437 +133,495 @@ namespace std {
#include <nana/deploy.hpp> #include <nana/deploy.hpp>
namespace nana { namespace experimental { namespace filesystem namespace nana {
{ namespace filesystem {
#ifndef CXX_NO_INLINE_NAMESPACE
inline namespace v1
{
#endif
enum class file_type enum class file_type
{ {
none = 0, ///< has not been determined or an error occurred while trying to determine none = 0, ///< has not been determined or an error occurred while trying to determine
not_found = -1, ///< Pseudo-type: file was not found. Is not considered an error not_found = -1, ///< Pseudo-type: file was not found. Is not considered an error
regular = 1, regular = 1,
directory = 2 , directory = 2,
symlink =3, ///< Symbolic link file symlink = 3, ///< Symbolic link file
block =4, ///< Block special file block = 4, ///< Block special file
character= 5 , ///< Character special file character = 5, ///< Character special file
fifo = 6 , ///< FIFO or pipe file fifo = 6, ///< FIFO or pipe file
socket =7, socket = 7,
unknown= 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other unknown = 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other
}; };
enum class perms enum class perms
{ {
none = 0, ///< There are no permissions set for the file. none = 0, ///< There are no permissions set for the file.
all = 0x1FF, ///< owner_all | group_all | others_all all = 0x1FF, ///< owner_all | group_all | others_all
mask = 0xFFF, ///< all | set_uid | set_gid | sticky_bit. mask = 0xFFF, ///< all | set_uid | set_gid | sticky_bit.
unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions
}; };
//enum class copy_options; //enum class copy_options;
enum class directory_options enum class directory_options
{ {
none, none,
follow_directory_symlink, follow_directory_symlink,
skip_permission_denied skip_permission_denied
}; };
struct space_info struct space_info
{ {
uintmax_t capacity; uintmax_t capacity;
uintmax_t free; uintmax_t free;
uintmax_t available; uintmax_t available;
}; };
using file_time_type = std::chrono::time_point<std::chrono::system_clock>; ///< trivial-clock> ; using file_time_type = std::chrono::time_point<std::chrono::system_clock>; ///< trivial-clock> ;
class file_status class file_status
{ {
file_type m_ft = file_type::none; file_type m_ft = file_type::none;
perms m_prms = perms::unknown; perms m_prms = perms::unknown;
public: public:
explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown); explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown);
// observers // observers
file_type type() const; file_type type() const;
perms permissions() const;
// modifiers perms permissions() const;
void type(file_type ft);
void permissions(perms prms);
private:
file_type value_;
perms perms_;
};
/// concerned only with lexical and syntactic aspects and does not necessarily exist in // modifiers
/// external storage, and the pathname is not necessarily valid for the current operating system void type(file_type ft);
/// or for a particular file system
/// A sequence of elements that identify the location of a file within a filesystem. void permissions(perms prms);
/// The elements are the:
/// rootname (opt), root-directory (opt), and an optional sequence of filenames. private:
/// The maximum number of elements in the sequence is operating system dependent. file_type value_;
class path perms perms_;
{ };
public:
/// concerned only with lexical and syntactic aspects and does not necessarily exist in
/// external storage, and the pathname is not necessarily valid for the current operating system
/// or for a particular file system
/// A sequence of elements that identify the location of a file within a filesystem.
/// The elements are the:
/// rootname (opt), root-directory (opt), and an optional sequence of filenames.
/// The maximum number of elements in the sequence is operating system dependent.
class path
{
public:
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
using value_type = wchar_t; using value_type = wchar_t;
const static value_type preferred_separator = L'\\'; const static value_type preferred_separator = L'\\';
#else #else
using value_type = char; using value_type = char;
const static value_type preferred_separator = '/'; const static value_type preferred_separator = '/';
#endif #endif
using string_type = std::basic_string<value_type>; using string_type = std::basic_string<value_type>;
path() = default; path() = default;
template<typename Source> template<typename Source>
path(const Source& source) path(const Source &source)
{ {
_m_assign(source); _m_assign(source);
} }
// modifiers // modifiers
void clear() noexcept; void clear() noexcept;
path& make_preferred();
path& remove_filename();
//path& replace_filename(const path& replacement);
//path& replace_extension(const path& replacement = path());
//void swap(path& rhs) noexcept;
// decomposition path &make_preferred();
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;
path extension() const;
// query path &remove_filename();
bool empty() const noexcept; //path& replace_filename(const path& replacement);
bool has_root_name() const { return !root_name().empty(); } //path& replace_extension(const path& replacement = path());
bool has_root_directory() const { return !root_directory().empty(); } //void swap(path& rhs) noexcept;
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().empty(); }; // temp
bool is_absolute() const;
bool is_relative() const;
int compare(const path& other) const; // decomposition
path root_name() const;
file_type what() const; path root_directory() const;
const value_type*c_str() const; path root_path() const;
const string_type& native() const;
operator string_type() const;
std::string string() const; path relative_path() const;
std::wstring wstring() const;
std::string u8string() const;
// std::u16string u16string() const;
// std::u32string u32string() const;
std::string generic_string() const ; path parent_path() const;
std::wstring generic_wstring() const;
std::string generic_u8string() const;
// std::u16string generic_u16string() const;
// std::u32string generic_u32string() const;
path lexically_normal() const; path filename() const;
//appends path stem() const;
path& operator/=(const path& other);
template<typename Source> path extension() const;
path& operator/=(const Source& source)
{
path other(source);
return this->operator/=(other);
}
template<typename Source> // query
path& append(const Source& source) bool empty() const noexcept;
{
path other(source);
return this->operator/=(other);
}
private:
void _m_assign(const std::string& source_utf8);
void _m_assign(const std::wstring& source);
private:
string_type pathstr_;
};
bool operator==(const path& lhs, const path& rhs); bool has_root_name() const
bool operator!=(const path& lhs, const path& rhs); { return !root_name().empty(); }
bool operator<(const path& lhs, const path& rhs);
bool operator>(const path& lhs, const path& rhs); bool has_root_directory() const
path operator/(const path& lhs, const path& rhs); { 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().empty(); }; // temp
bool is_absolute() const;
bool is_relative() const;
int compare(const path &other) const;
file_type what() const;
const value_type *c_str() const;
const string_type &native() const;
operator string_type() const;
std::string string() const;
std::wstring wstring() const;
// std::string u8string() const;
// std::u16string u16string() const;
// std::u32string u32string() const;
std::string generic_string() const;
std::wstring generic_wstring() const;
// std::string generic_u8string() const;
// std::u16string generic_u16string() const;
// std::u32string generic_u32string() const;
path lexically_normal() const;
//appends
path &operator/=(const path &other);
template<typename Source>
path &operator/=(const Source &source)
{
path other(source);
return this->operator/=(other);
}
template<typename Source>
path &append(const Source &source)
{
path other(source);
return this->operator/=(other);
}
private:
void _m_assign(const std::string &source_utf8);
void _m_assign(const std::wstring &source);
private:
string_type pathstr_;
};
bool operator==(const path &lhs, const path &rhs);
bool operator!=(const path &lhs, const path &rhs);
bool operator<(const path &lhs, const path &rhs);
bool operator>(const path &lhs, const path &rhs);
path operator/(const path &lhs, const path &rhs);
class filesystem_error class filesystem_error
: public std::system_error : public std::system_error
{ {
public: public:
explicit filesystem_error(const std::string& msg, std::error_code); explicit filesystem_error(const std::string &msg, std::error_code);
filesystem_error(const std::string& msg, const path& path1, std::error_code err); filesystem_error(const std::string &msg, const path &path1, std::error_code err);
filesystem_error(const std::string& msg, const path& path1, const path& path2, std::error_code err);
const path& path1() const noexcept; filesystem_error(const std::string &msg, const path &path1, const path &path2, std::error_code err);
const path& path2() const noexcept;
// const char* what() const noexcept; const path &path1() const noexcept;
private:
path path1_; const path &path2() const noexcept;
path path2_; // const char* what() const noexcept;
}; private:
path path1_;
path path2_;
};
class directory_entry class directory_entry
{ {
public: public:
directory_entry() = default; directory_entry() = default;
explicit directory_entry(const ::nana::experimental::filesystem::path&);
//modifiers explicit directory_entry(const filesystem::path &);
void assign(const ::nana::experimental::filesystem::path&);
void replace_filename(const ::nana::experimental::filesystem::path&);
//observers //modifiers
file_status status() const; void assign(const filesystem::path &);
operator const filesystem::path&() const { return path_; };
const filesystem::path& path() const;
private:
::nana::experimental::filesystem::path path_;
};
/// InputIterator that iterate over the sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator void replace_filename(const filesystem::path &);
class directory_iterator :public std::iterator<std::input_iterator_tag, directory_entry>
{
using find_handle = void*;
public:
directory_iterator() noexcept; //observers
explicit directory_iterator(const path& p); file_status status() const;
directory_iterator(const path& p, directory_options opt);
const value_type& operator*() const; operator const filesystem::path &() const
const value_type* operator->() const; { return path_; };
directory_iterator& operator++(); const filesystem::path &path() const;
directory_iterator operator++(int); ///< extention
bool equal(const directory_iterator& x) const; private:
filesystem::path path_;
};
private: /// InputIterator that iterate over the sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator
template<typename Char> class directory_iterator : public std::iterator<std::input_iterator_tag, directory_entry>
static bool _m_ignore(const Char * p) {
{ using find_handle = void *;
while(*p == '.') public:
++p;
return (*p == 0);
}
void _m_prepare(const path& file_path); directory_iterator() noexcept;
void _m_read();
private:
bool end_{false};
path::string_type path_;
directory_options option_{ directory_options::none };
std::shared_ptr<find_handle> find_ptr_; explicit directory_iterator(const path &p);
find_handle handle_{nullptr};
value_type value_;
};
/// enable directory_iterator range-based for statements
inline directory_iterator begin( directory_iterator iter) noexcept
{
return iter;
}
inline directory_iterator end( const directory_iterator&) noexcept directory_iterator(const path &p, directory_options opt);
{
return {}; const value_type &operator*() const;
}
const value_type *operator->() const;
directory_iterator &operator++();
directory_iterator operator++(int); ///< extention
bool equal(const directory_iterator &x) const;
private:
template<typename Char>
static bool _m_ignore(const Char *p)
{
while (*p == '.')
++p;
return (*p == 0);
}
void _m_prepare(const path &file_path);
void _m_read();
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};
value_type value_;
};
/// enable directory_iterator range-based for statements
inline directory_iterator begin(directory_iterator iter) noexcept
{
return iter;
}
inline directory_iterator end(const directory_iterator &) noexcept
{
return {};
}
//class recursive_directory_iterator; //class recursive_directory_iterator;
//// enable recursive_directory_iterator range-based for statements //// enable recursive_directory_iterator range-based for statements
//recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; //recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
//recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; //recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;
//template<typename Value_Type> //template<typename Value_Type>
inline bool operator==(const directory_iterator/*<Value_Type>*/ & x, const directory_iterator/*<Value_Type>*/ & y) inline bool operator==(const directory_iterator/*<Value_Type>*/ &x, const directory_iterator/*<Value_Type>*/ &y)
{ {
return x.equal(y); return x.equal(y);
} }
//template<typename Value_Type> //template<typename Value_Type>
inline bool operator!=(const directory_iterator/*<Value_Type>*/ & x, const directory_iterator/*<Value_Type>*/ & y) inline bool operator!=(const directory_iterator/*<Value_Type>*/ &x, const directory_iterator/*<Value_Type>*/ &y)
{ {
return !x.equal(y); return !x.equal(y);
} }
file_status status(const path& p); file_status status(const path &p);
file_status status(const path& p, std::error_code&);
std::uintmax_t file_size(const path& p); file_status status(const path &p, std::error_code &);
std::uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
inline bool is_directory(file_status s) noexcept std::uintmax_t file_size(const path &p);
{ return s.type() == file_type::directory ;}
bool is_directory(const path& p); std::uintmax_t file_size(const path &p, std::error_code &ec) noexcept;
bool is_directory(const path& p, std::error_code& ec) noexcept;
inline bool is_regular_file(file_status s) noexcept inline bool is_directory(file_status s) noexcept
{ { return s.type() == file_type::directory; }
return s.type() == file_type::regular;
}
inline bool is_regular_file(const path& p)
{
return is_regular_file(status(p));
}
// bool is_regular_file(const path& p, error_code& ec) noexcept;
// Returns: is_regular_file(status(p, ec)).Returns false if an error occurs.
inline bool is_empty(const path& p) bool is_directory(const path &p);
{
auto fs = status(p);
if (is_directory(fs)) bool is_directory(const path &p, std::error_code &ec) noexcept;
return (directory_iterator() == directory_iterator(p));
return (file_size(p) == 0); inline bool is_regular_file(file_status s) noexcept
} {
// bool is_empty(const path& p, error_code& ec) noexcept; return s.type() == file_type::regular;
}
inline bool is_regular_file(const path &p)
{
return is_regular_file(status(p));
}
// bool is_regular_file(const path& p, error_code& ec) noexcept; // todo:
// Returns: is_regular_file(status(p, ec)).Returns false if an error occurs. // todo:
inline bool is_empty(const path &p)
{
auto fs = status(p);
if (is_directory(fs))
return (directory_iterator() == directory_iterator(p));
return (file_size(p) == 0);
}
// bool is_empty(const path& p, error_code& ec) noexcept;
bool create_directories(const path& p); bool create_directories(const path &p);
//bool create_directories(const path& p, error_code& ec) noexcept;
bool create_directory(const path& p); //bool create_directories(const path& p, error_code& ec) noexcept;
//bool create_directory(const path& p, error_code& ec) noexcept; bool create_directory(const path &p);
bool create_directory(const path& p, const path& attributes);
//bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept; //bool create_directory(const path& p, error_code& ec) noexcept;
bool create_directory(const path &p, const path &attributes);
//bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept;
/// The time of last data modification of p, determined as if by the value of the POSIX /// The time of last data modification of p, determined as if by the value of the POSIX
/// stat structure member st_mtime obtained as if by POSIX stat(). /// stat structure member st_mtime obtained as if by POSIX stat().
file_time_type last_write_time(const path& p); file_time_type last_write_time(const path &p);
/// returns file_time_type::min() if an error occurs /// returns file_time_type::min() if an error occurs
//file_time_type last_write_time(const path& p, error_code& ec) noexcept; //file_time_type last_write_time(const path& p, error_code& ec) noexcept;
path current_path(); path current_path();
//path current_path(error_code& ec);
void current_path(const path& p); ///< chdir
//void current_path(const path& p, error_code& ec) noexcept;
bool remove(const path& p); //path current_path(error_code& ec);
bool remove(const path& p, std::error_code& ec); // noexcept; void current_path(const path &p); ///< chdir
//void current_path(const path& p, error_code& ec) noexcept;
//uintmax_t remove_all(const path& p); bool remove(const path &p);
//uintmax_t remove_all(const path& p, error_code& ec) noexcept;
template<typename CharType> bool remove(const path &p, std::error_code &ec); // noexcept;
std::basic_string<CharType> parent_path(const std::basic_string<CharType>& path)
{
auto index = path.size();
if (index) //uintmax_t remove_all(const path& p);
{ //uintmax_t remove_all(const path& p, error_code& ec) noexcept;
auto str = path.c_str();
for (--index; index > 0; --index) template<typename CharType>
{ std::basic_string<CharType> parent_path(const std::basic_string<CharType> &path)
auto c = str[index]; {
if (c != '\\' && c != '/') auto index = path.size();
break;
}
for (--index; index > 0; --index) if (index)
{ {
auto c = str[index]; auto str = path.c_str();
if (c == '\\' || c == '/')
break;
}
}
return index ? path.substr(0, index + 1) : std::basic_string<CharType>(); for (--index; index > 0; --index)
} {
#ifndef CXX_NO_INLINE_NAMESPACE auto c = str[index];
} //end namespace v1 if (c != '\\' && c != '/')
#endif break;
} //end namespace filesystem }
} //end namespace experimental
//namespace filesystem = experimental::filesystem; for (--index; index > 0; --index)
{
auto c = str[index];
if (c == '\\' || c == '/')
break;
}
}
return index ? path.substr(0, index + 1) : std::basic_string<CharType>();
}
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);
path weakly_canonical(const path& p);
path weakly_canonical(const path& p, std::error_code& err);
bool exists( file_status s ) noexcept;
bool exists( const path& p );
bool exists( const path& p, std::error_code& ec ) noexcept;
} //end namespace filesystem
} //end namespace nana } //end namespace nana
namespace std
namespace std { {
namespace experimental { namespace filesystem
namespace filesystem { {
#if defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703)
# ifdef CXX_NO_INLINE_NAMESPACE using namespace ::nana::filesystem;
using namespace nana::experimental::filesystem;
# 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);
path weakly_canonical(const path& p);
path weakly_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
#else #else
inline namespace nana_filesystem
{
using namespace ::nana::filesystem;
}
#endif
}
}
#else // not #if NANA_USING_NANA_FILESYSTEM and not BOOST_FILESYSTEM, also incomplete STD_FILESYSTEM
//Implements the missing functions for various version of experimental/filesystem //Implements the missing functions for various version of experimental/filesystem
# if defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM)
namespace std namespace std
{ {
namespace filesystem namespace filesystem
{ {
//Visual Studio 2017 #if defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703))
#if (defined(_MSC_VER) && (_MSC_VER > 1912)) || \ path absolute(const path& p);
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 801)) path absolute(const path& p, std::error_code& err);
path canonical(const path& p);
path canonical(const path& p, std::error_code& err);
path weakly_canonical(const path& p);
path weakly_canonical(const path& p, std::error_code& err);
#endif
/*
#if defined(NANA_MINGW) // todo ??
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
*/
//Visual Studio 2017
#if (defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM) && defined(_MSC_VER) && (_MSC_VER > 1912)) || \
(!defined(__clang__) && defined(__GNUC__) && (__cplusplus < 201603 || (__GNUC__* 100 + __GNUC_MINOR__ < 801)))
path weakly_canonical(const path& p); path weakly_canonical(const path& p);
path weakly_canonical(const path& p, std::error_code& err); path weakly_canonical(const path& p, std::error_code& err);
#endif #endif
} } // namespace filesystem
} } // namespace std
# endif
#endif //NANA_USING_NANA_FILESYSTEM #endif // incomplete STD_FILESYSTEM
#include <nana/pop_ignore_diagnostic> #include <nana/pop_ignore_diagnostic>
#endif //NANA_FILESYSTEM_HPP #endif //NANA_FILESYSTEM_HPP

View File

@ -1,13 +1,13 @@
/** /**
* Nana C++ Library(http://www.nanapro.org) * 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file nana\filesystem\filesystem_ext.hpp * @file nana\filesystem\filesystem_ext.hpp
* @autor by Ariel Vina-Rodriguez: * @autor Ariel Vina-Rodriguez:
* @brief Some convenient extensions to the filesystem library. * @brief Some convenient extensions to the filesystem library.
* *
*/ */
@ -15,8 +15,8 @@
#ifndef NANA_FILESYSTEM_EXT_HPP #ifndef NANA_FILESYSTEM_EXT_HPP
#define NANA_FILESYSTEM_EXT_HPP #define NANA_FILESYSTEM_EXT_HPP
#include <nana/filesystem/filesystem.hpp>
#include <nana/deploy.hpp> #include <nana/deploy.hpp>
#include <nana/filesystem/filesystem.hpp>
namespace nana namespace nana
{ {
@ -35,16 +35,6 @@ namespace filesystem_ext
std::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::filesystem::path& p)
{
#if NANA_USING_BOOST_FILESYSTEM
return nana::to_utf8(p.generic_wstring());
#else
return p.generic_u8string();
#endif
}
inline bool is_directory(const std::filesystem::directory_entry& dir) noexcept inline bool is_directory(const std::filesystem::directory_entry& dir) noexcept
{ {
return is_directory(dir.status()); return is_directory(dir.status());
@ -57,10 +47,10 @@ class directory_only_iterator : public std::filesystem::directory_iterator
directory_only_iterator& find_first() directory_only_iterator& find_first()
{ {
auto end = directory_only_iterator{}; directory_only_iterator end{};
while (*this != end) while (*this != end)
{ {
if (is_directory((**this).status())) if (is_directory((*(*this)).status()))
return *this; return *this;
this->directory_iterator::operator++(); this->directory_iterator::operator++();
} }

View File

@ -85,6 +85,7 @@ namespace nana
virtual void mouse_dropfiles(graph_reference, const arg_dropfiles&); virtual void mouse_dropfiles(graph_reference, const arg_dropfiles&);
virtual void focus(graph_reference, const arg_focus&); virtual void focus(graph_reference, const arg_focus&);
virtual void key_ime(graph_reference, const arg_ime&);
virtual void key_press(graph_reference, const arg_keyboard&); virtual void key_press(graph_reference, const arg_keyboard&);
virtual void key_char(graph_reference, const arg_keyboard&); virtual void key_char(graph_reference, const arg_keyboard&);
virtual void key_release(graph_reference, const arg_keyboard&); virtual void key_release(graph_reference, const arg_keyboard&);
@ -140,6 +141,7 @@ namespace nana
void resized(const arg_resized&, const bool); void resized(const arg_resized&, const bool);
void move(const arg_move&, const bool); void move(const arg_move&, const bool);
void focus(const arg_focus&, const bool); void focus(const arg_focus&, const bool);
void key_ime(const arg_ime& arg, const bool bForce__EmitInternal);
void key_press(const arg_keyboard&, const bool); void key_press(const arg_keyboard&, const bool);
void key_char(const arg_keyboard&, const bool); void key_char(const arg_keyboard&, const bool);
void key_release(const arg_keyboard&, const bool); void key_release(const arg_keyboard&, const bool);

View File

@ -34,6 +34,7 @@ namespace nana
unload, ///< A form is closed by clicking the X button, only works for root widget. unload, ///< A form is closed by clicking the X button, only works for root widget.
destroy, ///< A widget is about to be destroyed. destroy, ///< A widget is about to be destroyed.
focus, ///< A widget's focus is changed. focus, ///< A widget's focus is changed.
key_ime,
key_press, ///< A keyboard is pressed on a focus widget. key_press, ///< A keyboard is pressed on a focus widget.
key_char, ///< The focus widget received a character. key_char, ///< The focus widget received a character.
key_release, ///< A keyboard is released on a focus widget. key_release, ///< A keyboard is released on a focus widget.

View File

@ -466,6 +466,19 @@ namespace nana
reason focus_reason; ///< determines how the widget receives keyboard focus, it is ignored when 'getting' is equal to false reason focus_reason; ///< determines how the widget receives keyboard focus, it is ignored when 'getting' is equal to false
}; };
struct arg_ime: public event_arg
{
enum class reason
{
composition,
result
};
::nana::window window_handle; ///< A handle to the event window
reason ime_reason;
std::wstring composition_string;
};
struct arg_keyboard : public event_arg struct arg_keyboard : public event_arg
{ {
event_code evt_code; ///< it is event_code::key_press in current event event_code evt_code; ///< it is event_code::key_press in current event

View File

@ -17,7 +17,8 @@
#include <memory> #include <memory>
namespace nana namespace nana
{ {
class color_proxy /// a tool to share and set a color common to many uses
class color_proxy
{ {
public: public:
color_proxy(const color_proxy&); color_proxy(const color_proxy&);
@ -38,6 +39,7 @@ namespace nana
std::shared_ptr<color> color_; std::shared_ptr<color> color_;
};//end namespace color_proxy };//end namespace color_proxy
/// define common color and geometrical properties
struct widget_geometrics struct widget_geometrics
{ {
virtual ~widget_geometrics() = default; virtual ~widget_geometrics() = default;

View File

@ -1,13 +1,13 @@
/* /**
* A Message Box Class * A Message Box Class
* Nana C++ Library(http://www.nanapro.org) * 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/msgbox.hpp * @file nana/gui/msgbox.hpp
*/ */
#ifndef NANA_GUI_MSGBOX_HPP #ifndef NANA_GUI_MSGBOX_HPP
@ -81,8 +81,8 @@ namespace nana
return *this; return *this;
} }
/// \brief Displays the message that buffered in the stream. /// \brief Displays the message buffered in the stream.
/// @return, the button that user clicked. /// @return, the button the user clicked.
pick_t show() const; pick_t show() const;
/// A function object method alternative to show() /// A function object method alternative to show()
@ -98,6 +98,9 @@ namespace nana
icon_t icon_; icon_t icon_;
}; };
/// Simple convenience dialog to get values from the user.
///
/// The input value can be a boolean, string, a number, an option from a dropdown list or a date.
class inputbox class inputbox
{ {
struct abstract_content struct abstract_content
@ -110,6 +113,8 @@ namespace nana
}; };
public: public:
/// Shows a checkbox for boolean input
class boolean class boolean
: public abstract_content : public abstract_content
{ {
@ -128,6 +133,7 @@ namespace nana
std::unique_ptr<implement> impl_; std::unique_ptr<implement> impl_;
}; };
/// Integer input
class integer class integer
: public abstract_content : public abstract_content
{ {
@ -146,6 +152,7 @@ namespace nana
std::unique_ptr<implement> impl_; std::unique_ptr<implement> impl_;
}; };
/// Floating-point number input.
class real class real
: public abstract_content : public abstract_content
{ {
@ -164,6 +171,7 @@ namespace nana
std::unique_ptr<implement> impl_; std::unique_ptr<implement> impl_;
}; };
/// String input or an option from a dropdown list.
class text class text
: public abstract_content : public abstract_content
{ {
@ -192,6 +200,7 @@ namespace nana
std::unique_ptr<implement> impl_; std::unique_ptr<implement> impl_;
}; };
/// Date input
class date class date
: public abstract_content : public abstract_content
{ {
@ -214,6 +223,10 @@ namespace nana
std::unique_ptr<implement> impl_; std::unique_ptr<implement> impl_;
}; };
/// Path of a file.
///
/// The path requires an object of filebox. When the user clicks the `Browse` button,
/// it invokes the filebox with proper configurations to query a filename.
class path class path
: public abstract_content : public abstract_content
{ {
@ -231,11 +244,26 @@ namespace nana
std::unique_ptr<implement> impl_; std::unique_ptr<implement> impl_;
}; };
inputbox(window, ::std::string description, ::std::string title = ::std::string()); inputbox(window owner, ///< A handle to an owner window (just a parent form or widget works)
::std::string description, ///< tells users what the purpose for the input. It can be a formatted-text.
::std::string title = ::std::string() ///< The title for the inputbox.
);
void image(::nana::paint::image, bool is_left, const rectangle& valid_area = {}); /// shows images at left/right side of inputbox
void image_v(::nana::paint::image, bool is_top, const rectangle& valid_area = {}); void image(::nana::paint::image image, ///< The image
bool is_left, ///< true to place the image at left side, false to the right side
const rectangle& valid_area = {} ///< The area of the image to be displayed
);
/// shows images at top/bottom side of inputbox
void image_v(::nana::paint::image, ///< The image
bool is_top, ///< `true` to place the image at top side, `false` at bottom side
const rectangle& valid_area = {} ///< The area of the image to be displayed
);
/// Shows the inputbox and wait for the user input.
///
/// This method shows the inputbox without preventing the user interacts with other windows.
template<typename ...Args> template<typename ...Args>
bool show(Args&& ... args) bool show(Args&& ... args)
{ {
@ -251,7 +279,11 @@ namespace nana
return _m_open(contents, false); return _m_open(contents, false);
} }
template<typename ...Args> /// Shows the inputbox and wait for the user input blocking other windows.
///
/// This method blocks the execution and prevents user interaction with other
/// windows until the inputbox is closed.
template<typename ...Args>
bool show_modal(Args&& ... args) bool show_modal(Args&& ... args)
{ {
std::vector<abstract_content*> contents; std::vector<abstract_content*> contents;
@ -267,7 +299,7 @@ namespace nana
return _m_open(contents, true); return _m_open(contents, true);
} }
/// Sets a verifier to verify the user input. /// Sets a verifier to verify the user input, taking a handle to the inputbox.
void verify(std::function<bool(window)> verifier); void verify(std::function<bool(window)> verifier);
/** Sets the minimum width for the entry fields /** Sets the minimum width for the entry fields

View File

@ -395,7 +395,7 @@ namespace API
/// Blocks the execution and other windows' messages until the specified window is closed. /// Blocks the execution and other windows' messages until the specified window is closed.
void modal_window(window); void modal_window(window);
/// Blocks the execution until the specified window is closesd. /// Blocks the execution until the specified window is closed.
void wait_for(window); void wait_for(window);
color fgcolor(window); color fgcolor(window);

View File

@ -48,7 +48,7 @@ namespace nana
template<typename Function> template<typename Function>
void elapse(Function && fn) void elapse(Function && fn)
{ {
elapse_.connect(std::forward<Function>(fn)); elapse_->connect(std::forward<Function>(fn));
} }
void reset(); void reset();
@ -66,7 +66,7 @@ namespace nana
private: private:
unsigned _m_interval() const; unsigned _m_interval() const;
private: private:
nana::basic_event<arg_elapse> elapse_; std::shared_ptr<nana::basic_event<arg_elapse>> elapse_;
implement * const impl_; implement * const impl_;
}; };
}//end namespace nana }//end namespace nana

View File

@ -87,10 +87,10 @@ namespace nana{
typedef widget_object<category::widget_tag, drawerbase::button::trigger> base_type; typedef widget_object<category::widget_tag, drawerbase::button::trigger> base_type;
public: public:
button(); button();
button(window, bool visible); button(window parent, bool visible);
button(window, const ::std::string& caption, bool visible = true); button(window parent, const ::std::string& caption, bool visible = true);
button(window, const char* caption, bool visible = true); button(window parent, const char* caption, bool visible = true);
button(window, const nana::rectangle& = rectangle(), bool visible = true); button(window parent, const nana::rectangle& = rectangle(), bool visible = true);
/// Shows an icon in front of caption /// Shows an icon in front of caption
/** /**

View File

@ -65,6 +65,7 @@ namespace nana
void mouse_up(graph_reference, const arg_mouse&) override; void mouse_up(graph_reference, const arg_mouse&) override;
void mouse_move(graph_reference, const arg_mouse&) override; void mouse_move(graph_reference, const arg_mouse&) override;
void mouse_wheel(graph_reference, const arg_wheel&) override; void mouse_wheel(graph_reference, const arg_wheel&) override;
void key_ime(graph_reference, const arg_ime&) override;
void key_press(graph_reference, const arg_keyboard&) override; void key_press(graph_reference, const arg_keyboard&) override;
void key_char(graph_reference, const arg_keyboard&) override; void key_char(graph_reference, const arg_keyboard&) override;
private: private:

View File

@ -1,6 +1,6 @@
/* /*
* A Tree Container class implementation * A Tree Container class implementation
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -95,6 +95,13 @@ namespace detail
typedef tree_node<element_type> node_type; typedef tree_node<element_type> node_type;
typedef typename node_type::value_type value_type; typedef typename node_type::value_type value_type;
enum class enum_order
{
stop, //Stop enumeration
proceed_with_children,
proceed
};
tree_cont() tree_cont()
:root_(nullptr) :root_(nullptr)
{} {}
@ -234,59 +241,6 @@ namespace detail
return 0; return 0;
} }
template<typename Functor>
void for_each(node_type* node, Functor f)
{
if(nullptr == node) node = root_.child;
int state = 0; //0: Sibling, the last is a sibling of node
//1: Owner, the last is the owner of node
//>= 2: Children, the last is is a child of the node that before this node.
while(node)
{
switch(f(*node, state))
{
case 0: return;
case 1:
{
if(node->child)
{
node = node->child;
state = 1;
}
else
return;
continue;
}
break;
}
if(node->next)
{
node = node->next;
state = 0;
}
else
{
state = 1;
if(node == &root_) return;
while(true)
{
++state;
if(node->owner->next)
{
node = node->owner->next;
break;
}
else
node = node->owner;
if(node == &root_) return;
}
}
}
}
template<typename Functor> template<typename Functor>
void for_each(node_type* node, Functor f) const void for_each(node_type* node, Functor f) const
{ {
@ -296,24 +250,18 @@ namespace detail
//>= 2: Children, the last is is a child of the node that before this node. //>= 2: Children, the last is is a child of the node that before this node.
while(node) while(node)
{ {
switch(f(*node, state)) enum_order order = f(*node, state);
{
case 0: return;
case 1:
{
if(node->child)
{
node = node->child;
state = 1;
}
else
return;
continue;
}
break;
}
if(node->next) if (enum_order::stop == order)
{
return;
}
else if (node->child && (enum_order::proceed_with_children == order))
{
node = node->child;
state = 1;
}
else if(node->next)
{ {
node = node->next; node = node->next;
state = 0; state = 0;
@ -340,31 +288,37 @@ namespace detail
} }
} }
template<typename PredAllowChild> template<typename PredAllowChild, typename PredAllowNode>
unsigned child_size_if(const ::std::string& key, PredAllowChild pac) const unsigned child_size_if(const ::std::string& key, PredAllowChild pac, PredAllowNode pan) const
{ {
auto node = _m_locate(key); auto node = _m_locate(key);
return (node ? child_size_if<PredAllowChild>(*node, pac) : 0); return (node ? child_size_if<PredAllowChild, PredAllowNode>(*node, pac, pan) : 0);
} }
template<typename PredAllowChild> template<typename PredAllowChild, typename PredAllowNode>
unsigned child_size_if(const node_type& node, PredAllowChild pac) const unsigned child_size_if(const node_type& node, PredAllowChild pac, PredAllowNode pan) const
{ {
unsigned size = 0; unsigned size = 0;
const node_type* pnode = node.child; const node_type* pnode = node.child;
while(pnode) while(pnode)
{ {
if (!pan(*pnode))
{
pnode = pnode->next;
continue;
}
++size; ++size;
if(pnode->child && pac(*pnode)) if(pnode->child && pac(*pnode))
size += child_size_if<PredAllowChild>(*pnode, pac); size += child_size_if<PredAllowChild>(*pnode, pac, pan);
pnode = pnode->next; pnode = pnode->next;
} }
return size; return size;
} }
template<typename PredAllowChild> template<typename PredAllowChild, typename PredAllowNode>
std::size_t distance_if(const node_type * node, PredAllowChild pac) const std::size_t distance_if(const node_type * node, PredAllowChild pac, PredAllowNode pan) const
{ {
if(nullptr == node) return 0; if(nullptr == node) return 0;
const node_type * iterator = root_.child; const node_type * iterator = root_.child;
@ -374,6 +328,12 @@ namespace detail
while(iterator && iterator != node) while(iterator && iterator != node)
{ {
if (!pan(*iterator))
{
iterator = iterator->next;
continue;
}
++off; ++off;
if(iterator->child && pac(*iterator)) if(iterator->child && pac(*iterator))
@ -393,8 +353,8 @@ namespace detail
return off; return off;
} }
template<typename PredAllowChild> template<typename PredAllowChild, typename PredAllowNode>
node_type* advance_if(node_type* node, std::size_t off, PredAllowChild pac) node_type* advance_if(node_type* node, std::size_t off, PredAllowChild pac, PredAllowNode pan)
{ {
if(nullptr == node) node = root_.child; if(nullptr == node) node = root_.child;
@ -402,6 +362,12 @@ namespace detail
while(node && off) while(node && off)
{ {
if (!pan(*node))
{
node = node->next;
continue;
}
--off; --off;
if(node->child && pac(*node)) if(node->child && pac(*node))
{ {
@ -490,7 +456,7 @@ namespace detail
void _m_for_each(const ::std::string& key, Function function) const void _m_for_each(const ::std::string& key, Function function) const
{ {
//Ignores separaters at the begin of key. //Ignores separaters at the begin of key.
::std::string::size_type beg = key.find_first_not_of("\\/"); auto beg = key.find_first_not_of("\\/");
if (key.npos == beg) if (key.npos == beg)
return; return;

View File

@ -1,13 +1,13 @@
/** /**
* A Form Implementation * A Form Implementation
* Nana C++ Library(http://www.nanapro.org) * 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/form.hpp * @file nana/gui/widgets/form.hpp
*/ */
#ifndef NANA_GUI_WIDGET_FORM_HPP #ifndef NANA_GUI_WIDGET_FORM_HPP
@ -42,7 +42,7 @@ namespace nana
//place methods //place methods
place & get_place(); place & get_place();
void div(const char* div_text); void div(std::string div_text);
place::field_reference operator[](const char* field_name); place::field_reference operator[](const char* field_name);
void collocate() noexcept; void collocate() noexcept;
private: private:
@ -51,23 +51,30 @@ namespace nana
}//end namespace form }//end namespace form
}//end namespace drawerbase }//end namespace drawerbase
/// \brief Pop-up window. Is different from other window widgets: its default constructor creates the window. /// The form widget represents a popup window.
///
/// Overall it is a root widget (\see: Overview of widgets) which attaches the OS/Windowing system's native window.
/// It is different from other window widgets in that its default constructor creates the window.
/// \see nana::appearance /// \see nana::appearance
class form class form
: public drawerbase::form::form_base : public drawerbase::form::form_base
{ {
public: public:
/// helper template class for creating the appearance of the form.
using appear = ::nana::appear; using appear = ::nana::appear;
/// Creates a window at the point and size specified by rect, and with the specified appearance. Creates a form owned by the desktop. /// Creates a window form owned by the desktop, at the point and size specified by rect, and with the specified appearance.
form(const rectangle& = API::make_center(300, 200), const appearance& = {}); //Default constructor explicit form(const rectangle& = API::make_center(300, 200), const appearance& = {}); //Default constructor
form(const form&, const ::nana::size& = { 300, 200 }, const appearance& = {}); //Copy constructor /// Creates a window always floating above its owner at the point and size specified by rect, with the specified appearance. This window is always floating above its owner.
form(window, const ::nana::size& = { 300, 200 }, const appearance& = {}); explicit form(window owner, const ::nana::size& = { 300, 200 }, const appearance& = {});
/// Creates a window at the point and size specified by rect, with the specified appearance. This window is always floating above its owner. explicit form(window owner, const rectangle&, const appearance& = {});
form(window, const rectangle&, const appearance& = {}); form(const form&, const ::nana::size& = { 300, 200 }, const appearance& = {}); //Copy constructor
void modality() const; /// Blocks the execution and other windows' messages until this window is closed.
void wait_for_this(); void modality() const;
/// Blocks the execution until this window is closed.
void wait_for_this();
void keyboard_accelerator(const accel_key&, const std::function<void()>& fn); void keyboard_accelerator(const accel_key&, const std::function<void()>& fn);
}; };

View File

@ -47,10 +47,10 @@ namespace nana
class column_interface class column_interface
{ {
public: public:
/// Destructor // Destructor
virtual ~column_interface() = default; virtual ~column_interface() = default;
/// Returns the width of column, in pixel /// Returns the width of the column, in pixel
virtual unsigned width() const noexcept = 0; virtual unsigned width() const noexcept = 0;
/// Sets width /// Sets width
@ -824,6 +824,10 @@ namespace nana
/// Determines whether the item is displayed on the screen /// Determines whether the item is displayed on the screen
bool displayed() const; bool displayed() const;
/// Determines whether the item_proxy refers to invalid item.
/**
* @return true if the item_proxy refers to an invalid item, false otherwise.
*/
bool empty() const noexcept; bool empty() const noexcept;
/// Checks/unchecks the item /// Checks/unchecks the item
@ -1319,10 +1323,10 @@ the nana::detail::basic_window member pointer scheme
/// The output resolver that converts an item to an object /// The output resolver that converts an item to an object
using oresolver = drawerbase::listbox::oresolver; using oresolver = drawerbase::listbox::oresolver;
/// The representation of an item /// The representation of an item cell
using cell = drawerbase::listbox::cell; using cell = drawerbase::listbox::cell;
/// The options of exporting items into a string variable /// The options for exporting items into a string variable
using export_options = drawerbase::listbox::export_options; using export_options = drawerbase::listbox::export_options;
/// The interface for user-defined inline widgets /// The interface for user-defined inline widgets
@ -1332,12 +1336,12 @@ the nana::detail::basic_window member pointer scheme
using column_interface = drawerbase::listbox::column_interface; using column_interface = drawerbase::listbox::column_interface;
public: public:
/// Constructors // Constructors
listbox() = default; listbox() = default;
listbox(window, bool visible); listbox(window, bool visible);
listbox(window, const rectangle& = {}, bool visible = true); listbox(window, const rectangle& = {}, bool visible = true);
//Element access // Element access
/// Returns the category at specified location pos, with bounds checking. /// Returns the category at specified location pos, with bounds checking.
cat_proxy at(size_type pos); cat_proxy at(size_type pos);
@ -1356,7 +1360,7 @@ the nana::detail::basic_window member pointer scheme
item_proxy operator[](const index_pair& abs_pos); item_proxy operator[](const index_pair& abs_pos);
const item_proxy operator[](const index_pair &abs_pos) const; const item_proxy operator[](const index_pair &abs_pos) const;
//Associative category access // Associative category access
/// Returns a proxy to the category of the key or create a new one in the right order /// Returns a proxy to the category of the key or create a new one in the right order
/** /**
@ -1391,7 +1395,7 @@ the nana::detail::basic_window member pointer scheme
return cat_proxy(&_m_ess(), categ); return cat_proxy(&_m_ess(), categ);
} }
/// Removes a category which is associated with the specified key /// Removes the category associated with the specified key
/** /**
* @param key The key of category to remove * @param key The key of category to remove
*/ */
@ -1406,7 +1410,6 @@ the nana::detail::basic_window member pointer scheme
bool assoc_ordered(bool); bool assoc_ordered(bool);
void auto_draw(bool) noexcept; ///< Set state: Redraw automatically after an operation void auto_draw(bool) noexcept; ///< Set state: Redraw automatically after an operation
template<typename Function> template<typename Function>
@ -1432,15 +1435,17 @@ the nana::detail::basic_window member pointer scheme
void scroll(bool to_bottom, const index_pair& abs_pos); void scroll(bool to_bottom, const index_pair& abs_pos);
/// Appends a new column with a header text and the specified width at the end, and return it position /// Appends a new column with a header text and the specified width at the end, and return it position
///
/// If a width of 0 is passed the width will be set to fit the header text.
size_type append_header(std::string text_utf8, unsigned width = 120); size_type append_header(std::string text_utf8, unsigned width = 120);
size_type append_header(std::wstring text, unsigned width = 120); size_type append_header(std::wstring text, unsigned width = 120);
void clear_headers(); ///< Removes all the columns. void clear_headers(); ///< Removes all the columns.
cat_proxy append(std::string category); ///< Appends a new category to the end cat_proxy append(std::string category); ///< Appends a new category to the end
cat_proxy append(std::wstring category); ///< Appends a new category to the end cat_proxy append(std::wstring category); ///< Appends a new category to the end
void append(std::initializer_list<std::string> categories); ///< Appends categories to the end void append(std::initializer_list<std::string> categories); ///< Appends categories to the end
void append(std::initializer_list<std::wstring> categories); ///< Appends categories to the end void append(std::initializer_list<std::wstring> categories); ///< Appends categories to the end
/// Access a column at specified position /// Access a column at specified position
/** /**
@ -1480,7 +1485,7 @@ the nana::detail::basic_window member pointer scheme
void column_movable(bool); void column_movable(bool);
bool column_movable() const; bool column_movable() const;
/// Returns a rectangle in where the content is drawn. /// Returns the rectangle where the content is drawn.
rectangle content_area() const; rectangle content_area() const;
cat_proxy insert(cat_proxy, ::std::string); cat_proxy insert(cat_proxy, ::std::string);
@ -1489,7 +1494,7 @@ the nana::detail::basic_window member pointer scheme
/// Inserts an item before a specified position /// Inserts an item before a specified position
/** /**
* @param abs_pos The absolute position before which an item will be inserted. * @param abs_pos The absolute position before which an item will be inserted.
* @param text Text of the first column, in UTF-8 encoded. * @param text Text of the first column, UTF-8 encoded.
*/ */
void insert_item(const index_pair& abs_pos, ::std::string text); void insert_item(const index_pair& abs_pos, ::std::string text);
@ -1503,46 +1508,54 @@ the nana::detail::basic_window member pointer scheme
void insert_item(index_pair abs_pos, const listbox& rhs, const index_pairs& indexes); void insert_item(index_pair abs_pos, const listbox& rhs, const index_pairs& indexes);
/// Returns an index of item which contains the specified point. /// Returns the index pair of the item which contains the specified "screen" point.
index_pair cast(const point & screen_pos) const; index_pair cast(const point & screen_pos) const;
/// Returns the item which is hovered /// 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. * @param return_end Indicates whether to return an end position instead of an empty position if no item is 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. * @return The position of the hovered item. If return_end is true and no item is hovered it returns the position next to the last item of last category.
*/ */
index_pair hovered(bool return_end) const; index_pair hovered(bool return_end) const;
/// Returns the absolute position of column which contains the specified point. /// Returns the absolute position of the column which contains the specified "screen" point.
size_type column_from_pos(const point & pos) const; size_type column_from_pos(const point & screen_pos) const;
void checkable(bool); void checkable(bool make_checkeable); ///< Display a checkbox at te links of each item if make_checkeable=true
index_pairs checked() const; ///<Returns the items which are checked. index_pairs checked() const; ///< Returns all the items which are checked.
void clear(size_type cat); ///<Removes all the items from the specified category void clear(size_type cat); ///< Removes all the items from the specified category
void clear(); ///<Removes all the items from all categories void clear(); ///< Removes all the items from all categories
void erase(size_type cat); ///<Erases a category void erase(size_type cat); ///< Erases a category
void erase(); ///<Erases all categories. void erase(); ///< Erases all categories.
void erase(index_pairs indexes); ///<Erases specified items. void erase(index_pairs indexes); ///< Erases specified items.
item_proxy erase(item_proxy); item_proxy erase(item_proxy indx); ///< Erases specified item.
bool sortable() const; bool sortable() const; ///< return whether the listbox is set to be sortable
void sortable(bool enable); void sortable(bool enable); ///< set the listbox to be or not to be sortable
///Sets a strict weak ordering comparer for a column ///Sets a strict weak ordering comparer for a column
void set_sort_compare( size_type col, void set_sort_compare( size_type col,
std::function<bool(const std::string&, nana::any*, std::function<bool(const std::string&, nana::any*,
const std::string&, nana::any*, bool reverse)> strick_ordering); const std::string&, nana::any*, bool reverse)> strick_ordering);
/// sort() and invalidates any existing reference from display position to absolute item, that is: after sort() display offset point to different items /// Sort the items using the specified column.
///
/// Invalidates 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); void sort_col(size_type col, bool reverse = false);
size_type sort_col() const; size_type sort_col() const; ///< return the column currently used to sort items
/// potentially invalidates any existing reference from display position to absolute item, that is: after sort() display offset point to different items /// Eliminate any "column sorting", effectively setting the items in the order of creation.
///
/// Potentially invalidates any existing reference from display position to absolute item,
/// that is: after unsort() display offset may point to different items
void unsort(); void unsort();
///< Prevent sorting until `freeze` is set to false.
bool freeze_sort(bool freeze); bool freeze_sort(bool freeze);
index_pairs selected() const; ///<Get the absolute indexs of all the selected items index_pairs selected() const; ///<Get the absolute indexes of all the selected items
void show_header(bool); void show_header(bool);
bool visible_header() const; bool visible_header() const;
@ -1554,7 +1567,7 @@ the nana::detail::basic_window member pointer scheme
void enable_single(bool for_selection, bool category_limited); void enable_single(bool for_selection, bool category_limited);
void disable_single(bool for_selection); void disable_single(bool for_selection);
bool is_single_enabled(bool for_selection) const noexcept; ///< Determines whether the single selection/check is enabled. bool is_single_enabled(bool for_selection) const noexcept; ///< Determines whether the single selection/check is enabled.
export_options& def_export_options(); export_options& def_export_options(); ///< return a modifiable reference to the export options in use
/// Sets a renderer for category icon /// Sets a renderer for category icon

View File

@ -98,6 +98,7 @@ namespace nana{ namespace widgets
void set_accept(std::function<bool(char_type)>); void set_accept(std::function<bool(char_type)>);
void set_accept(accepts); void set_accept(accepts);
bool respond_ime(const arg_ime& arg);
bool respond_char(const arg_keyboard& arg); bool respond_char(const arg_keyboard& arg);
bool respond_key(const arg_keyboard& arg); bool respond_key(const arg_keyboard& arg);
@ -328,6 +329,8 @@ namespace nana{ namespace widgets
nana::upoint caret; //position of caret by text, it specifies the position of a new character nana::upoint caret; //position of caret by text, it specifies the position of a new character
nana::upoint shift_begin_caret; nana::upoint shift_begin_caret;
}points_; }points_;
size_t composition_size_ { 0 };
}; };
}//end namespace skeletons }//end namespace skeletons
}//end namespace widgets }//end namespace widgets

View File

@ -66,6 +66,7 @@ namespace nana
void mouse_move(graph_reference, const arg_mouse&) override; void mouse_move(graph_reference, const arg_mouse&) override;
void mouse_up(graph_reference, const arg_mouse& arg) override; void mouse_up(graph_reference, const arg_mouse& arg) override;
void mouse_leave(graph_reference, const arg_mouse&) override; void mouse_leave(graph_reference, const arg_mouse&) override;
void key_ime(graph_reference, const arg_ime& arg) override;
void key_press(graph_reference, const arg_keyboard&) override; void key_press(graph_reference, const arg_keyboard&) override;
void key_char(graph_reference, const arg_keyboard&) override; void key_char(graph_reference, const arg_keyboard&) override;
void resized(graph_reference, const arg_resized&) override; void resized(graph_reference, const arg_resized&) override;

View File

@ -83,6 +83,7 @@ namespace nana
void mouse_enter(graph_reference, const arg_mouse&) override; void mouse_enter(graph_reference, const arg_mouse&) override;
void mouse_leave(graph_reference, const arg_mouse&) override; void mouse_leave(graph_reference, const arg_mouse&) override;
void dbl_click(graph_reference, const arg_mouse&) override; void dbl_click(graph_reference, const arg_mouse&) override;
void key_ime(graph_reference, const arg_ime&) override;
void key_press(graph_reference, const arg_keyboard&)override; void key_press(graph_reference, const arg_keyboard&)override;
void key_char(graph_reference, const arg_keyboard&) override; void key_char(graph_reference, const arg_keyboard&) override;
void mouse_wheel(graph_reference, const arg_wheel&) override; void mouse_wheel(graph_reference, const arg_wheel&) override;

View File

@ -1,7 +1,7 @@
/** /**
* A Tree Box Implementation * A Tree Box Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at * (See accompanying file LICENSE or copy at
@ -49,7 +49,7 @@ namespace nana
struct node_attribute struct node_attribute
{ {
bool has_children; bool has_children; ///< Determines whether the node has visible children
bool expended; bool expended;
checkstate checked; checkstate checked;
bool selected; bool selected;
@ -117,6 +117,7 @@ namespace nana
::std::string text; ::std::string text;
nana::any value; nana::any value;
bool expanded; bool expanded;
bool hidden;
checkstate checked; checkstate checked;
::std::string img_idstr; ::std::string img_idstr;
}; };
@ -218,6 +219,12 @@ namespace nana
/// Select the node, and returns itself.. /// Select the node, and returns itself..
item_proxy& select(bool); item_proxy& select(bool);
/// Return true when the node is hidden.
bool hidden() const;
/// Hide the node, and returns itself.
item_proxy& hide(bool);
/// Return the icon. /// Return the icon.
const ::std::string& icon() const; const ::std::string& icon() const;
@ -343,6 +350,7 @@ namespace nana
basic_event<arg_treebox> checked; ///< a user checks or unchecks a node basic_event<arg_treebox> checked; ///< a user checks or unchecks a node
basic_event<arg_treebox> selected; ///< a user selects or unselects a node basic_event<arg_treebox> selected; ///< a user selects or unselects a node
basic_event<arg_treebox> hovered; ///< a user moves the cursor over a node basic_event<arg_treebox> hovered; ///< a user moves the cursor over a node
basic_event<arg_treebox> hidden; ///< a user hides or shows a node
}; };
}//end namespace treebox }//end namespace treebox
}//end namespace drawerbase }//end namespace drawerbase
@ -484,6 +492,14 @@ namespace nana
/// Gets the current hovered node. /// Gets the current hovered node.
item_proxy hovered(bool exclude_expander) const; item_proxy hovered(bool exclude_expander) const;
/// Enable/disable the interactions (selection, click, ...) on the entire line of the treebox.
/**
* @param enable bool whether to enable.
*/
void use_entire_line(bool enable);
private: private:
std::shared_ptr<scroll_operation_interface> _m_scroll_operation() override; std::shared_ptr<scroll_operation_interface> _m_scroll_operation() override;

View File

@ -7,7 +7,7 @@
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/widget.hpp * @file nana/gui/widgets/widget.hpp
*/ */
#ifndef NANA_GUI_WIDGET_HPP #ifndef NANA_GUI_WIDGET_HPP
@ -48,8 +48,8 @@ namespace nana
widget() = default; widget() = default;
virtual ~widget() = default; virtual ~widget() = default;
virtual window handle() const = 0; ///< Returns the handle of window, returns 0 if window is not created. virtual window handle() const = 0; ///< Returns the handle of window, returns 0 if window is not created.
bool empty() const; ///< Determines whether the manipulator is handling a window. bool empty() const; ///< Determines whether the manipulator is handling a window.
void close(); void close();
window parent() const; window parent() const;
@ -169,9 +169,17 @@ namespace nana
}; };
} }
/// Base class of all the classes defined as a widget window. Defaultly a widget_tag /// Base class of all the classes defined as a widget window. Defaultly a widget_tag
template<typename Category, typename DrawerTrigger, typename Events = ::nana::general_events, typename Scheme = ::nana::widget_geometrics, ///
typename = typename std::enable_if<std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value>::type> //type DrawerTrigger must be derived from nana::drawer_trigger /// \tparam Category
/// \tparam DrawerTrigger must be derived from nana::drawer_trigger
/// \tparam Events
/// \tparam Scheme
template<typename Category,
typename DrawerTrigger,
typename Events = ::nana::general_events,
typename Scheme = ::nana::widget_geometrics,
typename = typename std::enable_if<std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value>::type>
class widget_object: public detail::widget_base class widget_object: public detail::widget_base
{ {
protected: protected:
@ -293,8 +301,13 @@ namespace nana
std::unique_ptr<scheme_type> scheme_; std::unique_ptr<scheme_type> scheme_;
};//end class widget_object };//end class widget_object
/// Base class of all the classes defined as a non-graphics-buffer widget window. The second template parameter DrawerTrigger is always ignored.\see nana::panel /// Base class of all the classes defined as a non-graphics-buffer widget window.
template<typename DrawerTrigger, typename Events, typename Scheme> //type DrawerTrigger must be derived from nana::drawer_trigger ///
/// The second template parameter DrawerTrigger is always ignored.\see nana::panel
/// type DrawerTrigger must be derived from nana::drawer_trigger
template<typename DrawerTrigger,
typename Events,
typename Scheme>
class widget_object<category::lite_widget_tag, DrawerTrigger, Events, Scheme>: public detail::widget_base class widget_object<category::lite_widget_tag, DrawerTrigger, Events, Scheme>: public detail::widget_base
{ {
protected: protected:
@ -359,8 +372,14 @@ namespace nana
};//end class widget_object };//end class widget_object
/// Base class of all the classes defined as a root window. \see nana::form /// Base class of all the classes defined as a root window. \see nana::form
template<typename DrawerTrigger, typename Events, typename Scheme> //type DrawerTrigger must be derived from nana::drawer_trigger ///
/// \tparam DrawerTrigger must be derived from nana::drawer_trigger
/// \tparam Events
/// \tparam Scheme
template<typename DrawerTrigger,
typename Events,
typename Scheme>
class widget_object<category::root_tag, DrawerTrigger, Events, Scheme>: public detail::widget_base class widget_object<category::root_tag, DrawerTrigger, Events, Scheme>: public detail::widget_base
{ {
protected: protected:

View File

@ -1,7 +1,7 @@
/** /**
* A Character Encoding Set Implementation * A Character Encoding Set Implementation
* Nana C++ Library(http://www.nanapro.org) * 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -245,8 +245,12 @@ namespace nana
int bytes = ::WideCharToMultiByte(CP_ACP, 0, s, -1, 0, 0, 0, 0); int bytes = ::WideCharToMultiByte(CP_ACP, 0, s, -1, 0, 0, 0, 0);
if(bytes > 1) if(bytes > 1)
{ {
mbstr.resize(bytes - 1); // the bytes is the length of the string with null character.
::WideCharToMultiByte(CP_ACP, 0, s, -1, &(mbstr[0]), bytes - 1, 0, 0); mbstr.resize(bytes);
::WideCharToMultiByte(CP_ACP, 0, s, -1, &(mbstr[0]), bytes, 0, 0);
//Remove the null character written by WideCharToMultiByte
mbstr.pop_back();
} }
return true; return true;
#else #else
@ -279,8 +283,12 @@ namespace nana
int chars = ::MultiByteToWideChar(CP_ACP, 0, s, -1, 0, 0); int chars = ::MultiByteToWideChar(CP_ACP, 0, s, -1, 0, 0);
if(chars > 1) if(chars > 1)
{ {
wcstr.resize(chars - 1); // the length of the string with null character.
::MultiByteToWideChar(CP_ACP, 0, s, -1, &wcstr[0], chars - 1); wcstr.resize(chars);
::MultiByteToWideChar(CP_ACP, 0, s, -1, &wcstr[0], chars);
// remove the null character written by MultiByteToWideChar
wcstr.pop_back();
} }
#else #else
locale_initializer::init(); locale_initializer::init();

View File

@ -1,4 +1,4 @@
/* /**
* A ISO C++ FileSystem Implementation * A ISO C++ FileSystem Implementation
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
* *
@ -6,16 +6,17 @@
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/filesystem/filesystem.cpp * @file nana/filesystem/filesystem.cpp
* @description: * @description
* provide some interface for file management * provide some interface for file management
*/ */
#include <nana/config.hpp>
#include <nana/filesystem/filesystem_ext.hpp> #include <nana/filesystem/filesystem_ext.hpp>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <string>
#include <nana/config.hpp>
#ifdef _nana_std_put_time #ifdef _nana_std_put_time
#include <nana/stdc++.hpp> #include <nana/stdc++.hpp>
#else #else
@ -148,45 +149,41 @@ namespace nana
} }
} }
#if NANA_USING_NANA_FILESYSTEM #if NANA_USING_NANA_FILESYSTEM // and BOOST ?
namespace nana_fs = nana::experimental::filesystem; namespace nana_fs = nana::filesystem;
namespace nana
{
namespace filesystem
{
//class filesystem_error
filesystem_error::filesystem_error(const std::string& msg, std::error_code err)
: std::system_error(err, msg)
{}
namespace nana { namespace experimental { namespace filesystem filesystem_error::filesystem_error(const std::string& msg, const path& path1, std::error_code err)
{ : std::system_error(err, msg),
#ifndef CXX_NO_INLINE_NAMESPACE path1_(path1)
inline namespace v1 { {}
#endif
//class filesystem_error filesystem_error::filesystem_error(const std::string& msg, const path& path1, const path& path2, std::error_code err)
filesystem_error::filesystem_error(const std::string& msg, std::error_code err) : std::system_error(err, msg),
: std::system_error(err, msg) path1_(path1),
{} path2_(path2)
{}
filesystem_error::filesystem_error(const std::string& msg, const path& path1, std::error_code err) const path& filesystem_error::path1() const noexcept
: std::system_error(err, msg), {
path1_(path1) return path1_;
{} }
filesystem_error::filesystem_error(const std::string& msg, const path& path1, const path& path2, std::error_code err) const path& filesystem_error::path2() const noexcept
: std::system_error(err, msg), {
path1_(path1), return path2_;
path2_(path2) }
{} //end class filesystem_error
const path& filesystem_error::path1() const noexcept //Because of No wide character version of POSIX
{
return path1_;
}
const path& filesystem_error::path2() const noexcept
{
return path2_;
}
//end class filesystem_error
//Because of No wide character version of POSIX
#if defined(NANA_POSIX) #if defined(NANA_POSIX)
const char* separators = "/"; const char* separators = "/";
const char separator = '/'; const char separator = '/';
@ -512,10 +509,10 @@ namespace nana { namespace experimental { namespace filesystem
return to_wstring(pathstr_); return to_wstring(pathstr_);
} }
std::string path::u8string() const /*std::string path::u8string() const
{ {
return to_utf8(pathstr_); return to_utf8(pathstr_);
} }*/
std::string path::generic_string() const std::string path::generic_string() const
{ {
auto str = string(); auto str = string();
@ -528,12 +525,12 @@ namespace nana { namespace experimental { namespace filesystem
std::replace(str.begin(), str.end(), L'\\', L'/'); std::replace(str.begin(), str.end(), L'\\', L'/');
return str; return str;
} }
std::string path::generic_u8string() const // uppss ... /*std::string path::generic_u8string() const // uppss ...
{ {
auto str = pathstr_; auto str = pathstr_;
std::replace(str.begin(), str.end(), '\\', '/'); // uppss ... revise this !!!!! std::replace(str.begin(), str.end(), '\\', '/'); // uppss ... revise this !!!!!
return to_utf8(str); return to_utf8(str);
} }*/
path path::lexically_normal() const path path::lexically_normal() const
{ {
@ -667,7 +664,7 @@ namespace nana { namespace experimental { namespace filesystem
} }
//class directory_entry //class directory_entry
directory_entry::directory_entry(const nana_fs::path& p) directory_entry::directory_entry(const filesystem::path& p)
:path_{ p } :path_{ p }
{} {}
@ -713,112 +710,112 @@ namespace nana { namespace experimental { namespace filesystem
} }
}; };
directory_iterator::directory_iterator() noexcept directory_iterator::directory_iterator() noexcept
: end_(true), : end_(true),
handle_(nullptr) handle_(nullptr)
{} {}
directory_iterator::directory_iterator(const path& file_path) directory_iterator::directory_iterator(const path& file_path)
{ {
_m_prepare(file_path); _m_prepare(file_path);
} }
directory_iterator::directory_iterator(const path& p, directory_options opt): directory_iterator::directory_iterator(const path& p, directory_options opt):
option_(opt) option_(opt)
{ {
_m_prepare(p); _m_prepare(p);
} }
const directory_iterator::value_type& directory_iterator::operator*() const { return value_; } const directory_iterator::value_type& directory_iterator::operator*() const { return value_; }
const directory_iterator::value_type* const directory_iterator::value_type*
directory_iterator::operator->() const { return &(operator*()); } directory_iterator::operator->() const { return &(operator*()); }
directory_iterator& directory_iterator::operator++() directory_iterator& directory_iterator::operator++()
{ {
_m_read(); return *this; _m_read(); return *this;
} }
directory_iterator directory_iterator::operator++(int) directory_iterator directory_iterator::operator++(int)
{ {
directory_iterator tmp = *this; directory_iterator tmp = *this;
_m_read(); _m_read();
return tmp; return tmp;
} }
bool directory_iterator::equal(const directory_iterator& x) const bool directory_iterator::equal(const directory_iterator& x) const
{ {
if (end_ && (end_ == x.end_)) return true; if (end_ && (end_ == x.end_)) return true;
return (value_.path().filename() == x.value_.path().filename()); return (value_.path().filename() == x.value_.path().filename());
} }
void directory_iterator::_m_prepare(const path& file_path) void directory_iterator::_m_prepare(const path& file_path)
{ {
path_ = file_path.native(); path_ = file_path.native();
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
if (!path_.empty() && (path_.back() != L'/' && path_.back() != L'\\')) if (!path_.empty() && (path_.back() != L'/' && path_.back() != L'\\'))
path_ += L'\\'; path_ += L'\\';
auto pat = path_; auto pat = path_;
DWORD attr = ::GetFileAttributes(pat.data()); DWORD attr = ::GetFileAttributes(pat.data());
if ((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY)) if ((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY))
pat += L"*"; pat += L"*";
WIN32_FIND_DATAW wfd; WIN32_FIND_DATAW wfd;
::HANDLE handle = ::FindFirstFile(pat.data(), &wfd); ::HANDLE handle = ::FindFirstFile(pat.data(), &wfd);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
{ {
end_ = true; end_ = true;
return; return;
} }
while (_m_ignore(wfd.cFileName)) while (_m_ignore(wfd.cFileName))
{ {
if (::FindNextFile(handle, &wfd) == 0) if (::FindNextFile(handle, &wfd) == 0)
{ {
end_ = true; end_ = true;
::FindClose(handle); ::FindClose(handle);
return; return;
} }
} }
value_ = value_type(path(path_ + wfd.cFileName)); value_ = value_type(path(path_ + wfd.cFileName));
#elif defined(NANA_POSIX) #elif defined(NANA_POSIX)
if (path_.size() && (path_.back() != '/')) if (path_.size() && (path_.back() != '/'))
path_ += '/'; path_ += '/';
auto handle = opendir(path_.c_str()); auto handle = opendir(path_.c_str());
end_ = true; end_ = true;
if (handle) if (handle)
{ {
struct dirent * dnt = readdir(handle); struct dirent * dnt = readdir(handle);
if (dnt) if (dnt)
{ {
while (_m_ignore(dnt->d_name)) while (_m_ignore(dnt->d_name))
{ {
dnt = readdir(handle); dnt = readdir(handle);
if (dnt == 0) if (dnt == 0)
{ {
closedir(handle); closedir(handle);
return; return;
} }
} }
value_ = value_type(path_ + dnt->d_name); value_ = value_type(path_ + dnt->d_name);
end_ = false; end_ = false;
} }
} }
#endif #endif
if (false == end_) if (false == end_)
{ {
find_ptr_ = std::shared_ptr<find_handle>(new find_handle(handle), inner_handle_deleter()); find_ptr_ = std::shared_ptr<find_handle>(new find_handle(handle), inner_handle_deleter());
handle_ = handle; handle_ = handle;
} }
} }
void directory_iterator::_m_read() void directory_iterator::_m_read()
{ {
if (handle_) if (handle_)
{ {
@ -978,7 +975,6 @@ namespace nana { namespace experimental { namespace filesystem
#endif #endif
}//end namespace detail }//end namespace detail
file_status status(const path& p) file_status status(const path& p)
{ {
std::error_code err; std::error_code err;
@ -1108,93 +1104,290 @@ namespace nana { namespace experimental { namespace filesystem
return dateTime; return dateTime;
} }
bool create_directory(const path& p) bool create_directory(const path& p)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
return (FALSE != ::CreateDirectoryW(p.c_str(), 0)); return (FALSE != ::CreateDirectoryW(p.c_str(), 0));
#elif defined(NANA_POSIX) #elif defined(NANA_POSIX)
return (0 == ::mkdir(p.c_str(), static_cast<int>(perms::all))); return (0 == ::mkdir(p.c_str(), static_cast<int>(perms::all)));
#endif #endif
} }
bool remove(const path& p) bool remove(const path& p)
{ {
auto stat = status(p); auto stat = status(p);
if (stat.type() == file_type::directory) if (stat.type() == file_type::directory)
return detail::rm_dir(p); return detail::rm_dir(p);
return detail::rm_file(p); return detail::rm_file(p);
} }
bool remove(const path& p, std::error_code & ec) bool remove(const path& p, std::error_code & ec)
{ {
ec.clear(); ec.clear();
auto stat = status(p); auto stat = status(p);
if (stat.type() == file_type::directory) if (stat.type() == file_type::directory)
return detail::rm_dir(p); return detail::rm_dir(p);
return detail::rm_file(p); return detail::rm_file(p);
} }
path current_path() path current_path()
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
wchar_t buf[MAX_PATH]; wchar_t buf[MAX_PATH];
DWORD len = ::GetCurrentDirectoryW(MAX_PATH, buf); DWORD len = ::GetCurrentDirectoryW(MAX_PATH, buf);
if (len) if (len)
{ {
if (len > MAX_PATH) if (len > MAX_PATH)
{ {
wchar_t * p = new wchar_t[len + 1]; wchar_t * p = new wchar_t[len + 1];
::GetCurrentDirectoryW(len + 1, p); ::GetCurrentDirectoryW(len + 1, p);
std::wstring s = p; std::wstring s = p;
delete[] p; delete[] p;
return s; return s;
} }
return buf; return buf;
} }
#elif defined(NANA_POSIX) #elif defined(NANA_POSIX)
char buf[260]; char buf[260];
auto pstr = ::getcwd(buf, 260); auto pstr = ::getcwd(buf, 260);
if (pstr) if (pstr)
return pstr; return pstr;
int bytes = 260 + 260; int bytes = 260 + 260;
while (ERANGE == errno) while (ERANGE == errno)
{ {
std::unique_ptr<char[]> buf(new char[bytes]); std::unique_ptr<char[]> buf(new char[bytes]);
auto pstr = ::getcwd(buf.get(), bytes); auto pstr = ::getcwd(buf.get(), bytes);
if (pstr) if (pstr)
return path(pstr); return path(pstr);
bytes += 260; bytes += 260;
} }
#endif #endif
return path(); return path();
} }
void current_path(const path& p) void current_path(const path& p)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::SetCurrentDirectoryW(p.c_str()); ::SetCurrentDirectoryW(p.c_str());
#elif defined(NANA_POSIX) #elif defined(NANA_POSIX)
::chdir(p.c_str()); ::chdir(p.c_str());
#endif #endif
} }
#ifndef CXX_NO_INLINE_NAMESPACE path absolute(const path& p)
} //end namespace v1 {
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 #endif
}//end namespace filesystem return base_root_name / p;
} //end namespace experimental }
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,
std::error_code(static_cast<int>(std::errc::no_such_file_or_directory), std::generic_category())));
err->assign(static_cast<int>(std::errc::no_such_file_or_directory), std::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);
}
bool try_throw(int err_val, const path& p, std::error_code* ec, const char* message)
{
if (0 == err_val)
{
if (ec) ec->clear();
}
else
{ //error
if (nullptr == ec)
throw (filesystem_error(
message, p,
std::error_code(err_val, std::generic_category())));
else
ec->assign(err_val, std::system_category());
}
return err_val != 0;
}
path weakly_canonical(const path& p, std::error_code* err)
{
path head{ p };
std::error_code tmp_err;
std::vector<path> elements;
while (!head.empty())
{
auto head_status = status(head, tmp_err);
if (head_status.type() == file_type::unknown)
{
if (try_throw(static_cast<int>(std::errc::invalid_argument), head, err, "nana::filesystem::weakly_canonical"))
return path{};
}
if (head_status.type() != file_type::not_found)
break;
elements.emplace_back(head.filename());
head.remove_filename();
}
bool tail_has_dots = false;
path tail;
for (auto & e : elements)
{
tail /= e;
// for a later optimization, track if any dot or dot-dot elements are present
if (e.native().size() <= 2
&& e.native()[0] == '.'
&& (e.native().size() == 1 || e.native()[1] == '.'))
tail_has_dots = true;
}
if (head.empty())
return p.lexically_normal();
head = canonical(head, tmp_err);
if (try_throw(tmp_err.value(), head, err, "nana::filesystem::weakly_canonical"))
return path();
return tail.empty()
? head
: (tail_has_dots // optimization: only normalize if tail had dot or dot-dot element
? (head / tail).lexically_normal()
: head / tail);
}
path weakly_canonical(const path& p)
{
return weakly_canonical(p, nullptr);
}
path weakly_canonical(const path& p, std::error_code& err)
{
return weakly_canonical(p, &err);
}
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));
}
} //end namespace filesystem
}//end namespace nana }//end namespace nana
#else
namespace std namespace std
{ {
namespace filesystem namespace filesystem
{ {
#if defined(NANA_FILESYSTEM_FORCE) || \ #if defined(_MSC_VER) && (_MSC_VER < 1900) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703))
(defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)))
path absolute(const path& p) path absolute(const path& p)
{ {
if (p.empty()) if (p.empty())
@ -1379,8 +1572,8 @@ namespace std
return weakly_canonical(p, &err); return weakly_canonical(p, &err);
} }
#endif #endif
/*
#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW) #if defined(NANA_MINGW)
bool exists( std::filesystem::file_status s ) noexcept bool exists( std::filesystem::file_status s ) noexcept
{ {
return s.type() != file_type::not_found; return s.type() != file_type::not_found;
@ -1395,20 +1588,10 @@ namespace std
{ {
return exists(status(p, ec)); return exists(status(p, ec));
} }
#endif */
}//end namespace filesystem
}//end namespace std
#else //NANA_USING_NANA_FILESYSTEM #if (defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM) && defined(_MSC_VER) && (_MSC_VER > 1912)) || \
# if defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM) (!defined(__clang__) && defined(__GNUC__) && (__cplusplus < 201603 || (__GNUC__* 100 + __GNUC_MINOR__ < 801)))
//Defines the functions that are not provided by experimental/filesystem
namespace std
{
namespace filesystem
{
#if (defined(_MSC_VER) && (_MSC_VER > 1912)) || \
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 801))
namespace detail namespace detail
{ {
@ -1551,10 +1734,9 @@ namespace std
{ {
return weakly_canonical(p, &err); return weakly_canonical(p, &err);
} }
#endif #endif
} }//end namespace filesystem
} }//end namespace std
# endif
#endif //NANA_USING_NANA_FILESYSTEM #endif //NANA_USING_NANA_FILESYSTEM

View File

@ -622,6 +622,7 @@ namespace detail
} }
break; break;
case ConfigureNotify: case ConfigureNotify:
++(root_runtime->x11msg.config);
if(msgwnd->dimension.width != static_cast<unsigned>(xevent.xconfigure.width) || msgwnd->dimension.height != static_cast<unsigned>(xevent.xconfigure.height)) if(msgwnd->dimension.width != static_cast<unsigned>(xevent.xconfigure.width) || msgwnd->dimension.height != static_cast<unsigned>(xevent.xconfigure.height))
{ {
auto & cf = xevent.xconfigure; auto & cf = xevent.xconfigure;
@ -890,7 +891,12 @@ namespace detail
case MapNotify: case MapNotify:
case UnmapNotify: case UnmapNotify:
if(xevent.type == MapNotify) if(xevent.type == MapNotify)
{
++(root_runtime->x11msg.map);
x11_apply_exposed_position(native_window); x11_apply_exposed_position(native_window);
}
else
++(root_runtime->x11msg.unmap);
brock.event_expose(msgwnd, (xevent.type == MapNotify)); brock.event_expose(msgwnd, (xevent.type == MapNotify));
context.platform.motion_window = nullptr; context.platform.motion_window = nullptr;

View File

@ -77,6 +77,9 @@ namespace detail
typedef BOOL (__stdcall* imm_set_composition_window_type)(HIMC, LPCOMPOSITIONFORM); typedef BOOL (__stdcall* imm_set_composition_window_type)(HIMC, LPCOMPOSITIONFORM);
imm_set_composition_window_type imm_set_composition_window; imm_set_composition_window_type imm_set_composition_window;
typedef LONG(__stdcall* imm_get_composition_string_type)(HIMC, DWORD, LPVOID, DWORD);
imm_get_composition_string_type imm_get_composition_string;
} }
#pragma pack(1) #pragma pack(1)
//Decoder of WPARAM and LPARAM //Decoder of WPARAM and LPARAM
@ -170,15 +173,22 @@ namespace detail
static LRESULT WINAPI Bedrock_WIN32_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static LRESULT WINAPI Bedrock_WIN32_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
HINSTANCE windows_module_handle()
{
MEMORY_BASIC_INFORMATION mbi;
static int dummy;
VirtualQuery(&dummy, &mbi, sizeof(mbi));
return reinterpret_cast<HINSTANCE>(mbi.AllocationBase);
}
bedrock::bedrock() bedrock::bedrock()
: pi_data_(new pi_data), : pi_data_(new pi_data),
impl_(new private_impl) impl_(new private_impl)
{ {
nana::detail::platform_spec::instance(); //to guaranty the platform_spec object is initialized before using. nana::detail::platform_spec::instance(); //to guaranty the platform_spec object is initialized before using.
WNDCLASSEX wincl; WNDCLASSEX wincl;
wincl.hInstance = ::GetModuleHandle(0); wincl.hInstance = windows_module_handle();
wincl.lpszClassName = L"NanaWindowInternal"; wincl.lpszClassName = L"NanaWindowInternal";
wincl.lpfnWndProc = &Bedrock_WIN32_WindowProc; wincl.lpfnWndProc = &Bedrock_WIN32_WindowProc;
wincl.style = CS_DBLCLKS | CS_OWNDC; wincl.style = CS_DBLCLKS | CS_OWNDC;
@ -210,6 +220,9 @@ namespace detail
restrict::imm_set_composition_window = reinterpret_cast<restrict::imm_set_composition_window_type>( restrict::imm_set_composition_window = reinterpret_cast<restrict::imm_set_composition_window_type>(
::GetProcAddress(imm32, "ImmSetCompositionWindow")); ::GetProcAddress(imm32, "ImmSetCompositionWindow"));
restrict::imm_get_composition_string = reinterpret_cast<restrict::imm_get_composition_string_type>(
::GetProcAddress(imm32, "ImmGetCompositionStringW"));
} }
bedrock::~bedrock() bedrock::~bedrock()
@ -223,6 +236,8 @@ namespace detail
delete impl_; delete impl_;
delete pi_data_; delete pi_data_;
::UnregisterClass(L"NanaWindowInternal", windows_module_handle());
} }
@ -639,6 +654,8 @@ namespace detail
case WM_NCRBUTTONDOWN: case WM_NCRBUTTONDOWN:
case WM_NCMBUTTONDOWN: case WM_NCMBUTTONDOWN:
case WM_IME_STARTCOMPOSITION: case WM_IME_STARTCOMPOSITION:
case WM_IME_COMPOSITION:
case WM_IME_CHAR:
case WM_DROPFILES: case WM_DROPFILES:
case WM_MOUSELEAVE: case WM_MOUSELEAVE:
case WM_MOUSEWHEEL: //The WM_MOUSELAST may not include the WM_MOUSEWHEEL/WM_MOUSEHWHEEL when the version of SDK is low. case WM_MOUSEWHEEL: //The WM_MOUSELAST may not include the WM_MOUSEWHEEL/WM_MOUSEHWHEEL when the version of SDK is low.
@ -786,25 +803,67 @@ namespace detail
} }
break; break;
case WM_IME_STARTCOMPOSITION: case WM_IME_STARTCOMPOSITION:
if (msgwnd->other.attribute.root->ime_enabled) break;
case WM_IME_COMPOSITION:
if (lParam & (GCS_COMPSTR | GCS_RESULTSTR))
{ {
auto native_font = msgwnd->drawer.graphics.typeface().handle(); msgwnd = brock.focus();
LOGFONTW logfont; if (msgwnd && msgwnd->flags.enabled)
::GetObjectW(reinterpret_cast<HFONT>(native_font), sizeof logfont, &logfont); {
auto & wd_manager = brock.wd_manager();
auto composition_index = static_cast<DWORD>(lParam & (GCS_COMPSTR | GCS_RESULTSTR));
HIMC imc = restrict::imm_get_context(root_window); arg_ime arg;
restrict::imm_set_composition_font(imc, &logfont); arg.window_handle = msgwnd;
if (lParam & GCS_COMPSTR)
{
arg.ime_reason = arg_ime::reason::composition;
}
if (lParam & GCS_RESULTSTR)
{
arg.ime_reason = arg_ime::reason::result;
}
POINT pos; HIMC imc = restrict::imm_get_context(root_window);
::GetCaretPos(&pos); auto size = restrict::imm_get_composition_string(imc, composition_index, nullptr, 0);
if (size > 0)
{
wchar_t * buffer = new wchar_t[100 / sizeof(wchar_t) + 1];
size = restrict::imm_get_composition_string(imc, composition_index, buffer, size + sizeof(wchar_t));
buffer[size / sizeof(wchar_t)] = '\0';
arg.composition_string = std::move(buffer);
delete[] buffer;
}
restrict::imm_release_context(root_window, imc);
COMPOSITIONFORM cf = { CFS_POINT }; if (wd_manager.available(msgwnd))
cf.ptCurrentPos = pos; draw_invoker(&drawer::key_ime, msgwnd, arg, &context);
restrict::imm_set_composition_window(imc, &cf);
restrict::imm_release_context(root_window, imc); wd_manager.do_lazy_refresh(msgwnd, false);
}
} }
def_window_proc = true; def_window_proc = true;
break; break;
case WM_IME_CHAR:
msgwnd = brock.focus();
if (msgwnd && msgwnd->flags.enabled)
{
auto & wd_manager = brock.wd_manager();
arg_keyboard arg;
arg.evt_code = event_code::key_char;
arg.window_handle = msgwnd;
arg.key = static_cast<wchar_t>(wParam);
brock.get_key_state(arg);
arg.ignore = false;
msgwnd->annex.events_ptr->key_char.emit(arg, msgwnd);
if ((false == arg.ignore) && wd_manager.available(msgwnd))
draw_invoker(&drawer::key_char, msgwnd, arg, &context);
wd_manager.do_lazy_refresh(msgwnd, false);
}
break;
case WM_GETMINMAXINFO: case WM_GETMINMAXINFO:
{ {
bool take_over = false; bool take_over = false;

View File

@ -96,6 +96,11 @@ namespace nana
overridden_ &= ~(1 << static_cast<int>(event_code::focus)); overridden_ &= ~(1 << static_cast<int>(event_code::focus));
} }
void drawer_trigger::key_ime(graph_reference, const arg_ime&)
{
overridden_ &= ~(1 << static_cast<int>(event_code::key_ime));
}
void drawer_trigger::key_press(graph_reference, const arg_keyboard&) void drawer_trigger::key_press(graph_reference, const arg_keyboard&)
{ {
overridden_ &= ~(1 << static_cast<int>(event_code::key_press)); overridden_ &= ~(1 << static_cast<int>(event_code::key_press));
@ -318,6 +323,11 @@ namespace nana
_m_emit(event_code::focus, arg, &drawer_trigger::focus, bForce__EmitInternal); _m_emit(event_code::focus, arg, &drawer_trigger::focus, bForce__EmitInternal);
} }
void drawer::key_ime(const arg_ime& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::key_ime, arg, &drawer_trigger::key_ime, bForce__EmitInternal);
}
void drawer::key_press(const arg_keyboard& arg, const bool bForce__EmitInternal) void drawer::key_press(const arg_keyboard& arg, const bool bForce__EmitInternal)
{ {
_m_emit(event_code::key_press, arg, &drawer_trigger::key_press, bForce__EmitInternal); _m_emit(event_code::key_press, arg, &drawer_trigger::key_press, bForce__EmitInternal);

View File

@ -21,6 +21,10 @@
#include <map> #include <map>
#ifdef NANA_X11
# include <atomic>
#endif
namespace nana{ namespace nana{
namespace detail namespace detail
{ {
@ -75,6 +79,15 @@ namespace nana{
root_misc(root_misc&&); root_misc(root_misc&&);
root_misc(basic_window * wd, unsigned width, unsigned height); root_misc(basic_window * wd, unsigned width, unsigned height);
~root_misc(); ~root_misc();
#ifdef NANA_X11
struct x11msg_confirm
{
std::atomic<std::size_t> config{ 0 };
std::atomic<std::size_t> map{ 0 };
std::atomic<std::size_t> unmap{ 0 };
}x11msg;
#endif
private: private:
root_misc(const root_misc&) = delete; root_misc(const root_misc&) = delete;
root_misc& operator=(const root_misc&) = delete; root_misc& operator=(const root_misc&) = delete;

View File

@ -17,14 +17,15 @@
#include <nana/gui/detail/window_manager.hpp> #include <nana/gui/detail/window_manager.hpp>
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
#if defined(STD_THREAD_NOT_SUPPORTED) # if defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp> # include <nana/std_mutex.hpp>
#else # else
#include <mutex> # include <mutex>
#endif # endif
#include <map> # include <map>
#elif defined(NANA_X11) #elif defined(NANA_X11)
#include <nana/system/platform.hpp> # include <nana/system/platform.hpp>
# include "inner_fwd_implement.hpp"
#endif #endif
#include "../../paint/image_accessor.hpp" #include "../../paint/image_accessor.hpp"
@ -34,6 +35,10 @@ namespace nana{
namespace detail{ namespace detail{
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
//This function is defined in bedrock_windows.cpp
HINSTANCE windows_module_handle();
class tray_manager class tray_manager
{ {
struct window_extra_t struct window_extra_t
@ -199,26 +204,87 @@ namespace nana{
namespace x11_wait namespace x11_wait
{ {
struct param
{
Window handle;
root_misc * misc;
std::size_t comp_value;
};
static Bool configure(Display *disp, XEvent *evt, char *arg) static Bool configure(Display *disp, XEvent *evt, char *arg)
{ {
return disp && evt && arg && (evt->type == ConfigureNotify) && (evt->xconfigure.window == *reinterpret_cast<Window*>(arg)); auto p = reinterpret_cast<param*>(arg);
if(p)
{
if(p->misc->x11msg.config != p->comp_value)
return true;
if(disp && evt && (evt->type == ConfigureNotify))
{
if(evt->xconfigure.window == p->handle)
return true;
}
}
return false;
} }
static Bool map(Display *disp, XEvent *evt, char *arg) static Bool map(Display *disp, XEvent *evt, char *arg)
{ {
return disp && evt && arg && (evt->type == MapNotify) && (evt->xmap.window == *reinterpret_cast<Window*>(arg)); auto p = reinterpret_cast<param*>(arg);
if(p)
{
if(p->misc->x11msg.map != p->comp_value)
return true;
if(disp && evt && (evt->type == MapNotify))
{
if(evt->xmap.window == p->handle)
return true;
}
}
return false;
} }
static Bool unmap(Display *disp, XEvent *evt, char *arg) static Bool unmap(Display *disp, XEvent *evt, char *arg)
{ {
return disp && evt && arg && (evt->type == MapNotify) && (evt->xunmap.window == *reinterpret_cast<Window*>(arg)); auto p = reinterpret_cast<param*>(arg);
if(p)
{
if(p->misc->x11msg.unmap != p->comp_value)
return true;
if(disp && evt && (evt->type == UnmapNotify))
{
if(evt->xunmap.window == p->handle)
return true;
}
}
return false;
} }
} }
static void x11_wait_for(Window wd, Bool(*pred_fn)(Display*, XEvent*, char*)) static void x11_wait_for(Window wd, Bool(*pred_fn)(Display*, XEvent*, char*), std::size_t comp_value)
{ {
auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast<native_window_type>(wd));
x11_wait::param p;
p.handle = wd;
p.misc = misc;
if(pred_fn == &x11_wait::configure)
p.comp_value = misc->x11msg.config;
else if(pred_fn == &x11_wait::map)
p.comp_value = misc->x11msg.map;
else if(pred_fn == &x11_wait::unmap)
p.comp_value = misc->x11msg.unmap;
//Checks whether the msg is received.
if(p.comp_value != comp_value)
return;
p.comp_value = comp_value;
XEvent dummy; XEvent dummy;
::XPeekIfEvent(restrict::spec.open_display(), &dummy, pred_fn, reinterpret_cast<XPointer>(&wd)); ::XPeekIfEvent(restrict::spec.open_display(), &dummy, pred_fn, reinterpret_cast<XPointer>(&p));
} }
#endif #endif
@ -315,7 +381,7 @@ namespace nana{
HWND native_wd = ::CreateWindowEx(style_ex, L"NanaWindowInternal", L"Nana Window", HWND native_wd = ::CreateWindowEx(style_ex, L"NanaWindowInternal", L"Nana Window",
style, style,
pt.x, pt.y, 100, 100, pt.x, pt.y, 100, 100,
reinterpret_cast<HWND>(owner), 0, ::GetModuleHandle(0), 0); reinterpret_cast<HWND>(owner), 0, windows_module_handle(), 0);
//A window may have a border, this should be adjusted the client area fit for the specified size. //A window may have a border, this should be adjusted the client area fit for the specified size.
::RECT client; ::RECT client;
@ -504,7 +570,7 @@ namespace nana{
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS,
r.x, r.y, r.width, r.height, r.x, r.y, r.width, r.height,
reinterpret_cast<HWND>(parent), // The window is a child-window to desktop reinterpret_cast<HWND>(parent), // The window is a child-window to desktop
0, ::GetModuleHandle(0), 0); 0, windows_module_handle(), 0);
#elif defined(NANA_X11) #elif defined(NANA_X11)
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard psg;
@ -758,13 +824,17 @@ namespace nana{
if(show == is_window_visible(wd)) if(show == is_window_visible(wd))
return; return;
auto misc = bedrock::instance().wd_manager().root_runtime(wd);
if(show) if(show)
{ {
std::size_t cmp_value = misc->x11msg.map;
::XMapWindow(disp, reinterpret_cast<Window>(wd)); ::XMapWindow(disp, reinterpret_cast<Window>(wd));
//Wait for the mapping notify to update the local attribute of visibility so that //Wait for the mapping notify to update the local attribute of visibility so that
//the followed window_visible() call can return the updated visibility value. //the followed window_visible() call can return the updated visibility value.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::map); x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::map, cmp_value);
Window grab = restrict::spec.grab(0); Window grab = restrict::spec.grab(0);
if(grab == reinterpret_cast<Window>(wd)) if(grab == reinterpret_cast<Window>(wd))
@ -772,10 +842,12 @@ namespace nana{
} }
else else
{ {
std::size_t cmp_value = misc->x11msg.unmap;
::XUnmapWindow(disp, reinterpret_cast<Window>(wd)); ::XUnmapWindow(disp, reinterpret_cast<Window>(wd));
//Wait for the mapping notify to update the local attribute of visibility so that //Wait for the mapping notify to update the local attribute of visibility so that
//the followed window_visible() call can return the updated visibility value. //the followed window_visible() call can return the updated visibility value.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::unmap); x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::unmap, cmp_value);
} }
} }
static_cast<void>(active); //eliminate unused parameter compiler warning. static_cast<void>(active); //eliminate unused parameter compiler warning.
@ -1019,11 +1091,15 @@ namespace nana{
y += origin_y; y += origin_y;
} }
auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast<native_window_type>(wd));
std::size_t cmp_value = misc->x11msg.config;
::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y); ::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y);
//Wait for the configuration notify to update the local attribute of position so that //Wait for the configuration notify to update the local attribute of position so that
//the followed window_position() call can return the updated position value. //the followed window_position() call can return the updated position value.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure, cmp_value);
#endif #endif
} }
@ -1109,6 +1185,9 @@ namespace nana{
y += origin_y; y += origin_y;
} }
auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast<native_window_type>(wd));
std::size_t cmp_value = misc->x11msg.config;
::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height); ::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height);
//Wait for the configuration notify to update the local attribute of position so that //Wait for the configuration notify to update the local attribute of position so that
@ -1116,7 +1195,7 @@ namespace nana{
//It seems that XMoveResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called //It seems that XMoveResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called
//to make sure the local attribute is updated. //to make sure the local attribute is updated.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure); x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure, cmp_value);
return true; return true;
#endif #endif
@ -1283,11 +1362,15 @@ namespace nana{
hints.min_height = hints.max_height = sz.height; hints.min_height = hints.max_height = sz.height;
::XSetWMNormalHints(disp, reinterpret_cast<Window>(wd), &hints); ::XSetWMNormalHints(disp, reinterpret_cast<Window>(wd), &hints);
} }
auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast<native_window_type>(wd));
std::size_t cmp_value = misc->x11msg.config;
::XResizeWindow(disp, reinterpret_cast<Window>(wd), sz.width, sz.height); ::XResizeWindow(disp, reinterpret_cast<Window>(wd), sz.width, sz.height);
//It seems that XResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called //It seems that XResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called
//to make sure the local attribute is updated. //to make sure the local attribute is updated.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure); x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure, cmp_value);
return true; return true;
#endif #endif
} }

View File

@ -1516,21 +1516,31 @@ namespace nana
path_type parent_path{ str }; path_type parent_path{ str };
str += (len + 1); str += (len + 1);
while(*str) // if only one file was selected, the ofn.lpstrFile
// is returning only that file, without any parent
if (!*str)
{ {
len = ::wcslen(str); targets.emplace_back(parent_path);
targets.emplace_back(parent_path / path_type{str}); impl_->path = parent_path.parent_path().string();
str += (len + 1); }
else
{
while(*str)
{
len = ::wcslen(str);
targets.emplace_back(parent_path / path_type{str});
str += (len + 1);
}
impl_->path = parent_path.string();
} }
impl_->path = parent_path.u8string();
} }
else else
{ {
wfile.resize(std::wcslen(wfile.data())); wfile.resize(std::wcslen(wfile.data()));
targets.emplace_back(wfile); targets.emplace_back(wfile);
impl_->path = targets.front().parent_path().u8string(); impl_->path = targets.front().parent_path().string();
} }
#elif defined(NANA_POSIX) #elif defined(NANA_POSIX)

View File

@ -1,4 +1,4 @@
/* /**
* A Message Box Class * A Message Box Class
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
@ -7,10 +7,15 @@
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/msgbox.hpp * @file nana/gui/msgbox.hpp
* @Contributors * @Contributors
* James Bremner * James Bremner
* Ariel Vina-Rodriguez
*/ */
#define NOMINMAX
#include <algorithm> // max
#include <functional>
#include <cstdlib> //include std::abs
#include <nana/gui/compact.hpp> #include <nana/gui/compact.hpp>
#include <nana/gui/msgbox.hpp> #include <nana/gui/msgbox.hpp>
@ -27,8 +32,7 @@
#include <nana/datetime.hpp> #include <nana/datetime.hpp>
#include <nana/internationalization.hpp> #include <nana/internationalization.hpp>
#include <nana/gui/filebox.hpp> #include <nana/gui/filebox.hpp>
#include <functional>
#include <cstdlib> //include std::abs
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
#include <windows.h> #include <windows.h>
#elif defined(NANA_X11) #elif defined(NANA_X11)
@ -494,21 +498,29 @@ namespace nana
//end class msgbox //end class msgbox
//class inputbox //class inputbox todo: add schema
class inputbox_window class inputbox_window
: public ::nana::form : public ::nana::form
{ {
public: public:
inputbox_window(window owner, paint::image (&imgs)[4], ::nana::rectangle (&valid_areas)[4], const ::std::string & desc, const ::std::string& title, std::size_t contents, unsigned fixed_pixels, const std::vector<unsigned>& each_height) inputbox_window(window owner,
paint::image (&imgs)[4], ///< 4 ref to images
::nana::rectangle (&valid_areas)[4],
const ::std::string & description,
const ::std::string& title,
std::size_t contents,
unsigned fixed_pixels,
const std::vector<unsigned>& each_height)
: form(owner, API::make_center(owner, 500, 300), appear::decorate<>()) : form(owner, API::make_center(owner, 500, 300), appear::decorate<>())
{ {
throw_not_utf8(desc); throw_not_utf8(description);
throw_not_utf8(title); throw_not_utf8(title);
desc_.create(*this); description_.create(*this);
desc_.format(true).caption(desc); description_.format(true).caption(description);
auto desc_extent = desc_.measure(470); auto description_size = description_.measure(470);
btn_ok_.create(*this); btn_ok_.create(*this);
btn_ok_.i18n(i18n_eval("NANA_BUTTON_OK")); btn_ok_.i18n(i18n_eval("NANA_BUTTON_OK"));
@ -527,32 +539,26 @@ namespace nana
close(); close();
}); });
unsigned height = 20 + desc_extent.height + 10 + 38; unsigned height = 20 + description_size.height + 10 + 38;
std::stringstream ss_content; std::stringstream ss_content;
ss_content << "<margin=10 vert <desc weight=" << desc_extent.height << "><vert margin=[10]";
for (std::size_t i = 0; i < contents; ++i) for (std::size_t i = 0; i < contents; ++i)
{ {
unsigned px = 27; unsigned px = std::max(27u, each_height[i]);
if (each_height[i] > 27)
px = each_height[i];
ss_content << "<weight=" << (px + 3) << " margin=[3] input_" << i << ">"; ss_content << "<height=" << (px + 3) << " margin=[3] input_" << i << ">";
height += px + 1; height += px + 3;
} }
ss_content << "><margin=[15] weight=38<><buttons arrange=80 gap=10 weight=170>>>"; if (description_size.width < 200)
description_size.width = 200;
if (desc_extent.width < 200)
desc_extent.width = 200;
//Make sure the complete display of input extent //Make sure the complete display of input extent
if (desc_extent.width < fixed_pixels) if (description_size.width < fixed_pixels)
desc_extent.width = fixed_pixels; description_size.width = fixed_pixels;
desc_extent.width += 20; description_size.width += 20; // 2x margin 10
::nana::size img_sz[4]; ::nana::size img_sz[4];
@ -566,8 +572,9 @@ namespace nana
} }
else else
sz = imgs[2].size(); sz = imgs[2].size();
sz.width = static_cast<size::value_type>(double(sz.width) * (double(height) / double(sz.height))); const double scale_factor = double(height) / double(sz.height);
desc_extent.width += sz.width; sz.width = static_cast<size::value_type>(double(sz.width) * scale_factor);
description_size.width += sz.width;
} }
if (imgs[3]) //Right if (imgs[3]) //Right
@ -581,7 +588,7 @@ namespace nana
else else
sz = imgs[3].size(); sz = imgs[3].size();
sz.width = static_cast<size::value_type>(double(sz.width) * (double(height) / double(sz.height))); sz.width = static_cast<size::value_type>(double(sz.width) * (double(height) / double(sz.height)));
desc_extent.width += sz.width; description_size.width += sz.width;
} }
if (imgs[0]) //Top if (imgs[0]) //Top
@ -594,7 +601,8 @@ namespace nana
} }
else else
sz = imgs[0].size(); sz = imgs[0].size();
sz.height = static_cast<size::value_type>(double(sz.height) * (double(desc_extent.width) / double(sz.width))); const double scale_factor = double(description_size.width) / double(sz.width);
sz.height = static_cast<size::value_type>(double(sz.height) * scale_factor );
height += sz.height; height += sz.height;
} }
@ -608,16 +616,28 @@ namespace nana
} }
else else
sz = imgs[1].size(); sz = imgs[1].size();
sz.height = static_cast<size::value_type>(double(sz.height) * (double(desc_extent.width) / double(sz.width))); const double scale_factor = double(description_size.width) / double(sz.width);
sz.height = static_cast<size::value_type>(double(sz.height) * scale_factor);
height += sz.height; height += sz.height;
} }
std::stringstream ss; std::stringstream ss;
ss << "vert<img_top weight="<<img_sz[0].height<<"><<img_left weight="<<img_sz[2].width<<">"<<ss_content.str()<<"<img_right weight="<<img_sz[3].width<<">><img_bottom weight="<<img_sz[1].height<<">"; ss << "vert< img_top height="<<img_sz[0].height<<">"
<<" << img_left width=" <<img_sz[2].width <<">"
<<" <margin=10 vert <description height=" << description_size.height << ">" // added height: 2x10
<<" <vert margin=[10]" // added height: 10
<< ss_content.str()
<<" >"
<<" <height=38 margin=[15] <><width=170 buttons arrange=80 gap=10>"
<<" >>" // added height: 38
<<" < img_right width=" <<img_sz[3].width
<<" >>< img_bottom height="<<img_sz[1].height<<">";
// added height: 10 x3 = 30 + 38
auto& place = this->get_place(); auto& place = this->get_place();
place.div(ss.str().c_str()); place.div(ss.str().c_str());
place["desc"] << desc_; place["description"] << description_;
place["buttons"] << btn_ok_ << btn_cancel_; place["buttons"] << btn_ok_ << btn_cancel_;
const char * img_fields[4] = {"img_top", "img_bottom", "img_left", "img_right"}; const char * img_fields[4] = {"img_top", "img_bottom", "img_left", "img_right"};
@ -635,7 +655,7 @@ namespace nana
place.field_display(img_fields[i], imgs[i]); place.field_display(img_fields[i], imgs[i]);
} }
move(API::make_center(this->owner(), desc_extent.width, height)); move(API::make_center(this->owner(), description_size.width, height));
caption(title); caption(title);
} }
@ -659,7 +679,7 @@ namespace nana
return valid_input_; return valid_input_;
} }
private: private:
::nana::label desc_; ::nana::label description_;
::nana::button btn_ok_; ::nana::button btn_ok_;
::nana::button btn_cancel_; ::nana::button btn_cancel_;
bool valid_input_{ false }; bool valid_input_{ false };
@ -1247,7 +1267,7 @@ namespace nana
auto files = impl->fbox.show(); auto files = impl->fbox.show();
if(!files.empty()) if(!files.empty())
{ {
impl->value = files.front().u8string(); impl->value = files.front().string();
impl->path_edit.caption(impl->value); impl->path_edit.caption(impl->value);
} }
}); });

View File

@ -146,7 +146,8 @@ namespace nana
//draw caption //draw caption
auto text = to_wstring(API::window_caption(window_handle_)); auto text = to_wstring(API::window_caption(window_handle_));
text_rd_->render({ 3, 1 }, text.data(), text.size(), graph.size().width - 20, paint::text_renderer::mode::truncate_with_ellipsis); if((graph.size().width > 20) && (graph.size().width - 20 > 10))
text_rd_->render({ 3, 1 }, text.data(), text.size(), graph.size().width - 20, paint::text_renderer::mode::truncate_with_ellipsis);
//draw x button //draw x button
auto r = _m_button_area(); auto r = _m_button_area();

View File

@ -111,13 +111,13 @@ namespace nana
{ {
public: public:
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
timer_core(timer* sender, timer_identifier tmid, basic_event<arg_elapse>& evt_elapse): timer_core(timer* sender, timer_identifier tmid, std::shared_ptr<basic_event<arg_elapse>> evt_elapse):
sender_(sender), sender_(sender),
timer_(tmid), timer_(tmid),
evt_elapse_(evt_elapse) evt_elapse_(evt_elapse)
{} {}
#else #else
timer_core(timer* sender, basic_event<arg_elapse>& evt_elapse): timer_core(timer* sender, std::shared_ptr<basic_event<arg_elapse>> evt_elapse):
sender_(sender), sender_(sender),
timer_(this), timer_(this),
evt_elapse_(evt_elapse) evt_elapse_(evt_elapse)
@ -142,12 +142,15 @@ namespace nana
{ {
arg_elapse arg; arg_elapse arg;
arg.sender = sender_; arg.sender = sender_;
evt_elapse_.emit(arg, nullptr);
//retain the object to avoid it to be deleted during calling of emit
auto retain = evt_elapse_;
retain->emit(arg, nullptr);
} }
private: private:
timer * const sender_; timer * const sender_;
const timer_identifier timer_; const timer_identifier timer_;
nana::basic_event<arg_elapse> & evt_elapse_; std::shared_ptr<nana::basic_event<arg_elapse>> evt_elapse_;
}; //end class timer_core }; //end class timer_core
@ -175,8 +178,9 @@ namespace nana
}; };
//class timer //class timer
timer::timer() timer::timer():
: impl_(new implement) elapse_(std::make_shared<nana::basic_event<arg_elapse>>()),
impl_(new implement)
{ {
} }
@ -195,7 +199,7 @@ namespace nana
void timer::reset() void timer::reset()
{ {
stop(); stop();
elapse_.clear(); elapse_->clear();
} }
void timer::start() void timer::start()

View File

@ -773,6 +773,13 @@ namespace nana
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
void trigger::key_ime(graph_reference, const arg_ime& arg)
{
drawer_->editor()->respond_ime(arg);
if (drawer_->editor()->try_refresh())
API::dev::lazy_refresh();
}
void trigger::key_char(graph_reference, const arg_keyboard& arg) void trigger::key_char(graph_reference, const arg_keyboard& arg)
{ {
drawer_->editor()->respond_char(arg); drawer_->editor()->respond_char(arg);

View File

@ -39,7 +39,7 @@ namespace nana
place & form_base::get_place() place & form_base::get_place()
{ {
if (this->empty()) if (this->empty())
throw std::runtime_error("form::get_plac: the form has destroyed."); throw std::runtime_error("form::get_place(): the form has been destroyed.");
if (!place_) if (!place_)
place_.reset(new place{ *this }); place_.reset(new place{ *this });
@ -47,9 +47,9 @@ namespace nana
return *place_; return *place_;
} }
void form_base::div(const char* div_text) void form_base::div(std::string div_text)
{ {
get_place().div(div_text); get_place().div(std::move(div_text));
} }
place::field_reference form_base::operator[](const char* field_name) place::field_reference form_base::operator[](const char* field_name)

View File

@ -167,7 +167,7 @@ namespace nana
column(column&& other): column(column&& other):
caption(std::move(other.caption)), caption(std::move(other.caption)),
width_px(other.width_px), width_px(other.width_px),
range_width_px(other.range_width_px), range_width_px(other.range_width_px),
visible_state(other.visible_state), visible_state(other.visible_state),
index(other.index), index(other.index),
@ -184,7 +184,13 @@ namespace nana
index(pos), index(pos),
ess_(ess) ess_(ess)
{ {
if (px == 0)
{
fit_width_to_header();
}
} }
void fit_width_to_header();
private: private:
/// The definition is provided after essence /// The definition is provided after essence
void _m_refresh() noexcept; void _m_refresh() noexcept;
@ -2308,7 +2314,8 @@ namespace nana
size_type count_of_exposed(bool with_rest) const size_type count_of_exposed(bool with_rest) const
{ {
auto lister_s = this->content_view->view_area().height; auto lister_s = this->content_view->view_area().height;
return (lister_s / item_height()) + (with_rest && (lister_s % item_height()) ? 1 : 0); return (lister_s / item_height()) + (with_rest &&
listbox_ptr->scroll_operation()->visible(true) && (lister_s % item_height()) ? 1 : 0);
} }
void update(bool ignore_auto_draw = false) noexcept void update(bool ignore_auto_draw = false) noexcept
@ -2394,7 +2401,9 @@ namespace nana
nana::rectangle r; nana::rectangle r;
if (rect_lister(r)) if (rect_lister(r))
{ {
auto top = new_where.second * item_h + header_visible_px(); //potential displacement due to partially visible first visible item
auto disp = origin.y - first_display().item * item_h;
auto top = new_where.second * item_h + header_visible_px() - disp;
if (checkarea(item_xpos(r), static_cast<int>(top)).is_hit(pos)) if (checkarea(item_xpos(r), static_cast<int>(top)).is_hit(pos))
new_where.first = parts::checker; new_where.first = parts::checker;
} }
@ -2881,10 +2890,26 @@ namespace nana
return max_px; return max_px;
} }
void es_header::column::fit_width_to_header()
{
std::unique_ptr<paint::graphics> graph_helper;
auto graph = ess_->graph;
if (graph->empty())
{
//Creates a helper if widget graph is empty(when its size is 0).
graph_helper.reset(new paint::graphics{ nana::size{ 5, 5 } });
graph_helper->typeface(ess_->graph->typeface());
graph = graph_helper.get();
}
width_px = ess_->scheme_ptr->text_margin * 2; //margin at left/right end.
width_px += graph->text_extent_size(caption).width;
}
//es_header::column member functions //es_header::column member functions
void es_header::column::_m_refresh() noexcept void es_header::column::_m_refresh() noexcept
{ {
ess_->update(true); ess_->update(false);
} }
size_type es_header::column::position(bool disp_order) const noexcept size_type es_header::column::position(bool disp_order) const noexcept
@ -3316,16 +3341,27 @@ namespace nana
return false; return false;
} }
// init ir end to grab a header
void grab(const nana::point& pos, bool is_grab) void grab(const nana::point& pos, bool is_grab)
{ {
if(is_grab) if(is_grab) // init grabbing the header
{ {
grabs_.start_pos = pos.x; grabs_.start_pos = pos.x;
if(grabs_.splitter != npos) // resize header item, not move it if(grabs_.splitter == npos) // No splitter, no resize header, just moving
grabs_.item_width = essence_->header.at(grabs_.splitter).width_px; return;
// splitter grabbed - resize the header: take initial width
grabs_.item_width = essence_->header.at(grabs_.splitter).width_px;
} }
else if((grab_terminal_.index != npos) && (grab_terminal_.index != essence_->pointer_where.second)) else // end to grab the header
essence_->header.move(essence_->pointer_where.second, grab_terminal_.index, grab_terminal_.place_front); if (grabs_.splitter != npos) // some Splitter grab, just resizing, no need to move
return;
else if( (grab_terminal_.index != npos)
&& (grab_terminal_.index != essence_->pointer_where.second) )
// move header to terminal position
essence_->header.move(essence_->pointer_where.second, // from
grab_terminal_.index, // to
grab_terminal_.place_front);
} }
//grab_move //grab_move
@ -4273,7 +4309,10 @@ namespace nana
auto const good_list_r = essence_->rect_lister(list_r); auto const good_list_r = essence_->rect_lister(list_r);
auto & ptr_where = essence_->pointer_where; auto & ptr_where = essence_->pointer_where;
if((ptr_where.first == parts::header) && (ptr_where.second != npos || (drawer_header_->splitter() != npos)))
if( (ptr_where.first == parts::header) // click on header
&& ( ptr_where.second != npos // in ..
|| (drawer_header_->splitter() != npos))) // or splitter
{ {
essence_->ptr_state = item_state::pressed; essence_->ptr_state = item_state::pressed;
if(good_head_r) if(good_head_r)
@ -4282,7 +4321,8 @@ namespace nana
update = true; update = true;
} }
} }
else if(ptr_where.first == parts::list || ptr_where.first == parts::checker) else if( ptr_where.first == parts::list // click on list
|| ptr_where.first == parts::checker) // on a checker
{ {
index_pair item_pos = lister.advance(essence_->first_display(), static_cast<int>(ptr_where.second)); index_pair item_pos = lister.advance(essence_->first_display(), static_cast<int>(ptr_where.second));
@ -4455,13 +4495,16 @@ namespace nana
bool need_refresh = false; bool need_refresh = false;
//Don't sort the column when the mouse is due to released for stopping resizing column. //Don't sort the column when the mouse is due to released for stopping resizing column.
if ((drawer_header_->splitter() == npos) && essence_->header.attrib().sortable && essence_->pointer_where.first == parts::header && prev_state == item_state::pressed) if ( (drawer_header_->splitter() == npos) // no header splitter was selected
&& essence_->header.attrib().sortable
&& essence_->pointer_where.first == parts::header
&& prev_state == item_state::pressed)
{ {
//Try to sort the column //Try to sort the column
if(essence_->pointer_where.second < essence_->header.cont().size()) if(essence_->pointer_where.second < essence_->header.cont().size())
need_refresh = essence_->lister.sort_column(essence_->pointer_where.second, nullptr); need_refresh = essence_->lister.sort_column(essence_->pointer_where.second, nullptr);
} }
else if (item_state::grabbed == prev_state) else if (item_state::grabbed == prev_state) // selected splitter and grabbed
{ {
nana::point pos = arg.pos; nana::point pos = arg.pos;
essence_->widget_to_header(pos); essence_->widget_to_header(pos);
@ -4762,7 +4805,7 @@ namespace nana
bool item_proxy::empty() const noexcept bool item_proxy::empty() const noexcept
{ {
return !ess_; return !(ess_ && ess_->lister.good(pos_));
} }
item_proxy & item_proxy::check(bool ck, bool scroll_view) item_proxy & item_proxy::check(bool ck, bool scroll_view)
@ -5959,6 +6002,7 @@ namespace nana
{ {
internal_scope_guard lock; internal_scope_guard lock;
_m_ess().lister.sort_column(col, &reverse); _m_ess().lister.sort_column(col, &reverse);
_m_ess().update();
} }
auto listbox::sort_col() const -> size_type auto listbox::sort_col() const -> size_type
@ -6073,7 +6117,15 @@ namespace nana
auto listbox::last_visible() const -> index_pair auto listbox::last_visible() const -> index_pair
{ {
return _m_ess().lister.advance(_m_ess().first_display(), static_cast<int>(_m_ess().count_of_exposed(true))); if(!const_cast<listbox*>(this)->scroll_operation()->visible(true))
{
auto last_cat = size_categ()-1;
index_pair ip(last_cat, at(last_cat).size()-1);
if(last_cat == 0 && ip.item == npos) // if the listbox is empty
ip.cat = npos; // return empty index_pair
return ip;
}
return _m_ess().lister.advance(_m_ess().first_display(), static_cast<int>(_m_ess().count_of_exposed(true)-1));
} }
auto listbox::visibles() const -> index_pairs auto listbox::visibles() const -> index_pairs

View File

@ -922,7 +922,25 @@ namespace nana
} }
else if (checks::option == item.style) else if (checks::option == item.style)
{ {
get_drawer_trigger().mbuilder().checked(active, true); if(active > 0)
{
do {
if(menu->items[--active]->flags.splitter)
{
++active;
break;
}
} while(active > 0);
}
while(active < menu->items.size())
{
menu_item_type &el = *(menu->items[active++]);
if(el.flags.splitter)
break;
if(checks::option == el.style)
el.flags.checked = false;
}
item.flags.checked = true;
} }
this->_m_close_all(); //means deleting this; this->_m_close_all(); //means deleting this;

View File

@ -96,11 +96,11 @@ namespace nana
{ {
if (widget_) if (widget_)
{ {
auto value_px = (widget_->size().width - border_px * 2); unsigned value_px = (widget_->size().width - border_px * 2);
//avoid overflow //avoid overflow
if (unknown_ || (value_ < max_)) if (unknown_ || (value_ < max_))
value_px = static_cast<unsigned>(value_px * (double(value_) / double(max_))); value_px = unsigned(double(value_px) * (double(value_) / double(max_)));
if (value_px != value_px_) if (value_px != value_px_)
{ {

View File

@ -1163,6 +1163,43 @@ namespace nana {
impl_->capacities.acceptive = acceptive; impl_->capacities.acceptive = acceptive;
} }
bool text_editor::respond_ime(const arg_ime& arg)
{
if (!API::window_enabled(window_))
return false;
if (select_.a != select_.b)
{
points_.caret = _m_erase_select(false);
}
for (size_t i = 0; i < composition_size_; ++i)
{
backspace(false, false);
}
if (arg.ime_reason == arg_ime::reason::composition)
{
composition_size_ = arg.composition_string.length();
points_.caret = _m_put(std::move(arg.composition_string), false);
_m_reset_content_size(true);
textbase().text_changed();
if (this->_m_adjust_view())
impl_->cview->sync(false);
reset_caret();
impl_->try_refresh = sync_graph::refresh;
}
else
{
composition_size_ = 0;
}
return true;
}
bool text_editor::respond_char(const arg_keyboard& arg) //key is a character of ASCII code bool text_editor::respond_char(const arg_keyboard& arg) //key is a character of ASCII code
{ {
if (!API::window_enabled(window_)) if (!API::window_enabled(window_))

View File

@ -621,6 +621,13 @@ namespace nana
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
void drawer::key_ime(graph_reference, const arg_ime& arg)
{
impl_->editor()->respond_ime(arg);
if (impl_->editor()->try_refresh())
API::dev::lazy_refresh();
}
void drawer::key_press(graph_reference, const arg_keyboard& arg) void drawer::key_press(graph_reference, const arg_keyboard& arg)
{ {
if (impl_->editor()->respond_key(arg)) if (impl_->editor()->respond_key(arg))

View File

@ -1229,7 +1229,8 @@ namespace nana
void trigger::erase(std::size_t pos) void trigger::erase(std::size_t pos)
{ {
layouter_->erase(pos); if (layouter_->erase(pos))
API::refresh_window(layouter_->widget_handle());
} }
void trigger::tab_color(std::size_t i, bool is_bgcolor, const ::nana::color& clr) void trigger::tab_color(std::size_t i, bool is_bgcolor, const ::nana::color& clr)

View File

@ -152,6 +152,13 @@ namespace drawerbase {
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
void drawer::key_ime(graph_reference, const arg_ime& arg)
{
editor_->respond_ime(arg);
if (editor_->try_refresh())
API::dev::lazy_refresh();
}
void drawer::key_press(graph_reference, const arg_keyboard& arg) void drawer::key_press(graph_reference, const arg_keyboard& arg)
{ {
editor_->respond_key(arg); editor_->respond_key(arg);

View File

@ -104,6 +104,7 @@ namespace nana
delete ptr; delete ptr;
cont_.clear(); cont_.clear();
right_ = npos;
} }
@ -683,6 +684,7 @@ namespace nana
if(m && (m->textout != show)) if(m && (m->textout != show))
{ {
m->textout = show; m->textout = show;
m->pixels = 0; //force width calculation
API::refresh_window(this->handle()); API::refresh_window(this->handle());
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* A Treebox Implementation * A Treebox Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -70,7 +70,7 @@ namespace nana
const node_type* find_track_child_node(const node_type* node, const node_type * end, const char* pattern, std::size_t len, bool &finish) const node_type* find_track_child_node(const node_type* node, const node_type * end, const char* pattern, std::size_t len, bool &finish)
{ {
if(node->value.second.expanded) if(node->value.second.expanded && !node->value.second.hidden)
{ {
node = node->child; node = node->child;
while(node) while(node)
@ -79,7 +79,7 @@ namespace nana
if(node == end) break; if(node == end) break;
if(node->value.second.expanded) if(node->value.second.expanded && !node->value.second.hidden)
{ {
auto t = find_track_child_node(node, end, pattern, len, finish); auto t = find_track_child_node(node, end, pattern, len, finish);
if(t || finish) if(t || finish)
@ -184,10 +184,11 @@ namespace nana
class trigger::item_locator class trigger::item_locator
{ {
public: public:
using enum_order = tree_cont_type::enum_order;
using node_type = tree_cont_type::node_type; using node_type = tree_cont_type::node_type;
item_locator(implementation * impl, int item_pos, int x, int y); item_locator(implementation * impl, int item_pos, int x, int y);
int operator()(node_type &node, int affect); enum_order operator()(node_type &node, int affect);
node_type * node() const; node_type * node() const;
component what() const; component what() const;
bool item_body() const; bool item_body() const;
@ -212,6 +213,14 @@ namespace nana
} }
}; };
struct pred_allow_node
{
bool operator()(const trigger::tree_cont_type::node_type& node)
{
return !node.value.second.hidden;
}
};
//struct implementation //struct implementation
//@brief: some data for treebox trigger //@brief: some data for treebox trigger
class trigger::implementation class trigger::implementation
@ -220,6 +229,7 @@ namespace nana
: public compset_interface : public compset_interface
{ {
public: public:
using enum_order = tree_cont_type::enum_order;
using node_type = tree_cont_type::node_type; using node_type = tree_cont_type::node_type;
item_rendering_director(implementation * impl, const nana::point& pos): item_rendering_director(implementation * impl, const nana::point& pos):
@ -232,9 +242,11 @@ namespace nana
//0 = Sibling, the last is a sibling of node //0 = Sibling, the last is a sibling of node
//1 = Owner, the last is the owner of node //1 = Owner, the last is the owner of node
//>=2 = Children, the last is a child of a node that before this node. //>=2 = Children, the last is a child of a node that before this node.
int operator()(const node_type& node, int affect) enum_order operator()(const node_type& node, int affect)
{ {
iterated_node_ = &node; iterated_node_ = &node;
// Increase/decrease indent
switch (affect) switch (affect)
{ {
case 1: case 1:
@ -245,6 +257,9 @@ namespace nana
pos_.x -= impl_->data.scheme_ptr->indent_displacement * (affect - 1); pos_.x -= impl_->data.scheme_ptr->indent_displacement * (affect - 1);
} }
if (iterated_node_->value.second.hidden) // Skip drawing if the node is hidden
return enum_order::proceed;
auto & comp_placer = impl_->data.comp_placer; auto & comp_placer = impl_->data.comp_placer;
impl_->assign_node_attr(node_attr_, iterated_node_); impl_->assign_node_attr(node_attr_, iterated_node_);
@ -263,9 +278,9 @@ namespace nana
pos_.y += node_r_.height; pos_.y += node_r_.height;
if (pos_.y > static_cast<int>(impl_->data.graph->height())) if (pos_.y > static_cast<int>(impl_->data.graph->height()))
return 0; return enum_order::stop;
return (node.child && node.value.second.expanded ? 1 : 2); return ((node.child && node.value.second.expanded) ? enum_order::proceed_with_children : enum_order::proceed);
} }
private: private:
//Overrides compset_interface //Overrides compset_interface
@ -280,7 +295,12 @@ namespace nana
if (impl_->data.comp_placer->locate(comp, node_attr_, &attr.area)) if (impl_->data.comp_placer->locate(comp, node_attr_, &attr.area))
{ {
attr.mouse_pointed = node_attr_.mouse_pointed; attr.mouse_pointed = node_attr_.mouse_pointed;
attr.area.x += pos_.x;
if(comp == component_t::bground && impl_->use_entire_line)
attr.area.width = impl_->visible_w_pixels();
else
attr.area.x += pos_.x;
attr.area.y += pos_.y; attr.area.y += pos_.y;
return true; return true;
} }
@ -347,6 +367,9 @@ namespace nana
std::size_t scroll_timestamp; std::size_t scroll_timestamp;
nana::timer timer; nana::timer timer;
}adjust; }adjust;
bool use_entire_line;
public: public:
implementation() implementation()
{ {
@ -371,11 +394,24 @@ namespace nana
adjust.offset_x_adjust = 0; adjust.offset_x_adjust = 0;
adjust.node = nullptr; adjust.node = nullptr;
adjust.scroll_timestamp = 0; adjust.scroll_timestamp = 0;
use_entire_line = false;
} }
void assign_node_attr(node_attribute& ndattr, const node_type* node) const void assign_node_attr(node_attribute& ndattr, const node_type* node) const
{ {
ndattr.has_children = (nullptr != node->child); // Check if there is a visible child that node has.
// This is an improvement based on a new feature that allows treebox node to be hidden(PR#500)
ndattr.has_children = false;
for (auto p = node->child; p; p = p->next)
{
if (!p->value.second.hidden)
{
ndattr.has_children = true;
break;
}
}
ndattr.expended = node->value.second.expanded; ndattr.expended = node->value.second.expanded;
ndattr.text = node->value.second.text; ndattr.text = node->value.second.text;
ndattr.checked = node->value.second.checked; ndattr.checked = node->value.second.checked;
@ -552,7 +588,7 @@ namespace nana
if (p->child) if (p->child)
{ {
if (p->value.second.expanded || !ignore_folded_children) if ((p->value.second.expanded || !ignore_folded_children) && !p->value.second.hidden)
{ {
p = p->child; p = p->child;
continue; continue;
@ -603,8 +639,8 @@ namespace nana
} }
} }
auto pos = tree.distance_if(node, pred_allow_child{}); auto pos = tree.distance_if(node, pred_allow_child{}, pred_allow_node{});
auto last_pos = tree.distance_if(last(true), pred_allow_child{}); auto last_pos = tree.distance_if(last(true), pred_allow_child{}, pred_allow_node{});
auto const capacity = screen_capacity(true); auto const capacity = screen_capacity(true);
@ -612,7 +648,7 @@ namespace nana
//position of the requested item. //position of the requested item.
if (!use_bearing) if (!use_bearing)
{ {
auto first_pos = tree.distance_if(shape.first, pred_allow_child{}); auto first_pos = tree.distance_if(shape.first, pred_allow_child{}, pred_allow_node{});
if (pos < first_pos) if (pos < first_pos)
bearing = align_v::top; bearing = align_v::top;
@ -655,7 +691,7 @@ namespace nana
} }
auto prv_first = shape.first; auto prv_first = shape.first;
shape.first = attr.tree_cont.advance_if(nullptr, pos, drawerbase::treebox::pred_allow_child{}); shape.first = attr.tree_cont.advance_if(nullptr, pos, drawerbase::treebox::pred_allow_child{}, pred_allow_node{});
//Update the position of scroll //Update the position of scroll
show_scroll(); show_scroll();
@ -669,8 +705,8 @@ namespace nana
auto & tree = attr.tree_cont; auto & tree = attr.tree_cont;
auto const first_pos = tree.distance_if(shape.first, pred_allow_child{}); auto const first_pos = tree.distance_if(shape.first, pred_allow_child{}, pred_allow_node{});
auto const node_pos = tree.distance_if(node, pred_allow_child{}); auto const node_pos = tree.distance_if(node, pred_allow_child{}, pred_allow_node{});
auto const max_allow = max_allowed(); auto const max_allow = max_allowed();
switch(reason) switch(reason)
{ {
@ -680,12 +716,12 @@ namespace nana
//adjust if the number of its children are over the max number allowed //adjust if the number of its children are over the max number allowed
if (shape.first != node) if (shape.first != node)
{ {
auto child_size = tree.child_size_if(*node, pred_allow_child()); auto child_size = tree.child_size_if(*node, pred_allow_child(), pred_allow_node{});
if (child_size < max_allow) if (child_size < max_allow)
{ {
auto const size = node_pos - first_pos + child_size + 1; auto const size = node_pos - first_pos + child_size + 1;
if (size > max_allow) if (size > max_allow)
shape.first = tree.advance_if(shape.first, size - max_allow, pred_allow_child{}); shape.first = tree.advance_if(shape.first, size - max_allow, pred_allow_child{}, pred_allow_node{});
} }
else else
shape.first = node; shape.first = node;
@ -698,7 +734,7 @@ namespace nana
if (visual_size > max_allow) if (visual_size > max_allow)
{ {
if (first_pos + max_allow > visual_size) if (first_pos + max_allow > visual_size)
shape.first = tree.advance_if(nullptr, visual_size - max_allow, pred_allow_child{}); shape.first = tree.advance_if(nullptr, visual_size - max_allow, pred_allow_child{}, pred_allow_node{});
} }
else else
shape.first = nullptr; shape.first = nullptr;
@ -739,7 +775,7 @@ namespace nana
} }
else if (node_pos - first_pos > max_allow) else if (node_pos - first_pos > max_allow)
{ {
shape.first = tree.advance_if(nullptr, node_pos - max_allow + 1, pred_allow_child{}); shape.first = tree.advance_if(nullptr, node_pos - max_allow + 1, pred_allow_child{}, pred_allow_node{});
return true; return true;
} }
} }
@ -814,6 +850,27 @@ namespace nana
return false; return false;
} }
bool set_hidden(node_type* node, bool value)
{
if (node && node->value.second.hidden != value)
{
if (value == false)
{
//if hiding a parent of the selected node or the selected node itself - select nothing.
if (node->is_ancestor_of(node_state.selected) || node_state.selected == node)
set_selected(nullptr);
}
node->value.second.hidden = value;
data.stop_drawing = true;
item_proxy iprx(data.trigger_ptr, node);
data.widget_ptr->events().hidden.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, value }, data.widget_ptr->handle());
data.stop_drawing = false;
return true;
}
return false;
}
void show_scroll() void show_scroll()
{ {
if(nullptr == data.graph) return; if(nullptr == data.graph) return;
@ -841,7 +898,7 @@ namespace nana
adjust.scroll_timestamp = nana::system::timestamp(); adjust.scroll_timestamp = nana::system::timestamp();
adjust.timer.start(); adjust.timer.start();
shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll->value(), pred_allow_child{}); shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll->value(), pred_allow_child{}, pred_allow_node{});
draw(false, false, true); draw(false, false, true);
}); });
} }
@ -850,13 +907,13 @@ namespace nana
scroll.range(max_allow); scroll.range(max_allow);
} }
auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{}); auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{}, pred_allow_node{});
scroll.value(pos); scroll.value(pos);
} }
std::size_t visual_item_size() const std::size_t visual_item_size() const
{ {
return attr.tree_cont.child_size_if(std::string(), pred_allow_child{}); return attr.tree_cont.child_size_if(std::string(), pred_allow_child{}, pred_allow_node{});
} }
int visible_w_pixels() const int visible_w_pixels() const
@ -1153,6 +1210,20 @@ namespace nana
return *this; return *this;
} }
bool item_proxy::hidden() const
{
return node_->value.second.hidden;
}
item_proxy& item_proxy::hide(bool h)
{
auto* impl = trigger_->impl();
if (impl->set_hidden(node_, h))
impl->draw(true);
return *this;
}
const std::string& item_proxy::icon() const const std::string& item_proxy::icon() const
{ {
return node_->value.second.img_idstr; return node_->value.second.img_idstr;
@ -1274,7 +1345,10 @@ namespace nana
item_proxy item_proxy::operator++(int) item_proxy item_proxy::operator++(int)
{ {
return sibling(); item_proxy ip(*this);
if(trigger_ && node_)
node_ = node_->next;
return ip;
} }
item_proxy& item_proxy::operator*() item_proxy& item_proxy::operator*()
@ -1395,7 +1469,7 @@ namespace nana
switch(comp) switch(comp)
{ {
case component_t::expander: case component_t::expander:
if(attr.has_children) if (attr.has_children)
{ {
r->width = scheme_.item_offset; r->width = scheme_.item_offset;
return true; return true;
@ -1581,7 +1655,7 @@ namespace nana
node_(nullptr) node_(nullptr)
{} {}
int trigger::item_locator::operator()(node_type &node, int affect) auto trigger::item_locator::operator()(node_type &node, int affect) -> enum_order
{ {
switch(affect) switch(affect)
{ {
@ -1592,6 +1666,9 @@ namespace nana
item_pos_.x -= static_cast<int>(impl_->data.scheme_ptr->indent_displacement) * (affect - 1); item_pos_.x -= static_cast<int>(impl_->data.scheme_ptr->indent_displacement) * (affect - 1);
} }
if (node.value.second.hidden) // Do not account for hidden nodes
return enum_order::proceed;
impl_->assign_node_attr(node_attr_, &node); impl_->assign_node_attr(node_attr_, &node);
nana::rectangle node_r; nana::rectangle node_r;
auto & comp_placer = impl_->data.comp_placer; auto & comp_placer = impl_->data.comp_placer;
@ -1608,8 +1685,8 @@ namespace nana
nana::rectangle r = node_r; nana::rectangle r = node_r;
if (!comp_placer->locate(static_cast<component>(comp), node_attr_, &r)) if (!comp_placer->locate(static_cast<component>(comp), node_attr_, &r))
continue; continue;
if (r.is_hit(logic_pos)) if((comp == static_cast<int>(component::bground) && impl_->use_entire_line) || r.is_hit(logic_pos))
{ {
node_ = &node; node_ = &node;
what_ = static_cast<component>(comp); what_ = static_cast<component>(comp);
@ -1623,15 +1700,12 @@ namespace nana
} }
} }
return 0; //Stop iterating return enum_order::stop; //Stop iterating
} }
item_pos_.y += node_r.height; item_pos_.y += node_r.height;
if(node.value.second.expanded && node.child) return ((node.child && node.value.second.expanded) ? enum_order::proceed_with_children : enum_order::proceed);
return 1;
return 2;
} }
trigger::item_locator::node_type * trigger::item_locator::node() const trigger::item_locator::node_type * trigger::item_locator::node() const
@ -1662,11 +1736,11 @@ namespace nana
//class trigger //class trigger
//struct treebox_node_type //struct treebox_node_type
trigger::treebox_node_type::treebox_node_type() trigger::treebox_node_type::treebox_node_type()
:expanded(false), checked(checkstate::unchecked) :expanded(false), checked(checkstate::unchecked), hidden(false)
{} {}
trigger::treebox_node_type::treebox_node_type(std::string text) trigger::treebox_node_type::treebox_node_type(std::string text)
:text(std::move(text)), expanded(false), checked(checkstate::unchecked) :text(std::move(text)), expanded(false), checked(checkstate::unchecked), hidden(false)
{} {}
trigger::treebox_node_type& trigger::treebox_node_type::operator=(const treebox_node_type& rhs) trigger::treebox_node_type& trigger::treebox_node_type::operator=(const treebox_node_type& rhs)
@ -1952,13 +2026,14 @@ namespace nana
impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl); impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl);
auto const node = nl.node(); auto const node = nl.node();
if (!node) if (!node || !node->child)
return; return;
switch (nl.what()) switch (nl.what())
{ {
case component::icon: case component::icon:
case component::text: case component::text:
case component::bground:
impl_->set_expanded(node, !node->value.second.expanded); impl_->set_expanded(node, !node->value.second.expanded);
impl_->draw(true, true, false); impl_->draw(true, true, false);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
@ -2384,6 +2459,12 @@ namespace nana
return item_proxy(const_cast<drawer_trigger_t*>(dw), dw->impl()->node_state.pointed); return item_proxy(const_cast<drawer_trigger_t*>(dw), dw->impl()->node_state.pointed);
} }
void treebox::use_entire_line(bool enable)
{
auto dw = &get_drawer_trigger();
dw->impl()->use_entire_line = enable;
}
std::shared_ptr<scroll_operation_interface> treebox::_m_scroll_operation() std::shared_ptr<scroll_operation_interface> treebox::_m_scroll_operation()
{ {
internal_scope_guard lock; internal_scope_guard lock;

View File

@ -1473,7 +1473,7 @@ namespace paint
{ {
if (vertical) if (vertical)
{ {
int x1 = good_rct.x, x2 = good_rct.right(); int x1 = good_rct.x, x2 = good_rct.right() - 1;
auto y = good_rct.y; auto y = good_rct.y;
for (; y < endpos; ++y) for (; y < endpos; ++y)
{ {
@ -1489,7 +1489,7 @@ namespace paint
} }
else else
{ {
int y1 = good_rct.y, y2 = good_rct.bottom(); int y1 = good_rct.y, y2 = good_rct.bottom() - 1;
auto x = good_rct.x; auto x = good_rct.x;
for (; x < endpos; ++x) for (; x < endpos; ++x)
{ {

View File

@ -1,4 +1,4 @@
/* /**
* Paint Image Implementation * Paint Image Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
@ -7,9 +7,8 @@
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/paint/image.cpp * @file nana/paint/image.cpp
* @contributors: * @contributors nabijaczleweli(pr#106)
* nabijaczleweli(pr#106)
*/ */
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>

View File

@ -238,10 +238,18 @@ namespace nana{ namespace paint
auto d = rawptr; auto d = rawptr;
const unsigned char* s; const unsigned char* s;
int src_line_bytes;
if (is_negative) if (is_negative)
{
s = rawbits; s = rawbits;
src_line_bytes = -static_cast<int>(bytes_per_line);
}
else else
{
s = rawbits + bytes_per_line * (height - 1); s = rawbits + bytes_per_line * (height - 1);
src_line_bytes = static_cast<int>(bytes_per_line);
}
for(std::size_t i = 0; i < height; ++i) for(std::size_t i = 0; i < height; ++i)
{ {
@ -256,7 +264,7 @@ namespace nana{ namespace paint
s_p += 3; s_p += 3;
} }
d += pixel_size.width; d += pixel_size.width;
s -= bytes_per_line; s -= src_line_bytes;
} }
} }
else if(16 == bits_per_pixel) else if(16 == bits_per_pixel)