Merge branch 'develop'

This commit is contained in:
Jinhao 2019-07-20 18:52:14 +08:00
commit 38cdf47794
82 changed files with 4075 additions and 2526 deletions

View File

@ -44,10 +44,8 @@ matrix:
before_install:
- cd ..
- git clone --depth=1 --branch=hotfix https://github.com/qPCR4vir/nana-demo.git nana-demo
- git clone --depth=1 --branch=develop https://github.com/qPCR4vir/nana-demo.git nana-demo
- export PATH="$HOME/bin:$PATH"
#- mkdir ~/bin #it seemd that a bin already exists from 20170901
- wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.12/cmake-3.12.0-rc3-Linux-x86_64.sh || true
- chmod -R +x /tmp/tools
@ -65,7 +63,7 @@ before_script :
- cd demo-build
script:
- cmake -G"Unix Makefiles" ../nana-demo -DCMAKE_INSTALL_PREFIX=.. -DNANA_CMAKE_ENABLE_JPEG=ON -DNANA_CMAKE_FIND_BOOST_FILESYSTEM=ON -DNANA_CMAKE_AUTOMATIC_GUI_TESTING=ON
- 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
# todo: separate resources from sources (a directory for images)
- ls

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.6.2
project(nana VERSION 1.7.1
DESCRIPTION "C++ GUI library"
HOMEPAGE_URL http://nanapro.org
LANGUAGES CXX )
@ -30,6 +30,7 @@ project(nana VERSION 1.6.2
####################### Main setting of Nana targets, sources and installs #####################
add_library(nana)
add_library(nana::nana ALIAS nana)
target_compile_features(nana PUBLIC cxx_std_17)
# need after cxx_std_14 or cxx_std_17 ??
@ -54,27 +55,25 @@ target_compile_features(nana
# in your own CMakeLists.txt, and them :
# target_link_libraries(yourApp PRIVATE nana )
set(NANA_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source)
set(NANA_SOURCE_SUBDIRS
/.
/detail
/detail/posix
/filesystem
/gui
/gui/detail
/gui/widgets
/gui/widgets/skeletons
/paint
/paint/detail
/system
/threads
)
set(NANA_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source)
set(NANA_SOURCE_SUBDIRS /.
/detail
/detail/posix
/filesystem
/gui
/gui/detail
/gui/widgets
/gui/widgets/skeletons
/paint
/paint/detail
/system
/threads
)
if(NANA_CMAKE_ENABLE_AUDIO)
list(APPEND NANA_SOURCE_SUBDIRS
/audio
/audio/detail
)
/audio
/audio/detail
)
endif()
# collect all source files in the source-sub-dir
@ -87,26 +86,24 @@ target_sources(nana PRIVATE ${SOURCES})
### collect all headers sub-directories in a list to avoid duplication ###
# To show .h files in Visual Studio, add them to the list of sources in add_executable / add_library / target_sources
# and Use SOURCE_GROUP if all your sources are in the same directory
set(NANA_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include)
set(NANA_INCLUDE_SUBDIRS
/.
/filesystem
/gui
/gui/detail
/gui/widgets
/gui/widgets/skeletons
/paint
/paint/detail
/pat
/system
/threads
)
set(NANA_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include)
set(NANA_INCLUDE_SUBDIRS /.
/filesystem
/gui
/gui/detail
/gui/widgets
/gui/widgets/skeletons
/paint
/paint/detail
/pat
/system
/threads
)
if(NANA_CMAKE_ENABLE_AUDIO)
list(APPEND NANA_INCLUDE_SUBDIRS
/audio
/audio/detail
)
/audio
/audio/detail
)
endif()
foreach(subdir ${NANA_INCLUDE_SUBDIRS})

View File

@ -1,4 +1,6 @@
version: 1.0.{build}
image:
- Visual Studio 2017
build:
project: build\vc2015\nana.sln
project: build\vc2017\nana.sln
verbosity: minimal

View File

@ -14,8 +14,10 @@
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW??
target_compile_options(nana PRIVATE -Wall
PUBLIC -g )
target_compile_options(nana PRIVATE -Wall)
# todo: set in target property of nana
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -mtune=native -DNDEBUG")
set(THREADS_PREFER_PTHREAD_FLAG ON) # todo - test this
find_package(Threads REQUIRED)

View File

@ -1,8 +1,8 @@
option(NANA_CMAKE_INSTALL "Install nana when compile the library (to be consumed without cmake)" OFF)
option(NANA_CMAKE_INSTALL "Install nana when compile the library (to be consumed without cmake)" ON)
# Install the include directories too.
if(NANA_CMAKE_INSTALL)
# this is the prefered method to consume nana directly with some specific bulid system
# This is a method to consume nana with a bulid system not directly supported by nana.
# 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})

View File

@ -1,11 +1,12 @@
# The ISO C++ File System Technical Specification (ISO-TS, or STD) is optional.
# The ISO C++ File System Technical Specification (ISO-TS, or STD) was optional.
# http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf
# This is not a workaround, but an user option.
# The library maybe available in the std library in use or from Boost (almost compatible)
# 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)
# http://www.boost.org/doc/libs/1_60_0/libs/filesystem/doc/index.htm
# or you can choose to use the (partial, but functional) implementation provided by nana.
# If you include the file <nana/filesystem/filesystem.hpp> or <nana/filesystem/filesystem_ext.hpp>
# the selected option will be set by nana into std::experimental::filesystem
# 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.

View File

@ -40,12 +40,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AN
if(BUILD_SHARED_LIBS)
target_compile_options(nana PUBLIC -lgcc -lstdc++)
else()
if(MINGW)
target_compile_options(nana PUBLIC -static) # -static ?? cmake knows BUILD_SHARED_LIBS
else()
target_compile_options(nana PUBLIC -static-libgcc -static-libstdc++)
endif()
target_link_libraries(nana PUBLIC -static-libgcc -static-libstdc++)
endif(BUILD_SHARED_LIBS)
endif()

View File

@ -30,6 +30,8 @@ if (NANA_CMAKE_VERBOSE_PREPROCESSOR)
cmake_print_variables(CMAKE_BUILD_TYPE)
cmake_print_variables(CMAKE_CONFIGURATION_TYPES)
cmake_print_variables(CMAKE_CXX_FLAGS_RELEASE)
message ( "CMAKE_CXX_COMPILER_ID = " ${CMAKE_CXX_COMPILER_ID})
message ( "COMPILER_IS_CLANG = " ${COMPILER_IS_CLANG})
message ( "CMAKE_COMPILER_IS_GNUCXX = " ${CMAKE_COMPILER_IS_GNUCXX})

View File

@ -102,6 +102,7 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -116,6 +117,7 @@
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -132,6 +134,7 @@
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -150,6 +153,7 @@
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -252,6 +256,7 @@
<ClInclude Include="..\..\include\nana\gui.hpp" />
<ClInclude Include="..\..\include\nana\gui\animation.hpp" />
<ClInclude Include="..\..\include\nana\gui\basis.hpp" />
<ClInclude Include="..\..\include\nana\gui\dragdrop.hpp" />
<ClInclude Include="..\..\include\nana\gui\dragger.hpp" />
<ClInclude Include="..\..\include\nana\gui\drawing.hpp" />
<ClInclude Include="..\..\include\nana\gui\effects.hpp" />

View File

@ -474,6 +474,9 @@
<ClInclude Include="..\..\include\nana\verbose_preprocessor.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\dragdrop.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\include\nana\pop_ignore_diagnostic">

28
build/vc2019/nana.sln Normal file
View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{42D0520F-EFA5-4831-84FE-2B9085301C5D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x64.ActiveCfg = Debug|x64
{42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x64.Build.0 = Debug|x64
{42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x86.ActiveCfg = Debug|Win32
{42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x86.Build.0 = Debug|Win32
{42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x64.ActiveCfg = Release|x64
{42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x64.Build.0 = Release|x64
{42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x86.ActiveCfg = Release|Win32
{42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

316
build/vc2019/nana.vcxproj Normal file
View File

@ -0,0 +1,316 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{42D0520F-EFA5-4831-84FE-2B9085301C5D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>nana</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>..\..\include;$(IncludePath)</IncludePath>
<OutDir>../bin/</OutDir>
<IntDir>..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>..\..\include;$(IncludePath)</IncludePath>
<OutDir>../bin/</OutDir>
<IntDir>..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>../bin/</OutDir>
<IntDir>..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)</TargetName>
<IncludePath>..\..\include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>../bin/</OutDir>
<IntDir>..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName)</TargetName>
<IncludePath>..\..\include;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\source\any.cpp" />
<ClCompile Include="..\..\source\audio\detail\audio_device.cpp" />
<ClCompile Include="..\..\source\audio\detail\audio_stream.cpp" />
<ClCompile Include="..\..\source\audio\detail\buffer_preparation.cpp" />
<ClCompile Include="..\..\source\audio\player.cpp" />
<ClCompile Include="..\..\source\basic_types.cpp" />
<ClCompile Include="..\..\source\charset.cpp" />
<ClCompile Include="..\..\source\datetime.cpp" />
<ClCompile Include="..\..\source\deploy.cpp" />
<ClCompile Include="..\..\source\detail\platform_abstraction.cpp" />
<ClCompile Include="..\..\source\detail\platform_spec_windows.cpp" />
<ClCompile Include="..\..\source\filesystem\filesystem.cpp" />
<ClCompile Include="..\..\source\gui\animation.cpp" />
<ClCompile Include="..\..\source\gui\basis.cpp" />
<ClCompile Include="..\..\source\gui\detail\basic_window.cpp" />
<ClCompile Include="..\..\source\gui\detail\bedrock_pi.cpp" />
<ClCompile Include="..\..\source\gui\detail\bedrock_windows.cpp" />
<ClCompile Include="..\..\source\gui\detail\color_schemes.cpp" />
<ClCompile Include="..\..\source\gui\detail\drawer.cpp" />
<ClCompile Include="..\..\source\gui\detail\element_store.cpp" />
<ClCompile Include="..\..\source\gui\detail\events_operation.cpp" />
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
<ClCompile Include="..\..\source\gui\dragdrop.cpp" />
<ClCompile Include="..\..\source\gui\dragger.cpp" />
<ClCompile Include="..\..\source\gui\drawing.cpp" />
<ClCompile Include="..\..\source\gui\effects.cpp" />
<ClCompile Include="..\..\source\gui\element.cpp" />
<ClCompile Include="..\..\source\gui\filebox.cpp" />
<ClCompile Include="..\..\source\gui\layout_utility.cpp" />
<ClCompile Include="..\..\source\gui\msgbox.cpp" />
<ClCompile Include="..\..\source\gui\notifier.cpp" />
<ClCompile Include="..\..\source\gui\place.cpp" />
<ClCompile Include="..\..\source\gui\programming_interface.cpp" />
<ClCompile Include="..\..\source\gui\screen.cpp" />
<ClCompile Include="..\..\source\gui\state_cursor.cpp" />
<ClCompile Include="..\..\source\gui\timer.cpp" />
<ClCompile Include="..\..\source\gui\tooltip.cpp" />
<ClCompile Include="..\..\source\gui\widgets\button.cpp" />
<ClCompile Include="..\..\source\gui\widgets\categorize.cpp" />
<ClCompile Include="..\..\source\gui\widgets\checkbox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\combox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\date_chooser.cpp" />
<ClCompile Include="..\..\source\gui\widgets\float_listbox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\form.cpp" />
<ClCompile Include="..\..\source\gui\widgets\group.cpp" />
<ClCompile Include="..\..\source\gui\widgets\label.cpp" />
<ClCompile Include="..\..\source\gui\widgets\listbox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\menu.cpp" />
<ClCompile Include="..\..\source\gui\widgets\menubar.cpp" />
<ClCompile Include="..\..\source\gui\widgets\panel.cpp" />
<ClCompile Include="..\..\source\gui\widgets\picture.cpp" />
<ClCompile Include="..\..\source\gui\widgets\progress.cpp" />
<ClCompile Include="..\..\source\gui\widgets\scroll.cpp" />
<ClCompile Include="..\..\source\gui\widgets\skeletons\content_view.cpp" />
<ClCompile Include="..\..\source\gui\widgets\skeletons\text_editor.cpp" />
<ClCompile Include="..\..\source\gui\widgets\slider.cpp" />
<ClCompile Include="..\..\source\gui\widgets\spinbox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\tabbar.cpp" />
<ClCompile Include="..\..\source\gui\widgets\textbox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\toolbar.cpp" />
<ClCompile Include="..\..\source\gui\widgets\treebox.cpp" />
<ClCompile Include="..\..\source\gui\widgets\widget.cpp" />
<ClCompile Include="..\..\source\gui\wvl.cpp" />
<ClCompile Include="..\..\source\internationalization.cpp" />
<ClCompile Include="..\..\source\paint\detail\image_process_provider.cpp" />
<ClCompile Include="..\..\source\paint\detail\native_paint_interface.cpp" />
<ClCompile Include="..\..\source\paint\graphics.cpp" />
<ClCompile Include="..\..\source\paint\image.cpp" />
<ClCompile Include="..\..\source\paint\image_process_selector.cpp" />
<ClCompile Include="..\..\source\paint\pixel_buffer.cpp" />
<ClCompile Include="..\..\source\paint\text_renderer.cpp" />
<ClCompile Include="..\..\source\stdc++.cpp" />
<ClCompile Include="..\..\source\system\dataexch.cpp" />
<ClCompile Include="..\..\source\system\platform.cpp" />
<ClCompile Include="..\..\source\system\shared_wrapper.cpp" />
<ClCompile Include="..\..\source\system\timepiece.cpp" />
<ClCompile Include="..\..\source\threads\pool.cpp" />
<ClCompile Include="..\..\source\unicode_bidi.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\nana\any.hpp" />
<ClInclude Include="..\..\include\nana\basic_types.hpp" />
<ClInclude Include="..\..\include\nana\c++defines.hpp" />
<ClInclude Include="..\..\include\nana\charset.hpp" />
<ClInclude Include="..\..\include\nana\concepts.hpp" />
<ClInclude Include="..\..\include\nana\config.hpp" />
<ClInclude Include="..\..\include\nana\datetime.hpp" />
<ClInclude Include="..\..\include\nana\deploy.hpp" />
<ClInclude Include="..\..\include\nana\fwd.hpp" />
<ClInclude Include="..\..\include\nana\gui.hpp" />
<ClInclude Include="..\..\include\nana\gui\animation.hpp" />
<ClInclude Include="..\..\include\nana\gui\basis.hpp" />
<ClInclude Include="..\..\include\nana\gui\dragdrop.hpp" />
<ClInclude Include="..\..\include\nana\gui\dragger.hpp" />
<ClInclude Include="..\..\include\nana\gui\drawing.hpp" />
<ClInclude Include="..\..\include\nana\gui\effects.hpp" />
<ClInclude Include="..\..\include\nana\gui\element.hpp" />
<ClInclude Include="..\..\include\nana\gui\filebox.hpp" />
<ClInclude Include="..\..\include\nana\gui\layout_utility.hpp" />
<ClInclude Include="..\..\include\nana\gui\msgbox.hpp" />
<ClInclude Include="..\..\include\nana\gui\notifier.hpp" />
<ClInclude Include="..\..\include\nana\gui\place.hpp" />
<ClInclude Include="..\..\include\nana\gui\programming_interface.hpp" />
<ClInclude Include="..\..\include\nana\gui\screen.hpp" />
<ClInclude Include="..\..\include\nana\gui\state_cursor.hpp" />
<ClInclude Include="..\..\include\nana\gui\timer.hpp" />
<ClInclude Include="..\..\include\nana\gui\tooltip.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\button.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\categorize.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\checkbox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\combox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\date_chooser.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\float_listbox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\form.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\group.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\label.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\listbox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\menu.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\menubar.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\panel.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\picture.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\progress.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\scroll.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\slider.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\spinbox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\tabbar.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\textbox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\toolbar.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\treebox.hpp" />
<ClInclude Include="..\..\include\nana\gui\widgets\widget.hpp" />
<ClInclude Include="..\..\include\nana\gui\wvl.hpp" />
<ClInclude Include="..\..\include\nana\internationalization.hpp" />
<ClInclude Include="..\..\include\nana\key_type.hpp" />
<ClInclude Include="..\..\include\nana\optional.hpp" />
<ClInclude Include="..\..\include\nana\stdc++.hpp" />
<ClInclude Include="..\..\include\nana\std_condition_variable.hpp" />
<ClInclude Include="..\..\include\nana\std_mutex.hpp" />
<ClInclude Include="..\..\include\nana\std_thread.hpp" />
<ClInclude Include="..\..\include\nana\traits.hpp" />
<ClInclude Include="..\..\include\nana\unicode_bidi.hpp" />
<ClInclude Include="..\..\include\nana\verbose_preprocessor.hpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\include\nana\pop_ignore_diagnostic" />
<None Include="..\..\include\nana\push_ignore_diagnostic" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,489 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Sources">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Sources\audio">
<UniqueIdentifier>{81850bad-7436-405a-beb5-357c5e34f039}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\audio\detail">
<UniqueIdentifier>{44582b36-4575-4663-ac02-e80417f95d05}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\detail">
<UniqueIdentifier>{b7e3cdb7-99ac-473d-86c8-53dddce70480}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\filesystem">
<UniqueIdentifier>{02fa693c-edc1-4e04-bf1d-ec3c2a89182a}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\gui">
<UniqueIdentifier>{cffe7506-b96c-42aa-a747-41b5115d9580}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\gui\detail">
<UniqueIdentifier>{b6b2c032-c6a4-4884-8c14-eca4aa69ef0c}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\gui\widgets">
<UniqueIdentifier>{58f2e0f8-4d63-40db-807d-d7adf71c4ebe}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\gui\widgets\skeletons">
<UniqueIdentifier>{f288a25d-3ce8-4c2e-a86f-9aeda44bc557}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\paint">
<UniqueIdentifier>{90b2da01-605d-489b-b6c5-2af8d3c2d8a6}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\paint\detail">
<UniqueIdentifier>{430feed0-e1d9-45cb-8d59-e1a48a04d19f}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\system">
<UniqueIdentifier>{dcf62634-a658-453b-a58d-f1a96a12a8b8}</UniqueIdentifier>
</Filter>
<Filter Include="Sources\threads">
<UniqueIdentifier>{c1cdf46a-519f-422a-947f-39e173045414}</UniqueIdentifier>
</Filter>
<Filter Include="Include">
<UniqueIdentifier>{d68bd89c-170f-445f-b79f-aa03c881ab6b}</UniqueIdentifier>
</Filter>
<Filter Include="Include\gui">
<UniqueIdentifier>{a5d87649-2cd1-4a8f-a1f9-7151eaf6c772}</UniqueIdentifier>
</Filter>
<Filter Include="Include\gui\widgets">
<UniqueIdentifier>{0e6a58ab-652c-45d7-b9aa-8d9f2fa80ea1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\source\any.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="..\..\source\basic_types.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="..\..\source\charset.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="..\..\source\datetime.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="..\..\source\deploy.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="..\..\source\internationalization.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="..\..\source\stdc++.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="..\..\source\unicode_bidi.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="..\..\source\audio\detail\audio_device.cpp">
<Filter>Sources\audio\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\audio\detail\audio_stream.cpp">
<Filter>Sources\audio\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\audio\detail\buffer_preparation.cpp">
<Filter>Sources\audio\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\audio\player.cpp">
<Filter>Sources\audio</Filter>
</ClCompile>
<ClCompile Include="..\..\source\detail\platform_spec_windows.cpp">
<Filter>Sources\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\filesystem\filesystem.cpp">
<Filter>Sources\filesystem</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\basic_window.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\bedrock_pi.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\bedrock_windows.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\color_schemes.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\drawer.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\element_store.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\events_operation.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp">
<Filter>Sources\gui\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\skeletons\content_view.cpp">
<Filter>Sources\gui\widgets\skeletons</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\skeletons\text_editor.cpp">
<Filter>Sources\gui\widgets\skeletons</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\button.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\categorize.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\checkbox.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\combox.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\date_chooser.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\float_listbox.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\form.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\group.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\label.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\listbox.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\menu.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\menubar.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\panel.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\picture.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\progress.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\scroll.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\slider.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\spinbox.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\tabbar.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\textbox.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\toolbar.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\treebox.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\widgets\widget.cpp">
<Filter>Sources\gui\widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\source\paint\detail\image_process_provider.cpp">
<Filter>Sources\paint\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\paint\detail\native_paint_interface.cpp">
<Filter>Sources\paint\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\paint\graphics.cpp">
<Filter>Sources\paint</Filter>
</ClCompile>
<ClCompile Include="..\..\source\paint\image.cpp">
<Filter>Sources\paint</Filter>
</ClCompile>
<ClCompile Include="..\..\source\paint\image_process_selector.cpp">
<Filter>Sources\paint</Filter>
</ClCompile>
<ClCompile Include="..\..\source\paint\pixel_buffer.cpp">
<Filter>Sources\paint</Filter>
</ClCompile>
<ClCompile Include="..\..\source\paint\text_renderer.cpp">
<Filter>Sources\paint</Filter>
</ClCompile>
<ClCompile Include="..\..\source\system\dataexch.cpp">
<Filter>Sources\system</Filter>
</ClCompile>
<ClCompile Include="..\..\source\system\platform.cpp">
<Filter>Sources\system</Filter>
</ClCompile>
<ClCompile Include="..\..\source\system\shared_wrapper.cpp">
<Filter>Sources\system</Filter>
</ClCompile>
<ClCompile Include="..\..\source\system\timepiece.cpp">
<Filter>Sources\system</Filter>
</ClCompile>
<ClCompile Include="..\..\source\threads\pool.cpp">
<Filter>Sources\threads</Filter>
</ClCompile>
<ClCompile Include="..\..\source\detail\platform_abstraction.cpp">
<Filter>Sources\detail</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\animation.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\basis.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\dragger.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\drawing.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\effects.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\element.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\filebox.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\layout_utility.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\msgbox.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\notifier.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\place.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\programming_interface.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\screen.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\state_cursor.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\timer.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\tooltip.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\wvl.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
<ClCompile Include="..\..\source\gui\dragdrop.cpp">
<Filter>Sources\gui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\nana\gui\widgets\spinbox.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\group.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\treebox.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\listbox.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\menu.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\menubar.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\progress.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\widget.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\textbox.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\toolbar.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\button.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\combox.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\label.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\panel.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\picture.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\tabbar.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\categorize.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\scroll.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\slider.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\checkbox.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\date_chooser.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\float_listbox.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\widgets\form.hpp">
<Filter>Include\gui\widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\animation.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\basis.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\dragger.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\drawing.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\effects.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\element.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\filebox.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\layout_utility.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\msgbox.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\notifier.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\place.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\programming_interface.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\screen.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\state_cursor.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\timer.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\tooltip.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\wvl.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\any.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\basic_types.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\c++defines.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\charset.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\concepts.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\config.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\datetime.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\deploy.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\fwd.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\internationalization.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\key_type.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\optional.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\std_condition_variable.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\std_mutex.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\std_thread.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\stdc++.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\traits.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\unicode_bidi.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\verbose_preprocessor.hpp">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\nana\gui\dragdrop.hpp">
<Filter>Include\gui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\include\nana\pop_ignore_diagnostic">
<Filter>Include</Filter>
</None>
<None Include="..\..\include\nana\push_ignore_diagnostic">
<Filter>Include</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -118,7 +118,5 @@ namespace nana
}
}
#define NANA_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 )
#include <nana/pop_ignore_diagnostic>
#endif //NANA_DEPLOY_HPP

View File

@ -1 +1,54 @@
#include "gui/wvl.hpp"
/**
* Nana GUI Header
* Nana C++ Library(http://www.nanapro.org)
* 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.hpp
* @description
* the header file contains the files required for running of Nana.GUI
*/
#ifndef NANA_GUI_HPP
#define NANA_GUI_HPP
#include "gui/compact.hpp"
#include "gui/screen.hpp"
#include "gui/widgets/form.hpp"
#include "gui/drawing.hpp"
#include "gui/msgbox.hpp"
#include "gui/place.hpp"
namespace nana
{
#ifdef NANA_AUTOMATIC_GUI_TESTING
/// @brief Take control of the GUI and optionally automatically tests it.
///
/// @detail It transfers to nana the program flow control, which begin pumping messages
/// from the underlying OS, interpreting and sending it with suitable arguments
/// to the nana widgets that registered a response in the corresponding event.
/// It also accept arguments to be used in case of automatic GUI testing.
/// Other Way the arguments are ignored.
void exec(
unsigned wait = 1, ///< for the GUI to be constructed, in seconds
unsigned wait_end = 1, ///< for the GUI to be destructed, in seconds
std::function<void()> = {} ///< emit events to mimics user actions and may assert results
);
/// send a click message to this widget - useful in GUI testing
void click(widget& w);
/// in seconds
void Wait(unsigned wait = 0);
#else
void exec();
#endif
}//end namespace nana
#endif

View File

@ -24,10 +24,11 @@ namespace nana
{
namespace detail
{
struct native_window_handle_impl{};
struct window_handle_impl{};
struct event_handle_impl{};
struct native_drawable_impl{};
struct basic_window;
struct native_window_handle_impl;
struct native_drawable_impl;
struct event_handle_impl;
}
struct accel_key
@ -87,10 +88,11 @@ namespace nana
struct root_tag : public widget_tag{ static const flags value = flags::root; };
}// end namespace category
using native_window_type = detail::native_window_handle_impl*;
using window = detail::window_handle_impl*; ///< \see [What is window class ](https://sourceforge.net/p/nanapro/discussion/general/thread/bd0fabfb/)
using event_handle = detail::event_handle_impl*;
using native_drawable_type = detail::native_drawable_impl*;
using window = detail::basic_window*; ///< The window handle type representing nana window objects
using native_window_type = detail::native_window_handle_impl*; ///< The native window handle type representing system native windows. E.g, HWND in windows, Window in X11
using event_handle = detail::event_handle_impl*; ///< The event handle type representing nana window events
using native_drawable_type = detail::native_drawable_impl*; ///< The drawable handle type representing system native drawable objects. E.g. HDC in windows, Drawable in X11
struct keyboard

View File

@ -0,0 +1,57 @@
/**
* Nana GUI Library Definition
* Nana C++ Library(http://www.nanapro.org)
* 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/compact.hpp
* @description
* the header file contains the files required for running of Nana.GUI
*/
#ifndef NANA_GUI_WVL_HPP
#define NANA_GUI_WVL_HPP
#include "programming_interface.hpp"
namespace nana
{
namespace detail
{
struct form_loader_private
{
template<typename, bool> friend class form_loader;
private:
static void insert_form(::nana::widget*);
};
template<typename Form, bool IsVisible>
class form_loader
{
public:
template<typename... Args>
Form & operator()(Args &&... args) const
{
auto p = new Form(std::forward<Args>(args)...);
if (p->empty())
throw std::runtime_error("form_loader failed to create the form");
detail::form_loader_private::insert_form(p);
if (IsVisible)
p->show();
return *p;
}
};
}
template<typename Form, bool IsVisible = true>
using form_loader = detail::form_loader<Form, IsVisible>;
}//end namespace nana
#endif

View File

@ -1,7 +1,7 @@
/**
* A Bedrock Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -37,24 +37,36 @@ namespace detail
bedrock(const bedrock&) = delete;
bedrock& operator=(const bedrock&) = delete;
public:
using core_window_t = basic_window;
struct thread_context;
class flag_guard;
/// RAII class for window message processing
class root_guard
{
public:
/// Enables lazy_update
root_guard(bedrock& brock, basic_window* root_wd);
/// Disables lazy-update and clears update requesters queue.
~root_guard();
private:
bedrock& brock_;
basic_window* const root_wd_;
};
~bedrock();
void pump_event(window, bool is_modal);
void flush_surface(core_window_t*, bool forced, const rectangle* update_area = nullptr);
void flush_surface(basic_window*, bool forced, const rectangle* update_area = nullptr);
static int inc_window(thread_t tid = 0);
thread_context* open_thread_context(thread_t tid = 0);
thread_context* get_thread_context(thread_t tid = 0);
void remove_thread_context(thread_t tid = 0);
static bedrock& instance();
core_window_t* focus();
basic_window* focus();
void set_menubar_taken(core_window_t*);
void set_menubar_taken(basic_window*);
//Delay Restores focus when a menu which attached to menubar is closed
void delay_restore(int);
@ -70,7 +82,7 @@ namespace detail
bool shortkey_occurred() const;
element_store& get_element_store() const;
void map_through_widgets(core_window_t*, native_drawable_type);
void map_through_widgets(basic_window*, native_drawable_type);
//Closes the windows which are associated with the specified thread. If the given thread_id is 0, it closes all windows
void close_thread_window(thread_t thread_id);
@ -80,28 +92,28 @@ namespace detail
static void delete_platform_assoc(window_platform_assoc*);
void keyboard_accelerator(native_window_type, const accel_key&, const std::function<void()>&);
public:
void event_expose(core_window_t *, bool exposed);
void event_move(core_window_t*, int x, int y);
bool event_msleave(core_window_t*);
void event_focus_changed(core_window_t* root_wd, native_window_type receiver, bool getting);
void thread_context_destroy(core_window_t*);
void event_expose(basic_window *, bool exposed);
void event_move(basic_window*, int x, int y);
bool event_msleave(basic_window*);
void event_focus_changed(basic_window* root_wd, native_window_type receiver, bool getting);
void thread_context_destroy(basic_window*);
void thread_context_lazy_refresh();
void update_cursor(core_window_t*);
void set_cursor(core_window_t*, nana::cursor, thread_context*);
void define_state_cursor(core_window_t*, nana::cursor, thread_context*);
void undefine_state_cursor(core_window_t*, thread_context*);
void update_cursor(basic_window*);
void set_cursor(basic_window*, nana::cursor, thread_context*);
void define_state_cursor(basic_window*, nana::cursor, thread_context*);
void undefine_state_cursor(basic_window*, thread_context*);
color_schemes& scheme();
events_operation& evt_operation();
window_manager& wd_manager();
void manage_form_loader(core_window_t*, bool insert_or_remove);
void manage_form_loader(basic_window*, bool insert_or_remove);
public:
// if 'bForce__EmitInternal', then ONLY internal (widget's) events are processed (even through explicit filtering)
bool emit(event_code, core_window_t*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false);
bool emit(event_code, basic_window*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false);
private:
void _m_emit_core(event_code, core_window_t*, bool draw_only, const event_arg&, const bool bForce__EmitInternal);
void _m_event_filter(event_code, core_window_t*, thread_context*);
void _m_emit_core(event_code, basic_window*, bool draw_only, const event_arg&, const bool bForce__EmitInternal);
void _m_event_filter(event_code, basic_window*, thread_context*);
private:
static bedrock bedrock_object;

View File

@ -1,223 +0,0 @@
/*
* Effects Renderer
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/detail/effects_renderer.cpp
*/
#ifndef NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP
#define NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP
#include <nana/gui/effects.hpp>
#include <nana/paint/graphics.hpp>
#include <nana/paint/pixel_buffer.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/window_layout.hpp>
namespace nana{
namespace detail
{
template<typename CoreWindow>
class edge_nimbus_renderer
{
edge_nimbus_renderer() = default;
public:
using core_window_t = CoreWindow;
using window_layer = ::nana::detail::window_layout;
using graph_reference = ::nana::paint::graphics&;
static edge_nimbus_renderer& instance()
{
static edge_nimbus_renderer object;
return object;
}
constexpr unsigned weight() const
{
return 2;
}
void erase(core_window_t* wd)
{
if (effects::edge_nimbus::none == wd->effect.edge_nimbus)
return;
core_window_t * root_wd = wd->root_widget;
auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
for (auto i = nimbus.begin(); i != nimbus.end(); ++i)
{
if (i->window == wd)
{
auto pixels = weight();
rectangle r{wd->pos_root, wd->dimension};
r.x -= static_cast<int>(pixels);
r.y -= static_cast<int>(pixels);
r.width += static_cast<unsigned>(pixels << 1);
r.height += static_cast<unsigned>(pixels << 1);
root_wd->root_graph->paste(root_wd->root, r, r.x, r.y);
nimbus.erase(i);
break;
}
}
}
void render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr)
{
bool copy_separately = true;
std::vector<std::pair<rectangle, core_window_t*>> rd_set;
if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size())
{
auto root_wd = wd->root_widget;
auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
auto focused = root_wd->other.attribute.root->focus;
const unsigned pixels = weight();
auto graph = root_wd->root_graph;
nana::rectangle r;
for(auto & action : nimbus)
{
if(_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r))
{
if (action.window == wd)
{
if (update_area)
::nana::overlap(*update_area, rectangle(r), r);
copy_separately = false;
}
//Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered.
if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refreshed))
{
rd_set.emplace_back(r, action.window);
action.rendered = true;
}
}
else if(action.rendered)
{
action.rendered = false;
if (action.window == wd)
copy_separately = false;
::nana::rectangle erase_r(
action.window->pos_root.x - static_cast<int>(pixels),
action.window->pos_root.y - static_cast<int>(pixels),
static_cast<unsigned>(action.window->dimension.width + (pixels << 1)),
static_cast<unsigned>(action.window->dimension.height + (pixels << 1))
);
graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y);
}
}
}
if (copy_separately)
{
rectangle vr;
if (window_layer::read_visual_rectangle(wd, vr))
{
if (update_area)
::nana::overlap(*update_area, rectangle(vr), vr);
wd->root_graph->paste(wd->root, vr, vr.x, vr.y);
}
}
rectangle wd_r{ wd->pos_root, wd->dimension };
wd_r.pare_off(-static_cast<int>(this->weight()));
//Render
for (auto & rd : rd_set)
{
auto other_wd = rd.second;
if (other_wd != wd)
{
rectangle other_r{ other_wd->pos_root, other_wd->dimension };
other_r.pare_off(-static_cast<int>(this->weight()));
if (!overlapped(wd_r, other_r))
continue;
}
_m_render_edge_nimbus(other_wd, rd.first);
}
}
private:
/// Determines whether the effect will be rendered for the given window.
static bool _m_edge_nimbus(core_window_t * const wd, core_window_t * const focused_wd)
{
// Don't render the effect if the window is disabled.
if (wd->flags.enabled)
{
if ((focused_wd == wd) && (static_cast<unsigned>(wd->effect.edge_nimbus) & static_cast<unsigned>(effects::edge_nimbus::active)))
return true;
else if ((static_cast<unsigned>(wd->effect.edge_nimbus) & static_cast<unsigned>(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered))
return true;
}
return false;
}
void _m_render_edge_nimbus(core_window_t* wd, const nana::rectangle & visual)
{
wd->flags.action_before = wd->flags.action;
auto r = visual;
r.pare_off(-static_cast<int>(weight()));
rectangle good_r;
if (overlap(r, rectangle{ wd->root_graph->size() }, good_r))
{
if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) ||
(good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom()))
{
auto graph = wd->root_graph;
nana::paint::pixel_buffer pixbuf(graph->handle(), r);
pixel_argb_t px0, px1, px2, px3;
px0 = pixbuf.pixel(0, 0);
px1 = pixbuf.pixel(r.width - 1, 0);
px2 = pixbuf.pixel(0, r.height - 1);
px3 = pixbuf.pixel(r.width - 1, r.height - 1);
good_r.x = good_r.y = 1;
good_r.width = r.width - 2;
good_r.height = r.height - 2;
pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.95, false);
good_r.x = good_r.y = 0;
good_r.width = r.width;
good_r.height = r.height;
pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.4, false);
pixbuf.pixel(0, 0, px0);
pixbuf.pixel(r.width - 1, 0, px1);
pixbuf.pixel(0, r.height - 1, px2);
pixbuf.pixel(r.width - 1, r.height - 1, px3);
pixbuf.paste(wd->root, { r.x, r.y });
std::vector<typename window_layer::wd_rectangle> overlaps;
if(window_layer::read_overlaps(wd, visual, overlaps))
{
for(auto & wdr : overlaps)
graph->paste(wd->root, wdr.r, wdr.r.x, wdr.r.y);
}
}
else
wd->root_graph->paste(wd->root, visual, visual.x, visual.y);
}
}
};
}
}//end namespace nana
#endif

View File

@ -24,9 +24,13 @@
namespace nana
{
namespace API
{
bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window.
}
namespace detail
{
bool check_window(window);
void events_operation_register(event_handle);
class event_interface
@ -36,16 +40,16 @@ namespace nana
virtual void remove(event_handle) = 0;
};
class docker_interface
class event_docker_interface
{
public:
virtual ~docker_interface() = default;
virtual ~event_docker_interface() = default;
virtual event_interface* get_event() const = 0;
};
struct docker_base
: public docker_interface
: public event_docker_interface
{
event_interface * const event_ptr;
bool flag_deleted;
@ -78,11 +82,11 @@ namespace nana
event_base * const evt_;
};
event_handle _m_emplace(detail::docker_interface*, bool in_front);
event_handle _m_emplace(detail::event_docker_interface*, bool in_front);
protected:
unsigned emitting_count_{ 0 };
bool deleted_flags_{ false };
std::vector<detail::docker_interface*> * dockers_{ nullptr };
std::vector<detail::event_docker_interface*> * dockers_{ nullptr };
};
}//end namespace detail
@ -228,7 +232,7 @@ namespace nana
d->invoke(arg);
if (window_handle && (!detail::check_window(window_handle)))
if (window_handle && (!::nana::API::is_window(window_handle)))
break;
}
}

View File

@ -35,11 +35,9 @@ namespace detail
class window_layout
{
public:
typedef basic_window core_window_t;
struct wd_rectangle
{
core_window_t * window;
basic_window * window;
rectangle r;
};
@ -49,27 +47,27 @@ namespace detail
try_refresh
};
public:
static void paint(core_window_t*, paint_operation, bool request_refresh_children);
static void paint(basic_window*, paint_operation, bool request_refresh_children);
static bool maproot(core_window_t*, bool have_refreshed, bool request_refresh_children);
static bool maproot(basic_window*, bool have_refreshed, bool request_refresh_children);
static void paste_children_to_graphics(core_window_t*, nana::paint::graphics& graph);
static void paste_children_to_graphics(basic_window*, nana::paint::graphics& graph);
//read_visual_rectangle
//@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget,
// the visual rectangle is a rectangular block that a window should be displayed on screen.
// The result is a rectangle that is a visible area for its ancesters.
static bool read_visual_rectangle(core_window_t*, nana::rectangle& visual);
static bool read_visual_rectangle(basic_window*, nana::rectangle& visual);
//read_overlaps
// reads the overlaps that are overlapped a rectangular block
static bool read_overlaps(core_window_t*, const nana::rectangle& vis_rect, std::vector<wd_rectangle>& blocks);
static bool read_overlaps(basic_window*, const nana::rectangle& vis_rect, std::vector<wd_rectangle>& blocks);
static bool enable_effects_bground(core_window_t *, bool enabled);
static bool enable_effects_bground(basic_window *, bool enabled);
//make_bground
// update the glass buffer of a glass window.
static void make_bground(core_window_t* const);
static void make_bground(basic_window* const);
private:
/// _m_paste_children
@ -82,16 +80,16 @@ namespace detail
* @param graph A graphics object to which the child windows are pasted.
* @param graph_rpos The reference point to the graph.
*/
static void _m_paste_children(core_window_t* window, bool has_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos);
static void _m_paste_children(basic_window* window, bool has_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos);
static void _m_paint_glass_window(core_window_t*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other);
static void _m_paint_glass_window(basic_window*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other);
//Notify the windows which have brground to update their background buffer.
static void _m_notify_glasses(core_window_t* const sigwd);
static void _m_notify_glasses(basic_window* const sigwd);
private:
struct data_section
{
std::vector<core_window_t*> effects_bground_windows;
std::vector<basic_window*> effects_bground_windows;
};
static data_section data_sect;
};//end class window_layout

View File

@ -67,94 +67,93 @@ namespace detail
using native_window = native_window_type;
using mutex_type = revertible_mutex;
using core_window_t = basic_window;
window_manager();
~window_manager();
std::size_t number_of_core_window() const;
std::size_t window_count() const;
mutex_type & internal_lock() const;
void all_handles(std::vector<core_window_t*>&) const;
void all_handles(std::vector<basic_window*>&) const;
void event_filter(core_window_t*, bool is_make, event_code);
void event_filter(basic_window*, bool is_make, event_code);
bool available(core_window_t*);
bool available(core_window_t *, core_window_t*);
bool available(basic_window*);
bool available(basic_window *, basic_window*);
core_window_t* create_root(core_window_t*, bool nested, rectangle, const appearance&, widget*);
core_window_t* create_widget(core_window_t*, const rectangle&, bool is_lite, widget*);
void close(core_window_t*);
basic_window* create_root(basic_window*, bool nested, rectangle, const appearance&, widget*);
basic_window* create_widget(basic_window*, const rectangle&, bool is_lite, widget*);
void close(basic_window*);
//destroy
//@brief: Delete the window handle
void destroy(core_window_t*);
void destroy(basic_window*);
//destroy_handle
//@brief: Delete window handle, the handle type must be a root and a frame.
// Deletes a window whose category type is a root type or a frame type.
void destroy_handle(core_window_t*);
void destroy_handle(basic_window*);
void icon(core_window_t*, const paint::image& small_icon, const paint::image& big_icon);
void icon(basic_window*, const paint::image& small_icon, const paint::image& big_icon);
bool show(core_window_t* wd, bool visible);
bool show(basic_window* wd, bool visible);
//find a widget window at specified position
//@param root A root window
//@param pos Position
//@param ignore_captured A flag indicates whether to ignore redirecting the result to its captured window. If this paramter is true, it returns the window at the position, if the parameter is false, it returns the captured window if the captured window don't ignore children.
core_window_t* find_window(native_window_type root, const point& pos, bool ignore_captured = false);
basic_window* find_window(native_window_type root, const point& pos, bool ignore_captured = false);
//move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window
bool move(core_window_t*, int x, int y, bool passive);
bool move(core_window_t*, const rectangle&);
bool move(basic_window*, int x, int y, bool passive);
bool move(basic_window*, const rectangle&);
bool size(core_window_t*, nana::size, bool passive, bool ask_update);
bool size(basic_window*, nana::size, bool passive, bool ask_update);
core_window_t* root(native_window_type) const;
basic_window* root(native_window_type) const;
//Copy the root buffer that wnd specified into DeviceContext
void map(core_window_t*, bool forced, const rectangle* update_area = nullptr);
void map(basic_window*, bool forced, const rectangle* update_area = nullptr);
bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr);
void refresh_tree(core_window_t*);
bool update(basic_window*, bool redraw, bool force, const rectangle* update_area = nullptr);
void update_requesters(basic_window* root_wd);
void refresh_tree(basic_window*);
void do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false);
void do_lazy_refresh(basic_window*, bool force_copy_to_screen, bool refresh_tree = false);
bool set_parent(core_window_t* wd, core_window_t* new_parent);
core_window_t* set_focus(core_window_t*, bool root_has_been_focused, arg_focus::reason);
bool set_parent(basic_window* wd, basic_window* new_parent);
basic_window* set_focus(basic_window*, bool root_has_been_focused, arg_focus::reason);
core_window_t* capture_redirect(core_window_t*);
basic_window* capture_redirect(basic_window*);
bool capture_window_entered(int root_x, int root_y, bool& prev);
core_window_t * capture_window() const;
void capture_window(core_window_t*, bool capture, bool ignore_children_if_captured);
basic_window * capture_window() const;
void capture_window(basic_window*, bool capture, bool ignore_children_if_captured);
void enable_tabstop(core_window_t*);
core_window_t* tabstop(core_window_t*, bool forward) const; //forward means move to next in logic.
void enable_tabstop(basic_window*);
basic_window* tabstop(basic_window*, bool forward) const; //forward means move to next in logic.
void remove_trash_handle(thread_t tid);
bool enable_effects_bground(core_window_t*, bool);
bool enable_effects_bground(basic_window*, bool);
bool calc_window_point(core_window_t*, nana::point&);
bool calc_window_point(basic_window*, nana::point&);
root_misc* root_runtime(native_window) const;
bool register_shortkey(core_window_t*, unsigned long key);
void unregister_shortkey(core_window_t*, bool with_children);
bool register_shortkey(basic_window*, unsigned long key);
void unregister_shortkey(basic_window*, bool with_children);
core_window_t* find_shortkey(native_window_type, unsigned long key);
basic_window* find_shortkey(native_window_type, unsigned long key);
void set_safe_place(core_window_t* wd, std::function<void()>&& fn);
void set_safe_place(basic_window* wd, std::function<void()>&& fn);
void call_safe_place(thread_t thread_id);
private:
void _m_disengage(core_window_t*, core_window_t* for_new);
void _m_destroy(core_window_t*);
void _m_move_core(core_window_t*, const point& delta);
void _m_shortkeys(core_window_t*, bool with_chlidren, std::vector<std::pair<core_window_t*, unsigned long>>& keys) const;
core_window_t* _m_find(core_window_t*, const point&);
static bool _m_effective(core_window_t*, const point& root_pos);
void _m_disengage(basic_window*, basic_window* for_new);
void _m_destroy(basic_window*);
void _m_move_core(basic_window*, const point& delta);
void _m_shortkeys(basic_window*, bool with_chlidren, std::vector<std::pair<basic_window*, unsigned long>>& keys) const;
basic_window* _m_find(basic_window*, const point&);
static bool _m_effective(basic_window*, const point& root_pos);
private:
mutable mutex_type mutex_;
@ -165,10 +164,10 @@ namespace detail
{
struct captured
{
core_window_t *window;
basic_window *window;
bool inside;
bool ignore_children;
std::vector<std::pair<core_window_t*, bool> > history;
std::vector<std::pair<basic_window*, bool> > history;
}capture;
}attr_;

View File

@ -40,7 +40,16 @@ namespace nana
simple_dragdrop(simple_dragdrop&&) = delete;
simple_dragdrop& operator=(simple_dragdrop&&) = delete;
public:
simple_dragdrop(window source);
explicit simple_dragdrop(window source);
simple_dragdrop(window drag_origin,
std::function<bool()> when,
window drop_target,
std::function<void()> how)
: simple_dragdrop{drag_origin}
{
condition(when);
make_drop(drop_target, how);
}
~simple_dragdrop();
/// Condition checker

View File

@ -59,11 +59,7 @@ namespace nana
void text(const ::std::string&);
void icon(const ::std::string& icon_file);
void insert_icon(const ::std::string& icon_file);
#if 0 //deprecated
void period(unsigned millisecond);
#else
void period(std::chrono::milliseconds time);
#endif
detail::notifier_events& events();
window handle() const;
private:

View File

@ -1,16 +1,16 @@
/*
/**
* An Implementation of Place for Layout
* 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/place.cpp
* @file nana/gui/place.cpp
*
* @contributions:
* min/max and splitter bar initial weight by Ariel Vina-Rodriguez.
* @contributions
* error, width/height, min/max and splitter bar initial weight by Ariel Vina-Rodriguez.
*/
#ifndef NANA_GUI_PLACE_HPP
@ -79,6 +79,7 @@ namespace nana
{
struct implement;
class field_interface
{
field_interface(const field_interface&) = delete;
@ -103,6 +104,19 @@ namespace nana
virtual void _m_add_agent(const detail::place_agent&) = 0;
};
public:
class error :public std::invalid_argument
{
public:
error( const std::string& what,
const place& plc,
std::string field = "unknown",
std::string::size_type pos = std::string::npos);
std::string base_what;
std::string owner_caption; ///< truncate caption (title) of the "placed" widget
std::string div_text; ///< involved div_text
std::string field; ///< posible field where the error ocurred.
std::string::size_type pos; ///< posible position in the div_text where the error ocurred. npos if unknown
};
/// reference to a field manipulator which refers to a field object created by place
using field_reference = field_interface &;
@ -119,9 +133,13 @@ namespace nana
void splitter_renderer(std::function<void(window, paint::graphics&, mouse_action)> fn);
void div(std::string div_text); ///< Divides the attached widget into fields.
const std::string& div() const noexcept; ///< Returns div-text that depends on fields status.
void modify(const char* field_name, const char* div_text); ///< Modifies a specified field.
void div(std::string div_text); ///< Divides the attached widget into fields. May throw placa::error
const std::string& div() const noexcept; ///< Returns div-text that depends on fields status.
static bool valid_field_name(const char* name) ///< must begin with _a-zA-Z
{
return name && (*name == '_' || (('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z')));
}
void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. May throw placa::error
field_reference field(const char* name);///< Returns a field with the specified name.
@ -152,6 +170,8 @@ namespace nana
private:
implement * impl_;
};
}//end namespace nana
#include <nana/pop_ignore_diagnostic>

View File

@ -183,6 +183,13 @@ namespace API
};
}//end namespace detail
///Sets languages
/**
* Specifies the languages in order to make the program display multi-languages correctly
* Under Windows, the pragram can display multi-languages correctly, so this function is useless for Windows.
*/
void font_languages(const std::string& langs);
void exit(); ///< close all windows in current thread
void exit_all(); ///< close all windows

View File

@ -22,14 +22,16 @@
namespace nana
{
/// Can repeatedly call a piece of code.
class timer;
struct arg_elapse
: public event_arg
{
long long id; //timer identifier;
timer* sender; //indicates which timer emitted this notification
};
/// Can repeatedly call a piece of code.
class timer
{
struct implement;

View File

@ -35,7 +35,10 @@ namespace nana{
}//end namespace drawerbase
class group
: public widget_object<category::widget_tag, drawerbase::panel::drawer, general_events, drawerbase::group::scheme>
: public widget_object<category::widget_tag,
drawerbase::panel::drawer,
general_events,
drawerbase::group::scheme>
{
struct implement;
public:
@ -56,9 +59,8 @@ namespace nana{
group(window parent, const rectangle& = {}, bool visible = true);
/// The construction that creates the widget and set the title or caption
group(window parent, ///< a handle to the parent
::std::string title, ///< caption of the group
group(window parent, ///< a handle to the parent
::std::string title, ///< caption of the group
bool formatted = false, ///< Enable/disable the formatted text for the title
unsigned gap = 2, ///< between the content and the external limit
const rectangle& r = {} ,
@ -98,6 +100,10 @@ namespace nana{
group& enable_format_caption(bool format);
group& collocate() noexcept;
/// this will set the `usr_div_str` for an internal field, called the "user field".
/// The "full" `place` of a `group` widget is internally divided into a field for the title,
/// a field for the added "options" and a field for "user" widgets.
group& div(const char* div_str) noexcept;
field_reference operator[](const char* field);

View File

@ -1219,7 +1219,6 @@ namespace nana
unsigned min_column_width{ 20 }; ///< def=20 . non counting suspension_width
unsigned suspension_width{ 8 }; ///< def= . the trigger will set this to the width if ("...")
unsigned text_margin{ 5 }; ///< def= 5. Additional or extended with added (before) to the text width to determine the cell width. cell_w = text_w + ext_w +1
unsigned item_height_ex{ 6 }; ///< Set !=0 !!!! def=6. item_height = text_height + item_height_ex
@ -1292,7 +1291,10 @@ the nana::detail::basic_window member pointer scheme
\example listbox_Resolver.cpp
*/
class listbox
: public widget_object<category::widget_tag, drawerbase::listbox::trigger, drawerbase::listbox::listbox_events, drawerbase::listbox::scheme>,
: public widget_object<category::widget_tag,
drawerbase::listbox::trigger,
drawerbase::listbox::listbox_events,
drawerbase::listbox::scheme>,
public concepts::any_objective<drawerbase::listbox::size_type, 2>
{
public:
@ -1462,7 +1464,7 @@ the nana::detail::basic_window member pointer scheme
size_type column_size() const;
/// Move column to view_position
void move_column(size_type abs_pos, size_type view_pos);
void move_column(size_type abs_pos, size_type view_pos);
/// Sort columns in range first_col to last_col inclusive using the values from a row
void reorder_columns(size_type first_col,
@ -1568,7 +1570,7 @@ the nana::detail::basic_window member pointer scheme
* @param img_collapsed An icon displayed in front of category title when the category is collapsed.
* @return the reference of *this.
*/
listbox& category_icon(const paint::image& img_expanded, const paint::image&& img_collapsed);
listbox& category_icon(const paint::image& img_expanded, const paint::image& img_collapsed);
/// Returns first visible element
/**
@ -1590,6 +1592,18 @@ the nana::detail::basic_window member pointer scheme
* @return index_pairs containing all visible items.
*/
index_pairs visibles() const;
/// Sets a predicate that indicates whether to deselect items when mouse_up is triggered.
/**
* The predicate is called before the listbox attempts to deselect the selected items in the mouse_up event. Other situations,
* the predicates isn't called, for example, releasing mouse button after user performed a box selection, because listbox doesn't deselect the items during this operation.
* @param predicate Decides to deselect the items.
* The paramater of predicate indicates the mouse button which is releasing.
* It returns true to deselect the selected items. It returns false to cancel to deselect the selected items.
*/
void set_deselect(std::function<bool(nana::mouse)> predicate);
unsigned suspension_width() const;
private:
drawerbase::listbox::essence & _m_ess() const;
nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const override;

View File

@ -77,7 +77,10 @@ namespace nana
/// Spinbox Widget
class spinbox
: public widget_object <category::widget_tag, drawerbase::spinbox::drawer, drawerbase::spinbox::spinbox_events, ::nana::widgets::skeletons::text_editor_scheme>
: public widget_object <category::widget_tag,
drawerbase::spinbox::drawer,
drawerbase::spinbox::spinbox_events,
::nana::widgets::skeletons::text_editor_scheme>
{
public:
/// Constructs a spinbox.

View File

@ -1,4 +1,4 @@
/**
/**
* A Textbox Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
@ -177,6 +177,10 @@ namespace nana
/// Read the text from a specified line with a set offset. It returns true for success.
bool getline(std::size_t line_index,std::size_t offset,std::string& text) const;
// Get all text from textbox.
// It returns a empty string if failed or the textbox is empty.
std::string text() const { return caption(); }
/// Read the text from a specified line; returns an empty optional on failure
std::optional<std::string> getline(std::size_t pos) const;

View File

@ -33,14 +33,55 @@ namespace nana
{
namespace toolbar
{
struct item_proxy
{
nana::toolbar& widget;
std::size_t button;
enum class tool_type
{
button,
toggle
};
void enable(bool enable_state);
class item_proxy
{
public:
item_proxy(::nana::toolbar*, std::size_t pos);
bool enable() const;
item_proxy& enable(bool enable_state);
item_proxy& tooltype(tool_type type); ///< Sets the tool style.
bool istoggle() const; ///< Returns true if the tool style is toggle.
bool toggle() const; ///< Gets the tool toggle state (only if tool style is toggle).
item_proxy& toggle(bool toggle_state); ///< Sets the tool toggle state (only if tool style is toggle).
std::string toggle_group() const; ///< Returns the toggle group associated with the tool (only if tool style is toggle).
item_proxy& toggle_group(const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle).
item_proxy& textout(bool show); ///< Show/Hide the text inside the button
private:
nana::toolbar* const tb_;
std::size_t const pos_;
};
struct item_type
{
std::string text;
nana::paint::image image;
unsigned pixels{ 0 };
unsigned position{ 0 }; // last item position.
nana::size textsize;
bool enable{ true };
tool_type type{ tool_type::button };
bool toggle{ false };
std::string group;
bool textout{ false };
item_type(const std::string& text, const nana::paint::image& img, tool_type type)
:text(text), image(img), type(type)
{}
};
struct toolbar_events
: public general_events
{
@ -49,7 +90,6 @@ namespace nana
basic_event<arg_toolbar> leave; ///< The mouse leaves a control button.
};
struct item_type;
class item_container;
class drawer
@ -90,6 +130,7 @@ namespace nana
{
public:
using size_type = std::size_t; ///< A type to count the number of elements.
using tool_type = drawerbase::toolbar::tool_type;
toolbar() = default;
toolbar(window, bool visible, bool detached=false);
@ -102,6 +143,17 @@ namespace nana
bool enable(size_type index) const;
void enable(size_type index, bool enable_state);
void tooltype(size_type index, tool_type type); ///< Sets the tool style.
bool istoggle(size_type index) const; ///< Returns true if the tool style is toggle.
bool toggle(size_type index) const; ///< Gets the tool toggle state (only if tool style is toggle).
void toggle(size_type index, bool toggle_state); ///< Sets the tool toggle state (only if tool style is toggle).
std::string toggle_group(size_type index) const; ///< Returns the toggle group associated with the tool (only if tool style is toggle).
void toggle_group(size_type index, const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle).
void textout(size_type index, bool show); ///< Show/Hide the text inside the button
void scale(unsigned s); ///< Sets the scale of control button.
/// Enable to place buttons at right part. After calling it, every new button is right aligned.

View File

@ -350,7 +350,9 @@ namespace nana
/// \brief Displays a hierarchical list of items, such as the files and directories on a disk.
/// See also in [documentation](http://nanapro.org/en-us/documentation/widgets/treebox.htm)
class treebox
:public widget_object <category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events, drawerbase::treebox::scheme>
:public widget_object <category::widget_tag,
drawerbase::treebox::trigger,
drawerbase::treebox::treebox_events, drawerbase::treebox::scheme>
{
public:
/// A type refers to the item and is also used to iterate through the nodes.

View File

@ -1,88 +0,0 @@
/**
* Nana GUI Library Definition
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 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/wvl.hpp
* @description
* the header file contains the files required for running of Nana.GUI
*/
#ifndef NANA_GUI_WVL_HPP
#define NANA_GUI_WVL_HPP
#include "programming_interface.hpp"
#include "screen.hpp"
#include "widgets/form.hpp"
#include "drawing.hpp"
#include "msgbox.hpp"
#include "place.hpp"
namespace nana
{
namespace detail
{
struct form_loader_private
{
template<typename, bool> friend class form_loader;
private:
static void insert_form(::nana::widget*);
};
template<typename Form, bool IsVisible>
class form_loader
{
public:
template<typename... Args>
Form & operator()(Args &&... args) const
{
auto p = new Form(std::forward<Args>(args)...);
if (p->empty())
throw std::logic_error("form_loader failed to create the form");
detail::form_loader_private::insert_form(p);
if (IsVisible)
p->show();
return *p;
}
};
}
template<typename Form, bool IsVisible = true>
using form_loader = detail::form_loader<Form, IsVisible>;
#ifdef NANA_AUTOMATIC_GUI_TESTING
/// @brief Take control of the GUI and optionally automatically tests it.
///
/// @detail It transfers to nana the program flow control, which begin pumping messages
/// from the underlying OS, interpreting and sending it with suitable arguments
/// to the nana widgets that registered a response in the corresponding event.
/// It also accept arguments to be used in case of automatic GUI testing.
/// Other Way the arguments are ignored.
void exec(
unsigned wait = 1, ///< for the GUI to be constructed, in seconds
unsigned wait_end = 1, ///< for the GUI to be destructed, in seconds
std::function<void()> = {} ///< emit events to mimics user actions and may assert results
);
/// send a click message to this widget - useful in GUI testing
void click(widget& w);
/// in seconds
void Wait(unsigned wait = 0);
#else
void exec();
#endif
}//end namespace nana
#endif

View File

@ -10,14 +10,20 @@ namespace nana
{
public:
using graph_reference = graphics &;
enum class mode
{
truncate_with_ellipsis,
truncate_letter_with_ellipsis,
word_wrap
};
text_renderer(graph_reference graph, align = align::left);
nana::size extent_size(int x, int y, const wchar_t*, std::size_t len, unsigned restricted_pixels) const;
nana::size extent_size(int x, int y, const wchar_t*, std::size_t len, unsigned space_pixels) const;
void render(const point&, const wchar_t*, std::size_t len);
void render(const point&, const wchar_t*, std::size_t len, unsigned restricted_pixels, bool omitted);
void render(const point&, const wchar_t*, std::size_t len, unsigned restricted_pixels);
void render(const point&, const wchar_t*, std::size_t len, unsigned space_pixels, mode);
private:
graph_reference graph_;
align text_align_;

View File

@ -14,29 +14,28 @@
#if defined(NANA_WINDOWS)
#include <windows.h>
#endif
#include <cassert>
#include <array>
namespace {
std::tm localtime()
{
#if defined(NANA_WINDOWS) && !defined(NANA_MINGW)
time_t t;
::time(&t);
std::time_t t = std::time(nullptr);
std::tm tm;
if(localtime_s(&tm, &t) != 0)
assert(false);
if (localtime_s(&tm, &t) != 0)
throw std::runtime_error("invalid local time");
return tm;
#else
time_t t = std::time(nullptr);
struct tm * tm_addr = std::localtime(&t);
assert(tm_addr);
if(nullptr == tm_addr)
throw std::runtime_error("invalid local time");
return *tm_addr;
#endif
}
::nana::date::value to_dateval(const std::tm& t)
{
return {static_cast<unsigned>(t.tm_year + 1900), static_cast<unsigned>(t.tm_mon + 1), static_cast<unsigned>(t.tm_mday)};
@ -51,7 +50,7 @@ namespace {
namespace nana
{
//class date
//class date
void date::set(const std::tm& t)
{
value_ = to_dateval(t);

View File

@ -1,7 +1,7 @@
/**
* Platform Specification 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
@ -96,19 +96,19 @@ namespace detail
unsigned whitespace_pixels;
}string;
unsigned fgcolor_rgb{ 0xFFFFFFFF };
unsigned bgcolor_rgb{ 0xFFFFFFFF };
unsigned fgcolor_native{ 0xFFFFFFFF }; //Windows RGB format: 0xBBGGRR
unsigned bgcolor_native{ 0xFFFFFFFF }; //Windows RGB format
drawable_impl_type(const drawable_impl_type&) = delete;
drawable_impl_type& operator=(const drawable_impl_type&) = delete;
drawable_impl_type();
~drawable_impl_type();
unsigned get_color() const;
unsigned get_text_color() const;
void set_color(const ::nana::color&);
void set_text_color(const ::nana::color&);
private:
unsigned color_{ 0xffffffff };
unsigned text_color_{0xffffffff};
};
class platform_spec

View File

@ -1,4 +1,5 @@
#include "platform_abstraction.hpp"
#include <set>
#include <nana/deploy.hpp>
#include "../paint/truetype.hpp"
@ -153,6 +154,389 @@ IsWindows8OrGreater()
namespace nana
{
#ifdef NANA_USE_XFT
//A fallback fontset provides the multiple languages support.
class fallback_fontset
{
public:
fallback_fontset():
disp_(::nana::detail::platform_spec::instance().open_display())
{
}
~fallback_fontset()
{
for(auto xft: xftset_)
::XftFontClose(disp_, xft);
}
void open(const std::string& font_desc, const std::set<std::string>& langs)
{
for(auto xft: xftset_)
::XftFontClose(disp_, xft);
xftset_.clear();
std::set<std::string> loaded;
for(auto & lang : langs)
{
std::string patstr = "*" + font_desc + ":lang=" + lang;
auto pat = ::XftNameParse(patstr.c_str());
XftResult res;
auto match_pat = ::XftFontMatch(disp_, ::XDefaultScreen(disp_), pat, &res);
if (match_pat)
{
char * sf;
if(XftResultTypeMismatch != ::XftPatternGetString(match_pat, "family", 0, &sf))
{
//Avoid loading a some font repeatedly
if(loaded.count(sf))
continue;
}
auto xft = ::XftFontOpenPattern(disp_, match_pat);
if(xft)
xftset_.push_back(xft);
}
}
}
int draw(::XftDraw* xftdraw, ::XftColor * xftcolor, ::XftFont* xft, int x, int y, const wchar_t* str, std::size_t len)
{
if(nullptr == str || 0 == len)
return 0;
int const init_x = x;
std::unique_ptr<FT_UInt[]> glyph_indexes(new FT_UInt[len]);
while(true)
{
auto preferred = _m_scan_fonts(xft, str, len, glyph_indexes.get());
x += _m_draw(xftdraw, xftcolor, preferred.first, x, y, str, preferred.second, glyph_indexes.get());
if(len == preferred.second)
break;
len -= preferred.second;
str += preferred.second;
}
return x - init_x;
}
std::unique_ptr<unsigned[]> glyph_pixels(::XftFont* xft, const wchar_t* str, std::size_t len)
{
if(nullptr == xft || nullptr == str || 0 == len)
return {};
std::unique_ptr<FT_UInt[]> glyph_indexes{new FT_UInt[len]};
std::unique_ptr<unsigned[]> pxbuf{new unsigned[len]};
auto pbuf = pxbuf.get();
auto pstr = str;
auto size = len;
while(true)
{
auto preferred = _m_scan_fonts(xft, pstr, size, glyph_indexes.get());
_m_glyph_px(preferred.first, pstr, preferred.second, glyph_indexes.get(), pbuf);
if(size == preferred.second)
break;
size -= preferred.second;
pstr += preferred.second;
pbuf += preferred.second;
}
return pxbuf;
}
nana::size extents(::XftFont* xft, const wchar_t* str, std::size_t len)
{
nana::size extent;
if(nullptr == str || 0 == len)
return extent;
std::unique_ptr<FT_UInt[]> glyph_indexes(new FT_UInt[len]);
while(len > 0)
{
auto preferred = _m_scan_fonts(xft, str, len, glyph_indexes.get());
extent.width += _m_extents(preferred.first, str, preferred.second, glyph_indexes.get());
if(preferred.first->ascent + preferred.first->descent > static_cast<int>(extent.height))
extent.height = preferred.first->ascent + preferred.first->descent;
len -= preferred.second;
str += preferred.second;
}
return extent;
}
private:
//Tab is a invisible character
int _m_draw(::XftDraw* xftdraw, ::XftColor* xftcolor, ::XftFont* xft, int x, int y, const wchar_t* str, std::size_t len, const FT_UInt* glyph_indexes)
{
int const init_x = x;
auto p = str;
auto const end = str + len;
y += xft->ascent;
::XGlyphInfo ext;
while(p < end)
{
auto off = p - str;
auto ptab = _m_find_tab(p, end);
if(ptab == p)
{
++p;
//x += static_cast<int>(tab_pixels_);
continue;
}
auto const size = ptab - p;
::XftDrawGlyphs(xftdraw, xftcolor, xft, x, y, glyph_indexes + off, size);
::XftGlyphExtents(disp_, xft, glyph_indexes + off, size, &ext);
x += ext.xOff;
if(ptab == end)
break;
p = ptab + 1;
}
return x - init_x;
}
//Tab is a invisible character
unsigned _m_extents(::XftFont* xft, const wchar_t* const str, const std::size_t len, const FT_UInt* glyph_indexes)
{
unsigned pixels = 0;
auto p = str;
auto const end = str + len;
::XGlyphInfo ext;
while(p < end)
{
auto off = p - str;
auto ptab = _m_find_tab(p, end);
if(ptab == p)
{
++p;
//extents->xOff += tab_pixels_;
continue;
}
::XftGlyphExtents(disp_, xft, glyph_indexes + off, ptab - p, &ext);
pixels += ext.xOff;
if(end == ptab)
break;
p = ptab + 1;
}
return pixels;
}
//Tab is a invisible character
void _m_glyph_px(::XftFont* xft, const wchar_t* str, std::size_t len, const FT_UInt* glyph_indexes, unsigned* pxbuf)
{
auto const end = str + len;
::XGlyphInfo extent;
for(auto p = str; p < end; ++p)
{
if('\t' != *p)
{
::XftGlyphExtents(disp_, xft, glyph_indexes, 1, &extent);
*pxbuf = extent.xOff;
}
else
*pxbuf = 0;//tab_pixels_;
++glyph_indexes;
}
}
static const wchar_t* _m_find_tab(const wchar_t* begin, const wchar_t* end)
{
while(begin < end)
{
if('\t' == *begin)
return begin;
++begin;
}
return end;
}
std::pair<::XftFont*, std::size_t> _m_scan_fonts(::XftFont* xft, const wchar_t* str, std::size_t len, FT_UInt* const glyphs) const
{
auto preferred = xft;
auto idx = ::XftCharIndex(disp_, xft, *str);
if(0 == idx)
{
for(auto ft : xftset_)
{
idx = ::XftCharIndex(disp_, ft, *str);
if(idx)
{
preferred = ft;
break;
}
}
}
*glyphs = idx;
if(0 == idx)
{
//scan the str with all fonts until a char index is found.
for(std::size_t i = 1; i < len; ++i)
{
if(::XftCharIndex(disp_, xft, str[i]))
return {preferred, i};
for(auto ft : xftset_)
{
if(::XftCharIndex(disp_, ft, str[i]))
return {preferred, i};
}
glyphs[i] = 0;
}
return {preferred, len};
}
//scan the str with preferred font until a char index is invalid.
for(std::size_t i = 1; i < len; ++i)
{
idx = ::XftCharIndex(disp_, preferred, str[i]);
if(0 == idx)
return {preferred, i};
glyphs[i] = idx;
}
return {preferred, len};
}
private:
Display* const disp_;
std::vector<::XftFont*> xftset_;
};
/// Fallback fontset manager
class fallback_manager
{
public:
fallback_manager():
langs_(_m_split_lang("ar,hi,zh-cn,zh-tw,ja,ko,th"))
{
}
void languages(const std::string& lang)
{
langs_ = _m_split_lang(lang);
for(auto & xft : xft_table_)
{
xft.second->open(xft.first, langs_);
}
}
std::shared_ptr<fallback_fontset> make_fallback(const std::string& font_desc)
{
auto i = xft_table_.find(font_desc);
if(i != xft_table_.end())
return i->second;
auto fb = std::make_shared<fallback_fontset>();
fb->open(font_desc, langs_);
xft_table_[font_desc] = fb;
return fb;
}
void release_fallback(std::shared_ptr<fallback_fontset>& p)
{
for(auto i = xft_table_.cbegin(); i != xft_table_.cend(); ++i)
{
if(i->second == p)
{
if(p.use_count() <= 2)
xft_table_.erase(i);
break;
}
}
}
private:
static std::set<std::string> _m_split_lang(const std::string& lang)
{
std::set<std::string> langs;
std::size_t start_pos = 0;
while(true)
{
auto pos = lang.find(',', start_pos);
auto l = lang.substr(start_pos, lang.npos == pos? lang.npos : pos - start_pos);
if(!l.empty())
langs.insert(l);
if(lang.npos == pos)
break;
start_pos = pos + 1;
}
return langs;
}
private:
std::set<std::string> langs_;
std::map<std::string, std::shared_ptr<fallback_fontset>> xft_table_;
};
#endif
struct platform_runtime
{
std::shared_ptr<font_interface> font;
#ifdef NANA_X11
std::map<std::string, std::size_t> fontconfig_counts;
#endif
#ifdef NANA_USE_XFT
fallback_manager fb_manager;
#endif
};
namespace
{
namespace data
{
static platform_runtime* storage;
}
}
static platform_runtime& platform_storage()
{
if (nullptr == data::storage)
throw std::runtime_error("platform_abstraction is empty");
return *data::storage;
}
class internal_font
: public font_interface
@ -160,13 +544,24 @@ namespace nana
public:
using path_type = std::filesystem::path;
#ifdef NANA_USE_XFT
internal_font(const path_type& ttf, const std::string& font_family, double font_size, const font_style& fs, native_font_type native_font, std::shared_ptr<fallback_fontset> fallback):
ttf_(ttf),
family_(font_family),
size_(font_size),
style_(fs),
native_handle_(native_font),
fallback_(fallback)
{}
#else
internal_font(const path_type& ttf, const std::string& font_family, double font_size, const font_style& fs, native_font_type native_font):
ttf_(ttf),
family_(font_family),
size_(font_size),
style_(fs),
native_handle_(native_font)
{}
{}
#endif
~internal_font()
{
@ -175,6 +570,7 @@ namespace nana
#elif defined(NANA_X11)
auto disp = ::nana::detail::platform_spec::instance().open_display();
# ifdef NANA_USE_XFT
platform_storage().fb_manager.release_fallback(fallback_);
::XftFontClose(disp, reinterpret_cast<XftFont*>(native_handle_));
# else
::XFreeFontSet(disp, reinterpret_cast<XFontSet>(native_handle_));
@ -203,39 +599,58 @@ namespace nana
{
return native_handle_;
}
#ifdef NANA_USE_XFT
fallback_fontset* fallback() const
{
return fallback_.get();
}
#endif
private:
path_type const ttf_;
std::string const family_;
double const size_;
font_style const style_;
native_font_type const native_handle_;
};
struct platform_runtime
{
std::shared_ptr<font_interface> font;
#ifdef NANA_X11
std::map<std::string, std::size_t> fontconfig_counts;
#ifdef NANA_USE_XFT
std::shared_ptr<fallback_fontset> fallback_;
#endif
};
namespace
#ifdef NANA_USE_XFT
void nana_xft_draw_string(::XftDraw* xftdraw, ::XftColor* xftcolor, font_interface* ft, const nana::point& pos, const wchar_t * str, std::size_t len)
{
namespace data
{
static platform_runtime* storage;
}
auto fallback = static_cast<internal_font*>(ft)->fallback();
if(nullptr == fallback)
return;
auto xft = reinterpret_cast<XftFont*>(static_cast<internal_font*>(ft)->native_handle());
fallback->draw(xftdraw, xftcolor, xft, pos.x, pos.y, str, len);
}
static platform_runtime& platform_storage()
{
if (nullptr == data::storage)
throw std::runtime_error("platform_abstraction is empty");
return *data::storage;
nana::size nana_xft_extents(font_interface* ft, const wchar_t* str, std::size_t len)
{
auto fallback = static_cast<internal_font*>(ft)->fallback();
if(nullptr == fallback)
return {};
auto xft = reinterpret_cast<XftFont*>(static_cast<internal_font*>(ft)->native_handle());
return fallback->extents(xft, str, len);
}
std::unique_ptr<unsigned[]> nana_xft_glyph_pixels(font_interface* ft, const wchar_t* str, std::size_t len)
{
auto fallback = static_cast<internal_font*>(ft)->fallback();
if(nullptr == fallback)
return {};
auto xft = reinterpret_cast<XftFont*>(static_cast<internal_font*>(ft)->native_handle());
return fallback->glyph_pixels(xft, str, len);
}
#endif
void platform_abstraction::initialize()
{
if (nullptr == data::storage)
@ -284,6 +699,13 @@ namespace nana
#endif
}
void platform_abstraction::font_languages(const std::string& langs)
{
#ifdef NANA_USE_XFT
platform_storage().fb_manager.languages(langs);
#endif
}
::std::shared_ptr<platform_abstraction::font> platform_abstraction::default_font(const ::std::shared_ptr<font>& new_font)
{
auto & r = platform_storage();
@ -364,10 +786,22 @@ namespace nana
auto disp = ::nana::detail::platform_spec::instance().open_display();
# ifdef NANA_USE_XFT
if(font_family.empty())
font_family = '*';
font_family = "*";
std::string pat_str = font_family + '-' + std::to_string(size_pt ? size_pt : platform_abstraction::font_default_pt());
auto pat = ::XftNameParse(pat_str.c_str());
std::string pat_str = '-' + std::to_string(size_pt ? size_pt : platform_abstraction::font_default_pt());
if(fs.weight < 400)
pat_str += ":light";
else if(400 == fs.weight)
pat_str += ":medium";
else if(fs.weight < 700)
pat_str += ":demibold";
else
pat_str += (700 == fs.weight ? ":bold": ":black");
if(fs.italic)
pat_str += ":slant=italic";
auto pat = ::XftNameParse((font_family + pat_str).c_str());
XftResult res;
auto match_pat = ::XftFontMatch(disp, ::XDefaultScreen(disp), pat, &res);
@ -387,8 +821,16 @@ namespace nana
XFontSet fd = ::XCreateFontSet(display_, const_cast<char*>(pat_str.c_str()), &missing_list, &missing_count, &defstr);
# endif
#endif
if (fd)
{
#ifdef NANA_USE_XFT
auto fallback = platform_storage().fb_manager.make_fallback(pat_str);
return std::make_shared<internal_font>(std::move(ttf), std::move(font_family), size_pt, fs, reinterpret_cast<native_font_type>(fd), fallback);
#else
return std::make_shared<internal_font>(std::move(ttf), std::move(font_family), size_pt, fs, reinterpret_cast<native_font_type>(fd));
#endif
}
return{};
}

View File

@ -1,7 +1,7 @@
/*
* Platform Abstraction
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2017-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -34,6 +34,7 @@ namespace nana
/// Shutdown before destruction of platform_spec
static void shutdown();
static double font_default_pt();
static void font_languages(const std::string&);
static ::std::shared_ptr<font> default_font(const ::std::shared_ptr<font>&);
static ::std::shared_ptr<font> make_font(const ::std::string& font_family, double size_pt, const font::font_style& fs);
static ::std::shared_ptr<font> make_font_from_ttf(const path_type& ttf, double size_pt, const font::font_style& fs);

View File

@ -1,7 +1,7 @@
/*
* Platform Specification 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 Nana Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -27,7 +27,6 @@
#include <algorithm>
#include <nana/paint/graphics.hpp>
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/window_manager.hpp>
#include <nana/system/platform.hpp>
#include <nana/paint/pixel_buffer.hpp>
@ -35,6 +34,7 @@
#include <sstream>
#include "posix/msg_dispatcher.hpp"
#include "../gui/detail/basic_window.hpp"
namespace nana
{
@ -95,7 +95,7 @@ namespace detail
return std::string();
}
//end class conf
#if 0
//class charset_conv
charset_conv::charset_conv(const char* tocode, const char* fromcode)
{
@ -140,6 +140,7 @@ namespace detail
return rstr;
}
//end class charset_conv
#endif
#endif
//Caret implementation
@ -209,15 +210,15 @@ namespace detail
class timer_runner
{
typedef void (*timer_proc_t)(std::size_t id);
using handler_type = void(*)(const timer_core*);
struct timer_tag
{
std::size_t id;
thread_t tid;
const timer_core* handle;
thread_t thread_id;
std::size_t interval;
std::size_t timestamp;
timer_proc_t proc;
handler_type handler;
};
//timer_group
@ -233,32 +234,32 @@ namespace detail
struct timer_group
{
bool proc_entered{false}; //This flag indicates whether the timers are going to do event.
std::set<std::size_t> timers;
std::vector<std::size_t> delay_deleted;
std::set<const timer_core*> timers;
std::vector<const timer_core*> delay_deleted;
};
public:
timer_runner()
: is_proc_handling_(false)
{}
void set(std::size_t id, std::size_t interval, timer_proc_t proc)
void set(const timer_core* handle, std::size_t interval, handler_type handler)
{
auto i = holder_.find(id);
auto i = holder_.find(handle);
if(i != holder_.end())
{
i->second.interval = interval;
i->second.proc = proc;
i->second.handler = handler;
return;
}
auto tid = nana::system::this_thread_id();
threadmap_[tid].timers.insert(id);
threadmap_[tid].timers.insert(handle);
timer_tag & tag = holder_[id];
tag.id = id;
tag.tid = tid;
timer_tag & tag = holder_[handle];
tag.handle = handle;
tag.thread_id = tid;
tag.interval = interval;
tag.timestamp = 0;
tag.proc = proc;
tag.handler = handler;
}
bool is_proc_handling() const
@ -266,12 +267,12 @@ namespace detail
return is_proc_handling_;
}
void kill(std::size_t id)
bool kill(const timer_core* handle)
{
auto i = holder_.find(id);
auto i = holder_.find(handle);
if(i != holder_.end())
{
auto tid = i->second.tid;
auto tid = i->second.thread_id;
auto ig = threadmap_.find(tid);
if(ig != threadmap_.end()) //Generally, the ig should not be the end of threadmap_
@ -279,20 +280,16 @@ namespace detail
auto & group = ig->second;
if(!group.proc_entered)
{
group.timers.erase(id);
group.timers.erase(handle);
if(group.timers.empty())
threadmap_.erase(ig);
}
else
group.delay_deleted.push_back(id);
group.delay_deleted.push_back(handle);
}
holder_.erase(i);
}
}
bool empty() const
{
return (holder_.empty());
return holder_.empty();
}
void timer_proc(thread_t tid)
@ -314,7 +311,7 @@ namespace detail
tag.timestamp = ticks;
try
{
tag.proc(tag.id);
tag.handler(tag.handle);
}catch(...){} //nothrow
}
}
@ -330,7 +327,7 @@ namespace detail
private:
bool is_proc_handling_;
std::map<thread_t, timer_group> threadmap_;
std::map<std::size_t, timer_tag> holder_;
std::map<const timer_core*, timer_tag> holder_;
};
drawable_impl_type::drawable_impl_type()
@ -338,49 +335,28 @@ namespace detail
string.tab_length = 4;
string.tab_pixels = 0;
string.whitespace_pixels = 0;
#if defined(NANA_USE_XFT)
conv_.handle = ::iconv_open("UTF-8", NANA_UNICODE);
conv_.code = NANA_UNICODE;
#endif
}
drawable_impl_type::~drawable_impl_type()
{
#if defined(NANA_USE_XFT)
::iconv_close(conv_.handle);
#endif
}
unsigned drawable_impl_type::get_color() const
{
return color_;
}
unsigned drawable_impl_type::get_text_color() const
{
return text_color_;
}
void drawable_impl_type::set_color(const ::nana::color& clr)
{
color_ = (clr.px_color().value & 0xFFFFFF);
bgcolor_rgb = (clr.px_color().value & 0xFFFFFF);
}
void drawable_impl_type::set_text_color(const ::nana::color& clr)
{
text_color_ = (clr.px_color().value & 0xFFFFFF);
fgcolor_rgb = (clr.px_color().value & 0xFFFFFF);
update_text_color();
}
void drawable_impl_type::update_color()
{
if (color_ != current_color_)
if (bgcolor_rgb != current_color_)
{
auto & spec = nana::detail::platform_spec::instance();
platform_scope_guard lock;
current_color_ = color_;
auto col = color_;
current_color_ = bgcolor_rgb;
auto col = bgcolor_rgb;
switch (spec.screen_depth())
{
case 16:
@ -391,18 +367,32 @@ namespace detail
}
::XSetForeground(spec.open_display(), context, col);
::XSetBackground(spec.open_display(), context, col);
#if defined(NANA_USE_XFT)
//xft_fgcolor also needs to be assigned.
//assumes the xft_fgcolor is not assigned in update_color. There is a situation that causes a bug.
//
//update_text_color ( if fgcolor_rgb = A, then current_color = A and xft_fgcolor = A)
//update_color (if bgcolor_rgb = B, then current_color = B and xft_fgcolor is still A)
//update_text_color ( if fgcolor_rgb = B, then current_color = B, xft_fgcolor is still A)
xft_fgcolor.color.red = ((0xFF0000 & col) >> 16) * 0x101;
xft_fgcolor.color.green = ((0xFF00 & col) >> 8) * 0x101;
xft_fgcolor.color.blue = (0xFF & col) * 0x101;
xft_fgcolor.color.alpha = 0xFFFF;
#endif
}
}
void drawable_impl_type::update_text_color()
{
if (text_color_ != current_color_)
if (fgcolor_rgb != current_color_)
{
auto & spec = nana::detail::platform_spec::instance();
platform_scope_guard lock;
current_color_ = text_color_;
auto col = text_color_;
current_color_ = fgcolor_rgb;
auto col = fgcolor_rgb;
switch (spec.screen_depth())
{
case 16:
@ -445,7 +435,7 @@ namespace detail
}
platform_spec::timer_runner_tag::timer_runner_tag()
: runner(0), delete_declared(false)
: runner(nullptr), delete_declared(false)
{}
platform_spec::platform_spec()
@ -987,30 +977,32 @@ namespace detail
return r;
}
void platform_spec::set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t))
void platform_spec::set_timer(const timer_core* handle, std::size_t interval, void (*timer_proc)(const timer_core*))
{
std::lock_guard<decltype(timer_.mutex)> lock(timer_.mutex);
if(0 == timer_.runner)
if(!timer_.runner)
timer_.runner = new timer_runner;
timer_.runner->set(id, interval, timer_proc);
timer_.runner->set(handle, interval, timer_proc);
timer_.delete_declared = false;
}
void platform_spec::kill_timer(std::size_t id)
void platform_spec::kill_timer(const timer_core* handle)
{
if(timer_.runner == 0) return;
std::lock_guard<decltype(timer_.mutex)> lock(timer_.mutex);
timer_.runner->kill(id);
if(timer_.runner->empty())
if(timer_.runner)
{
if(timer_.runner->is_proc_handling() == false)
// Test if there is not a timer after killing
if(timer_.runner->kill(handle))
{
delete timer_.runner;
timer_.runner = 0;
if(timer_.runner->is_proc_handling() == false)
{
delete timer_.runner;
timer_.runner = nullptr;
}
else
timer_.delete_declared = true;
}
else
timer_.delete_declared = true;
}
}
@ -1023,7 +1015,7 @@ namespace detail
if(timer_.delete_declared)
{
delete timer_.runner;
timer_.runner = 0;
timer_.runner = nullptr;
timer_.delete_declared = false;
}
}

View File

@ -1,7 +1,7 @@
/**
* Platform Specification 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
@ -42,28 +42,22 @@ namespace detail
::DeleteObject(pixmap);
}
unsigned drawable_impl_type::get_color() const
{
return color_;
}
unsigned drawable_impl_type::get_text_color() const
{
return text_color_;
}
#define NANA_WINDOWS_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 )
void drawable_impl_type::set_color(const ::nana::color& clr)
{
color_ = (clr.px_color().value & 0xFFFFFF);
bgcolor_rgb = (clr.px_color().value & 0xFFFFFF);
bgcolor_native = NANA_WINDOWS_RGB(bgcolor_rgb);
}
void drawable_impl_type::set_text_color(const ::nana::color& clr)
{
auto rgb = (clr.px_color().value & 0xFFFFFF);
if (text_color_ != rgb)
if (fgcolor_rgb != rgb)
{
::SetTextColor(context, NANA_RGB(rgb));
text_color_ = rgb;
fgcolor_rgb = rgb;
fgcolor_native = NANA_WINDOWS_RGB(rgb);
::SetTextColor(context, fgcolor_native);
}
}

View File

@ -1,7 +1,7 @@
/*
* Platform Specification 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
@ -42,7 +42,6 @@
#if defined(NANA_USE_XFT)
#include <X11/Xft/Xft.h>
#include <iconv.h>
#include <fstream>
#endif
@ -62,19 +61,6 @@ namespace detail
private:
std::ifstream ifs_;
};
class charset_conv
{
charset_conv(const charset_conv&) = delete;
charset_conv& operator=(const charset_conv*) = delete;
public:
charset_conv(const char* tocode, const char* fromcode);
~charset_conv();
std::string charset(const std::string& str) const;
std::string charset(const char * buf, std::size_t len) const;
private:
iconv_t handle_;
};
#endif
struct drawable_impl_type
@ -95,16 +81,15 @@ namespace detail
unsigned whitespace_pixels;
}string;
unsigned fgcolor_rgb{ 0xFFFFFFFF };
unsigned bgcolor_rgb{ 0xFFFFFFFF };
#if defined(NANA_USE_XFT)
XftDraw * xftdraw{nullptr};
XftColor xft_fgcolor;
const std::string charset(const std::wstring& str, const std::string& strcode);
#endif
drawable_impl_type();
~drawable_impl_type();
unsigned get_color() const;
unsigned get_text_color() const;
void set_color(const ::nana::color&);
void set_text_color(const ::nana::color&);
@ -115,16 +100,6 @@ namespace detail
drawable_impl_type& operator=(const drawable_impl_type&) = delete;
unsigned current_color_{ 0xFFFFFF };
unsigned color_{ 0xFFFFFFFF };
unsigned text_color_{ 0xFFFFFFFF };
#if defined(NANA_USE_XFT)
struct conv_tag
{
iconv_t handle;
std::string code;
}conv_;
#endif
};
struct atombase_tag
@ -171,6 +146,13 @@ namespace detail
//A forward declaration of caret data
struct caret_rep;
/// class timer_core
/**
* Platform-spec only provides the declaration for intrducing a handle type, the definition
* of timer_core is given by gui/timer.cpp
*/
class timer_core;
class timer_runner;
class platform_scope_guard
@ -251,8 +233,8 @@ namespace detail
//when native_interface::show a window that is registered as a grab
//window, the native_interface grabs the window.
Window grab(Window);
void set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t id));
void kill_timer(std::size_t id);
void set_timer(const timer_core*, std::size_t interval, void (*timer_proc)(const timer_core* tm));
void kill_timer(const timer_core*);
void timer_proc(thread_t tid);
//Message dispatcher

View File

@ -110,42 +110,6 @@ namespace nana
return tm.str();
}
return {};
/*
// Deprecated
//Windows stores file times using the FILETIME structure, which is a 64 bit value of 100ns intervals from January 1, 1601.
//What's worse is that this 1601 date is fairly common to see given that it's the all zeroes value, and it is far before the
//earliest date representable with time_t.std::filesystem can't change the reality of the underlying platform.
try {
#if NANA_USING_BOOST_FILESYSTEM
// The return type of boost::filesystem::last_write_time isn't
// the same as in nana and std implementations of this function
auto ftime = std::chrono::system_clock::from_time_t(fs::last_write_time(path));
#else
auto ftime = fs::last_write_time(path);
#endif
// crash: VS2015 will not read the time for some files (for example: C:/hiberfil.sys)
// and will return file_time_type(-1) without throwing
// https://msdn.microsoft.com/en-us/library/dn823784.aspx
if (ftime == ((fs::file_time_type::min)())) return{};
//A workaround for VC2013
using time_point = decltype(ftime);
auto cftime = time_point::clock::to_time_t(ftime);
std::stringstream tm;
tm << std::put_time(std::localtime(&cftime), "%Y-%m-%d, %H:%M:%S");
return tm.str();
}
catch (...) {
return{};
}
#endif
*/
}
bool modified_file_time(const fs::path& p, struct tm& t)

View File

@ -10,7 +10,7 @@
* @file: nana/gui/detail/basic_window.cpp
*/
#include <nana/gui/detail/basic_window.hpp>
#include "basic_window.hpp"
#include <nana/gui/detail/native_window_interface.hpp>
namespace nana

View File

@ -14,11 +14,11 @@
#ifndef NANA_GUI_DETAIL_BASIC_WINDOW_HPP
#define NANA_GUI_DETAIL_BASIC_WINDOW_HPP
#include <nana/push_ignore_diagnostic>
#include "drawer.hpp"
#include "events_holder.hpp"
#include "widget_geometrics.hpp"
#include "widget_content_measurer_interface.hpp"
#include "widget_notifier_interface.hpp"
#include <nana/gui/detail/drawer.hpp>
#include <nana/gui/detail/events_holder.hpp>
#include <nana/gui/detail/widget_geometrics.hpp>
#include <nana/gui/detail/widget_content_measurer_interface.hpp>
#include <nana/gui/detail/widget_notifier_interface.hpp>
#include <nana/basic_types.hpp>
#include <nana/system/platform.hpp>
#include <nana/gui/effects.hpp>

View File

@ -11,16 +11,18 @@
*/
#include "../../detail/platform_spec_selector.hpp"
#include "basic_window.hpp"
#include "bedrock_types.hpp"
#include <nana/gui/compact.hpp>
#include <nana/gui/widgets/widget.hpp>
#include <nana/gui/detail/event_code.hpp>
#include <nana/system/platform.hpp>
#include <sstream>
#include <nana/system/timepiece.hpp>
#include <nana/gui/wvl.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/element_store.hpp>
#include <sstream>
#include <algorithm>
namespace nana
@ -64,11 +66,6 @@ namespace nana
namespace detail
{
bool check_window(window wd)
{
return bedrock::instance().wd_manager().available(reinterpret_cast<window_manager::core_window_t*>(wd));
}
void events_operation_register(event_handle evt)
{
bedrock::instance().evt_operation().register_evt(evt);
@ -77,7 +74,7 @@ namespace nana
class bedrock::flag_guard
{
public:
flag_guard(bedrock* brock, core_window_t * wd)
flag_guard(bedrock* brock, basic_window * wd)
: brock_{ brock }, wd_(wd)
{
wd_->flags.refreshing = true;
@ -90,11 +87,28 @@ namespace nana
}
private:
bedrock *const brock_;
core_window_t *const wd_;
basic_window *const wd_;
};
bedrock::core_window_t* bedrock::focus()
//class root_guard
bedrock::root_guard::root_guard(bedrock& brock, basic_window* root_wd):
brock_(brock),
root_wd_(root_wd)
{
root_wd_->other.attribute.root->lazy_update = true;
}
bedrock::root_guard::~root_guard()
{
if (!brock_.wd_manager().available(root_wd_))
return;
root_wd_->other.attribute.root->lazy_update = false;
root_wd_->other.attribute.root->update_requesters.clear();
}
//end class root_guard
basic_window* bedrock::focus()
{
auto wd = wd_manager().root(native_interface::get_focus_window());
return (wd ? wd->other.attribute.root->focus : nullptr);
@ -110,7 +124,7 @@ namespace nana
return pi_data_->wd_manager;
}
void bedrock::manage_form_loader(core_window_t* wd, bool insert_or_remove)
void bedrock::manage_form_loader(basic_window* wd, bool insert_or_remove)
{
if (insert_or_remove)
{
@ -127,7 +141,7 @@ namespace nana
void bedrock::close_thread_window(thread_t thread_id)
{
std::vector<core_window_t*> v;
std::vector<basic_window*> v;
wd_manager().all_handles(v);
std::vector<native_window_type> roots;
@ -146,7 +160,7 @@ namespace nana
native_interface::close_window(i);
}
void bedrock::event_expose(core_window_t * wd, bool exposed)
void bedrock::event_expose(basic_window * wd, bool exposed)
{
if (nullptr == wd) return;
@ -154,11 +168,11 @@ namespace nana
arg_expose arg;
arg.exposed = exposed;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
if (emit(event_code::expose, wd, arg, false, get_thread_context()))
{
//Get the window who has the activated caret
const core_window_t * caret_wd = ((wd->annex.caret_ptr && wd->annex.caret_ptr->activated()) ? wd : wd->child_caret());
auto const caret_wd = ((wd->annex.caret_ptr && wd->annex.caret_ptr->activated()) ? wd : wd->child_caret());
if (caret_wd)
{
if (exposed)
@ -181,19 +195,19 @@ namespace nana
}
}
void bedrock::event_move(core_window_t* wd, int x, int y)
void bedrock::event_move(basic_window* wd, int x, int y)
{
if (wd)
{
arg_move arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.x = x;
arg.y = y;
emit(event_code::move, wd, arg, true, get_thread_context());
}
}
bool bedrock::event_msleave(core_window_t* hovered)
bool bedrock::event_msleave(basic_window* hovered)
{
if (wd_manager().available(hovered) && hovered->flags.enabled)
{
@ -201,7 +215,7 @@ namespace nana
arg_mouse arg;
arg.evt_code = event_code::mouse_leave;
arg.window_handle = reinterpret_cast<window>(hovered);
arg.window_handle = hovered;
arg.pos.x = arg.pos.y = 0;
arg.left_button = arg.right_button = arg.mid_button = false;
arg.ctrl = arg.shift = false;
@ -212,12 +226,12 @@ namespace nana
}
//The wd must be a root window
void bedrock::event_focus_changed(core_window_t* root_wd, native_window_type receiver, bool getting)
void bedrock::event_focus_changed(basic_window* root_wd, native_window_type receiver, bool getting)
{
auto focused = root_wd->other.attribute.root->focus;
arg_focus arg;
arg.window_handle = reinterpret_cast<window>(focused);
arg.window_handle = focused;
arg.getting = getting;
arg.receiver = receiver;
@ -243,7 +257,7 @@ namespace nana
}
}
void bedrock::update_cursor(core_window_t * wd)
void bedrock::update_cursor(basic_window * wd)
{
internal_scope_guard isg;
if (wd_manager().available(wd))
@ -265,7 +279,7 @@ namespace nana
}
}
void bedrock::set_menubar_taken(core_window_t* wd)
void bedrock::set_menubar_taken(basic_window* wd)
{
auto pre = pi_data_->menu.taken_window;
pi_data_->menu.taken_window = wd;
@ -379,7 +393,7 @@ namespace nana
return pi_data_->scheme;
}
void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg, const bool bForce__EmitInternal)
void bedrock::_m_emit_core(event_code evt_code, basic_window* wd, bool draw_only, const ::nana::event_arg& event_arg, const bool bForce__EmitInternal)
{
auto retain = wd->annex.events_ptr;
auto evts_ptr = retain.get();
@ -399,7 +413,7 @@ namespace nana
wd->drawer.click(*arg, bForce__EmitInternal);
}
if (bProcess__External_event)
evts_ptr->click.emit(*arg, reinterpret_cast<window>(wd));
evts_ptr->click.emit(*arg, wd);
}
}
break;
@ -454,7 +468,7 @@ namespace nana
}
if (bProcess__External_event)
evt_addr->emit(*arg, reinterpret_cast<window>(wd));
evt_addr->emit(*arg, wd);
break;
}
case event_code::mouse_wheel:
@ -469,7 +483,7 @@ namespace nana
}
if (bProcess__External_event)
evts_ptr->mouse_wheel.emit(*arg, reinterpret_cast<window>(wd));
evts_ptr->mouse_wheel.emit(*arg, wd);
}
break;
}
@ -513,7 +527,7 @@ namespace nana
}
if (bProcess__External_event)
evt_addr->emit(*arg, reinterpret_cast<window>(wd));
evt_addr->emit(*arg, wd);
break;
}
case event_code::expose:
@ -521,7 +535,7 @@ namespace nana
{
auto arg = dynamic_cast<const arg_expose*>(&event_arg);
if (arg)
evts_ptr->expose.emit(*arg, reinterpret_cast<window>(wd));
evts_ptr->expose.emit(*arg, wd);
}
break;
case event_code::focus:
@ -535,7 +549,7 @@ namespace nana
wd->drawer.focus(*arg, bForce__EmitInternal);
}
if (bProcess__External_event)
evts_ptr->focus.emit(*arg, reinterpret_cast<window>(wd));
evts_ptr->focus.emit(*arg, wd);
}
break;
}
@ -550,7 +564,7 @@ namespace nana
wd->drawer.move(*arg, bForce__EmitInternal);
}
if (bProcess__External_event)
evts_ptr->move.emit(*arg, reinterpret_cast<window>(wd));
evts_ptr->move.emit(*arg, wd);
}
break;
}
@ -565,7 +579,7 @@ namespace nana
wd->drawer.resizing(*arg, bForce__EmitInternal);
}
if (bProcess__External_event)
evts_ptr->resizing.emit(*arg, reinterpret_cast<window>(wd));
evts_ptr->resizing.emit(*arg, wd);
}
break;
}
@ -580,7 +594,7 @@ namespace nana
wd->drawer.resized(*arg, bForce__EmitInternal);
}
if (bProcess__External_event)
evts_ptr->resized.emit(*arg, reinterpret_cast<window>(wd));
evts_ptr->resized.emit(*arg, wd);
}
break;
}
@ -592,7 +606,7 @@ namespace nana
{
auto evt_root = dynamic_cast<events_root_extension*>(evts_ptr);
if (evt_root)
evt_root->unload.emit(*arg, reinterpret_cast<window>(wd));
evt_root->unload.emit(*arg, wd);
}
}
break;
@ -601,7 +615,7 @@ namespace nana
{
auto arg = dynamic_cast<const arg_destroy*>(&event_arg);
if (arg)
evts_ptr->destroy.emit(*arg, reinterpret_cast<window>(wd));
evts_ptr->destroy.emit(*arg, wd);
}
break;
default:
@ -609,7 +623,7 @@ namespace nana
}
}
void bedrock::thread_context_destroy(core_window_t * wd)
void bedrock::thread_context_destroy(basic_window * wd)
{
auto ctx = get_thread_context(0);
if(ctx && ctx->event_window == wd)
@ -620,15 +634,15 @@ namespace nana
{
auto ctx = get_thread_context(0);
if(ctx && ctx->event_window)
ctx->event_window->other.upd_state = core_window_t::update_state::refreshed;
ctx->event_window->other.upd_state = basic_window::update_state::refreshed;
}
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal)
bool bedrock::emit(event_code evt_code, basic_window* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal)
{
if(wd_manager().available(wd) == false)
return false;
core_window_t * prev_wd = nullptr;
basic_window * prev_wd = nullptr;
if(thrd)
{
prev_wd = thrd->event_window;
@ -663,7 +677,7 @@ namespace nana
return good_wd;
}
void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd)
void bedrock::_m_event_filter(event_code event_id, basic_window * wd, thread_context * thrd)
{
auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow);

View File

@ -141,9 +141,9 @@ namespace detail
delete impl_;
}
void bedrock::flush_surface(core_window_t* wd, bool forced, const rectangle* update_area)
void bedrock::flush_surface(basic_window* wd, bool forced, const rectangle* update_area)
{
wd->drawer.map(reinterpret_cast<window>(wd), forced, update_area);
wd->drawer.map(wd, forced, update_area);
}
//inc_window
@ -248,14 +248,14 @@ namespace detail
return impl_->estore;
}
void bedrock::map_through_widgets(core_window_t*, native_drawable_type)
void bedrock::map_through_widgets(basic_window*, native_drawable_type)
{
//No implementation for Linux
}
void assign_arg(arg_mouse& arg, basic_window* wd, unsigned msg, const XEvent& evt)
{
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.button = ::nana::mouse::any_button;
int mask_state = 0;
@ -308,7 +308,7 @@ namespace detail
void assign_arg(arg_focus& arg, basic_window* wd, native_window_type recv, bool getting)
{
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.receiver = recv;
arg.getting = getting;
arg.focus_reason = arg_focus::reason::general;
@ -317,7 +317,7 @@ namespace detail
void assign_arg(arg_wheel& arg, basic_window* wd, const XEvent& evt)
{
arg.evt_code = event_code::mouse_wheel;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
if (ButtonRelease == evt.type && (evt.xbutton.button == Button4 || evt.xbutton.button == Button5))
{
arg.evt_code = event_code::mouse_wheel;
@ -371,12 +371,12 @@ namespace detail
if(msgwd)
{
arg_dropfiles arg;
arg.window_handle = reinterpret_cast<window>(msgwd);
arg.window_handle = msgwd;
arg.files.swap(*msg.u.mouse_drop.files);
delete msg.u.mouse_drop.files;
arg.pos.x = msg.u.mouse_drop.x - msgwd->pos_root.x;
arg.pos.y = msg.u.mouse_drop.y - msgwd->pos_root.y;
msgwd->annex.events_ptr->mouse_dropfiles.emit(arg, reinterpret_cast<window>(msgwd));
msgwd->annex.events_ptr->mouse_dropfiles.emit(arg, msgwd);
brock.wd_manager().do_lazy_refresh(msgwd, false);
}
break;
@ -512,11 +512,9 @@ namespace detail
auto const native_window = rruntime->window->root;
nana::detail::charset_conv charset(NANA_UNICODE, "UTF-8");
const std::string& str = charset.charset(std::string(keybuf, keybuf + keybuf_len));
auto const charbuf = reinterpret_cast<const wchar_t*>(str.c_str());
auto const len = str.size() / sizeof(wchar_t);
auto wstr = nana::to_wstring(std::string{keybuf, keybuf + keybuf_len});
auto const charbuf = wstr.c_str();
auto const len = wstr.length();
for(std::size_t i = 0; i < len; ++i)
{
@ -539,15 +537,15 @@ namespace detail
auto shr_wd = wd_manager.find_shortkey(native_window, arg.key);
if(shr_wd)
{
arg.window_handle = reinterpret_cast<window>(shr_wd);
arg.window_handle = shr_wd;
brock.emit(event_code::shortkey, shr_wd, arg, true, &context);
}
continue;
}
arg.evt_code = event_code::key_char;
arg.window_handle = reinterpret_cast<window>(msgwd);
msgwd->annex.events_ptr->key_char.emit(arg, reinterpret_cast<window>(msgwd));
arg.window_handle = msgwd;
msgwd->annex.events_ptr->key_char.emit(arg, msgwd);
if(arg.ignore == false && wd_manager.available(msgwd))
draw_invoker(&drawer::key_char, msgwd, arg, &context);
}
@ -556,34 +554,11 @@ namespace detail
context.is_alt_pressed = false;
}
class window_proc_guard
{
public:
window_proc_guard(detail::basic_window* wd) :
root_wd_(wd)
{
root_wd_->other.attribute.root->lazy_update = true;
}
~window_proc_guard()
{
if (!bedrock::instance().wd_manager().available(root_wd_))
return;
root_wd_->other.attribute.root->lazy_update = false;
root_wd_->other.attribute.root->update_requesters.clear();
}
private:
detail::basic_window* const root_wd_;
};
void window_proc_for_xevent(Display* /*display*/, XEvent& xevent)
{
typedef detail::bedrock::core_window_t core_window_t;
static auto& brock = detail::bedrock::instance();
static unsigned long last_mouse_down_time;
static core_window_t* last_mouse_down_window;
static basic_window* last_mouse_down_window;
auto native_window = reinterpret_cast<native_window_type>(event_window(xevent));
auto & wd_manager = brock.wd_manager();
@ -593,7 +568,8 @@ namespace detail
{
auto const root_wd = root_runtime->window;
auto msgwnd = root_wd;
window_proc_guard wp_guard{ root_wd };
detail::bedrock::root_guard rw_guard{ brock, root_wd };
auto& context = *brock.get_thread_context(msgwnd->thread_id);
@ -786,7 +762,7 @@ namespace detail
{
msgwnd->set_action(mouse_action::hovered);
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
click_arg.window_handle = msgwnd;
draw_invoker(&drawer::click, msgwnd, click_arg, &context);
}
}
@ -804,16 +780,16 @@ namespace detail
draw_invoker(&drawer::mouse_up, msgwnd, arg, &context);
if(click_arg.window_handle)
evt_ptr->click.emit(click_arg, reinterpret_cast<window>(msgwnd));
evt_ptr->click.emit(click_arg, msgwnd);
if (wd_manager.available(msgwnd))
{
arg.evt_code = event_code::mouse_up;
evt_ptr->mouse_up.emit(arg, reinterpret_cast<window>(msgwnd));
evt_ptr->mouse_up.emit(arg, msgwnd);
}
}
else if(click_arg.window_handle)
msgwnd->annex.events_ptr->click.emit(click_arg, reinterpret_cast<window>(msgwnd));
msgwnd->annex.events_ptr->click.emit(click_arg, msgwnd);
wd_manager.do_lazy_refresh(msgwnd, false);
}
@ -937,7 +913,7 @@ namespace detail
//Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
::nana::rectangle update_area(xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height);
if (!update_area.empty())
msgwnd->drawer.map(reinterpret_cast<window>(msgwnd), true, &update_area);
msgwnd->drawer.map(msgwnd, true, &update_area);
}
}
break;
@ -1016,7 +992,7 @@ namespace detail
else if((keyboard::space == os_code) && msgwnd->flags.space_click_enabled)
{
//Clicked by spacebar
if((nullptr == pressed_wd) && (nullptr == pressed_wd_space))
if((nullptr == pressed_wd) && (nullptr == pressed_wd_space) && msgwnd->flags.enabled)
{
arg_mouse arg;
arg.alt = modifiers_status.alt;
@ -1027,7 +1003,7 @@ namespace detail
arg.mid_button = false;
arg.pos.x = 0;
arg.pos.y = 0;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
msgwnd->set_action(mouse_action::pressed);
@ -1049,7 +1025,7 @@ namespace detail
bool focused = (brock.focus() == msgwnd);
arg_keyboard arg;
arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.ignore = false;
arg.key = os_code;
brock.get_key_state(arg);
@ -1071,7 +1047,7 @@ namespace detail
arg.ignore = false;
arg.key = os_code;
arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
brock.emit(event_code::key_press, msgwnd, arg, true, &context);
@ -1119,7 +1095,7 @@ namespace detail
msgwnd = brock.focus();
if(msgwnd)
{
if(msgwnd == pressed_wd_space)
if((msgwnd == pressed_wd_space) && msgwnd->flags.enabled)
{
msgwnd->set_action(mouse_action::normal);
@ -1127,7 +1103,7 @@ namespace detail
arg_click click_arg;
click_arg.mouse_args = nullptr;
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
click_arg.window_handle = msgwnd;
arg_mouse arg;
arg.alt = false;
@ -1138,7 +1114,7 @@ namespace detail
arg.mid_button = false;
arg.pos.x = 0;
arg.pos.y = 0;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
draw_invoker(&drawer::mouse_up, msgwnd, arg, &context);
@ -1152,7 +1128,7 @@ namespace detail
arg_keyboard arg;
arg.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.ignore = false;
arg.key = os_code;
brock.get_key_state(arg);
@ -1178,7 +1154,7 @@ namespace detail
arg_keyboard arg;
arg.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.ignore = false;
arg.key = os_code;
brock.get_key_state(arg);
@ -1205,7 +1181,7 @@ namespace detail
if(msgwnd->flags.enabled && (atoms.wm_delete_window == static_cast<Atom>(xclient.data.l[0])))
{
arg_unload arg;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.cancel = false;
brock.emit(event_code::unload, msgwnd, arg, true, &context);
if(false == arg.cancel)
@ -1215,14 +1191,8 @@ namespace detail
}
}
if (wd_manager.available(root_wd) && root_wd->other.attribute.root->update_requesters.size())
{
for (auto wd : root_wd->other.attribute.root->update_requesters)
{
window_layout::paint(wd, window_layout::paint_operation::have_refreshed, false);
wd_manager.map(wd, true);
}
}
wd_manager.update_requesters(root_wd);
root_runtime = wd_manager.root_runtime(native_window);
if(root_runtime)
@ -1262,10 +1232,10 @@ namespace detail
lock.revert();
native_window_type owner_native{};
core_window_t * owner = 0;
basic_window * owner = nullptr;
if(condition_wd && is_modal)
{
native_window_type modal = reinterpret_cast<core_window_t*>(condition_wd)->root;
native_window_type modal = condition_wd->root;
owner_native = native_interface::get_window(modal, window_relationship::owner);
if(owner_native)
{
@ -1276,7 +1246,7 @@ namespace detail
}
}
nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? reinterpret_cast<core_window_t*>(condition_wd)->root : 0);
nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? condition_wd->root : 0);
if(owner_native)
{
@ -1304,7 +1274,7 @@ namespace detail
}//end bedrock::event_loop
//Dynamically set a cursor for a window
void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd)
void bedrock::set_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd)
{
if (nullptr == thrd)
thrd = get_thread_context(wd->thread_id);
@ -1347,14 +1317,14 @@ namespace detail
}
}
void bedrock::define_state_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd)
void bedrock::define_state_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd)
{
wd->root_widget->other.attribute.root->state_cursor = cur;
wd->root_widget->other.attribute.root->state_cursor_window = wd;
set_cursor(wd, cur, thrd);
}
void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd)
void bedrock::undefine_state_cursor(basic_window * wd, thread_context* thrd)
{
if (!wd_manager().available(wd))
return;

View File

@ -18,12 +18,12 @@ namespace nana
color_schemes scheme;
events_operation evt_operation;
window_manager wd_manager;
std::set<core_window_t*> auto_form_set;
std::set<basic_window*> auto_form_set;
bool shortkey_occurred{ false };
struct menu_rep
{
core_window_t* taken_window{ nullptr };
basic_window* taken_window{ nullptr };
bool delay_restore{ false };
native_window_type window{ nullptr };
native_window_type owner{ nullptr };
@ -37,7 +37,7 @@ namespace nana
{
unsigned event_pump_ref_count{0};
int window_count{0}; //The number of windows
core_window_t* event_window{nullptr};
basic_window* event_window{nullptr};
struct platform_detail_tag
{
@ -46,7 +46,7 @@ namespace nana
struct cursor_tag
{
core_window_t * window;
basic_window * window;
native_window_type native_handle;
nana::cursor predef_cursor;
HCURSOR handle;
@ -66,7 +66,7 @@ namespace nana
unsigned event_pump_ref_count{0};
int window_count{0}; //The number of windows
core_window_t* event_window{nullptr};
basic_window* event_window{nullptr};
bool is_alt_pressed{false};
bool is_ctrl_pressed{false};
@ -78,7 +78,7 @@ namespace nana
struct cursor_tag
{
core_window_t * window;
basic_window * window;
native_window_type native_handle;
nana::cursor predef_cursor;
Cursor handle;

View File

@ -18,7 +18,8 @@
#include <nana/gui/detail/event_code.hpp>
#include <nana/system/platform.hpp>
#include <nana/system/timepiece.hpp>
#include <nana/gui.hpp>
#include <nana/gui/compact.hpp>
#include <nana/gui/msgbox.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/window_layout.hpp>
@ -213,9 +214,9 @@ namespace detail
bedrock::~bedrock()
{
if(wd_manager().number_of_core_window())
if(wd_manager().window_count())
{
std::string msg = "Nana.GUI detects a memory leaks in window_manager, " + std::to_string(wd_manager().number_of_core_window()) + " window(s) are not uninstalled.";
std::string msg = "Nana.GUI detects a memory leaks in window_manager, " + std::to_string(wd_manager().window_count()) + " window(s) are not uninstalled.";
std::cerr << msg; /// \todo add list of cations of opening windows and if auto testing GUI do auto OK after 2 seconds.
::MessageBoxA(0, msg.c_str(), ("Nana C++ Library"), MB_OK);
}
@ -290,7 +291,7 @@ namespace detail
return bedrock_object;
}
void bedrock::flush_surface(core_window_t* wd, bool forced, const rectangle* update_area)
void bedrock::flush_surface(basic_window* wd, bool forced, const rectangle* update_area)
{
if (nana::system::this_thread_id() != wd->thread_id)
{
@ -311,7 +312,7 @@ namespace detail
}
}
else
wd->drawer.map(reinterpret_cast<window>(wd), forced, update_area);
wd->drawer.map(wd, forced, update_area);
}
void interior_helper_for_menu(MSG& msg, native_window_type menu_window)
@ -367,7 +368,7 @@ namespace detail
MSG msg;
if (condition_wd)
{
HWND native_handle = reinterpret_cast<HWND>(reinterpret_cast<core_window_t*>(condition_wd)->root);
HWND native_handle = reinterpret_cast<HWND>(condition_wd->root);
if (is_modal)
{
HWND owner = ::GetWindow(native_handle, GW_OWNER);
@ -466,7 +467,7 @@ namespace detail
void assign_arg(nana::arg_mouse& arg, basic_window* wd, unsigned msg, const parameter_decoder& pmdec)
{
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
bool set_key_state = true;
switch (msg)
@ -530,7 +531,7 @@ namespace detail
void assign_arg(arg_wheel& arg, basic_window* wd, const parameter_decoder& pmdec)
{
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.evt_code = event_code::mouse_wheel;
POINT point = { pmdec.mouse.x, pmdec.mouse.y };
@ -581,7 +582,7 @@ namespace detail
case nana::detail::messages::remote_flush_surface:
{
auto stru = reinterpret_cast<detail::messages::map_thread*>(lParam);
bedrock.wd_manager().map(reinterpret_cast<bedrock::core_window_t*>(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area));
bedrock.wd_manager().map(reinterpret_cast<basic_window*>(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area));
::UpdateWindow(wd);
::HeapFree(::GetProcessHeap(), 0, stru);
}
@ -652,7 +653,7 @@ namespace detail
return true;
}
void adjust_sizing(bedrock::core_window_t* wd, ::RECT * const r, int edge, unsigned req_width, unsigned req_height)
void adjust_sizing(basic_window* wd, ::RECT * const r, int edge, unsigned req_width, unsigned req_height)
{
unsigned width = static_cast<unsigned>(r->right - r->left) - wd->extra_width;
unsigned height = static_cast<unsigned>(r->bottom - r->top) - wd->extra_height;
@ -740,27 +741,6 @@ namespace detail
return static_cast<wchar_t>(vkey);
}
class window_proc_guard
{
public:
window_proc_guard(detail::basic_window* wd) :
root_wd_(wd)
{
root_wd_->other.attribute.root->lazy_update = true;
}
~window_proc_guard()
{
if (!bedrock::instance().wd_manager().available(root_wd_))
return;
root_wd_->other.attribute.root->lazy_update = false;
root_wd_->other.attribute.root->update_requesters.clear();
}
private:
detail::basic_window* const root_wd_;
};
LRESULT CALLBACK Bedrock_WIN32_WindowProc(HWND root_window, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT window_proc_value = 0;
@ -793,7 +773,7 @@ namespace detail
auto const root_wd = root_runtime->window;
auto msgwnd = root_wd;
window_proc_guard wp_guard{ root_wd };
detail::bedrock::root_guard rw_guard{ brock, root_wd };
switch (message)
{
@ -1006,7 +986,7 @@ namespace detail
msgwnd->set_action(mouse_action::hovered);
if ((::nana::mouse::left_button == arg.button) && (pressed_wd == msgwnd))
{
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
click_arg.window_handle = msgwnd;
draw_invoker(&drawer::click, msgwnd, click_arg, &context);
}
}
@ -1018,16 +998,16 @@ namespace detail
draw_invoker(&drawer::mouse_up, msgwnd, arg, &context);
if (click_arg.window_handle)
retain->click.emit(click_arg, reinterpret_cast<window>(msgwnd));
retain->click.emit(click_arg, msgwnd);
if (wd_manager.available(msgwnd))
{
arg.evt_code = event_code::mouse_up;
retain->mouse_up.emit(arg, reinterpret_cast<window>(msgwnd));
retain->mouse_up.emit(arg, msgwnd);
}
}
else if (click_arg.window_handle)
retain->click.emit(click_arg, reinterpret_cast<window>(msgwnd));
retain->click.emit(click_arg, msgwnd);
wd_manager.do_lazy_refresh(msgwnd, false);
}
@ -1197,9 +1177,9 @@ namespace detail
dropfiles.pos = pos;
wd_manager.calc_window_point(msgwnd, dropfiles.pos);
dropfiles.window_handle = reinterpret_cast<window>(msgwnd);
dropfiles.window_handle = msgwnd;
msgwnd->annex.events_ptr->mouse_dropfiles.emit(dropfiles, reinterpret_cast<window>(msgwnd));
msgwnd->annex.events_ptr->mouse_dropfiles.emit(dropfiles, msgwnd);
wd_manager.do_lazy_refresh(msgwnd, false);
}
}
@ -1253,7 +1233,7 @@ namespace detail
static_cast<unsigned>(r->bottom - r->top - msgwnd->extra_height));
arg_resizing arg;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.width = size_before.width;
arg.height = size_before.height;
@ -1306,7 +1286,7 @@ namespace detail
//Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
::nana::rectangle update_area(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
if (!update_area.empty())
msgwnd->drawer.map(reinterpret_cast<window>(msgwnd), true, &update_area);
msgwnd->drawer.map(msgwnd, true, &update_area);
}
::EndPaint(root_window, &ps);
}
@ -1321,7 +1301,7 @@ namespace detail
arg.evt_code = event_code::shortkey;
arg.key = static_cast<wchar_t>(wParam < 0x61 ? wParam + 0x61 - 0x41 : wParam);
arg.ctrl = arg.shift = false;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.ignore = false;
brock.emit(event_code::shortkey, msgwnd, arg, true, &context);
def_window_proc = false;
@ -1337,7 +1317,7 @@ namespace detail
bool focused = (brock.focus() == msgwnd);
arg_keyboard arg;
arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.ignore = false;
arg.key = static_cast<wchar_t>(wParam);
brock.get_key_state(arg);
@ -1365,7 +1345,7 @@ namespace detail
arg_keyboard arg;
arg.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.ignore = false;
arg.key = static_cast<wchar_t>(wParam);
brock.get_key_state(arg);
@ -1407,7 +1387,7 @@ namespace detail
else if ((VK_SPACE == wParam) && msgwnd->flags.space_click_enabled)
{
//Clicked by spacebar
if (nullptr == pressed_wd && nullptr == pressed_wd_space)
if ((nullptr == pressed_wd) && (nullptr == pressed_wd_space) && msgwnd->flags.enabled)
{
arg_mouse arg;
arg.alt = false;
@ -1418,7 +1398,7 @@ namespace detail
arg.mid_button = false;
arg.pos.x = 0;
arg.pos.y = 0;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
msgwnd->set_action(mouse_action::pressed);
@ -1433,7 +1413,7 @@ namespace detail
{
arg_keyboard arg;
arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.ignore = false;
arg.key = translate_virtual_key(wParam);
brock.get_key_state(arg);
@ -1464,12 +1444,12 @@ namespace detail
{
arg_keyboard arg;
arg.evt_code = event_code::key_char;
arg.window_handle = reinterpret_cast<window>(msgwnd);
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, reinterpret_cast<window>(msgwnd));
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);
@ -1489,7 +1469,7 @@ namespace detail
msgwnd = brock.focus();
if (msgwnd)
{
if (msgwnd == pressed_wd_space)
if ((msgwnd == pressed_wd_space) && msgwnd->flags.enabled)
{
msgwnd->set_action(mouse_action::normal);
@ -1497,7 +1477,7 @@ namespace detail
arg_click click_arg;
click_arg.mouse_args = nullptr;
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
click_arg.window_handle = msgwnd;
arg_mouse arg;
arg.alt = false;
@ -1508,7 +1488,7 @@ namespace detail
arg.mid_button = false;
arg.pos.x = 0;
arg.pos.y = 0;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
draw_invoker(&drawer::mouse_up, msgwnd, arg, &context);
@ -1521,7 +1501,7 @@ namespace detail
{
arg_keyboard keyboard_arg;
keyboard_arg.evt_code = event_code::key_release;
keyboard_arg.window_handle = reinterpret_cast<window>(msgwnd);
keyboard_arg.window_handle = msgwnd;
keyboard_arg.key = translate_virtual_key(wParam);
brock.get_key_state(keyboard_arg);
keyboard_arg.ignore = false;
@ -1542,7 +1522,7 @@ namespace detail
case WM_CLOSE:
{
arg_unload arg;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.window_handle = msgwnd;
arg.cancel = false;
brock.emit(event_code::unload, msgwnd, arg, true, &context);
if (!arg.cancel)
@ -1577,14 +1557,7 @@ namespace detail
def_window_proc = true;
}
if (wd_manager.available(root_wd) && root_wd->other.attribute.root->update_requesters.size())
{
for (auto wd : root_wd->other.attribute.root->update_requesters)
{
window_layout::paint(wd, window_layout::paint_operation::have_refreshed, false);
wd_manager.map(wd, true);
}
}
wd_manager.update_requesters(root_wd);
root_runtime = wd_manager.root_runtime(native_window);
if(root_runtime)
@ -1666,7 +1639,7 @@ namespace detail
return impl_->estore;
}
void bedrock::map_through_widgets(core_window_t* wd, native_drawable_type drawable)
void bedrock::map_through_widgets(basic_window* wd, native_drawable_type drawable)
{
auto graph_context = reinterpret_cast<HDC>(wd->root_graph->handle()->context);
@ -1713,7 +1686,7 @@ namespace detail
}
//Dynamically set a cursor for a window
void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd)
void bedrock::set_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd)
{
if (nullptr == thrd)
thrd = get_thread_context(wd->thread_id);
@ -1758,7 +1731,7 @@ namespace detail
}
}
void bedrock::define_state_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd)
void bedrock::define_state_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd)
{
wd->root_widget->other.attribute.root->state_cursor = cur;
wd->root_widget->other.attribute.root->state_cursor_window = wd;
@ -1768,11 +1741,8 @@ namespace detail
::ShowCursor(TRUE);
}
void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd)
void bedrock::undefine_state_cursor(basic_window * wd, thread_context* thrd)
{
if (nullptr == thrd)
thrd = get_thread_context(wd->thread_id);
HCURSOR rev_handle = ::LoadCursor(nullptr, IDC_ARROW);
if (!wd_manager().available(wd))
{
@ -1781,6 +1751,9 @@ namespace detail
return;
}
if (nullptr == thrd)
thrd = get_thread_context(wd->thread_id);
wd->root_widget->other.attribute.root->state_cursor = nana::cursor::arrow;
wd->root_widget->other.attribute.root->state_cursor_window = nullptr;

View File

@ -1,7 +1,7 @@
/*
* A Drawer Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -10,11 +10,11 @@
* @file: nana/gui/detail/drawer.cpp
*/
#include "basic_window.hpp"
#include "effects_renderer.hpp"
#include <nana/config.hpp>
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/drawer.hpp>
#include <nana/gui/detail/effects_renderer.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include "dynamic_drawing_object.hpp"
#if defined(NANA_X11)
@ -23,8 +23,6 @@
namespace nana
{
typedef detail::edge_nimbus_renderer<detail::bedrock::core_window_t> edge_nimbus_renderer_t;
//class drawer_trigger
void drawer_trigger::attached(widget_reference, graph_reference){}
void drawer_trigger::detached(){} //none-const
@ -344,8 +342,7 @@ namespace nana
{
if(wd)
{
auto iwd = reinterpret_cast<bedrock_type::core_window_t*>(wd);
bool owns_caret = (iwd->annex.caret_ptr) && (iwd->annex.caret_ptr->visible());
bool owns_caret = (wd->annex.caret_ptr) && (wd->annex.caret_ptr->visible());
//The caret in X11 is implemented by Nana, it is different from Windows'
//the caret in X11 is asynchronous, it is hard to hide and show the caret
@ -354,20 +351,20 @@ namespace nana
if(owns_caret)
{
#ifndef NANA_X11
iwd->annex.caret_ptr->visible(false);
wd->annex.caret_ptr->visible(false);
#else
owns_caret = nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, false);
owns_caret = nana::detail::platform_spec::instance().caret_update(wd->root, *wd->root_graph, false);
#endif
}
edge_nimbus_renderer_t::instance().render(iwd, forced, update_area);
edge_nimbus_renderer::instance().render(wd, forced, update_area);
if(owns_caret)
{
#ifndef NANA_X11
iwd->annex.caret_ptr->visible(true);
wd->annex.caret_ptr->visible(true);
#else
nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, true);
nana::detail::platform_spec::instance().caret_update(wd->root, *wd->root_graph, true);
#endif
}
}
@ -475,4 +472,192 @@ namespace nana
return data_impl_->mth_state[pos];
}
}//end namespace detail
namespace detail
{
//class edge_nimbus_renderer
edge_nimbus_renderer& edge_nimbus_renderer::instance()
{
static edge_nimbus_renderer object;
return object;
}
void edge_nimbus_renderer::erase(basic_window* wd)
{
if (effects::edge_nimbus::none == wd->effect.edge_nimbus)
return;
auto root_wd = wd->root_widget;
auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
for (auto i = nimbus.begin(); i != nimbus.end(); ++i)
{
if (i->window == wd)
{
auto pixels = weight();
rectangle r{ wd->pos_root, wd->dimension };
r.x -= static_cast<int>(pixels);
r.y -= static_cast<int>(pixels);
r.width += static_cast<unsigned>(pixels << 1);
r.height += static_cast<unsigned>(pixels << 1);
root_wd->root_graph->paste(root_wd->root, r, r.x, r.y);
nimbus.erase(i);
break;
}
}
}
void edge_nimbus_renderer::render(basic_window* wd, bool forced, const rectangle* update_area)
{
bool copy_separately = true;
std::vector<std::pair<rectangle, basic_window*>> rd_set;
if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size())
{
auto root_wd = wd->root_widget;
auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
auto focused = root_wd->other.attribute.root->focus;
const unsigned pixels = weight();
auto graph = root_wd->root_graph;
nana::rectangle r;
for (auto & action : nimbus)
{
if (_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r))
{
if (action.window == wd)
{
if (update_area)
::nana::overlap(*update_area, rectangle(r), r);
copy_separately = false;
}
//Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered.
if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == basic_window::update_state::refreshed))
{
rd_set.emplace_back(r, action.window);
action.rendered = true;
}
}
else if (action.rendered)
{
action.rendered = false;
if (action.window == wd)
copy_separately = false;
::nana::rectangle erase_r(
action.window->pos_root.x - static_cast<int>(pixels),
action.window->pos_root.y - static_cast<int>(pixels),
static_cast<unsigned>(action.window->dimension.width + (pixels << 1)),
static_cast<unsigned>(action.window->dimension.height + (pixels << 1))
);
graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y);
}
}
}
if (copy_separately)
{
rectangle vr;
if (window_layer::read_visual_rectangle(wd, vr))
{
if (update_area)
::nana::overlap(*update_area, rectangle(vr), vr);
wd->root_graph->paste(wd->root, vr, vr.x, vr.y);
}
}
rectangle wd_r{ wd->pos_root, wd->dimension };
wd_r.pare_off(-static_cast<int>(this->weight()));
//Render
for (auto & rd : rd_set)
{
auto other_wd = rd.second;
if (other_wd != wd)
{
rectangle other_r{ other_wd->pos_root, other_wd->dimension };
other_r.pare_off(-static_cast<int>(this->weight()));
if (!overlapped(wd_r, other_r))
continue;
}
_m_render_edge_nimbus(other_wd, rd.first);
}
}
/// Determines whether the effect will be rendered for the given window.
bool edge_nimbus_renderer::_m_edge_nimbus(basic_window * const wd, basic_window * const focused_wd)
{
// Don't render the effect if the window is disabled.
if (wd->flags.enabled)
{
if ((focused_wd == wd) && (static_cast<unsigned>(wd->effect.edge_nimbus) & static_cast<unsigned>(effects::edge_nimbus::active)))
return true;
else if ((static_cast<unsigned>(wd->effect.edge_nimbus) & static_cast<unsigned>(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered))
return true;
}
return false;
}
void edge_nimbus_renderer::_m_render_edge_nimbus(basic_window* wd, const nana::rectangle & visual)
{
wd->flags.action_before = wd->flags.action;
auto r = visual;
r.pare_off(-static_cast<int>(weight()));
rectangle good_r;
if (overlap(r, rectangle{ wd->root_graph->size() }, good_r))
{
if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) ||
(good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom()))
{
auto graph = wd->root_graph;
nana::paint::pixel_buffer pixbuf(graph->handle(), r);
pixel_argb_t px0, px1, px2, px3;
px0 = pixbuf.pixel(0, 0);
px1 = pixbuf.pixel(r.width - 1, 0);
px2 = pixbuf.pixel(0, r.height - 1);
px3 = pixbuf.pixel(r.width - 1, r.height - 1);
good_r.x = good_r.y = 1;
good_r.width = r.width - 2;
good_r.height = r.height - 2;
pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.95, false);
good_r.x = good_r.y = 0;
good_r.width = r.width;
good_r.height = r.height;
pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.4, false);
pixbuf.pixel(0, 0, px0);
pixbuf.pixel(r.width - 1, 0, px1);
pixbuf.pixel(0, r.height - 1, px2);
pixbuf.pixel(r.width - 1, r.height - 1, px3);
pixbuf.paste(wd->root, { r.x, r.y });
std::vector<typename window_layer::wd_rectangle> overlaps;
if (window_layer::read_overlaps(wd, visual, overlaps))
{
for (auto & wdr : overlaps)
graph->paste(wd->root, wdr.r, wdr.r.x, wdr.r.y);
}
}
else
wd->root_graph->paste(wd->root, visual, visual.x, visual.y);
}
}
//end class edge_nimbus_renderer
}//end namespace detail
}//end namespace nana

View File

@ -0,0 +1,52 @@
/*
* Effects Renderer
* Nana C++ Library(http://www.nanapro.org)
* 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/detail/effects_renderer.cpp
*/
#ifndef NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP
#define NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP
#include "basic_window.hpp"
#include <nana/gui/effects.hpp>
#include <nana/paint/graphics.hpp>
#include <nana/paint/pixel_buffer.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/window_layout.hpp>
namespace nana{
namespace detail
{
/// Effect edige nimbus renderer
class edge_nimbus_renderer
{
edge_nimbus_renderer() = default;
public:
using window_layer = ::nana::detail::window_layout;
using graph_reference = ::nana::paint::graphics&;
static edge_nimbus_renderer& instance();
constexpr unsigned weight() const
{
return 2;
}
void erase(basic_window* wd);
void render(basic_window* wd, bool forced, const rectangle* update_area = nullptr);
private:
/// Determines whether the effect will be rendered for the given window.
static bool _m_edge_nimbus(basic_window * const wd, basic_window * const focused_wd);
void _m_render_edge_nimbus(basic_window* wd, const nana::rectangle & visual);
};
}
}//end namespace nana
#endif

View File

@ -26,9 +26,7 @@ namespace nana
auto i = handles_.find(evt);
if (i != handles_.end())
{
reinterpret_cast<detail::docker_interface*>(evt)->get_event()->remove(evt);
}
reinterpret_cast<detail::event_docker_interface*>(evt)->get_event()->remove(evt);
}
//end namespace events_operation
@ -80,35 +78,33 @@ namespace nana
void event_base::remove(event_handle evt)
{
internal_scope_guard lock;
if (dockers_)
for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i)
{
for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i)
if (reinterpret_cast<detail::event_docker_interface*>(evt) == *i)
{
if (reinterpret_cast<detail::docker_interface*>(evt) == *i)
//Checks whether this event is working now.
if (emitting_count_)
{
//Checks whether this event is working now.
if (emitting_count_)
{
static_cast<docker_base*>(*i)->flag_deleted = true;
deleted_flags_ = true;
}
else
{
bedrock::instance().evt_operation().cancel(evt);
dockers_->erase(i);
delete reinterpret_cast<detail::docker_interface*>(evt);
}
break;
static_cast<docker_base*>(*i)->flag_deleted = true;
deleted_flags_ = true;
}
else
{
bedrock::instance().evt_operation().cancel(evt);
dockers_->erase(i);
delete reinterpret_cast<detail::event_docker_interface*>(evt);
}
return;
}
}
}
event_handle event_base::_m_emplace(detail::docker_interface* docker_ptr, bool in_front)
event_handle event_base::_m_emplace(detail::event_docker_interface* docker_ptr, bool in_front)
{
internal_scope_guard lock;
if (nullptr == dockers_)
dockers_ = new std::vector<detail::docker_interface*>;
dockers_ = new std::vector<detail::event_docker_interface*>;
auto evt = reinterpret_cast<event_handle>(docker_ptr);

View File

@ -15,8 +15,8 @@
#define NANA_GUI_INNER_FWD_IMPLEMENT_HPP
#include <nana/push_ignore_diagnostic>
#include "basic_window.hpp"
#include <nana/gui/detail/inner_fwd.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include <nana/paint/graphics.hpp>
#include <map>

View File

@ -11,8 +11,8 @@
*
*/
#include "basic_window.hpp"
#include <nana/gui/detail/window_layout.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp>
#include <algorithm>
@ -22,7 +22,7 @@ namespace nana
namespace detail
{
//class window_layout
void window_layout::paint(core_window_t* wd, paint_operation operation, bool req_refresh_children)
void window_layout::paint(basic_window* wd, paint_operation operation, bool req_refresh_children)
{
if (wd->flags.refreshing && (paint_operation::try_refresh == operation))
return;
@ -41,7 +41,7 @@ namespace nana
_m_paint_glass_window(wd, (paint_operation::try_refresh == operation), req_refresh_children, false, true);
}
bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool req_refresh_children)
bool window_layout::maproot(basic_window* wd, bool have_refreshed, bool req_refresh_children)
{
auto check_opaque = wd->seek_non_lite_widget_ancestor();
if (check_opaque && check_opaque->flags.refreshing)
@ -80,7 +80,7 @@ namespace nana
return false;
}
void window_layout::paste_children_to_graphics(core_window_t* wd, nana::paint::graphics& graph)
void window_layout::paste_children_to_graphics(basic_window* wd, nana::paint::graphics& graph)
{
_m_paste_children(wd, false, false, rectangle{ wd->pos_root, wd->dimension }, graph, wd->pos_root);
}
@ -89,7 +89,7 @@ namespace nana
///@brief Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget,
/// the visual rectangle is a rectangular block that a window should be displayed on screen.
/// The result is a rectangle that is a visible area for its ancestors.
bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual)
bool window_layout::read_visual_rectangle(basic_window* wd, nana::rectangle& visual)
{
if (! wd->displayed()) return false;
@ -139,7 +139,7 @@ namespace nana
//read_overlaps
// reads the overlaps that are overlapped a rectangular block
bool window_layout::read_overlaps(core_window_t* wd, const nana::rectangle& vis_rect, std::vector<wd_rectangle>& blocks)
bool window_layout::read_overlaps(basic_window* wd, const nana::rectangle& vis_rect, std::vector<wd_rectangle>& blocks)
{
auto const is_wd_root = (category::flags::root == wd->other.category);
wd_rectangle block;
@ -150,7 +150,7 @@ namespace nana
{
for (++i; i != wd->parent->children.cend(); ++i)
{
core_window_t* cover = *i;
basic_window* cover = *i;
if (!cover->visible)
continue;
@ -182,7 +182,7 @@ namespace nana
return (!blocks.empty());
}
bool window_layout::enable_effects_bground(core_window_t * wd, bool enabled)
bool window_layout::enable_effects_bground(basic_window * wd, bool enabled)
{
if (category::flags::widget != wd->other.category)
return false;
@ -220,15 +220,15 @@ namespace nana
//make_bground
// update the glass buffer of a glass window.
void window_layout::make_bground(core_window_t* const wd)
void window_layout::make_bground(basic_window* const wd)
{
nana::point rpos{ wd->pos_root };
auto & glass_buffer = wd->other.glass_buffer;
if (category::flags::lite_widget == wd->parent->other.category)
{
std::vector<core_window_t*> layers;
core_window_t * beg = wd->parent;
std::vector<basic_window*> layers;
auto beg = wd->parent;
while (beg && (category::flags::lite_widget == beg->other.category))
{
layers.push_back(beg);
@ -240,11 +240,11 @@ namespace nana
nana::rectangle r(wd->pos_owner, wd->dimension);
for (auto i = layers.rbegin(), layers_rend = layers.rend(); i != layers_rend; ++i)
{
core_window_t * pre = *i;
auto pre = *i;
if (false == pre->visible)
continue;
core_window_t * term = ((i + 1 != layers_rend) ? *(i + 1) : wd);
auto term = ((i + 1 != layers_rend) ? *(i + 1) : wd);
r.position(wd->pos_root - pre->pos_root);
for (auto child : pre->children)
@ -286,10 +286,10 @@ namespace nana
}
if (wd->effect.bground)
wd->effect.bground->take_effect(reinterpret_cast<window>(wd), glass_buffer);
wd->effect.bground->take_effect(wd, glass_buffer);
}
void window_layout::_m_paste_children(core_window_t* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos)
void window_layout::_m_paste_children(basic_window* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos)
{
nana::rectangle rect;
for (auto child : wd->children)
@ -333,7 +333,7 @@ namespace nana
}
}
void window_layout::_m_paint_glass_window(core_window_t* wd, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other)
void window_layout::_m_paint_glass_window(basic_window* wd, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other)
{
//A window which has an empty graphics(and lite-widget) does not notify
//glass windows for updating their background.
@ -381,7 +381,7 @@ namespace nana
/// Notify the glass windows that are overlapped with the specified visual rectangle.
/// If a child window of sigwd is a glass window, it doesn't to be notified.
void window_layout::_m_notify_glasses(core_window_t* const sigwd)
void window_layout::_m_notify_glasses(basic_window* const sigwd)
{
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
for (auto wd : data_sect.effects_bground_windows)
@ -420,7 +420,7 @@ namespace nana
else
{
//test if sigwnd is a parent of glass window x, or a slibing of the glass window, or a child of the slibing of the glass window.
core_window_t *p = wd->parent, *signode = sigwd;
basic_window *p = wd->parent, *signode = sigwd;
while (signode->parent && (signode->parent != p))
signode = signode->parent;

View File

@ -18,7 +18,8 @@
#include <nana/gui/detail/window_layout.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/effects_renderer.hpp>
#include "effects_renderer.hpp"
#include "window_register.hpp"
#include "inner_fwd_implement.hpp"
@ -281,7 +282,7 @@ namespace detail
paint::image default_icon_big;
paint::image default_icon_small;
lite_map<core_window_t*, std::vector<std::function<void()>>> safe_place;
lite_map<basic_window*, std::vector<std::function<void()>>> safe_place;
};
//end struct wdm_private_impl
@ -454,7 +455,7 @@ namespace detail
delete impl_;
}
std::size_t window_manager::number_of_core_window() const
std::size_t window_manager::window_count() const
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -467,14 +468,14 @@ namespace detail
return mutex_;
}
void window_manager::all_handles(std::vector<core_window_t*> &v) const
void window_manager::all_handles(std::vector<basic_window*> &v) const
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
v = impl_->wd_register.queue();
}
void window_manager::event_filter(core_window_t* wd, bool is_make, event_code evtid)
void window_manager::event_filter(basic_window* wd, bool is_make, event_code evtid)
{
switch(evtid)
{
@ -486,21 +487,21 @@ namespace detail
}
}
bool window_manager::available(core_window_t* wd)
bool window_manager::available(basic_window* wd)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
return impl_->wd_register.available(wd);
}
bool window_manager::available(core_window_t * a, core_window_t* b)
bool window_manager::available(basic_window * a, basic_window* b)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
return (impl_->wd_register.available(a) && impl_->wd_register.available(b));
}
window_manager::core_window_t* window_manager::create_root(core_window_t* owner, bool nested, rectangle r, const appearance& app, widget* wdg)
basic_window* window_manager::create_root(basic_window* owner, bool nested, rectangle r, const appearance& app, widget* wdg)
{
native_window_type native = nullptr;
if (owner)
@ -524,7 +525,7 @@ namespace detail
auto result = native_interface::create_window(native, nested, r, app);
if (result.native_handle)
{
auto wd = new core_window_t(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr);
auto wd = new basic_window(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr);
if (nested)
{
wd->owner = nullptr;
@ -552,7 +553,7 @@ namespace detail
return nullptr;
}
window_manager::core_window_t* window_manager::create_widget(core_window_t* parent, const rectangle& r, bool is_lite, widget* wdg)
basic_window* window_manager::create_widget(basic_window* parent, const rectangle& r, bool is_lite, widget* wdg)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -564,17 +565,17 @@ namespace detail
auto wdg_notifier = widget_notifier_interface::get_notifier(wdg);
core_window_t * wd;
basic_window * wd;
if (is_lite)
wd = new core_window_t(parent, std::move(wdg_notifier), r, (category::lite_widget_tag**)nullptr);
wd = new basic_window(parent, std::move(wdg_notifier), r, (category::lite_widget_tag**)nullptr);
else
wd = new core_window_t(parent, std::move(wdg_notifier), r, (category::widget_tag**)nullptr);
wd = new basic_window(parent, std::move(wdg_notifier), r, (category::widget_tag**)nullptr);
impl_->wd_register.insert(wd);
return wd;
}
void window_manager::close(core_window_t *wd)
void window_manager::close(basic_window *wd)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -587,7 +588,7 @@ namespace detail
{
auto &brock = bedrock::instance();
arg_unload arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.cancel = false;
brock.emit(event_code::unload, wd, arg, true, brock.get_thread_context());
if (false == arg.cancel)
@ -616,7 +617,7 @@ namespace detail
//destroy
//@brief: Delete the window handle
void window_manager::destroy(core_window_t* wd)
void window_manager::destroy(basic_window* wd)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -640,7 +641,7 @@ namespace detail
update(parent, false, false, &update_area);
}
void window_manager::destroy_handle(core_window_t* wd)
void window_manager::destroy_handle(basic_window* wd)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -653,7 +654,7 @@ namespace detail
}
}
void window_manager::icon(core_window_t* wd, const paint::image& small_icon, const paint::image& big_icon)
void window_manager::icon(basic_window* wd, const paint::image& small_icon, const paint::image& big_icon)
{
if(!big_icon.empty() || !small_icon.empty())
{
@ -676,7 +677,7 @@ namespace detail
//show
//@brief: show or hide a window
bool window_manager::show(core_window_t* wd, bool visible)
bool window_manager::show(basic_window* wd, bool visible)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -701,7 +702,7 @@ namespace detail
return true;
}
window_manager::core_window_t* window_manager::find_window(native_window_type root, const point& pos, bool ignore_captured)
basic_window* window_manager::find_window(native_window_type root, const point& pos, bool ignore_captured)
{
if (nullptr == root)
return nullptr;
@ -739,7 +740,7 @@ namespace detail
}
//move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window
bool window_manager::move(core_window_t* wd, int x, int y, bool passive)
bool window_manager::move(basic_window* wd, int x, int y, bool passive)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -758,7 +759,7 @@ namespace detail
auto &brock = bedrock::instance();
arg_move arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.x = x;
arg.y = y;
@ -788,7 +789,7 @@ namespace detail
return false;
}
bool window_manager::move(core_window_t* wd, const rectangle& r)
bool window_manager::move(basic_window* wd, const rectangle& r)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -812,7 +813,7 @@ namespace detail
wd->other.upd_state = basic_window::update_state::request_refresh;
arg_move arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.x = r.x;
arg.y = r.y;
brock.emit(event_code::move, wd, arg, true, brock.get_thread_context());
@ -846,7 +847,7 @@ namespace detail
native_interface::move_window(wd->root, root_r);
arg_resized arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.width = root_r.width;
arg.height = root_r.height;
brock.emit(event_code::resized, wd, arg, true, brock.get_thread_context());
@ -864,7 +865,7 @@ namespace detail
// e.g, when the size of window is changed by OS/user, the function should not resize the
// window again, otherwise, it causes an infinite loop, because when a root_widget is resized,
// window_manager will call the function.
bool window_manager::size(core_window_t* wd, nana::size sz, bool passive, bool ask_update)
bool window_manager::size(basic_window* wd, nana::size sz, bool passive, bool ask_update)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -875,7 +876,7 @@ namespace detail
if (sz != wd->dimension)
{
arg_resizing arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.border = window_border::none;
arg.width = sz.width;
arg.height = sz.height;
@ -902,7 +903,7 @@ namespace detail
if (wd->dimension == sz)
return false;
std::vector<core_window_t*> presence;
std::vector<basic_window*> presence;
if (wd->dimension.width < sz.width || wd->dimension.height < sz.height)
{
@ -970,16 +971,16 @@ namespace detail
}
arg_resized arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.width = sz.width;
arg.height = sz.height;
brock.emit(event_code::resized, wd, arg, ask_update, brock.get_thread_context());
return true;
}
window_manager::core_window_t* window_manager::root(native_window_type wd) const
basic_window* window_manager::root(native_window_type wd) const
{
static std::pair<native_window_type, core_window_t*> cache;
static std::pair<native_window_type, basic_window*> cache;
if(cache.first == wd) return cache.second;
//Thread-Safe Required!
@ -996,7 +997,7 @@ namespace detail
}
//Copy the root buffer that wnd specified into DeviceContext
void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area)
void window_manager::map(basic_window* wd, bool forced, const rectangle* update_area)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1008,7 +1009,7 @@ namespace detail
//@brief: update is used for displaying the screen-off buffer.
// Because of a good efficiency, if it is called in an event procedure and the event procedure window is the
// same as update's, update would not map the screen-off buffer and just set the window for lazy refresh
bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area)
bool window_manager::update(basic_window* wd, bool redraw, bool forced, const rectangle* update_area)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1045,13 +1046,36 @@ namespace detail
else if (redraw)
window_layer::paint(wd, paint_operation::try_refresh, false);
if (wd->other.upd_state == core_window_t::update_state::lazy)
wd->other.upd_state = core_window_t::update_state::refreshed;
if (wd->other.upd_state == basic_window::update_state::lazy)
wd->other.upd_state = basic_window::update_state::refreshed;
}
return true;
}
void window_manager::refresh_tree(core_window_t* wd)
void window_manager::update_requesters(basic_window* root_wd)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if (this->available(root_wd) && root_wd->other.attribute.root->update_requesters.size())
{
for (auto wd : root_wd->other.attribute.root->update_requesters)
{
using paint_operation = window_layer::paint_operation;
if (!this->available(wd))
continue;
//#431
//Redraws the widget when it has beground effect.
//Because the widget just redraw if it didn't have bground effect when it was inserted to the update_requesters queue
window_layer::paint(wd, (wd->effect.bground ? paint_operation::try_refresh : paint_operation::have_refreshed), false);
this->map(wd, true);
}
}
}
void window_manager::refresh_tree(basic_window* wd)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1063,7 +1087,7 @@ namespace detail
//do_lazy_refresh
//@brief: defined a behavior of flush the screen
void window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree)
void window_manager::do_lazy_refresh(basic_window* wd, bool force_copy_to_screen, bool refresh_tree)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1077,11 +1101,11 @@ namespace detail
using paint_operation = window_layer::paint_operation;
if (wd->visible_parents())
{
if ((wd->other.upd_state == core_window_t::update_state::refreshed) || (wd->other.upd_state == core_window_t::update_state::request_refresh) || force_copy_to_screen)
if ((wd->other.upd_state == basic_window::update_state::refreshed) || (wd->other.upd_state == basic_window::update_state::request_refresh) || force_copy_to_screen)
{
if (!wd->try_lazy_update(wd->other.upd_state == core_window_t::update_state::request_refresh))
if (!wd->try_lazy_update(wd->other.upd_state == basic_window::update_state::request_refresh))
{
window_layer::paint(wd, (wd->other.upd_state == core_window_t::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree);
window_layer::paint(wd, (wd->other.upd_state == basic_window::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree);
this->map(wd, force_copy_to_screen);
}
}
@ -1100,10 +1124,10 @@ namespace detail
window_layer::paint(wd, paint_operation::try_refresh, refresh_tree); //only refreshing if it has an invisible parent
}
wd->other.upd_state = core_window_t::update_state::none;
wd->other.upd_state = basic_window::update_state::none;
}
bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa)
bool window_manager::set_parent(basic_window* wd, basic_window* newpa)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1130,7 +1154,7 @@ namespace detail
//set_focus
//@brief: set a keyboard focus to a window. this may fire a focus event.
window_manager::core_window_t* window_manager::set_focus(core_window_t* wd, bool root_has_been_focused, arg_focus::reason reason)
basic_window* window_manager::set_focus(basic_window* wd, bool root_has_been_focused, arg_focus::reason reason)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1154,7 +1178,7 @@ namespace detail
prev_focus->annex.caret_ptr->activate(false);
arg.getting = false;
arg.window_handle = reinterpret_cast<window>(prev_focus);
arg.window_handle = prev_focus;
arg.receiver = wd->root;
arg.focus_reason = arg_focus::reason::general;
brock.emit(event_code::focus, prev_focus, arg, true, brock.get_thread_context());
@ -1171,7 +1195,7 @@ namespace detail
if(wd->annex.caret_ptr)
wd->annex.caret_ptr->activate(true);
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
arg.getting = true;
arg.receiver = wd->root;
arg.focus_reason = reason;
@ -1194,7 +1218,7 @@ namespace detail
return prev_focus;
}
window_manager::core_window_t* window_manager::capture_redirect(core_window_t* wd)
basic_window* window_manager::capture_redirect(basic_window* wd)
{
if(attr_.capture.window && (attr_.capture.ignore_children == false) && (attr_.capture.window != wd))
{
@ -1221,12 +1245,12 @@ namespace detail
return false;
}
window_manager::core_window_t * window_manager::capture_window() const
basic_window * window_manager::capture_window() const
{
return attr_.capture.window;
}
void window_manager::capture_window(core_window_t* wd, bool captured, bool ignore_children)
void window_manager::capture_window(basic_window* wd, bool captured, bool ignore_children)
{
if (!this->available(wd))
return;
@ -1262,7 +1286,7 @@ namespace detail
wd->flags.captured = false;
if(attr_cap.size())
{
std::pair<core_window_t*, bool> last = attr_cap.back();
std::pair<basic_window*, bool> last = attr_cap.back();
attr_cap.pop_back();
if (impl_->wd_register.available(last.first))
@ -1297,7 +1321,7 @@ namespace detail
// this method insert a window which catches an user TAB into a TAB window container
// the TAB window container is held by a wd's root widget. Not every widget has a TAB window container,
// the container is created while a first Tab Window is setting
void window_manager::enable_tabstop(core_window_t* wd)
void window_manager::enable_tabstop(basic_window* wd)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1309,7 +1333,7 @@ namespace detail
}
// preconditions of get_tabstop: tabstop is not empty and at least one window is visible
window_manager::core_window_t* get_tabstop(window_manager::core_window_t* wd, bool forward)
basic_window* get_tabstop(basic_window* wd, bool forward)
{
auto & tabs = wd->root_widget->other.attribute.root->tabstop;
@ -1324,7 +1348,7 @@ namespace detail
if (i != end)
{
++i;
window_manager::core_window_t* ts = (i != end ? (*i) : tabs.front());
basic_window* ts = (i != end ? (*i) : tabs.front());
return (ts != wd ? ts : 0);
}
else
@ -1340,7 +1364,7 @@ namespace detail
return nullptr;
}
auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t*
auto window_manager::tabstop(basic_window* wd, bool forward) const -> basic_window*
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1384,7 +1408,7 @@ namespace detail
impl_->wd_register.delete_trash(tid);
}
bool window_manager::enable_effects_bground(core_window_t* wd, bool enabled)
bool window_manager::enable_effects_bground(basic_window* wd, bool enabled)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1394,7 +1418,7 @@ namespace detail
return false;
}
bool window_manager::calc_window_point(core_window_t* wd, nana::point& pos)
bool window_manager::calc_window_point(basic_window* wd, nana::point& pos)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1414,19 +1438,19 @@ namespace detail
return impl_->misc_register.find(native_wd);
}
bool window_manager::register_shortkey(core_window_t* wd, unsigned long key)
bool window_manager::register_shortkey(basic_window* wd, unsigned long key)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd))
{
//the root runtime must exist, because the wd is valid. Otherse, it's bug of library
return root_runtime(wd->root)->shortkeys.make(reinterpret_cast<window>(wd), key);
return root_runtime(wd->root)->shortkeys.make(wd, key);
}
return false;
}
void window_manager::unregister_shortkey(core_window_t* wd, bool with_children)
void window_manager::unregister_shortkey(basic_window* wd, bool with_children)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
@ -1435,7 +1459,7 @@ namespace detail
auto root_rt = root_runtime(wd->root);
if (root_rt)
{
root_rt->shortkeys.umake(reinterpret_cast<window>(wd));
root_rt->shortkeys.umake(wd);
if (with_children)
{
for (auto child : wd->children)
@ -1444,7 +1468,7 @@ namespace detail
}
}
window_manager::core_window_t* window_manager::find_shortkey(native_window_type native_window, unsigned long key)
basic_window* window_manager::find_shortkey(native_window_type native_window, unsigned long key)
{
if(native_window)
{
@ -1452,12 +1476,12 @@ namespace detail
std::lock_guard<mutex_type> lock(mutex_);
auto object = root_runtime(native_window);
if(object)
return reinterpret_cast<core_window_t*>(object->shortkeys.find(key));
return object->shortkeys.find(key);
}
return nullptr;
}
void window_manager::set_safe_place(core_window_t* wd, std::function<void()>&& fn)
void window_manager::set_safe_place(basic_window* wd, std::function<void()>&& fn)
{
if (fn)
{
@ -1499,7 +1523,7 @@ namespace detail
return false;
}
void window_manager::_m_disengage(core_window_t* wd, core_window_t* for_new)
void window_manager::_m_disengage(basic_window* wd, basic_window* for_new)
{
auto * const wdpa = wd->parent;
@ -1513,7 +1537,7 @@ namespace detail
//Holds the shortkeys of wd and its children, and then
//register these shortkeys for establishing.
std::vector<std::pair<core_window_t*,unsigned long>> sk_holder;
std::vector<std::pair<basic_window*,unsigned long>> sk_holder;
if ((!established) || (pa_root_attr != root_attr))
{
@ -1575,10 +1599,8 @@ namespace detail
if (!established)
{
using effect_renderer = detail::edge_nimbus_renderer<basic_window>;
//remove the window from edge nimbus effect when it is destroying
effect_renderer::instance().erase(wd);
edge_nimbus_renderer::instance().erase(wd);
}
else if (pa_root_attr != root_attr)
{
@ -1634,8 +1656,8 @@ namespace detail
auto delta_pos = wd->pos_root - for_new->pos_root;
std::function<void(core_window_t*, const nana::point&)> set_pos_root;
set_pos_root = [&set_pos_root](core_window_t* wd, const nana::point& delta_pos)
std::function<void(basic_window*, const nana::point&)> set_pos_root;
set_pos_root = [&set_pos_root](basic_window* wd, const nana::point& delta_pos)
{
for (auto child : wd->children)
{
@ -1666,7 +1688,7 @@ namespace detail
}
}
void window_manager::_m_destroy(core_window_t* wd)
void window_manager::_m_destroy(basic_window* wd)
{
if(wd->flags.destroying) return;
@ -1682,13 +1704,11 @@ namespace detail
wd->annex.caret_ptr = nullptr;
}
using effect_renderer = detail::edge_nimbus_renderer<basic_window>;
//remove the window from edge nimbus effect when it is destroying
effect_renderer::instance().erase(wd);
edge_nimbus_renderer::instance().erase(wd);
arg_destroy arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.window_handle = wd;
brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context());
//Delete the children widgets.
@ -1718,7 +1738,7 @@ namespace detail
wd->drawer.graphics.release();
}
void window_manager::_m_move_core(core_window_t* wd, const point& delta)
void window_manager::_m_move_core(basic_window* wd, const point& delta)
{
if(category::flags::root != wd->other.category) //A root widget always starts at (0, 0) and its children are not to be changed
{
@ -1740,14 +1760,14 @@ namespace detail
}
}
void window_manager::_m_shortkeys(core_window_t* wd, bool with_children, std::vector<std::pair<core_window_t*, unsigned long>>& keys) const
void window_manager::_m_shortkeys(basic_window* wd, bool with_children, std::vector<std::pair<basic_window*, unsigned long>>& keys) const
{
if (impl_->wd_register.available(wd))
{
//The root_rt must exist, because wd is valid. Otherwise, it's a bug of the library.
auto root_rt = root_runtime(wd->root);
auto pkeys = root_rt->shortkeys.keys(reinterpret_cast<window>(wd));
auto pkeys = root_rt->shortkeys.keys(wd);
if (pkeys)
{
for (auto key : *pkeys)
@ -1765,7 +1785,7 @@ namespace detail
//_m_find
//@brief: find a window on root window through a given root coordinate.
// the given root coordinate must be in the rectangle of wnd.
window_manager::core_window_t* window_manager::_m_find(core_window_t* wd, const point& pos)
basic_window* window_manager::_m_find(basic_window* wd, const point& pos)
{
if(!wd->visible)
return nullptr;
@ -1789,7 +1809,7 @@ namespace detail
}
//_m_effective, test if the window is a handle of window that specified by (root_x, root_y)
bool window_manager::_m_effective(core_window_t* wd, const point& root_pos)
bool window_manager::_m_effective(basic_window* wd, const point& root_pos)
{
if(wd == nullptr || false == wd->visible) return false;
return rectangle{ wd->pos_root, wd->dimension }.is_hit(root_pos);

View File

@ -1,7 +1,7 @@
#ifndef NANA_WINDOW_REGISTER_HEADER_INCLUDED
#define NANA_WINDOW_REGISTER_HEADER_INCLUDED
#include <nana/gui/detail/basic_window.hpp>
#include "basic_window.hpp"
#include <set>
#include <vector>
#include <algorithm> //std::find

View File

@ -1,7 +1,7 @@
/**
* Drag and Drop Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -13,9 +13,9 @@
#include <nana/gui/dragdrop.hpp>
#include <nana/gui/programming_interface.hpp>
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include "detail/basic_window.hpp"
#include <map>
#include <set>
@ -157,10 +157,16 @@ namespace nana
};
#ifdef NANA_WINDOWS
template<typename Interface, const IID& iid>
class win32com_iunknown : public Interface
class win32com_iunknown final: public Interface
{
public:
template<typename ...Args>
win32com_iunknown(Args&& ... args) :
Interface(std::forward<Args>(args)...)
{}
//Implements IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
@ -188,6 +194,7 @@ namespace nana
LONG ref_count_{ 1 };
};
class win32com_drop_target : public IDropTarget, public dragdrop_session
{
public:
@ -273,296 +280,300 @@ namespace nana
DWORD effect_{ DROPEFFECT_NONE };
};
class drop_source : public win32com_iunknown<IDropSource, IID_IDropSource>
class drop_source_impl : public IDropSource
{
public:
drop_source_impl(window wd) :
window_handle_(wd)
{}
window source() const
{
public:
drop_source(window wd) :
window_handle_(wd)
{}
window source() const
{
return window_handle_;
}
private:
// IDropSource
STDMETHODIMP QueryContinueDrag(BOOL esc_pressed, DWORD key_state) override
{
if (esc_pressed)
return DRAGDROP_S_CANCEL;
//Drop the object if left button is released.
if (0 == (key_state & (MK_LBUTTON)))
return DRAGDROP_S_DROP;
return S_OK;
}
STDMETHODIMP GiveFeedback(DWORD effect) override
{
return DRAGDROP_S_USEDEFAULTCURSORS;
}
private:
window const window_handle_;
};
class win32_dropdata : public win32com_iunknown<IDataObject, IID_IDataObject>
return window_handle_;
}
private:
// IDropSource
STDMETHODIMP QueryContinueDrag(BOOL esc_pressed, DWORD key_state) override
{
public:
struct data_entry
if (esc_pressed)
return DRAGDROP_S_CANCEL;
//Drop the object if left button is released.
if (0 == (key_state & (MK_LBUTTON)))
return DRAGDROP_S_DROP;
return S_OK;
}
STDMETHODIMP GiveFeedback(DWORD effect) override
{
return DRAGDROP_S_USEDEFAULTCURSORS;
}
private:
window const window_handle_;
};
using drop_source = win32com_iunknown<drop_source_impl, IID_IDropSource>;
class win32_dropdata_impl: public IDataObject
{
public:
struct data_entry
{
FORMATETC format;
STGMEDIUM medium;
bool read_from; //Indicates the data which is used for reading.
~data_entry()
{
FORMATETC format;
STGMEDIUM medium;
bool read_from; //Indicates the data which is used for reading.
::CoTaskMemFree(format.ptd);
::ReleaseStgMedium(&medium);
}
~data_entry()
{
::CoTaskMemFree(format.ptd);
::ReleaseStgMedium(&medium);
}
bool compare(const FORMATETC& fmt, bool rdfrom) const
{
return (format.cfFormat == fmt.cfFormat &&
(format.tymed & fmt.tymed) != 0 &&
(format.dwAspect == DVASPECT_THUMBNAIL || format.dwAspect == DVASPECT_ICON || medium.tymed == TYMED_NULL || format.lindex == fmt.lindex || (format.lindex == 0 && fmt.lindex == -1) || (format.lindex == -1 && fmt.lindex == 0)) &&
format.dwAspect == fmt.dwAspect && read_from == rdfrom);
}
bool compare(const FORMATETC& fmt, bool rdfrom) const
{
return (format.cfFormat == fmt.cfFormat &&
(format.tymed & fmt.tymed) != 0 &&
(format.dwAspect == DVASPECT_THUMBNAIL || format.dwAspect == DVASPECT_ICON || medium.tymed == TYMED_NULL || format.lindex == fmt.lindex || (format.lindex == 0 && fmt.lindex == -1) || (format.lindex == -1 && fmt.lindex == 0)) &&
format.dwAspect == fmt.dwAspect && read_from == rdfrom);
}
};
data_entry * find(const FORMATETC& fmt, bool read_from) const
data_entry * find(const FORMATETC& fmt, bool read_from) const
{
data_entry * last_weak_match = nullptr;
for (auto & entry : entries_)
{
data_entry * last_weak_match = nullptr;
for (auto & entry : entries_)
if (entry->compare(fmt, read_from))
{
if (entry->compare(fmt, read_from))
{
auto entry_ptd = entry->format.ptd;
if (entry_ptd && fmt.ptd && entry_ptd->tdSize == fmt.ptd->tdSize && (0 == std::memcmp(entry_ptd, fmt.ptd, fmt.ptd->tdSize)))
return entry.get();
else if (nullptr == entry_ptd && nullptr == fmt.ptd)
return entry.get();
auto entry_ptd = entry->format.ptd;
if (entry_ptd && fmt.ptd && entry_ptd->tdSize == fmt.ptd->tdSize && (0 == std::memcmp(entry_ptd, fmt.ptd, fmt.ptd->tdSize)))
return entry.get();
else if (nullptr == entry_ptd && nullptr == fmt.ptd)
return entry.get();
last_weak_match = entry.get();
}
}
return last_weak_match;
}
void assign(const detail::dragdrop_data& data)
{
if (!data.files.empty())
{
std::size_t bytes = sizeof(wchar_t);
for (auto & file : data.files)
{
auto file_s = file.wstring();
bytes += (file_s.size() + 1) * sizeof(file_s.front());
}
auto hglobal = ::GlobalAlloc(GHND | GMEM_SHARE, sizeof(DROPFILES) + bytes);
auto dropfiles = reinterpret_cast<DROPFILES*>(::GlobalLock(hglobal));
dropfiles->pFiles = sizeof(DROPFILES);
dropfiles->fWide = true;
auto file_buf = reinterpret_cast<char*>(dropfiles) + sizeof(DROPFILES);
for (auto & file : data.files)
{
auto file_s = file.wstring();
std::memcpy(file_buf, file_s.data(), (file_s.size() + 1) * sizeof(file_s.front()));
file_buf += (file_s.size() + 1) * sizeof(file_s.front());
}
*reinterpret_cast<wchar_t*>(file_buf) = 0;
::GlobalUnlock(hglobal);
assign(hglobal);
last_weak_match = entry.get();
}
}
return last_weak_match;
}
data_entry* assign(HGLOBAL hglobal)
void assign(const detail::dragdrop_data& data)
{
if (!data.files.empty())
{
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
auto entry = find(fmt, true);
if (entry)
std::size_t bytes = sizeof(wchar_t);
for (auto & file : data.files)
{
//Free the current entry for reuse
::CoTaskMemFree(entry->format.ptd);
::ReleaseStgMedium(&entry->medium);
}
else
{
//Create a new entry
entries_.emplace_back(new data_entry);
entry = entries_.back().get();
auto file_s = file.wstring();
bytes += (file_s.size() + 1) * sizeof(file_s.front());
}
//Assign the format to the entry.
entry->read_from = true;
entry->format = fmt;
auto hglobal = ::GlobalAlloc(GHND | GMEM_SHARE, sizeof(DROPFILES) + bytes);
//Assign the stgMedium
entry->medium.tymed = TYMED_HGLOBAL;
entry->medium.hGlobal = hglobal;
entry->medium.pUnkForRelease = nullptr;
auto dropfiles = reinterpret_cast<DROPFILES*>(::GlobalLock(hglobal));
dropfiles->pFiles = sizeof(DROPFILES);
dropfiles->fWide = true;
return entry;
}
public:
// Implement IDataObject
STDMETHODIMP GetData(FORMATETC *request_format, STGMEDIUM *pmedium) override
{
if (!(request_format && pmedium))
return E_INVALIDARG;
auto file_buf = reinterpret_cast<char*>(dropfiles)+sizeof(DROPFILES);
pmedium->hGlobal = nullptr;
auto entry = find(*request_format, true);
if (entry)
return _m_copy_medium(pmedium, &entry->medium, &entry->format);
return DV_E_FORMATETC;
}
STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) override
{
return E_NOTIMPL;
}
STDMETHODIMP QueryGetData(FORMATETC *pformatetc) override
{
if (NULL == pformatetc)
return E_INVALIDARG;
if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
return DV_E_DVASPECT;
HRESULT result = DV_E_TYMED;
for (auto & entry : entries_)
for (auto & file : data.files)
{
if (entry->format.tymed & pformatetc->tymed)
{
if (entry->format.cfFormat == pformatetc->cfFormat)
return S_OK;
result = DV_E_FORMATETC;
}
auto file_s = file.wstring();
std::memcpy(file_buf, file_s.data(), (file_s.size() + 1) * sizeof(file_s.front()));
file_buf += (file_s.size() + 1) * sizeof(file_s.front());
}
return result;
*reinterpret_cast<wchar_t*>(file_buf) = 0;
::GlobalUnlock(hglobal);
assign(hglobal);
}
}
STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) override
data_entry* assign(HGLOBAL hglobal)
{
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
auto entry = find(fmt, true);
if (entry)
{
return E_NOTIMPL;
//Free the current entry for reuse
::CoTaskMemFree(entry->format.ptd);
::ReleaseStgMedium(&entry->medium);
}
STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) override
else
{
if (!(pformatetc && pmedium))
return E_INVALIDARG;
if (pformatetc->tymed != pmedium->tymed)
return E_FAIL;
//Create a new entry
entries_.emplace_back(new data_entry);
auto entry = entries_.back().get();
entry->format = *pformatetc;
_m_copy_medium(&entry->medium, pmedium, pformatetc);
if (TRUE == fRelease)
::ReleaseStgMedium(pmedium);
return S_OK;
entry = entries_.back().get();
}
STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) override
//Assign the format to the entry.
entry->read_from = true;
entry->format = fmt;
//Assign the stgMedium
entry->medium.tymed = TYMED_HGLOBAL;
entry->medium.hGlobal = hglobal;
entry->medium.pUnkForRelease = nullptr;
return entry;
}
public:
// Implement IDataObject
STDMETHODIMP GetData(FORMATETC *request_format, STGMEDIUM *pmedium) override
{
if (!(request_format && pmedium))
return E_INVALIDARG;
pmedium->hGlobal = nullptr;
auto entry = find(*request_format, true);
if (entry)
return _m_copy_medium(pmedium, &entry->medium, &entry->format);
return DV_E_FORMATETC;
}
STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) override
{
return E_NOTIMPL;
}
STDMETHODIMP QueryGetData(FORMATETC *pformatetc) override
{
if (NULL == pformatetc)
return E_INVALIDARG;
if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
return DV_E_DVASPECT;
HRESULT result = DV_E_TYMED;
for (auto & entry : entries_)
{
if (NULL == ppenumFormatEtc)
if (entry->format.tymed & pformatetc->tymed)
{
if (entry->format.cfFormat == pformatetc->cfFormat)
return S_OK;
result = DV_E_FORMATETC;
}
}
return result;
}
STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) override
{
return E_NOTIMPL;
}
STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) override
{
if (!(pformatetc && pmedium))
return E_INVALIDARG;
if (pformatetc->tymed != pmedium->tymed)
return E_FAIL;
entries_.emplace_back(new data_entry);
auto entry = entries_.back().get();
entry->format = *pformatetc;
_m_copy_medium(&entry->medium, pmedium, pformatetc);
if (TRUE == fRelease)
::ReleaseStgMedium(pmedium);
return S_OK;
}
STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) override
{
if (NULL == ppenumFormatEtc)
return E_INVALIDARG;
if (DATADIR_GET != dwDirection)
return E_NOTIMPL;
*ppenumFormatEtc = nullptr;
FORMATETC rgfmtetc[] =
{
//{ CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL }
{ CF_HDROP, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL }
};
return ::SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc);
}
STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) override
{
return OLE_E_ADVISENOTSUPPORTED;
}
STDMETHODIMP DUnadvise(DWORD dwConnection) override
{
return OLE_E_ADVISENOTSUPPORTED;
}
STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise) override
{
return OLE_E_ADVISENOTSUPPORTED;
}
private:
static HRESULT _m_copy_medium(STGMEDIUM* stgmed_dst, STGMEDIUM* stgmed_src, FORMATETC* fmt_src)
{
if (!(stgmed_dst && stgmed_src && fmt_src))
return E_INVALIDARG;
switch (stgmed_src->tymed)
{
case TYMED_HGLOBAL:
stgmed_dst->hGlobal = (HGLOBAL)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0);
break;
case TYMED_GDI:
case TYMED_ENHMF:
//GDI object can't be copied to an existing HANDLE
if (stgmed_dst->hGlobal)
return E_INVALIDARG;
if (DATADIR_GET != dwDirection)
return E_NOTIMPL;
*ppenumFormatEtc = nullptr;
FORMATETC rgfmtetc[] =
{
//{ CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL }
{ CF_HDROP, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL }
};
return ::SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc);
stgmed_dst->hGlobal = (HBITMAP)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0);
break;
case TYMED_MFPICT:
stgmed_dst->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(stgmed_src->hMetaFilePict, fmt_src->cfFormat, 0);
break;
case TYMED_FILE:
stgmed_dst->lpszFileName = (LPOLESTR)OleDuplicateData(stgmed_src->lpszFileName, fmt_src->cfFormat, 0);
break;
case TYMED_ISTREAM:
stgmed_dst->pstm = stgmed_src->pstm;
stgmed_src->pstm->AddRef();
break;
case TYMED_ISTORAGE:
stgmed_dst->pstg = stgmed_src->pstg;
stgmed_src->pstg->AddRef();
break;
case TYMED_NULL:
default:
break;
}
STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) override
stgmed_dst->tymed = stgmed_src->tymed;
stgmed_dst->pUnkForRelease = nullptr;
if (stgmed_src->pUnkForRelease)
{
return OLE_E_ADVISENOTSUPPORTED;
stgmed_dst->pUnkForRelease = stgmed_src->pUnkForRelease;
stgmed_src->pUnkForRelease->AddRef();
}
STDMETHODIMP DUnadvise(DWORD dwConnection) override
{
return OLE_E_ADVISENOTSUPPORTED;
}
STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise) override
{
return OLE_E_ADVISENOTSUPPORTED;
}
private:
static HRESULT _m_copy_medium(STGMEDIUM* stgmed_dst, STGMEDIUM* stgmed_src, FORMATETC* fmt_src)
{
if (!(stgmed_dst && stgmed_src && fmt_src))
return E_INVALIDARG;
switch (stgmed_src->tymed)
{
case TYMED_HGLOBAL:
stgmed_dst->hGlobal = (HGLOBAL)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0);
break;
case TYMED_GDI:
case TYMED_ENHMF:
//GDI object can't be copied to an existing HANDLE
if (stgmed_dst->hGlobal)
return E_INVALIDARG;
stgmed_dst->hGlobal = (HBITMAP)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0);
break;
case TYMED_MFPICT:
stgmed_dst->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(stgmed_src->hMetaFilePict, fmt_src->cfFormat, 0);
break;
case TYMED_FILE:
stgmed_dst->lpszFileName = (LPOLESTR)OleDuplicateData(stgmed_src->lpszFileName, fmt_src->cfFormat, 0);
break;
case TYMED_ISTREAM:
stgmed_dst->pstm = stgmed_src->pstm;
stgmed_src->pstm->AddRef();
break;
case TYMED_ISTORAGE:
stgmed_dst->pstg = stgmed_src->pstg;
stgmed_src->pstg->AddRef();
break;
case TYMED_NULL:
default:
break;
}
stgmed_dst->tymed = stgmed_src->tymed;
stgmed_dst->pUnkForRelease = nullptr;
if (stgmed_src->pUnkForRelease)
{
stgmed_dst->pUnkForRelease = stgmed_src->pUnkForRelease;
stgmed_src->pUnkForRelease->AddRef();
}
return S_OK;
}
private:
std::vector<std::unique_ptr<data_entry>> entries_;
return S_OK;
}
private:
std::vector<std::unique_ptr<data_entry>> entries_;
};
using win32_dropdata = win32com_iunknown<win32_dropdata_impl, IID_IDataObject>;
#elif defined(NANA_X11)
class x11_dropdata
@ -710,7 +721,7 @@ namespace nana
i->second->set_current_source(drag_wd);
DWORD result_effect{ DROPEFFECT_NONE };
auto status = ::DoDragDrop(dropdata, drop_src, DROPEFFECT_COPY, &result_effect);
::DoDragDrop(dropdata, drop_src, DROPEFFECT_COPY, &result_effect);
i->second->set_current_source(nullptr);
@ -961,8 +972,7 @@ namespace nana
if (API::is_window(window_handle))
{
dragging = true;
auto real_wd = reinterpret_cast<detail::basic_window*>(window_handle);
real_wd->other.dnd_state = dragdrop_status::not_ready;
window_handle->other.dnd_state = dragdrop_status::not_ready;
}
API::release_capture(window_handle);
@ -1000,9 +1010,7 @@ namespace nana
if (arg.is_left_button() && API::is_window(impl_->window_handle))
{
impl_->dragging = ((!impl_->predicate) || impl_->predicate());
auto real_wd = reinterpret_cast<detail::basic_window*>(impl_->window_handle);
real_wd->other.dnd_state = dragdrop_status::ready;
impl_->window_handle->other.dnd_state = dragdrop_status::ready;
}
});
@ -1010,14 +1018,13 @@ namespace nana
if (!(arg.is_left_button() && impl_->dragging && API::is_window(arg.window_handle)))
return;
auto real_wd = reinterpret_cast<detail::basic_window*>(arg.window_handle);
real_wd->other.dnd_state = dragdrop_status::in_progress;
arg.window_handle->other.dnd_state = dragdrop_status::in_progress;
std::unique_ptr<dragdrop_service::dropdata_type> dropdata{new dragdrop_service::dropdata_type};
auto has_dropped = dragdrop_service::instance().dragdrop(arg.window_handle, dropdata.get(), nullptr);
real_wd->other.dnd_state = dragdrop_status::not_ready;
arg.window_handle->other.dnd_state = dragdrop_status::not_ready;
impl_->dragging = false;
if (has_dropped)
@ -1116,9 +1123,7 @@ namespace nana
if (arg.is_left_button() && API::is_window(impl_->source_handle))
{
impl_->dragging = ((!impl_->predicate) || impl_->predicate());
auto real_wd = reinterpret_cast<detail::basic_window*>(impl_->source_handle);
real_wd->other.dnd_state = dragdrop_status::ready;
impl_->source_handle->other.dnd_state = dragdrop_status::ready;
}
});
@ -1126,13 +1131,9 @@ namespace nana
if (!(arg.is_left_button() && impl_->dragging && API::is_window(arg.window_handle)))
return;
auto real_wd = reinterpret_cast<detail::basic_window*>(arg.window_handle);
real_wd->other.dnd_state = dragdrop_status::in_progress;
arg.window_handle->other.dnd_state = dragdrop_status::in_progress;
impl_->make_drop();
real_wd->other.dnd_state = dragdrop_status::not_ready;
arg.window_handle->other.dnd_state = dragdrop_status::not_ready;
impl_->dragging = false;
});
}

View File

@ -10,9 +10,9 @@
* @file: nana/gui/drawing.cpp
*/
#include "detail/basic_window.hpp"
#include <nana/gui/drawing.hpp>
#include <nana/gui/programming_interface.hpp>
#include <nana/gui/detail/basic_window.hpp>
namespace nana
{
@ -22,11 +22,9 @@ namespace nana
{
namespace
{
using core_window_t = detail::basic_window;
inline detail::drawer& get_drawer(window wd)
{
return reinterpret_cast<core_window_t*>(wd)->drawer;
return wd->drawer;
}
}
}
@ -38,7 +36,7 @@ namespace nana
if (!API::is_window(wd))
throw std::invalid_argument("drawing: invalid window parameter");
if (reinterpret_cast<restrict::core_window_t*>(wd)->is_draw_through())
if (wd->is_draw_through())
throw std::invalid_argument("drawing: the window is draw_through enabled");
}
@ -46,7 +44,7 @@ namespace nana
bool drawing::empty() const
{
return API::empty_window(handle_) || reinterpret_cast<restrict::core_window_t*>(handle_)->root_graph->empty();
return API::empty_window(handle_) || handle_->root_graph->empty();
}
void drawing::update() const

View File

@ -1062,6 +1062,8 @@ namespace nana
{
if(text.length() == start_pos)
return files;
else if(0 == start_pos) //single selection
return {text};
return {};
}

View File

@ -12,7 +12,10 @@
* James Bremner
*/
#include <nana/gui.hpp>
#include <nana/gui/compact.hpp>
#include <nana/gui/msgbox.hpp>
#include <nana/gui/drawing.hpp>
#include <nana/gui/widgets/form.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/spinbox.hpp>

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
/*
/**
* Parts of Class Place
* 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
* (See accompanying file LICENSE or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/place_parts.hpp
* @file nana/gui/place_parts.hpp
*/
#ifndef NANA_GUI_PLACE_PARTS_HPP
#define NANA_GUI_PLACE_PARTS_HPP
@ -126,6 +126,12 @@ namespace nana
{
close_fn_ = std::move(fn);
}
bool hit_close() const
{
return x_pointed_;
}
private:
virtual void attached(widget_reference wdg, graph_reference graph) override
{
@ -140,7 +146,7 @@ namespace nana
//draw caption
auto text = to_wstring(API::window_caption(window_handle_));
text_rd_->render({ 3, 1 }, text.data(), text.size(), graph.size().width - 20, true);
text_rd_->render({ 3, 1 }, text.data(), text.size(), graph.size().width - 20, paint::text_renderer::mode::truncate_with_ellipsis);
//draw x button
auto r = _m_button_area();
@ -310,7 +316,9 @@ namespace nana
{
move_pos += moves_.start_container_pos;
API::move_window(container_->handle(), move_pos);
notifier_->notify_move();
if(!caption_.get_drawer_trigger().hit_close())
notifier_->notify_move();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -9,18 +9,18 @@
*
* @file: nana/gui/state_cursor.cpp
*/
#include "detail/basic_window.hpp"
#include <nana/gui/state_cursor.hpp>
#include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/window_manager.hpp>
namespace nana
{
state_cursor::state_cursor(window handle, cursor cur)
: handle_(handle)
state_cursor::state_cursor(window wd, cursor cur)
: handle_(wd)
{
auto & brock = detail::bedrock::instance();
auto wd = reinterpret_cast<detail::basic_window*>(handle);
if (brock.wd_manager().available(wd))
brock.define_state_cursor(wd, cur, nullptr);
else
@ -39,10 +39,9 @@ namespace nana
{
if (handle_)
{
nana::internal_scope_guard lock;
auto & brock = detail::bedrock::instance();
auto wd = reinterpret_cast<detail::basic_window*>(handle_);
if (brock.wd_manager().available(wd))
brock.undefine_state_cursor(wd, nullptr);
brock.undefine_state_cursor(handle_, nullptr);
}
handle_ = rhs.handle_;
rhs.handle_ = nullptr;
@ -54,10 +53,9 @@ namespace nana
{
if (handle_)
{
nana::internal_scope_guard lock;
auto & brock = detail::bedrock::instance();
auto wd = reinterpret_cast<detail::basic_window*>(handle_);
if (brock.wd_manager().available(wd))
brock.undefine_state_cursor(wd, nullptr);
brock.undefine_state_cursor(handle_, nullptr);
}
}
}

View File

@ -28,24 +28,26 @@
#if defined(NANA_WINDOWS)
#include <windows.h>
#elif defined(NANA_POSIX)
#include "../detail/platform_spec_selector.hpp"
#include "../detail/posix/platform_spec.hpp"
#include <nana/system/platform.hpp>
#endif
namespace nana
{
class timer_core;
namespace detail
{
class timer_core;
}
#if defined(NANA_WINDOWS)
typedef UINT_PTR timer_identifier;
#else
typedef timer_core* timer_identifier;
typedef const detail::timer_core* timer_identifier;
#endif
class timer_driver
{
typedef std::lock_guard<std::recursive_mutex> lock_guard;
friend class timer_core;
friend class detail::timer_core;
timer_driver() = default;
public:
@ -56,7 +58,7 @@ namespace nana
}
template<typename Factory>
timer_core* create(unsigned ms, Factory && factory)
detail::timer_core* create(unsigned ms, Factory && factory)
{
#if defined(NANA_WINDOWS)
auto tmid = ::SetTimer(nullptr, 0, ms, &timer_driver::_m_timer_proc);
@ -68,9 +70,9 @@ namespace nana
#else
auto p = factory();
auto tmid = p;
::nana::detail::platform_spec::instance().set_timer(reinterpret_cast<std::size_t>(tmid), ms, &timer_driver::_m_timer_proc);
::nana::detail::platform_spec::instance().set_timer(tmid, ms, &timer_driver::_m_timer_proc);
#endif
lock_guard lock(mutex_);
::nana::internal_scope_guard lock;
timer_table_[tmid].reset(p);
return p;
}
@ -80,16 +82,17 @@ namespace nana
return nullptr;
}
void destroy(timer_identifier tid)
void destroy(timer_identifier handle)
{
lock_guard lock(mutex_);
auto i = timer_table_.find(tid);
::nana::internal_scope_guard lock;
auto i = timer_table_.find(handle);
if (i != timer_table_.end())
{
#if defined(NANA_WINDOWS)
::KillTimer(nullptr, tid);
::KillTimer(nullptr, handle);
#else
::nana::detail::platform_spec::instance().kill_timer(reinterpret_cast<std::size_t>(tid));
::nana::detail::platform_spec::instance().kill_timer(handle);
#endif
timer_table_.erase(i);
}
@ -98,23 +101,26 @@ namespace nana
#if defined(NANA_WINDOWS)
static void __stdcall _m_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime);
#else
static void _m_timer_proc(std::size_t id);
static void _m_timer_proc(timer_identifier id);
#endif
private:
std::recursive_mutex mutex_;
std::map<timer_identifier, std::unique_ptr<timer_core>> timer_table_;
std::map<timer_identifier, std::unique_ptr<detail::timer_core>> timer_table_;
};
class timer_core
class detail::timer_core
{
public:
#if defined(NANA_WINDOWS)
timer_core(timer_identifier tmid, basic_event<arg_elapse>& evt_elapse)
: timer_(tmid), evt_elapse_(evt_elapse)
timer_core(timer* sender, timer_identifier tmid, basic_event<arg_elapse>& evt_elapse):
sender_(sender),
timer_(tmid),
evt_elapse_(evt_elapse)
{}
#else
timer_core(basic_event<arg_elapse>& evt_elapse)
: timer_(this), evt_elapse_(evt_elapse)
timer_core(timer* sender, basic_event<arg_elapse>& evt_elapse):
sender_(sender),
timer_(this),
evt_elapse_(evt_elapse)
{}
#endif
@ -128,45 +134,44 @@ namespace nana
#if defined(NANA_WINDOWS)
::SetTimer(nullptr, timer_, ms, &timer_driver::_m_timer_proc);
#else
::nana::detail::platform_spec::instance().set_timer(reinterpret_cast<std::size_t>(timer_), ms, &timer_driver::_m_timer_proc);
::nana::detail::platform_spec::instance().set_timer(timer_, ms, &timer_driver::_m_timer_proc);
#endif
}
void emit(const arg_elapse& arg)
void emit()
{
arg_elapse arg;
arg.sender = sender_;
evt_elapse_.emit(arg, nullptr);
}
private:
timer * const sender_;
const timer_identifier timer_;
nana::basic_event<arg_elapse> & evt_elapse_;
}; //end class timer_core
#if defined(NANA_WINDOWS)
void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR id, DWORD /*dwTime*/)
void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR handle, DWORD /*dwTime*/)
#else
void timer_driver::_m_timer_proc(std::size_t id)
void timer_driver::_m_timer_proc(timer_identifier handle)
#endif
{
auto & driver = instance();
auto & time_tbl = instance().timer_table_;
lock_guard lock(driver.mutex_);
#if defined(NANA_WINDOWS)
auto i = driver.timer_table_.find(id);
#else
auto i = driver.timer_table_.find(reinterpret_cast<timer_identifier>(id));
#endif
if (i == driver.timer_table_.end())
::nana::internal_scope_guard lock;
auto i = time_tbl.find(handle);
if (i == time_tbl.end())
return;
arg_elapse arg;
arg.id = id;
i->second->emit(arg);
i->second->emit();
}
struct timer::implement
{
unsigned interval = 1000; //Defaultly 1 second.
timer_core * tm_core = nullptr;
unsigned interval{ 1000 }; //1 second in default
detail::timer_core * tm_core{ nullptr };
};
//class timer
@ -183,8 +188,7 @@ namespace nana
timer::~timer()
{
if (impl_->tm_core)
timer_driver::instance().destroy(impl_->tm_core->id());
stop();
delete impl_;
}
@ -201,12 +205,12 @@ namespace nana
#if defined(NANA_WINDOWS)
impl_->tm_core = timer_driver::instance().create(impl_->interval, [this](timer_identifier id)
{
return new timer_core(id, elapse_);
return new detail::timer_core(this, id, elapse_);
});
#else
impl_->tm_core = timer_driver::instance().create(impl_->interval, [this]
{
return new timer_core(elapse_);
return new detail::timer_core(this, elapse_);
});
#endif
}

View File

@ -261,7 +261,7 @@ namespace nana{ namespace drawerbase
graph.palette(true, text_color);
if (attr_.omitted)
tr.render(pos, txtptr, txtlen, omitted_pixels, true);
tr.render(pos, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis);
else
#ifdef _nana_std_has_string_view
graph.bidi_string(pos, { txtptr, txtlen });
@ -276,9 +276,9 @@ namespace nana{ namespace drawerbase
graph.palette(true, color{ colors::white });
if(attr_.omitted)
{
tr.render(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen, omitted_pixels, true);
tr.render(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis);
graph.palette(true, color{ colors::gray });
tr.render(pos, txtptr, txtlen, omitted_pixels, true);
tr.render(pos, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis);
}
else
{

View File

@ -1,16 +1,16 @@
/*
/**
* A Categorize Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/widgets/categorize.cpp
* @file nana/gui/widgets/categorize.cpp
*/
#include <nana/gui/wvl.hpp>
#include <nana/gui/compact.hpp>
#include <nana/gui/widgets/categorize.hpp>
#include <nana/gui/widgets/float_listbox.hpp>
#include <nana/gui/element.hpp>

View File

@ -70,13 +70,13 @@ namespace nana{ namespace drawerbase
if (!wdg->enabled())
{
graph.palette(true, colors::white);
tr.render({ 17 + interval, 2 }, title.c_str(), title.length(), pixels);
tr.render({ 17 + interval, 2 }, title.c_str(), title.length(), pixels, paint::text_renderer::mode::word_wrap);
graph.palette(true, static_cast<color_rgb>(0x808080));
}
else
graph.palette(true, wdg->fgcolor());
tr.render({ 16 + interval, 1 }, title.c_str(), title.length(), pixels);
tr.render({ 16 + interval, 1 }, title.c_str(), title.length(), pixels, paint::text_renderer::mode::word_wrap);
}
//draw crook

View File

@ -10,9 +10,9 @@
* @file: nana/gui/widgets/combox.cpp
*/
#include <nana/gui.hpp>
#include <nana/gui/widgets/combox.hpp>
#include <nana/gui/compact.hpp>
#include <nana/gui/element.hpp>
#include <nana/gui/widgets/combox.hpp>
#include <nana/system/dataexch.hpp>
#include <nana/gui/widgets/float_listbox.hpp>
#include <nana/gui/widgets/skeletons/text_editor.hpp>

View File

@ -1,19 +1,19 @@
/**
* A group widget implementation
* Nana C++ Library(http://www.nanaro.org)
* Copyright(C) 2015-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2015-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* (See accompanying file LICENSE or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/widgets/group.cpp
* @file nana/gui/widgets/group.cpp
*
* @Author: Stefan Pfeifer(st-321), Ariel Vina-Rodriguez (qPCR4vir)
* @author Stefan Pfeifer(st-321), Ariel Vina-Rodriguez (qPCR4vir)
*
* @brief group is a widget used to visually group and layout other widgets.
*
* @contributor:
* @contributor
* dankan1890(https://github.com/dankan1890)
*/

View File

@ -15,7 +15,7 @@
* Benjamin Navarro(pr#81)
* besh81(pr#130)
* dankan1890(pr#158)
* ErrorFlynn(pr#418)
* ErrorFlynn(pr#418,pr#448,pr#454)
*
*/
#include <algorithm>
@ -549,9 +549,9 @@ namespace nana
if (!front) view++;
if (view >= cont_.size() ) return;
auto i = std::find_if( cont_.begin(),
cont_.end(),
[&](const column& c){return col==c.index;});
auto i = std::find_if( cont_.begin(),
cont_.end(),
[&](const column& c){return col==c.index;});
if (i==cont_.end()) return;
@ -1199,23 +1199,15 @@ namespace nana
return{};
}
/// return a ref to the real item object at display!!! position pos using current sorting only if it is active, and at absolute position if no sorting is currently active.
/// return a ref to the real item object at display position
category_t::container::value_type& at(const index_pair& pos)
{
auto acc_pos = pos.item;
if (npos != sort_attrs_.column)
acc_pos = index_cast(pos, true).item; //convert display position to absolute position
return get(pos.cat)->items.at(acc_pos);
return get(pos.cat)->items.at(index_cast(pos, true).item);
}
const category_t::container::value_type& at(const index_pair& pos) const
{
auto acc_pos = pos.item;
if (npos != sort_attrs_.column)
acc_pos = index_cast(pos, true).item; //convert display position to absolute position
return get(pos.cat)->items.at(acc_pos);
return get(pos.cat)->items.at(index_cast(pos, true).item);
}
std::vector<cell> at_model(const index_pair& pos) const
@ -2019,6 +2011,8 @@ namespace nana
std::function<void(paint::graphics&, const rectangle&, bool)> ctg_icon_renderer; ///< Renderer for the category icon
std::function<bool(nana::mouse)> pred_msup_deselect;
struct operation_rep
{
operation_states state{operation_states::none};
@ -2065,6 +2059,11 @@ namespace nana
};
}
unsigned suspension_width() const
{
return (graph ? graph->text_extent_size(L"...").width : 0);
}
bool cs_status(index_pair abs_pos, bool for_selection) const
{
if (abs_pos.is_category())
@ -3358,7 +3357,7 @@ namespace nana
else
{
//Default scheme
new_w = (std::max)(new_w, essence_->scheme_ptr->suspension_width + essence_->scheme_ptr->min_column_width);
new_w = (std::max)(new_w, essence_->suspension_width() + essence_->scheme_ptr->min_column_width);
}
if(col.width_px != new_w)
@ -4003,6 +4002,7 @@ namespace nana
if (draw_column)
{
//Draw item text
paint::aligner text_aligner{*graph, col.alignment};
unsigned text_margin_right = 0;
@ -4148,7 +4148,6 @@ namespace nana
if (graph.text_metrics(as, ds, il))
essence_->text_height = as + ds;
essence_->scheme_ptr->suspension_width = graph.text_extent_size("...").width;
essence_->calc_content_size(true);
}
@ -4343,7 +4342,7 @@ namespace nana
else
{
auto selected = lister.pick_items(true);
if (selected.cend() != std::find(selected.cbegin(), selected.cend(), item_pos))
if (selected.cend() != std::find(selected.cbegin(), selected.cend(), abs_item_pos))
{
//If the current selected one has been selected before selecting, remains the selection states for all
//selected items. But these items will be unselected when the mouse is released.
@ -4359,6 +4358,8 @@ namespace nana
}
else
lister.select_for_all(false, abs_item_pos);
lister.latest_selected_abs = abs_item_pos;
}
}
else
@ -4474,11 +4475,14 @@ namespace nana
essence_->stop_mouse_selection();
need_refresh = true;
}
if (operation_states::msup_deselect == essence_->operation.state)
{
essence_->operation.state = operation_states::none;
need_refresh |= essence_->lister.select_for_all(false, essence_->operation.item);
//Don't deselect if the predicate returns false
if(!(essence_->pred_msup_deselect && !essence_->pred_msup_deselect(arg.button)))
need_refresh |= essence_->lister.select_for_all(false, essence_->operation.item);
}
if (need_refresh)
@ -6043,7 +6047,7 @@ namespace nana
return *this;
}
listbox& listbox::category_icon(const paint::image& img_expanded, const paint::image&& img_collapsed)
listbox& listbox::category_icon(const paint::image& img_expanded, const paint::image& img_collapsed)
{
internal_scope_guard lock;
_m_ess().ctg_icon_renderer = [img_expanded, img_collapsed](paint::graphics& graph, const rectangle& rt_icon, bool expanded)
@ -6110,6 +6114,17 @@ namespace nana
return indexes;
}
void listbox::set_deselect(std::function<bool(nana::mouse)> predicate)
{
_m_ess().pred_msup_deselect = std::move(predicate);
}
unsigned listbox::suspension_width() const
{
nana::internal_scope_guard lock;
return _m_ess().suspension_width();
}
drawerbase::listbox::essence & listbox::_m_ess() const
{
return get_drawer_trigger().ess();
@ -6193,7 +6208,7 @@ namespace nana
std::vector<size_type> new_idx;
for(size_type i=first_col; i<=last_col; ++i) new_idx.push_back(i);
internal_scope_guard lock;
auto ip_row = this->at(row);
auto pnany=_m_ess().lister.anyobj(row,false);

View File

@ -13,12 +13,13 @@
* dankan1890(pr#158)
*/
#include <nana/gui/compact.hpp>
#include <nana/gui/screen.hpp>
#include <nana/gui/widgets/menu.hpp>
#include <nana/gui/timer.hpp>
#include <nana/system/platform.hpp>
#include <nana/gui/element.hpp>
#include <nana/gui/wvl.hpp>
#include <nana/paint/text_renderer.hpp>
#include <cctype> //introduces tolower
#include <vector>
@ -147,7 +148,7 @@ namespace nana
nana::paint::text_renderer tr(graph);
auto wstr = to_wstring(text);
tr.render(pos, wstr.c_str(), wstr.length(), text_pixels, true);
tr.render(pos, wstr.c_str(), wstr.length(), text_pixels, paint::text_renderer::mode::truncate_with_ellipsis);
}
void sub_arrow(graph_reference graph, const nana::point& pos, unsigned pixels, const attr&)

View File

@ -1050,7 +1050,7 @@ namespace nana
std::wstring wtext = to_wstring(item.text);
tr.render({ m.r.x + 24, m.r.y + static_cast<int>(m.r.height - ts.height) / 2 },
wtext.c_str(), wtext.length(), basis_.item_pixels - 24 - 18, true);
wtext.c_str(), wtext.length(), basis_.item_pixels - 24 - 18, paint::text_renderer::mode::truncate_with_ellipsis);
}
}

View File

@ -27,26 +27,6 @@ namespace nana
{
namespace toolbar
{
struct item_type
{
enum kind{ button, container};
typedef std::size_t size_type;
std::string text;
nana::paint::image image;
unsigned pixels{0};
unsigned position{ 0 }; // last item position.
nana::size textsize;
bool enable{true};
kind type;
item_type(const std::string& text, const nana::paint::image& img, kind type)
:text(text), image(img), type(type)
{}
};
class item_container
{
public:
@ -58,7 +38,7 @@ namespace nana
clear();
}
void insert(size_type pos, std::string text, const nana::paint::image& img, item_type::kind type)
void insert(size_type pos, std::string text, const nana::paint::image& img, tool_type type)
{
item_type* m = new item_type(std::move(text), img, type);
@ -70,12 +50,12 @@ namespace nana
void push_back(const std::string& text, const nana::paint::image& img)
{
insert(cont_.size(), text, img, item_type::kind::button);
insert(cont_.size(), text, img, tool_type::button);
}
void push_back(const std::string& text)
{
insert(cont_.size(), text, nana::paint::image(), item_type::kind::button);
insert(cont_.size(), text, nana::paint::image(), tool_type::button);
}
//Contributed by kmribti(pr#105)
@ -126,6 +106,45 @@ namespace nana
cont_.clear();
}
void update_toggle_group(item_type* item, bool toggle_state, bool clicked = true)
{
if(!item)
return;
if(item->group.empty())
{
item->toggle = toggle_state;
return;
}
// group rules:
// 1. inside a group only one item at the time is selected
// 2. inside a group one item must always be selected
// 3. a group with only one item IS NOT a group
bool is_group = false;
// look for other items inside the group
for(auto i : cont_)
{
if(i == item)
continue;
if(i && i->group == item->group)
{
if(toggle_state == false && clicked == false) // needs to avoid to break rule no. 2
return;
is_group = true;
i->toggle = false;
}
}
item->toggle = is_group ? true : toggle_state;
}
private:
container_type cont_;
size_t right_{ npos };
@ -137,8 +156,8 @@ namespace nana
enum class state_t{normal, highlighted, selected};
const static unsigned extra_size = 6;
item_renderer(nana::paint::graphics& graph, bool textout, unsigned scale, const ::nana::color& bgcolor)
:graph(graph), textout(textout), scale(scale), bgcolor(bgcolor)
item_renderer(nana::paint::graphics& graph, unsigned scale, const ::nana::color& bgcolor, const ::nana::color& fgcolor)
:graph(graph), scale(scale), bgcolor(bgcolor), fgcolor(fgcolor)
{}
void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state)
@ -152,6 +171,13 @@ namespace nana
if (state_t::highlighted == state || state_t::selected == state)
graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast<color_rgb>(state_t::selected == state ? 0x99CCFF : 0xC0DDFC), true);
}
else if (item.type == tool_type::toggle && item.toggle)
{
nana::rectangle background_r(x, y, width, height);
graph.rectangle(background_r, false, static_cast<color_rgb>(item.enable ? 0x3399FF : 0x999999));
graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast<color_rgb>(item.enable ? 0xC0DDFC : 0x969696), true);
}
if(!item.image.empty())
{
@ -181,17 +207,17 @@ namespace nana
width -= scale;
}
if(textout)
if(item.textout)
{
graph.string({ x + static_cast<int>(width - item.textsize.width) / 2, y + static_cast<int>(height - item.textsize.height) / 2 }, item.text);
graph.string({ x + static_cast<int>(width - item.textsize.width) / 2, y + static_cast<int>(height - item.textsize.height) / 2 }, item.text, fgcolor );
}
}
protected:
nana::paint::graphics& graph;
bool textout;
unsigned scale;
::nana::color bgcolor;
::nana::color fgcolor;
};
struct drawer::drawer_impl_type
@ -200,7 +226,6 @@ namespace nana
paint::graphics* graph_ptr{ nullptr };
unsigned scale{16};
bool textout{false};
size_type which{npos};
item_renderer::state_t state{item_renderer::state_t::normal};
@ -237,10 +262,11 @@ namespace nana
int x = 2, y = 2;
auto bgcolor = API::bgcolor(widget_->handle());
auto fgcolor = API::fgcolor(widget_->handle());
graph.palette(true, bgcolor);
graph.gradual_rectangle(rectangle{ graph.size() }, bgcolor.blend(colors::white, 0.1), bgcolor.blend(colors::black, 0.05), true);
item_renderer ir(graph, impl_->textout, impl_->scale, bgcolor);
item_renderer ir(graph, impl_->scale, bgcolor, fgcolor);
size_type index = 0;
for (auto item : impl_->items.container())
@ -378,6 +404,10 @@ namespace nana
size_type which = _m_which(arg.pos, false);
if(impl_->which == which)
{
// update toggle state
auto m = impl_->items.at(impl_->which);
impl_->items.update_toggle_group(m, !m->toggle);
::nana::arg_toolbar arg{ *widget_, which };
widget_->events().selected.emit(arg, widget_->handle());
@ -419,19 +449,76 @@ namespace nana
if (item->text.size())
item->textsize = impl_->graph_ptr->text_extent_size(item->text);
if (item->image.empty() == false)
if(item->image.empty())
{
if(item->textsize.width && item->textout)
item->pixels = item->textsize.width + 8;
else
item->pixels = impl_->scale + item_renderer::extra_size;
}
else
{
item->pixels = impl_->scale + item_renderer::extra_size;
if (item->textsize.width && impl_->textout)
item->pixels += item->textsize.width + 8;
if(item->textsize.width && item->textout)
item->pixels += item->textsize.width + 8;
}
}
}
//class drawer
// Item Proxy
void item_proxy::enable(bool enable_state)
item_proxy::item_proxy(::nana::toolbar* t, std::size_t pos)
: tb_{ t }, pos_{ pos }
{}
bool item_proxy::enable() const
{
widget.enable(button, enable_state);
return tb_->enable(pos_);
}
item_proxy& item_proxy::enable(bool enable_state)
{
tb_->enable(pos_, enable_state);
return *this;
}
item_proxy& item_proxy::tooltype(tool_type type)
{
tb_->tooltype(pos_, type);
return *this;
}
bool item_proxy::istoggle() const
{
return tb_->istoggle(pos_);
}
bool item_proxy::toggle() const
{
return tb_->toggle(pos_);
}
item_proxy& item_proxy::toggle(bool toggle_state)
{
tb_->toggle(pos_, toggle_state);
return *this;
}
std::string item_proxy::toggle_group() const
{
return tb_->toggle_group(pos_);
}
item_proxy& item_proxy::textout(bool show)
{
tb_->textout(pos_, show);
return *this;
}
item_proxy& item_proxy::toggle_group(const ::std::string& group)
{
tb_->toggle_group(pos_, group);
return *this;
}
}//end namespace toolbar
}//end namespace drawerbase
@ -465,14 +552,14 @@ namespace nana
{
get_drawer_trigger().items().push_back(text, img);
API::refresh_window(handle());
return {*this, get_drawer_trigger().items().size() - 1u};
return {this, get_drawer_trigger().items().size() - 1u};
}
drawerbase::toolbar::item_proxy toolbar::append(const std::string& text)
{
get_drawer_trigger().items().push_back(text, {});
API::refresh_window(this->handle());
return {*this, get_drawer_trigger().items().size() - 1u};
return {this, get_drawer_trigger().items().size() - 1u};
}
void toolbar::clear()
@ -507,6 +594,100 @@ namespace nana
}
}
void toolbar::tooltype(size_type index, tool_type type)
{
auto & items = get_drawer_trigger().items();
if(items.size() > index)
{
auto m = items.at(index);
if(m && m->type != type)
{
m->type = type;
API::refresh_window(this->handle());
}
}
}
bool toolbar::istoggle(size_type index) const
{
auto & items = get_drawer_trigger().items();
if(items.size() <= index)
return false;
auto m = items.at(index);
return (m && m->type == tool_type::toggle);
}
bool toolbar::toggle(size_type index) const
{
auto & items = get_drawer_trigger().items();
if(items.size() <= index)
return false;
auto m = items.at(index);
return (m && m->toggle);
}
void toolbar::toggle(size_type index, bool toggle_state)
{
auto & items = get_drawer_trigger().items();
if(items.size() > index)
{
auto m = items.at(index);
if(m)
{
items.update_toggle_group(m, toggle_state, false);
API::refresh_window(this->handle());
}
}
}
std::string toolbar::toggle_group(size_type index) const
{
auto & items = get_drawer_trigger().items();
if(items.size() <= index)
return "";
auto m = items.at(index);
return m ? m->group : "";
}
void toolbar::toggle_group(size_type index, const ::std::string& group)
{
auto & items = get_drawer_trigger().items();
if(items.size() > index)
{
auto m = items.at(index);
if(m && (m->group != group))
{
m->group = group;
API::refresh_window(this->handle());
}
}
}
void toolbar::textout(size_type index, bool show)
{
auto & items = get_drawer_trigger().items();
if(items.size() > index)
{
auto m = items.at(index);
if(m && (m->textout != show))
{
m->textout = show;
API::refresh_window(this->handle());
}
}
}
void toolbar::scale(unsigned s)
{
get_drawer_trigger().scale(s);

View File

@ -1,6 +1,6 @@
/*
* Nana GUI Library Definition
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -11,7 +11,8 @@
* the file contains the files required for running of Nana.GUI
*/
#include <nana/gui/wvl.hpp>
#include <nana/gui/compact.hpp>
#include <nana/gui/widgets/widget.hpp>
#include <nana/gui/detail/bedrock.hpp>
#include <nana/std_thread.hpp>
#include <iostream>
@ -29,7 +30,7 @@ namespace nana
{
void form_loader_private::insert_form(::nana::widget* p)
{
bedrock::instance().manage_form_loader(reinterpret_cast<basic_window*>(p->handle()), true);
bedrock::instance().manage_form_loader(p->handle(), true);
}
}

View File

@ -30,16 +30,21 @@ namespace nana
png_byte color_type = ::png_get_color_type(png_ptr, info_ptr);
const auto bit_depth = ::png_get_bit_depth(png_ptr, info_ptr);
pixbuf_.open(png_width, png_height);
//do some extra work for palette/gray color type
if (PNG_COLOR_TYPE_PALETTE == color_type)
::png_set_palette_to_rgb(png_ptr);
else if ((PNG_COLOR_TYPE_GRAY == color_type) && (bit_depth < 8))
else if ((PNG_COLOR_TYPE_GRAY == color_type) || (PNG_COLOR_TYPE_GRAY_ALPHA == color_type))
::png_set_gray_to_rgb(png_ptr);
auto is_alpha_enabled = (::png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0);
if (is_alpha_enabled)
::png_set_tRNS_to_alpha(png_ptr);
is_alpha_enabled |= ((PNG_COLOR_MASK_ALPHA & color_type) != 0);
pixbuf_.alpha_channel(is_alpha_enabled);
//make sure 8-bit per channel
if (16 == bit_depth)
::png_set_strip_16(png_ptr);
@ -51,11 +56,6 @@ namespace nana
png_bytep * row_ptrs = new png_bytep[png_height];
const std::size_t png_rowbytes = ::png_get_rowbytes(png_ptr, info_ptr);
pixbuf_.open(png_width, png_height);
is_alpha_enabled |= ((PNG_COLOR_MASK_ALPHA & color_type) != 0);
pixbuf_.alpha_channel(is_alpha_enabled);
if (is_alpha_enabled && (png_rowbytes == png_width * sizeof(pixel_argb_t)))
{
for (int i = 0; i < png_height; ++i)
@ -63,14 +63,17 @@ namespace nana
::png_read_image(png_ptr, row_ptrs);
for (int i = 0; i < png_height; ++i)
if (std::is_same<pixel_argb_t, pixel_color_t>::value)
{
auto p = pixbuf_.raw_ptr(i);
for (int u = 0; u < png_width; ++u)
for (int i = 0; i < png_height; ++i)
{
auto t = p[u].element.red;
p[u].element.red = p[u].element.blue;
p[u].element.blue = t;
auto p = pixbuf_.raw_ptr(i);
for (int u = 0; u < png_width; ++u)
{
auto t = p[u].element.red;
p[u].element.red = p[u].element.blue;
p[u].element.blue = t;
}
}
}
}
@ -82,7 +85,6 @@ namespace nana
row_ptrs[i] = reinterpret_cast<png_bytep>(png_pixbuf + png_rowbytes * i);
::png_read_image(png_ptr, row_ptrs);
//::png_destroy_read_struct(&png_ptr, &info_ptr, 0);
std::size_t png_pixel_bytes = png_rowbytes / png_width;

View File

@ -1,7 +1,7 @@
/*
* Platform Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -24,6 +24,14 @@
namespace nana
{
#ifdef NANA_USE_XFT
//Forward-declarations
//These names are defined platform_abstraction.cpp
class font_interface;
void nana_xft_draw_string(::XftDraw* xftdraw, ::XftColor* xftcolor, font_interface* ft, const nana::point& pos, const wchar_t * str, std::size_t len);
nana::size nana_xft_extents(font_interface* ft, const wchar_t* str, std::size_t len);
#endif
namespace paint
{
namespace detail
@ -144,14 +152,19 @@ namespace detail
if (::GetTextExtentPoint32(dw->context, text, static_cast<int>(len), &size))
return nana::size(size.cx, size.cy);
#elif defined(NANA_X11)
std::string utf8text = to_utf8(std::wstring(text, len));
#if defined(NANA_USE_XFT)
#if 0
std::string utf8text = to_utf8(std::wstring(text, len));
XGlyphInfo ext;
XftFont * fs = reinterpret_cast<XftFont*>(dw->font->native_handle());
::XftTextExtentsUtf8(nana::detail::platform_spec::instance().open_display(), fs,
reinterpret_cast<XftChar8*>(const_cast<char*>(utf8text.data())), utf8text.size(), &ext);
return nana::size(ext.xOff, fs->ascent + fs->descent);
#else
return nana_xft_extents(dw->font.get(), text, len);
#endif
#else
std::string utf8text = to_utf8(std::wstring(text, len));
XRectangle ink;
XRectangle logic;
::XmbTextExtents(reinterpret_cast<XFontSet>(dw->font->native_handle()), utf8text.c_str(), utf8text.size(), &ink, &logic);
@ -178,11 +191,20 @@ namespace detail
return nana::size(size.cx, size.cy);
#elif defined(NANA_X11)
#if defined(NANA_USE_XFT)
#if 0
XGlyphInfo ext;
XftFont * fs = reinterpret_cast<XftFont*>(dw->font->native_handle());
::XftTextExtentsUtf8(nana::detail::platform_spec::instance().open_display(), fs,
reinterpret_cast<XftChar8*>(const_cast<char*>(text)), len, &ext);
return nana::size(ext.xOff, fs->ascent + fs->descent);
#else
#ifdef _nana_std_has_string_view
auto wstr = to_wstring(std::string_view(text, len));
#else
auto wstr = to_wstring(std::string(text,len));
#endif
return nana_xft_extents(dw->font.get(), wstr.data(), wstr.size());
#endif
#else
XRectangle ink;
XRectangle logic;
@ -238,19 +260,8 @@ namespace detail
#if defined(NANA_WINDOWS)
::TextOut(dw->context, pos.x, pos.y, str, static_cast<int>(len));
#elif defined(NANA_X11)
auto disp = ::nana::detail::platform_spec::instance().open_display();
#if defined(NANA_USE_XFT)
auto fs = reinterpret_cast<XftFont*>(dw->font->native_handle());
//Fixed missing array declaration by dareg
std::unique_ptr<FT_UInt[]> glyphs_ptr(new FT_UInt[len]);
auto glyphs = glyphs_ptr.get();
const auto endstr = str + len;
for(auto chr = str; chr != endstr; ++chr)
{
(*glyphs++) = XftCharIndex(disp, fs, *chr);
}
XftDrawGlyphs(dw->xftdraw, &(dw->xft_fgcolor), fs, pos.x, pos.y + fs->ascent, glyphs_ptr.get(), len);
nana_xft_draw_string(dw->xftdraw, &(dw->xft_fgcolor), dw->font.get(), pos, str, len);
#else
XFontSet fs = reinterpret_cast<XFontSet>(dw->font->native_handle());
XFontSetExtents * ext = ::XExtentsOfFontSet(fs);

View File

@ -1,7 +1,7 @@
/*
* Paint Graphics 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
@ -28,6 +28,10 @@
namespace nana
{
//Forward-declarations
//These names are defined platform_abstraction.cpp
std::unique_ptr<unsigned[]> nana_xft_glyph_pixels(font_interface*, const wchar_t* str, std::size_t len);
namespace detail
{
font_style::font_style(unsigned weight, bool italic, bool underline, bool strike_out) :
@ -502,8 +506,8 @@ namespace paint
if (!text.empty())
{
unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels;
#if defined(NANA_WINDOWS)
unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels;
int * dx = new int[text.size()];
SIZE extents;
::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast<int>(text.size()), 0, 0, dx, &extents);
@ -516,22 +520,7 @@ namespace paint
}
delete[] dx;
#elif defined(NANA_X11) && defined(NANA_USE_XFT)
auto disp = nana::detail::platform_spec::instance().open_display();
auto xft = reinterpret_cast<XftFont*>(impl_->handle->font->native_handle());
XGlyphInfo extents;
for (std::size_t i = 0; i < text.size(); ++i)
{
if (text[i] != '\t')
{
FT_UInt glyphs = ::XftCharIndex(disp, xft, text[i]);
::XftGlyphExtents(disp, xft, &glyphs, 1, &extents);
pxbuf[i] = extents.xOff;
}
else
pxbuf[i] = tab_pixels;
}
return nana_xft_glyph_pixels(impl_->handle->font.get(), text.data(), text.size());
#endif
}
return pxbuf;
@ -1100,7 +1089,7 @@ namespace paint
::nana::color graphics::palette(bool for_text) const
{
if (impl_->handle)
return static_cast<color_rgb>(for_text ? impl_->handle->get_text_color() : impl_->handle->get_color());
return static_cast<color_rgb>(for_text ? impl_->handle->fgcolor_rgb : impl_->handle->bgcolor_rgb);
return{};
}
@ -1132,7 +1121,7 @@ namespace paint
if (impl_->handle)
{
#if defined(NANA_WINDOWS)
::SetPixel(impl_->handle->context, x, y, NANA_RGB(impl_->handle->get_color()));
::SetPixel(impl_->handle->context, x, y, impl_->handle->bgcolor_native);
#elif defined(NANA_X11)
Display* disp = nana::detail::platform_spec::instance().open_display();
impl_->handle->update_color();
@ -1328,14 +1317,14 @@ namespace paint
#if defined(NANA_WINDOWS)
if (pos1 != pos2)
{
auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color())));
auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native));
::MoveToEx(impl_->handle->context, pos1.x, pos1.y, 0);
::LineTo(impl_->handle->context, pos2.x, pos2.y);
::DeleteObject(::SelectObject(impl_->handle->context, prv_pen));
}
::SetPixel(impl_->handle->context, pos2.x, pos2.y, NANA_RGB(impl_->handle->get_color()));
::SetPixel(impl_->handle->context, pos2.x, pos2.y, impl_->handle->bgcolor_native);
#elif defined(NANA_X11)
Display* disp = nana::detail::platform_spec::instance().open_display();
impl_->handle->update_color();
@ -1361,7 +1350,7 @@ namespace paint
{
if (!impl_->handle) return;
#if defined(NANA_WINDOWS)
auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color())));
auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native));
::LineTo(impl_->handle->context, pos.x, pos.y);
@ -1394,7 +1383,7 @@ namespace paint
{
#if defined(NANA_WINDOWS)
auto brush = ::CreateSolidBrush(NANA_RGB(impl_->handle->get_color()));
auto brush = ::CreateSolidBrush(impl_->handle->bgcolor_native);
::RECT native_r = { r.x, r.y, r.right(), r.bottom()};
@ -1519,6 +1508,7 @@ namespace paint
if (impl_->changed == false) impl_->changed = true;
}
#define NANA_WINDOWS_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 )
void graphics::round_rectangle(const ::nana::rectangle& r, unsigned radius_x, unsigned radius_y, const color& clr, bool solid, const color& solid_clr)
{
if (impl_->handle)
@ -1528,8 +1518,8 @@ namespace paint
if (solid)
{
auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color())));
auto prv_brush = ::SelectObject(impl_->handle->context, ::CreateSolidBrush(NANA_RGB(solid_clr.px_color().value)));
auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native));
auto prv_brush = ::SelectObject(impl_->handle->context, ::CreateSolidBrush(NANA_WINDOWS_RGB(solid_clr.px_color().value)));
::RoundRect(impl_->handle->context, r.x, r.y, r.right(), r.bottom(), static_cast<int>(radius_x * 2), static_cast<int>(radius_y * 2));
@ -1538,7 +1528,7 @@ namespace paint
}
else
{
auto brush = ::CreateSolidBrush(NANA_RGB(impl_->handle->get_color()));
auto brush = ::CreateSolidBrush(impl_->handle->bgcolor_native);
auto region = ::CreateRoundRectRgn(r.x, r.y, r.x + static_cast<int>(r.width) + 1, r.y + static_cast<int>(r.height) + 1, static_cast<int>(radius_x + 1), static_cast<int>(radius_y + 1));

View File

@ -16,7 +16,7 @@ namespace nana
auto const end = str + len;
for(auto i = str; i != end; ++i)
{
if(*i == '\n')
if('\n' == *i)
{
top += static_cast<int>(f(top, str, i - str));
str = i + 1;
@ -26,212 +26,180 @@ namespace nana
f(top, str, end - str);
}
struct draw_string
{
drawable_type dw;
const int x, endpos;
align text_align;
draw_string(drawable_type dw, int x, int endpos, align ta)
: dw(dw), x(x), endpos(endpos), text_align(ta)
{}
class string_drawer
{
public:
string_drawer(graphics& graph, int left, int right, align ta, bool use_ellipsis):
graph_(graph),
left_(left),
right_(right),
text_align_(ta)
{
if (use_ellipsis)
{
#ifdef _nana_std_has_string_view
ellipsis_px_ = graph.text_extent_size(std::string_view{ "...", 3 }).width;
#else
ellipsis_px_ = graph.text_extent_size("...", 3).width;
#endif
}
}
unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize)
{
auto const drawable = graph_.handle();
auto const reordered = unicode_reorder(buf, bufsize);
if (reordered.empty())
return 0;
unsigned return_max_height = 0;
unsigned string_px = 0;
std::vector<nana::size> word_metrics;
for (auto & ent : reordered)
{
auto word_sz = detail::text_extent_size(drawable, ent.begin, ent.end - ent.begin);
word_metrics.push_back(word_sz);
nana::point pos{ x, top };
unsigned pixels = 0;
string_px += word_sz.width;
if (word_sz.height > return_max_height)
return_max_height = word_sz.height;
}
switch(text_align)
auto text_align = text_align_;
// Checks if ellipsis is enabled and the total pixels of string is larger than the space.
if (ellipsis_px_ && (static_cast<int>(string_px) > right_ - left_))
{
//The string should be drawn from left most point no matter what text align is.
text_align = align::left;
}
nana::point pos{ left_, top };
auto wdm = word_metrics.data();
switch (text_align)
{
case align::left:
for(auto & ent : reordered)
for (auto & ent : reordered)
{
std::size_t len = ent.end - ent.begin;
nana::size ts = detail::text_extent_size(dw, ent.begin, len);
if (pos.x + static_cast<int>(wdm->width) > 0)
{
if (pos.x + static_cast<int>(wdm->width) <= right_ - static_cast<int>(ellipsis_px_))
{
//This word can be fully painted.
detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin);
}
else
{
//This word is painted partially. Firstly, paints the word on a dummy graphics buffer.
if(ts.height > pixels) pixels = ts.height;
if(pos.x + static_cast<int>(ts.width) > 0)
detail::draw_string(dw, pos, ent.begin, len);
nana::rectangle r{ nana::size{ static_cast<unsigned>(right_ - ellipsis_px_) - pos.x, wdm->height } };
pos.x += static_cast<int>(ts.width);
if(pos.x >= endpos)
nana::paint::graphics dummy({ r.width, r.height });
dummy.typeface(graph_.typeface());
dummy.bitblt(r, graph_, pos);
#ifdef _nana_std_has_string_view
dummy.string({}, { ent.begin, static_cast<unsigned>(ent.end - ent.begin) }, graph_.palette(true));
#else
dummy.palette(true, graph_.palette(true));
dummy.string({}, ent.begin, ent.end - ent.begin);
#endif
r.x = pos.x;
r.y = top;
graph_.bitblt(r, dummy);
if (ellipsis_px_)
detail::draw_string(drawable, point{ right_ - static_cast<int>(ellipsis_px_), top }, L"...", 3);
break;
}
}
pos.x += static_cast<int>(wdm->width);
if (pos.x > right_ - static_cast<int>(ellipsis_px_))
break;
++wdm;
}
break;
case align::center:
pos.x = (right_ - left_ - string_px) / 2;
for (auto & ent : reordered)
{
unsigned lenpx = 0;
std::unique_ptr<unsigned[]> entity_pxs(new unsigned[reordered.size()]);
auto ent_px = entity_pxs.get();
for(auto & ent : reordered)
{
auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin);
if(ts.height > pixels) pixels = ts.height;
lenpx += ts.width;
*ent_px++ = ts.width;
}
pos.x += (endpos - pos.x - static_cast<int>(lenpx))/2;
ent_px = entity_pxs.get();
for(auto & ent : reordered)
{
if (pos.x + static_cast<int>(*ent_px) > 0)
detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin);
pos.x += static_cast<int>(*ent_px++);
if(pos.x >= endpos)
break;
}
detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin);
pos.x += (wdm++)->width;
}
break;
case align::right:
wdm = word_metrics.data() + word_metrics.size() - 1;
pos.x = right_;
for (auto i = reordered.crbegin(); i != reordered.crend(); ++i)
{
int xend = endpos;
std::swap(pos.x, xend);
for(auto i = reordered.crbegin(); i != reordered.crend(); ++i)
{
auto & ent = *i;
std::size_t len = ent.end - ent.begin;
nana::size ts = detail::text_extent_size(dw, ent.begin, len);
if(ts.height > pixels) pixels = ts.height;
if(pos.x > xend)
{
pos.x -= static_cast<int>(ts.width);
detail::draw_string(dw, pos, i->begin, len);
}
if(pos.x <= xend || pos.x <= 0)
break;
}
pos.x -= (wdm--)->width;
detail::draw_string(drawable, pos, i->begin, i->end - i->begin);
}
break;
}
return pixels;
}
};
struct draw_string_omitted
{
graphics & graph;
int x, endpos;
unsigned omitted_pixels;
draw_string_omitted(graphics& graph, int x, int endpos, bool omitted)
: graph(graph), x(x), endpos(endpos)
{
#ifdef _nana_std_has_string_view
omitted_pixels = (omitted ? graph.text_extent_size(std::string_view{ "...", 3 }).width : 0);
#else
omitted_pixels = (omitted ? graph.text_extent_size("...", 3).width : 0);
#endif
if (endpos - x > static_cast<int>(omitted_pixels))
this->endpos -= omitted_pixels;
else
this->endpos = x;
}
unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize)
{
drawable_type dw = graph.handle();
::nana::point pos{ x, top };
unsigned pixels = 0;
auto const reordered = unicode_reorder(buf, bufsize);
for(auto & i : reordered)
{
std::size_t len = i.end - i.begin;
nana::size ts = detail::text_extent_size(dw, i.begin, len);
if(ts.height > pixels) pixels = ts.height;
if(pos.x + static_cast<int>(ts.width) <= endpos)
{
detail::draw_string(dw, pos, i.begin, len);
pos.x += static_cast<int>(ts.width);
}
else
{
nana::rectangle r;
r.width = endpos - pos.x;
r.height = ts.height;
nana::paint::graphics dum_graph({ r.width, r.height });
dum_graph.bitblt(r, graph, pos);
#ifdef _nana_std_has_string_view
dum_graph.string({}, { i.begin, len }, graph.palette(true));
#else
dum_graph.palette(true, graph.palette(true));
dum_graph.string({}, i.begin, len);
#endif
r.x = pos.x;
r.y = top;
graph.bitblt(r, dum_graph);
if(omitted_pixels)
detail::draw_string(dw, point{ endpos, top }, L"...", 3);
break;
}
}
return pixels;
return return_max_height;
}
private:
graphics& graph_;
const int left_, right_; //the range of rendering area in x-axis
const align text_align_;
unsigned ellipsis_px_{ 0 };
};
struct draw_string_auto_changing_lines
{
graphics & graph;
int x, endpos;
align text_align;
const int left, right;
const align text_align;
draw_string_auto_changing_lines(graphics& graph, int x, int endpos, align ta)
: graph(graph), x(x), endpos(endpos), text_align(ta)
draw_string_auto_changing_lines(graphics& graph, int left, int right, align ta):
graph(graph),
left(left),
right(right),
text_align(ta)
{}
unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize)
{
unsigned pixels = 0;
unsigned return_max_height = 0;
auto const dw = graph.handle();
unsigned str_w = 0;
auto const drawable = graph.handle();
unsigned string_px = 0;
std::vector<nana::size> ts_keeper;
std::vector<nana::size> word_metrics;
auto const reordered = unicode_reorder(buf, bufsize);
for(auto & i : reordered)
{
nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin);
if(ts.height > pixels) pixels = ts.height;
ts_keeper.emplace_back(ts);
str_w += ts.width;
auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin);
word_metrics.emplace_back(word_sz);
string_px += word_sz.width;
if (return_max_height < word_sz.height)
return_max_height = word_sz.height;
}
const nana::size* wdm = word_metrics.data();
//Test whether the text needs the new line.
if(x + static_cast<int>(str_w) > endpos)
if(left + static_cast<int>(string_px) > right)
{
pixels = 0;
unsigned line_pixels = 0;
nana::point pos{ x, top };
int orig_top = top;
auto i_ts_keeper = ts_keeper.cbegin();
unsigned max_height = 0;
nana::point pos{ left, top };
const int orig_top = top;
for(auto & i : reordered)
{
if(line_pixels < i_ts_keeper->height)
line_pixels = i_ts_keeper->height;
if(max_height < wdm->height)
max_height = wdm->height;
bool beyond_edge = (pos.x + static_cast<int>(i_ts_keeper->width) > endpos);
bool beyond_edge = (pos.x + static_cast<int>(wdm->width) > right);
if(beyond_edge)
{
const std::size_t len = i.end - i.begin;
@ -251,10 +219,10 @@ namespace nana
{
auto pxbuf = pixel_buf.get();
idx_splitted = find_splitted(idx_head, len, pos.x, endpos, pxbuf);
idx_splitted = find_splitted(idx_head, len, pos.x, right, pxbuf);
if(idx_splitted == len)
{
detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head);
detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head);
for(std::size_t i = idx_head; i < len; ++i)
pos.x += static_cast<int>(pxbuf[i]);
@ -264,17 +232,16 @@ namespace nana
//Check the word whether it is splittable.
if(splittable(i.begin, idx_splitted))
{
detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head);
detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head);
idx_head = idx_splitted;
pos.x = x;
pos.y += static_cast<int>(line_pixels);
line_pixels = i_ts_keeper->height;
pos.x = left;
pos.y += static_cast<int>(max_height);
}
else
{
//Search the splittable character from idx_head to idx_splitted
const wchar_t * u = i.begin + idx_splitted;
const wchar_t * head = i.begin + idx_head;
const wchar_t * const head = i.begin + idx_head;
for(; head < u; --u)
{
@ -284,112 +251,102 @@ namespace nana
if(u != head)
{
detail::draw_string(dw, pos, head, u - head);
detail::draw_string(drawable, pos, head, u - head);
idx_head += u - head;
pos.x = x;
pos.y += static_cast<int>(line_pixels);
line_pixels = i_ts_keeper->height;
pos.x = left;
pos.y += static_cast<int>(max_height);
}
else
{
u = i.begin + idx_splitted;
const wchar_t * end = i.begin + len;
for(; u < end; ++u)
for(; u < i.begin + len; ++u)
{
if(splittable(head, u - head))
break;
}
std::size_t splen = u - head;
pos.y += static_cast<int>(line_pixels);
pos.x = x;
detail::draw_string(dw, pos, head, splen);
line_pixels = i_ts_keeper->height;
pos.y += static_cast<int>(max_height);
pos.x = left;
detail::draw_string(drawable, pos, head, splen);
for(std::size_t k = idx_head; k < idx_head + splen; ++k)
pos.x += static_cast<int>(pxbuf[k]);
if (pos.x >= endpos)
if (pos.x >= right)
{
pos.x = x;
pos.y += static_cast<int>(line_pixels);
pos.x = left;
pos.y += static_cast<int>(wdm->height);
}
idx_head += splen;
}
}
max_height = wdm->height;
}while(idx_head < len);
}
else
{
pos.x = x;
pos.y += static_cast<int>(line_pixels);
detail::draw_string(dw, pos, i.begin, 1);
pos.x += static_cast<int>(i_ts_keeper->width);
pos.x = left;
pos.y += static_cast<int>(max_height);
detail::draw_string(drawable, pos, i.begin, 1);
pos.x += static_cast<int>(wdm->width);
}
line_pixels = 0;
max_height = 0;
}
else
{
detail::draw_string(dw, pos, i.begin, i.end - i.begin);
pos.x += static_cast<int>(i_ts_keeper->width);
detail::draw_string(drawable, pos, i.begin, i.end - i.begin);
pos.x += static_cast<int>(wdm->width);
}
++i_ts_keeper;
++wdm;
}
pixels = (top - orig_top) + line_pixels;
return_max_height = (top - orig_top) + max_height;
}
else
{
point pos{ left, top };
//The text could be drawn in a line.
if((align::left == text_align) || (align::center == text_align))
{
point pos{ x, top };
if(align::center == text_align)
pos.x += (endpos - x - static_cast<int>(str_w)) / 2;
auto i_ts_keeper = ts_keeper.cbegin();
pos.x += (right - left - static_cast<int>(string_px)) / 2;
for(auto & ent : reordered)
{
const nana::size & ts = *i_ts_keeper;
if (pos.x + static_cast<int>(wdm->width) > 0)
detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin);
if (pos.x + static_cast<int>(ts.width) > 0)
detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin);
pos.x += static_cast<int>(ts.width);
++i_ts_keeper;
pos.x += static_cast<int>(wdm->width);
++wdm;
}
}
else if(align::right == text_align)
{
point pos{ endpos, top };
auto i_ts_keeper = ts_keeper.crbegin();
pos.x = right;
for(auto i = reordered.crbegin(); i != reordered.crend(); ++i)
{
if (pos.x < 0)
break;
auto & ent = *i;
std::size_t len = ent.end - ent.begin;
const nana::size & ts = *i_ts_keeper;
pos.x -= static_cast<int>(ts.width);
if (pos.x >= 0)
detail::draw_string(dw, pos, ent.begin, len);
++i_ts_keeper;
pos.x -= static_cast<int>(wdm->width);
detail::draw_string(drawable, pos, ent.begin, len);
++wdm;
}
}
}
return pixels;
return return_max_height;
}
static std::size_t find_splitted(std::size_t begin, std::size_t end, int x, int endpos, unsigned * pxbuf)
{
unsigned acc_width = 0;
for(std::size_t i = begin; i < end; ++i)
for (std::size_t i = begin; i < end; ++i)
{
if(x + static_cast<int>(acc_width + pxbuf[i]) > endpos)
{
if(i == begin)
++i;
return i;
}
acc_width += pxbuf[i];
if ((x += static_cast<int>(pxbuf[i])) > endpos)
return (begin == i ? i + 1 : i);
}
return end;
}
@ -399,12 +356,11 @@ namespace nana
wchar_t ch = str[index];
if(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))
{
wchar_t prch;
if(index)
{
prch = str[index - 1];
auto prch = str[index - 1];
if('0' <= ch && ch <= '9')
return !(('0' <= prch && prch <= '9') || (str[index - 1] == '-'));
return !(('0' <= prch && prch <= '9') || (prch == '-'));
return (('z' < prch || prch < 'a') && ('Z' < prch || prch < 'A'));
}
@ -418,44 +374,53 @@ namespace nana
struct extent_auto_changing_lines
{
graphics & graph;
int x, endpos;
const int left, right;
unsigned extents;
extent_auto_changing_lines(graphics& graph, int x, int endpos)
: graph(graph), x(x), endpos(endpos), extents(0)
extent_auto_changing_lines(graphics& graph, int left, int right):
graph(graph),
left(left),
right(right),
extents(0)
{}
unsigned operator()(int top, const wchar_t * buf, std::size_t bufsize)
{
unsigned pixels = 0;
unsigned return_max_height = 0;
drawable_type dw = graph.handle();
unsigned str_w = 0;
std::vector<nana::size> ts_keeper;
auto drawable = graph.handle();
std::vector<nana::size> word_metrics;
unsigned string_px = 0;
auto const reordered = unicode_reorder(buf, bufsize);
for(auto & i : reordered)
{
nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin);
ts_keeper.emplace_back(ts);
str_w += ts.width;
auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin);
word_metrics.emplace_back(word_sz);
string_px += word_sz.width;
if (return_max_height < word_sz.height)
return_max_height = word_sz.height;
}
auto i_ts_keeper = ts_keeper.cbegin();
//Test whether the text needs the new line.
if(x + static_cast<int>(str_w) > endpos)
if(left + static_cast<int>(string_px) > right)
{
unsigned line_pixels = 0;
int xpos = x;
int orig_top = top;
unsigned max_height = 0;
int xpos = left;
const int orig_top = top;
auto wdm = word_metrics.data();
for(auto & i : reordered)
{
if(line_pixels < i_ts_keeper->height)
line_pixels = i_ts_keeper->height;
if(max_height < wdm->height)
max_height = wdm->height;
bool beyond_edge = (xpos + static_cast<int>(i_ts_keeper->width) > endpos);
bool beyond_edge = (xpos + static_cast<int>(wdm->width) > right);
if(beyond_edge)
{
std::size_t len = i.end - i.begin;
@ -475,21 +440,22 @@ namespace nana
do
{
idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, endpos, pxbuf);
idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, right, pxbuf);
if(idx_splitted == len)
{
for(std::size_t i = idx_head; i < len; ++i)
xpos += static_cast<int>(pxbuf[i]);
break;
}
//Check the word whether it is splittable.
if(draw_string_auto_changing_lines::splittable(i.begin, idx_splitted))
{
idx_head = idx_splitted;
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
xpos = left;
top += max_height;
max_height = wdm->height;
}
else
{
@ -503,14 +469,11 @@ namespace nana
break;
}
if(u != head)
{
idx_head += u - head;
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
}
else
xpos = left;
top += max_height;
max_height = wdm->height;
if(u == head)
{
u = i.begin + idx_splitted;
const wchar_t * end = i.begin + len;
@ -520,52 +483,45 @@ namespace nana
break;
}
std::size_t splen = u - head;
top += line_pixels;
xpos = x;
line_pixels = i_ts_keeper->height;
for(std::size_t k = idx_head; k < idx_head + splen; ++k)
xpos += static_cast<int>(pxbuf[k]);
if(xpos >= endpos)
if(xpos >= right)
{
xpos = x;
top += line_pixels;
xpos = left;
top += max_height;
}
idx_head += splen;
}
else
idx_head += u - head;
}
}while(idx_head < len);
}
else
xpos = x + static_cast<int>(i_ts_keeper->width);
xpos = left + static_cast<int>(wdm->width);
line_pixels = 0;
max_height = 0;
}
else
xpos += static_cast<int>(i_ts_keeper->width);
xpos += static_cast<int>(wdm->width);
++i_ts_keeper;
++wdm;
}
pixels = (top - orig_top) + line_pixels;
return_max_height = (top - orig_top) + max_height;
}
else
{
while(i_ts_keeper != ts_keeper.cend())
{
const nana::size & ts = *(i_ts_keeper++);
if(ts.height > pixels) pixels = ts.height;
}
}
extents += pixels;
return pixels;
extents += return_max_height;
return return_max_height;
}
};
}//end namespace helper
//class text_renderer
text_renderer::text_renderer(graph_reference graph, align ta)
: graph_(graph), text_align_(ta)
text_renderer::text_renderer(graph_reference graph, align ta):
graph_(graph),
text_align_(ta)
{}
nana::size text_renderer::extent_size(int x, int y, const wchar_t* str, std::size_t len, unsigned restricted_pixels) const
@ -585,26 +541,25 @@ namespace nana
{
if (graph_)
{
helper::draw_string ds(graph_.handle(), pos.x, static_cast<int>(graph_.width()), text_align_);
helper::for_each_line(str, len, pos.y, ds);
helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast<int>(graph_.width()), text_align_, false };
helper::for_each_line(str, len, pos.y, sd);
}
}
void text_renderer::render(const point& pos, const wchar_t* str, std::size_t len, unsigned restricted_pixels, bool omitted)
void text_renderer::render(const point& pos, const wchar_t* str, std::size_t len, unsigned space_pixels, mode rendering_mode)
{
if (graph_)
if (graph_ && str && len && space_pixels)
{
helper::draw_string_omitted dso(graph_, pos.x, pos.x + static_cast<int>(restricted_pixels), omitted);
helper::for_each_line(str, len, pos.y, dso);
}
}
void text_renderer::render(const point& pos, const wchar_t * str, std::size_t len, unsigned restricted_pixels)
{
if (graph_)
{
helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast<int>(restricted_pixels), text_align_);
helper::for_each_line(str, len, pos.y, dsacl);
if (mode::truncate_letter_with_ellipsis == rendering_mode || mode::truncate_with_ellipsis == rendering_mode)
{
helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast<int>(space_pixels), text_align_, true };
helper::for_each_line(str, len, pos.y, sd);
}
else if (mode::word_wrap == rendering_mode)
{
helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast<int>(space_pixels), text_align_);
helper::for_each_line(str, len, pos.y, dsacl);
}
}
}
//end class text_renderer

View File

@ -15,15 +15,14 @@
#include <nana/paint/graphics.hpp>
#include <nana/paint/pixel_buffer.hpp>
#include <vector>
#include <cassert>
#include <cstring>
#if defined(NANA_WINDOWS)
# include <windows.h>
#elif defined(NANA_X11)
# include "../detail/platform_spec_selector.hpp"
# include <nana/gui/detail/bedrock.hpp>
# include <nana/gui/detail/basic_window.hpp>
# include "../detail/platform_spec_selector.hpp"
# include "../gui/detail/basic_window.hpp"
#endif
namespace nana{ namespace system{
@ -71,7 +70,6 @@ namespace nana{ namespace system{
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
HDC hDC = ::GetDC(NULL);
if (::GetDIBits(hDC, (HBITMAP)g.pixmap(), 0, 1, NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS) == 0) {
assert(false);
::ReleaseDC(NULL, hDC);
return false;
}
@ -109,7 +107,6 @@ namespace nana{ namespace system{
::CloseClipboard();
}
}
assert(false);
::GlobalFree(h_gmem);
return false;
@ -266,8 +263,8 @@ namespace nana{ namespace system{
spec.lock_xlib();
{
internal_scope_guard isg;
detail::bedrock::core_window_t * wd = detail::bedrock::instance().focus();
internal_scope_guard lock;
auto wd = detail::bedrock::instance().focus();
if(wd) requester = wd->root;
}
spec.unlock_xlib();

View File

@ -141,6 +141,7 @@ namespace threads
::pthread_join(thr->handle, 0);
::pthread_detach(thr->handle);
#endif
delete thr;
}
std::lock_guard<decltype(mutex_)> lock(mutex_);

View File

@ -1,3 +1,17 @@
/*
* Unicode Bidi-Language Implementation
* Nana C++ Library(http://www.nanapro.org)
* 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/unicode_bidi.cpp
* @contributors:
* glavangeorge(pr#440)
*/
#include <nana/unicode_bidi.hpp>
#include <nana/c++defines.hpp>
@ -976,7 +990,7 @@ namespace nana
return unicode_character_type::katakana;
if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || (0x00AA == ch || 0x00B5 == ch || 0x00BA == ch) || (0x00C0 <= ch && ch <= 0x00D6) ||
(0x00D8 <= ch && ch <= 0x00F6) || (0x00F8 <= ch && ch <= 0x0236) || (0x0250 <= ch || ch <= 0x02C1))
(0x00D8 <= ch && ch <= 0x00F6) || (0x00F8 <= ch && ch <= 0x0236) || (0x0250 <= ch && ch <= 0x02C1))
return unicode_character_type::aletter;
if ('\'' == ch || 0x00AD == ch || 0x00B7 == ch || 0x05F4 == ch || 0x2019 == ch || 0x2027 == ch)