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
before_install:
# donwload nana-demo first
# we are in: 'user'/nana/
- cd ..
# we are in: 'user'/
- 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"
- 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
@ -53,76 +57,24 @@ install:
- /tmp/tools/cmake --prefix="$HOME" --exclude-subdir
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/
- "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
# 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:
- 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
- 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)
- ls
# we were still in: 'user'/demo-build/
- cd ../nana-test/bin
- ls
- ./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
- ls -lh

View File

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

View File

@ -1,12 +1,12 @@
# 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)
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

View File

@ -38,13 +38,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AN
endif()
if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # APPLE Clang
target_compile_options(nana PUBLIC -stdlib=libstdc++)
endif ()
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
target_compile_options(nana PRIVATE -fmax-errors=3)
endif()

View File

@ -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.
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
# of the project linking to the nana lib here generated
target_sources(nana PRIVATE ${HEADERS})
target_include_directories(nana PRIVATE ${NANA_INCLUDE_DIR})
message("The compiled Nana library will be installed in ${CMAKE_INSTALL_PREFIX}/lib")
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.
install(TARGETS nana
ARCHIVE DESTINATION lib
@ -15,8 +18,13 @@ if(NANA_CMAKE_INSTALL)
RUNTIME DESTINATION bin)
install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include) # in ${CMAKE_INSTALL_PREFIX}/include/nana
message("The Nana include files will be installed in ${CMAKE_INSTALL_PREFIX}/include")
target_include_directories(nana PUBLIC $<BUILD_INTERFACE:${NANA_INCLUDE_DIR}>
$<INSTALL_INTERFACE:include> )
else()
# 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_include_directories(nana PUBLIC ${NANA_INCLUDE_DIR})
endif()

View File

@ -1,30 +1,36 @@
# 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
# 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
# to "implement" it (ab)using Boost (almost compatible)
# The library may be not available or working correctly in the std library you use.
# 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
# or you can choose to use the (partial, but functional) implementation provided by nana.
# If you include the file <nana/filesystem/filesystem.hpp> or <nana/filesystem/filesystem_ext.hpp>
# the selected option will be set by nana into std::filesystem
# By default Nana will try to use the STD. If STD is not available and NANA_CMAKE_FIND_BOOST_FILESYSTEM
# is set to ON nana will try to use boost if available. Nana own implementation will be use if none of
# the previus were selected or available.
# By ncluding the file <nana/filesystem/filesystem.hpp> or <nana/filesystem/filesystem_ext.hpp>
# the selected option is inlined 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.
# You can change that default if you change one of the following
# (please don't define more than one of the _XX_FORCE options):
option(NANA_CMAKE_NANA_FILESYSTEM_FORCE "Force nana filesystem over ISO and boost?" OFF)
option(NANA_CMAKE_STD_FILESYSTEM_FORCE "Use of STD filesystem?(a compilation error will ocurre if not available)" OFF)
option(NANA_CMAKE_BOOST_FILESYSTEM_FORCE "Force use of Boost filesystem if available (over STD)?" OFF)
option(NANA_CMAKE_FIND_BOOST_FILESYSTEM "Search: Is Boost filesystem available?" OFF)
set (TEST_FS_LIB OFF)
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)
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)
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)
# 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,
@ -43,14 +49,131 @@ elseif(NANA_CMAKE_BOOST_FILESYSTEM_FORCE)
set(Boost_USE_STATIC_RUNTIME ON)
else()
# todo test for std (for now just force nana or boost if there no std)
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()
# todo if not test for boost
# if not add nana filesystem
endif()
# 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(NANA_STATIC_STDLIB "Link nana statically to C++ standard library" ON)
if(BUILD_SHARED_LIBS) # todo test
@ -35,12 +36,11 @@ if(BUILD_SHARED_LIBS) # todo test
endif()
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW??
if(BUILD_SHARED_LIBS)
target_compile_options(nana PUBLIC -lgcc -lstdc++)
else()
target_link_libraries(nana PUBLIC -static-libgcc -static-libstdc++)
endif(BUILD_SHARED_LIBS)
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()

View File

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

View File

@ -16,6 +16,7 @@
#define NANA_ANY_HPP
#include <typeinfo>
#include <type_traits>
#include <utility>
#include "c++defines.hpp"
@ -74,7 +75,7 @@ namespace nana
any(Value && value,
typename std::enable_if<!std::is_same<any&, 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>
any& operator=(Value&& other)
{
any(other).swap(*this);
any(std::forward<Value>(other)).swap(*this);
return *this;
}

View File

@ -1,7 +1,7 @@
/**
* Predefined Symbols for C++
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -48,14 +48,15 @@
#ifndef NANA_CXX_DEFINES_INCLUDED
#define NANA_CXX_DEFINES_INCLUDED
#define STD_FILESYSTEM_NOT_SUPPORTED
// #define STD_FILESYSTEM_NOT_SUPPORTED
//C++ language
#if defined(_MSC_VER)
# if (_MSC_VER < 1900)
# if (_MSC_VER < 1900) // VC2013
# //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,
# //So Nana use nana.filesystem implement instead for VC2013
# define STD_FILESYSTEM_NOT_SUPPORTED
#
# //Nana defines some macros for lack of support of keywords
# define _ALLOW_KEYWORD_MACROS
@ -64,8 +65,6 @@
# define noexcept //no support of noexcept until Visual C++ 2015
# define constexpr //no support of constexpr until Visual C++ 2015 ? const ??
# else
# undef STD_FILESYSTEM_NOT_SUPPORTED
# endif
#elif defined(__GNUC__) && not defined(__clang__)
# if (__GNUC__ == 4 && __GNUC_MINOR__ < 6)
@ -89,7 +88,7 @@
#define NANA_MINGW
#endif // MINGW
#elif defined(APPLE) //Mac OS X
#elif defined(__APPLE__) || defined(APPLE) //Mac OS X
//Symbols for MACOS
#define NANA_MACOS
#define NANA_POSIX
@ -125,16 +124,16 @@
#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__)
//<codecvt> is a known issue on libstdc++, it works on libc++
#define STD_CODECVT_NOT_SUPPORTED
#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__)
//<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
//It's a known issue of libstdc++ on MinGW
@ -155,6 +154,8 @@
# if ((__GNUC__ > 5) || ((__GNUC__ == 5) && (__GNUC_MINOR__ >= 3 ) ) )
# undef STD_FILESYSTEM_NOT_SUPPORTED
# else
# define STD_FILESYSTEM_NOT_SUPPORTED
# endif
#if (__GNUC__ == 4)

View File

@ -9,7 +9,7 @@
*
* @file nana/filesystem/filesystem.hpp
* @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
*/
@ -34,32 +34,26 @@
//Filesystem Selection
#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_STD_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
#define NANA_USING_NANA_FILESYSTEM 1
#elif (defined(BOOST_FILESYSTEM_AVAILABLE) && ( defined(BOOST_FILESYSTEM_FORCE) || ( defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(STD_FILESYSTEM_FORCE) ) ))
#undef NANA_USING_BOOST_FILESYSTEM
#define NANA_USING_BOOST_FILESYSTEM 1
# include <chrono>
# include <boost/filesystem.hpp>
// add boost::filesystem into std::experimental::filesystem
// inline boost::filesystem into std::filesystem
namespace std {
namespace experimental {
namespace filesystem {
inline namespace boost_filesystem {
using namespace boost::filesystem;
using file_time_type = std::chrono::time_point<std::chrono::system_clock>;
@ -75,16 +69,16 @@ namespace std {
socket = boost::filesystem::file_type::socket_file,
unknown = boost::filesystem::file_type::type_unknown,
};
// Boost dont include generic_u8string
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp
//
// Boost versions: 1.67.0, 1.66.0, ... 1.56.0 enable directory_iterator C++11 range-base for
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp
// but travis come with an oooold version of boost
// 1.55.0 NOT enable directory_iterator C++11 range-base for
// http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp
#if BOOST_VERSION < 105600
namespace boost
// Boost dont include generic_u8string
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp
//
// Boost versions: 1.67.0, 1.66.0, ... 1.56.0 enable directory_iterator C++11 range-base for
// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp
// but travis come with an oooold version of boost
// 1.55.0 NOT enable directory_iterator C++11 range-base for
// http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp
#if BOOST_VERSION < 105600
namespace boost { // todo ??
// 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
@ -99,19 +93,10 @@ namespace std {
{
return directory_iterator();
}
#endif
} // filesystem
} // experimental
namespace filesystem
{
using namespace experimental::filesystem;
}
#ifndef __cpp_lib_experimental_filesystem
# define __cpp_lib_experimental_filesystem 201406
#endif
#endif
} // boost_filesystem
} // filesystem
} // std
#else
@ -133,7 +118,7 @@ namespace std {
# undef NANA_USING_STD_EXPERIMENTAL_FILESYSTEM
# define NANA_USING_STD_EXPERIMENTAL_FILESYSTEM
# endif
#endif
#endif // BOOST_FILESYSTEM and NANA_FILESYSTEM
#if NANA_USING_NANA_FILESYSTEM
@ -148,25 +133,21 @@ namespace std {
#include <nana/deploy.hpp>
namespace nana { namespace experimental { namespace filesystem
{
#ifndef CXX_NO_INLINE_NAMESPACE
inline namespace v1
{
#endif
namespace nana {
namespace filesystem {
enum class file_type
{
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
regular = 1,
directory = 2 ,
symlink =3, ///< Symbolic link file
block =4, ///< Block special file
character= 5 , ///< Character special file
fifo = 6 , ///< FIFO or pipe file
socket =7,
unknown= 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other
directory = 2,
symlink = 3, ///< Symbolic link file
block = 4, ///< Block special file
character = 5, ///< Character special file
fifo = 6, ///< FIFO or pipe file
socket = 7,
unknown = 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other
};
enum class perms
@ -204,11 +185,14 @@ namespace nana { namespace experimental { namespace filesystem
// observers
file_type type() const;
perms permissions() const;
// modifiers
void type(file_type ft);
void permissions(perms prms);
private:
file_type value_;
perms perms_;
@ -236,105 +220,142 @@ namespace nana { namespace experimental { namespace filesystem
path() = default;
template<typename Source>
path(const Source& source)
path(const Source &source)
{
_m_assign(source);
}
// modifiers
void clear() noexcept;
path& make_preferred();
path& remove_filename();
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 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
bool empty() const noexcept;
bool has_root_name() const { return !root_name().empty(); }
bool has_root_directory() const { return !root_directory().empty(); }
bool has_root_path() const { return !root_path().empty(); }
bool has_relative_path() const { return !relative_path().empty(); }
bool has_parent_path() const { return !parent_path().empty(); }; // temp;;
bool has_filename() const { return !filename().empty(); }; // temp;
bool has_root_name() const
{ return !root_name().empty(); }
bool has_root_directory() const
{ return !root_directory().empty(); }
bool has_root_path() const
{ return !root_path().empty(); }
bool has_relative_path() const
{ return !relative_path().empty(); }
bool has_parent_path() const
{ return !parent_path().empty(); }; // temp;;
bool has_filename() const
{ return !filename().empty(); }; // temp;
//bool has_stem() const;
bool has_extension() const { return !extension().empty(); }; // temp
bool has_extension() const
{ return !extension().empty(); }; // temp
bool is_absolute() const;
bool is_relative() const;
int compare(const path& other) const;
int compare(const path &other) const;
file_type what() const;
const value_type*c_str() const;
const string_type& native() 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::string u8string() const;
// std::u16string u16string() const;
// std::u32string u32string() const;
std::string generic_string() const ;
std::string generic_string() const;
std::wstring generic_wstring() const;
std::string generic_u8string() 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);
path &operator/=(const path &other);
template<typename Source>
path& operator/=(const Source& source)
path &operator/=(const Source &source)
{
path other(source);
return this->operator/=(other);
}
template<typename Source>
path& append(const Source& 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);
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);
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
: public std::system_error
{
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, const path& path2, std::error_code err);
filesystem_error(const std::string &msg, const path &path1, std::error_code err);
const path& path1() const noexcept;
const path& path2() const noexcept;
filesystem_error(const std::string &msg, const path &path1, const path &path2, std::error_code err);
const path &path1() const noexcept;
const path &path2() const noexcept;
// const char* what() const noexcept;
private:
path path1_;
@ -346,65 +367,78 @@ namespace nana { namespace experimental { namespace filesystem
{
public:
directory_entry() = default;
explicit directory_entry(const ::nana::experimental::filesystem::path&);
explicit directory_entry(const filesystem::path &);
//modifiers
void assign(const ::nana::experimental::filesystem::path&);
void replace_filename(const ::nana::experimental::filesystem::path&);
void assign(const filesystem::path &);
void replace_filename(const filesystem::path &);
//observers
file_status status() const;
operator const filesystem::path&() const { return path_; };
const filesystem::path& path() const;
operator const filesystem::path &() const
{ return path_; };
const filesystem::path &path() const;
private:
::nana::experimental::filesystem::path path_;
filesystem::path path_;
};
/// InputIterator that iterate over the sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator
class directory_iterator :public std::iterator<std::input_iterator_tag, directory_entry>
class directory_iterator : public std::iterator<std::input_iterator_tag, directory_entry>
{
using find_handle = void*;
using find_handle = void *;
public:
directory_iterator() noexcept;
explicit directory_iterator(const path& p);
directory_iterator(const path& p, directory_options opt);
const value_type& operator*() const;
const value_type* operator->() const;
explicit directory_iterator(const path &p);
directory_iterator(const path &p, directory_options opt);
const value_type &operator*() const;
const value_type *operator->() const;
directory_iterator &operator++();
directory_iterator& operator++();
directory_iterator operator++(int); ///< extention
bool equal(const directory_iterator& x) const;
bool equal(const directory_iterator &x) const;
private:
template<typename Char>
static bool _m_ignore(const Char * p)
static bool _m_ignore(const Char *p)
{
while(*p == '.')
while (*p == '.')
++p;
return (*p == 0);
}
void _m_prepare(const path& file_path);
void _m_prepare(const path &file_path);
void _m_read();
private:
bool end_{false};
path::string_type path_;
directory_options option_{ directory_options::none };
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
inline directory_iterator begin(directory_iterator iter) noexcept
{
return iter;
}
inline directory_iterator end( const directory_iterator&) noexcept
inline directory_iterator end(const directory_iterator &) noexcept
{
return {};
}
@ -416,42 +450,46 @@ namespace nana { namespace experimental { namespace filesystem
//recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;
//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);
}
//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);
}
file_status status(const path& p);
file_status status(const path& p, std::error_code&);
file_status status(const path &p);
std::uintmax_t file_size(const path& p);
std::uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
file_status status(const path &p, std::error_code &);
std::uintmax_t file_size(const path &p);
std::uintmax_t file_size(const path &p, std::error_code &ec) noexcept;
inline bool is_directory(file_status s) noexcept
{ return s.type() == file_type::directory ;}
{ return s.type() == file_type::directory; }
bool is_directory(const path& p);
bool is_directory(const path& p, std::error_code& ec) noexcept;
bool is_directory(const path &p);
bool is_directory(const path &p, std::error_code &ec) noexcept;
inline bool is_regular_file(file_status s) noexcept
{
return s.type() == file_type::regular;
}
inline bool is_regular_file(const path& p)
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.
// 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)
inline bool is_empty(const path &p)
{
auto fs = status(p);
@ -463,34 +501,38 @@ namespace nana { namespace experimental { namespace filesystem
// 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_directory(const path &p);
//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);
//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
/// 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
//file_time_type last_write_time(const path& p, error_code& ec) noexcept;
path current_path();
//path current_path(error_code& ec);
void current_path(const path& p); ///< chdir
void current_path(const path &p); ///< chdir
//void current_path(const path& p, error_code& ec) noexcept;
bool remove(const path& p);
bool remove(const path& p, std::error_code& ec); // noexcept;
bool remove(const path &p);
bool remove(const path &p, std::error_code &ec); // noexcept;
//uintmax_t remove_all(const path& p);
//uintmax_t remove_all(const path& p, error_code& ec) noexcept;
template<typename CharType>
std::basic_string<CharType> parent_path(const std::basic_string<CharType>& path)
std::basic_string<CharType> parent_path(const std::basic_string<CharType> &path)
{
auto index = path.size();
@ -515,34 +557,45 @@ namespace nana { namespace experimental { namespace filesystem
return index ? path.substr(0, index + 1) : std::basic_string<CharType>();
}
#ifndef CXX_NO_INLINE_NAMESPACE
} //end namespace v1
#endif
} //end namespace filesystem
} //end namespace experimental
//namespace filesystem = experimental::filesystem;
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
namespace std
{
namespace filesystem
{
#if defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703)
using namespace ::nana::filesystem;
#else
inline namespace nana_filesystem
{
using namespace ::nana::filesystem;
}
#endif
}
}
namespace std {
namespace experimental {
namespace filesystem {
# ifdef CXX_NO_INLINE_NAMESPACE
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)))
#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
namespace std
{
namespace filesystem
{
#if defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703))
path absolute(const path& p);
path absolute(const path& p, std::error_code& err);
@ -552,33 +605,23 @@ namespace std {
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)
/*
#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
}
} // std
#else
//Implements the missing functions for various version of experimental/filesystem
# if defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM)
namespace std
{
namespace filesystem
{
*/
//Visual Studio 2017
#if (defined(_MSC_VER) && (_MSC_VER > 1912)) || \
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 801))
#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, std::error_code& err);
#endif
}
}
# endif
#endif
} // namespace filesystem
} // namespace std
#endif //NANA_USING_NANA_FILESYSTEM
#endif // incomplete STD_FILESYSTEM
#include <nana/pop_ignore_diagnostic>
#endif //NANA_FILESYSTEM_HPP

View File

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

View File

@ -85,6 +85,7 @@ namespace nana
virtual void mouse_dropfiles(graph_reference, const arg_dropfiles&);
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_char(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 move(const arg_move&, 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_char(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.
destroy, ///< A widget is about to be destroyed.
focus, ///< A widget's focus is changed.
key_ime,
key_press, ///< A keyboard is pressed on a focus widget.
key_char, ///< The focus widget received a character.
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
};
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
{
event_code evt_code; ///< it is event_code::key_press in current event

View File

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

View File

@ -1,13 +1,13 @@
/*
/**
* A Message Box Class
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/msgbox.hpp
* @file nana/gui/msgbox.hpp
*/
#ifndef NANA_GUI_MSGBOX_HPP
@ -81,8 +81,8 @@ namespace nana
return *this;
}
/// \brief Displays the message that buffered in the stream.
/// @return, the button that user clicked.
/// \brief Displays the message buffered in the stream.
/// @return, the button the user clicked.
pick_t show() const;
/// A function object method alternative to show()
@ -98,6 +98,9 @@ namespace nana
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
{
struct abstract_content
@ -110,6 +113,8 @@ namespace nana
};
public:
/// Shows a checkbox for boolean input
class boolean
: public abstract_content
{
@ -128,6 +133,7 @@ namespace nana
std::unique_ptr<implement> impl_;
};
/// Integer input
class integer
: public abstract_content
{
@ -146,6 +152,7 @@ namespace nana
std::unique_ptr<implement> impl_;
};
/// Floating-point number input.
class real
: public abstract_content
{
@ -164,6 +171,7 @@ namespace nana
std::unique_ptr<implement> impl_;
};
/// String input or an option from a dropdown list.
class text
: public abstract_content
{
@ -192,6 +200,7 @@ namespace nana
std::unique_ptr<implement> impl_;
};
/// Date input
class date
: public abstract_content
{
@ -214,6 +223,10 @@ namespace nana
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
: public abstract_content
{
@ -231,11 +244,26 @@ namespace nana
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 = {});
void image_v(::nana::paint::image, bool is_top, const rectangle& valid_area = {});
/// shows images at left/right side of inputbox
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>
bool show(Args&& ... args)
{
@ -251,6 +279,10 @@ namespace nana
return _m_open(contents, false);
}
/// 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)
{
@ -267,7 +299,7 @@ namespace nana
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);
/** 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.
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);
color fgcolor(window);

View File

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

View File

@ -87,10 +87,10 @@ namespace nana{
typedef widget_object<category::widget_tag, drawerbase::button::trigger> base_type;
public:
button();
button(window, bool visible);
button(window, const ::std::string& caption, bool visible = true);
button(window, const char* caption, bool visible = true);
button(window, const nana::rectangle& = rectangle(), bool visible = true);
button(window parent, bool visible);
button(window parent, const ::std::string& caption, bool visible = true);
button(window parent, const char* caption, bool visible = true);
button(window parent, const nana::rectangle& = rectangle(), bool visible = true);
/// 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_move(graph_reference, const arg_mouse&) 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_char(graph_reference, const arg_keyboard&) override;
private:

View File

@ -1,6 +1,6 @@
/*
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -95,6 +95,13 @@ namespace detail
typedef tree_node<element_type> node_type;
typedef typename node_type::value_type value_type;
enum class enum_order
{
stop, //Stop enumeration
proceed_with_children,
proceed
};
tree_cont()
:root_(nullptr)
{}
@ -234,59 +241,6 @@ namespace detail
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>
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.
while(node)
{
switch(f(*node, state))
enum_order order = f(*node, state);
if (enum_order::stop == order)
{
case 0: return;
case 1:
{
if(node->child)
return;
}
else if (node->child && (enum_order::proceed_with_children == order))
{
node = node->child;
state = 1;
}
else
return;
continue;
}
break;
}
if(node->next)
else if(node->next)
{
node = node->next;
state = 0;
@ -340,31 +288,37 @@ namespace detail
}
}
template<typename PredAllowChild>
unsigned child_size_if(const ::std::string& key, PredAllowChild pac) const
template<typename PredAllowChild, typename PredAllowNode>
unsigned child_size_if(const ::std::string& key, PredAllowChild pac, PredAllowNode pan) const
{
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>
unsigned child_size_if(const node_type& node, PredAllowChild pac) const
template<typename PredAllowChild, typename PredAllowNode>
unsigned child_size_if(const node_type& node, PredAllowChild pac, PredAllowNode pan) const
{
unsigned size = 0;
const node_type* pnode = node.child;
while(pnode)
{
if (!pan(*pnode))
{
pnode = pnode->next;
continue;
}
++size;
if(pnode->child && pac(*pnode))
size += child_size_if<PredAllowChild>(*pnode, pac);
size += child_size_if<PredAllowChild>(*pnode, pac, pan);
pnode = pnode->next;
}
return size;
}
template<typename PredAllowChild>
std::size_t distance_if(const node_type * node, PredAllowChild pac) const
template<typename PredAllowChild, typename PredAllowNode>
std::size_t distance_if(const node_type * node, PredAllowChild pac, PredAllowNode pan) const
{
if(nullptr == node) return 0;
const node_type * iterator = root_.child;
@ -374,6 +328,12 @@ namespace detail
while(iterator && iterator != node)
{
if (!pan(*iterator))
{
iterator = iterator->next;
continue;
}
++off;
if(iterator->child && pac(*iterator))
@ -393,8 +353,8 @@ namespace detail
return off;
}
template<typename PredAllowChild>
node_type* advance_if(node_type* node, std::size_t off, PredAllowChild pac)
template<typename PredAllowChild, typename PredAllowNode>
node_type* advance_if(node_type* node, std::size_t off, PredAllowChild pac, PredAllowNode pan)
{
if(nullptr == node) node = root_.child;
@ -402,6 +362,12 @@ namespace detail
while(node && off)
{
if (!pan(*node))
{
node = node->next;
continue;
}
--off;
if(node->child && pac(*node))
{
@ -490,7 +456,7 @@ namespace detail
void _m_for_each(const ::std::string& key, Function function) const
{
//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)
return;

View File

@ -1,13 +1,13 @@
/**
* A Form Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* 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
@ -42,7 +42,7 @@ namespace nana
//place methods
place & get_place();
void div(const char* div_text);
void div(std::string div_text);
place::field_reference operator[](const char* field_name);
void collocate() noexcept;
private:
@ -51,22 +51,29 @@ namespace nana
}//end namespace form
}//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
class form
: public drawerbase::form::form_base
{
public:
/// helper template class for creating the appearance of the form.
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.
form(const rectangle& = API::make_center(300, 200), const appearance& = {}); //Default constructor
/// Creates a window form owned by the desktop, at the point and size specified by rect, and with the specified appearance.
explicit form(const rectangle& = API::make_center(300, 200), const appearance& = {}); //Default 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.
explicit form(window owner, const ::nana::size& = { 300, 200 }, const appearance& = {});
explicit form(window owner, const rectangle&, const appearance& = {});
form(const form&, const ::nana::size& = { 300, 200 }, const appearance& = {}); //Copy constructor
form(window, 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.
form(window, const rectangle&, const appearance& = {});
/// Blocks the execution and other windows' messages until this window is closed.
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);

View File

@ -47,10 +47,10 @@ namespace nana
class column_interface
{
public:
/// Destructor
// Destructor
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;
/// Sets width
@ -824,6 +824,10 @@ namespace nana
/// Determines whether the item is displayed on the screen
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;
/// 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
using oresolver = drawerbase::listbox::oresolver;
/// The representation of an item
/// The representation of an item 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;
/// 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;
public:
/// Constructors
// Constructors
listbox() = default;
listbox(window, bool visible);
listbox(window, const rectangle& = {}, bool visible = true);
//Element access
// Element access
/// Returns the category at specified location pos, with bounds checking.
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);
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
/**
@ -1391,7 +1395,7 @@ the nana::detail::basic_window member pointer scheme
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
*/
@ -1406,7 +1410,6 @@ the nana::detail::basic_window member pointer scheme
bool assoc_ordered(bool);
void auto_draw(bool) noexcept; ///< Set state: Redraw automatically after an operation
template<typename Function>
@ -1432,6 +1435,8 @@ the nana::detail::basic_window member pointer scheme
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
///
/// 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::wstring text, unsigned width = 120);
@ -1480,7 +1485,7 @@ the nana::detail::basic_window member pointer scheme
void column_movable(bool);
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;
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
/**
* @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);
@ -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);
/// 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;
/// Returns the item which is hovered
/**
* @param return_end Indicates whether to return an end position instead of empty position if an item is not hovered.
* @return The position of the hovered item. If return_end is true, it returns the position next to the last item of last category if an item is not hovered.
* @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 and no item is hovered it returns the position next to the last item of last category.
*/
index_pair hovered(bool return_end) const;
/// Returns the absolute position of column which contains the specified point.
size_type column_from_pos(const point & pos) const;
/// Returns the absolute position of the column which contains the specified "screen" point.
size_type column_from_pos(const point & screen_pos) const;
void checkable(bool);
index_pairs checked() const; ///<Returns the items which are checked.
void checkable(bool make_checkeable); ///< Display a checkbox at te links of each item if make_checkeable=true
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(); ///<Removes all the items from all categories
void erase(size_type cat); ///<Erases a category
void erase(); ///<Erases all categories.
void erase(index_pairs indexes); ///<Erases specified items.
item_proxy erase(item_proxy);
void clear(size_type cat); ///< Removes all the items from the specified category
void clear(); ///< Removes all the items from all categories
void erase(size_type cat); ///< Erases a category
void erase(); ///< Erases all categories.
void erase(index_pairs indexes); ///< Erases specified items.
item_proxy erase(item_proxy indx); ///< Erases specified item.
bool sortable() const;
void sortable(bool enable);
bool sortable() const; ///< return whether the listbox is set to be sortable
void sortable(bool enable); ///< set the listbox to be or not to be sortable
///Sets a strict weak ordering comparer for a column
void set_sort_compare( size_type col,
std::function<bool(const std::string&, nana::any*,
const std::string&, nana::any*, bool reverse)> strick_ordering);
/// 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);
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();
///< Prevent sorting until `freeze` is set to false.
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);
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 disable_single(bool for_selection);
bool is_single_enabled(bool for_selection) const noexcept; ///< Determines whether the single selection/check is enabled.
export_options& def_export_options();
export_options& def_export_options(); ///< return a modifiable reference to the export options in use
/// 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(accepts);
bool respond_ime(const arg_ime& arg);
bool respond_char(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 shift_begin_caret;
}points_;
size_t composition_size_ { 0 };
};
}//end namespace skeletons
}//end namespace widgets

View File

@ -66,6 +66,7 @@ namespace nana
void mouse_move(graph_reference, const arg_mouse&) override;
void mouse_up(graph_reference, const arg_mouse& arg) 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_char(graph_reference, const arg_keyboard&) 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_leave(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_char(graph_reference, const arg_keyboard&) override;
void mouse_wheel(graph_reference, const arg_wheel&) override;

View File

@ -1,7 +1,7 @@
/**
* A Tree Box Implementation
* 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.
* (See accompanying file LICENSE or copy at
@ -49,7 +49,7 @@ namespace nana
struct node_attribute
{
bool has_children;
bool has_children; ///< Determines whether the node has visible children
bool expended;
checkstate checked;
bool selected;
@ -117,6 +117,7 @@ namespace nana
::std::string text;
nana::any value;
bool expanded;
bool hidden;
checkstate checked;
::std::string img_idstr;
};
@ -218,6 +219,12 @@ namespace nana
/// Select the node, and returns itself..
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.
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> 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> hidden; ///< a user hides or shows a node
};
}//end namespace treebox
}//end namespace drawerbase
@ -484,6 +492,14 @@ namespace nana
/// Gets the current hovered node.
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:
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
* 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
@ -170,8 +170,16 @@ namespace nana
}
/// 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
{
protected:
@ -293,8 +301,13 @@ namespace nana
std::unique_ptr<scheme_type> scheme_;
};//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
template<typename DrawerTrigger, typename Events, typename Scheme> //type DrawerTrigger must be derived from nana::drawer_trigger
/// 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
/// 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
{
protected:
@ -360,7 +373,13 @@ namespace nana
/// 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
{
protected:

View File

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

View File

@ -1,4 +1,4 @@
/*
/**
* A ISO C++ FileSystem Implementation
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
@ -6,16 +6,17 @@
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/filesystem/filesystem.cpp
* @description:
* @file nana/filesystem/filesystem.cpp
* @description
* provide some interface for file management
*/
#include <nana/config.hpp>
#include <nana/filesystem/filesystem_ext.hpp>
#include <vector>
#include <sstream>
#include <string>
#include <nana/config.hpp>
#ifdef _nana_std_put_time
#include <nana/stdc++.hpp>
#else
@ -148,16 +149,13 @@ namespace nana
}
}
#if NANA_USING_NANA_FILESYSTEM
namespace nana_fs = nana::experimental::filesystem;
namespace nana { namespace experimental { namespace filesystem
{
#ifndef CXX_NO_INLINE_NAMESPACE
inline namespace v1 {
#endif
#if NANA_USING_NANA_FILESYSTEM // and BOOST ?
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)
@ -185,7 +183,6 @@ namespace nana { namespace experimental { namespace filesystem
}
//end class filesystem_error
//Because of No wide character version of POSIX
#if defined(NANA_POSIX)
const char* separators = "/";
@ -512,10 +509,10 @@ namespace nana { namespace experimental { namespace filesystem
return to_wstring(pathstr_);
}
std::string path::u8string() const
/*std::string path::u8string() const
{
return to_utf8(pathstr_);
}
}*/
std::string path::generic_string() const
{
auto str = string();
@ -528,12 +525,12 @@ namespace nana { namespace experimental { namespace filesystem
std::replace(str.begin(), str.end(), L'\\', L'/');
return str;
}
std::string path::generic_u8string() const // uppss ...
/*std::string path::generic_u8string() const // uppss ...
{
auto str = pathstr_;
std::replace(str.begin(), str.end(), '\\', '/'); // uppss ... revise this !!!!!
return to_utf8(str);
}
}*/
path path::lexically_normal() const
{
@ -667,7 +664,7 @@ namespace nana { namespace experimental { namespace filesystem
}
//class directory_entry
directory_entry::directory_entry(const nana_fs::path& p)
directory_entry::directory_entry(const filesystem::path& p)
:path_{ p }
{}
@ -978,7 +975,6 @@ namespace nana { namespace experimental { namespace filesystem
#endif
}//end namespace detail
file_status status(const path& p)
{
std::error_code err;
@ -1182,19 +1178,216 @@ namespace nana { namespace experimental { namespace filesystem
#endif
}
#ifndef CXX_NO_INLINE_NAMESPACE
} //end namespace v1
path absolute(const path& p)
{
if (p.empty())
return p;
auto abs_base = current_path();
// store expensive to compute values that are needed multiple times
path p_root_name(p.root_name());
path base_root_name(abs_base.root_name());
path p_root_directory(p.root_directory());
if (!p_root_name.empty()) // p.has_root_name()
{
if (p_root_directory.empty()) // !p.has_root_directory()
return p_root_name / abs_base.root_directory()
/ abs_base.relative_path() / p.relative_path();
// p is absolute, so fall through to return p at end of block
}
else if (!p_root_directory.empty()) // p.has_root_directory()
{
#ifdef NANA_POSIX
// POSIX can have root name it it is a network path
if (base_root_name.empty()) // !abs_base.has_root_name()
return p;
#endif
}//end namespace filesystem
} //end namespace experimental
return base_root_name / p;
}
else
return abs_base / p;
return p; // p.is_absolute() is true
}
path absolute(const path& p, std::error_code& /*err*/)
{
return absolute(p);
}
path canonical(const path& p, std::error_code* err)
{
path source(p.is_absolute() ? p : absolute(p));
path root(source.root_path());
path result;
std::error_code local_ec;
file_status stat(status(source, local_ec));
if (stat.type() == file_type::not_found)
{
if (nullptr == err)
throw (filesystem_error(
"nana::filesystem::canonical", source,
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
#else
namespace std
{
namespace filesystem
{
#if defined(NANA_FILESYSTEM_FORCE) || \
(defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)))
#if defined(_MSC_VER) && (_MSC_VER < 1900) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703))
path absolute(const path& p)
{
if (p.empty())
@ -1379,8 +1572,8 @@ namespace std
return weakly_canonical(p, &err);
}
#endif
#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW)
/*
#if defined(NANA_MINGW)
bool exists( std::filesystem::file_status s ) noexcept
{
return s.type() != file_type::not_found;
@ -1395,20 +1588,10 @@ namespace std
{
return exists(status(p, ec));
}
#endif
}//end namespace filesystem
}//end namespace std
*/
#else //NANA_USING_NANA_FILESYSTEM
# if defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM)
//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))
#if (defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM) && defined(_MSC_VER) && (_MSC_VER > 1912)) || \
(!defined(__clang__) && defined(__GNUC__) && (__cplusplus < 201603 || (__GNUC__* 100 + __GNUC_MINOR__ < 801)))
namespace detail
{
@ -1551,10 +1734,9 @@ namespace std
{
return weakly_canonical(p, &err);
}
#endif
}
}
# endif
#endif
}//end namespace filesystem
}//end namespace std
#endif //NANA_USING_NANA_FILESYSTEM

View File

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

View File

@ -77,6 +77,9 @@ namespace detail
typedef BOOL (__stdcall* imm_set_composition_window_type)(HIMC, LPCOMPOSITIONFORM);
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)
//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);
HINSTANCE windows_module_handle()
{
MEMORY_BASIC_INFORMATION mbi;
static int dummy;
VirtualQuery(&dummy, &mbi, sizeof(mbi));
return reinterpret_cast<HINSTANCE>(mbi.AllocationBase);
}
bedrock::bedrock()
: pi_data_(new pi_data),
impl_(new private_impl)
{
nana::detail::platform_spec::instance(); //to guaranty the platform_spec object is initialized before using.
WNDCLASSEX wincl;
wincl.hInstance = ::GetModuleHandle(0);
wincl.hInstance = windows_module_handle();
wincl.lpszClassName = L"NanaWindowInternal";
wincl.lpfnWndProc = &Bedrock_WIN32_WindowProc;
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>(
::GetProcAddress(imm32, "ImmSetCompositionWindow"));
restrict::imm_get_composition_string = reinterpret_cast<restrict::imm_get_composition_string_type>(
::GetProcAddress(imm32, "ImmGetCompositionStringW"));
}
bedrock::~bedrock()
@ -223,6 +236,8 @@ namespace detail
delete impl_;
delete pi_data_;
::UnregisterClass(L"NanaWindowInternal", windows_module_handle());
}
@ -639,6 +654,8 @@ namespace detail
case WM_NCRBUTTONDOWN:
case WM_NCMBUTTONDOWN:
case WM_IME_STARTCOMPOSITION:
case WM_IME_COMPOSITION:
case WM_IME_CHAR:
case WM_DROPFILES:
case WM_MOUSELEAVE:
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;
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();
LOGFONTW logfont;
::GetObjectW(reinterpret_cast<HFONT>(native_font), sizeof logfont, &logfont);
msgwnd = brock.focus();
if (msgwnd && msgwnd->flags.enabled)
{
auto & wd_manager = brock.wd_manager();
auto composition_index = static_cast<DWORD>(lParam & (GCS_COMPSTR | GCS_RESULTSTR));
arg_ime arg;
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;
}
HIMC imc = restrict::imm_get_context(root_window);
restrict::imm_set_composition_font(imc, &logfont);
POINT pos;
::GetCaretPos(&pos);
COMPOSITIONFORM cf = { CFS_POINT };
cf.ptCurrentPos = pos;
restrict::imm_set_composition_window(imc, &cf);
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);
if (wd_manager.available(msgwnd))
draw_invoker(&drawer::key_ime, msgwnd, arg, &context);
wd_manager.do_lazy_refresh(msgwnd, false);
}
}
def_window_proc = true;
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:
{
bool take_over = false;

View File

@ -96,6 +96,11 @@ namespace nana
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&)
{
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);
}
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)
{
_m_emit(event_code::key_press, arg, &drawer_trigger::key_press, bForce__EmitInternal);

View File

@ -21,6 +21,10 @@
#include <map>
#ifdef NANA_X11
# include <atomic>
#endif
namespace nana{
namespace detail
{
@ -75,6 +79,15 @@ namespace nana{
root_misc(root_misc&&);
root_misc(basic_window * wd, unsigned width, unsigned height);
~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:
root_misc(const root_misc&) = delete;
root_misc& operator=(const root_misc&) = delete;

View File

@ -17,14 +17,15 @@
#include <nana/gui/detail/window_manager.hpp>
#if defined(NANA_WINDOWS)
#if defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp>
#else
#include <mutex>
#endif
#include <map>
# if defined(STD_THREAD_NOT_SUPPORTED)
# include <nana/std_mutex.hpp>
# else
# include <mutex>
# endif
# include <map>
#elif defined(NANA_X11)
#include <nana/system/platform.hpp>
# include <nana/system/platform.hpp>
# include "inner_fwd_implement.hpp"
#endif
#include "../../paint/image_accessor.hpp"
@ -34,6 +35,10 @@ namespace nana{
namespace detail{
#if defined(NANA_WINDOWS)
//This function is defined in bedrock_windows.cpp
HINSTANCE windows_module_handle();
class tray_manager
{
struct window_extra_t
@ -199,26 +204,87 @@ namespace nana{
namespace x11_wait
{
struct param
{
Window handle;
root_misc * misc;
std::size_t comp_value;
};
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)
{
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)
{
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;
::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
@ -315,7 +381,7 @@ namespace nana{
HWND native_wd = ::CreateWindowEx(style_ex, L"NanaWindowInternal", L"Nana Window",
style,
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.
::RECT client;
@ -504,7 +570,7 @@ namespace nana{
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS,
r.x, r.y, r.width, r.height,
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)
nana::detail::platform_scope_guard psg;
@ -758,13 +824,17 @@ namespace nana{
if(show == is_window_visible(wd))
return;
auto misc = bedrock::instance().wd_manager().root_runtime(wd);
if(show)
{
std::size_t cmp_value = misc->x11msg.map;
::XMapWindow(disp, reinterpret_cast<Window>(wd));
//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.
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);
if(grab == reinterpret_cast<Window>(wd))
@ -772,10 +842,12 @@ namespace nana{
}
else
{
std::size_t cmp_value = misc->x11msg.unmap;
::XUnmapWindow(disp, reinterpret_cast<Window>(wd));
//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.
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.
@ -1019,11 +1091,15 @@ namespace nana{
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);
//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.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure, cmp_value);
#endif
}
@ -1109,6 +1185,9 @@ namespace nana{
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);
//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
//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;
#endif
@ -1283,11 +1362,15 @@ namespace nana{
hints.min_height = hints.max_height = sz.height;
::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);
//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.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure, cmp_value);
return true;
#endif
}

View File

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

View File

@ -1,4 +1,4 @@
/*
/**
* A Message Box Class
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
@ -7,10 +7,15 @@
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/msgbox.hpp
* @file nana/gui/msgbox.hpp
* @Contributors
* 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/msgbox.hpp>
@ -27,8 +32,7 @@
#include <nana/datetime.hpp>
#include <nana/internationalization.hpp>
#include <nana/gui/filebox.hpp>
#include <functional>
#include <cstdlib> //include std::abs
#if defined(NANA_WINDOWS)
#include <windows.h>
#elif defined(NANA_X11)
@ -494,21 +498,29 @@ namespace nana
//end class msgbox
//class inputbox
//class inputbox todo: add schema
class inputbox_window
: public ::nana::form
{
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<>())
{
throw_not_utf8(desc);
throw_not_utf8(description);
throw_not_utf8(title);
desc_.create(*this);
desc_.format(true).caption(desc);
auto desc_extent = desc_.measure(470);
description_.create(*this);
description_.format(true).caption(description);
auto description_size = description_.measure(470);
btn_ok_.create(*this);
btn_ok_.i18n(i18n_eval("NANA_BUTTON_OK"));
@ -527,32 +539,26 @@ namespace nana
close();
});
unsigned height = 20 + desc_extent.height + 10 + 38;
unsigned height = 20 + description_size.height + 10 + 38;
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)
{
unsigned px = 27;
if (each_height[i] > 27)
px = each_height[i];
unsigned px = std::max(27u, 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 (desc_extent.width < 200)
desc_extent.width = 200;
if (description_size.width < 200)
description_size.width = 200;
//Make sure the complete display of input extent
if (desc_extent.width < fixed_pixels)
desc_extent.width = fixed_pixels;
if (description_size.width < fixed_pixels)
description_size.width = fixed_pixels;
desc_extent.width += 20;
description_size.width += 20; // 2x margin 10
::nana::size img_sz[4];
@ -566,8 +572,9 @@ namespace nana
}
else
sz = imgs[2].size();
sz.width = static_cast<size::value_type>(double(sz.width) * (double(height) / double(sz.height)));
desc_extent.width += sz.width;
const double scale_factor = double(height) / double(sz.height);
sz.width = static_cast<size::value_type>(double(sz.width) * scale_factor);
description_size.width += sz.width;
}
if (imgs[3]) //Right
@ -581,7 +588,7 @@ namespace nana
else
sz = imgs[3].size();
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
@ -594,7 +601,8 @@ namespace nana
}
else
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;
}
@ -608,16 +616,28 @@ namespace nana
}
else
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;
}
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();
place.div(ss.str().c_str());
place["desc"] << desc_;
place["description"] << description_;
place["buttons"] << btn_ok_ << btn_cancel_;
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]);
}
move(API::make_center(this->owner(), desc_extent.width, height));
move(API::make_center(this->owner(), description_size.width, height));
caption(title);
}
@ -659,7 +679,7 @@ namespace nana
return valid_input_;
}
private:
::nana::label desc_;
::nana::label description_;
::nana::button btn_ok_;
::nana::button btn_cancel_;
bool valid_input_{ false };
@ -1247,7 +1267,7 @@ namespace nana
auto files = impl->fbox.show();
if(!files.empty())
{
impl->value = files.front().u8string();
impl->value = files.front().string();
impl->path_edit.caption(impl->value);
}
});

View File

@ -146,6 +146,7 @@ namespace nana
//draw caption
auto text = to_wstring(API::window_caption(window_handle_));
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

View File

@ -111,13 +111,13 @@ namespace nana
{
public:
#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),
timer_(tmid),
evt_elapse_(evt_elapse)
{}
#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),
timer_(this),
evt_elapse_(evt_elapse)
@ -142,12 +142,15 @@ namespace nana
{
arg_elapse arg;
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:
timer * const sender_;
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
@ -175,8 +178,9 @@ namespace nana
};
//class timer
timer::timer()
: impl_(new implement)
timer::timer():
elapse_(std::make_shared<nana::basic_event<arg_elapse>>()),
impl_(new implement)
{
}
@ -195,7 +199,7 @@ namespace nana
void timer::reset()
{
stop();
elapse_.clear();
elapse_->clear();
}
void timer::start()

View File

@ -773,6 +773,13 @@ namespace nana
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)
{
drawer_->editor()->respond_char(arg);

View File

@ -39,7 +39,7 @@ namespace nana
place & form_base::get_place()
{
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_)
place_.reset(new place{ *this });
@ -47,9 +47,9 @@ namespace nana
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)

View File

@ -184,7 +184,13 @@ namespace nana
index(pos),
ess_(ess)
{
if (px == 0)
{
fit_width_to_header();
}
}
void fit_width_to_header();
private:
/// The definition is provided after essence
void _m_refresh() noexcept;
@ -2308,7 +2314,8 @@ namespace nana
size_type count_of_exposed(bool with_rest) const
{
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
@ -2394,7 +2401,9 @@ namespace nana
nana::rectangle 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))
new_where.first = parts::checker;
}
@ -2881,10 +2890,26 @@ namespace nana
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
void es_header::column::_m_refresh() noexcept
{
ess_->update(true);
ess_->update(false);
}
size_type es_header::column::position(bool disp_order) const noexcept
@ -3316,16 +3341,27 @@ namespace nana
return false;
}
// init ir end to grab a header
void grab(const nana::point& pos, bool is_grab)
{
if(is_grab)
if(is_grab) // init grabbing the header
{
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
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))
essence_->header.move(essence_->pointer_where.second, grab_terminal_.index, grab_terminal_.place_front);
else // end to grab the header
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
@ -4273,7 +4309,10 @@ namespace nana
auto const good_list_r = essence_->rect_lister(list_r);
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;
if(good_head_r)
@ -4282,7 +4321,8 @@ namespace nana
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));
@ -4455,13 +4495,16 @@ namespace nana
bool need_refresh = false;
//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
if(essence_->pointer_where.second < essence_->header.cont().size())
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;
essence_->widget_to_header(pos);
@ -4762,7 +4805,7 @@ namespace nana
bool item_proxy::empty() const noexcept
{
return !ess_;
return !(ess_ && ess_->lister.good(pos_));
}
item_proxy & item_proxy::check(bool ck, bool scroll_view)
@ -5959,6 +6002,7 @@ namespace nana
{
internal_scope_guard lock;
_m_ess().lister.sort_column(col, &reverse);
_m_ess().update();
}
auto listbox::sort_col() const -> size_type
@ -6073,7 +6117,15 @@ namespace nana
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

View File

@ -922,7 +922,25 @@ namespace nana
}
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;

View File

@ -96,11 +96,11 @@ namespace nana
{
if (widget_)
{
auto value_px = (widget_->size().width - border_px * 2);
unsigned value_px = (widget_->size().width - border_px * 2);
//avoid overflow
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_)
{

View File

@ -1163,6 +1163,43 @@ namespace nana {
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
{
if (!API::window_enabled(window_))

View File

@ -621,6 +621,13 @@ namespace nana
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)
{
if (impl_->editor()->respond_key(arg))

View File

@ -1229,7 +1229,8 @@ namespace nana
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)

View File

@ -152,6 +152,13 @@ namespace drawerbase {
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)
{
editor_->respond_key(arg);

View File

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

View File

@ -1,7 +1,7 @@
/*
* A Treebox Implementation
* 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.
* (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)
{
if(node->value.second.expanded)
if(node->value.second.expanded && !node->value.second.hidden)
{
node = node->child;
while(node)
@ -79,7 +79,7 @@ namespace nana
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);
if(t || finish)
@ -184,10 +184,11 @@ namespace nana
class trigger::item_locator
{
public:
using enum_order = tree_cont_type::enum_order;
using node_type = tree_cont_type::node_type;
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;
component what() 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
//@brief: some data for treebox trigger
class trigger::implementation
@ -220,6 +229,7 @@ namespace nana
: public compset_interface
{
public:
using enum_order = tree_cont_type::enum_order;
using node_type = tree_cont_type::node_type;
item_rendering_director(implementation * impl, const nana::point& pos):
@ -232,9 +242,11 @@ namespace nana
//0 = Sibling, the last is a sibling 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.
int operator()(const node_type& node, int affect)
enum_order operator()(const node_type& node, int affect)
{
iterated_node_ = &node;
// Increase/decrease indent
switch (affect)
{
case 1:
@ -245,6 +257,9 @@ namespace nana
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;
impl_->assign_node_attr(node_attr_, iterated_node_);
@ -263,9 +278,9 @@ namespace nana
pos_.y += node_r_.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:
//Overrides compset_interface
@ -280,7 +295,12 @@ namespace nana
if (impl_->data.comp_placer->locate(comp, node_attr_, &attr.area))
{
attr.mouse_pointed = node_attr_.mouse_pointed;
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;
return true;
}
@ -347,6 +367,9 @@ namespace nana
std::size_t scroll_timestamp;
nana::timer timer;
}adjust;
bool use_entire_line;
public:
implementation()
{
@ -371,11 +394,24 @@ namespace nana
adjust.offset_x_adjust = 0;
adjust.node = nullptr;
adjust.scroll_timestamp = 0;
use_entire_line = false;
}
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.text = node->value.second.text;
ndattr.checked = node->value.second.checked;
@ -552,7 +588,7 @@ namespace nana
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;
continue;
@ -603,8 +639,8 @@ namespace nana
}
}
auto pos = tree.distance_if(node, pred_allow_child{});
auto last_pos = tree.distance_if(last(true), 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{}, pred_allow_node{});
auto const capacity = screen_capacity(true);
@ -612,7 +648,7 @@ namespace nana
//position of the requested item.
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)
bearing = align_v::top;
@ -655,7 +691,7 @@ namespace nana
}
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
show_scroll();
@ -669,8 +705,8 @@ namespace nana
auto & tree = attr.tree_cont;
auto const first_pos = tree.distance_if(shape.first, pred_allow_child{});
auto const node_pos = tree.distance_if(node, 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{}, pred_allow_node{});
auto const max_allow = max_allowed();
switch(reason)
{
@ -680,12 +716,12 @@ namespace nana
//adjust if the number of its children are over the max number allowed
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)
{
auto const size = node_pos - first_pos + child_size + 1;
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
shape.first = node;
@ -698,7 +734,7 @@ namespace nana
if (visual_size > max_allow)
{
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
shape.first = nullptr;
@ -739,7 +775,7 @@ namespace nana
}
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;
}
}
@ -814,6 +850,27 @@ namespace nana
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()
{
if(nullptr == data.graph) return;
@ -841,7 +898,7 @@ namespace nana
adjust.scroll_timestamp = nana::system::timestamp();
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);
});
}
@ -850,13 +907,13 @@ namespace nana
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);
}
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
@ -1153,6 +1210,20 @@ namespace nana
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
{
return node_->value.second.img_idstr;
@ -1274,7 +1345,10 @@ namespace nana
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*()
@ -1395,7 +1469,7 @@ namespace nana
switch(comp)
{
case component_t::expander:
if(attr.has_children)
if (attr.has_children)
{
r->width = scheme_.item_offset;
return true;
@ -1581,7 +1655,7 @@ namespace nana
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)
{
@ -1592,6 +1666,9 @@ namespace nana
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);
nana::rectangle node_r;
auto & comp_placer = impl_->data.comp_placer;
@ -1609,7 +1686,7 @@ namespace nana
if (!comp_placer->locate(static_cast<component>(comp), node_attr_, &r))
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;
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;
if(node.value.second.expanded && node.child)
return 1;
return 2;
return ((node.child && node.value.second.expanded) ? enum_order::proceed_with_children : enum_order::proceed);
}
trigger::item_locator::node_type * trigger::item_locator::node() const
@ -1662,11 +1736,11 @@ namespace nana
//class trigger
//struct 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)
: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)
@ -1952,13 +2026,14 @@ namespace nana
impl_->attr.tree_cont.for_each<item_locator&>(shape.first, nl);
auto const node = nl.node();
if (!node)
if (!node || !node->child)
return;
switch (nl.what())
{
case component::icon:
case component::text:
case component::bground:
impl_->set_expanded(node, !node->value.second.expanded);
impl_->draw(true, true, false);
API::dev::lazy_refresh();
@ -2384,6 +2459,12 @@ namespace nana
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()
{
internal_scope_guard lock;

View File

@ -1473,7 +1473,7 @@ namespace paint
{
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;
for (; y < endpos; ++y)
{
@ -1489,7 +1489,7 @@ namespace paint
}
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;
for (; x < endpos; ++x)
{

View File

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

View File

@ -238,10 +238,18 @@ namespace nana{ namespace paint
auto d = rawptr;
const unsigned char* s;
int src_line_bytes;
if (is_negative)
{
s = rawbits;
src_line_bytes = -static_cast<int>(bytes_per_line);
}
else
{
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)
{
@ -256,7 +264,7 @@ namespace nana{ namespace paint
s_p += 3;
}
d += pixel_size.width;
s -= bytes_per_line;
s -= src_line_bytes;
}
}
else if(16 == bits_per_pixel)