Merge branch 'hotfixes-1.0.1' into develop

Conflicts:
	.gitignore
	include/nana/deploy.hpp
	source/deploy.cpp
	source/gui/widgets/listbox.cpp
This commit is contained in:
Jinhao 2015-05-03 03:08:26 +08:00
commit 08e860a7e7
81 changed files with 2639 additions and 1737 deletions

4
.gitignore vendored
View File

@ -24,6 +24,7 @@ bii/deps/*
[Bb]in [Bb]in
[Dd]ebug*/ [Dd]ebug*/
*.lib *.lib
*.a
*.sbr *.sbr
obj/ obj/
[Rr]elease*/ [Rr]elease*/
@ -31,5 +32,4 @@ _ReSharper*/
[Tt]est[Rr]esult* [Tt]est[Rr]esult*
*.suo *.suo
*.sdf *.sdf
lib/
bii/.hive.db

View File

@ -1,20 +1,26 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2013 for Windows Desktop # Visual Studio Express 2013 for Windows Desktop
VisualStudioVersion = 12.0.21005.1 VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{25B21068-491B-4A9F-B99F-6C27BF31BAAD}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{25B21068-491B-4A9F-B99F-6C27BF31BAAD}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32 Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|Win32.ActiveCfg = Debug|Win32 {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|Win32.ActiveCfg = Debug|Win32
{25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|Win32.Build.0 = Debug|Win32 {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|Win32.Build.0 = Debug|Win32
{25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x64.ActiveCfg = Debug|x64
{25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x64.Build.0 = Debug|x64
{25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|Win32.ActiveCfg = Release|Win32 {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|Win32.ActiveCfg = Release|Win32
{25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|Win32.Build.0 = Release|Win32 {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|Win32.Build.0 = Release|Win32
{25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.ActiveCfg = Release|x64
{25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -5,10 +5,18 @@
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32"> <ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{25B21068-491B-4A9F-B99F-6C27BF31BAAD}</ProjectGuid> <ProjectGuid>{25B21068-491B-4A9F-B99F-6C27BF31BAAD}</ProjectGuid>
@ -22,6 +30,12 @@
<PlatformToolset>v120</PlatformToolset> <PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
@ -29,21 +43,48 @@
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <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" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<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'"> <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" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>../bin/vc2013/</OutDir> <OutDir>../bin/vc2013/</OutDir>
<IncludePath>..\..\include;$(IncludePath)</IncludePath>
<SourcePath>..\..\source;$(VC_SourcePath);</SourcePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>..\..\include;$(IncludePath)</IncludePath>
<SourcePath>..\..\source;$(VC_SourcePath);</SourcePath>
<OutDir>../bin/vc2013/</OutDir>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>../bin/vc2013/</OutDir> <OutDir>../bin/vc2013/</OutDir>
<IncludePath>..\..\include;$(IncludePath)</IncludePath>
<SourcePath>..\..\source;$(VC_SourcePath);</SourcePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>..\..\include;$(IncludePath)</IncludePath>
<SourcePath>..\..\source;$(VC_SourcePath);</SourcePath>
<OutDir>../bin/vc2013/</OutDir>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
@ -52,13 +93,33 @@
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
<Lib> <Lib>
<OutputFile>$(OutDir)\nana_debug.lib</OutputFile> <OutputFile>$(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<OutputFile>$(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib</OutputFile>
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -70,6 +131,8 @@
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -78,7 +141,28 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
</Link> </Link>
<Lib> <Lib>
<OutputFile>$(OutDir)\nana_release.lib</OutputFile> <OutputFile>$(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Lib>
<OutputFile>$(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib</OutputFile>
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

1
extrlib/readme (2).txt Normal file
View File

@ -0,0 +1 @@
The libpng.a is for MinGW(Not linux), and other .lib files are for VS2013

View File

@ -18,7 +18,7 @@
namespace nana namespace nana
{ {
//A constant value for the invalid position. /// A constant value for the invalid position.
const std::size_t npos = static_cast<std::size_t>(-1); const std::size_t npos = static_cast<std::size_t>(-1);
@ -127,8 +127,7 @@ namespace nana
using pixel_color_t = pixel_argb_t; using pixel_color_t = pixel_argb_t;
//http://www.w3.org/TR/2011/REC-css3-color-20110607/ /// See extended CSS color keywords (4.3) in http://www.w3.org/TR/2011/REC-css3-color-20110607/
//4.3. Extended color keywords
enum class colors enum class colors
{ {
alice_blue = 0xf0f8ff, alice_blue = 0xf0f8ff,
@ -283,7 +282,7 @@ namespace nana
//temporary defintions, these will be replaced by color schema //temporary defintions, these will be replaced by color schema
button_face_shadow_start = 0xF5F4F2, button_face_shadow_start = 0xF5F4F2,
button_face_shadow_end = 0xD5D2CA, button_face_shadow_end = 0xD5D2CA,
button_face = 0xD4D0C8, button_face = 0xD4D0C8 , //,light_cyan
dark_border = 0x404040, dark_border = 0x404040,
gray_border = 0x808080, gray_border = 0x808080,
highlight = 0x1CC4F7 highlight = 0x1CC4F7
@ -320,10 +319,10 @@ namespace nana
color blend(const color& bgcolor, bool ignore_bgcolor_alpha) const; color blend(const color& bgcolor, bool ignore_bgcolor_alpha) const;
///< Blends two colors with the specified alpha, and the alpha values that come with these two colors are both ignored. /// Blends two colors with the specified alpha, and the alpha values that come with these two colors are both ignored.
color blend(const color& bgcolor, double alpha) const; color blend(const color& bgcolor, double alpha) const;
///< Determines whether the color is completely transparent. /// Determines whether the color is completely transparent.
bool invisible() const; bool invisible() const;
pixel_color_t px_color() const; pixel_color_t px_color() const;
pixel_argb_t argb() const; pixel_argb_t argb() const;
@ -435,10 +434,10 @@ namespace nana
unsigned height; unsigned height;
}; };
class area_rotator class rectangle_rotator
{ {
public: public:
area_rotator(bool rotated, const ::nana::rectangle& area); rectangle_rotator(bool rotated, const ::nana::rectangle& area);
int x() const; int x() const;
int & x_ref(); int & x_ref();
@ -455,7 +454,7 @@ namespace nana
private: private:
bool rotated_; bool rotated_;
::nana::rectangle area_; ::nana::rectangle area_;
};//end class area_rotator };//end class rectangle_rotator
enum class arrange enum class arrange
{ {

View File

@ -1,7 +1,7 @@
/* /*
* Nana Configuration * Nana Configuration
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -20,10 +20,13 @@
#define PLATFORM_SPEC_HPP <nana/detail/win32/platform_spec.hpp> #define PLATFORM_SPEC_HPP <nana/detail/win32/platform_spec.hpp>
//Test if it is MINGW //Test if it is MINGW
#if defined(__MINGW32__) #if defined(__MINGW32__) || defined(__MINGW64__)
#define NANA_MINGW #define NANA_MINGW
#define STD_CODECVT_NOT_SUPPORTED #define STD_CODECVT_NOT_SUPPORTED
//#define STD_THREAD_NOT_SUPPORTED //Use this flag if MinGW version is older than 4.8.1 #if (__GNUC__ == 4) && ((__GNUC_MINOR__ < 8) || (__GNUC_MINOR__ == 8 && __GNUC_PATCHLEVEL__ < 1))
//Use this flag if MinGW version is older than 4.8.1
#define STD_THREAD_NOT_SUPPORTED
#endif
#endif #endif
#elif (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) #elif (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC)
//Linux: //Linux:
@ -35,6 +38,13 @@
# static_assert(false, "Only Windows and Unix are support now"); # static_assert(false, "Only Windows and Unix are support now");
#endif #endif
#if defined(NANA_MINGW) || defined(NANA_LINUX)
#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ <= 1)
//Some functions which are specified in 21.5 Numeric conversions in Strings library have not yet implemented
#define STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED
#endif
#endif
//Here defines some flags that tell Nana what features will be supported. //Here defines some flags that tell Nana what features will be supported.
#define NANA_UNICODE #define NANA_UNICODE

View File

@ -23,8 +23,8 @@
#undef NANA_WINDOWS #undef NANA_WINDOWS
#endif #endif
//Implement workarounds for MinGW //Implement workarounds for GCC/MinGW which version is below 4.8.2
#if defined(NANA_MINGW) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) #if defined(STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED)
namespace std namespace std
{ {
//Workaround for no implemenation of std::stoi in MinGW. //Workaround for no implemenation of std::stoi in MinGW.

View File

@ -172,7 +172,7 @@ namespace detail
{ {
int pending; int pending;
{ {
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard lock;
pending = ::XPending(display_); pending = ::XPending(display_);
if(pending) if(pending)
{ {

View File

@ -96,7 +96,8 @@ namespace nana
//System Code for OS //System Code for OS
os_pageup = 0x21, os_pagedown, os_pageup = 0x21, os_pagedown,
os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down, os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down,
os_insert = 0x2D, os_del os_insert = 0x2D, os_del ,
os_end = 0x23 , os_home //Pos 1
}; };
}; };

View File

@ -166,7 +166,8 @@ namespace detail
bool fullscreen :1; //When the window is maximizing whether it fit for fullscreen. bool fullscreen :1; //When the window is maximizing whether it fit for fullscreen.
bool borderless :1; bool borderless :1;
bool make_bground_declared : 1; //explicitly make bground for bground effects bool make_bground_declared : 1; //explicitly make bground for bground effects
unsigned Reserved :21; bool ignore_menubar_focus : 1; //A flag indicates whether the menubar sets the focus.
unsigned Reserved :20;
unsigned char tab; //indicate a window that can receive the keyboard TAB unsigned char tab; //indicate a window that can receive the keyboard TAB
mouse_action action; mouse_action action;
}flags; }flags;
@ -175,7 +176,6 @@ namespace detail
{ {
caret_descriptor* caret; caret_descriptor* caret;
std::shared_ptr<general_events> events_ptr; std::shared_ptr<general_events> events_ptr;
general_events* attached_events;
}together; }together;
widget_colors* scheme{ nullptr }; widget_colors* scheme{ nullptr };

View File

@ -54,13 +54,14 @@ namespace detail
native_window_type root(core_window_t*); native_window_type root(core_window_t*);
void set_menubar_taken(core_window_t*); void set_menubar_taken(core_window_t*);
core_window_t* get_menubar_taken();
//Delay Restores focus when a menu which attached to menubar is closed
void delay_restore(int);
bool close_menu_if_focus_other_window(native_window_type focus); bool close_menu_if_focus_other_window(native_window_type focus);
void set_menu(native_window_type menu_window, bool is_keyboard_condition); void set_menu(native_window_type menu_window, bool is_keyboard_condition);
native_window_type get_menu(native_window_type owner, bool is_keyboard_condition); native_window_type get_menu(native_window_type owner, bool is_keyboard_condition);
native_window_type get_menu(); native_window_type get_menu();
void remove_menu(); void erase_menu(bool try_destroy);
void empty_menu();
void get_key_state(arg_keyboard&); void get_key_state(arg_keyboard&);
bool set_keyboard_shortkey(bool yes); bool set_keyboard_shortkey(bool yes);

View File

@ -23,7 +23,6 @@ namespace nana
void register_evt(event_handle); void register_evt(event_handle);
void cancel(event_handle); void cancel(event_handle);
void erase(event_handle); void erase(event_handle);
std::size_t size() const;
private: private:
mutable std::recursive_mutex mutex_; mutable std::recursive_mutex mutex_;
std::unordered_set<event_handle> register_; std::unordered_set<event_handle> register_;

View File

@ -1,4 +1,4 @@
/* /**
* Definition of General Events * Definition of General Events
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -19,7 +19,6 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <algorithm>
namespace nana namespace nana
{ {
@ -43,11 +42,13 @@ namespace nana
void events_operation_cancel(event_handle); void events_operation_cancel(event_handle);
}//end namespace detail }//end namespace detail
/// base clase for all event argument types
class event_arg class event_arg
{ {
public: public:
virtual ~event_arg(); virtual ~event_arg();
/// ignorable handlers behind the current one in a chain of event handlers will not get called.
void stop_propagation() const; void stop_propagation() const;
bool propagation_stopped() const; bool propagation_stopped() const;
private: private:
@ -56,18 +57,19 @@ namespace nana
struct general_events; struct general_events;
/// the type of the members of general_events
template<typename Arg> template<typename Arg>
class basic_event : public detail::event_interface class basic_event : public detail::event_interface
{ {
public: public:
typedef const typename std::remove_reference<Arg>::type & arg_reference; using arg_reference = const typename std::remove_reference<Arg>::type &;
private: private:
struct docker struct docker
: public detail::docker_interface : public detail::docker_interface
{ {
basic_event * const event_ptr; basic_event * const event_ptr;
std::function<void(arg_reference)> invoke; std::function<void(arg_reference)> invoke;
bool flag_entered{ false };
bool flag_deleted{ false }; bool flag_deleted{ false };
bool unignorable{false}; bool unignorable{false};
@ -89,7 +91,38 @@ namespace nana
return event_ptr; return event_ptr;
} }
}; };
//class emit_counter is a RAII helper for emitting count
//It is used for avoiding a try{}catch block which is required for some finial works when
//event handlers throw exceptions.
class emit_counter
{
public:
emit_counter(basic_event* evt)
: evt_{evt}
{
++evt->emitting_count_;
}
~emit_counter()
{
if ((0 == --evt_->emitting_count_) && evt_->deleted_flags_)
{
evt_->deleted_flags_ = false;
for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();)
{
if (i->get()->flag_deleted)
i = evt_->dockers_->erase(i);
else
++i;
}
}
}
private:
basic_event * const evt_;
};
public: public:
/// It will get called firstly, because it is set at the beginning of the chain.
template<typename Function> template<typename Function>
event_handle connect_front(Function && fn) event_handle connect_front(Function && fn)
{ {
@ -112,6 +145,7 @@ namespace nana
}); });
} }
/// It will not get called if stop_propagation() was called.
template<typename Function> template<typename Function>
event_handle connect(Function && fn) event_handle connect(Function && fn)
{ {
@ -127,13 +161,15 @@ namespace nana
return evt; return evt;
} }
template<typename Function> /// It will not get called if stop_propagation() was called.
template<typename Function>
event_handle operator()(Function&& fn) event_handle operator()(Function&& fn)
{ {
return connect(std::forward<Function>(fn)); return connect(std::forward<Function>(fn));
} }
template<typename Function> /// It will get called because it is unignorable.
template<typename Function>
event_handle connect_unignorable(Function && fn, bool in_front = false) event_handle connect_unignorable(Function && fn, bool in_front = false)
{ {
internal_scope_guard lock; internal_scope_guard lock;
@ -157,54 +193,37 @@ namespace nana
return (nullptr == dockers_ ? 0 : dockers_->size()); return (nullptr == dockers_ ? 0 : dockers_->size());
} }
void emit(arg_reference& arg) const void emit(arg_reference& arg)
{ {
internal_scope_guard lock; internal_scope_guard lock;
if (nullptr == dockers_) if (nullptr == dockers_)
return; return;
//Make a copy to allow create/destroy a new event handler when the call of emit in an event. emit_counter ec(this);
const std::size_t fixed_size = 10;
docker* fixed_buffer[fixed_size];
docker** transitory = fixed_buffer;
std::unique_ptr<docker*[]> variable_buffer;
auto& dockers = *dockers_; auto& dockers = *dockers_;
if (dockers.size() > fixed_size) const auto dockers_len = dockers.size();
{
variable_buffer.reset(new docker*[dockers.size()]);
transitory = variable_buffer.get();
}
auto output = transitory; //The dockers may resize when a new event handler is created by a calling handler.
for (auto & dck : dockers) //Traverses with position can avaid crash error which caused by a iterator which becomes invalid.
for (std::size_t pos = 0; pos < dockers_len; ++pos)
{ {
(*output++) = dck.get(); auto docker_ptr = dockers[pos].get();
} if (docker_ptr->flag_deleted)
bool stop_propagation = false;
for (; transitory != output; ++transitory)
{
auto docker_ptr = *transitory;
if (stop_propagation && !docker_ptr->unignorable)
continue; continue;
auto i = std::find_if(dockers.begin(), dockers.end(), [docker_ptr](std::unique_ptr<docker>& p){ docker_ptr->invoke(arg);
return (docker_ptr == p.get()); if (arg.propagation_stopped())
});
if (i != dockers.end())
{ {
docker_ptr->flag_entered = true; for (++pos; pos < dockers_len; ++pos)
docker_ptr->invoke(arg); {
auto docker_ptr = dockers[pos].get();
if (!docker_ptr->unignorable || docker_ptr->flag_deleted)
continue;
if (arg.propagation_stopped()) docker_ptr->invoke(arg);
stop_propagation = true; }
break;
docker_ptr->flag_entered = false;
if (docker_ptr->flag_deleted)
dockers.erase(i);
} }
} }
} }
@ -221,17 +240,20 @@ namespace nana
internal_scope_guard lock; internal_scope_guard lock;
if (dockers_) if (dockers_)
{ {
auto i = std::find_if(dockers_->begin(), dockers_->end(), [evt](const std::unique_ptr<docker>& sp) for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i)
{ {
return (reinterpret_cast<detail::docker_interface*>(evt) == sp.get()); if (reinterpret_cast<detail::docker_interface*>(evt) == i->get())
}); {
//Checks whether this event is working now.
if (i != dockers_->end()) if (emitting_count_ > 1)
{ {
if (i->get()->flag_entered) i->get()->flag_deleted = true;
i->get()->flag_deleted = true; deleted_flags_ = true;
else }
dockers_->erase(i); else
dockers_->erase(i);
break;
}
} }
} }
} }
@ -392,22 +414,27 @@ namespace nana
} }
}; };
private: private:
unsigned emitting_count_{ 0 };
bool deleted_flags_{ false };
std::unique_ptr<std::vector<std::unique_ptr<docker>>> dockers_; std::unique_ptr<std::vector<std::unique_ptr<docker>>> dockers_;
}; };
struct arg_mouse struct arg_mouse
: public event_arg : public event_arg
{ {
event_code evt_code; event_code evt_code; ///<
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
::nana::point pos; ::nana::point pos; ///< cursor position in the event window
bool left_button; bool left_button; ///< mouse left button is pressed?
bool mid_button; bool mid_button; ///< mouse middle button is pressed?
bool right_button; bool right_button; ///< mouse right button is pressed?
bool shift; bool shift; ///< keyboard Shift is pressed?
bool ctrl; bool ctrl; ///< keyboard Ctrl is pressed?
}; };
/// in arg_wheel event_code is event_code::mouse_wheel
/// The type arg_wheel is derived from arg_mouse, a handler
/// with prototype void(const arg_mouse&) can be set for mouse_wheel.
struct arg_wheel : public arg_mouse struct arg_wheel : public arg_mouse
{ {
enum class wheel{ enum class wheel{
@ -415,98 +442,99 @@ namespace nana
horizontal horizontal
}; };
wheel which; ///<which wheel is rotated wheel which; ///< which wheel is rotated
bool upwards; ///< true if the wheel is rotated to the top/left, depends on which. false otherwise. bool upwards; ///< true if the wheel is rotated to the top/left, depends on which and false otherwise
unsigned distance; //expressed in multiples or divisions of 120 unsigned distance; ///< expressed in multiples or divisions of 120
}; };
struct arg_dropfiles : public event_arg struct arg_dropfiles : public event_arg
{ {
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
::nana::point pos; ::nana::point pos; ///< cursor position in the event window
std::vector<nana::string> files; std::vector<nana::string> files; ///< external filenames
}; };
struct arg_expose : public event_arg struct arg_expose : public event_arg
{ {
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
bool exposed; bool exposed; ///< the window is visible?
}; };
struct arg_focus : public event_arg struct arg_focus : public event_arg
{ {
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
::nana::native_window_type receiver; ::nana::native_window_type receiver; ///< it is a native window handle, and specified which window receives focus
bool getting; bool getting; ///< the window received focus?
}; };
struct arg_keyboard : public event_arg struct arg_keyboard : public event_arg
{ {
event_code evt_code; event_code evt_code; ///< it is event_code::key_press in current event
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
mutable nana::char_t key; mutable nana::char_t key; ///< the key corresponding to the key pressed
mutable bool ignore; mutable bool ignore; ///< this member is not used
bool ctrl; bool ctrl; ///< keyboard Ctrl is pressed?
bool shift; bool shift; ///< keyboard Shift is pressed
}; };
struct arg_move : public event_arg struct arg_move : public event_arg
{ {
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
int x; int x; ///<
int y; int y; ///<
}; };
struct arg_resized : public event_arg struct arg_resized : public event_arg
{ {
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
unsigned width; unsigned width; ///< new width in pixels.
unsigned height; unsigned height; ///< new height in pixels.
}; };
struct arg_resizing : public event_arg struct arg_resizing : public event_arg
{ {
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
window_border border; window_border border; ///< the window is being resized by moving border
mutable unsigned width; mutable unsigned width; ///< new width in pixels. If it is modified, the window's width will be the modified value
mutable unsigned height; mutable unsigned height; ///< new height in pixels. If it is modified, the window's height will be the modified value
}; };
struct arg_unload : public event_arg struct arg_unload : public event_arg
{ {
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
mutable bool cancel; mutable bool cancel; ///<
}; };
struct arg_destroy : public event_arg struct arg_destroy : public event_arg
{ {
::nana::window window_handle; ::nana::window window_handle; ///< A handle to the event window
}; };
/// provides some fundamental events that every widget owns.
struct general_events struct general_events
{ {
virtual ~general_events(){} virtual ~general_events(){}
basic_event<arg_mouse> mouse_enter; basic_event<arg_mouse> mouse_enter; ///< the cursor enters the window
basic_event<arg_mouse> mouse_move; basic_event<arg_mouse> mouse_move; ///< the cursor moves on the window
basic_event<arg_mouse> mouse_leave; basic_event<arg_mouse> mouse_leave; ///< the cursor leaves the window
basic_event<arg_mouse> mouse_down; basic_event<arg_mouse> mouse_down; ///< the user presses the mouse button
basic_event<arg_mouse> mouse_up; basic_event<arg_mouse> mouse_up; ///< the user presses the mouse button
basic_event<arg_mouse> click; basic_event<arg_mouse> click; ///< the window is clicked, but occurs after mouse_down and before mouse_up
basic_event<arg_mouse> dbl_click; basic_event<arg_mouse> dbl_click; ///< the window is double clicked
basic_event<arg_wheel> mouse_wheel; basic_event<arg_wheel> mouse_wheel; ///< the mouse wheel rotates while the window has focus
basic_event<arg_dropfiles> mouse_dropfiles; basic_event<arg_dropfiles> mouse_dropfiles; ///< the mouse drops some external data while the window enable accepting files
basic_event<arg_expose> expose; basic_event<arg_expose> expose; ///< the visibility changes
basic_event<arg_focus> focus; basic_event<arg_focus> focus; ///< the window receives or loses keyboard focus
basic_event<arg_keyboard> key_press; basic_event<arg_keyboard> key_press; ///< a key is pressed while the window has focus. event code is event_code::key_press
basic_event<arg_keyboard> key_release; basic_event<arg_keyboard> key_release; ///< a key is released while the window has focus. event code is event_code::key_release
basic_event<arg_keyboard> key_char; basic_event<arg_keyboard> key_char; ///< a character, whitespace or backspace is pressed. event code is event_code::key_char
basic_event<arg_keyboard> shortkey; basic_event<arg_keyboard> shortkey; ///< a defined short key is pressed. event code is event_code::shortkey
basic_event<arg_move> move; basic_event<arg_move> move; ///< the window changes position
basic_event<arg_resizing> resizing; basic_event<arg_resizing> resizing; ///< the window is changing its size
basic_event<arg_resized> resized; basic_event<arg_resized> resized; ///< the window is changing its size
basic_event<arg_destroy> destroy; basic_event<arg_destroy> destroy; ///< the window is destroyed, but occurs when all children have been destroyed
}; };
namespace detail namespace detail

View File

@ -25,7 +25,6 @@
#include <map> #include <map>
#include <iterator> #include <iterator>
#include <algorithm>
namespace nana namespace nana
{ {
@ -260,9 +259,14 @@ namespace nana
{ {
if(cond_type::is_queue(handle)) if(cond_type::is_queue(handle))
{ {
auto i = std::find(queue.begin(), queue.end(), handle); for (auto i = queue.begin(); i != queue.end(); ++i)
if(i != queue.end()) {
queue.erase(i); if (handle == *i)
{
queue.erase(i);
break;
}
}
} }
} }
}; };

View File

@ -1,7 +1,7 @@
/* /*
* Implementations of Inner Forward Declaration * Implementations of Inner Forward Declaration
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -19,7 +19,6 @@
#include "../../paint/graphics.hpp" #include "../../paint/graphics.hpp"
#include <map> #include <map>
#include <algorithm>
namespace nana{ namespace nana{
namespace detail namespace detail
@ -62,12 +61,15 @@ namespace nana{
void umake(window wd) void umake(window wd)
{ {
if (wd == nullptr) return; if (wd == nullptr) return;
auto i = std::find_if(keybase_.begin(), keybase_.end(), [wd](const item_type& m){
return (m.handle == wd);
});
if (i != keybase_.end()) for (auto i = keybase_.begin(), end = keybase_.end(); i != end; ++i)
keybase_.erase(i); {
if (i->handle == wd)
{
keybase_.erase(i);
break;
}
}
} }
std::vector<unsigned long> keys(window wd) const std::vector<unsigned long> keys(window wd) const

View File

@ -10,7 +10,7 @@
* @file: nana/gui/place.cpp * @file: nana/gui/place.cpp
* *
* @contributions: * @contributions:
* min/max and splitter bar initial weight by qPCR4vir. * min/max and splitter bar initial weight by Ariel Vina-Rodriguez.
*/ */
#ifndef NANA_GUI_PLACE_HPP #ifndef NANA_GUI_PLACE_HPP

View File

@ -77,6 +77,8 @@ namespace API
window create_frame(window, const rectangle&, widget* attached); window create_frame(window, const rectangle&, widget* attached);
paint::graphics* window_graphics(window); paint::graphics* window_graphics(window);
void delay_restore(bool);
}//end namespace dev }//end namespace dev
@ -193,7 +195,7 @@ namespace API
return *comp_wdg_colors; return *comp_wdg_colors;
} }
nana::point window_position(window); point window_position(window);
void move_window(window, int x, int y); void move_window(window, int x, int y);
void move_window(window wd, const rectangle&); void move_window(window wd, const rectangle&);
@ -203,9 +205,11 @@ namespace API
void draw_through(window, std::function<void()>); void draw_through(window, std::function<void()>);
void map_through_widgets(window, native_drawable_type); void map_through_widgets(window, native_drawable_type);
nana::size window_size(window); size window_size(window);
void window_size(window, const size&); void window_size(window, const size&);
bool window_rectangle(window, rectangle&); size window_outline_size(window);
void window_outline_size(window, const size&);
bool get_window_rectangle(window, rectangle&);
bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window. bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window.
void window_enabled(window, bool); void window_enabled(window, bool);
bool window_enabled(window); bool window_enabled(window);
@ -235,7 +239,7 @@ namespace API
cursor window_cursor(window); cursor window_cursor(window);
void activate_window(window); void activate_window(window);
bool is_focus_window(window); bool is_focus_ready(window);
window focus_window(); window focus_window();
void focus_window(window); void focus_window(window);
@ -288,7 +292,6 @@ namespace API
void register_menu_window(window, bool has_keyboard); void register_menu_window(window, bool has_keyboard);
bool attach_menubar(window menubar); bool attach_menubar(window menubar);
void detach_menubar(window menubar); void detach_menubar(window menubar);
void restore_menubar_taken_window();
bool is_window_zoomed(window, bool ask_for_max); ///<Tests a window whether it is maximized or minimized. bool is_window_zoomed(window, bool ask_for_max); ///<Tests a window whether it is maximized or minimized.

View File

@ -27,25 +27,37 @@ namespace nana
/// The index of monitor. /// The index of monitor.
virtual std::size_t get_index() const = 0; virtual std::size_t get_index() const = 0;
virtual bool is_primary_monitor() const = 0;
/// Returns the positional coordinates and size of the display device in reference to the desktop area /// Returns the positional coordinates and size of the display device in reference to the desktop area
virtual const ::nana::rectangle& area() const = 0; virtual const ::nana::rectangle& area() const = 0;
virtual const ::nana::rectangle& workarea() const = 0;
}; };
class screen class screen
{ {
struct implement;
public: public:
static ::nana::size desktop_size(); static ::nana::size desktop_size();
static ::nana::size primary_monitor_size(); static ::nana::size primary_monitor_size();
static std::shared_ptr<display> from_point(const point&);
static std::shared_ptr<display> from_window(window); screen();
/// Reload has no preconditions, it's safe to call on moved-from
void reload();
/// Returns the number of display monitors /// Returns the number of display monitors
std::size_t count() const; std::size_t count() const;
std::shared_ptr<display> get_display(std::size_t index) const; display& from_point(const point&);
std::shared_ptr<display> get_primary() const; display& from_window(window);
display& get_display(std::size_t index) const;
display& get_primary() const;
void for_each(std::function<void(display&)>) const; void for_each(std::function<void(display&)>) const;
private:
std::shared_ptr<implement> impl_;
}; };
}//end namespace nana }//end namespace nana

View File

@ -1,13 +1,13 @@
/* /**
* A Button Implementation * A Button Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/button.hpp * @file: nana/gui/widgets/button.hpp
*/ */
#ifndef NANA_GUI_WIDGET_BUTTON_HPP #ifndef NANA_GUI_WIDGET_BUTTON_HPP

View File

@ -1,4 +1,4 @@
/* /**
* A Categorize Implementation * A Categorize Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -7,7 +7,7 @@
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/categorize.hpp * @file: nana/gui/widgets/categorize.hpp
*/ */
#ifndef NANA_GUI_WIDGET_CATEGORIZE_HPP #ifndef NANA_GUI_WIDGET_CATEGORIZE_HPP

View File

@ -1,13 +1,13 @@
/* /**
* A CheckBox Implementation * A CheckBox Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/checkbox.hpp * @file: nana/gui/widgets/checkbox.hpp
*/ */
#ifndef NANA_GUI_WIDGET_CHECKBOX_HPP #ifndef NANA_GUI_WIDGET_CHECKBOX_HPP

View File

@ -1,4 +1,4 @@
/* /**
* A Combox Implementation * A Combox Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -7,7 +7,7 @@
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/combox.hpp * @file: nana/gui/widgets/combox.hpp
*/ */
#ifndef NANA_GUI_WIDGETS_COMBOX_HPP #ifndef NANA_GUI_WIDGETS_COMBOX_HPP

View File

@ -1,4 +1,4 @@
/* /**
* A date chooser Implementation * A date chooser Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)

View File

@ -1,7 +1,7 @@
/* /**
* A float_listbox Implementation * A float_listbox Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at

View File

@ -1,4 +1,4 @@
/* /**
* A Form Implementation * A Form Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)

View File

@ -1,7 +1,7 @@
/* /**
* A Frame Implementation * A Frame Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -9,7 +9,7 @@
* *
* @file: nana/gui/widgets/frame.hpp * @file: nana/gui/widgets/frame.hpp
* *
* A frame provides a way to contain the platform window in a stdex GUI Window * @brief A frame provides a way to contain the platform window in a stdex GUI Window
*/ */
#ifndef NANA_GUI_WIDGET_FRAME_HPP #ifndef NANA_GUI_WIDGET_FRAME_HPP

View File

@ -1,7 +1,7 @@
/* /**
* A Label Control Implementation * A Label Control Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at

View File

@ -1,4 +1,4 @@
/* /**
* A List Box Implementation * A List Box Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -8,6 +8,7 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/listbox.hpp * @file: nana/gui/widgets/listbox.hpp
* @contributors: Ariel Vina-Rodriguez
* *
*/ */
@ -16,6 +17,7 @@
#include "widget.hpp" #include "widget.hpp"
#include <nana/concepts.hpp> #include <nana/concepts.hpp>
#include <nana/key_type.hpp> #include <nana/key_type.hpp>
//#include <nana/paint/graphics.hpp>
#include <functional> #include <functional>
#include <initializer_list> #include <initializer_list>
@ -27,7 +29,7 @@ namespace nana
{ {
namespace listbox namespace listbox
{ {
typedef std::size_t size_type; using size_type = std::size_t ;
struct cell struct cell
{ {
@ -35,7 +37,7 @@ namespace nana
{ {
::nana::color bgcolor; ::nana::color bgcolor;
::nana::color fgcolor; ::nana::color fgcolor;
/// ::nana::paint::font font; \todo
format() = default; format() = default;
format(const ::nana::color& bgcolor, const ::nana::color& fgcolor); format(const ::nana::color& bgcolor, const ::nana::color& fgcolor);
}; };
@ -112,7 +114,8 @@ namespace nana
std::size_t pos_{0}; std::size_t pos_{0};
}; };
struct index_pair /// usefull for both absolute and display (sorted) positions
struct index_pair
{ {
size_type cat; //The pos of category size_type cat; //The pos of category
size_type item; //the pos of item in a category. size_type item; //the pos of item in a category.
@ -169,7 +172,8 @@ namespace nana
class drawer_header_impl; class drawer_header_impl;
class drawer_lister_impl; class drawer_lister_impl;
class trigger: public drawer_trigger /// mostly works on display positions
class trigger: public drawer_trigger
{ {
public: public:
trigger(); trigger();
@ -192,19 +196,29 @@ namespace nana
void dbl_click(graph_reference, const arg_mouse&) override; void dbl_click(graph_reference, const arg_mouse&) override;
void resized(graph_reference, const arg_resized&) override; void resized(graph_reference, const arg_resized&) override;
void key_press(graph_reference, const arg_keyboard&) override; void key_press(graph_reference, const arg_keyboard&) override;
void key_char(graph_reference, const arg_keyboard&) override;
private: private:
essence_t * essence_; essence_t * essence_;
drawer_header_impl *drawer_header_; drawer_header_impl *drawer_header_;
drawer_lister_impl *drawer_lister_; drawer_lister_impl *drawer_lister_;
};//end class trigger };//end class trigger
class item_proxy /// operate with absolute positions and contain only the position but montain pointers to parts of the real items
/// item_proxy self, it references and iterators are not invalidated by sort()
class item_proxy
: public std::iterator<std::input_iterator_tag, item_proxy> : public std::iterator<std::input_iterator_tag, item_proxy>
{ {
public: public:
item_proxy(essence_t*); item_proxy(essence_t*);
item_proxy(essence_t*, const index_pair&); item_proxy(essence_t*, const index_pair&);
/// the main porpose of this it to make obvious that item_proxy operate with absolute positions, and dont get moved during sort()
static item_proxy from_display(essence_t *ess, const index_pair &relative) ;
item_proxy from_display(const index_pair &relative) const;
/// posible use: last_selected_display = last_selected.to_display().item; use with caution, it get invalidated after a sort()
index_pair to_display() const;
bool empty() const; bool empty() const;
item_proxy & check(bool ck); item_proxy & check(bool ck);
@ -237,7 +251,7 @@ namespace nana
auto && cells = ores.move_cells(); auto && cells = ores.move_cells();
auto cols = columns(); auto cols = columns();
cells.resize(cols); cells.resize(cols);
for (auto pos = 0; pos < cols; ++pos) for (auto pos = 0u; pos < cols; ++pos)
{ {
auto & el = cells[pos]; auto & el = cells[pos];
if (el.text.size() == 1 && el.text[0] == nana::char_t(0)) if (el.text.size() == 1 && el.text[0] == nana::char_t(0))
@ -318,8 +332,8 @@ namespace nana
essence_t * _m_ess() const; essence_t * _m_ess() const;
private: private:
std::vector<cell> & _m_cells() const; std::vector<cell> & _m_cells() const;
nana::any * _m_value(bool alloc_if_empty); nana::any * _m_value(bool alloc_if_empty);
const nana::any * _m_value() const; const nana::any * _m_value() const;
private: private:
essence_t * ess_; essence_t * ess_;
category_t* cat_{nullptr}; category_t* cat_{nullptr};
@ -334,7 +348,7 @@ namespace nana
cat_proxy(essence_t*, size_type pos); cat_proxy(essence_t*, size_type pos);
cat_proxy(essence_t*, category_t*); cat_proxy(essence_t*, category_t*);
/// Append an item at end of the category, set_value determines whether assign T object to the value of item. /// Append an item at abs end of the category, set_value determines whether assign T object to the value of item.
template<typename T> template<typename T>
item_proxy append(T&& t, bool set_value = false) item_proxy append(T&& t, bool set_value = false)
{ {
@ -367,13 +381,18 @@ namespace nana
item_proxy cbegin() const; item_proxy cbegin() const;
item_proxy cend() const; item_proxy cend() const;
item_proxy at(size_type pos) const; item_proxy at(size_type pos_abs) const;
item_proxy back() const; item_proxy back() const;
/// Returns the index of a item by its display pos, the index of the item isn't changed after sorting. /// Returns the absolute index of a item by its display pos, the index of the item isn't changed after sorting.
/// convert from display order to absolute (find the real item in that display pos) but without check from current active sorting, in fact using just the last sorting !!!
size_type index_by_display_order(size_type disp_order) const; size_type index_by_display_order(size_type disp_order) const;
size_type display_order(size_type pos) const;
size_type position() const; /// find display order for the real item but without check from current active sorting, in fact using just the last sorting !!!
size_type display_order(size_type pos) const;
/// this cat position
size_type position() const;
/// Returns the number of items /// Returns the number of items
size_type size() const; size_type size() const;
@ -410,9 +429,21 @@ namespace nana
private: private:
essence_t* ess_{nullptr}; essence_t* ess_{nullptr};
category_t* cat_{nullptr}; category_t* cat_{nullptr};
size_type pos_{0}; size_type pos_{0}; ///< Absolute position, not relative to display, and dont change during sort()
}; };
}
struct export_options
{
nana::string sep = nana::string {STR("\t" )},
endl= nana::string {STR("\n")} ;
bool only_selected_items{true},
only_checked_items {false},
only_visible_columns{true};
using columns_indexs = std::vector<size_type>;
columns_indexs columns_order;
};
}
}//end namespace drawerbase }//end namespace drawerbase
struct arg_listbox struct arg_listbox
@ -446,12 +477,12 @@ namespace nana
} }
}//end namespace drawerbase }//end namespace drawerbase
/*! \brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain \a items. /*! \brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain a list of \a items.
A category is a text with can be \a selected, \a checked and \a expanded to show the items. A category is a text with can be \a selected, \a checked and \a expanded to show the items.
An item is formed by \a column-fields, each corresponding to one of the \a headers. An item is formed by \a column-fields, each corresponding to one of the \a headers.
An item can be \a selected and \a checked. An item can be \a selected and \a checked.
The user can \a drag the header to \a reisize it or to \a reorganize it. The user can \a drag the header to \a reisize it or to \a reorganize it.
By \a clicking on a header the list get \a reordered, first up, and then down alternatively, By \a clicking on a header the list get \a reordered, first up, and then down alternatively.
*/ */
class listbox 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>,
@ -465,7 +496,9 @@ By \a clicking on a header the list get \a reordered, first up, and then down al
using selection = drawerbase::listbox::selection; ///<A container type for items. using selection = drawerbase::listbox::selection; ///<A container type for items.
using iresolver = drawerbase::listbox::iresolver; using iresolver = drawerbase::listbox::iresolver;
using oresolver = drawerbase::listbox::oresolver; using oresolver = drawerbase::listbox::oresolver;
using cell = drawerbase::listbox::cell; using cell = drawerbase::listbox::cell;
using export_options= drawerbase::listbox::export_options;
using columns_indexs= drawerbase::listbox::size_type;
public: public:
listbox() = default; listbox() = default;
listbox(window, bool visible); listbox(window, bool visible);
@ -481,8 +514,11 @@ By \a clicking on a header the list get \a reordered, first up, and then down al
void append(std::initializer_list<nana::string>); ///<Appends categories at the end void append(std::initializer_list<nana::string>); ///<Appends categories at the end
cat_proxy insert(cat_proxy, nana::string); cat_proxy insert(cat_proxy, nana::string);
cat_proxy at(size_type pos) const; cat_proxy at(size_type pos) const;
/// add categories in order when use a key?
listbox& ordered_categories(bool); listbox& ordered_categories(bool);
/// return a proxy to tha cat with the key or create a new one in the right order
template<typename Key> template<typename Key>
cat_proxy operator[](const Key & ck) cat_proxy operator[](const Key & ck)
{ {
@ -507,7 +543,7 @@ By \a clicking on a header the list get \a reordered, first up, and then down al
return cat_proxy(&_m_ess(), _m_at_key(p)); return cat_proxy(&_m_ess(), _m_at_key(p));
} }
item_proxy at(const index_pair&) const; item_proxy at(const index_pair &abs_pos) const;
void insert(const index_pair&, nana::string); ///<Insert a new item with a text in the first column. void insert(const index_pair&, nana::string); ///<Insert a new item with a text in the first column.
@ -536,20 +572,26 @@ By \a clicking on a header the list get \a reordered, first up, and then down al
_m_ease_key(&key); _m_ease_key(&key);
} }
///Sets a strick weak ordering comparer for a column bool sortable() const;
void sortable(bool enable);
///Sets a strict weak ordering comparer for a column
void set_sort_compare(size_type col, std::function<bool(const nana::string&, nana::any*, void set_sort_compare(size_type col, std::function<bool(const nana::string&, nana::any*,
const nana::string&, nana::any*, bool reverse)> strick_ordering); const nana::string&, nana::any*, bool reverse)> strick_ordering);
void sort_col(size_type col, bool reverse = false); /// sort() and ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items
void sort_col(size_type col, bool reverse = false);
size_type sort_col() const; size_type sort_col() const;
void unsort();
/// potencially ivalidate any existing reference from display position to absolute item, that is: after sort() display offset point to different items
void unsort();
bool freeze_sort(bool freeze); bool freeze_sort(bool freeze);
selection selected() const; ///<Get the indexs of all the selected items selection selected() const; ///<Get the absolute indexs of all the selected items
void show_header(bool); void show_header(bool);
bool visible_header() const; bool visible_header() const;
void move_select(bool upwards); ///<Selects an item besides the current selected item. void move_select(bool upwards); ///<Selects an item besides the current selected item in the display.
size_type size_categ() const; ///<Get the number of categories size_type size_categ() const; ///<Get the number of categories
size_type size_item() const; ///<The number of items in the default category size_type size_item() const; ///<The number of items in the default category
@ -557,6 +599,7 @@ By \a clicking on a header the list get \a reordered, first up, and then down al
void enable_single(bool for_selection, bool category_limited); void enable_single(bool for_selection, bool category_limited);
void disable_single(bool for_selection); void disable_single(bool for_selection);
export_options& def_export_options();
private: private:
drawerbase::listbox::essence_t & _m_ess() const; drawerbase::listbox::essence_t & _m_ess() const;
nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const; nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const;

View File

@ -1,4 +1,4 @@
/* /**
* A Menu implementation * A Menu implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com)
@ -139,16 +139,16 @@ namespace nana
void clear(); ///< Erases all of the items. void clear(); ///< Erases all of the items.
/// Closes the menu. It does not destroy the menu; just close the window for the menu. /// Closes the menu. It does not destroy the menu; just close the window for the menu.
void close(); void close();
void image(std::size_t index, const paint::image& icon); void image(std::size_t pos, const paint::image& icon);
void check_style(std::size_t index, checks); void check_style(std::size_t pos, checks);
void checked(std::size_t index, bool); void checked(std::size_t pos, bool);
bool checked(std::size_t index) const; bool checked(std::size_t pos) const;
void enabled(std::size_t index, bool);///< Enables or disables the mouse or keyboard input for the item. void enabled(std::size_t pos, bool);///< Enables or disables the mouse or keyboard input for the item.
bool enabled(std::size_t index) const; bool enabled(std::size_t pos) const;
void erase(std::size_t index); ///< Removes the item void erase(std::size_t pos); ///< Removes the item
bool link(std::size_t index, menu& menu_obj);///< Link a menu to the item as a sub menu. bool link(std::size_t pos, menu& menu_obj);///< Link a menu to the item as a sub menu.
menu * link(std::size_t index); ///< Retrieves a linked sub menu of the item. menu * link(std::size_t pos); ///< Retrieves a linked sub menu of the item.
menu *create_sub_menu(std::size_t index); menu *create_sub_menu(std::size_t pos);
void popup(window owner, int x, int y); ///< Popup the menu at the owner window. void popup(window owner, int x, int y); ///< Popup the menu at the owner window.
void popup_await(window owner, int x, int y); void popup_await(window owner, int x, int y);
void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item. void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item.
@ -171,7 +171,6 @@ namespace nana
const pat::cloneable<renderer_interface>& renderer() const; const pat::cloneable<renderer_interface>& renderer() const;
private: private:
void _m_destroy_menu_window();
void _m_popup(window, int x, int y, bool called_by_menubar); void _m_popup(window, int x, int y, bool called_by_menubar);
private: private:
implement * impl_; implement * impl_;

View File

@ -24,12 +24,16 @@ namespace nana
class item_renderer class item_renderer
{ {
public: public:
enum state_t{state_normal, state_highlight, state_selected}; enum class state
typedef nana::paint::graphics& graph_reference; {
normal, highlighted, selected
};
using graph_reference = paint::graphics&;
item_renderer(window, graph_reference); item_renderer(window, graph_reference);
virtual void background(const nana::point& pos, const nana::size& size, state_t); virtual void background(const point&, const ::nana::size&, state);
virtual void caption(int x, int y, const nana::string& text); virtual void caption(const point&, const ::nana::string&);
private: private:
window handle_; window handle_;
graph_reference graph_; graph_reference graph_;
@ -61,7 +65,6 @@ namespace nana
bool _m_popup_menu(); bool _m_popup_menu();
void _m_total_close(); void _m_total_close();
bool _m_close_menu(); bool _m_close_menu();
void _m_unload_menu_window();
std::size_t _m_item_by_pos(const ::nana::point&); std::size_t _m_item_by_pos(const ::nana::point&);
bool _m_track_mouse(const ::nana::point&); bool _m_track_mouse(const ::nana::point&);
void _m_draw(); void _m_draw();

View File

@ -1,4 +1,4 @@
/* /**
* A Panel Implementation * A Panel Implementation
* Nana C++ Library(http://www.nanaro.org) * Nana C++ Library(http://www.nanaro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -8,8 +8,10 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/panel.hpp * @file: nana/gui/widgets/panel.hpp
* @author: Jinhao
* @contributors: Ariel Vina-Rodriguez
* *
* @brief: panel is a widget used for placing some widgets. * @brief panel is a widget used for placing some widgets.
*/ */
#ifndef NANA_GUI_WIDGETS_PANEL_HPP #ifndef NANA_GUI_WIDGETS_PANEL_HPP
@ -44,11 +46,13 @@ namespace nana
panel(window wd, bool visible) panel(window wd, bool visible)
{ {
this->create(wd, rectangle(), visible); this->create(wd, rectangle(), visible);
this->bgcolor(API::bgcolor(wd));
} }
panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true) panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true)
{ {
this->create(wd, r, visible); this->create(wd, r, visible);
this->bgcolor(API::bgcolor(wd));
} }
bool transparent() const bool transparent() const

View File

@ -1,4 +1,4 @@
/* /**
* A Picture Implementation * A Picture Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -9,7 +9,7 @@
* *
* @file: nana/gui/widgets/picture.hpp * @file: nana/gui/widgets/picture.hpp
* *
* Used for showing a picture * @brief Used for showing a picture
*/ */
#ifndef NANA_GUI_WIDGET_PICTURE_HPP #ifndef NANA_GUI_WIDGET_PICTURE_HPP
#define NANA_GUI_WIDGET_PICTURE_HPP #define NANA_GUI_WIDGET_PICTURE_HPP
@ -34,7 +34,7 @@ namespace nana
void attached(widget_reference, graph_reference) override; void attached(widget_reference, graph_reference) override;
private: private:
void refresh(graph_reference) override; void refresh(graph_reference) override;
void _m_draw_background(); void _m_draw_background(unsigned,unsigned);
private: private:
implement * const impl_; implement * const impl_;
}; };

View File

@ -1,4 +1,4 @@
/* /**
* A Progress Indicator Implementation * A Progress Indicator Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)

View File

@ -1,4 +1,4 @@
/* /**
* A Scroll Implementation * A Scroll Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -8,6 +8,7 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/scroll.hpp * @file: nana/gui/widgets/scroll.hpp
* @contributors: Ariel Vina-Rodriguez
*/ */
#ifndef NANA_GUI_WIDGET_SCROLL_HPP #ifndef NANA_GUI_WIDGET_SCROLL_HPP
#define NANA_GUI_WIDGET_SCROLL_HPP #define NANA_GUI_WIDGET_SCROLL_HPP
@ -49,17 +50,17 @@ namespace nana
struct metrics_type struct metrics_type
{ {
typedef std::size_t size_type; using size_type = std::size_t;
size_type peak; size_type peak; ///< the whole total
size_type range; size_type range; ///< how many is shonw on a page, that is, How many to scroll after click on first or second
size_type step; size_type step; ///< how many to scroll by click in forward or backward
size_type value; size_type value; ///< current offset calculated from the very beginnig
buttons what; buttons what;
bool pressed; bool pressed;
size_type scroll_length; size_type scroll_length; ///< the lenght in pixels of the central button show how many of the total (peak) is shonw (range)
int scroll_pos; int scroll_pos; ///< in pixels, and correspond to the offsset from the very beginning (value)
int scroll_mouse_offset; int scroll_mouse_offset;
metrics_type(); metrics_type();
@ -70,11 +71,11 @@ namespace nana
public: public:
struct states struct states
{ {
enum{none, highlight, actived, selected}; enum{ none, highlight, actived, selected };
}; };
typedef nana::paint::graphics& graph_reference; using graph_reference = paint::graphics&;
const static unsigned fixedsize = 16; const static unsigned fixedsize = 16; // make it part of a new "metric" in the widget_scheme
drawer(metrics_type& m); drawer(metrics_type& m);
void set_vertical(bool); void set_vertical(bool);
@ -114,7 +115,7 @@ namespace nana
void peak(size_type s) void peak(size_type s)
{ {
if(graph_ && (metrics_.peak != s)) if (graph_ && (metrics_.peak != s))
{ {
metrics_.peak = s; metrics_.peak = s;
API::refresh_window(widget_->handle()); API::refresh_window(widget_->handle());
@ -123,10 +124,10 @@ namespace nana
void value(size_type s) void value(size_type s)
{ {
if(s + metrics_.range > metrics_.peak) if (s + metrics_.range > metrics_.peak)
s = metrics_.peak - metrics_.range; s = metrics_.peak - metrics_.range;
if(graph_ && (metrics_.value != s)) if (graph_ && (metrics_.value != s))
{ {
metrics_.value = s; metrics_.value = s;
_m_emit_value_changed(); _m_emit_value_changed();
@ -137,7 +138,7 @@ namespace nana
void range(size_type s) void range(size_type s)
{ {
if(graph_ && (metrics_.range != s)) if (graph_ && (metrics_.range != s))
{ {
metrics_.range = s; metrics_.range = s;
API::refresh_window(widget_->handle()); API::refresh_window(widget_->handle());
@ -151,31 +152,31 @@ namespace nana
bool make_step(bool forward, unsigned multiple) bool make_step(bool forward, unsigned multiple)
{ {
if(graph_) if (graph_)
{ {
size_type step = (multiple > 1 ? metrics_.step * multiple : metrics_.step); size_type step = (multiple > 1 ? metrics_.step * multiple : metrics_.step);
size_type value = metrics_.value; size_type value = metrics_.value;
if(forward) if (forward)
{ {
size_type maxv = metrics_.peak - metrics_.range; size_type maxv = metrics_.peak - metrics_.range;
if(metrics_.peak > metrics_.range && value < maxv) if (metrics_.peak > metrics_.range && value < maxv)
{ {
if(maxv - value >= step) if (maxv - value >= step)
value += step; value += step;
else else
value = maxv; value = maxv;
} }
} }
else if(value) else if (value)
{ {
if(value > step) if (value > step)
value -= step; value -= step;
else else
value = 0; value = 0;
} }
size_type cmpvalue = metrics_.value; size_type cmpvalue = metrics_.value;
metrics_.value = value; metrics_.value = value;
if(value != cmpvalue) if (value != cmpvalue)
{ {
_m_emit_value_changed(); _m_emit_value_changed();
return true; return true;
@ -221,24 +222,24 @@ namespace nana
void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override
{ {
bool redraw = false; bool redraw = false;
if(metrics_.pressed && (metrics_.what == buttons::scroll)) if (metrics_.pressed && (metrics_.what == buttons::scroll))
{ {
size_type cmpvalue = metrics_.value; size_type cmpvalue = metrics_.value;
drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x)); drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x));
if(cmpvalue != metrics_.value) if (cmpvalue != metrics_.value)
_m_emit_value_changed(); _m_emit_value_changed();
redraw = true; redraw = true;
} }
else else
{ {
buttons what = drawer_.what(graph, arg.pos); buttons what = drawer_.what(graph, arg.pos);
if(metrics_.what != what) if (metrics_.what != what)
{ {
redraw = true; redraw = true;
metrics_.what = what; metrics_.what = what;
} }
} }
if(redraw) if (redraw)
{ {
drawer_.draw(graph, metrics_.what); drawer_.draw(graph, metrics_.what);
API::lazy_refresh(); API::lazy_refresh();
@ -247,11 +248,11 @@ namespace nana
void mouse_down(graph_reference graph, const arg_mouse& arg) override void mouse_down(graph_reference graph, const arg_mouse& arg) override
{ {
if(arg.left_button) if (arg.left_button)
{ {
metrics_.pressed = true; metrics_.pressed = true;
metrics_.what = drawer_.what(graph, arg.pos); metrics_.what = drawer_.what(graph, arg.pos);
switch(metrics_.what) switch (metrics_.what)
{ {
case buttons::first: case buttons::first:
case buttons::second: case buttons::second:
@ -265,13 +266,13 @@ namespace nana
break; break;
case buttons::forward: case buttons::forward:
case buttons::backward: case buttons::backward:
{ {
size_type cmpvalue = metrics_.value; size_type cmpvalue = metrics_.value;
drawer_.auto_scroll(); drawer_.auto_scroll();
if(cmpvalue != metrics_.value) if (cmpvalue != metrics_.value)
_m_emit_value_changed(); _m_emit_value_changed();
} }
break; break;
default: //Ignore buttons::none default: //Ignore buttons::none
break; break;
} }
@ -294,7 +295,7 @@ namespace nana
void mouse_leave(graph_reference graph, const arg_mouse&) override void mouse_leave(graph_reference graph, const arg_mouse&) override
{ {
if(metrics_.pressed) return; if (metrics_.pressed) return;
metrics_.what = buttons::none; metrics_.what = buttons::none;
drawer_.draw(graph, buttons::none); drawer_.draw(graph, buttons::none);
@ -303,7 +304,7 @@ namespace nana
void mouse_wheel(graph_reference graph, const arg_wheel& arg) override void mouse_wheel(graph_reference graph, const arg_wheel& arg) override
{ {
if(make_step(arg.upwards == false, 3)) if (make_step(arg.upwards == false, 3))
{ {
drawer_.draw(graph, metrics_.what); drawer_.draw(graph, metrics_.what);
API::lazy_refresh(); API::lazy_refresh();
@ -333,7 +334,7 @@ namespace nana
/// Provides a way to display an object which is larger than the window's client area. /// Provides a way to display an object which is larger than the window's client area.
template<bool Vertical> template<bool Vertical>
class scroll class scroll // add a widget scheme?
: public widget_object<category::widget_tag, drawerbase::scroll::trigger<Vertical>, drawerbase::scroll::scroll_events<Vertical>> : public widget_object<category::widget_tag, drawerbase::scroll::trigger<Vertical>, drawerbase::scroll::scroll_events<Vertical>>
{ {
typedef widget_object<category::widget_tag, drawerbase::scroll::trigger<Vertical> > base_type; typedef widget_object<category::widget_tag, drawerbase::scroll::trigger<Vertical> > base_type;
@ -345,29 +346,29 @@ namespace nana
/// \brief The construct that creates a widget. /// \brief The construct that creates a widget.
/// @param wd A handle to the parent window of the widget being created. /// @param wd A handle to the parent window of the widget being created.
/// @param visible specifying the visible after creating. /// @param visible specify the visibility after creation.
scroll(window wd, bool visible) scroll(window wd, bool visible)
{ {
this->create(wd, rectangle(), visible); this->create(wd, rectangle(), visible); // add a widget scheme? and take some colors from these wd?
} }
/// \brief The construct that creates a widget. /// \brief The construct that creates a widget.
/// @param wd A handle to the parent window of the widget being created. /// @param wd A handle to the parent window of the widget being created.
/// @param r the size and position of the widget in its parent window coordinate. /// @param r the size and position of the widget in its parent window coordinate.
/// @param visible specifying the visible after creating. /// @param visible specify the visibility after creation.
scroll(window wd, const rectangle& r, bool visible = true) scroll(window wd, const rectangle& r, bool visible = true)
{ {
this->create(wd, r, visible); this->create(wd, r, visible);
} }
/// \brief Determines whether it is scrollable. /// \brief Determines whether it is scrollable.
/// @param for_less whether it can be scrolled for a less value. /// @param for_less whether it can be scrolled for a less value (backward or "up" if true, forward or "down" if false).
bool scrollable(bool for_less) const bool scrollable(bool for_less) const
{ {
auto & m = this->get_drawer_trigger().metrics(); auto & m = this->get_drawer_trigger().metrics();
return (for_less ? (0 != m.value) : (m.value < m.peak - m.range)); return (for_less ? (0 != m.value) : (m.value < m.peak - m.range));
} }
/// the whole total (peak)
size_type amount() const size_type amount() const
{ {
return this->get_drawer_trigger().metrics().peak; return this->get_drawer_trigger().metrics().peak;
@ -378,7 +379,7 @@ namespace nana
return this->get_drawer_trigger().peak(Max); return this->get_drawer_trigger().peak(Max);
} }
/// Get the range of the widget. /// Get the range of the widget (how many is shonw on a page, that is, How many to scroll after click on first or second)
size_type range() const size_type range() const
{ {
return this->get_drawer_trigger().metrics().range; return this->get_drawer_trigger().metrics().range;
@ -390,7 +391,7 @@ namespace nana
return this->get_drawer_trigger().range(r); return this->get_drawer_trigger().range(r);
} }
/// \brief Get the value. /// \brief Get the value (current offset calculated from the very beginnig)
/// @return the value. /// @return the value.
size_type value() const size_type value() const
{ {
@ -419,12 +420,12 @@ namespace nana
return this->get_drawer_trigger().step(s); return this->get_drawer_trigger().step(s);
} }
/// \brief Increase/decrease values by a step. /// \brief Increase/decrease values by a step (alternativelly by some number of steps).
/// @param forward it determines whether increase or decrease. /// @param forward it determines whether increase or decrease.
/// @return true if the value is changed. /// @return true if the value is changed.
bool make_step(bool forward) bool make_step(bool forward, unsigned steps = 1)
{ {
if(this->get_drawer_trigger().make_step(forward, 1)) if (this->get_drawer_trigger().make_step(forward, steps))
{ {
API::refresh_window(this->handle()); API::refresh_window(this->handle());
return true; return true;
@ -437,13 +438,17 @@ namespace nana
/// @return true if the vlaue is changed. /// @return true if the vlaue is changed.
bool make_scroll(bool forward) bool make_scroll(bool forward)
{ {
if(this->get_drawer_trigger().make_step(forward, 3)) return this->make_step(forward, 3); // set this 3 in the metrics of the widget scheme ?
{
API::refresh_window(this->handle());
return true;
}
return false;
} }
/// \brief Increase/decrease values by a page as if it is scrolled page up.
/// @param forward it determines whether increase or decrease.
/// @return true if the vlaue is changed.
bool make_page_scroll(bool forward)
{
return this->make_step(forward, range() - 1);
}
};//end class scroll };//end class scroll
}//end namespace nana }//end namespace nana
#endif #endif

View File

@ -157,7 +157,8 @@ namespace nana{ namespace widgets
void set_accept(std::function<bool(char_type)>); void set_accept(std::function<bool(char_type)>);
void set_accept(accepts); void set_accept(accepts);
bool respone_keyboard(char_type); bool respond_char(char_type);
bool respond_key(char_type);
void typeface_changed(); void typeface_changed();
@ -227,7 +228,6 @@ namespace nana{ namespace widgets
void del(); void del();
void backspace(bool record_undo = true); void backspace(bool record_undo = true);
void undo(bool reverse); void undo(bool reverse);
bool move(nana::char_t);
void move_ns(bool to_north); //Moves up and down void move_ns(bool to_north); //Moves up and down
void move_left(); void move_left();
void move_right(); void move_right();

View File

@ -1,4 +1,4 @@
/* /**
* A Slider Implementation * A Slider Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)

View File

@ -1,4 +1,4 @@
/* /**
* A Spin box widget * A Spin box widget
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)

View File

@ -1,4 +1,4 @@
/* /**
* A Tabbar implementation * A Tabbar implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -7,8 +7,8 @@
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/tabbar.hpp * @file: nana/gui/widgets/tabbar.hpp
* @brief: A tabbar contains tab items and toolbox for scrolling, closing, selecting items. * @brief A tabbar contains tab items and toolbox for scrolling, closing, selecting items.
* *
*/ */
#ifndef NANA_GUI_WIDGET_TABBAR_HPP #ifndef NANA_GUI_WIDGET_TABBAR_HPP

View File

@ -1,4 +1,4 @@
/* /**
* A Textbox Implementation * A Textbox Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)

View File

@ -1,4 +1,4 @@
/* /**
* A Toolbar Implementation * A Toolbar Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)

View File

@ -1,4 +1,4 @@
/* /**
* A Tree Box Implementation * A Tree Box Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -7,12 +7,12 @@
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/treebox.hpp * @file: nana/gui/widgets/treebox.hpp
* @brief: * @brief
* The treebox organizes the nodes by a key string. * The treebox organizes the nodes by a key string.
* The treebox would have a vertical scrollbar if the node * The treebox would have a vertical scrollbar if there are too many nodes
* is too many to display. And it does not have a horizontal scrollbar, * to display. It does not have an horizontal scrollbar:
* the widget will adjust the node's displaying position for fitting. * the widget will adjust the node's displaying position for fitting.
*/ */
#ifndef NANA_GUI_WIDGETS_TREEBOX_HPP #ifndef NANA_GUI_WIDGETS_TREEBOX_HPP
@ -332,12 +332,13 @@ namespace nana
}//end namespace treebox }//end namespace treebox
}//end namespace drawerbase }//end namespace drawerbase
struct arg_treebox /// a type of treebox event parameter
struct arg_treebox
: public event_arg : public event_arg
{ {
treebox& widget; treebox& widget; ///< where the event occurs
drawerbase::treebox::item_proxy & item; drawerbase::treebox::item_proxy & item; ///< the operated node
bool operated; bool operated; ///< operation state of the event
arg_treebox(treebox&, drawerbase::treebox::item_proxy&, bool operated); arg_treebox(treebox&, drawerbase::treebox::item_proxy&, bool operated);
}; };
@ -349,28 +350,30 @@ namespace nana
struct treebox_events struct treebox_events
: public general_events : public general_events
{ {
basic_event<arg_treebox> expanded; basic_event<arg_treebox> expanded; ///< a user expands or shrinks a node
basic_event<arg_treebox> checked; basic_event<arg_treebox> checked; ///< a user checks or unchecks a node
basic_event<arg_treebox> selected; basic_event<arg_treebox> selected; ///< a user selects or unselects a node
basic_event<arg_treebox> hovered; basic_event<arg_treebox> hovered; ///< a user moves the cursor over a node
}; };
}//end namespace treebox }//end namespace treebox
}//end namespace drawerbase }//end namespace drawerbase
/// Displays a hierarchical list of items, such as the files and directories on a disk. /// \brief Displays a hierarchical list of items, such as the files and directories on a disk.
class treebox /// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm)
class treebox
:public widget_object < category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events> :public widget_object < category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events>
{ {
public: public:
/// A type refers to the item and also used to iterate through the node. /// A type refers to the item and is also used to iterate through the nodes.
typedef drawerbase::treebox::item_proxy item_proxy; typedef drawerbase::treebox::item_proxy item_proxy;
/// state images for the node
typedef drawerbase::treebox::node_image_tag node_image_type; typedef drawerbase::treebox::node_image_tag node_image_type;
/// The interface of treebox item renderer /// The interface of treebox user-defined item renderer
typedef drawerbase::treebox::renderer_interface renderer_interface; typedef drawerbase::treebox::renderer_interface renderer_interface;
/// The interface of treebox compset_placer /// The interface of treebox compset_placer to define the position of node components
typedef drawerbase::treebox::compset_placer_interface compset_placer_interface; typedef drawerbase::treebox::compset_placer_interface compset_placer_interface;
/// The default constructor without creating the widget. /// The default constructor without creating the widget.
@ -378,7 +381,7 @@ namespace nana
/// \brief The construct that creates a widget. /// \brief The construct that creates a widget.
/// @param wd A handle to the parent window of the widget being created. /// @param wd A handle to the parent window of the widget being created.
/// @param visible specifying the visible after creating. /// @param visible specifying the visibility after creating.
treebox(window wd, bool visible); treebox(window wd, bool visible);
/// \brief The construct that creates a widget. /// \brief The construct that creates a widget.
@ -388,16 +391,16 @@ namespace nana
treebox(window, const nana::rectangle& = rectangle(), bool visible = true); treebox(window, const nana::rectangle& = rectangle(), bool visible = true);
template<typename ItemRenderer> template<typename ItemRenderer>
treebox & renderer(const ItemRenderer & rd) treebox & renderer(const ItemRenderer & rd) ///< set user-defined node renderer
{ {
get_drawer_trigger().renderer(::nana::pat::cloneable<renderer_interface>(rd)); get_drawer_trigger().renderer(::nana::pat::cloneable<renderer_interface>(rd));
return *this; return *this;
} }
const nana::pat::cloneable<renderer_interface> & renderer() const; const nana::pat::cloneable<renderer_interface> & renderer() const; ///< get user-defined node renderer
template<typename Placer> template<typename Placer>
treebox & placer(const Placer & r) treebox & placer(const Placer & r) ///< location of a node components
{ {
get_drawer_trigger().placer(::nana::pat::cloneable<compset_placer_interface>(r)); get_drawer_trigger().placer(::nana::pat::cloneable<compset_placer_interface>(r));
return *this; return *this;
@ -406,38 +409,51 @@ namespace nana
const nana::pat::cloneable<compset_placer_interface> & placer() const; const nana::pat::cloneable<compset_placer_interface> & placer() const;
/// \brief Eanble the widget to be draws automatically when it is operated. /// \brief Eanble the widget to be draws automatically when it is operated.
///
/// The treebox automatically redraws after certain operations, but,
/// under some circumstances, it is good to disable the automatic drawing mode,
/// for example, before adding nodes in a loop, disable the mode to avoiding
/// frequent and useless refresh for better performance, and then, after
/// the operations, enable the automatic redraw mode again.
/// @param bool whether to enable. /// @param bool whether to enable.
void auto_draw(bool); void auto_draw(bool);
/// \brief Enable the checkbox for each item of the widget. /// \brief Enable the checkboxs for each item of the widget.
/// @param bool wheter to enable. /// @param bool indicates whether to show or hide the checkboxs.
treebox & checkable(bool enable); treebox & checkable(bool enable);
/// Determinte whether the checkbox is enabled.
bool checkable() const; bool checkable() const; ///< Determinte whether the checkboxs are enabled.
node_image_type& icon(const nana::string& id) const; /// \brief Creates an icon scheme with the specified name.
///
/// The icon scheme includes 3 images for node states.
/// These states are 'normal', 'hovered' and 'expanded'.
/// If 'hovered' or 'expanded' are not set, it uses 'normal' state image for these 2 states.
/// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm)
node_image_type& icon(const nana::string& id ///< the name of an icon scheme. If the name is not existing, it creates a new scheme for the name.
) const;
void icon_erase(const nana::string& id); void icon_erase(const nana::string& id);
item_proxy find(const nana::string& keypath); ///< Find an item though a specified keypath. item_proxy find(const nana::string& keypath); ///< Find an item though a specified keypath.
/// Inserts a new node to treebox, but if the keypath exists returns the existing node. /// Inserts a new node to treebox, but if the keypath exists returns the existing node.
item_proxy insert(const nana::string& path_key, ///< specifies the node hierarchical item_proxy insert(const nana::string& path_key, ///< specifies the node hierarchy
nana::string title ///< used for displaying nana::string title ///< used for displaying
); );
/// Inserts a new node to treebox, but if the keypath exists returns the existing node. /// Inserts a new node to treebox, but if the keypath exists returns the existing node.
item_proxy insert( item_proxy pos, ///< the parent item node item_proxy insert( item_proxy pos, ///< the parent item node
const nana::string& key, ///< specifies the new node const nana::string& key, ///< specifies the new node
nana::string title ///< used for displaying. nana::string title ///< title used for displaying in the new node.
); );
item_proxy erase(item_proxy i); item_proxy erase(item_proxy i); ///< Removes the node at pos and return the Item proxy following the removed node
void erase(const nana::string& keypath); void erase(const nana::string& keypath); ///< Removes the node by the key path.
nana::string make_key_path(item_proxy i, const nana::string& splitter) const;///<returns the key path nana::string make_key_path(item_proxy i, const nana::string& splitter) const;///<returns the key path
item_proxy selected() const; item_proxy selected() const; ///< returns the selected node
};//end class treebox };//end class treebox
}//end namespace nana }//end namespace nana
#endif #endif

View File

@ -1,4 +1,4 @@
/* /**
* The fundamental widget class implementation * The fundamental widget class implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -409,6 +409,16 @@ namespace nana
{ {
API::map_through_widgets(handle(), drawable); API::map_through_widgets(handle(), drawable);
} }
void outline_size(const ::nana::size& sz)
{
API::window_outline_size(handle(), sz);
}
::nana::size outline_size() const
{
return API::window_outline_size(handle());
}
protected: protected:
DrawerTrigger& get_drawer_trigger() DrawerTrigger& get_drawer_trigger()
{ {

View File

@ -22,10 +22,10 @@ namespace nana
virtual ~key_interface(){} virtual ~key_interface(){}
virtual bool same_type(const key_interface*) const = 0; virtual bool same_type(const key_interface*) const = 0;
virtual bool compare(const key_interface*) const = 0; virtual bool compare(const key_interface*) const = 0; ///< is this key less than right key? [call it less(rk), less_than(rk) or compare_less(rk)?: if (lk.less_than(rk )) ]
}; //end class key_interface }; //end class key_interface
//Use less compare for equal compare //Use less compare for equal compare [call it equal_by_less()?]
inline bool pred_equal_by_less(const key_interface * left, const key_interface* right) inline bool pred_equal_by_less(const key_interface * left, const key_interface* right)
{ {
return (left->compare(right) == false) && (right->compare(left) == false); return (left->compare(right) == false) && (right->compare(left) == false);

View File

@ -1,3 +1,15 @@
/*
* Bitmap Format Graphics Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/paint/detail/image_bmp.hpp
* @contributors: Ryan Gonzalez
*/
#ifndef NANA_PAINT_DETAIL_IMAGE_BMP_HPP #ifndef NANA_PAINT_DETAIL_IMAGE_BMP_HPP
#define NANA_PAINT_DETAIL_IMAGE_BMP_HPP #define NANA_PAINT_DETAIL_IMAGE_BMP_HPP

View File

@ -1,6 +1,7 @@
/* /*
* Paint Image Implementation * Paint Image Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -39,6 +40,8 @@ namespace paint
bool empty() const; bool empty() const;
operator unspecified_bool_t() const; operator unspecified_bool_t() const;
void close(); void close();
bool alpha() const;
nana::size size() const; nana::size size() const;
void paste(graphics& dst, int x, int y) const; void paste(graphics& dst, int x, int y) const;
void paste(const nana::rectangle& r_src, graphics& dst, const point& p_dst) const;///< Paste the area of picture specified by r_src into the destination graphics specified by dst at position p_dst. void paste(const nana::rectangle& r_src, graphics& dst, const point& p_dst) const;///< Paste the area of picture specified by r_src into the destination graphics specified by dst at position p_dst.

View File

@ -14,7 +14,13 @@
#define NANA_SYSTEM_DATAEXCH_HPP #define NANA_SYSTEM_DATAEXCH_HPP
#include <nana/basic_types.hpp> #include <nana/basic_types.hpp>
namespace nana{ namespace system{ namespace nana{
namespace paint{
class graphics;
}
namespace system{
/// a data exchange mechanism through Windows Clipboard, X11 Selection. /// a data exchange mechanism through Windows Clipboard, X11 Selection.
class dataexch class dataexch
{ {
@ -26,6 +32,7 @@ namespace nana{ namespace system{
void set(const nana::char_t* text); void set(const nana::char_t* text);
void set(const nana::string& text); void set(const nana::string& text);
bool set(const nana::paint::graphics& g);
void get(nana::string& str); void get(nana::string& str);
private: private:
bool _m_set(unsigned type, const void* buf, std::size_t size); bool _m_set(unsigned type, const void* buf, std::size_t size);

View File

@ -8,6 +8,7 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/basic_types.cpp * @file: nana/basic_types.cpp
* @contributos: Jan
*/ */
#include <nana/basic_types.hpp> #include <nana/basic_types.hpp>
@ -18,6 +19,8 @@
#endif #endif
#include <algorithm> #include <algorithm>
#include <stdexcept>
namespace nana namespace nana
{ {
//class color //class color
@ -736,12 +739,12 @@ namespace nana
int rectangle::right() const int rectangle::right() const
{ {
return static_cast<int>(x + width); return x + static_cast<int>(width);
} }
int rectangle::bottom() const int rectangle::bottom() const
{ {
return static_cast<int>(y + height); return y + static_cast<int>(height);
} }
bool rectangle::is_hit(int pos_x, int pos_y) const bool rectangle::is_hit(int pos_x, int pos_y) const
@ -753,7 +756,7 @@ namespace nana
bool rectangle::is_hit(const point& pos) const bool rectangle::is_hit(const point& pos) const
{ {
return (x <= pos.x && pos.x < x + static_cast<int>(width)) && return (x <= pos.x && pos.x < x + static_cast<int>(width)) &&
(y <= pos.y && pos.y < y + static_cast<int>(height)); (y <= pos.y && pos.y < y + static_cast<int>(height));
} }
bool rectangle::empty() const bool rectangle::empty() const
@ -762,65 +765,65 @@ namespace nana
} }
//end struct rectangle //end struct rectangle
//class area_rotator //class rectangle_rotator
area_rotator::area_rotator(bool rotated, const ::nana::rectangle& area) rectangle_rotator::rectangle_rotator(bool rotated, const ::nana::rectangle& area)
: rotated_(rotated), : rotated_(rotated),
area_(area) area_(area)
{} {}
int area_rotator::x() const int rectangle_rotator::x() const
{ {
return (rotated_ ? area_.y : area_.x); return (rotated_ ? area_.y : area_.x);
} }
int & area_rotator::x_ref() int & rectangle_rotator::x_ref()
{ {
return (rotated_ ? area_.y : area_.x); return (rotated_ ? area_.y : area_.x);
} }
int area_rotator::y() const int rectangle_rotator::y() const
{ {
return (rotated_ ? area_.x : area_.y); return (rotated_ ? area_.x : area_.y);
} }
int & area_rotator::y_ref() int & rectangle_rotator::y_ref()
{ {
return (rotated_ ? area_.x : area_.y); return (rotated_ ? area_.x : area_.y);
} }
unsigned area_rotator::w() const unsigned rectangle_rotator::w() const
{ {
return (rotated_ ? area_.height : area_.width); return (rotated_ ? area_.height : area_.width);
} }
unsigned & area_rotator::w_ref() unsigned & rectangle_rotator::w_ref()
{ {
return (rotated_ ? area_.height : area_.width); return (rotated_ ? area_.height : area_.width);
} }
unsigned area_rotator::h() const unsigned rectangle_rotator::h() const
{ {
return (rotated_ ? area_.width : area_.height); return (rotated_ ? area_.width : area_.height);
} }
unsigned & area_rotator::h_ref() unsigned & rectangle_rotator::h_ref()
{ {
return (rotated_ ? area_.width : area_.height); return (rotated_ ? area_.width : area_.height);
} }
int area_rotator::right() const int rectangle_rotator::right() const
{ {
return (rotated_ ? area_.y + static_cast<int>(area_.height) : area_.x + static_cast<int>(area_.width)); return (rotated_ ? area_.y + static_cast<int>(area_.height) : area_.x + static_cast<int>(area_.width));
} }
int area_rotator::bottom() const int rectangle_rotator::bottom() const
{ {
return (rotated_ ? area_.x + static_cast<int>(area_.width) : area_.y + static_cast<int>(area_.height)); return (rotated_ ? area_.x + static_cast<int>(area_.width) : area_.y + static_cast<int>(area_.height));
} }
const ::nana::rectangle& area_rotator::result() const const ::nana::rectangle& rectangle_rotator::result() const
{ {
return area_; return area_;
} }
//end class area_rotator //end class rectangle_rotator
} }

View File

@ -23,7 +23,8 @@
#include PLATFORM_SPEC_HPP #include PLATFORM_SPEC_HPP
#endif #endif
#if defined(NANA_MINGW) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) //Implement workarounds for GCC/MinGW which version is below 4.8.2
#if defined(STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED)
#include <sstream> #include <sstream>
namespace std namespace std
{ {

View File

@ -1,7 +1,7 @@
/* /*
* Platform Specification Implementation * Platform Specification Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Nana Software License, Version 1.0. * Distributed under the Nana Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -841,7 +841,10 @@ namespace detail
if((attr.your_event_mask & addr->input_context_event_mask) == addr->input_context_event_mask) if((attr.your_event_mask & addr->input_context_event_mask) == addr->input_context_event_mask)
{ {
XSetWindowAttributes new_attr; XSetWindowAttributes new_attr;
new_attr.event_mask = (attr.your_event_mask & ~addr->input_context_event_mask);
//Don't remove the KeyPress and KeyRelease mask(0x3), otherwise the window will not receive
//Keyboard events after destroying caret
new_attr.event_mask = (attr.your_event_mask & ~(addr->input_context_event_mask & (~0x3)));
::XChangeWindowAttributes(display_, reinterpret_cast<Window>(wd), CWEventMask, &new_attr); ::XChangeWindowAttributes(display_, reinterpret_cast<Window>(wd), CWEventMask, &new_attr);
} }
} }

View File

@ -347,6 +347,7 @@ namespace nana
flags.destroying = false; flags.destroying = false;
flags.borderless = false; flags.borderless = false;
flags.make_bground_declared = false; flags.make_bground_declared = false;
flags.ignore_menubar_focus = false;
visible = false; visible = false;
@ -355,7 +356,6 @@ namespace nana
effect.bground_fade_rate = 0; effect.bground_fade_rate = 0;
together.caret = nullptr; together.caret = nullptr;
together.attached_events = nullptr;
extra_width = extra_height = 0; extra_width = extra_height = 0;
@ -368,16 +368,15 @@ namespace nana
bool basic_window::set_events(const std::shared_ptr<general_events>& p) bool basic_window::set_events(const std::shared_ptr<general_events>& p)
{ {
if (together.attached_events) if (together.events_ptr)
return false; return false;
together.events_ptr = p; together.events_ptr = p;
together.attached_events = p.get();
return true; return true;
} }
general_events * basic_window::get_events() const general_events * basic_window::get_events() const
{ {
return together.attached_events; return together.events_ptr.get();
} }
//end struct basic_window //end struct basic_window
}//end namespace detail }//end namespace detail

View File

@ -146,6 +146,9 @@ namespace nana
void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg) void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg)
{ {
auto retain = wd->together.events_ptr;
auto evts_ptr = retain.get();
switch (evt_code) switch (evt_code)
{ {
case event_code::click: case event_code::click:
@ -162,35 +165,36 @@ namespace nana
void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&); void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&);
::nana::basic_event<arg_mouse>* evt_addr; ::nana::basic_event<arg_mouse>* evt_addr;
switch (evt_code) switch (evt_code)
{ {
case event_code::click: case event_code::click:
drawer_event_fn = &drawer::click; drawer_event_fn = &drawer::click;
evt_addr = &wd->together.attached_events->click; evt_addr = &evts_ptr->click;
break; break;
case event_code::dbl_click: case event_code::dbl_click:
drawer_event_fn = &drawer::dbl_click; drawer_event_fn = &drawer::dbl_click;
evt_addr = &wd->together.attached_events->dbl_click; evt_addr = &evts_ptr->dbl_click;
break; break;
case event_code::mouse_enter: case event_code::mouse_enter:
drawer_event_fn = &drawer::mouse_enter; drawer_event_fn = &drawer::mouse_enter;
evt_addr = &wd->together.attached_events->mouse_enter; evt_addr = &evts_ptr->mouse_enter;
break; break;
case event_code::mouse_move: case event_code::mouse_move:
drawer_event_fn = &drawer::mouse_move; drawer_event_fn = &drawer::mouse_move;
evt_addr = &wd->together.attached_events->mouse_move; evt_addr = &evts_ptr->mouse_move;
break; break;
case event_code::mouse_leave: case event_code::mouse_leave:
drawer_event_fn = &drawer::mouse_leave; drawer_event_fn = &drawer::mouse_leave;
evt_addr = &wd->together.attached_events->mouse_leave; evt_addr = &evts_ptr->mouse_leave;
break; break;
case event_code::mouse_down: case event_code::mouse_down:
drawer_event_fn = &drawer::mouse_down; drawer_event_fn = &drawer::mouse_down;
evt_addr = &wd->together.attached_events->mouse_down; evt_addr = &evts_ptr->mouse_down;
break; break;
case event_code::mouse_up: case event_code::mouse_up:
drawer_event_fn = &drawer::mouse_up; drawer_event_fn = &drawer::mouse_up;
evt_addr = &wd->together.attached_events->mouse_up; evt_addr = &evts_ptr->mouse_up;
break; break;
default: default:
throw std::runtime_error("Invalid mouse event code"); throw std::runtime_error("Invalid mouse event code");
@ -209,7 +213,7 @@ namespace nana
{ {
wd->drawer.mouse_wheel(*arg); wd->drawer.mouse_wheel(*arg);
if (!draw_only) if (!draw_only)
wd->together.attached_events->mouse_wheel.emit(*arg); evts_ptr->mouse_wheel.emit(*arg);
} }
break; break;
} }
@ -229,19 +233,19 @@ namespace nana
{ {
case event_code::key_press: case event_code::key_press:
drawer_event_fn = &drawer::key_press; drawer_event_fn = &drawer::key_press;
evt_addr = &wd->together.attached_events->key_press; evt_addr = &evts_ptr->key_press;
break; break;
case event_code::key_char: case event_code::key_char:
drawer_event_fn = &drawer::key_char; drawer_event_fn = &drawer::key_char;
evt_addr = &wd->together.attached_events->key_char; evt_addr = &evts_ptr->key_char;
break; break;
case event_code::key_release: case event_code::key_release:
drawer_event_fn = &drawer::key_release; drawer_event_fn = &drawer::key_release;
evt_addr = &wd->together.attached_events->key_release; evt_addr = &evts_ptr->key_release;
break; break;
case event_code::shortkey: case event_code::shortkey:
drawer_event_fn = &drawer::shortkey; drawer_event_fn = &drawer::shortkey;
evt_addr = &wd->together.attached_events->shortkey; evt_addr = &evts_ptr->shortkey;
break; break;
default: default:
throw std::runtime_error("Invalid keyboard event code"); throw std::runtime_error("Invalid keyboard event code");
@ -256,7 +260,7 @@ namespace nana
{ {
auto arg = dynamic_cast<const arg_expose*>(&event_arg); auto arg = dynamic_cast<const arg_expose*>(&event_arg);
if (arg) if (arg)
wd->together.attached_events->expose.emit(*arg); evts_ptr->expose.emit(*arg);
} }
break; break;
case event_code::focus: case event_code::focus:
@ -266,7 +270,7 @@ namespace nana
{ {
wd->drawer.focus(*arg); wd->drawer.focus(*arg);
if (!draw_only) if (!draw_only)
wd->together.attached_events->focus.emit(*arg); evts_ptr->focus.emit(*arg);
} }
break; break;
} }
@ -277,7 +281,7 @@ namespace nana
{ {
wd->drawer.move(*arg); wd->drawer.move(*arg);
if (!draw_only) if (!draw_only)
wd->together.attached_events->move.emit(*arg); evts_ptr->move.emit(*arg);
} }
break; break;
} }
@ -288,7 +292,7 @@ namespace nana
{ {
wd->drawer.resizing(*arg); wd->drawer.resizing(*arg);
if (!draw_only) if (!draw_only)
wd->together.attached_events->resizing.emit(*arg); evts_ptr->resizing.emit(*arg);
} }
break; break;
} }
@ -299,7 +303,7 @@ namespace nana
{ {
wd->drawer.resized(*arg); wd->drawer.resized(*arg);
if (!draw_only) if (!draw_only)
wd->together.attached_events->resized.emit(*arg); evts_ptr->resized.emit(*arg);
} }
break; break;
} }
@ -309,9 +313,9 @@ namespace nana
auto arg = dynamic_cast<const arg_unload*>(&event_arg); auto arg = dynamic_cast<const arg_unload*>(&event_arg);
if (arg && (wd->other.category == category::flags::root)) if (arg && (wd->other.category == category::flags::root))
{ {
auto evt_ptr = dynamic_cast<events_root_extension*>(wd->together.attached_events); auto evt_root = dynamic_cast<events_root_extension*>(evts_ptr);
if (evt_ptr) if (evt_root)
evt_ptr->unload.emit(*arg); evt_root->unload.emit(*arg);
} }
} }
break; break;
@ -320,7 +324,7 @@ namespace nana
{ {
auto arg = dynamic_cast<const arg_destroy*>(&event_arg); auto arg = dynamic_cast<const arg_destroy*>(&event_arg);
if (arg) if (arg)
wd->together.attached_events->destroy.emit(*arg); evts_ptr->destroy.emit(*arg);
} }
break; break;
default: default:

View File

@ -1,7 +1,7 @@
/* /*
* Bedrock Selector * Bedrock Selector
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Nana Software License, Version 1.0. * Distributed under the Nana Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at

View File

@ -21,8 +21,6 @@
#include <nana/detail/linux_X11/platform_spec.hpp> #include <nana/detail/linux_X11/platform_spec.hpp>
#endif #endif
#include <algorithm>
namespace nana namespace nana
{ {
typedef detail::edge_nimbus_renderer<detail::bedrock::core_window_t> edge_nimbus_renderer_t; typedef detail::edge_nimbus_renderer<detail::bedrock::core_window_t> edge_nimbus_renderer_t;
@ -351,12 +349,13 @@ namespace nana
{ {
if(p) if(p)
{ {
auto i = std::find(dynamic_drawing_objects_.begin(), dynamic_drawing_objects_.end(), p); for (auto i = dynamic_drawing_objects_.begin(); i != dynamic_drawing_objects_.end(); ++i)
if (i != dynamic_drawing_objects_.end()) if (*i == p)
{ {
delete (*i); delete (*i);
dynamic_drawing_objects_.erase(i); dynamic_drawing_objects_.erase(i);
} break;
}
} }
} }

View File

@ -41,12 +41,6 @@ namespace nana
reinterpret_cast<detail::docker_interface*>(evt)->get_event()->remove(evt); reinterpret_cast<detail::docker_interface*>(evt)->get_event()->remove(evt);
} }
} }
std::size_t events_operation::size() const
{
lock_guard lock(mutex_);
return register_.size();
}
//end namespace events_operation //end namespace events_operation
}//end namespace detail }//end namespace detail
}//end namespace nana }//end namespace nana

View File

@ -102,27 +102,18 @@ namespace detail
{ {
struct thread_context_cache struct thread_context_cache
{ {
unsigned tid; unsigned tid{ 0 };
thread_context *object; thread_context *object{ nullptr };
}tcontext; }tcontext;
cache_type()
{
tcontext.tid = 0;
tcontext.object = nullptr;
}
}cache; }cache;
struct menu_tag struct menu_tag
{ {
menu_tag() core_window_t* taken_window{ nullptr };
:taken_window(nullptr), window(nullptr), owner(nullptr), has_keyboard(false) bool delay_restore{ false };
{} native_window_type window{ nullptr };
native_window_type owner{ nullptr };
core_window_t* taken_window; bool has_keyboard{ false };
native_window_type window;
native_window_type owner;
bool has_keyboard;
}menu; }menu;
struct keyboard_tracking_state_tag struct keyboard_tracking_state_tag
@ -282,14 +273,39 @@ namespace detail
void bedrock::set_menubar_taken(core_window_t* wd) void bedrock::set_menubar_taken(core_window_t* wd)
{ {
auto pre = impl_->menu.taken_window;
impl_->menu.taken_window = wd; impl_->menu.taken_window = wd;
//assigning of a nullptr taken window is to restore the focus of pre taken
if ((!wd) && pre)
{
internal_scope_guard lock;
wd_manager.set_focus(pre, false);
wd_manager.update(pre, true, false);
}
} }
bedrock::core_window_t* bedrock::get_menubar_taken() //0:Enable delay, 1:Cancel, 2:Restores, 3: Restores when menu is destroying
void bedrock::delay_restore(int state)
{ {
core_window_t* wd = impl_->menu.taken_window; switch (state)
impl_->menu.taken_window = nullptr; {
return wd; case 0: //Enable
break;
case 1: //Cancel
break;
case 2: //Restore if key released
//restores the focus when menu is closed by pressing keyboard
if (!impl_->menu.window)
set_menubar_taken(nullptr);
break;
case 3: //Restores if destroying
//when the menu is destroying, restores the focus if delay restore is not declared
if (!impl_->menu.delay_restore)
set_menubar_taken(nullptr);
}
impl_->menu.delay_restore = (0 == state);
} }
bool bedrock::close_menu_if_focus_other_window(native_window_type wd) bool bedrock::close_menu_if_focus_other_window(native_window_type wd)
@ -304,7 +320,7 @@ namespace detail
else else
return false; return false;
} }
remove_menu(); erase_menu(true);
return true; return true;
} }
return false; return false;
@ -314,7 +330,7 @@ namespace detail
{ {
if(menu_window && impl_->menu.window != menu_window) if(menu_window && impl_->menu.window != menu_window)
{ {
remove_menu(); erase_menu(true);
impl_->menu.window = menu_window; impl_->menu.window = menu_window;
impl_->menu.owner = native_interface::get_owner_window(menu_window); impl_->menu.owner = native_interface::get_owner_window(menu_window);
impl_->menu.has_keyboard = has_keyboard; impl_->menu.has_keyboard = has_keyboard;
@ -338,21 +354,13 @@ namespace detail
return impl_->menu.window; return impl_->menu.window;
} }
void bedrock::remove_menu() void bedrock::erase_menu(bool try_destroy)
{ {
if(impl_->menu.window) if (impl_->menu.window)
{ {
native_window_type delwin = impl_->menu.window; if (try_destroy)
impl_->menu.window = impl_->menu.owner = nullptr; native_interface::close_window(impl_->menu.window);
impl_->menu.has_keyboard = false;
native_interface::close_window(delwin);
}
}
void bedrock::empty_menu()
{
if(impl_->menu.window)
{
impl_->menu.window = impl_->menu.owner = nullptr; impl_->menu.window = impl_->menu.owner = nullptr;
impl_->menu.has_keyboard = false; impl_->menu.has_keyboard = false;
} }
@ -363,6 +371,7 @@ namespace detail
XKeyEvent xkey; XKeyEvent xkey;
nana::detail::platform_spec::instance().read_keystate(xkey); nana::detail::platform_spec::instance().read_keystate(xkey);
arg.ctrl = (xkey.state & ControlMask); arg.ctrl = (xkey.state & ControlMask);
arg.shift = (xkey.state & ShiftMask);
} }
bool bedrock::set_keyboard_shortkey(bool yes) bool bedrock::set_keyboard_shortkey(bool yes)
@ -372,6 +381,11 @@ namespace detail
return ret; return ret;
} }
bool bedrock::whether_keyboard_shortkey() const
{
return impl_->keyboard_tracking_state.has_shortkey_occured;
}
element_store& bedrock::get_element_store() const element_store& bedrock::get_element_store() const
{ {
return impl_->estore; return impl_->estore;
@ -569,7 +583,7 @@ namespace detail
delete 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.x = msg.u.mouse_drop.x - msgwd->pos_root.x;
arg.pos.y = msg.u.mouse_drop.y - msgwd->pos_root.y; arg.pos.y = msg.u.mouse_drop.y - msgwd->pos_root.y;
msgwd->together.attached_events->mouse_dropfiles.emit(arg); msgwd->together.events_ptr->mouse_dropfiles.emit(arg);
brock.wd_manager.do_lazy_refresh(msgwd, false); brock.wd_manager.do_lazy_refresh(msgwd, false);
} }
break; break;
@ -700,8 +714,8 @@ namespace detail
msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y);
if(nullptr == msgwnd) break; if(nullptr == msgwnd) break;
if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
brock.remove_menu(); brock.erase_menu(true);
else else
brock.close_menu_if_focus_other_window(msgwnd->root); brock.close_menu_if_focus_other_window(msgwnd->root);
@ -719,12 +733,11 @@ namespace detail
if(kill_focus != new_focus) if(kill_focus != new_focus)
brock.wd_manager.do_lazy_refresh(kill_focus, false); brock.wd_manager.do_lazy_refresh(kill_focus, false);
} }
auto retain = msgwnd->together.events_ptr;
msgwnd->root_widget->other.attribute.root->context.focus_changed = false; msgwnd->root_widget->other.attribute.root->context.focus_changed = false;
context.event_window = msgwnd; context.event_window = msgwnd;
pressed_wd = nullptr; pressed_wd = nullptr;
//make_eventinfo(ei, msgwnd, message, xevent);
msgwnd->flags.action = mouse_action::pressed; msgwnd->flags.action = mouse_action::pressed;
arg_mouse arg; arg_mouse arg;
assign_arg(arg, msgwnd, ButtonPress, xevent); assign_arg(arg, msgwnd, ButtonPress, xevent);
@ -753,7 +766,7 @@ namespace detail
nana::point mspos{xevent.xbutton.x, xevent.xbutton.y}; nana::point mspos{xevent.xbutton.x, xevent.xbutton.y};
while(msgwnd) while(msgwnd)
{ {
if(msgwnd->together.attached_events->mouse_wheel.length() != 0) if(msgwnd->together.events_ptr->mouse_wheel.length() != 0)
{ {
mspos -= msgwnd->pos_root; mspos -= msgwnd->pos_root;
arg_wheel arg; arg_wheel arg;
@ -774,6 +787,8 @@ namespace detail
msgwnd->flags.action = mouse_action::normal; msgwnd->flags.action = mouse_action::normal;
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {
auto retain = msgwnd->together.events_ptr;
arg_mouse arg; arg_mouse arg;
assign_arg(arg, msgwnd, message, xevent); assign_arg(arg, msgwnd, message, xevent);
@ -795,27 +810,29 @@ namespace detail
{ {
if(hit) if(hit)
msgwnd->flags.action = mouse_action::over; msgwnd->flags.action = mouse_action::over;
auto retain = msgwnd->together.events_ptr;
auto evt_ptr = retain.get();
auto events_ptr = msgwnd->together.events_ptr;
arg.evt_code = event_code::mouse_up; arg.evt_code = event_code::mouse_up;
emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); emit_drawer(&drawer::mouse_up, msgwnd, arg, &context);
if(fire_click) if(fire_click)
{ {
arg.evt_code = event_code::click; arg.evt_code = event_code::click;
msgwnd->together.attached_events->click.emit(arg); evt_ptr->click.emit(arg);
} }
if (brock.wd_manager.available(msgwnd)) if (brock.wd_manager.available(msgwnd))
{ {
arg.evt_code = event_code::mouse_up; arg.evt_code = event_code::mouse_up;
msgwnd->together.attached_events->mouse_up.emit(arg); evt_ptr->mouse_up.emit(arg);
} }
} }
else if(fire_click) else if(fire_click)
{ {
arg.evt_code = event_code::click; arg.evt_code = event_code::click;
msgwnd->together.attached_events->click.emit(arg); msgwnd->together.events_ptr->click.emit(arg);
} }
brock.wd_manager.do_lazy_refresh(msgwnd, false); brock.wd_manager.do_lazy_refresh(msgwnd, false);
} }
@ -828,8 +845,11 @@ namespace detail
if(brock.wd_manager.available(msgwnd)) if(brock.wd_manager.available(msgwnd))
{ {
//The msgwnd may be destroyed if the window is destroyed by calling native interface of close_window(). //The msgwnd may be destroyed if the window is destroyed by calling native interface of close_window().
if(msgwnd->root == brock.get_menu()) if (msgwnd->root == brock.get_menu())
brock.empty_menu(); {
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore not decleared
}
spec.remove(native_window); spec.remove(native_window);
brock.wd_manager.destroy(msgwnd); brock.wd_manager.destroy(msgwnd);
@ -928,6 +948,9 @@ namespace detail
nana::detail::platform_spec::instance().write_keystate(xevent.xkey); nana::detail::platform_spec::instance().write_keystate(xevent.xkey);
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {
if (brock.get_menu())
brock.delay_restore(0); //Enable delay restore
if(msgwnd->root != brock.get_menu()) if(msgwnd->root != brock.get_menu())
msgwnd = brock.focus(); msgwnd = brock.focus();
@ -961,8 +984,8 @@ namespace detail
else else
{ {
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard psg;
status = XLookupBoth; status = XLookupKeySym;
len = ::XLookupString(&xevent.xkey, keybuf, 32, &keysym, 0); keysym = ::XLookupKeysym(&xevent.xkey, 0);
} }
keybuf[len] = 0; keybuf[len] = 0;
@ -999,7 +1022,9 @@ namespace detail
context.platform.keychar = keychar; context.platform.keychar = keychar;
if(keychar == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab if(keychar == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab
{ {
auto the_next = brock.wd_manager.tabstop(msgwnd, true); arg_keyboard argkey;
brock.get_key_state(argkey);
auto the_next = brock.wd_manager.tabstop(msgwnd, !argkey.shift);
if(the_next) if(the_next)
{ {
brock.wd_manager.set_focus(the_next, false); brock.wd_manager.set_focus(the_next, false);
@ -1010,12 +1035,31 @@ namespace detail
else if(keyboard::alt == keychar) else if(keyboard::alt == keychar)
{ {
context.is_alt_pressed = true; context.is_alt_pressed = true;
if (brock.whether_keyboard_shortkey() == false)
{
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
if (msgwnd)
{
bool focused = (brock.focus() == msgwnd);
arg_keyboard arg;
arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.ignore = false;
arg.key = static_cast<nana::char_t>(keychar);
brock.get_key_state(arg);
brock.emit(event_code::key_press, msgwnd, arg, true, &context);
msgwnd->root_widget->flags.ignore_menubar_focus = (focused && (brock.focus() != msgwnd));
}
else
brock.erase_menu(true);
}
} }
else if(keychar) else
{ {
arg_keyboard arg; arg_keyboard arg;
arg.ignore = false; arg.ignore = false;
arg.key = keychar; arg.key = keychar ? keychar : xevent.xkey.keycode;
arg.evt_code = event_code::key_press; arg.evt_code = event_code::key_press;
brock.get_key_state(arg); brock.get_key_state(arg);
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1061,7 +1105,7 @@ namespace detail
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
brock.get_key_state(arg); brock.get_key_state(arg);
msgwnd->together.attached_events->key_char.emit(arg); msgwnd->together.events_ptr->key_char.emit(arg);
if(arg.ignore == false && brock.wd_manager.available(msgwnd)) if(arg.ignore == false && brock.wd_manager.available(msgwnd))
brock.emit_drawer(event_code::key_char, msgwnd, arg, &context); brock.emit_drawer(event_code::key_char, msgwnd, arg, &context);
} }
@ -1092,11 +1136,35 @@ namespace detail
brock.get_key_state(arg); brock.get_key_state(arg);
brock.emit(event_code::key_release, msgwnd, arg, true, &context); brock.emit(event_code::key_release, msgwnd, arg, true, &context);
} }
brock.delay_restore(2); //Restores while key release
} }
else else
{ {
context.is_alt_pressed = false; context.is_alt_pressed = false;
brock.set_keyboard_shortkey(false); if (brock.set_keyboard_shortkey(false) == false)
{
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
if (msgwnd)
{
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
if (set_focus)
brock.wd_manager.set_focus(msgwnd, false);
arg_keyboard arg;
arg.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.ignore = false;
arg.key = static_cast<nana::char_t>(context.platform.keychar);
brock.get_key_state(arg);
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
if (!set_focus)
{
brock.set_menubar_taken(nullptr);
msgwnd->root_widget->flags.ignore_menubar_focus = false;
}
}
}
} }
break; break;
default: default:

View File

@ -13,6 +13,7 @@
#include <nana/config.hpp> #include <nana/config.hpp>
#include PLATFORM_SPEC_HPP #include PLATFORM_SPEC_HPP
#include <nana/gui/detail/native_window_interface.hpp> #include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/screen.hpp>
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED) #if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp> #include <nana/std_mutex.hpp>
@ -35,10 +36,10 @@ namespace nana{
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
static HICON icon(const nana::paint::image& img) static HICON icon(const nana::paint::image& img)
{ {
paint::detail::image_ico * ico = dynamic_cast<paint::detail::image_ico*>(img.image_ptr_.get()); auto ico = dynamic_cast<paint::detail::image_ico*>(img.image_ptr_.get());
if(ico && ico->ptr()) if(ico && ico->ptr())
return *(ico->ptr()); return *(ico->ptr());
return 0; return nullptr;
} }
#endif #endif
}; };
@ -51,17 +52,13 @@ namespace nana{
{ {
struct window_extra_t struct window_extra_t
{ {
HICON ico; HICON ico{nullptr};
window_extra_t()
: ico(0)
{}
}; };
typedef std::map<native_window_type, window_extra_t> map_t; typedef std::map<native_window_type, window_extra_t> map_t;
private: private:
tray_manager(){} tray_manager() = default;
public: public:
typedef window_extra_t extra_t; typedef window_extra_t extra_t;
@ -205,19 +202,21 @@ namespace nana{
if(owner && (nested == false)) if(owner && (nested == false))
::ClientToScreen(reinterpret_cast<HWND>(owner), &pt); ::ClientToScreen(reinterpret_cast<HWND>(owner), &pt);
HWND wnd = ::CreateWindowEx(style_ex, STR("NanaWindowInternal"), STR("Nana Window"), HWND native_wd = ::CreateWindowEx(style_ex, STR("NanaWindowInternal"), STR("Nana Window"),
style, style,
pt.x, pt.y, 100, 100, pt.x, pt.y, 100, 100,
reinterpret_cast<HWND>(owner), 0, ::GetModuleHandle(0), 0); reinterpret_cast<HWND>(owner), 0, ::GetModuleHandle(0), 0);
//A window may have a border, this should be adjusted the client area fit for the specified size. //A window may have a border, this should be adjusted the client area fit for the specified size.
::RECT client; ::RECT client;
::GetClientRect(wnd, &client); //The right and bottom of client by GetClientRect indicate the width and height of the area ::GetClientRect(native_wd, &client); //The right and bottom of client by GetClientRect indicate the width and height of the area
::RECT wd_area; ::RECT wd_area;
::GetWindowRect(wnd, &wd_area); ::GetWindowRect(native_wd, &wd_area);
wd_area.right -= wd_area.left;
wd_area.bottom -= wd_area.top; //a dimension with borders and caption title
if(nested) wd_area.right -= wd_area.left; //wd_area.right = width
wd_area.bottom -= wd_area.top; //wd_area.bottom = height
if (nested)
{ {
wd_area.left = pt.x; wd_area.left = pt.x;
wd_area.top = pt.y; wd_area.top = pt.y;
@ -226,14 +225,15 @@ namespace nana{
int delta_w = static_cast<int>(r.width) - client.right; int delta_w = static_cast<int>(r.width) - client.right;
int delta_h = static_cast<int>(r.height) - client.bottom; int delta_h = static_cast<int>(r.height) - client.bottom;
::MoveWindow(wnd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true); ::MoveWindow(native_wd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true);
::GetClientRect(native_wd, &client);
::GetWindowRect(native_wd, &wd_area);
::GetClientRect(wnd, &client);
::GetWindowRect(wnd, &wd_area);
wd_area.right -= wd_area.left; wd_area.right -= wd_area.left;
wd_area.bottom -= wd_area.top; wd_area.bottom -= wd_area.top;
window_result result = {reinterpret_cast<native_window_type>(wnd), window_result result = { reinterpret_cast<native_window_type>(native_wd),
static_cast<unsigned>(client.right), static_cast<unsigned>(client.bottom), static_cast<unsigned>(client.right), static_cast<unsigned>(client.bottom),
static_cast<unsigned>(wd_area.right - client.right), static_cast<unsigned>(wd_area.bottom - client.bottom)}; static_cast<unsigned>(wd_area.right - client.right), static_cast<unsigned>(wd_area.bottom - client.bottom)};
#elif defined(NANA_X11) #elif defined(NANA_X11)
@ -556,6 +556,7 @@ namespace nana{
{ {
::EnableWindow(native_wd, true); ::EnableWindow(native_wd, true);
::SetActiveWindow(native_wd); ::SetActiveWindow(native_wd);
::SetForegroundWindow(native_wd);
} }
else else
::PostMessage(native_wd, nana::detail::messages::async_activate, 0, 0); ::PostMessage(native_wd, nana::detail::messages::async_activate, 0, 0);
@ -580,27 +581,30 @@ namespace nana{
//event, when the client receives the event, the specified window has been already //event, when the client receives the event, the specified window has been already
//destroyed. This is a feature which is different from Windows. So the following //destroyed. This is a feature which is different from Windows. So the following
//works should be handled before calling XDestroyWindow. //works should be handled before calling XDestroyWindow.
auto & bedrock = bedrock::instance(); auto & brock = bedrock::instance();
if(wd == bedrock.get_menu()) if(wd == brock.get_menu())
bedrock.empty_menu(); {
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore is not decleard
}
Display* disp = restrict::spec.open_display(); Display* disp = restrict::spec.open_display();
restrict::spec.remove(wd); restrict::spec.remove(wd);
auto iwd = bedrock.wd_manager.root(wd); auto iwd = brock.wd_manager.root(wd);
if(iwd) if(iwd)
{ {
{ {
//Before calling window_manager::destroy, make sure the window is invisible. //Before calling window_manager::destroy, make sure the window is invisible.
//It is a behavior like Windows. //It is a behavior like Windows.
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard lock;
restrict::spec.set_error_handler(); restrict::spec.set_error_handler();
::XUnmapWindow(disp, reinterpret_cast<Window>(wd)); ::XUnmapWindow(disp, reinterpret_cast<Window>(wd));
::XFlush(disp); ::XFlush(disp);
restrict::spec.rev_error_handler(); restrict::spec.rev_error_handler();
} }
bedrock.wd_manager.destroy(iwd); brock.wd_manager.destroy(iwd);
bedrock.rt_manager.remove_if_exists(iwd); brock.rt_manager.remove_if_exists(iwd);
bedrock.wd_manager.destroy_handle(iwd); brock.wd_manager.destroy_handle(iwd);
} }
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard psg;

View File

@ -8,6 +8,7 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/detail/win32/bedrock.cpp * @file: nana/gui/detail/win32/bedrock.cpp
* @contributors: Ariel Vina-Rodriguez
*/ */
#include <nana/config.hpp> #include <nana/config.hpp>
@ -184,17 +185,18 @@ namespace detail
{ {
struct thread_context_cache struct thread_context_cache
{ {
unsigned tid = 0; unsigned tid{ 0 };
thread_context *object = nullptr; thread_context *object{ nullptr };
}tcontext; }tcontext;
}cache; }cache;
struct menu_tag struct menu_tag
{ {
core_window_t* taken_window = nullptr; core_window_t* taken_window{ nullptr };
native_window_type window = nullptr; bool delay_restore{ false };
native_window_type owner = nullptr; native_window_type window{ nullptr };
bool has_keyboard = false; native_window_type owner{ nullptr };
bool has_keyboard{false};
}menu; }menu;
struct keyboard_tracking_state_tag struct keyboard_tracking_state_tag
@ -266,12 +268,6 @@ namespace detail
::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK); ::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK);
} }
if(evt_operation.size())
{
std::stringstream ss;
ss<<"Nana.GUI detects a memory leaks in events operation, "<<static_cast<unsigned>(evt_operation.size())<<" event(s) are not uninstalled.";
::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK);
}
delete impl_; delete impl_;
delete pi_data_; delete pi_data_;
} }
@ -855,7 +851,7 @@ namespace detail
case WM_WINDOWPOSCHANGED: case WM_WINDOWPOSCHANGED:
if ((reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW) && (!msgwnd->visible)) if ((reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW) && (!msgwnd->visible))
brock.event_expose(msgwnd, true); brock.event_expose(msgwnd, true);
else if((reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_HIDEWINDOW) && msgwnd->visible) else if ((reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_HIDEWINDOW) && msgwnd->visible)
brock.event_expose(msgwnd, false); brock.event_expose(msgwnd, false);
def_window_proc = true; def_window_proc = true;
@ -875,6 +871,7 @@ namespace detail
if (!brock.emit(event_code::focus, focus, arg, true, &context)) if (!brock.emit(event_code::focus, focus, arg, true, &context))
brock.wd_manager.set_focus(msgwnd, true); brock.wd_manager.set_focus(msgwnd, true);
} }
def_window_proc = true;
break; break;
case WM_KILLFOCUS: case WM_KILLFOCUS:
if(msgwnd->other.attribute.root->focus) if(msgwnd->other.attribute.root->focus)
@ -895,10 +892,14 @@ namespace detail
//focus_changed means that during an event procedure if the focus is changed //focus_changed means that during an event procedure if the focus is changed
if(brock.wd_manager.available(msgwnd)) if(brock.wd_manager.available(msgwnd))
msgwnd->root_widget->other.attribute.root->context.focus_changed = true; msgwnd->root_widget->other.attribute.root->context.focus_changed = true;
def_window_proc = true;
break; break;
case WM_MOUSEACTIVATE: case WM_MOUSEACTIVATE:
if(msgwnd->flags.take_active == false) if(msgwnd->flags.take_active == false)
return MA_NOACTIVATE; return MA_NOACTIVATE;
def_window_proc = true;
break; break;
case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
pressed_wd = nullptr; pressed_wd = nullptr;
@ -926,8 +927,8 @@ namespace detail
if(nullptr == msgwnd) break; if(nullptr == msgwnd) break;
//if event on the menubar, just remove the menu if it is not associating with the menubar //if event on the menubar, just remove the menu if it is not associating with the menubar
if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
brock.remove_menu(); brock.erase_menu(true);
else else
brock.close_menu_if_focus_other_window(msgwnd->root); brock.close_menu_if_focus_other_window(msgwnd->root);
@ -948,6 +949,8 @@ namespace detail
arg_mouse arg; arg_mouse arg;
assign_arg(arg, msgwnd, message, pmdec); assign_arg(arg, msgwnd, message, pmdec);
msgwnd->flags.action = mouse_action::pressed; msgwnd->flags.action = mouse_action::pressed;
auto retain = msgwnd->together.events_ptr;
if (brock.emit(event_code::mouse_down, msgwnd, arg, true, &context)) if (brock.emit(event_code::mouse_down, msgwnd, arg, true, &context))
{ {
//If a root_window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. //If a root_window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event.
@ -982,6 +985,8 @@ namespace detail
msgwnd->flags.action = mouse_action::normal; msgwnd->flags.action = mouse_action::normal;
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {
auto retain = msgwnd->together.events_ptr;
nana::arg_mouse arg; nana::arg_mouse arg;
assign_arg(arg, msgwnd, message, pmdec); assign_arg(arg, msgwnd, message, pmdec);
@ -1011,19 +1016,19 @@ namespace detail
if (fire_click) if (fire_click)
{ {
arg.evt_code = event_code::click; arg.evt_code = event_code::click;
msgwnd->together.attached_events->click.emit(arg); retain->click.emit(arg);
} }
if (brock.wd_manager.available(msgwnd)) if (brock.wd_manager.available(msgwnd))
{ {
arg.evt_code = event_code::mouse_up; arg.evt_code = event_code::mouse_up;
msgwnd->together.attached_events->mouse_up.emit(arg); retain->mouse_up.emit(arg);
} }
} }
else if (fire_click) else if (fire_click)
{ {
arg.evt_code = event_code::click; arg.evt_code = event_code::click;
msgwnd->together.attached_events->click.emit(arg); retain->click.emit(arg);
} }
brock.wd_manager.do_lazy_refresh(msgwnd, false); brock.wd_manager.do_lazy_refresh(msgwnd, false);
} }
@ -1103,7 +1108,7 @@ namespace detail
case WM_MOUSEHWHEEL: case WM_MOUSEHWHEEL:
{ {
//The focus window receives the message in Windows system, it should be redirected to the hovered window //The focus window receives the message in Windows system, it should be redirected to the hovered window
::POINT scr_pos{ int(LOWORD(lParam)), int(HIWORD(lParam)) }; //Screen position ::POINT scr_pos{ pmdec.mouse.x, pmdec.mouse.y}; //Screen position
auto pointer_wd = ::WindowFromPoint(scr_pos); auto pointer_wd = ::WindowFromPoint(scr_pos);
if (pointer_wd == root_window) if (pointer_wd == root_window)
{ {
@ -1114,7 +1119,7 @@ namespace detail
auto evt_wd = scrolled_wd; auto evt_wd = scrolled_wd;
while (evt_wd) while (evt_wd)
{ {
if (evt_wd->together.attached_events->mouse_wheel.length() != 0) if (evt_wd->together.events_ptr->mouse_wheel.length() != 0)
{ {
def_window_proc = false; def_window_proc = false;
nana::point mspos{ scr_pos.x, scr_pos.y }; nana::point mspos{ scr_pos.x, scr_pos.y };
@ -1189,7 +1194,7 @@ namespace detail
brock.wd_manager.calc_window_point(msgwnd, dropfiles.pos); brock.wd_manager.calc_window_point(msgwnd, dropfiles.pos);
dropfiles.window_handle = reinterpret_cast<window>(msgwnd); dropfiles.window_handle = reinterpret_cast<window>(msgwnd);
msgwnd->together.attached_events->mouse_dropfiles.emit(dropfiles); msgwnd->together.events_ptr->mouse_dropfiles.emit(dropfiles);
brock.wd_manager.do_lazy_refresh(msgwnd, false); brock.wd_manager.do_lazy_refresh(msgwnd, false);
} }
} }
@ -1308,6 +1313,7 @@ namespace detail
} }
break; break;
case WM_SYSCHAR: case WM_SYSCHAR:
def_window_proc = true;
brock.set_keyboard_shortkey(true); brock.set_keyboard_shortkey(true);
msgwnd = brock.wd_manager.find_shortkey(native_window, static_cast<unsigned long>(wParam)); msgwnd = brock.wd_manager.find_shortkey(native_window, static_cast<unsigned long>(wParam));
if(msgwnd) if(msgwnd)
@ -1319,17 +1325,17 @@ namespace detail
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.ignore = false; arg.ignore = false;
brock.emit(event_code::shortkey, msgwnd, arg, true, &context); brock.emit(event_code::shortkey, msgwnd, arg, true, &context);
def_window_proc = false;
} }
def_window_proc = true;
break; break;
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
if(brock.whether_keyboard_shortkey() == false) def_window_proc = true;
if (brock.whether_keyboard_shortkey() == false)
{ {
msgwnd = msgwnd->root_widget->other.attribute.root->menubar; msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
if(msgwnd) if (msgwnd)
{ {
brock.wd_manager.set_focus(msgwnd, false); bool focused = (brock.focus() == msgwnd);
arg_keyboard arg; arg_keyboard arg;
arg.evt_code = event_code::key_press; arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1337,18 +1343,26 @@ namespace detail
arg.key = static_cast<nana::char_t>(wParam); arg.key = static_cast<nana::char_t>(wParam);
brock.get_key_state(arg); brock.get_key_state(arg);
brock.emit(event_code::key_press, msgwnd, arg, true, &context); brock.emit(event_code::key_press, msgwnd, arg, true, &context);
msgwnd->root_widget->flags.ignore_menubar_focus = (focused && (brock.focus() != msgwnd));
} }
else if(brock.get_menu()) else
brock.remove_menu(); brock.erase_menu(true);
} }
def_window_proc = true;
break; break;
case WM_SYSKEYUP: case WM_SYSKEYUP:
def_window_proc = true;
if(brock.set_keyboard_shortkey(false) == false) if(brock.set_keyboard_shortkey(false) == false)
{ {
msgwnd = msgwnd->root_widget->other.attribute.root->menubar; msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
if(msgwnd) if(msgwnd)
{ {
//Don't call default window proc to avoid popuping system menu.
def_window_proc = false;
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
if (set_focus)
brock.wd_manager.set_focus(msgwnd, false);
arg_keyboard arg; arg_keyboard arg;
arg.evt_code = event_code::key_release; arg.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1356,21 +1370,30 @@ namespace detail
arg.key = static_cast<nana::char_t>(wParam); arg.key = static_cast<nana::char_t>(wParam);
brock.get_key_state(arg); brock.get_key_state(arg);
brock.emit(event_code::key_release, msgwnd, arg, true, &context); brock.emit(event_code::key_release, msgwnd, arg, true, &context);
if (!set_focus)
{
brock.set_menubar_taken(nullptr);
msgwnd->root_widget->flags.ignore_menubar_focus = false;
}
} }
} }
def_window_proc = true;
break; break;
case WM_KEYDOWN: case WM_KEYDOWN:
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {
if(msgwnd->root != brock.get_menu()) auto menu_wd = brock.get_menu();
if (menu_wd)
brock.delay_restore(0); //Enable delay restore
if (msgwnd->root != menu_wd)
msgwnd = brock.focus(); msgwnd = brock.focus();
if(msgwnd) if(msgwnd)
{ {
if((wParam == 9) && (false == (msgwnd->flags.tab & tab_type::eating))) //Tab if((wParam == 9) && (false == (msgwnd->flags.tab & tab_type::eating))) //Tab
{ {
auto the_next = brock.wd_manager.tabstop(msgwnd, true); auto the_next = brock.wd_manager.tabstop(msgwnd, (::GetKeyState(VK_SHIFT) >= 0));
if(the_next) if(the_next)
{ {
brock.wd_manager.set_focus(the_next, false); brock.wd_manager.set_focus(the_next, false);
@ -1388,6 +1411,17 @@ namespace detail
arg.key = static_cast<nana::char_t>(wParam); arg.key = static_cast<nana::char_t>(wParam);
brock.get_key_state(arg); brock.get_key_state(arg);
brock.emit(event_code::key_press, msgwnd, arg, true, &context); brock.emit(event_code::key_press, msgwnd, arg, true, &context);
if (msgwnd->root_widget->other.attribute.root->menubar == msgwnd)
{
//In order to keep the focus on the menubar, cancel the delay_restore
//when pressing ESC to close the menu which is popuped by the menubar.
//If no menu popuped by the menubar, it should enable delay restore to
//restore the focus for taken window.
int cmd = (menu_wd && (keyboard::escape == static_cast<nana::char_t>(wParam)) ? 1 : 0);
brock.delay_restore(cmd);
}
} }
} }
} }
@ -1405,7 +1439,7 @@ namespace detail
brock.get_key_state(arg); brock.get_key_state(arg);
arg.ignore = false; arg.ignore = false;
msgwnd->together.attached_events->key_char.emit(arg); msgwnd->together.events_ptr->key_char.emit(arg);
if ((false == arg.ignore) && brock.wd_manager.available(msgwnd)) if ((false == arg.ignore) && brock.wd_manager.available(msgwnd))
brock.emit_drawer(event_code::key_char, msgwnd, arg, &context); brock.emit_drawer(event_code::key_char, msgwnd, arg, &context);
@ -1432,6 +1466,8 @@ namespace detail
} }
else else
brock.set_keyboard_shortkey(false); brock.set_keyboard_shortkey(false);
brock.delay_restore(2); //Restores while key release
break; break;
case WM_CLOSE: case WM_CLOSE:
{ {
@ -1449,8 +1485,12 @@ namespace detail
break; break;
} }
case WM_DESTROY: case WM_DESTROY:
if(msgwnd->root == brock.get_menu()) if (msgwnd->root == brock.get_menu())
brock.empty_menu(); {
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore not decleared
}
brock.wd_manager.destroy(msgwnd); brock.wd_manager.destroy(msgwnd);
nana::detail::platform_spec::instance().release_window_icon(msgwnd->root); nana::detail::platform_spec::instance().release_window_icon(msgwnd->root);
@ -1513,14 +1553,40 @@ namespace detail
void bedrock::set_menubar_taken(core_window_t* wd) void bedrock::set_menubar_taken(core_window_t* wd)
{ {
auto pre = impl_->menu.taken_window;
impl_->menu.taken_window = wd; impl_->menu.taken_window = wd;
//assigning of a nullptr taken window is to restore the focus of pre taken
//don't restore the focus if pre is a menu.
if ((!wd) && pre && (pre->root != get_menu()))
{
internal_scope_guard lock;
wd_manager.set_focus(pre, false);
wd_manager.update(pre, true, false);
}
} }
bedrock::core_window_t* bedrock::get_menubar_taken() //0:Enable delay, 1:Cancel, 2:Restores, 3: Restores when menu is destroying
void bedrock::delay_restore(int state)
{ {
core_window_t* wd = impl_->menu.taken_window; switch (state)
impl_->menu.taken_window = nullptr; {
return wd; case 0: //Enable
break;
case 1: //Cancel
break;
case 2: //Restore if key released
//restores the focus when menu is closed by pressing keyboard
if ((!impl_->menu.window) && impl_->menu.delay_restore)
set_menubar_taken(nullptr);
break;
case 3: //Restores if destroying
//when the menu is destroying, restores the focus if delay restore is not declared
if (!impl_->menu.delay_restore)
set_menubar_taken(nullptr);
}
impl_->menu.delay_restore = (0 == state);
} }
bool bedrock::close_menu_if_focus_other_window(native_window_type wd) bool bedrock::close_menu_if_focus_other_window(native_window_type wd)
@ -1535,7 +1601,7 @@ namespace detail
else else
return false; return false;
} }
remove_menu(); erase_menu(true);
return true; return true;
} }
return false; return false;
@ -1545,7 +1611,7 @@ namespace detail
{ {
if(menu_wd && impl_->menu.window != menu_wd) if(menu_wd && impl_->menu.window != menu_wd)
{ {
remove_menu(); erase_menu(true);
impl_->menu.window = menu_wd; impl_->menu.window = menu_wd;
impl_->menu.owner = native_interface::get_owner_window(menu_wd); impl_->menu.owner = native_interface::get_owner_window(menu_wd);
@ -1569,21 +1635,13 @@ namespace detail
return impl_->menu.window; return impl_->menu.window;
} }
void bedrock::remove_menu() void bedrock::erase_menu(bool try_destroy)
{ {
if(impl_->menu.window) if (impl_->menu.window)
{
auto delwin = impl_->menu.window;
impl_->menu.window = impl_->menu.owner = nullptr;
impl_->menu.has_keyboard = false;
native_interface::close_window(delwin);
}
}
void bedrock::empty_menu()
{
if(impl_->menu.window)
{ {
if (try_destroy)
native_interface::close_window(impl_->menu.window);
impl_->menu.window = impl_->menu.owner = nullptr; impl_->menu.window = impl_->menu.owner = nullptr;
impl_->menu.has_keyboard = false; impl_->menu.has_keyboard = false;
} }

View File

@ -8,7 +8,8 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/detail/window_manager.cpp * @file: nana/gui/detail/window_manager.cpp
* * @author: Jinhao
* @contributors: Katsuhisa Yuasa
*/ */
#include <nana/config.hpp> #include <nana/config.hpp>
@ -20,7 +21,6 @@
#include <nana/gui/layout_utility.hpp> #include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/effects_renderer.hpp> #include <nana/gui/detail/effects_renderer.hpp>
#include <stdexcept> #include <stdexcept>
#include <algorithm>
namespace nana namespace nana
{ {
@ -191,7 +191,7 @@ namespace detail
switch(evtid) switch(evtid)
{ {
case event_code::mouse_drop: case event_code::mouse_drop:
wd->flags.dropable = (is_make || (0 != wd->together.attached_events->mouse_dropfiles.length())); wd->flags.dropable = (is_make || (0 != wd->together.events_ptr->mouse_dropfiles.length()));
break; break;
default: default:
break; break;
@ -875,7 +875,16 @@ namespace detail
if (!root_has_been_focused) if (!root_has_been_focused)
native_interface::set_focus(root_wd->root); native_interface::set_focus(root_wd->root);
brock.set_menubar_taken(wd); //A fix by Katsuhisa Yuasa
//The menubar token window will be redirected to the prev focus window when the new
//focus window is a menubar.
//The focus window will be restore to the prev focus which losts the focus becuase of
//memberbar.
if (wd == wd->root_widget->other.attribute.root->menubar)
wd = prev_focus;
if (wd != wd->root_widget->other.attribute.root->menubar)
brock.set_menubar_taken(wd);
} }
return prev_focus; return prev_focus;
} }
@ -975,11 +984,15 @@ namespace detail
} }
else else
{ {
auto i = std::find_if(attr_cap.begin(), attr_cap.end(), for (auto i = attr_cap.begin(), end = attr_cap.end(); i != end; ++i)
[wd](const std::pair<core_window_t*, bool> & x){ return (x.first == wd);}); {
if (i->first == wd)
{
attr_cap.erase(i);
break;
}
}
if(i != attr_cap.end())
attr_cap.erase(i);
return attr_.capture.window; return attr_.capture.window;
} }
return wd; return wd;

View File

@ -973,6 +973,7 @@ namespace nana
const nana::char_t * filter; const nana::char_t * filter;
nana::string filter_holder; nana::string filter_holder;
nana::string default_extension;
if(impl_->filters.size()) if(impl_->filters.size())
{ {
for(auto & f : impl_->filters) for(auto & f : impl_->filters)
@ -990,6 +991,21 @@ namespace nana
} }
filter_holder += fs; filter_holder += fs;
filter_holder += static_cast<nana::string::value_type>('\0'); filter_holder += static_cast<nana::string::value_type>('\0');
//Get the default file extentsion
if (default_extension.empty())
{
pos = fs.find_last_of('.');
if (pos != fs.npos)
{
fs = fs.substr(pos + 1);
if (fs != L"*")
{
default_extension = fs;
ofn.lpstrDefExt = default_extension.data();
}
}
}
} }
filter = filter_holder.data(); filter = filter_holder.data();
} }
@ -1002,6 +1018,10 @@ namespace nana
ofn.lpstrFileTitle = nullptr; ofn.lpstrFileTitle = nullptr;
ofn.nMaxFileTitle = 0; ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = (impl_->path.size() ? impl_->path.c_str() : nullptr); ofn.lpstrInitialDir = (impl_->path.size() ? impl_->path.c_str() : nullptr);
if (!impl_->open_or_save)
ofn.Flags = OFN_OVERWRITEPROMPT; //Overwrite prompt if it is save mode
if(FALSE == (impl_->open_or_save ? ::GetOpenFileName(&ofn) : ::GetSaveFileName(&ofn))) if(FALSE == (impl_->open_or_save ? ::GetOpenFileName(&ofn) : ::GetSaveFileName(&ofn)))
return false; return false;

View File

@ -8,7 +8,7 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/layout_utility.hpp * @file: nana/gui/layout_utility.hpp
* * @contributors: Ryan Gonzalez
* *
*/ */
#include <nana/gui/layout_utility.hpp> #include <nana/gui/layout_utility.hpp>

View File

@ -1,14 +1,15 @@
/* /*
* Implementation of Notifier * Implementation of Notifier
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/notifier.cpp * @file: nana/gui/notifier.cpp
*/ * @contributors: Jan
*/
#include <nana/deploy.hpp> #include <nana/deploy.hpp>
#include <nana/gui/programming_interface.hpp> #include <nana/gui/programming_interface.hpp>
#include <nana/gui/notifier.hpp> #include <nana/gui/notifier.hpp>
@ -16,7 +17,12 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp>
#else
#include <mutex> #include <mutex>
#endif
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
#include <nana/detail/win32/platform_spec.hpp> #include <nana/detail/win32/platform_spec.hpp>

View File

@ -1,7 +1,7 @@
/* /**
* An Implementation of Place for Layout * An Implementation of Place for Layout
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -21,6 +21,7 @@
#include <memory> #include <memory>
#include <limits> #include <limits>
#include <algorithm>
namespace nana namespace nana
{ {
@ -558,18 +559,22 @@ namespace nana
return token::identifier; return token::identifier;
} }
std::string err = "an invalid character '"; _m_throw_error(*sp_);
err += *sp_;
err += "'";
_m_throw_error(err);
return token::error; //Useless, just for syntax correction. return token::error; //Useless, just for syntax correction.
} }
private: private:
void _m_throw_error(char err_char) void _m_throw_error(char err_char)
{
std::string str = "place: invalid character '";
str += err_char;
str += '\'';
_m_throw_error(str);
}
void _m_throw_error(const std::string& err)
{ {
std::stringstream ss; std::stringstream ss;
ss << "place: invalid character '" << err_char << "' at " << static_cast<unsigned>(sp_ - divstr_); ss << "place: " << err << " at " << static_cast<unsigned>(sp_ - divstr_);
throw std::runtime_error(ss.str()); throw std::runtime_error(ss.str());
} }
@ -578,8 +583,7 @@ namespace nana
if (token::equal != read()) if (token::equal != read())
_m_throw_error("an equal sign is required after '" + idstr_ + "'"); _m_throw_error("an equal sign is required after '" + idstr_ + "'");
const char* p = sp_; const char* p = _m_eat_whitespace(sp_);
for (; *p == ' '; ++p);
auto neg_ptr = p; auto neg_ptr = p;
if ('-' == *p) if ('-' == *p)
@ -598,8 +602,7 @@ namespace nana
if (token::equal != read()) if (token::equal != read())
_m_throw_error("an equal sign is required after '" + idstr + "'"); _m_throw_error("an equal sign is required after '" + idstr + "'");
const char* p = sp_; const char* p = _m_eat_whitespace(sp_);
for (; *p == ' ' || *p == '\t'; ++p);
reparray_.reset(); reparray_.reset();
auto tk = read(); auto tk = read();
@ -619,14 +622,7 @@ namespace nana
} }
} }
void _m_throw_error(const std::string& err) static const char* _m_eat_whitespace(const char* sp)
{
std::stringstream ss;
ss << "place: " << err << " at " << static_cast<unsigned>(sp_ - divstr_);
throw std::runtime_error(ss.str());
}
const char* _m_eat_whitespace(const char* sp)
{ {
while (*sp && !isgraph(*sp)) while (*sp && !isgraph(*sp))
++sp; ++sp;
@ -677,7 +673,7 @@ namespace nana
if (gotcha) if (gotcha)
{ {
for (; *sp == ' ' || *sp == '\t'; ++sp); sp = _m_eat_whitespace(sp);
if ('%' == *sp) if ('%' == *sp)
{ {
if (number_t::kind::integer == number_.kind_of()) if (number_t::kind::integer == number_.kind_of())
@ -757,6 +753,20 @@ namespace nana
for (auto & e : fastened) for (auto & e : fastened)
API::show_window(e.handle, vsb); API::show_window(e.handle, vsb);
} }
static event_handle erase_element(std::vector<element_t>& elements, window handle)
{
for (auto i = elements.begin(), end = elements.end(); i != end; ++i)
{
if (i->handle == handle)
{
auto evt_destroy = i->evt_destroy;
elements.erase(i);
return evt_destroy;
}
}
return nullptr;
}
private: private:
//The defintion is moved after the definition of class division //The defintion is moved after the definition of class division
template<typename Function> template<typename Function>
@ -768,15 +778,8 @@ namespace nana
{ {
return API::events(wd).destroy.connect([this](const arg_destroy& arg) return API::events(wd).destroy.connect([this](const arg_destroy& arg)
{ {
for (auto i = elements.begin(), end = elements.end(); i != end; ++i) if (erase_element(elements, arg.window_handle))
{ place_ptr_->collocate();
if (arg.window_handle == i->handle)
{
elements.erase(i);
break;
}
}
place_ptr_->collocate();
}); });
} }
@ -815,13 +818,7 @@ namespace nana
//does not change the layout. //does not change the layout.
auto evt = API::events(wd).destroy([this](const arg_destroy& arg) auto evt = API::events(wd).destroy([this](const arg_destroy& arg)
{ {
auto destroyed_wd = arg.window_handle; erase_element(fastened, arg.window_handle);
auto i = std::find_if(fastened.begin(), fastened.end(), [destroyed_wd](element_t& e){
return (e.handle == destroyed_wd);
});
if (i != fastened.end())
fastened.erase(i);
}); });
fastened.emplace_back(wd, evt); fastened.emplace_back(wd, evt);
@ -929,16 +926,9 @@ namespace nana
{ {
for (auto & child : div->children) for (auto & child : div->children)
{ {
if (child->field) if (child->field && (!vsb || child->visible))
{ child->field->visible(vsb);
if (vsb)
{
if (child->visible)
child->field->visible(true);
}
else
child->field->visible(false);
}
_m_visible_for_child(child.get(), vsb); _m_visible_for_child(child.get(), vsb);
} }
} }
@ -985,7 +975,7 @@ namespace nana
const bool vert = (kind::arrange != kind_of_division); const bool vert = (kind::arrange != kind_of_division);
auto area_margined = margin_area(); auto area_margined = margin_area();
area_rotator area(vert, area_margined); rectangle_rotator area(vert, area_margined);
auto area_px = area.w(); auto area_px = area.w();
auto fa = _m_fixed_and_adjustable(kind_of_division, area_px); auto fa = _m_fixed_and_adjustable(kind_of_division, area_px);
@ -1001,7 +991,7 @@ namespace nana
if(!child->display) //Ignore the division if the corresponding field is not displayed. if(!child->display) //Ignore the division if the corresponding field is not displayed.
continue; continue;
area_rotator child_area(vert, child->field_area); rectangle_rotator child_area(vert, child->field_area);
child_area.x_ref() = static_cast<int>(position); child_area.x_ref() = static_cast<int>(position);
child_area.y_ref() = area.y(); child_area.y_ref() = area.y();
child_area.h_ref() = area.h(); child_area.h_ref() = area.h();
@ -1510,17 +1500,6 @@ namespace nana
class place::implement::div_splitter class place::implement::div_splitter
: public division : public division
{ {
struct div_block
{
division * div;
int pixels;
double scale;
div_block(division* d, int px)
: div(d), pixels(px)
{}
};
enum{splitter_px = 4}; enum{splitter_px = 4};
public: public:
div_splitter(place_parts::number_t init_weight) div_splitter(place_parts::number_t init_weight)
@ -1533,14 +1512,9 @@ namespace nana
this->weight.assign(splitter_px); this->weight.assign(splitter_px);
} }
void leaf_left(division * d) void set_leaf(bool is_left, division * d)
{ {
leaf_left_ = d; (is_left ? leaf_left_ : leaf_right_) = d;
}
void leaf_right(division * d)
{
leaf_right_ = d;
} }
void direction(bool horizontal) void direction(bool horizontal)
@ -1565,8 +1539,9 @@ namespace nana
auto px_ptr = &nana::rectangle::width; auto px_ptr = &nana::rectangle::width;
auto area_left = leaf_left_->margin_area(); //Use field_area of leaf, not margin_area. Otherwise splitter would be at wrong position
auto area_right = leaf_right_->margin_area(); auto area_left = leaf_left_->field_area;
auto area_right = leaf_right_->field_area;
if (nana::cursor::size_we != splitter_cursor_) if (nana::cursor::size_we != splitter_cursor_)
{ {
@ -1590,7 +1565,7 @@ namespace nana
return; return;
const bool vert = (::nana::cursor::size_we != splitter_cursor_); const bool vert = (::nana::cursor::size_we != splitter_cursor_);
auto area_px = area_rotator(vert, div_owner->margin_area()).w(); auto area_px = rectangle_rotator(vert, div_owner->margin_area()).w();
int delta = (vert ? splitter_.pos().y - begin_point_.y : splitter_.pos().x - begin_point_.x); int delta = (vert ? splitter_.pos().y - begin_point_.y : splitter_.pos().x - begin_point_.x);
int total_pixels = static_cast<int>(left_pixels_ + right_pixels_); int total_pixels = static_cast<int>(left_pixels_ + right_pixels_);
@ -1631,8 +1606,8 @@ namespace nana
{ {
const bool vert = (::nana::cursor::size_we != splitter_cursor_); const bool vert = (::nana::cursor::size_we != splitter_cursor_);
area_rotator left(vert, leaf_left_->field_area); rectangle_rotator left(vert, leaf_left_->field_area);
area_rotator right(vert, leaf_right_->field_area); rectangle_rotator right(vert, leaf_right_->field_area);
auto area_px = right.right() - left.x(); auto area_px = right.right() - left.x();
auto right_px = static_cast<int>(limit_px(leaf_right_, init_weight_.get_value(area_px), static_cast<unsigned>(area_px))); auto right_px = static_cast<int>(limit_px(leaf_right_, init_weight_.get_value(area_px), static_cast<unsigned>(area_px)));
@ -1642,7 +1617,7 @@ namespace nana
else if (pos > limited_range.right()) else if (pos > limited_range.right())
pos = limited_range.right(); pos = limited_range.right();
area_rotator sp_r(vert, field_area); nana::rectangle_rotator sp_r(vert, field_area);
sp_r.x_ref() = pos; sp_r.x_ref() = pos;
left.w_ref() = static_cast<unsigned>(pos - left.x()); left.w_ref() = static_cast<unsigned>(pos - left.x());
@ -1658,7 +1633,7 @@ namespace nana
leaf_right_->collocate(wd); leaf_right_->collocate(wd);
//Set the leafs' weight //Set the leafs' weight
area_rotator area(vert, div_owner->field_area); rectangle_rotator area(vert, div_owner->field_area);
double imd_rate = 100.0 / static_cast<int>(area.w()); double imd_rate = 100.0 / static_cast<int>(area.w());
leaf_left_->weight.assign_percent(imd_rate * static_cast<int>(left.w())); leaf_left_->weight.assign_percent(imd_rate * static_cast<int>(left.w()));
@ -1673,14 +1648,14 @@ namespace nana
splitter_.move(this->field_area); splitter_.move(this->field_area);
} }
private: private:
area_rotator _m_update_splitter_range() rectangle_rotator _m_update_splitter_range()
{ {
const bool vert = (cursor::size_ns == splitter_cursor_); const bool vert = (cursor::size_ns == splitter_cursor_);
area_rotator area(vert, div_owner->margin_area()); rectangle_rotator area(vert, div_owner->margin_area());
area_rotator left(vert, leaf_left_->field_area); rectangle_rotator left(vert, leaf_left_->field_area);
area_rotator right(vert, leaf_right_->field_area); rectangle_rotator right(vert, leaf_right_->field_area);
const int left_base = left.x(), right_base = right.right(); const int left_base = left.x(), right_base = right.right();
int pos = left_base; int pos = left_base;
@ -1785,7 +1760,7 @@ namespace nana
if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division)) if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division))
{ {
auto splitter = new div_splitter(tknizer.number()); auto splitter = new div_splitter(tknizer.number());
splitter->leaf_left(children.back().get()); splitter->set_leaf(true, children.back().get());
children.back()->div_next = splitter; children.back()->div_next = splitter;
children.emplace_back(splitter); children.emplace_back(splitter);
} }
@ -1797,7 +1772,7 @@ namespace nana
{ {
children.back()->div_next = div.get(); children.back()->div_next = div.get();
if (division::kind::splitter == children.back()->kind_of_division) if (division::kind::splitter == children.back()->kind_of_division)
dynamic_cast<div_splitter&>(*children.back()).leaf_right(div.get()); dynamic_cast<div_splitter&>(*children.back()).set_leaf(false, div.get());
} }
children.emplace_back(div.release()); children.emplace_back(div.release());
} }
@ -2182,29 +2157,14 @@ namespace nana
bool recollocate = false; bool recollocate = false;
for (auto & fld : impl_->fields) for (auto & fld : impl_->fields)
{ {
auto & elements = fld.second->elements; auto evt = fld.second->erase_element(fld.second->elements, handle);
for (auto i = elements.begin(); i != elements.end();) if (evt)
{ {
if (i->handle == handle) API::umake_event(evt);
{ recollocate |= (nullptr != fld.second->attached);
API::umake_event(i->evt_destroy);
i = elements.erase(i);
recollocate |= (nullptr != fld.second->attached);
}
else
++i;
} }
auto i = std::find_if(fld.second->fastened.begin(), fld.second->fastened.end(), [handle](implement::field_impl::element_t& e) API::umake_event( fld.second->erase_element(fld.second->fastened, handle));
{
return (e.handle == handle);
});
if (i != fld.second->fastened.end())
{
API::umake_event(i->evt_destroy);
fld.second->fastened.erase(i);
}
} }
if (recollocate) if (recollocate)

View File

@ -1,13 +1,14 @@
/* /*
* Nana GUI Programming Interface Implementation * Nana GUI Programming Interface Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/programming_interface.cpp * @file: nana/gui/programming_interface.cpp
* @author: Jinhao
*/ */
#include <nana/gui/programming_interface.hpp> #include <nana/gui/programming_interface.hpp>
@ -15,7 +16,6 @@
#include <nana/system/platform.hpp> #include <nana/system/platform.hpp>
#include <nana/gui/detail/native_window_interface.hpp> #include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/widgets/widget.hpp> #include <nana/gui/widgets/widget.hpp>
#include <algorithm>
namespace nana namespace nana
{ {
@ -53,7 +53,7 @@ namespace API
if (!restrict::window_manager.available(reinterpret_cast<restrict::core_window_t*>(wd))) if (!restrict::window_manager.available(reinterpret_cast<restrict::core_window_t*>(wd)))
return nullptr; return nullptr;
return reinterpret_cast<restrict::core_window_t*>(wd)->together.attached_events; return reinterpret_cast<restrict::core_window_t*>(wd)->together.events_ptr.get();
} }
}//end namespace detail }//end namespace detail
@ -239,6 +239,11 @@ namespace API
return &reinterpret_cast<restrict::core_window_t*>(wd)->drawer.graphics; return &reinterpret_cast<restrict::core_window_t*>(wd)->drawer.graphics;
return nullptr; return nullptr;
} }
void delay_restore(bool enable)
{
restrict::bedrock.delay_restore(enable ? 0 : 1);
}
}//end namespace dev }//end namespace dev
//exit //exit
@ -259,8 +264,20 @@ namespace API
if((wd->thread_id == tid) && (wd->root != root)) if((wd->thread_id == tid) && (wd->root != root))
{ {
root = wd->root; root = wd->root;
if(roots.cend() == std::find(roots.cbegin(), roots.cend(), root)) for (auto i = roots.cbegin(); i != roots.cend(); ++i)
{
if (*i == root)
{
root = nullptr;
break;
}
}
if (!root)
{
root = wd->root;
roots.push_back(root); roots.push_back(root);
}
} }
} }
@ -598,7 +615,7 @@ namespace API
nana::size window_size(window wd) nana::size window_size(window wd)
{ {
nana::rectangle r; nana::rectangle r;
API::window_rectangle(wd, r); API::get_window_rectangle(wd, r);
return{ r.width, r.height }; return{ r.width, r.height };
} }
@ -618,7 +635,46 @@ namespace API
} }
} }
bool window_rectangle(window wd, rectangle& r) ::nana::size window_outline_size(window wd)
{
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
internal_scope_guard lock;
if (!restrict::window_manager.available(iwd))
return{};
auto sz = window_size(wd);
sz.width += iwd->extra_width;
sz.height += iwd->extra_height;
return sz;
}
void window_outline_size(window wd, const size& sz)
{
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
internal_scope_guard lock;
if (restrict::window_manager.available(iwd))
{
if (category::flags::root == iwd->other.category)
{
size inner_size = sz;
if (inner_size.width < iwd->extra_width)
inner_size.width = 0;
else
inner_size.width -= iwd->extra_width;
if (inner_size.height < iwd->extra_height)
inner_size.height = 0;
else
inner_size.height -= iwd->extra_height;
window_size(wd, inner_size);
}
else
window_size(wd, sz);
}
}
bool get_window_rectangle(window wd, rectangle& r)
{ {
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd); auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
internal_scope_guard lock; internal_scope_guard lock;
@ -751,7 +807,7 @@ namespace API
return cursor::arrow; return cursor::arrow;
} }
bool is_focus_window(window wd) bool is_focus_ready(window wd)
{ {
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd); auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
internal_scope_guard lock; internal_scope_guard lock;
@ -1163,17 +1219,6 @@ namespace API
} }
} }
void restore_menubar_taken_window()
{
auto wd = restrict::bedrock.get_menubar_taken();
if(wd)
{
internal_scope_guard lock;
restrict::window_manager.set_focus(wd, false);
restrict::window_manager.update(wd, true, false);
}
}
bool is_window_zoomed(window wd, bool ask_for_max) bool is_window_zoomed(window wd, bool ask_for_max)
{ {
auto const iwd = reinterpret_cast<restrict::core_window_t*>(wd); auto const iwd = reinterpret_cast<restrict::core_window_t*>(wd);

View File

@ -25,39 +25,22 @@ namespace nana
: public display : public display
{ {
public: public:
real_display(std::size_t number) real_display() = default; //For requirement of vector
: index_(number)
{
#if defined(NANA_WINDOWS)
DISPLAY_DEVICE disp;
disp.cb = sizeof disp;
if (::EnumDisplayDevices(nullptr, static_cast<DWORD>(index_), &disp, 0))
{
DEVMODE mode;
mode.dmSize = sizeof mode;
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
{
area_.x = mode.dmPosition.x;
area_.y = mode.dmPosition.y;
area_.width = mode.dmPelsWidth;
area_.height = mode.dmPelsHeight;
return;
}
}
#else
if (0 == index_)
{
area_ = detail::native_interface::primary_monitor_size();
return;
}
#endif
throw std::invalid_argument("Nana.Screen: Invalid monitor index.");
}
real_display(std::size_t number, const ::nana::rectangle& r) #if defined(NANA_WINDOWS)
: index_(number), area_(r) real_display(std::size_t number, const MONITORINFOEX& mi)
: index_(number),
is_primary_(mi.dwFlags & /*MONITORINFOF_PRIMARY*/ 0x1),
area_(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top),
workarea_(mi.rcWork.left, mi.rcWork.top, mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top)
{ {
} }
#else
real_display(std::size_t number, const ::nana::rectangle& r)
: index_(number), is_primary_(true), area_(r), workarea_(r)
{
}
#endif
public: public:
//Implementation of display //Implementation of display
std::size_t get_index() const override std::size_t get_index() const override
@ -65,13 +48,25 @@ namespace nana
return index_; return index_;
} }
bool is_primary_monitor() const override
{
return is_primary_;
}
const ::nana::rectangle& area() const override const ::nana::rectangle& area() const override
{ {
return area_; return area_;
} }
const ::nana::rectangle& workarea() const override
{
return workarea_;
}
private: private:
const std::size_t index_; std::size_t index_;
bool is_primary_;
::nana::rectangle area_; ::nana::rectangle area_;
::nana::rectangle workarea_;
}; };
//class screen //class screen
@ -92,7 +87,61 @@ namespace nana
return ::nana::detail::native_interface::primary_monitor_size(); return ::nana::detail::native_interface::primary_monitor_size();
} }
std::shared_ptr<display> screen::from_point(const point& pos)
struct screen::implement
{
std::vector<real_display> displays;
#if defined(NANA_WINDOWS)
void load_monitors()
{
std::vector<real_display> tmp;
::EnumDisplayMonitors(nullptr, nullptr, implement::enum_proc, reinterpret_cast<LPARAM>(&tmp));
tmp.swap(displays);
}
static BOOL __stdcall enum_proc(HMONITOR handle, HDC context, LPRECT r, LPARAM self_ptr)
{
auto disp_cont = reinterpret_cast<std::vector<real_display>*>(self_ptr);
MONITORINFOEX mi;
mi.cbSize = sizeof(MONITORINFOEX);
if (::GetMonitorInfo(handle, &mi))
disp_cont->emplace_back(disp_cont->size(), mi);
return TRUE;
}
#else
void load_monitors()
{
displays.clear();
displays.emplace_back(0, primary_monitor_size());
}
#endif
};
screen::screen()
: impl_(std::make_shared<implement>())
{
impl_->load_monitors();
}
void screen::reload()
{
//It is only when the screen is a moved-from object that impl_ is empty
if (!impl_)
std::make_shared<implement>().swap(impl_);
impl_->load_monitors();
}
std::size_t screen::count() const
{
return impl_->displays.size();
}
display& screen::from_point(const point& pos)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD); typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD);
@ -107,87 +156,47 @@ namespace nana
mi.cbSize = sizeof mi; mi.cbSize = sizeof mi;
if (::GetMonitorInfo(monitor, &mi)) if (::GetMonitorInfo(monitor, &mi))
{ {
DISPLAY_DEVICE disp; for (auto & disp : impl_->displays)
disp.cb = sizeof disp;
DWORD index = 0;
while (::EnumDisplayDevices(nullptr, index++, &disp, 0))
{ {
DEVMODE mode; auto & r = disp.area();
mode.dmSize = sizeof mode; if (r.x == mi.rcMonitor.left && r.y == mi.rcMonitor.top &&
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) r.width == unsigned(mi.rcMonitor.right - mi.rcMonitor.left) &&
{ r.height == unsigned(mi.rcMonitor.bottom - mi.rcMonitor.top)
if (mode.dmPosition.x == mi.rcWork.left && mode.dmPosition.y == mi.rcWork.top && )
(static_cast<int>(mode.dmPelsWidth) == mi.rcWork.right - mi.rcWork.left) && return disp;
(static_cast<int>(mode.dmPelsHeight) == mi.rcWork.bottom - mi.rcWork.top))
{
return std::make_shared<real_display>(static_cast<std::size_t>(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast<unsigned>(mode.dmPelsWidth), static_cast<unsigned>(mode.dmPelsHeight) });
}
}
} }
} }
} }
#endif #endif
return screen().get_primary(); return get_primary();
} }
std::shared_ptr<display> screen::from_window(window wd) display& screen::from_window(window wd)
{ {
::nana::point pos; ::nana::point pos;
API::calc_screen_point(wd, pos); API::calc_screen_point(wd, pos);
return from_point(pos); return from_point(pos);
} }
std::size_t screen::count() const
{
#if defined(NANA_WINDOWS)
DISPLAY_DEVICE disp;
disp.cb = sizeof disp;
DWORD index = 0; display& screen::get_display(std::size_t index) const
while (::EnumDisplayDevices(nullptr, index++, &disp, 0)); {
return static_cast<std::size_t>(index - 1); return impl_->displays.at(index);
#else
return 1;
#endif
} }
std::shared_ptr<display> screen::get_display(std::size_t index) const display& screen::get_primary() const
{ {
return std::make_shared<real_display>(index); for (auto & disp : impl_->displays)
} if (disp.is_primary_monitor())
return disp;
std::shared_ptr<display> screen::get_primary() const throw std::logic_error("no primary monitor found");
{
#if defined(NANA_WINDOWS)
//return rectangle(mi.rcWork.left, mi.rcWork.top,
// mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top);
DISPLAY_DEVICE disp;
disp.cb = sizeof disp;
DWORD index = 0;
while (::EnumDisplayDevices(nullptr, index++, &disp, 0))
{
DEVMODE mode;
mode.dmSize = sizeof mode;
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
{
if (mode.dmPosition.x == 0 && mode.dmPosition.y == 0)
return std::make_shared<real_display>(static_cast<std::size_t>(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast<unsigned>(mode.dmPelsWidth), static_cast<unsigned>(mode.dmPelsHeight) });
}
}
#endif
return std::make_shared<real_display>(0);
} }
void screen::for_each(std::function<void(display&)> fn) const void screen::for_each(std::function<void(display&)> fn) const
{ {
auto n = count(); for (auto & disp : impl_->displays)
for (decltype(n) i = 0; i < n; ++i)
{
real_display disp(i);
fn(disp); fn(disp);
}
} }
//end class screen //end class screen
} }

View File

@ -109,11 +109,11 @@ namespace nana
{ {
public: public:
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
timer_core(timer_identifier tmid, const nana::basic_event<arg_elapse>& evt_elapse) timer_core(timer_identifier tmid, basic_event<arg_elapse>& evt_elapse)
: timer_(tmid), evt_elapse_(evt_elapse) : timer_(tmid), evt_elapse_(evt_elapse)
{} {}
#else #else
timer_core(const nana::basic_event<arg_elapse>& evt_elapse) timer_core(basic_event<arg_elapse>& evt_elapse)
: timer_(this), evt_elapse_(evt_elapse) : timer_(this), evt_elapse_(evt_elapse)
{} {}
#endif #endif
@ -138,7 +138,7 @@ namespace nana
} }
private: private:
const timer_identifier timer_; const timer_identifier timer_;
const nana::basic_event<arg_elapse> & evt_elapse_; nana::basic_event<arg_elapse> & evt_elapse_;
}; //end class timer_core }; //end class timer_core
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)

View File

@ -1,6 +1,7 @@
/* /*
* A Tooltip Implementation * A Tooltip Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -34,14 +35,14 @@ namespace nana
nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed) nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed)
{ {
auto scr_area = screen::from_point(pos)->area(); auto scr_area = screen().from_point(pos).workarea();
if (pos.x + sz.width > scr_area.x + scr_area.width) if (pos.x + static_cast<int>(sz.width) > scr_area.right())
pos.x = static_cast<int>(scr_area.x + scr_area.width - sz.width); pos.x = scr_area.right() - static_cast<int>(sz.width);
if (pos.x < scr_area.x) if (pos.x < scr_area.x)
pos.x = scr_area.x; pos.x = scr_area.x;
if (pos.y + sz.height >= scr_area.y + scr_area.height) if (pos.y + static_cast<int>(sz.height) >= scr_area.bottom())
pos.y = static_cast<int>(scr_area.y + scr_area.height - sz.height); pos.y = scr_area.bottom() - static_cast<int>(sz.height);
else if (!overlap_allowed) else if (!overlap_allowed)
pos.y += 20; //Add some pixels to avoid overlapping between cursor and tip window. pos.y += 20; //Add some pixels to avoid overlapping between cursor and tip window.
@ -77,7 +78,7 @@ namespace nana
void tooltip_text(const nana::string& text) override void tooltip_text(const nana::string& text) override
{ {
label_.caption(text); label_.caption(text);
auto text_s = label_.measure(screen::from_window(label_)->area().width * 2 / 3); auto text_s = label_.measure(screen().from_window(label_).workarea().width * 2 / 3);
this->size(nana::size{ text_s.width + 10, text_s.height + 10 }); this->size(nana::size{ text_s.width + 10, text_s.height + 10 });
label_.move(rectangle{ 5, 5, text_s.width, text_s.height }); label_.move(rectangle{ 5, 5, text_s.width, text_s.height });

View File

@ -129,22 +129,26 @@ namespace checkbox
checkbox::checkbox(window wd, bool visible) checkbox::checkbox(window wd, bool visible)
{ {
create(wd, rectangle(), visible); create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
} }
checkbox::checkbox(window wd, const nana::string& text, bool visible) checkbox::checkbox(window wd, const nana::string& text, bool visible)
{ {
create(wd, rectangle(), visible); create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
caption(text); caption(text);
} }
checkbox::checkbox(window wd, const nana::char_t* text, bool visible) checkbox::checkbox(window wd, const nana::char_t* text, bool visible)
{ {
create(wd, rectangle(), visible); create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
caption(text); caption(text);
} }
checkbox::checkbox(window wd, const nana::rectangle& r, bool visible) checkbox::checkbox(window wd, const nana::rectangle& r, bool visible)
{ {
bgcolor(API::bgcolor(wd));
create(wd, r, visible); create(wd, r, visible);
} }

View File

@ -677,6 +677,7 @@ namespace nana
if(!drawer_->widget_ptr()->enabled()) if(!drawer_->widget_ptr()->enabled())
return; return;
bool call_other_keys = false;
if(drawer_->editable()) if(drawer_->editable())
{ {
bool is_move_up = false; bool is_move_up = false;
@ -684,7 +685,7 @@ namespace nana
{ {
case keyboard::os_arrow_left: case keyboard::os_arrow_left:
case keyboard::os_arrow_right: case keyboard::os_arrow_right:
drawer_->editor()->move(arg.key); drawer_->editor()->respond_key(arg.key);
drawer_->editor()->reset_caret(); drawer_->editor()->reset_caret();
break; break;
case keyboard::os_arrow_up: case keyboard::os_arrow_up:
@ -692,6 +693,8 @@ namespace nana
case keyboard::os_arrow_down: case keyboard::os_arrow_down:
drawer_->move_items(is_move_up, true); drawer_->move_items(is_move_up, true);
break; break;
default:
call_other_keys = true;
} }
} }
else else
@ -706,14 +709,19 @@ namespace nana
case keyboard::os_arrow_down: case keyboard::os_arrow_down:
drawer_->move_items(is_move_up, true); drawer_->move_items(is_move_up, true);
break; break;
default:
call_other_keys = true;
} }
} }
if (call_other_keys)
drawer_->editor()->respond_key(arg.key);
API::lazy_refresh(); API::lazy_refresh();
} }
void trigger::key_char(graph_reference graph, const arg_keyboard& arg) void trigger::key_char(graph_reference graph, const arg_keyboard& arg)
{ {
if (drawer_->editor()->respone_keyboard(arg.key)) if (drawer_->editor()->respond_char(arg.key))
API::lazy_refresh(); API::lazy_refresh();
} }
//end class trigger //end class trigger

View File

@ -37,21 +37,25 @@ namespace nana
::nana::color clr{ 0xaf, 0xc7, 0xe3 }; ::nana::color clr{ 0xaf, 0xc7, 0xe3 };
graph.rectangle(r, false, clr); graph.rectangle(r, false, clr);
auto right = r.right() - 1;
auto bottom = r.bottom() - 1;
graph.set_color(colors::white); graph.set_color(colors::white);
graph.set_pixel(r.x, r.y); graph.set_pixel(r.x, r.y);
graph.set_pixel(r.x + r.width - 1, r.y); graph.set_pixel(right, r.y);
graph.set_pixel(r.x, r.y + r.height - 1); graph.set_pixel(r.x, bottom);
graph.set_pixel(r.x + r.width - 1, r.y + r.height - 1); graph.set_pixel(right, bottom);
--right;
--bottom;
graph.set_color(clr); graph.set_color(clr);
graph.set_pixel(r.x + 1, r.y + 1); graph.set_pixel(r.x + 1, r.y + 1);
graph.set_pixel(r.x + r.width - 2, r.y + 1); graph.set_pixel(right, r.y + 1);
graph.set_pixel(r.x + 1, r.y + r.height - 2); graph.set_pixel(r.x + 1, bottom);
graph.set_pixel(r.x + r.width - 2, r.y + r.height - 2); graph.set_pixel(right, bottom);
nana::rectangle po_r(r); nana::rectangle po_r(r);
graph.rectangle(po_r.pare_off(1), false, { 0xEB, 0xF4, 0xFB }); graph.rectangle(po_r.pare_off(1), false, static_cast<color_rgb>(0xEBF4FB));
graph.gradual_rectangle(po_r.pare_off(1), { 0xDD, 0xEC, 0xFD }, { 0xC2, 0xDC, 0xFD }, true); graph.gradual_rectangle(po_r.pare_off(1), static_cast<color_rgb>(0xDDECFD), static_cast<color_rgb>(0xC2DCFD), true);
} }
else else
graph.rectangle(r, true, colors::white); graph.rectangle(r, true, colors::white);
@ -113,13 +117,8 @@ namespace nana
class drawer_impl class drawer_impl
{ {
public: public:
typedef widget& widget_reference; using widget_reference = widget&;
typedef nana::paint::graphics& graph_reference; using graph_reference = paint::graphics&;
drawer_impl()
: widget_(nullptr), graph_(nullptr), image_pixels_(16),
ignore_first_mouseup_(true), module_(nullptr)
{}
void clear_state() void clear_state()
{ {
@ -151,25 +150,19 @@ namespace nana
{ {
if(scrollbar_.empty()) return; if(scrollbar_.empty()) return;
bool update = false; const auto before_change = state_.offset_y;
if(upwards) if(upwards)
{ {
if(state_.offset_y) if (before_change)
{
--(state_.offset_y); --(state_.offset_y);
update = true;
}
} }
else else
{ {
if((state_.offset_y + module_->max_items) < module_->items.size()) if ((before_change + module_->max_items) < module_->items.size())
{
++(state_.offset_y); ++(state_.offset_y);
update = true;
}
} }
if(update) if(before_change != state_.offset_y)
{ {
draw(); draw();
scrollbar_.value(state_.offset_y); scrollbar_.value(state_.offset_y);
@ -323,8 +316,7 @@ namespace nana
state_.renderer->image(_m_image_enabled(), image_pixels_); state_.renderer->image(_m_image_enabled(), image_pixels_);
for(std::size_t i = state_.offset_y; i < items; ++i) for(std::size_t i = state_.offset_y; i < items; ++i)
{ {
item_renderer::state_t state = item_renderer::StateNone; auto state = (i != state_.index ? item_renderer::StateNone : item_renderer::StateHighlighted);
if(i == state_.index) state = item_renderer::StateHighlighted;
state_.renderer->render(*widget_, *graph_, item_r, module_->items[i].get(), state); state_.renderer->render(*widget_, *graph_, item_r, module_->items[i].get(), state);
item_r.y += item_pixels; item_r.y += item_pixels;
@ -384,20 +376,20 @@ namespace nana
scrollbar_.close(); scrollbar_.close();
} }
private: private:
widget * widget_; widget * widget_{nullptr};
nana::paint::graphics * graph_; nana::paint::graphics * graph_{nullptr};
unsigned image_pixels_; //Define the width pixels of the image area unsigned image_pixels_{16}; //Define the width pixels of the image area
bool ignore_first_mouseup_; bool ignore_first_mouseup_{true};
struct state_type struct state_type
{ {
std::size_t offset_y; std::size_t offset_y{0};
std::size_t index; //The index of the selected item. std::size_t index{npos}; //The index of the selected item.
item_renderer * const orig_renderer; item_renderer * const orig_renderer;
item_renderer * renderer; item_renderer * renderer;
state_type(): offset_y(0), index(npos), orig_renderer(new def_item_renderer), renderer(orig_renderer){} state_type(): orig_renderer(new def_item_renderer), renderer(orig_renderer){}
~state_type() ~state_type()
{ {
delete orig_renderer; delete orig_renderer;
@ -405,7 +397,7 @@ namespace nana
}state_; }state_;
nana::scroll<true> scrollbar_; nana::scroll<true> scrollbar_;
const module_def* module_; const module_def* module_{nullptr};
}; };
//class drawer_impl; //class drawer_impl;

View File

@ -8,6 +8,8 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: source/gui/widgets/label.cpp * @file: source/gui/widgets/label.cpp
* @author: Jinhao
* @contributors: Ariel Vina-Rodriguez
*/ */
#include <nana/gui/widgets/label.hpp> #include <nana/gui/widgets/label.hpp>
@ -586,8 +588,6 @@ namespace nana
std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos) std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos)
{ {
std::pair<std::size_t, std::size_t> r;
std::size_t n = i->data_ptr->text().length(); std::size_t n = i->data_ptr->text().length();
while(pos >= n) while(pos >= n)
{ {
@ -765,23 +765,27 @@ namespace nana
label::label(window wd, bool visible) label::label(window wd, bool visible)
{ {
create(wd, rectangle(), visible); create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
} }
label::label(window wd, const nana::string& text, bool visible) label::label(window wd, const nana::string& text, bool visible)
{ {
create(wd, rectangle(), visible); create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
caption(text); caption(text);
} }
label::label(window wd, const nana::char_t* text, bool visible) label::label(window wd, const nana::char_t* text, bool visible)
{ {
create(wd, rectangle(), visible); create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
caption(text); caption(text);
} }
label::label(window wd, const rectangle& r, bool visible) label::label(window wd, const rectangle& r, bool visible)
{ {
create(wd, r, visible); create(wd, r, visible);
bgcolor(API::bgcolor(wd));
} }
label& label::transparent(bool enabled) label& label::transparent(bool enabled)
@ -847,24 +851,16 @@ namespace nana
label& label::text_align(align th, align_v tv) label& label::text_align(align th, align_v tv)
{ {
internal_scope_guard isg; internal_scope_guard lock;
auto impl = get_drawer_trigger().impl(); auto impl = get_drawer_trigger().impl();
bool to_update = false; if (th != impl->text_align || tv != impl->text_align_v)
if(impl->text_align != th)
{ {
impl->text_align = th; impl->text_align = th;
to_update = true;
}
if(impl->text_align_v != tv)
{
impl->text_align_v = tv; impl->text_align_v = tv;
to_update = true; API::refresh_window(*this);
} }
if(to_update)
API::refresh_window(*this);
return *this; return *this;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* /*
* A Menu implementation * A Menu implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2009-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -106,7 +106,7 @@ namespace nana
sz.width -= 30; sz.width -= 30;
sz.height -= 2; sz.height -= 2;
graph.rectangle(false, colors::gray_border); graph.rectangle(false, colors::gray_border);
graph.rectangle({ 1, 1, 28, sz.height }, true, { 0xf6, 0xf6, 0xf6 }); graph.rectangle({ 1, 1, 28, sz.height }, true, static_cast<color_rgb>(0xf6f6f6));
graph.rectangle({ 29, 1, sz.width, sz.height }, true, colors::white); graph.rectangle({ 29, 1, sz.width, sz.height }, true, colors::white);
} }
@ -122,17 +122,17 @@ namespace nana
nana::point(r.x + r.width - 1, r.y + r.height - 1) nana::point(r.x + r.width - 1, r.y + r.height - 1)
}; };
graph.set_color({0xc0, 0xdd, 0xfc}); graph.set_color(static_cast<color_rgb>(0xc0ddfc));
for(int i = 0; i < 4; ++i) for(int i = 0; i < 4; ++i)
graph.set_pixel(points[i].x, points[i].y); graph.set_pixel(points[i].x, points[i].y);
if(at.enabled) if(at.enabled)
graph.gradual_rectangle(nana::rectangle(r).pare_off(1), { 0xE8, 0xF0, 0xF4 }, { 0xDB,0xEC,0xF4 }, true); graph.gradual_rectangle(nana::rectangle(r).pare_off(1), static_cast<color_rgb>(0xE8F0F4), static_cast<color_rgb>(0xDBECF4), true);
} }
if(at.checked && (checks::none != at.check_style)) if(at.checked && (checks::none != at.check_style))
{ {
graph.rectangle(r, false, { 0xCD, 0xD3, 0xE6 }); graph.rectangle(r, false, static_cast<color_rgb>(0xCDD3E6));
::nana::color clr(0xE6, 0xEF, 0xF4); ::nana::color clr(0xE6, 0xEF, 0xF4);
graph.rectangle(nana::rectangle(r).pare_off(1), true, clr); graph.rectangle(nana::rectangle(r).pare_off(1), true, clr);
@ -151,7 +151,7 @@ namespace nana
void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at) void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at)
{ {
graph.set_color(at.enabled ? colors::black : colors::gray_border); graph.set_text_color(at.enabled ? colors::black : colors::gray_border);
nana::paint::text_renderer tr(graph); nana::paint::text_renderer tr(graph);
tr.render(pos, text.c_str(), text.length(), text_pixels, true); tr.render(pos, text.c_str(), text.length(), text_pixels, true);
} }
@ -363,59 +363,58 @@ namespace nana
bool goto_next(bool forword) bool goto_next(bool forword)
{ {
state_.nullify_mouse = true; state_.nullify_mouse = true;
if(menu_->items.size()) if (menu_->items.empty())
{ return false;
std::size_t index = state_.active;
bool end = false; auto pos = state_.active;
while(true) const auto lastpos = menu_->items.size() - 1;
bool end = false;
while(true)
{
if(forword)
{ {
if(forword) if(pos == lastpos)
{ {
if(index == menu_->items.size() - 1) if (end)
{ {
if(end == false) pos = npos;
{ break;
end = true;
index = 0;
}
else
{
index = npos;
break;
}
} }
else
++index; end = true;
pos = 0;
} }
else else
{ ++pos;
if(index == 0 || index == npos)
{
if(end == false)
{
end = true;
index = menu_->items.size() - 1;
}
else
break;
}
else
--index;
}
if(menu_->items.at(index).flags.splitter == false)
break;
} }
else
if(index != npos && index != state_.active)
{ {
state_.active = index; if(pos == 0 || pos == npos)
state_.sub_window = false; {
if (end)
draw(); break;
return true;
end = true;
pos = lastpos;
}
else
--pos;
} }
if(! menu_->items.at(pos).flags.splitter)
break;
} }
if(pos != npos && pos != state_.active)
{
state_.active = pos;
state_.sub_window = false;
draw();
return true;
}
return false; return false;
} }
@ -486,30 +485,32 @@ namespace nana
std::size_t index = 0; std::size_t index = 0;
for(auto & m : menu_->items) for(auto & m : menu_->items)
{ {
if(std::tolower(m.hotkey) == key) if (std::tolower(m.hotkey) != key)
{ {
if(!m.flags.splitter) ++index;
{ continue;
if(m.sub_menu)
{
state_.active = index;
state_.active_timestamp = nana::system::timestamp();
draw();
API::update_window(*widget_);
return 2;
}
else if(m.flags.enabled)
{
std::move(fn_close_tree_)();
item_proxy ip(index, m);
m.functor.operator()(ip);
return 1;
}
}
break;
} }
++index;
if(!m.flags.splitter)
{
if(m.sub_menu)
{
state_.active = index;
state_.active_timestamp = nana::system::timestamp();
draw();
API::update_window(*widget_);
return 2;
}
else if(m.flags.enabled)
{
std::move(fn_close_tree_)();
item_proxy ip(index, m);
m.functor.operator()(ip);
return 1;
}
}
break;
} }
return 0; return 0;
} }
@ -529,53 +530,53 @@ namespace nana
int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2; int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2;
std::size_t index = 0; std::size_t pos = 0;
for(auto & m : menu_->items) for(auto & m : menu_->items)
{ {
if(false == m.flags.splitter) if(m.flags.splitter)
{
renderer_interface::attr attr = _m_make_renderer_attr(index == state_.active, m);
//Draw item background
renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character
nana::char_t hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
if(m.image.empty() == false)
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image);
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if(hotkey)
{
m.hotkey = hotkey;
if(m.flags.enabled)
{
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
int x = item_r.x + 40 + off_w;
int y = item_r.y + text_top_off + hotkey_size.height;
graph_->set_color(colors::black);
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
}
}
if(m.sub_menu)
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1;
}
else
{ {
graph_->set_color(colors::gray_border); graph_->set_color(colors::gray_border);
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph_->width()) - 1, item_r.y }); graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph_->width()) - 1, item_r.y });
item_r.y += 2; item_r.y += 2;
++pos;
continue;
}
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
//Draw item background
renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character
nana::char_t hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
if(m.image.empty() == false)
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image);
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if(hotkey)
{
m.hotkey = hotkey;
if(m.flags.enabled)
{
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
int x = item_r.x + 40 + off_w;
int y = item_r.y + text_top_off + hotkey_size.height;
graph_->set_color(colors::black);
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
}
} }
++index; if(m.sub_menu)
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1;
++pos;
} }
} }
private: private:
@ -592,9 +593,9 @@ namespace nana
std::size_t _m_get_index_by_pos(int x, int y) const std::size_t _m_get_index_by_pos(int x, int y) const
{ {
if( (x < static_cast<int>(detail_.border.x)) || if( (x < static_cast<int>(detail_.border.x)) ||
(x > static_cast<int>(graph_->width() - detail_.border.x)) || (x > static_cast<int>(graph_->width()) - static_cast<int>(detail_.border.x)) ||
(y < static_cast<int>(detail_.border.y)) || (y < static_cast<int>(detail_.border.y)) ||
(y > static_cast<int>(graph_->height() - detail_.border.y))) (y > static_cast<int>(graph_->height()) - static_cast<int>(detail_.border.y)))
return npos; return npos;
int pos = detail_.border.y; int pos = detail_.border.y;
@ -659,14 +660,14 @@ namespace nana
API::calc_screen_point(*widget_, pos); API::calc_screen_point(*widget_, pos);
//get the screen coordinates of the widget pos. //get the screen coordinates of the widget pos.
auto scr_area = screen::from_point(detail_.monitor_pos)->area(); auto scr_area = screen().from_point(detail_.monitor_pos).workarea();
if(pos.x + size.width > scr_area.x + scr_area.width) if(pos.x + static_cast<int>(size.width) > scr_area.right())
pos.x = static_cast<int>(scr_area.x + scr_area.width - size.width); pos.x = scr_area.right() - static_cast<int>(size.width);
if(pos.x < scr_area.x) pos.x = scr_area.x; if(pos.x < scr_area.x) pos.x = scr_area.x;
if(pos.y + size.height > scr_area.y + scr_area.height) if(pos.y + static_cast<int>(size.height) > scr_area.bottom())
pos.y = static_cast<int>(scr_area.y + scr_area.height - size.height); pos.y = scr_area.bottom() - static_cast<int>(size.height);
if(pos.y < scr_area.y) pos.y = scr_area.y; if(pos.y < scr_area.y) pos.y = scr_area.y;
auto owner = API::get_owner_window(*widget_); auto owner = API::get_owner_window(*widget_);
@ -705,7 +706,7 @@ namespace nana
menu_window(window wd, const point& pos, renderer_interface * rdptr) menu_window(window wd, const point& pos, renderer_interface * rdptr)
: base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()), : base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()),
want_focus_(nullptr == wd), want_focus_(nullptr == wd || (API::focus_window() != wd)),
event_focus_(nullptr) event_focus_(nullptr)
{ {
caption(STR("nana menu window")); caption(STR("nana menu window"));
@ -729,11 +730,6 @@ namespace nana
API::activate_window(this->parent()); API::activate_window(this->parent());
API::take_active(this->handle(), false, nullptr); API::take_active(this->handle(), false, nullptr);
} }
else
{
activate();
focus();
}
if(submenu_.parent == nullptr) if(submenu_.parent == nullptr)
{ {
@ -753,14 +749,6 @@ namespace nana
pick(); pick();
}); });
if (want_focus_)
{
event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg)
{
_m_focus_changed(arg);
});
}
timer_.interval(100); timer_.interval(100);
timer_.elapse([this]{ timer_.elapse([this]{
this->_m_check_repeatly(); this->_m_check_repeatly();
@ -768,6 +756,30 @@ namespace nana
timer_.start(); timer_.start();
show(); show();
if (want_focus_)
{
event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg)
{
//when the focus of the menu window is losing, close the menu.
//But here is not every menu window may have focus event installed,
//It is only installed when the owner of window is the desktop window.
if (false == arg.getting && (arg.receiver != API::root(*this)))
{
for (auto child = submenu_.child; child; child = child->submenu_.child)
{
if (API::root(child->handle()) == arg.receiver)
return;
}
_m_close_all();
}
});
focus();
activate();
}
} }
void goto_next(bool forward) void goto_next(bool forward)
@ -783,39 +795,33 @@ namespace nana
API::update_window(object->handle()); API::update_window(object->handle());
} }
bool goto_submenu() bool submenu(bool enter)
{ {
menu_window * object = this; menu_window * object = this;
while(object->submenu_.child) while (object->submenu_.child)
object = object->submenu_.child; object = object->submenu_.child;
state_.auto_popup_submenu = false; state_.auto_popup_submenu = false;
if (enter)
{
if (object->submenu_.parent)
{
auto & sub = object->submenu_.parent->submenu_;
sub.child = nullptr;
sub.object = nullptr;
object->close();
return true;
}
return false;
}
nana::point pos; nana::point pos;
menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0); menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0);
return object->_m_show_submenu(sbm, pos, true); return object->_m_show_submenu(sbm, pos, true);
} }
bool exit_submenu()
{
menu_window * object =this;
while(object->submenu_.child)
object = object->submenu_.child;
state_.auto_popup_submenu = false;
if (object->submenu_.parent)
{
auto & sub = object->submenu_.parent->submenu_;
sub.child = nullptr;
sub.object = nullptr;
object->close();
return true;
}
return false;
}
int send_shortkey(nana::char_t key) int send_shortkey(nana::char_t key)
{ {
menu_window * object = this; menu_window * object = this;
@ -832,62 +838,52 @@ namespace nana
object = object->submenu_.child; object = object->submenu_.child;
auto active = object->get_drawer_trigger().active(); auto active = object->get_drawer_trigger().active();
if (active != npos) auto * menu = object->get_drawer_trigger().data();
if ((npos == active) || !menu)
return;
menu_item_type & item = menu->items.at(active);
if (item.flags.splitter == false && item.sub_menu == nullptr)
{ {
auto * menu = object->get_drawer_trigger().data(); //There is a situation that menu will not call functor if the item style is check_option
if (menu) //and it is checked before clicking.
bool call_functor = true;
if (checks::highlight == item.style)
{ {
menu_item_type & item = menu->items.at(active); item.flags.checked = !item.flags.checked;
if (item.flags.splitter == false && item.sub_menu == nullptr) }
else if (checks::option == item.style)
{
//Forward Looks for a splitter
auto pos = active;
while (pos)
{ {
//There is a situation that menu will not call functor if the item style is check_option if (menu->items.at(--pos).flags.splitter)
//and it is checked before clicking. break;
bool call_functor = true;
if (checks::highlight == item.style)
{
item.flags.checked = !item.flags.checked;
}
else if (checks::option == item.style)
{
if (active > 0)
{
//clear the checked state in front of active if it is check_option.
auto i = active;
do
{
--i;
menu_item_type & im = menu->items.at(i);
if (im.flags.splitter) break;
if (checks::option == im.style && im.flags.checked)
im.flags.checked = false;
} while (i);
}
for (auto i = active + 1; i < menu->items.size(); ++i)
{
menu_item_type & im = menu->items.at(i);
if (im.flags.splitter) break;
if ((checks::option == im.style) && im.flags.checked)
im.flags.checked = false;
}
item.flags.checked = true;
}
this->_m_close_all(); //means deleting this;
//The deleting operation has moved here, because item.functor.operator()(ip)
//may create a window, which make a killing focus for menu window, if so the close_all
//operation preformences after item.functor.operator()(ip), that would be deleting this object twice!
if (call_functor && item.flags.enabled && item.functor)
{
item_type::item_proxy ip(active, item);
item.functor.operator()(ip);
}
} }
for (; pos < menu->items.size(); ++pos)
{
menu_item_type & im = menu->items.at(pos);
if (im.flags.splitter) break;
if ((checks::option == im.style) && im.flags.checked)
im.flags.checked = false;
}
item.flags.checked = true;
}
this->_m_close_all(); //means deleting this;
//The deleting operation has moved here, because item.functor.operator()(ip)
//may create a window, which make a killing focus for menu window, if so the close_all
//operation preformences after item.functor.operator()(ip), that would be deleting this object twice!
if (call_functor && item.flags.enabled && item.functor)
{
item_type::item_proxy ip(active, item);
item.functor.operator()(ip);
} }
} }
} }
@ -943,50 +939,29 @@ namespace nana
} }
} }
//when the focus of the menu window is losing, close the menu.
//But here is not every menu window may have focus event installed,
//It is only installed when the owner of window is the desktop window.
void _m_focus_changed(const arg_focus& arg)
{
if (false == arg.getting)
{
for (auto child = submenu_.child; child; child = child->submenu_.child)
{
if (API::root(child->handle()) == arg.receiver)
return;
}
_m_close_all();
}
}
void _m_key_down(const arg_keyboard& arg) void _m_key_down(const arg_keyboard& arg)
{ {
switch(arg.key) switch(arg.key)
{ {
case keyboard::os_arrow_up: case keyboard::os_arrow_up:
this->goto_next(false);
break;
case keyboard::os_arrow_down: case keyboard::os_arrow_down:
this->goto_next(true); this->goto_next(keyboard::os_arrow_down == arg.key);
break; break;
case keyboard::os_arrow_left: case keyboard::os_arrow_left:
this->exit_submenu();
break;
case keyboard::os_arrow_right: case keyboard::os_arrow_right:
this->goto_submenu(); this->submenu(keyboard::os_arrow_right == arg.key);
break; break;
case keyboard::enter: case keyboard::enter:
this->pick(); this->pick();
break; break;
default: default:
if(2 != send_shortkey(arg.key)) if (2 != send_shortkey(arg.key))
{ {
if(API::empty_window(*this) == false) if (API::empty_window(*this) == false)
close(); close();
} }
else else
goto_submenu(); this->submenu(true);
} }
} }
@ -1165,7 +1140,7 @@ namespace nana
{ {
if(impl_->mbuilder.set_sub_menu(index, menu_obj.impl_->mbuilder.data())) if(impl_->mbuilder.set_sub_menu(index, menu_obj.impl_->mbuilder.data()))
{ {
implement::info& minfo = impl_->sub_container[index]; auto& minfo = impl_->sub_container[index];
minfo.handle = &menu_obj; minfo.handle = &menu_obj;
minfo.kill = false; minfo.kill = false;
return true; return true;
@ -1184,9 +1159,10 @@ namespace nana
menu *menu::create_sub_menu(std::size_t index) menu *menu::create_sub_menu(std::size_t index)
{ {
menu * sub = new menu; menu * sub = new menu;
if(link(index, *sub))
if (this->link(index, *sub))
{ {
implement::info& minfo = impl_->sub_container[index]; auto& minfo = impl_->sub_container[index];
minfo.handle = sub; minfo.handle = sub;
minfo.kill = true; minfo.kill = true;
return sub; return sub;
@ -1255,12 +1231,12 @@ namespace nana
bool menu::goto_submen() bool menu::goto_submen()
{ {
return (impl_->uiobj ? impl_->uiobj->goto_submenu() : false); return (impl_->uiobj ? impl_->uiobj->submenu(true) : false);
} }
bool menu::exit_submenu() bool menu::exit_submenu()
{ {
return (impl_->uiobj ? impl_->uiobj->exit_submenu() : false); return (impl_->uiobj ? impl_->uiobj->submenu(false) : false);
} }
std::size_t menu::size() const std::size_t menu::size() const
@ -1311,21 +1287,17 @@ namespace nana
impl_->mbuilder.renderer(rd); impl_->mbuilder.renderer(rd);
} }
void menu::_m_destroy_menu_window()
{
impl_->uiobj = nullptr;
if(impl_->destroy_answer)
impl_->destroy_answer();
}
void menu::_m_popup(window wd, int x, int y, bool called_by_menubar) void menu::_m_popup(window wd, int x, int y, bool called_by_menubar)
{ {
if (impl_->mbuilder.data().items.size()) if (impl_->mbuilder.data().items.size())
{ {
close(); close();
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, point(x, y), &(*impl_->mbuilder.renderer()))); impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, point(x, y), &(*impl_->mbuilder.renderer())));
impl_->uiobj->events().destroy.connect_unignorable([this]{ impl_->uiobj->events().destroy.connect_unignorable([this]{
_m_destroy_menu_window(); impl_->uiobj = nullptr;
if (impl_->destroy_answer)
impl_->destroy_answer();
}); });
impl_->uiobj->popup(impl_->mbuilder.data(), called_by_menubar); impl_->uiobj->popup(impl_->mbuilder.data(), called_by_menubar);
} }

View File

@ -1,7 +1,7 @@
/* /*
* A Menubar implementation * A Menubar implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2009-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -30,21 +30,21 @@ namespace nana
{ {
struct item_type struct item_type
{ {
item_type(const nana::string& text, unsigned long shortkey) item_type(const ::nana::string& text, unsigned long shortkey)
: text(text), shortkey(shortkey) : text(text), shortkey(shortkey)
{} {}
nana::string text; ::nana::string text;
unsigned long shortkey; unsigned long shortkey;
nana::menu menu_obj; ::nana::menu menu_obj;
nana::point pos; ::nana::point pos;
nana::size size; ::nana::size size;
}; };
class trigger::itembase class trigger::itembase
{ {
public: public:
typedef std::vector<item_type*> container; using container = std::vector<item_type*>;
~itembase() ~itembase()
{ {
@ -52,22 +52,12 @@ namespace nana
delete i; delete i;
} }
void append(const nana::string& text, unsigned long shortkey) void append(const ::nana::string& text, unsigned long shortkey)
{ {
if(shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41); if(shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41);
cont_.push_back(new item_type(text, shortkey)); cont_.push_back(new item_type(text, shortkey));
} }
nana::menu* get_menu(std::size_t index) const
{
return (index < cont_.size() ? &(cont_[index]->menu_obj) : nullptr);
}
const item_type& at(std::size_t index) const
{
return *cont_.at(index);
}
std::size_t find(unsigned long shortkey) const std::size_t find(unsigned long shortkey) const
{ {
if(shortkey) if(shortkey)
@ -98,19 +88,19 @@ namespace nana
:handle_(wd), graph_(graph) :handle_(wd), graph_(graph)
{} {}
void item_renderer::background(const nana::point& pos, const nana::size& size, state_t state) void item_renderer::background(const nana::point& pos, const nana::size& size, state item_state)
{ {
auto bground = API::fgcolor(handle_); auto bground = API::fgcolor(handle_);
::nana::color border, body, corner; ::nana::color border, body, corner;
switch(state) switch (item_state)
{ {
case item_renderer::state_highlight: case state::highlighted:
border = colors::highlight; border = colors::highlight;
body.from_rgb(0xC0, 0xDD, 0xFC); body.from_rgb(0xC0, 0xDD, 0xFC);
corner = body.blend(bground, 0.5); corner = body.blend(bground, 0.5);
break; break;
case item_renderer::state_selected: case state::selected:
border = colors::dark_border; border = colors::dark_border;
body = colors::white; body = colors::white;
corner = body.blend(bground, 0.5); corner = body.blend(bground, 0.5);
@ -122,17 +112,19 @@ namespace nana
nana::rectangle r(pos, size); nana::rectangle r(pos, size);
graph_.rectangle(r, false, border); graph_.rectangle(r, false, border);
int right = pos.x + static_cast<int>(size.width) - 1;
int bottom = pos.y + static_cast<int>(size.height) - 1;
graph_.set_color(corner); graph_.set_color(corner);
graph_.set_pixel(pos.x, pos.y); graph_.set_pixel(pos.x, pos.y);
graph_.set_pixel(pos.x + size.width - 1, pos.y); graph_.set_pixel(right, pos.y);
graph_.set_pixel(pos.x, pos.y + size.height - 1); graph_.set_pixel(pos.x, bottom);
graph_.set_pixel(pos.x + size.width - 1, pos.y + size.height - 1); graph_.set_pixel(right, bottom);
graph_.rectangle(r.pare_off(1), true, body); graph_.rectangle(r.pare_off(1), true, body);
} }
void item_renderer::caption(int x, int y, const nana::string& text) void item_renderer::caption(const point& pos, const nana::string& text)
{ {
graph_.string({ x, y }, text, colors::black); graph_.string(pos, text, colors::black);
} }
//end class item_renderer //end class item_renderer
@ -146,23 +138,28 @@ namespace nana
delete items_; delete items_;
} }
nana::menu* trigger::push_back(const nana::string& text) nana::menu* trigger::push_back(const ::nana::string& text)
{ {
nana::string::value_type shkey; ::nana::char_t shkey;
API::transform_shortkey_text(text, shkey, nullptr); API::transform_shortkey_text(text, shkey, nullptr);
if(shkey) if(shkey)
API::register_shortkey(widget_->handle(), shkey); API::register_shortkey(widget_->handle(), shkey);
auto i = items_->cont().size(); auto pos = items_->cont().size();
items_->append(text, shkey); items_->append(text, shkey);
_m_draw(); _m_draw();
return items_->get_menu(i); API::update_window(*widget_);
return at(pos);
} }
nana::menu* trigger::at(std::size_t index) const nana::menu* trigger::at(std::size_t pos) const
{ {
return items_->get_menu(index); if (pos < items_->cont().size())
return &(items_->cont()[pos]->menu_obj);
return nullptr;
} }
std::size_t trigger::size() const std::size_t trigger::size() const
@ -219,22 +216,17 @@ namespace nana
void trigger::mouse_down(graph_reference graph, const arg_mouse& arg) void trigger::mouse_down(graph_reference graph, const arg_mouse& arg)
{ {
state_.nullify_mouse = false; state_.nullify_mouse = false;
state_.active = _m_item_by_pos(arg.pos); state_.active = _m_item_by_pos(arg.pos);
if(state_.menu_active == false)
if (npos != state_.active)
{ {
if(state_.active != npos) if (!state_.menu_active)
{
state_.menu_active = true; state_.menu_active = true;
_m_popup_menu();
}
else
_m_total_close();
}
else if(npos == state_.active)
_m_total_close();
else
_m_popup_menu(); _m_popup_menu();
}
else
_m_total_close();
_m_draw(); _m_draw();
API::lazy_refresh(); API::lazy_refresh();
@ -256,7 +248,6 @@ namespace nana
_m_draw(); _m_draw();
API::lazy_refresh(); API::lazy_refresh();
} }
} }
void trigger::focus(graph_reference, const arg_focus& arg) void trigger::focus(graph_reference, const arg_focus& arg)
@ -281,10 +272,10 @@ namespace nana
switch(arg.key) switch(arg.key)
{ {
case keyboard::os_arrow_down: case keyboard::os_arrow_down:
state_.menu->goto_next(true); break;
case keyboard::backspace: case keyboard::backspace:
case keyboard::os_arrow_up: case keyboard::os_arrow_up:
state_.menu->goto_next(false); break; state_.menu->goto_next(keyboard::os_arrow_down == arg.key);
break;
case keyboard::os_arrow_right: case keyboard::os_arrow_right:
if(state_.menu->goto_submen() == false) if(state_.menu->goto_submen() == false)
_m_move(false); _m_move(false);
@ -305,17 +296,26 @@ namespace nana
state_.menu->pick(); state_.menu->pick();
break; break;
default: default:
if(2 != state_.menu->send_shortkey(arg.key)) //Katsuhisa Yuasa: menubar key_press improvements
//send_shortkey has 3 states, 0 = UNKNOWN KEY, 1 = ITEM, 2 = GOTO SUBMENU
int sk_state = state_.menu->send_shortkey(arg.key);
switch(sk_state)
{ {
if(state_.active != npos) case 0: //UNKNOWN KEY
break;
case 1: //ITEM
if (state_.active != npos)
{ {
_m_total_close(); _m_total_close();
if(arg.key == 18) //ALT if (arg.key == 18) //ALT
state_.behavior = state_.behavior_focus; state_.behavior = state_.behavior_focus;
} }
} break;
else case 2: //GOTO SUBMENU
state_.menu->goto_submen(); state_.menu->goto_submen();
break;
}
break;
} }
} }
else else
@ -323,19 +323,34 @@ namespace nana
switch(arg.key) switch(arg.key)
{ {
case keyboard::os_arrow_right: case keyboard::os_arrow_right:
_m_move(false);
break;
case keyboard::backspace: case keyboard::backspace:
case keyboard::os_arrow_left: case keyboard::os_arrow_left:
_m_move(true); _m_move(keyboard::os_arrow_right != arg.key);
break;
case keyboard::os_arrow_up:
case keyboard::os_arrow_down:
case keyboard::enter:
state_.menu_active = true;
if(_m_popup_menu())
state_.menu->goto_next(true);
break; break;
case keyboard::escape: case keyboard::escape:
if(state_.behavior == state_.behavior_focus) if(state_.behavior == state_.behavior_focus)
{ {
state_.active= npos; state_.active= npos;
state_.behavior = state_.behavior_none; state_.behavior = state_.behavior_none;
API::restore_menubar_taken_window();
} }
break;
default:
std::size_t index = items_->find(arg.key);
if(index != npos)
{
state_.active = index;
state_.menu_active = true;
if(_m_popup_menu())
state_.menu->goto_next(true);
}
break;
} }
} }
@ -419,20 +434,37 @@ namespace nana
bool trigger::_m_popup_menu() bool trigger::_m_popup_menu()
{ {
if(state_.menu_active && (state_.menu != items_->get_menu(state_.active))) auto& items = items_->cont();
{
std::size_t index = state_.active;
_m_close_menu();
state_.active = index;
state_.menu = items_->get_menu(state_.active); auto pos = state_.active;
if(state_.menu) if (pos >= items.size())
return false;
if(state_.menu_active && (state_.menu != &(items[pos]->menu_obj)))
{
API::dev::delay_restore(true);
_m_close_menu();
API::dev::delay_restore(false);
state_.active = pos;
auto & m = items[pos];
state_.menu = &(m->menu_obj);
state_.menu->destroy_answer([this]
{ {
const item_type &m = items_->at(state_.active); state_.menu = nullptr;
state_.menu->destroy_answer(std::bind(&trigger::_m_unload_menu_window, this)); if (state_.passive_close)
menu_accessor::popup(*state_.menu, widget_->handle(), m.pos.x, m.pos.y + m.size.height); {
return true; _m_total_close();
}
_m_draw();
API::update_window(widget_->handle());
}
});
if (API::focus_window() != this->widget_->handle())
API::focus_window(widget_->handle());
menu_accessor::popup(*state_.menu, *widget_, m->pos.x, m->pos.y + static_cast<int>(m->size.height));
return true;
} }
return false; return false;
} }
@ -443,8 +475,6 @@ namespace nana
state_.menu_active = false; state_.menu_active = false;
state_.behavior = state_.behavior_none; state_.behavior = state_.behavior_none;
API::restore_menubar_taken_window();
auto pos = API::cursor_position(); auto pos = API::cursor_position();
API::calc_window_point(widget_->handle(), pos); API::calc_window_point(widget_->handle(), pos);
state_.active = _m_item_by_pos(pos); state_.active = _m_item_by_pos(pos);
@ -463,17 +493,6 @@ namespace nana
return false; return false;
} }
void trigger::_m_unload_menu_window()
{
state_.menu = nullptr;
if(state_.passive_close)
{
_m_total_close();
_m_draw();
API::update_window(widget_->handle());
}
}
std::size_t trigger::_m_item_by_pos(const ::nana::point& pos) std::size_t trigger::_m_item_by_pos(const ::nana::point& pos)
{ {
if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25)) if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25))
@ -521,9 +540,9 @@ namespace nana
for(auto i : items_->cont()) for(auto i : items_->cont())
{ {
//Transform the text if it contains the hotkey character //Transform the text if it contains the hotkey character
nana::string::value_type hotkey; ::nana::char_t hotkey;
nana::string::size_type hotkey_pos; ::nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos); auto text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos);
nana::size text_s = graph_->text_extent_size(text); nana::size text_s = graph_->text_extent_size(text);
@ -532,10 +551,11 @@ namespace nana
i->pos = item_pos; i->pos = item_pos;
i->size = item_s; i->size = item_s;
item_renderer::state_t state = (index != state_.active ? ird.state_normal : (state_.menu_active ? ird.state_selected : ird.state_highlight)); using state = item_renderer::state;
ird.background(item_pos, item_s, state); state item_state = (index != state_.active ? state::normal : (state_.menu_active ? state::selected : state::highlighted));
ird.background(item_pos, item_s, item_state);
if(state == ird.state_selected) if (state::selected == item_state)
{ {
int x = item_pos.x + item_s.width; int x = item_pos.x + item_s.width;
int y1 = item_pos.y + 2, y2 = item_pos.y + item_s.height - 1; int y1 = item_pos.y + 2, y2 = item_pos.y + item_s.height - 1;
@ -545,7 +565,7 @@ namespace nana
//Draw text, the text is transformed from orignal for hotkey character //Draw text, the text is transformed from orignal for hotkey character
int text_top_off = (item_s.height - text_s.height) / 2; int text_top_off = (item_s.height - text_s.height) / 2;
ird.caption(item_pos.x + 8, item_pos.y + text_top_off, text); ird.caption({ item_pos.x + 8, item_pos.y + text_top_off }, text);
if(hotkey) if(hotkey)
{ {
@ -566,7 +586,12 @@ namespace nana
//struct state_type //struct state_type
trigger::state_type::state_type() trigger::state_type::state_type()
:active(npos), behavior(behavior_none), menu_active(false), passive_close(true), nullify_mouse(false), menu(nullptr) : active(npos),
behavior(behavior_none),
menu_active(false),
passive_close(true),
nullify_mouse(false),
menu(nullptr)
{} {}
//end struct state_type //end struct state_type
//end class trigger //end class trigger

View File

@ -109,8 +109,7 @@ namespace nana
} }
} }
if (fit_size.width < graphsize.width || fit_size.height < graphsize.height) _m_draw_background(fit_size.width, fit_size.height);
_m_draw_background();
backimg.image.stretch(valid_area, graph, { pos, fit_size }); backimg.image.stretch(valid_area, graph, { pos, fit_size });
} }
@ -141,14 +140,15 @@ namespace nana
break; break;
} }
if (valid_area.width < graphsize.width || valid_area.height < graphsize.height) _m_draw_background(valid_area.width, valid_area.height);
_m_draw_background();
backimg.image.paste(valid_area, graph, pos); backimg.image.paste(valid_area, graph, pos);
} }
} }
else else
{ {
_m_draw_background(graphsize.width, graphsize.height);
color invalid_clr_for_call; color invalid_clr_for_call;
backimg.bground->draw(graph, invalid_clr_for_call, invalid_clr_for_call, graphsize, element_state::normal); backimg.bground->draw(graph, invalid_clr_for_call, invalid_clr_for_call, graphsize, element_state::normal);
} }
@ -156,18 +156,22 @@ namespace nana
graph.setsta(); graph.setsta();
} }
void drawer::_m_draw_background() void drawer::_m_draw_background(unsigned w, unsigned h)
{ {
auto graph = impl_->graph_ptr; auto graph = impl_->graph_ptr;
if (graph && (bground_mode::basic != API::effects_bground_mode(*impl_->wdg_ptr))) if (graph && (bground_mode::basic != API::effects_bground_mode(*impl_->wdg_ptr)))
{ {
auto & bground = impl_->gradual_bground; if (w < graph->size().width || h < graph->size().width || impl_->backimg.image.alpha())
if (bground.gradual_from.invisible() || bground.gradual_to.invisible()) {
graph->rectangle(true, impl_->wdg_ptr->bgcolor()); auto & bground = impl_->gradual_bground;
else if (bground.gradual_from == bground.gradual_to) if (bground.gradual_from.invisible() || bground.gradual_to.invisible())
graph->rectangle(true, bground.gradual_from); graph->rectangle(true, impl_->wdg_ptr->bgcolor());
else else if (bground.gradual_from == bground.gradual_to)
graph->gradual_rectangle(graph->size(), bground.gradual_from, bground.gradual_to, !bground.horizontal); graph->rectangle(true, bground.gradual_from);
else
graph->gradual_rectangle(graph->size(), bground.gradual_from, bground.gradual_to, !bground.horizontal);
}
} }
} }
//end class drawer //end class drawer

View File

@ -52,20 +52,11 @@ namespace nana
pos = screen_pos.x; pos = screen_pos.x;
} }
if(scale >= fixedsize * 2) const auto bound_pos = static_cast<int>(scale >= fixedsize * 2 ? fixedsize : scale / 2);
{ if (pos < bound_pos)
if(pos < static_cast<int>(fixedsize)) return buttons::first;
return buttons::first; if (pos > static_cast<int>(scale) - bound_pos)
if(pos > static_cast<int>(scale - fixedsize)) return buttons::second;
return buttons::second;
}
else
{
if(pos < static_cast<int>(scale / 2))
return buttons::first;
if(pos > static_cast<int>(scale / 2))
return buttons::second;
}
if(metrics_.scroll_length) if(metrics_.scroll_length)
{ {
@ -100,7 +91,7 @@ namespace nana
metrics_.scroll_pos = pos; metrics_.scroll_pos = pos;
auto value_max = metrics_.peak - metrics_.range; auto value_max = metrics_.peak - metrics_.range;
metrics_.value = pos * value_max / scroll_area; metrics_.value = pos * value_max / scroll_area;
if(metrics_.value < metrics_.peak - metrics_.range) if(metrics_.value < value_max)
{ {
int selfpos = static_cast<int>(metrics_.value * scroll_area / value_max); int selfpos = static_cast<int>(metrics_.value * scroll_area / value_max);
int nextpos = static_cast<int>((metrics_.value + 1) * scroll_area / value_max); int nextpos = static_cast<int>((metrics_.value + 1) * scroll_area / value_max);
@ -115,22 +106,22 @@ namespace nana
void drawer::auto_scroll() void drawer::auto_scroll()
{ {
if(_m_check()) if (!_m_check())
return;
if(buttons::forward == metrics_.what)
{ //backward
if(metrics_.value <= metrics_.range)
metrics_.value = 0;
else
metrics_.value -= (metrics_.range-1);
}
else if(buttons::backward == metrics_.what)
{ {
if(buttons::forward == metrics_.what) if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range)
{ //backward metrics_.value = metrics_.peak - metrics_.range;
if(metrics_.value <= metrics_.range) else
metrics_.value = 0; metrics_.value += (metrics_.range-1);
else
metrics_.value -= metrics_.range;
}
else if(buttons::backward == metrics_.what)
{
if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range)
metrics_.value = metrics_.peak - metrics_.range;
else
metrics_.value += metrics_.range;
}
} }
} }
@ -141,26 +132,20 @@ namespace nana
_m_background(graph); _m_background(graph);
::nana::rectangle r(graph.size()); rectangle_rotator r(vertical_, graph.size());
if(vertical_) r.x_ref() = static_cast<int>(r.w() - fixedsize);
{ r.w_ref() = fixedsize;
r.y = r.height - fixedsize;
r.height = fixedsize;
}
else
{
r.x = r.width - fixedsize;
r.width = fixedsize;
}
int state = ((_m_check() == false || what == buttons::none) ? states::none : states::highlight); int state = ((_m_check() == false || what == buttons::none) ? states::none : states::highlight);
int moused_state = (_m_check() ? (metrics_.pressed ? states::selected : states::actived) : states::none); int moused_state = (_m_check() ? (metrics_.pressed ? states::selected : states::actived) : states::none);
auto result = r.result();
//draw first //draw first
_m_draw_button(graph, { 0, 0, r.width, r.height }, buttons::first, (buttons::first == what ? moused_state : state)); _m_draw_button(graph, { 0, 0, result.width, result.height }, buttons::first, (buttons::first == what ? moused_state : state));
//draw second //draw second
_m_draw_button(graph, r, buttons::second, (buttons::second == what ? moused_state : state)); _m_draw_button(graph, result, buttons::second, (buttons::second == what ? moused_state : state));
//draw scroll //draw scroll
_m_draw_scroll(graph, (buttons::scroll == what ? moused_state : states::highlight)); _m_draw_scroll(graph, (buttons::scroll == what ? moused_state : states::highlight));
@ -171,64 +156,61 @@ namespace nana
{ {
graph.rectangle(true, {0xf0, 0xf0, 0xf0}); graph.rectangle(true, {0xf0, 0xf0, 0xf0});
if(metrics_.pressed && _m_check()) if (!metrics_.pressed || !_m_check())
return;
nana::rectangle_rotator r(vertical_, graph.size());
if(metrics_.what == buttons::forward)
{ {
int x = 0, y = 0; r.x_ref() = static_cast<int>(fixedsize);
unsigned width = graph.width(), height = graph.height(); r.w_ref() = metrics_.scroll_pos;
if(metrics_.what == buttons::forward)
{
*(vertical_ ? &y : &x) = fixedsize;
*(vertical_ ? &height: &width) = metrics_.scroll_pos;
}
else if(buttons::backward == metrics_.what)
{
*(vertical_ ? &y : &x) = static_cast<int>(fixedsize + metrics_.scroll_pos + metrics_.scroll_length);
*(vertical_ ? &height: &width) = static_cast<unsigned>((vertical_ ? graph.height() : graph.width()) - (fixedsize * 2 + metrics_.scroll_pos + metrics_.scroll_length));
}
else
return;
if(width && height)
graph.rectangle({ x, y, width, height }, true, {0xDC, 0xDC, 0xDC});
} }
else if(buttons::backward == metrics_.what)
{
r.x_ref() = static_cast<int>(fixedsize + metrics_.scroll_pos + metrics_.scroll_length);
r.w_ref() = static_cast<unsigned>((vertical_ ? graph.height() : graph.width()) - (fixedsize * 2 + metrics_.scroll_pos + metrics_.scroll_length));
}
else
return;
auto result = r.result();
if (!result.empty())
graph.rectangle(result, true, static_cast<color_rgb>(0xDCDCDC));
} }
void drawer::_m_button_frame(graph_reference graph, rectangle r, int state) void drawer::_m_button_frame(graph_reference graph, rectangle r, int state)
{ {
if(state) if (!state)
return;
::nana::color clr{0x97, 0x97, 0x97}; //highlight
switch(state)
{ {
::nana::color clr{0x97, 0x97, 0x97}; //highlight case states::actived:
switch(state) clr.from_rgb(0x86, 0xD5, 0xFD); break;
{ case states::selected:
case states::actived: clr.from_rgb(0x3C, 0x7F, 0xB1); break;
clr.from_rgb(0x86, 0xD5, 0xFD); break;
case states::selected:
clr.from_rgb(0x3C, 0x7F, 0xB1); break;
}
graph.rectangle(r, false, clr);
clr = clr.blend(colors::white, 0.5);
graph.set_color(clr);
r.pare_off(2);
if(vertical_)
{
unsigned half = r.width / 2;
graph.rectangle({ r.x + static_cast<int>(r.width - half), r.y, half, r.height }, true);
r.width -= half;
}
else
{
unsigned half = r.height / 2;
graph.rectangle({r.x, r.y + static_cast<int>(r.height - half), r.width, half}, true);
r.height -= half;
}
//graph.shadow_rectangle(x, y, width, height, 0xFFFFFF, color_x, !vertical_);
graph.gradual_rectangle(r, colors::white, clr, !vertical_);
} }
graph.rectangle(r, false, clr);
clr = clr.blend(colors::white, 0.5);
graph.set_color(clr);
r.pare_off(2);
if(vertical_)
{
unsigned half = r.width / 2;
graph.rectangle({ r.x + static_cast<int>(r.width - half), r.y, half, r.height }, true);
r.width -= half;
}
else
{
unsigned half = r.height / 2;
graph.rectangle({r.x, r.y + static_cast<int>(r.height - half), r.width, half}, true);
r.height -= half;
}
graph.gradual_rectangle(r, colors::white, clr, !vertical_);
} }
bool drawer::_m_check() const bool drawer::_m_check() const
@ -271,20 +253,11 @@ namespace nana
{ {
if(_m_check()) if(_m_check())
{ {
::nana::rectangle r(graph.size()); rectangle_rotator r(vertical_, graph.size());
r.x_ref() = static_cast<int>(fixedsize + metrics_.scroll_pos);
r.w_ref() = static_cast<unsigned>(metrics_.scroll_length);
if(vertical_) _m_button_frame(graph, r.result(), state);
{
r.y = fixedsize + metrics_.scroll_pos;
r.height = static_cast<unsigned>(metrics_.scroll_length);
}
else
{
r.x = fixedsize + metrics_.scroll_pos;
r.width = static_cast<unsigned>(metrics_.scroll_length);
}
_m_button_frame(graph, r, state);
} }
} }

View File

@ -1,15 +1,15 @@
/* /*
* A text editor implementation * A text editor implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/skeletons/text_editor.cpp * @file: nana/gui/widgets/skeletons/text_editor.cpp
* @description: * @contributors: Ariel Vina-Rodriguez
*/ */
#include <nana/gui/widgets/skeletons/text_editor.hpp> #include <nana/gui/widgets/skeletons/text_editor.hpp>
#include <nana/gui/widgets/skeletons/textbase_export_interface.hpp> #include <nana/gui/widgets/skeletons/textbase_export_interface.hpp>
#include <nana/gui/element.hpp> #include <nana/gui/element.hpp>
@ -18,6 +18,7 @@
#include <numeric> #include <numeric>
#include <cwctype> #include <cwctype>
#include <set> #include <set>
#include <algorithm>
namespace nana{ namespace widgets namespace nana{ namespace widgets
{ {
@ -314,7 +315,13 @@ namespace nana{ namespace widgets
if (pos.y > static_cast<unsigned>(textbase.lines())) if (pos.y > static_cast<unsigned>(textbase.lines()))
pos.y = static_cast<unsigned>(textbase.lines()); pos.y = static_cast<unsigned>(textbase.lines());
pos.x = editor_._m_pixels_by_char(textbase.getline(pos.y), pos.x) + editor_.text_area_.area.x; std::unique_ptr<nana::string> mask_str;
if (editor_.mask_char_)
mask_str.reset(new nana::string(textbase.getline(pos.y).size(), editor_.mask_char_));
auto & lnstr = editor_.mask_char_ ? *mask_str : textbase.getline(pos.y);
pos.x = editor_._m_pixels_by_char(lnstr, pos.x) + editor_.text_area_.area.x;
int pos_y = static_cast<int>((pos.y - editor_.points_.offset.y) * editor_.line_height() + editor_._m_text_top_base()); int pos_y = static_cast<int>((pos.y - editor_.points_.offset.y) * editor_.line_height() + editor_._m_text_top_base());
int pos_x = static_cast<int>(pos.x - editor_.points_.offset.x); int pos_x = static_cast<int>(pos.x - editor_.points_.offset.x);
@ -327,7 +334,13 @@ namespace nana{ namespace widgets
nana::upoint res{ 0, static_cast<unsigned>(_m_textline_from_screen(scrpos.y)) }; nana::upoint res{ 0, static_cast<unsigned>(_m_textline_from_screen(scrpos.y)) };
//Convert the screen point to text caret point //Convert the screen point to text caret point
const string_type& lnstr = editor_.textbase_.getline(res.y); const string_type& real_str = editor_.textbase_.getline(res.y);
std::unique_ptr<nana::string> mask_str;
if (editor_.mask_char_)
mask_str.reset(new nana::string(real_str.size(), editor_.mask_char_));
auto & lnstr = (editor_.mask_char_ ? *mask_str : real_str);
if (lnstr.size() > 0) if (lnstr.size() > 0)
{ {
scrpos.x += (editor_.points_.offset.x - editor_.text_area_.area.x); scrpos.x += (editor_.points_.offset.x - editor_.text_area_.area.x);
@ -676,7 +689,7 @@ namespace nana{ namespace widgets
} }
} }
else else
editor_.render(API::is_focus_window(editor_.window_)); editor_.render(API::is_focus_ready(editor_.window_));
} }
void render(const ::nana::color& fgcolor) override void render(const ::nana::color& fgcolor) override
@ -737,17 +750,24 @@ namespace nana{ namespace widgets
nana::point scrpos; nana::point scrpos;
if (0 != pos.x) if (0 != pos.x)
{ {
nana::string str;
for (auto & sec : mtr.line_sections) for (auto & sec : mtr.line_sections)
{ {
std::size_t chsize = sec.end - sec.begin; std::size_t chsize = sec.end - sec.begin;
str.clear();
if (editor_.mask_char_)
str.append(chsize, editor_.mask_char_);
else
str.append(sec.begin, sec.end);
if (pos.x < chsize) if (pos.x < chsize)
{ {
scrpos.x = editor_._m_pixels_by_char(nana::string(sec.begin, sec.end), pos.x); scrpos.x = editor_._m_pixels_by_char(str, pos.x);
break; break;
} }
else if (pos.x == chsize) else if (pos.x == chsize)
{ {
scrpos.x = editor_._m_text_extent_size(nana::string(sec.begin, sec.end).data(), sec.end - sec.begin).width; scrpos.x = editor_._m_text_extent_size(str.data(), sec.end - sec.begin).width;
break; break;
} }
else else
@ -773,13 +793,19 @@ namespace nana{ namespace widgets
return{ 0, static_cast<unsigned>(primary) }; return{ 0, static_cast<unsigned>(primary) };
//First of all, find the text of secondary. //First of all, find the text of secondary.
auto str = mtr.line_sections[secondary]; auto real_str = mtr.line_sections[secondary];
std::unique_ptr<nana::string> mask_str;
if (editor_.mask_char_)
mask_str.reset(new nana::string(real_str.end - real_str.begin, editor_.mask_char_));
const ::nana::char_t * str = (editor_.mask_char_ ? mask_str->data() : real_str.begin);
std::vector<unicode_bidi::entity> reordered; std::vector<unicode_bidi::entity> reordered;
unicode_bidi bidi; unicode_bidi bidi;
bidi.linestr(str.begin, str.end - str.begin, reordered); bidi.linestr(str, real_str.end - real_str.begin, reordered);
nana::upoint res(static_cast<unsigned>(str.begin - mtr.line_sections.front().begin), static_cast<unsigned>(primary)); nana::upoint res(static_cast<unsigned>(real_str.begin - mtr.line_sections.front().begin), static_cast<unsigned>(primary));
scrpos.x -= editor_.text_area_.area.x; scrpos.x -= editor_.text_area_.area.x;
if (scrpos.x < 0) if (scrpos.x < 0)
scrpos.x = 0; scrpos.x = 0;
@ -793,7 +819,7 @@ namespace nana{ namespace widgets
std::unique_ptr<unsigned[]> pxbuf(new unsigned[len]); std::unique_ptr<unsigned[]> pxbuf(new unsigned[len]);
res.x += editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), str_px, scrpos.x, _m_is_right_text(ent)); res.x += editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), str_px, scrpos.x, _m_is_right_text(ent));
res.x += static_cast<unsigned>(ent.begin - str.begin); res.x += static_cast<unsigned>(ent.begin - str);
return res; return res;
} }
scrpos.x -= str_px; scrpos.x -= str_px;
@ -1133,12 +1159,14 @@ namespace nana{ namespace widgets
public: public:
void parse(const ::nana::string& text, const keywords* kwptr) void parse(const ::nana::string& text, const keywords* kwptr)
{ {
if (text.empty()) if ( kwptr->kwbase.empty() || text.empty() )
return; return;
using index = ::nana::string::size_type;
std::vector<entity> entities; std::vector<entity> entities;
auto test_whole_word = [&text](std::size_t pos, std::size_t len) auto test_whole_word = [&text](index pos, index len)
{ {
if (pos) if (pos)
{ {
@ -1160,53 +1188,48 @@ namespace nana{ namespace widgets
::nana::cistring cistr; ::nana::cistring cistr;
for (auto & ds : kwptr->kwbase) for (auto & ds : kwptr->kwbase)
{ {
std::size_t pos; index pos{0} ;
const ::nana::char_t* begin; for (index rest{text.size()}; rest >= ds.text.size() ; ++pos, rest = text.size() - pos)
const ::nana::char_t* end; {
if (ds.case_sensitive) if (ds.case_sensitive)
{ {
pos = text.find(ds.text); pos = text.find(ds.text, pos);
if (pos == text.npos) if (pos == text.npos)
continue; break;
if (ds.whole_word_matched) if (ds.whole_word_matched)
{ {
if (!test_whole_word(pos, ds.text.size())) if (!test_whole_word(pos, ds.text.size()))
continue; continue;
} }
}
else
{
if (cistr.empty())
cistr.append(text.data(), text.size());
begin = text.data() + pos; pos = cistr.find(ds.text.data(), pos);
end = begin + ds.text.size(); if (pos == cistr.npos)
} break;
else
{
if (cistr.empty())
cistr.append(text.data(), text.size());
pos = cistr.find(ds.text.data()); if (ds.whole_word_matched)
if (pos == cistr.npos) {
continue; if (!test_whole_word(pos, ds.text.size()))
continue;
}
}
if (ds.whole_word_matched) auto ki = kwptr->schemes.find(ds.scheme);
{ if (ki != kwptr->schemes.end() && ki->second)
if (!test_whole_word(pos, ds.text.size())) {
continue; schemes_.emplace(ds.scheme, ki->second);
} entities.emplace_back();
auto & last = entities.back();
begin = text.data() + pos; last.begin = text.data() + pos;
end = begin + ds.text.size(); last.end = last.begin + ds.text.size();
} last.scheme = ki->second.get();
}
auto ki = kwptr->schemes.find(ds.scheme); }
if (ki != kwptr->schemes.end() && ki->second)
{
schemes_.emplace(ds.scheme, ki->second);
entities.emplace_back();
auto & last = entities.back();
last.begin = begin;
last.end = end;
last.scheme = ki->second.get();
}
} }
if (!entities.empty()) if (!entities.empty())
@ -1221,7 +1244,7 @@ namespace nana{ namespace widgets
while(i != entities.end()) while(i != entities.end())
{ {
if (previous->end > i->begin) if (previous->end > i->begin)
i = entities.erase(i); i = entities.erase(i); // erase overlaping. Left only the first.
else else
++i; ++i;
} }
@ -1326,7 +1349,7 @@ namespace nana{ namespace widgets
attributes_.acceptive = acceptive; attributes_.acceptive = acceptive;
} }
bool text_editor::respone_keyboard(char_type key) //key is a character of ASCII code bool text_editor::respond_char(char_type key) //key is a character of ASCII code
{ {
switch (key) switch (key)
{ {
@ -1377,6 +1400,24 @@ namespace nana{ namespace widgets
return false; return false;
} }
bool text_editor::respond_key(char_type key)
{
switch (key)
{
case keyboard::os_arrow_left: move_left(); break;
case keyboard::os_arrow_right: move_right(); break;
case keyboard::os_arrow_up: move_ns(true); break;
case keyboard::os_arrow_down: move_ns(false); break;
case keyboard::os_del:
if (this->attr().editable)
del();
break;
default:
return false;
}
return true;
}
void text_editor::typeface_changed() void text_editor::typeface_changed()
{ {
behavior_->pre_calc_lines(width_pixels()); behavior_->pre_calc_lines(width_pixels());
@ -1407,7 +1448,7 @@ namespace nana{ namespace widgets
move_caret(upoint{}); move_caret(upoint{});
_m_scrollbar(); _m_scrollbar();
render(API::is_focus_window(window_)); render(API::is_focus_ready(window_));
return true; return true;
} }
return false; return false;
@ -1425,7 +1466,7 @@ namespace nana{ namespace widgets
_m_reset(); _m_reset();
behavior_->pre_calc_lines(width_pixels()); behavior_->pre_calc_lines(width_pixels());
render(API::is_focus_window(window_)); render(API::is_focus_ready(window_));
_m_scrollbar(); _m_scrollbar();
return true; return true;
} }
@ -1676,7 +1717,7 @@ namespace nana{ namespace widgets
//Set caret position through text coordinate //Set caret position through text coordinate
void text_editor::move_caret(const upoint& crtpos) void text_editor::move_caret(const upoint& crtpos)
{ {
if (!API::is_focus_window(window_)) if (!API::is_focus_ready(window_))
return; return;
const unsigned line_pixels = line_height(); const unsigned line_pixels = line_height();
@ -1718,7 +1759,7 @@ namespace nana{ namespace widgets
void text_editor::show_caret(bool isshow) void text_editor::show_caret(bool isshow)
{ {
if(isshow == false || API::is_focus_window(window_)) if(isshow == false || API::is_focus_ready(window_))
API::caret_visible(window_, isshow); API::caret_visible(window_, isshow);
} }
@ -1883,7 +1924,7 @@ namespace nana{ namespace widgets
{ {
behavior_->adjust_caret_into_screen(); behavior_->adjust_caret_into_screen();
reset_caret(); reset_caret();
render(API::is_focus_window(window_)); render(API::is_focus_ready(window_));
_m_scrollbar(); _m_scrollbar();
points_.xpos = points_.caret.x; points_.xpos = points_.caret.x;
@ -2105,25 +2146,6 @@ namespace nana{ namespace widgets
} }
bool text_editor::move(nana::char_t key)
{
switch(key)
{
case keyboard::os_arrow_left: move_left(); break;
case keyboard::os_arrow_right: move_right(); break;
case keyboard::os_arrow_up: move_ns(true); break;
case keyboard::os_arrow_down: move_ns(false); break;
case keyboard::os_del:
if (this->attr().editable)
del();
break;
default:
return false;
}
return true;
}
void text_editor::move_ns(bool to_north) void text_editor::move_ns(bool to_north)
{ {
const bool redraw_required = _m_cancel_select(0); const bool redraw_required = _m_cancel_select(0);
@ -2528,7 +2550,7 @@ namespace nana{ namespace widgets
//The number of new lines minus one //The number of new lines minus one
const auto chp_end = text.data() + (begin == text.npos ? text.size() : begin); const auto chp_end = text.data() + (begin == text.npos ? text.size() : begin);
for (auto chp = text.data() + (pos + 2); chp != chp_end; ++chp) for (auto chp = text.data() + (pos + 1); chp != chp_end; ++chp)
if (*chp == '\n') if (*chp == '\n')
lines.emplace_back(0, 0); lines.emplace_back(0, 0);
@ -2764,18 +2786,17 @@ namespace nana{ namespace widgets
} }
} }
void text_editor::_m_draw_string(int top, const ::nana::color& clr, const nana::upoint& str_pos, const nana::string& linestr, bool if_mask) const void text_editor::_m_draw_string(int top, const ::nana::color& clr, const nana::upoint& str_pos, const nana::string& str, bool if_mask) const
{ {
::nana::point text_pos{ text_area_.area.x - points_.offset.x, top }; ::nana::point text_pos{ text_area_.area.x - points_.offset.x, top };
const int xend = text_area_.area.x + static_cast<int>(text_area_.area.width); const int xend = text_area_.area.x + static_cast<int>(text_area_.area.width);
std::unique_ptr<nana::string> mask_str;
if (if_mask && mask_char_) if (if_mask && mask_char_)
{ mask_str.reset(new nana::string(str.size(), mask_char_));
nana::string maskstr;
maskstr.append(linestr.size(), mask_char_);
graph_.string(text_pos, maskstr, clr); auto & linestr = (if_mask && mask_char_ ? *mask_str : str);
return;
}
unicode_bidi bidi; unicode_bidi bidi;
std::vector<unicode_bidi::entity> reordered; std::vector<unicode_bidi::entity> reordered;

View File

@ -14,6 +14,7 @@
#include <nana/gui/widgets/skeletons/text_editor.hpp> #include <nana/gui/widgets/skeletons/text_editor.hpp>
#include <nana/gui/element.hpp> #include <nana/gui/element.hpp>
#include <nana/gui/timer.hpp> #include <nana/gui/timer.hpp>
#include <algorithm>
namespace nana namespace nana
{ {
@ -328,7 +329,7 @@ namespace nana
void render() void render()
{ {
editor_->render(API::is_focus_window(editor_->window_handle())); editor_->render(API::is_focus_ready(editor_->window_handle()));
_m_draw_spins(spin_stated_); _m_draw_spins(spin_stated_);
} }
@ -420,7 +421,7 @@ namespace nana
if (!editor_) if (!editor_)
return; return;
if (API::is_focus_window(editor_->window_handle())) if (API::is_focus_ready(editor_->window_handle()))
editor_->text(range_->value()); editor_->text(range_->value());
else else
editor_->text(modifier_.prefix + range_->value() + modifier_.suffix); editor_->text(modifier_.prefix + range_->value() + modifier_.suffix);
@ -559,7 +560,7 @@ namespace nana
void drawer::key_press(graph_reference, const arg_keyboard& arg) void drawer::key_press(graph_reference, const arg_keyboard& arg)
{ {
if (impl_->editor()->move(arg.key)) if (impl_->editor()->respond_key(arg.key))
{ {
impl_->editor()->reset_caret(); impl_->editor()->reset_caret();
impl_->draw_spins(); impl_->draw_spins();
@ -569,7 +570,7 @@ namespace nana
void drawer::key_char(graph_reference, const arg_keyboard& arg) void drawer::key_char(graph_reference, const arg_keyboard& arg)
{ {
if (impl_->editor()->respone_keyboard(arg.key)) if (impl_->editor()->respond_char(arg.key))
{ {
if (!impl_->value(impl_->editor()->text())) if (!impl_->value(impl_->editor()->text()))
impl_->draw_spins(); impl_->draw_spins();

View File

@ -83,7 +83,7 @@ namespace drawerbase {
void drawer::refresh(graph_reference graph) void drawer::refresh(graph_reference graph)
{ {
editor_->render(API::is_focus_window(*widget_)); editor_->render(API::is_focus_ready(*widget_));
} }
void drawer::focus(graph_reference graph, const arg_focus& arg) void drawer::focus(graph_reference graph, const arg_focus& arg)
@ -136,7 +136,7 @@ namespace drawerbase {
void drawer::key_press(graph_reference, const arg_keyboard& arg) void drawer::key_press(graph_reference, const arg_keyboard& arg)
{ {
if(editor_->move(arg.key)) if(editor_->respond_key(arg.key))
{ {
editor_->reset_caret(); editor_->reset_caret();
API::lazy_refresh(); API::lazy_refresh();
@ -145,7 +145,7 @@ namespace drawerbase {
void drawer::key_char(graph_reference, const arg_keyboard& arg) void drawer::key_char(graph_reference, const arg_keyboard& arg)
{ {
if (editor_->respone_keyboard(arg.key)) if (editor_->respond_char(arg.key))
API::lazy_refresh(); API::lazy_refresh();
} }
@ -314,7 +314,7 @@ namespace drawerbase {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if (editor->line_wrapped(autl)) if (editor->line_wrapped(autl))
editor->render(API::is_focus_window(handle())); API::update_window(handle());
return *this; return *this;
} }
@ -389,7 +389,7 @@ namespace drawerbase {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if(editor && editor->select(yes)) if(editor && editor->select(yes))
API::refresh_window(*this); API::update_window(*this);
} }
void textbox::copy() const void textbox::copy() const
@ -407,7 +407,7 @@ namespace drawerbase {
if(editor) if(editor)
{ {
editor->paste(); editor->paste();
API::refresh_window(*this); API::update_window(*this);
} }
} }

View File

@ -101,7 +101,7 @@ namespace nana
bool widget::focused() const bool widget::focused() const
{ {
return API::is_focus_window(handle()); return (API::focus_window() == handle());
} }
void widget::show() void widget::show()

View File

@ -250,6 +250,11 @@ namespace paint
image_ptr_.reset(); image_ptr_.reset();
} }
bool image::alpha() const
{
return (image_ptr_ ? image_ptr_->alpha_channel() : false);
}
nana::size image::size() const nana::size image::size() const
{ {
return (image_ptr_ ? image_ptr_->size() : nana::size()); return (image_ptr_ ? image_ptr_->size() : nana::size());

View File

@ -12,6 +12,10 @@
#include <nana/system/dataexch.hpp> #include <nana/system/dataexch.hpp>
#include <nana/traits.hpp> #include <nana/traits.hpp>
#include <nana/paint/graphics.hpp>
#include <vector>
#include <cassert>
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
#include <windows.h> #include <windows.h>
#elif defined(NANA_X11) #elif defined(NANA_X11)
@ -33,6 +37,86 @@ namespace nana{ namespace system{
_m_set(std::is_same<char, nana::char_t>::value ? format::text : format::unicode, text.c_str(), (text.length() + 1) * sizeof(nana::char_t)); _m_set(std::is_same<char, nana::char_t>::value ? format::text : format::unicode, text.c_str(), (text.length() + 1) * sizeof(nana::char_t));
} }
bool dataexch::set(const nana::paint::graphics& g)
{
#if defined(NANA_WINDOWS)
size sz = g.size();
paint::pixel_buffer pbuffer;
rectangle r;
r.x = 0;
r.y = 0;
r.width = sz.width;
r.height = sz.height;
pbuffer.attach(g.handle(), r);
size_t bytes_per_line = pbuffer.bytes_per_line();
size_t bitmap_bytes = bytes_per_line * r.height;
struct {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[256];
} bmi = {0};
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);
int err = ::GetLastError();
::ReleaseDC(NULL, hDC);
return false;
}
if (!::ReleaseDC(NULL, hDC)) {
return false;
}
size_t header_size = sizeof(bmi.bmiHeader);
// Bitmaps are huge, so to avoid unnegligible extra copy, this routine does not use private _m_set method.
HGLOBAL h_gmem = ::GlobalAlloc(GHND | GMEM_SHARE, header_size + bitmap_bytes);
void * gmem = ::GlobalLock(h_gmem);
if (!gmem) {
assert(false);
goto Label_GlobalFree;
}
char* p = (char*)gmem;
// Fix BITMAPINFOHEADER obtained from GetDIBits WinAPI
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biHeight = ::abs(bmi.bmiHeader.biHeight);
memcpy(p, &bmi, header_size);
p += header_size;
// many programs do not support bottom-up DIB, so reversing row order is needed.
for (int y=0; y<bmi.bmiHeader.biHeight; ++y) {
memcpy(p, pbuffer.raw_ptr(bmi.bmiHeader.biHeight - 1 - y), bytes_per_line);
p += bytes_per_line;
}
if (!::GlobalUnlock(h_gmem) && GetLastError() != NO_ERROR) {
assert(false);
goto Label_GlobalFree;
}
if (!::OpenClipboard(::GetFocus())) {
goto Label_GlobalFree;
}
if (!::EmptyClipboard()) {
goto Label_GlobalFree;
}
if (!::SetClipboardData(CF_DIB, h_gmem)) {
goto Label_GlobalFree;
}
if (!::CloseClipboard()) {
// really?
return false;
}
return true;
Label_GlobalFree:
::GlobalFree(h_gmem);
return false;
//#elif defined(NANA_X11)
#else
throw "not implemented yet.";
return false;
#endif
}
void dataexch::get(nana::string& str) void dataexch::get(nana::string& str)
{ {
std::size_t size; std::size_t size;
@ -78,8 +162,8 @@ namespace nana{ namespace system{
case format::unicode: type = CF_UNICODETEXT; break; case format::unicode: type = CF_UNICODETEXT; break;
case format::pixmap: type = CF_BITMAP; break; case format::pixmap: type = CF_BITMAP; break;
} }
::SetClipboardData(type, g); HANDLE h = ::SetClipboardData(type, g);
res = true; res = (h != NULL);
} }
::CloseClipboard(); ::CloseClipboard();
} }