diff --git a/.gitignore b/.gitignore index 53eee01b..71a1545a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ lib/ *.ninja* CMakeCache.txt CMakeFiles/ +.idea/ cmake_install.cmake *.DS_Store .idea/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b65dadc..e416d60c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,23 @@ # Contributor: # Robert Hauck - Enable support for PNG/Freetype # Qiangqiang Wu - Add biicode support +# Ariel Vina-Rodriguez (qPCR4vir) + +#https://cmake.org/cmake-tutorial/ +#https://cmake.org/cmake/help/v3.3/module/CMakeDependentOption.html?highlight=cmakedependentoption +# use CACHE FORCE or set(USE_meganz_mingw_std_threads ON) or delete CMakecache.txt or the entirely build dir +# if your changes don't execute +option(USE_meganz_mingw_std_threads "replaced boost.thread with meganz's mingw-std-threads." OFF) +option(USE_UNICODE "Use Unicode Character Set" ON) +option(ENABLE_PNG "Enable the use of PNG" OFF) +option(LIBPNG_FROM_OS "Use libpng from operating system." ON) +option(ENABLE_JPEG "Enable the use of JPEG" OFF) +option(LIBJPEG_FROM_OS "Use libjpeg from operating system." ON) +option(CMAKE_VERBOSE_PREPROCESSOR "Show annoying debug messages during compilation." OFF) +option(CMAKE_STOP_VERBOSE_PREPROCESSOR "Stop compilation after showing the annoying debug messages." ON) +option(BUILD_NANA_DEMOS "Build all the demos form the nana_demo repository." OFF) +option(CMAKE_STD_make_unique_NOT_SUPPORTED "Add support for make_unique<>()." OFF) +#set(CMAKE_STD_make_unique_NOT_SUPPORTED OFF) # set compile flags if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") @@ -18,37 +35,47 @@ if(BIICODE) add_biicode_targets() return() -endif() +endif(BIICODE) project(nana) cmake_minimum_required(VERSION 2.8) -#Global MSVC definitions if(WIN32) - if(MSVC) + add_definitions(-DWIN32) + + #Global MSVC definitions + if(MSVC) option(WIN32_USE_MP "Set to ON to build nana with the /MP option (Visual Studio 2005 and above)." ON) # ?? if(WIN32_USE_MP) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") - endif() - + endif(WIN32_USE_MP) endif(MSVC) + + if(MINGW) + add_definitions(-DMINGW) + #Find PNG + if(USE_meganz_mingw_std_threads) + add_definitions(-DUSE_github_com_meganz_mingw_std_threads) + # remove_definitions() + endif(USE_meganz_mingw_std_threads) + endif(MINGW) + endif(WIN32) #Unicode -option(USE_UNICODE "Use Unicode Character Set") if(USE_UNICODE) add_definitions(-DNANA_UNICODE) -endif() +endif(USE_UNICODE) if(APPLE) add_definitions(-DAPPLE) include_directories(/opt/X11/include/) elseif(UNIX) add_definitions(-Dlinux) -endif() +endif(APPLE) @@ -56,19 +83,10 @@ if(UNIX) find_package(Freetype) if (FREETYPE_FOUND) include_directories( ${FREETYPE_INCLUDE_DIRS}) - endif() -endif() - -if(WIN32) - add_definitions(-DWIN32) - if(MINGW) - add_definitions(-DMINGW) - endif() -endif() + endif(FREETYPE_FOUND) +endif(UNIX) #Find PNG -option(ENABLE_PNG "Enable the use of PNG") -option(LIBPNG_FROM_OS "Use libpng from operating system.") if(ENABLE_PNG) add_definitions(-DNANA_ENABLE_PNG) if(LIBPNG_FROM_OS) @@ -76,13 +94,11 @@ if(ENABLE_PNG) if (PNG_FOUND) include_directories( ${PNG_INCLUDE_DIRS}) add_definitions(-DUSE_LIBPNG_FROM_OS) - endif() - endif() -endif() + endif(PNG_FOUND) + endif(LIBPNG_FROM_OS) +endif(ENABLE_PNG) #Find JPEG -option(ENABLE_JPEG "Enable the use of JPEG") -option(LIBJPEG_FROM_OS "Use libjpeg from operating system.") if(ENABLE_JPEG) add_definitions(-DNANA_ENABLE_JPEG) if(LIBJPEG_FROM_OS) @@ -90,12 +106,23 @@ if(ENABLE_JPEG) if (JPEG_FOUND) include_directories( ${JPEG_INCLUDE_DIRS}) add_definitions(-DUSE_LIBJPEG_FROM_OS) - endif() - endif() -endif() + endif(JPEG_FOUND) + endif(LIBJPEG_FROM_OS) +endif(ENABLE_JPEG) +#Unicode +if(CMAKE_VERBOSE_PREPROCESSOR) + add_definitions(-DVERBOSE_PREPROCESSOR) +endif(CMAKE_VERBOSE_PREPROCESSOR) + +# STD_make_unique_NOT_SUPPORTED +if(CMAKE_STD_make_unique_NOT_SUPPORTED) + add_definitions(-DSTD_make_unique_NOT_SUPPORTED) +endif(CMAKE_STD_make_unique_NOT_SUPPORTED) + + set(NANA_SOURCE_DIR ${CMAKE_SOURCE_DIR}/source) set(NANA_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) @@ -116,13 +143,16 @@ aux_source_directory(${NANA_SOURCE_DIR}/paint/detail NANA_PAINT_DETAIL_SOURCE) aux_source_directory(${NANA_SOURCE_DIR}/system NANA_SYSTEM_SOURCE) aux_source_directory(${NANA_SOURCE_DIR}/threads NANA_THREADS_SOURCE) +#To show .h files in Visual Studio, add them to the list of sources in add_executable / add_library +#and Use SOURCE_GROUP if all your sources are in the same directory + add_library(${PROJECT_NAME} ${NANA_SOURCE} ${NANA_DETAIL_SOURCE} ${NANA_FILESYSTEM_SOURCE} -#if(NOT APPLE) +if(NOT APPLE) ${NANA_AUDIO_SOURCE} ${NANA_AUDIO_DETAIL_SOURCE} -#endif +endif (NOT APPLE) ${NANA_GUI_SOURCE} ${NANA_GUI_DETAIL_SOURCE} ${NANA_GUI_WIDGETS_SOURCE} @@ -132,17 +162,82 @@ add_library(${PROJECT_NAME} ${NANA_SOURCE} ${NANA_SYSTEM_SOURCE} ${NANA_THREADS_SOURCE}) -#if(APPLE) -target_link_libraries(${PROJECT_NAME} -L/opt/X11/lib/ -lX11 -lXft -lpng -liconv) -#endif() +if(APPLE) + #Headers: use INCLUDE_DIRECTORIES + # Libraries: use FIND_LIBRARY and link with the result of it (try to avoid LINK_DIRECTORIES + target_link_libraries(${PROJECT_NAME} -L/opt/X11/lib/ -lX11 -lXft -lpng -liconv) + +endif(APPLE) install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) +# ?? install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include) set_property( TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14 ) -add_executable(nana_test test.cpp) -set_property( TARGET nana_test PROPERTY CXX_STANDARD 14 ) -target_link_libraries(nana_test ${PROJECT_NAME}) +if (BUILD_NANA_DEMOS) + set (CMAKE_INSTALL_PREFIX ${DEMO_BIN}) + set(DEMO_BIN ${NANA_SOURCE_DIR}../nana-demo/bin) + set(CMAKE_INSTALL_PREFIX ) + add_executable(file_explorer ../nana-demo/file_explorer.cpp) + set_property( TARGET file_explorer PROPERTY CXX_STANDARD 14 ) + target_link_libraries(file_explorer ${PROJECT_NAME}) + install(TARGETS file_explorer RUNTIME DESTINATION &{DEMO_BIN}) + + add_executable(calculator ../nana-demo/calculator.cpp) + set_property( TARGET calculator PROPERTY CXX_STANDARD 14 ) + target_link_libraries(calculator ${PROJECT_NAME}) + install(TARGETS calculator RUNTIME DESTINATION &{DEMO_BIN}) + + add_executable(FreeMe ../nana-demo/FreeMe.cpp) + set_property( TARGET FreeMe PROPERTY CXX_STANDARD 14 ) + target_link_libraries(FreeMe ${PROJECT_NAME}) + install(TARGETS FreeMe RUNTIME DESTINATION &{DEMO_BIN}) + + add_executable(notepad ../nana-demo/notepad.cpp) + set_property( TARGET notepad PROPERTY CXX_STANDARD 14 ) + target_link_libraries(notepad ${PROJECT_NAME}) + install(TARGETS notepad RUNTIME DESTINATION &{DEMO_BIN}) + + add_executable(widget_show ../nana-demo/widget_show.cpp) + set_property( TARGET widget_show PROPERTY CXX_STANDARD 14 ) + target_link_libraries(widget_show ${PROJECT_NAME}) + install(TARGETS widget_show RUNTIME DESTINATION &{DEMO_BIN}) + + add_executable(widget_show2 ../nana-demo/widget_show2.cpp) + set_property( TARGET widget_show2 PROPERTY CXX_STANDARD 14 ) + target_link_libraries(widget_show2 ${PROJECT_NAME}) + install(TARGETS widget_show2 RUNTIME DESTINATION &{DEMO_BIN}) + + add_executable(a_group_impl ../nana-demo/Examples/a_group_impl.cpp) + set_property( TARGET a_group_impl PROPERTY CXX_STANDARD 14 ) + target_link_libraries(a_group_impl ${PROJECT_NAME}) + + add_executable(animate-bmp ../nana-demo/Examples/animate-bmp.cpp) + set_property( TARGET animate-bmp PROPERTY CXX_STANDARD 14 ) + target_link_libraries(animate-bmp ${PROJECT_NAME}) + + add_executable(audio_player ../nana-demo/Examples/audio_player.cpp) + set_property( TARGET audio_player PROPERTY CXX_STANDARD 14 ) + target_link_libraries(audio_player ${PROJECT_NAME}) + + + #add_executable(nana_test test.cpp) + #set_property( TARGET nana_test PROPERTY CXX_STANDARD 14 ) + #target_link_libraries(nana_test ${PROJECT_NAME}) + + #set(NANA_DEMOS_DIR ${CMAKE_SOURCE_DIR}/../nana-demo) + #set(NANA_EXAMPLES_DIR ${CMAKE_SOURCE_DIR}/../Examples/nana-demo/) + # https://cmake.org/cmake/help/v3.3/command/file.html?highlight=glob#file + #file( GLOB_RECURSE DEMO_SOURCES RELATIVE ../nana-demo *.cpp ) + + #foreach( demofile ${DEMO_SOURCES} ) + # string( REPLACE ".cpp" "" demoname ${demofile} ) + # add_executable( ${demoname} ${demofile} ) + # set_property( TARGET ${demoname} PROPERTY CXX_STANDARD 14 ) + # target_link_libraries(${demoname} ${PROJECT_NAME}) + #endforeach( demofile ${DEMO_SOURCES} ) +endif(BUILD_NANA_DEMOS) + diff --git a/include/nana/config.hpp b/include/nana/config.hpp index e97c70f6..696492de 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -7,7 +7,39 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/config.hpp + * @file nana/config.hpp + * + * @brief Provide switches to adapt to the target OS, use of external libraries or workarounds compiler errors or lack of std C++ support. + * + * To control target OS/compiler: + * - NANA_WINDOWS + * - NANA_MINGW + * - NANA_POSIX + * - NANA_LINUX + * - NANA_MACOS + * - NANA_X11 + * - NANA_UNICODE + * + * External libraries: + * - NANA_LIBPNG, USE_LIBPNG_FROM_OS + * - NANA_LIBJPEG, USE_LIBJPEG_FROM_OS + * + * (see: Feature-testing recommendations for C++ + * in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0096r0.html + * for example: __cpp_lib_experimental_filesystem = 201406 in is a known issue on libstdc++, it works on libc++) + * - STD_THREAD_NOT_SUPPORTED (GCC < 4.8.1) + * - STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED (MinGW with GCC < 4.8.1) + * - USE_github_com_meganz_mingw_std_threads (MinGW with GCC < 4.8.1) + * - STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED (MinGW with GCC < 4.8.1) + * - STD_TO_STRING_NOT_SUPPORTED (MinGW with GCC < 4.8) + * - VERBOSE_PREPROCESSOR, STOP_VERBOSE_PREPROCESSOR + * - STD_make_unique_NOT_SUPPORTED (MinGW with GCC < 4.8.1) + * or __cpp_lib_make_unique + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0096r0.html#detail.cpp14.n3656 */ #ifndef NANA_CONFIG_HPP @@ -67,18 +99,31 @@ // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. #define STD_CODECVT_NOT_SUPPORTED #endif // _MSC_VER == 1900 -#endif // _MSVC -#if defined(__clang__) +#elif defined(__clang__) //Clang + + #include //Introduces some implement-specific flags of ISO C++ Library #if defined(__GLIBCPP__) || defined(__GLIBCXX__) // is a known issue on libstdc++, it works on libc++ #define STD_CODECVT_NOT_SUPPORTED #endif #elif defined(__GNUC__) //GCC + + #include //Introduces some implement-specific flags of ISO C++ Library #if defined(__GLIBCPP__) || defined(__GLIBCXX__) // is a known issue on libstdc++, it works on libc++ #define STD_CODECVT_NOT_SUPPORTED + + //It's a known issue of libstdc++ on MinGW + //introduce to_string/to_wstring workarounds for disabled capacity of stdlib + #ifdef _GLIBCXX_HAVE_BROKEN_VSWPRINTF + #if (__GNUC__ < 5) + # define STD_TO_STRING_NOT_SUPPORTED + #endif + + #define STD_TO_WSTRING_NOT_SUPPORTED + #endif #endif #if (__GNUC__ == 4) @@ -89,16 +134,29 @@ //but if USE_github_com_meganz_mingw_std_threads is enabled, //boost.thread will be replaced with meganz's mingw-std-threads. // https://github.com/meganz/mingw-std-threads - //#define USE_github_com_meganz_mingw_std_threads + #if !defined( USE_github_com_meganz_mingw_std_threads ) + //#define USE_github_com_meganz_mingw_std_threads + #endif + #if !defined(STD_make_unique_NOT_SUPPORTED) + #define STD_make_unique_NOT_SUPPORTED + #endif //STD_make_unique_NOT_SUPPORTED + #endif #if defined(NANA_MINGW) - //It's a known issue under MinGW + //It's a knonwn issue under MinGW #define STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED #endif - #if ((__GNUC_MINOR__ < 8) || defined(NANA_MINGW)) - #define STD_TO_STRING_NOT_SUPPORTED + #if (__GNUC_MINOR__ < 8) + //introduce to_string/to_wstring workaround for lack of stdlib definitions + #ifndef STD_TO_STRING_NOT_SUPPORTED + # define STD_TO_STRING_NOT_SUPPORTED + #endif + + #ifndef STD_TO_WSTRING_NOT_SUPPORTED + # define STD_TO_WSTRING_NOT_SUPPORTED + #endif #endif #endif #endif @@ -151,5 +209,13 @@ #endif #endif +#if !defined(VERBOSE_PREPROCESSOR) + //#define VERBOSE_PREPROCESSOR +#endif -#endif //NANA_CONFIG_HPP +#if !defined(STOP_VERBOSE_PREPROCESSOR) + #define STOP_VERBOSE_PREPROCESSOR +#endif + + +#endif // NANA_CONFIG_HPP \ No newline at end of file diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index 694f016d..8d9f2cb3 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -3,8 +3,8 @@ * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at + * 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/deploy.hpp @@ -15,9 +15,12 @@ #ifndef NANA_DEPLOY_HPP #define NANA_DEPLOY_HPP -#include - #include +#if defined(VERBOSE_PREPROCESSOR) + #include +#endif + +#include #include //Implement workarounds for GCC/MinGW which version is below 4.8.2 @@ -71,7 +74,12 @@ namespace std std::string to_string(long long); std::string to_string(unsigned long long); std::string to_string(float); - +} +#endif + +#ifdef STD_TO_WSTRING_NOT_SUPPORTED +namespace std +{ std::wstring to_wstring(long double); std::wstring to_wstring(double); std::wstring to_wstring(unsigned); @@ -146,4 +154,44 @@ namespace nana #define NANA_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) +#if defined(STD_make_unique_NOT_SUPPORTED) +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3656.htm + +#include +#include +#include +#include + +namespace std { + template struct _Unique_if { + typedef unique_ptr _Single_object; + }; + + template struct _Unique_if { + typedef unique_ptr _Unknown_bound; + }; + + template struct _Unique_if { + typedef void _Known_bound; + }; + + template + typename _Unique_if::_Single_object + make_unique(Args&&... args) { + return unique_ptr(new T(std::forward(args)...)); + } + + template + typename _Unique_if::_Unknown_bound + make_unique(size_t n) { + typedef typename remove_extent::type U; + return unique_ptr(new U[n]()); + } + + template + typename _Unique_if::_Known_bound + make_unique(Args&&...) = delete; +} +#endif //STD_make_unique_NOT_SUPPORTED + #endif //NANA_MACROS_HPP diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp index 4ad3d1d0..aade67a5 100644 --- a/include/nana/gui/detail/native_window_interface.hpp +++ b/include/nana/gui/detail/native_window_interface.hpp @@ -72,10 +72,12 @@ namespace detail static void capture_window(native_window_type, bool); static nana::point cursor_position(); static native_window_type get_owner_window(native_window_type); + static native_window_type parent_window(native_window_type); + static native_window_type parent_window(native_window_type child, native_window_type new_parent, bool returns_previous); //For Caret - static void caret_create(native_window_type, const ::nana::size&); + static void caret_create(native_window_type, const ::nana::size&); static void caret_destroy(native_window_type); - static void caret_pos(native_window_type, const ::nana::point&); + static void caret_pos(native_window_type, const ::nana::point&); static void caret_visible(native_window_type, bool); static void set_focus(native_window_type); diff --git a/include/nana/verbose_preprocessor.hpp b/include/nana/verbose_preprocessor.hpp new file mode 100644 index 00000000..b62267f6 --- /dev/null +++ b/include/nana/verbose_preprocessor.hpp @@ -0,0 +1,56 @@ +/** + * Nana Verbose preprocessor + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 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/verbose_preprocessor.hpp + * + * @brief show the values of configuration constants during compilation to facilitate build debugging. + * + * Set VERBOSE_PREPROCESSOR to 1 to show the messages or to 0 for a normal build. + * Normally set to 0. Set to 1 only in case you want to debug the build system because it is extremely repetitive and slow. + * + * @authors Ariel Vina-Rodriguez (qPCR4vir) + * + */ +// Created by ariel.rodriguez on 08.12.2015. +// + +#ifndef NANA_VERBOSE_PREPROCESSOR_H +#define NANA_VERBOSE_PREPROCESSOR_H + +#if defined(VERBOSE_PREPROCESSOR) + + #define STRING2(x) #x + #define STRING(x) STRING2(x) + #pragma message ( "\nVerbose preprocessor =" STRING(VERBOSE_PREPROCESSOR)" , \n STOP_VERBOSE_PREPROCESSOR=" STRING(STOP_VERBOSE_PREPROCESSOR) ) + + #pragma message ( "\nWindows: \n _WIN32=" STRING(_WIN32) ", \n __WIN32__ =" STRING(__WIN32__) " , \n WIN32=" STRING(WIN32)" , \n NANA_WINDOWS=" STRING(NANA_WINDOWS) ) + + #pragma message ( "\nUNICODE: \n NANA_UNICODE=" STRING(NANA_UNICODE) ", \n _UNICODE =" STRING(_UNICODE) " , \n UNICODE=" STRING(UNICODE) ) + + #pragma message ( "\nMinGW: \n __MINGW32__=" STRING(__MINGW32__) ", \n __MINGW64__=" STRING(__MINGW64__) " , \n MINGW=" STRING(MINGW) ) + + #pragma message ( "\nGNU: \n __GNUC__=" STRING(__GNUC__) ", \n __GNUC_MINOR__=" STRING(__GNUC_MINOR__) " , \n __GNUC_PATCHLEVEL__=" STRING(__GNUC_PATCHLEVEL__) ) + + #pragma message ( "\nSTD: \nSTD_CODECVT_NOT_SUPPORTED=" STRING(STD_CODECVT_NOT_SUPPORTED) " , \nSTD_THREAD_NOT_SUPPORTED=" STRING(STD_THREAD_NOT_SUPPORTED) ) + + #pragma message ( "\nSTD: \nUSE_github_com_meganz_mingw_std_threads=" STRING(USE_github_com_meganz_mingw_std_threads) " , \nSTD_THREAD_NOT_SUPPORTED=" STRING(STD_THREAD_NOT_SUPPORTED) ) + + #pragma message ( "\nClang compiler: \n__clang__=" STRING(__clang__) ", \n__GLIBCPP__=" STRING(__GLIBCPP__) " , \n__GLIBCXX__=" STRING(__GLIBCXX__) ) + + #pragma message ( "\nMSC: \n_MSC_VER=" STRING(_MSC_VER) ", \n_MSC_FULL_VER=" STRING(_MSC_FULL_VER ) ) + + #if defined(STOP_VERBOSE_PREPROCESSOR) + #error ("\nCompilation stopped to avoid annoying messages") + #endif + +#endif // VERBOSE_PREPROCESSOR + + + +#endif //NANA_VERBOSE_PREPROCESSOR_H diff --git a/source/deploy.cpp b/source/deploy.cpp index 5b3140da..2594de28 100644 --- a/source/deploy.cpp +++ b/source/deploy.cpp @@ -299,6 +299,7 @@ namespace std #endif //STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED #ifdef STD_TO_STRING_NOT_SUPPORTED +#include namespace std { std::string to_string(double v) @@ -363,7 +364,13 @@ namespace std ss << v; return ss.str(); } +} +#endif // STD_TO_STRING_NOT_SUPPORTED +#ifdef STD_TO_WSTRING_NOT_SUPPORTED +#include +namespace std +{ std::wstring to_wstring(double v) { std::wstringstream ss; diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index dbfe6c46..d310d223 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -281,7 +281,8 @@ namespace nana{ attr_mask, &win_attr); if(handle) { - if(owner) + //make owner if it is a popup window + if((!nested) && owner) restrict::spec.make_owner(owner, reinterpret_cast(handle)); XTextProperty name; @@ -417,8 +418,6 @@ namespace nana{ if(handle) { - restrict::spec.make_owner(parent, reinterpret_cast(handle)); - XTextProperty name; char text[] = "Nana Child Window"; char * str = text; @@ -786,21 +785,30 @@ namespace nana{ #if defined(NANA_WINDOWS) ::RECT r; ::GetWindowRect(reinterpret_cast(wd), & r); - HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); - if(owner) + HWND coord_wd = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + + if (!coord_wd) + coord_wd = ::GetParent(reinterpret_cast(wd)); + + if (coord_wd) { ::POINT pos = {r.left, r.top}; - ::ScreenToClient(owner, &pos); + ::ScreenToClient(coord_wd, &pos); return nana::point(pos.x, pos.y); } return nana::point(r.left, r.top); #elif defined(NANA_X11) int x, y; nana::detail::platform_scope_guard psg; - Window root = reinterpret_cast(restrict::spec.get_owner(wd)); - if(root == 0) root = restrict::spec.root_window(); + Window coord_wd = reinterpret_cast(restrict::spec.get_owner(wd)); + if(!coord_wd) + { + coord_wd = reinterpret_cast(parent_window(wd)); + if(!coord_wd) + coord_wd = restrict::spec.root_window(); + } Window child; - if(True == ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), root, 0, 0, &x, &y, &child)) + if(True == ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), coord_wd, 0, 0, &x, &y, &child)) return nana::point(x, y); return nana::point(0, 0); #endif @@ -1190,6 +1198,54 @@ namespace nana{ #endif } + native_window_type native_interface::parent_window(native_window_type wd) + { +#ifdef NANA_WINDOWS + return reinterpret_cast(::GetParent(reinterpret_cast(wd))); +#elif defined(NANA_X11) + Window root; + Window parent; + Window * children; + unsigned size; + + platform_scope_guard lock; + + if(0 != ::XQueryTree(restrict::spec.open_display(), reinterpret_cast(wd), + &root, &parent, &children, &size)) + { + ::XFree(children); + return reinterpret_cast(parent); + } + return nullptr; +#endif + } + + native_window_type native_interface::parent_window(native_window_type child, native_window_type new_parent, bool returns_previous) + { +#ifdef NANA_WINDOWS + auto prev = ::SetParent(reinterpret_cast(child), reinterpret_cast(new_parent)); + + if (prev) + ::PostMessage(prev, WM_CHANGEUISTATE, UIS_INITIALIZE, NULL); + + ::SetWindowPos(reinterpret_cast(child), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + + return reinterpret_cast(returns_previous ? prev : nullptr); +#elif defined(NANA_X11) + native_window_type prev = nullptr; + + platform_scope_guard lock; + + if(returns_previous) + prev = parent_window(child); + + ::XReparentWindow(restrict::spec.open_display(), + reinterpret_cast(child), reinterpret_cast(new_parent), + 0, 0); + return prev; +#endif + } + void native_interface::caret_create(native_window_type wd, const ::nana::size& caret_sz) { #if defined(NANA_WINDOWS) diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 9f0e779e..f44be0a6 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -140,7 +140,7 @@ namespace nana for (++i; i < end; ++i) { core_window_t* cover = *i; - if (cover->visible && (nullptr == cover->effect.bground)) + if ((category::flags::root != cover->other.category) && cover->visible && (nullptr == cover->effect.bground)) { if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r)) { @@ -271,9 +271,15 @@ namespace nana for (auto child : wd->children) { //it will not past children if no drawer and visible is false. - if ((false == child->visible) || ((child->other.category != category::lite_widget_tag::value) && child->drawer.graphics.empty())) + if ((false == child->visible) || ((category::flags::lite_widget != child->other.category) && child->drawer.graphics.empty())) continue; + if (category::flags::root == child->other.category) + { + paint(child, is_child_refreshed, is_child_refreshed); + continue; + } + if (nullptr == child->effect.bground) { if (overlap(nana::rectangle{ child->pos_root, child->dimension }, parent_rect, rect)) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 909cf193..4aa19757 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -291,6 +291,14 @@ namespace detail if (result.native_handle) { core_window_t* wd = new core_window_t(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr); + if (nested) + { + wd->owner = nullptr; + wd->parent = owner; + wd->index = static_cast(owner->children.size()); + owner->children.push_back(wd); + } + wd->flags.take_active = !app.no_activate; wd->title = native_interface::window_caption(result.native_handle); @@ -542,10 +550,10 @@ namespace detail std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { - if(wd->other.category != category::root_tag::value) + if (category::flags::root != wd->other.category) { //Move child widgets - if(x != wd->pos_owner.x || y != wd->pos_owner.y) + if (x != wd->pos_owner.x || y != wd->pos_owner.y) { point delta{ x - wd->pos_owner.x, y - wd->pos_owner.y }; @@ -562,8 +570,20 @@ namespace detail return true; } } - else if(false == passive) + else if (!passive) + { + //Check if this root is a nested + if (wd->parent && (category::flags::root != wd->parent->other.category)) + { + //The parent of the window is not a root, the position should + //be transformed to a position based on its parent. + + x += wd->parent->pos_root.x; + y += wd->parent->pos_root.y; + } + native_interface::move_window(wd->root, x, y); + } } return false; @@ -602,22 +622,36 @@ namespace detail } else { + ::nana::rectangle root_r = r; + //Move event should not get called here, + //because the window is a root, the event will get called by system event handler. + + //Check if this root is a nested + if (wd->parent && (category::flags::root != wd->parent->other.category)) + { + //The parent of the window is not a root, the position should + //be transformed to a position based on its parent. + + root_r.x += wd->parent->pos_root.x; + root_r.y += wd->parent->pos_root.y; + } + if(size_changed) { - wd->dimension.width = r.width; - wd->dimension.height = r.height; + wd->dimension.width = root_r.width; + wd->dimension.height = root_r.height; wd->drawer.graphics.make(wd->dimension); wd->root_graph->make(wd->dimension); - native_interface::move_window(wd->root, r); + native_interface::move_window(wd->root, root_r); arg_resized arg; arg.window_handle = reinterpret_cast(wd); - arg.width = r.width; - arg.height = r.height; + arg.width = root_r.width; + arg.height = root_r.height; brock.emit(event_code::resized, wd, arg, true, brock.get_thread_context()); } else - native_interface::move_window(wd->root, r.x, r.y); + native_interface::move_window(wd->root, root_r.x, root_r.y); } return (moved || size_changed); @@ -919,34 +953,37 @@ namespace detail arg.receiver = wd->root; brock.emit(event_code::focus, prev_focus, arg, true, brock.get_thread_context()); } + + //Check the prev_focus again, because it may be closed in focus event + if (!impl_->wd_register.available(prev_focus)) + prev_focus = nullptr; } else if(wd->root == native_interface::get_focus_window()) - wd = nullptr; //no new focus_window + return prev_focus; //no new focus_window - if(wd) - { - if(wd->together.caret) - wd->together.caret->set_active(true); - arg.window_handle = reinterpret_cast(wd); - arg.getting = true; - arg.receiver = wd->root; - brock.emit(event_code::focus, wd, arg, true, brock.get_thread_context()); + if(wd->together.caret) + wd->together.caret->set_active(true); - if (!root_has_been_focused) - native_interface::set_focus(root_wd->root); + arg.window_handle = reinterpret_cast(wd); + arg.getting = true; + arg.receiver = wd->root; + brock.emit(event_code::focus, wd, arg, true, brock.get_thread_context()); - //A fix by Katsuhisa Yuasa - //The menubar token window will be redirected to the prev focus window when the new - //focus window is a menubar. - //The focus window will be restore to the prev focus which losts the focus becuase of - //memberbar. - if (wd == wd->root_widget->other.attribute.root->menubar) - wd = prev_focus; + if (!root_has_been_focused) + native_interface::set_focus(root_wd->root); + + //A fix by Katsuhisa Yuasa + //The menubar token window will be redirected to the prev focus window when the new + //focus window is a menubar. + //The focus window will be restore to the prev focus which losts the focus becuase of + //memberbar. + if (prev_focus && (wd == wd->root_widget->other.attribute.root->menubar)) + wd = prev_focus; + + if (wd != wd->root_widget->other.attribute.root->menubar) + brock.set_menubar_taken(wd); - if (wd != wd->root_widget->other.attribute.root->menubar) - brock.set_menubar_taken(wd); - } return prev_focus; } @@ -1301,7 +1338,9 @@ namespace detail void window_manager::_m_disengage(core_window_t* wd, core_window_t* for_new) { auto * const wdpa = wd->parent; - bool established = (for_new && wdpa != for_new); + + + bool established = (for_new && (wdpa != for_new)); decltype(for_new->root_widget->other.attribute.root) pa_root_attr = nullptr; if (established) @@ -1443,14 +1482,26 @@ namespace detail std::function set_pos_root; set_pos_root = [&set_pos_root](core_window_t* wd, const nana::point& delta_pos) { - wd->pos_root -= delta_pos; for (auto child : wd->children) { - child->root = wd->root; - child->root_graph = wd->root_graph; - child->root_widget = wd->root_widget; - set_pos_root(child, delta_pos); + if (category::flags::root == child->other.category) + { + auto pos = native_interface::window_position(child->root); + native_interface::parent_window(child->root, wd->root, false); + + pos -= delta_pos; + native_interface::move_window(child->root, pos.x, pos.y); + } + else + { + child->root = wd->root; + child->root_graph = wd->root_graph; + child->root_widget = wd->root_widget; + set_pos_root(child, delta_pos); + } } + + wd->pos_root -= delta_pos; }; set_pos_root(wd, delta_pos); @@ -1481,8 +1532,30 @@ namespace detail brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); //Delete the children widgets. - for (auto i = wd->children.rbegin(), end = wd->children.rend(); i != end; ++i) - _m_destroy(*i); + for (auto i = wd->children.rbegin(), end = wd->children.rend(); i != end;) + { + auto child = *i; + + if (category::flags::root == child->other.category) + { + //closing a child root window erases itself from wd->children, + //to make sure the iterator is valid, it must be reloaded. + + auto offset = std::distance(wd->children.rbegin(), i); + + //!!! + //a potential issue is that if the calling thread is not same with child's thread, + //the child root window may not be erased from wd->children now. + native_interface::close_window(child->root); + + i = wd->children.rbegin(); + std::advance(i, offset); + end = wd->children.rend(); + continue; + } + _m_destroy(child); + ++i; + } wd->children.clear(); @@ -1508,7 +1581,7 @@ namespace detail void window_manager::_m_move_core(core_window_t* wd, const point& delta) { - if(wd->other.category != category::root_tag::value) //A root widget always starts at (0, 0) and its childs are not to be changed + if(category::flags::root != wd->other.category) //A root widget always starts at (0, 0) and its childs are not to be changed { wd->pos_root += delta; if (category::flags::frame != wd->other.category) @@ -1525,6 +1598,11 @@ namespace detail for (auto child : wd->children) _m_move_core(child, delta); } + else + { + auto pos = native_interface::window_position(wd->root) + delta; + native_interface::move_window(wd->root, pos.x, pos.y); + } } //_m_find diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index a0a53cbc..02a68fca 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -542,8 +542,8 @@ namespace API { auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return reinterpret_cast(iwd->other.category == category::flags::root ? iwd->owner : iwd->parent); + if (restrict::wd_manager().available(iwd)) + return reinterpret_cast(iwd->parent); return nullptr; } diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 200871b1..b9a458e1 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -58,12 +58,12 @@ namespace nana cell::cell(std::string text, const format& fmt) : text(std::move(text)), - custom_format(new format{ fmt }) //make_unique + custom_format(std::make_unique( fmt )) // or custom_format(new format{ fmt }) {} cell::cell(std::string text, const ::nana::color& bgcolor, const ::nana::color& fgcolor) : text(std::move(text)), - custom_format{ new format{ bgcolor, fgcolor } } //make_unique + custom_format{std::make_unique( bgcolor, fgcolor ) } //custom_format{ new format{ bgcolor, fgcolor } } {} cell& cell::operator=(const cell& rhs) diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 39665a63..f2a9b61c 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -528,17 +528,16 @@ namespace nana auto index = state_.active; for (auto & m : menu_->items) { + if (0 == index--) + break; + if (m.flags.splitter) { pos.y += 2; continue; } - if (0 == index) - break; - pos.y += _m_item_height() + 1; - --index; } tmstamp = state_.active_timestamp;