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
[Dd]ebug*/
*.lib
*.a
*.sbr
obj/
[Rr]elease*/
@ -31,5 +32,4 @@ _ReSharper*/
[Tt]est[Rr]esult*
*.suo
*.sdf
bii/.hive.db
lib/

View File

@ -1,20 +1,26 @@

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

View File

@ -5,10 +5,18 @@
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{25B21068-491B-4A9F-B99F-6C27BF31BAAD}</ProjectGuid>
@ -22,6 +30,12 @@
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</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">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
@ -29,21 +43,48 @@
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</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" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup 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'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</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 Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<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 Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<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>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@ -52,13 +93,33 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<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>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -70,6 +131,8 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -78,7 +141,28 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
<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>
</ItemDefinitionGroup>
<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
{
//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);
@ -127,8 +127,7 @@ namespace nana
using pixel_color_t = pixel_argb_t;
//http://www.w3.org/TR/2011/REC-css3-color-20110607/
//4.3. Extended color keywords
/// See extended CSS color keywords (4.3) in http://www.w3.org/TR/2011/REC-css3-color-20110607/
enum class colors
{
alice_blue = 0xf0f8ff,
@ -283,7 +282,7 @@ namespace nana
//temporary defintions, these will be replaced by color schema
button_face_shadow_start = 0xF5F4F2,
button_face_shadow_end = 0xD5D2CA,
button_face = 0xD4D0C8,
button_face = 0xD4D0C8 , //,light_cyan
dark_border = 0x404040,
gray_border = 0x808080,
highlight = 0x1CC4F7
@ -320,10 +319,10 @@ namespace nana
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;
///< Determines whether the color is completely transparent.
/// Determines whether the color is completely transparent.
bool invisible() const;
pixel_color_t px_color() const;
pixel_argb_t argb() const;
@ -435,10 +434,10 @@ namespace nana
unsigned height;
};
class area_rotator
class rectangle_rotator
{
public:
area_rotator(bool rotated, const ::nana::rectangle& area);
rectangle_rotator(bool rotated, const ::nana::rectangle& area);
int x() const;
int & x_ref();
@ -455,7 +454,7 @@ namespace nana
private:
bool rotated_;
::nana::rectangle area_;
};//end class area_rotator
};//end class rectangle_rotator
enum class arrange
{

View File

@ -1,7 +1,7 @@
/*
* Nana Configuration
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -20,10 +20,13 @@
#define PLATFORM_SPEC_HPP <nana/detail/win32/platform_spec.hpp>
//Test if it is MINGW
#if defined(__MINGW32__)
#if defined(__MINGW32__) || defined(__MINGW64__)
#define NANA_MINGW
#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
#elif (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC)
//Linux:
@ -35,6 +38,13 @@
# static_assert(false, "Only Windows and Unix are support now");
#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.
#define NANA_UNICODE

View File

@ -23,8 +23,8 @@
#undef NANA_WINDOWS
#endif
//Implement workarounds for MinGW
#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)
namespace std
{
//Workaround for no implemenation of std::stoi in MinGW.

View File

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

View File

@ -96,7 +96,8 @@ namespace nana
//System Code for OS
os_pageup = 0x21, os_pagedown,
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 borderless :1;
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
mouse_action action;
}flags;
@ -175,7 +176,6 @@ namespace detail
{
caret_descriptor* caret;
std::shared_ptr<general_events> events_ptr;
general_events* attached_events;
}together;
widget_colors* scheme{ nullptr };

View File

@ -54,13 +54,14 @@ namespace detail
native_window_type root(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);
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();
void remove_menu();
void empty_menu();
void erase_menu(bool try_destroy);
void get_key_state(arg_keyboard&);
bool set_keyboard_shortkey(bool yes);

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/*
* Implementations of Inner Forward Declaration
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -19,7 +19,6 @@
#include "../../paint/graphics.hpp"
#include <map>
#include <algorithm>
namespace nana{
namespace detail
@ -62,12 +61,15 @@ namespace nana{
void umake(window wd)
{
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())
keybase_.erase(i);
for (auto i = keybase_.begin(), end = keybase_.end(); i != end; ++i)
{
if (i->handle == wd)
{
keybase_.erase(i);
break;
}
}
}
std::vector<unsigned long> keys(window wd) const

View File

@ -10,7 +10,7 @@
* @file: nana/gui/place.cpp
*
* @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

View File

@ -77,6 +77,8 @@ namespace API
window create_frame(window, const rectangle&, widget* attached);
paint::graphics* window_graphics(window);
void delay_restore(bool);
}//end namespace dev
@ -193,7 +195,7 @@ namespace API
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 wd, const rectangle&);
@ -203,9 +205,11 @@ namespace API
void draw_through(window, std::function<void()>);
void map_through_widgets(window, native_drawable_type);
nana::size window_size(window);
size window_size(window);
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.
void window_enabled(window, bool);
bool window_enabled(window);
@ -235,7 +239,7 @@ namespace API
cursor window_cursor(window);
void activate_window(window);
bool is_focus_window(window);
bool is_focus_ready(window);
window focus_window();
void focus_window(window);
@ -288,7 +292,6 @@ namespace API
void register_menu_window(window, bool has_keyboard);
bool attach_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.

View File

@ -27,25 +27,37 @@ namespace nana
/// The index of monitor.
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
virtual const ::nana::rectangle& area() const = 0;
virtual const ::nana::rectangle& workarea() const = 0;
};
class screen
{
struct implement;
public:
static ::nana::size desktop_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
std::size_t count() const;
std::shared_ptr<display> get_display(std::size_t index) const;
std::shared_ptr<display> get_primary() const;
display& from_point(const point&);
display& from_window(window);
display& get_display(std::size_t index) const;
display& get_primary() const;
void for_each(std::function<void(display&)>) const;
private:
std::shared_ptr<implement> impl_;
};
}//end namespace nana

View File

@ -1,13 +1,13 @@
/*
/**
* A Button Implementation
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
* 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

View File

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

View File

@ -1,13 +1,13 @@
/*
/**
* A CheckBox Implementation
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
* 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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/*
/**
* A float_listbox Implementation
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at

View File

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

View File

@ -1,7 +1,7 @@
/*
/**
* A Frame Implementation
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -9,7 +9,7 @@
*
* @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

View File

@ -1,7 +1,7 @@
/*
/**
* A Label Control Implementation
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at

View File

@ -1,4 +1,4 @@
/*
/**
* A List Box Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -8,6 +8,7 @@
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/widgets/listbox.hpp
* @contributors: Ariel Vina-Rodriguez
*
*/
@ -16,6 +17,7 @@
#include "widget.hpp"
#include <nana/concepts.hpp>
#include <nana/key_type.hpp>
//#include <nana/paint/graphics.hpp>
#include <functional>
#include <initializer_list>
@ -27,7 +29,7 @@ namespace nana
{
namespace listbox
{
typedef std::size_t size_type;
using size_type = std::size_t ;
struct cell
{
@ -35,7 +37,7 @@ namespace nana
{
::nana::color bgcolor;
::nana::color fgcolor;
/// ::nana::paint::font font; \todo
format() = default;
format(const ::nana::color& bgcolor, const ::nana::color& fgcolor);
};
@ -112,7 +114,8 @@ namespace nana
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 item; //the pos of item in a category.
@ -169,7 +172,8 @@ namespace nana
class drawer_header_impl;
class drawer_lister_impl;
class trigger: public drawer_trigger
/// mostly works on display positions
class trigger: public drawer_trigger
{
public:
trigger();
@ -192,19 +196,29 @@ namespace nana
void dbl_click(graph_reference, const arg_mouse&) override;
void resized(graph_reference, const arg_resized&) override;
void key_press(graph_reference, const arg_keyboard&) override;
void key_char(graph_reference, const arg_keyboard&) override;
private:
essence_t * essence_;
drawer_header_impl *drawer_header_;
drawer_lister_impl *drawer_lister_;
};//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:
item_proxy(essence_t*);
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;
item_proxy & check(bool ck);
@ -237,7 +251,7 @@ namespace nana
auto && cells = ores.move_cells();
auto cols = columns();
cells.resize(cols);
for (auto pos = 0; pos < cols; ++pos)
for (auto pos = 0u; pos < cols; ++pos)
{
auto & el = cells[pos];
if (el.text.size() == 1 && el.text[0] == nana::char_t(0))
@ -318,8 +332,8 @@ namespace nana
essence_t * _m_ess() const;
private:
std::vector<cell> & _m_cells() const;
nana::any * _m_value(bool alloc_if_empty);
const nana::any * _m_value() const;
nana::any * _m_value(bool alloc_if_empty);
const nana::any * _m_value() const;
private:
essence_t * ess_;
category_t* cat_{nullptr};
@ -334,7 +348,7 @@ namespace nana
cat_proxy(essence_t*, size_type pos);
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>
item_proxy append(T&& t, bool set_value = false)
{
@ -367,13 +381,18 @@ namespace nana
item_proxy cbegin() const;
item_proxy cend() const;
item_proxy at(size_type pos) const;
item_proxy at(size_type pos_abs) 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 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
size_type size() const;
@ -410,9 +429,21 @@ namespace nana
private:
essence_t* ess_{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
struct arg_listbox
@ -446,12 +477,12 @@ namespace nana
}
}//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.
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.
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
: 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 iresolver = drawerbase::listbox::iresolver;
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:
listbox() = default;
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
cat_proxy insert(cat_proxy, nana::string);
cat_proxy at(size_type pos) const;
/// add categories in order when use a key?
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>
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));
}
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.
@ -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);
}
///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*,
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;
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);
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);
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_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 disable_single(bool for_selection);
export_options& def_export_options();
private:
drawerbase::listbox::essence_t & _m_ess() 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
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com)
@ -139,16 +139,16 @@ namespace nana
void clear(); ///< Erases all of the items.
/// Closes the menu. It does not destroy the menu; just close the window for the menu.
void close();
void image(std::size_t index, const paint::image& icon);
void check_style(std::size_t index, checks);
void checked(std::size_t index, bool);
bool checked(std::size_t index) const;
void enabled(std::size_t index, bool);///< Enables or disables the mouse or keyboard input for the item.
bool enabled(std::size_t index) const;
void erase(std::size_t index); ///< Removes the item
bool link(std::size_t index, 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 *create_sub_menu(std::size_t index);
void image(std::size_t pos, const paint::image& icon);
void check_style(std::size_t pos, checks);
void checked(std::size_t pos, bool);
bool checked(std::size_t pos) const;
void enabled(std::size_t pos, bool);///< Enables or disables the mouse or keyboard input for the item.
bool enabled(std::size_t pos) const;
void erase(std::size_t pos); ///< Removes the item
bool link(std::size_t pos, menu& menu_obj);///< Link a menu to the item as a sub menu.
menu * link(std::size_t pos); ///< Retrieves a linked sub menu of the item.
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_await(window owner, int x, int y);
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;
private:
void _m_destroy_menu_window();
void _m_popup(window, int x, int y, bool called_by_menubar);
private:
implement * impl_;

View File

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

View File

@ -1,4 +1,4 @@
/*
/**
* A Panel Implementation
* Nana C++ Library(http://www.nanaro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -8,8 +8,10 @@
* http://www.boost.org/LICENSE_1_0.txt)
*
* @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
@ -44,11 +46,13 @@ namespace nana
panel(window wd, bool visible)
{
this->create(wd, rectangle(), visible);
this->bgcolor(API::bgcolor(wd));
}
panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true)
{
this->create(wd, r, visible);
this->bgcolor(API::bgcolor(wd));
}
bool transparent() const

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/*
/**
* A Scroll Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -8,6 +8,7 @@
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/widgets/scroll.hpp
* @contributors: Ariel Vina-Rodriguez
*/
#ifndef NANA_GUI_WIDGET_SCROLL_HPP
#define NANA_GUI_WIDGET_SCROLL_HPP
@ -49,17 +50,17 @@ namespace nana
struct metrics_type
{
typedef std::size_t size_type;
using size_type = std::size_t;
size_type peak;
size_type range;
size_type step;
size_type value;
size_type peak; ///< the whole total
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; ///< how many to scroll by click in forward or backward
size_type value; ///< current offset calculated from the very beginnig
buttons what;
bool pressed;
size_type scroll_length;
int scroll_pos;
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; ///< in pixels, and correspond to the offsset from the very beginning (value)
int scroll_mouse_offset;
metrics_type();
@ -70,11 +71,11 @@ namespace nana
public:
struct states
{
enum{none, highlight, actived, selected};
enum{ none, highlight, actived, selected };
};
typedef nana::paint::graphics& graph_reference;
const static unsigned fixedsize = 16;
using graph_reference = paint::graphics&;
const static unsigned fixedsize = 16; // make it part of a new "metric" in the widget_scheme
drawer(metrics_type& m);
void set_vertical(bool);
@ -114,7 +115,7 @@ namespace nana
void peak(size_type s)
{
if(graph_ && (metrics_.peak != s))
if (graph_ && (metrics_.peak != s))
{
metrics_.peak = s;
API::refresh_window(widget_->handle());
@ -123,10 +124,10 @@ namespace nana
void value(size_type s)
{
if(s + metrics_.range > metrics_.peak)
if (s + metrics_.range > metrics_.peak)
s = metrics_.peak - metrics_.range;
if(graph_ && (metrics_.value != s))
if (graph_ && (metrics_.value != s))
{
metrics_.value = s;
_m_emit_value_changed();
@ -137,7 +138,7 @@ namespace nana
void range(size_type s)
{
if(graph_ && (metrics_.range != s))
if (graph_ && (metrics_.range != s))
{
metrics_.range = s;
API::refresh_window(widget_->handle());
@ -151,31 +152,31 @@ namespace nana
bool make_step(bool forward, unsigned multiple)
{
if(graph_)
if (graph_)
{
size_type step = (multiple > 1 ? metrics_.step * multiple : metrics_.step);
size_type value = metrics_.value;
if(forward)
if (forward)
{
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;
else
value = maxv;
}
}
else if(value)
else if (value)
{
if(value > step)
if (value > step)
value -= step;
else
value = 0;
}
size_type cmpvalue = metrics_.value;
metrics_.value = value;
if(value != cmpvalue)
if (value != cmpvalue)
{
_m_emit_value_changed();
return true;
@ -221,24 +222,24 @@ namespace nana
void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override
{
bool redraw = false;
if(metrics_.pressed && (metrics_.what == buttons::scroll))
if (metrics_.pressed && (metrics_.what == buttons::scroll))
{
size_type cmpvalue = metrics_.value;
drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x));
if(cmpvalue != metrics_.value)
if (cmpvalue != metrics_.value)
_m_emit_value_changed();
redraw = true;
}
else
{
buttons what = drawer_.what(graph, arg.pos);
if(metrics_.what != what)
if (metrics_.what != what)
{
redraw = true;
metrics_.what = what;
}
}
if(redraw)
if (redraw)
{
drawer_.draw(graph, metrics_.what);
API::lazy_refresh();
@ -247,11 +248,11 @@ namespace nana
void mouse_down(graph_reference graph, const arg_mouse& arg) override
{
if(arg.left_button)
if (arg.left_button)
{
metrics_.pressed = true;
metrics_.what = drawer_.what(graph, arg.pos);
switch(metrics_.what)
switch (metrics_.what)
{
case buttons::first:
case buttons::second:
@ -265,13 +266,13 @@ namespace nana
break;
case buttons::forward:
case buttons::backward:
{
size_type cmpvalue = metrics_.value;
drawer_.auto_scroll();
if(cmpvalue != metrics_.value)
_m_emit_value_changed();
}
break;
{
size_type cmpvalue = metrics_.value;
drawer_.auto_scroll();
if (cmpvalue != metrics_.value)
_m_emit_value_changed();
}
break;
default: //Ignore buttons::none
break;
}
@ -294,7 +295,7 @@ namespace nana
void mouse_leave(graph_reference graph, const arg_mouse&) override
{
if(metrics_.pressed) return;
if (metrics_.pressed) return;
metrics_.what = buttons::none;
drawer_.draw(graph, buttons::none);
@ -303,7 +304,7 @@ namespace nana
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);
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.
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>>
{
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.
/// @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)
{
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.
/// @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 visible specifying the visible after creating.
/// @param visible specify the visibility after creation.
scroll(window wd, const rectangle& r, bool visible = true)
{
this->create(wd, r, visible);
}
/// \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
{
auto & m = this->get_drawer_trigger().metrics();
return (for_less ? (0 != m.value) : (m.value < m.peak - m.range));
}
/// the whole total (peak)
size_type amount() const
{
return this->get_drawer_trigger().metrics().peak;
@ -378,7 +379,7 @@ namespace nana
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
{
return this->get_drawer_trigger().metrics().range;
@ -390,7 +391,7 @@ namespace nana
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.
size_type value() const
{
@ -419,12 +420,12 @@ namespace nana
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.
/// @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());
return true;
@ -437,13 +438,17 @@ namespace nana
/// @return true if the vlaue is changed.
bool make_scroll(bool forward)
{
if(this->get_drawer_trigger().make_step(forward, 3))
{
API::refresh_window(this->handle());
return true;
}
return false;
return this->make_step(forward, 3); // set this 3 in the metrics of the widget scheme ?
}
/// \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 namespace nana
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/*
/**
* A Tree Box Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -7,12 +7,12 @@
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/widgets/treebox.hpp
* @brief:
* @file: nana/gui/widgets/treebox.hpp
* @brief
* The treebox organizes the nodes by a key string.
* The treebox would have a vertical scrollbar if the node
* is too many to display. And it does not have a horizontal scrollbar,
* the widget will adjust the node's displaying position for fitting.
* The treebox would have a vertical scrollbar if there are too many nodes
* to display. It does not have an horizontal scrollbar:
* the widget will adjust the node's displaying position for fitting.
*/
#ifndef NANA_GUI_WIDGETS_TREEBOX_HPP
@ -332,12 +332,13 @@ namespace nana
}//end namespace treebox
}//end namespace drawerbase
struct arg_treebox
/// a type of treebox event parameter
struct arg_treebox
: public event_arg
{
treebox& widget;
drawerbase::treebox::item_proxy & item;
bool operated;
treebox& widget; ///< where the event occurs
drawerbase::treebox::item_proxy & item; ///< the operated node
bool operated; ///< operation state of the event
arg_treebox(treebox&, drawerbase::treebox::item_proxy&, bool operated);
};
@ -349,28 +350,30 @@ namespace nana
struct treebox_events
: public general_events
{
basic_event<arg_treebox> expanded;
basic_event<arg_treebox> checked;
basic_event<arg_treebox> selected;
basic_event<arg_treebox> hovered;
basic_event<arg_treebox> expanded; ///< a user expands or shrinks a node
basic_event<arg_treebox> checked; ///< a user checks or unchecks a node
basic_event<arg_treebox> selected; ///< a user selects or unselects a node
basic_event<arg_treebox> hovered; ///< a user moves the cursor over a node
};
}//end namespace treebox
}//end namespace drawerbase
/// Displays a hierarchical list of items, such as the files and directories on a disk.
class treebox
/// \brief Displays a hierarchical list of items, such as the files and directories on a disk.
/// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm)
class treebox
:public widget_object < category::widget_tag, drawerbase::treebox::trigger, drawerbase::treebox::treebox_events>
{
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;
/// state images for the node
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;
/// 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;
/// The default constructor without creating the widget.
@ -378,7 +381,7 @@ namespace nana
/// \brief The construct that creates a widget.
/// @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);
/// \brief The construct that creates a widget.
@ -388,16 +391,16 @@ namespace nana
treebox(window, const nana::rectangle& = rectangle(), bool visible = true);
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));
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>
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));
return *this;
@ -406,38 +409,51 @@ namespace nana
const nana::pat::cloneable<compset_placer_interface> & placer() const;
/// \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.
void auto_draw(bool);
/// \brief Enable the checkbox for each item of the widget.
/// @param bool wheter to enable.
/// \brief Enable the checkboxs for each item of the widget.
/// @param bool indicates whether to show or hide the checkboxs.
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);
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.
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
);
/// 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
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
item_proxy selected() const;
item_proxy selected() const; ///< returns the selected node
};//end class treebox
}//end namespace nana
#endif

View File

@ -1,4 +1,4 @@
/*
/**
* The fundamental widget class implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
@ -409,6 +409,16 @@ namespace nana
{
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:
DrawerTrigger& get_drawer_trigger()
{

View File

@ -22,10 +22,10 @@ namespace nana
virtual ~key_interface(){}
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
//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)
{
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
#define NANA_PAINT_DETAIL_IMAGE_BMP_HPP

View File

@ -1,6 +1,7 @@
/*
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -39,6 +40,8 @@ namespace paint
bool empty() const;
operator unspecified_bool_t() const;
void close();
bool alpha() const;
nana::size size() 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.

View File

@ -14,7 +14,13 @@
#define NANA_SYSTEM_DATAEXCH_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.
class dataexch
{
@ -26,6 +32,7 @@ namespace nana{ namespace system{
void set(const nana::char_t* text);
void set(const nana::string& text);
bool set(const nana::paint::graphics& g);
void get(nana::string& str);
private:
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)
*
* @file: nana/basic_types.cpp
* @contributos: Jan
*/
#include <nana/basic_types.hpp>
@ -18,6 +19,8 @@
#endif
#include <algorithm>
#include <stdexcept>
namespace nana
{
//class color
@ -736,12 +739,12 @@ namespace nana
int rectangle::right() const
{
return static_cast<int>(x + width);
return x + static_cast<int>(width);
}
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
@ -753,7 +756,7 @@ namespace nana
bool rectangle::is_hit(const point& pos) const
{
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
@ -762,65 +765,65 @@ namespace nana
}
//end struct rectangle
//class area_rotator
area_rotator::area_rotator(bool rotated, const ::nana::rectangle& area)
//class rectangle_rotator
rectangle_rotator::rectangle_rotator(bool rotated, const ::nana::rectangle& area)
: rotated_(rotated),
area_(area)
{}
int area_rotator::x() const
int rectangle_rotator::x() const
{
return (rotated_ ? area_.y : area_.x);
}
int & area_rotator::x_ref()
int & rectangle_rotator::x_ref()
{
return (rotated_ ? area_.y : area_.x);
}
int area_rotator::y() const
int rectangle_rotator::y() const
{
return (rotated_ ? area_.x : area_.y);
}
int & area_rotator::y_ref()
int & rectangle_rotator::y_ref()
{
return (rotated_ ? area_.x : area_.y);
}
unsigned area_rotator::w() const
unsigned rectangle_rotator::w() const
{
return (rotated_ ? area_.height : area_.width);
}
unsigned & area_rotator::w_ref()
unsigned & rectangle_rotator::w_ref()
{
return (rotated_ ? area_.height : area_.width);
}
unsigned area_rotator::h() const
unsigned rectangle_rotator::h() const
{
return (rotated_ ? area_.width : area_.height);
}
unsigned & area_rotator::h_ref()
unsigned & rectangle_rotator::h_ref()
{
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));
}
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));
}
const ::nana::rectangle& area_rotator::result() const
const ::nana::rectangle& rectangle_rotator::result() const
{
return area_;
}
//end class area_rotator
//end class rectangle_rotator
}

View File

@ -23,7 +23,8 @@
#include PLATFORM_SPEC_HPP
#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>
namespace std
{

View File

@ -1,7 +1,7 @@
/*
* Platform Specification Implementation
* 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.
* (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)
{
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);
}
}

View File

@ -347,6 +347,7 @@ namespace nana
flags.destroying = false;
flags.borderless = false;
flags.make_bground_declared = false;
flags.ignore_menubar_focus = false;
visible = false;
@ -355,7 +356,6 @@ namespace nana
effect.bground_fade_rate = 0;
together.caret = nullptr;
together.attached_events = nullptr;
extra_width = extra_height = 0;
@ -368,16 +368,15 @@ namespace nana
bool basic_window::set_events(const std::shared_ptr<general_events>& p)
{
if (together.attached_events)
if (together.events_ptr)
return false;
together.events_ptr = p;
together.attached_events = p.get();
return true;
}
general_events * basic_window::get_events() const
{
return together.attached_events;
return together.events_ptr.get();
}
//end struct basic_window
}//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)
{
auto retain = wd->together.events_ptr;
auto evts_ptr = retain.get();
switch (evt_code)
{
case event_code::click:
@ -162,35 +165,36 @@ namespace nana
void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&);
::nana::basic_event<arg_mouse>* evt_addr;
switch (evt_code)
{
case event_code::click:
drawer_event_fn = &drawer::click;
evt_addr = &wd->together.attached_events->click;
evt_addr = &evts_ptr->click;
break;
case event_code::dbl_click:
drawer_event_fn = &drawer::dbl_click;
evt_addr = &wd->together.attached_events->dbl_click;
evt_addr = &evts_ptr->dbl_click;
break;
case event_code::mouse_enter:
drawer_event_fn = &drawer::mouse_enter;
evt_addr = &wd->together.attached_events->mouse_enter;
evt_addr = &evts_ptr->mouse_enter;
break;
case event_code::mouse_move:
drawer_event_fn = &drawer::mouse_move;
evt_addr = &wd->together.attached_events->mouse_move;
evt_addr = &evts_ptr->mouse_move;
break;
case event_code::mouse_leave:
drawer_event_fn = &drawer::mouse_leave;
evt_addr = &wd->together.attached_events->mouse_leave;
evt_addr = &evts_ptr->mouse_leave;
break;
case event_code::mouse_down:
drawer_event_fn = &drawer::mouse_down;
evt_addr = &wd->together.attached_events->mouse_down;
evt_addr = &evts_ptr->mouse_down;
break;
case event_code::mouse_up:
drawer_event_fn = &drawer::mouse_up;
evt_addr = &wd->together.attached_events->mouse_up;
evt_addr = &evts_ptr->mouse_up;
break;
default:
throw std::runtime_error("Invalid mouse event code");
@ -209,7 +213,7 @@ namespace nana
{
wd->drawer.mouse_wheel(*arg);
if (!draw_only)
wd->together.attached_events->mouse_wheel.emit(*arg);
evts_ptr->mouse_wheel.emit(*arg);
}
break;
}
@ -229,19 +233,19 @@ namespace nana
{
case event_code::key_press:
drawer_event_fn = &drawer::key_press;
evt_addr = &wd->together.attached_events->key_press;
evt_addr = &evts_ptr->key_press;
break;
case event_code::key_char:
drawer_event_fn = &drawer::key_char;
evt_addr = &wd->together.attached_events->key_char;
evt_addr = &evts_ptr->key_char;
break;
case event_code::key_release:
drawer_event_fn = &drawer::key_release;
evt_addr = &wd->together.attached_events->key_release;
evt_addr = &evts_ptr->key_release;
break;
case event_code::shortkey:
drawer_event_fn = &drawer::shortkey;
evt_addr = &wd->together.attached_events->shortkey;
evt_addr = &evts_ptr->shortkey;
break;
default:
throw std::runtime_error("Invalid keyboard event code");
@ -256,7 +260,7 @@ namespace nana
{
auto arg = dynamic_cast<const arg_expose*>(&event_arg);
if (arg)
wd->together.attached_events->expose.emit(*arg);
evts_ptr->expose.emit(*arg);
}
break;
case event_code::focus:
@ -266,7 +270,7 @@ namespace nana
{
wd->drawer.focus(*arg);
if (!draw_only)
wd->together.attached_events->focus.emit(*arg);
evts_ptr->focus.emit(*arg);
}
break;
}
@ -277,7 +281,7 @@ namespace nana
{
wd->drawer.move(*arg);
if (!draw_only)
wd->together.attached_events->move.emit(*arg);
evts_ptr->move.emit(*arg);
}
break;
}
@ -288,7 +292,7 @@ namespace nana
{
wd->drawer.resizing(*arg);
if (!draw_only)
wd->together.attached_events->resizing.emit(*arg);
evts_ptr->resizing.emit(*arg);
}
break;
}
@ -299,7 +303,7 @@ namespace nana
{
wd->drawer.resized(*arg);
if (!draw_only)
wd->together.attached_events->resized.emit(*arg);
evts_ptr->resized.emit(*arg);
}
break;
}
@ -309,9 +313,9 @@ namespace nana
auto arg = dynamic_cast<const arg_unload*>(&event_arg);
if (arg && (wd->other.category == category::flags::root))
{
auto evt_ptr = dynamic_cast<events_root_extension*>(wd->together.attached_events);
if (evt_ptr)
evt_ptr->unload.emit(*arg);
auto evt_root = dynamic_cast<events_root_extension*>(evts_ptr);
if (evt_root)
evt_root->unload.emit(*arg);
}
}
break;
@ -320,7 +324,7 @@ namespace nana
{
auto arg = dynamic_cast<const arg_destroy*>(&event_arg);
if (arg)
wd->together.attached_events->destroy.emit(*arg);
evts_ptr->destroy.emit(*arg);
}
break;
default:

View File

@ -1,7 +1,7 @@
/*
* Bedrock Selector
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at

View File

@ -21,8 +21,6 @@
#include <nana/detail/linux_X11/platform_spec.hpp>
#endif
#include <algorithm>
namespace nana
{
typedef detail::edge_nimbus_renderer<detail::bedrock::core_window_t> edge_nimbus_renderer_t;
@ -351,12 +349,13 @@ namespace nana
{
if(p)
{
auto i = std::find(dynamic_drawing_objects_.begin(), dynamic_drawing_objects_.end(), p);
if (i != dynamic_drawing_objects_.end())
{
delete (*i);
dynamic_drawing_objects_.erase(i);
}
for (auto i = dynamic_drawing_objects_.begin(); i != dynamic_drawing_objects_.end(); ++i)
if (*i == p)
{
delete (*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);
}
}
std::size_t events_operation::size() const
{
lock_guard lock(mutex_);
return register_.size();
}
//end namespace events_operation
}//end namespace detail
}//end namespace nana

View File

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

View File

@ -13,6 +13,7 @@
#include <nana/config.hpp>
#include PLATFORM_SPEC_HPP
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/screen.hpp>
#if defined(NANA_WINDOWS)
#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp>
@ -35,10 +36,10 @@ namespace nana{
#if defined(NANA_WINDOWS)
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())
return *(ico->ptr());
return 0;
return nullptr;
}
#endif
};
@ -51,17 +52,13 @@ namespace nana{
{
struct window_extra_t
{
HICON ico;
window_extra_t()
: ico(0)
{}
HICON ico{nullptr};
};
typedef std::map<native_window_type, window_extra_t> map_t;
private:
tray_manager(){}
tray_manager() = default;
public:
typedef window_extra_t extra_t;
@ -205,19 +202,21 @@ namespace nana{
if(owner && (nested == false))
::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,
pt.x, pt.y, 100, 100,
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.
::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;
::GetWindowRect(wnd, &wd_area);
wd_area.right -= wd_area.left;
wd_area.bottom -= wd_area.top;
if(nested)
::GetWindowRect(native_wd, &wd_area);
//a dimension with borders and caption title
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.top = pt.y;
@ -226,14 +225,15 @@ namespace nana{
int delta_w = static_cast<int>(r.width) - client.right;
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.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>(wd_area.right - client.right), static_cast<unsigned>(wd_area.bottom - client.bottom)};
#elif defined(NANA_X11)
@ -556,6 +556,7 @@ namespace nana{
{
::EnableWindow(native_wd, true);
::SetActiveWindow(native_wd);
::SetForegroundWindow(native_wd);
}
else
::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
//destroyed. This is a feature which is different from Windows. So the following
//works should be handled before calling XDestroyWindow.
auto & bedrock = bedrock::instance();
if(wd == bedrock.get_menu())
bedrock.empty_menu();
auto & brock = bedrock::instance();
if(wd == brock.get_menu())
{
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore is not decleard
}
Display* disp = restrict::spec.open_display();
restrict::spec.remove(wd);
auto iwd = bedrock.wd_manager.root(wd);
auto iwd = brock.wd_manager.root(wd);
if(iwd)
{
{
//Before calling window_manager::destroy, make sure the window is invisible.
//It is a behavior like Windows.
nana::detail::platform_scope_guard psg;
nana::detail::platform_scope_guard lock;
restrict::spec.set_error_handler();
::XUnmapWindow(disp, reinterpret_cast<Window>(wd));
::XFlush(disp);
restrict::spec.rev_error_handler();
}
bedrock.wd_manager.destroy(iwd);
bedrock.rt_manager.remove_if_exists(iwd);
bedrock.wd_manager.destroy_handle(iwd);
brock.wd_manager.destroy(iwd);
brock.rt_manager.remove_if_exists(iwd);
brock.wd_manager.destroy_handle(iwd);
}
nana::detail::platform_scope_guard psg;

View File

@ -8,6 +8,7 @@
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/detail/win32/bedrock.cpp
* @contributors: Ariel Vina-Rodriguez
*/
#include <nana/config.hpp>
@ -184,17 +185,18 @@ namespace detail
{
struct thread_context_cache
{
unsigned tid = 0;
thread_context *object = nullptr;
unsigned tid{ 0 };
thread_context *object{ nullptr };
}tcontext;
}cache;
struct menu_tag
{
core_window_t* taken_window = nullptr;
native_window_type window = nullptr;
native_window_type owner = nullptr;
bool has_keyboard = false;
core_window_t* taken_window{ nullptr };
bool delay_restore{ false };
native_window_type window{ nullptr };
native_window_type owner{ nullptr };
bool has_keyboard{false};
}menu;
struct keyboard_tracking_state_tag
@ -266,12 +268,6 @@ namespace detail
::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 pi_data_;
}
@ -855,7 +851,7 @@ namespace detail
case WM_WINDOWPOSCHANGED:
if ((reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW) && (!msgwnd->visible))
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);
def_window_proc = true;
@ -875,6 +871,7 @@ namespace detail
if (!brock.emit(event_code::focus, focus, arg, true, &context))
brock.wd_manager.set_focus(msgwnd, true);
}
def_window_proc = true;
break;
case WM_KILLFOCUS:
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
if(brock.wd_manager.available(msgwnd))
msgwnd->root_widget->other.attribute.root->context.focus_changed = true;
def_window_proc = true;
break;
case WM_MOUSEACTIVATE:
if(msgwnd->flags.take_active == false)
return MA_NOACTIVATE;
def_window_proc = true;
break;
case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
pressed_wd = nullptr;
@ -926,8 +927,8 @@ namespace detail
if(nullptr == msgwnd) break;
//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))
brock.remove_menu();
if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
brock.erase_menu(true);
else
brock.close_menu_if_focus_other_window(msgwnd->root);
@ -948,6 +949,8 @@ namespace detail
arg_mouse arg;
assign_arg(arg, msgwnd, message, pmdec);
msgwnd->flags.action = mouse_action::pressed;
auto retain = msgwnd->together.events_ptr;
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.
@ -982,6 +985,8 @@ namespace detail
msgwnd->flags.action = mouse_action::normal;
if(msgwnd->flags.enabled)
{
auto retain = msgwnd->together.events_ptr;
nana::arg_mouse arg;
assign_arg(arg, msgwnd, message, pmdec);
@ -1011,19 +1016,19 @@ namespace detail
if (fire_click)
{
arg.evt_code = event_code::click;
msgwnd->together.attached_events->click.emit(arg);
retain->click.emit(arg);
}
if (brock.wd_manager.available(msgwnd))
{
arg.evt_code = event_code::mouse_up;
msgwnd->together.attached_events->mouse_up.emit(arg);
retain->mouse_up.emit(arg);
}
}
else if (fire_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);
}
@ -1103,7 +1108,7 @@ namespace detail
case WM_MOUSEHWHEEL:
{
//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);
if (pointer_wd == root_window)
{
@ -1114,7 +1119,7 @@ namespace detail
auto evt_wd = scrolled_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;
nana::point mspos{ scr_pos.x, scr_pos.y };
@ -1189,7 +1194,7 @@ namespace detail
brock.wd_manager.calc_window_point(msgwnd, dropfiles.pos);
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);
}
}
@ -1308,6 +1313,7 @@ namespace detail
}
break;
case WM_SYSCHAR:
def_window_proc = true;
brock.set_keyboard_shortkey(true);
msgwnd = brock.wd_manager.find_shortkey(native_window, static_cast<unsigned long>(wParam));
if(msgwnd)
@ -1319,17 +1325,17 @@ namespace detail
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.ignore = false;
brock.emit(event_code::shortkey, msgwnd, arg, true, &context);
def_window_proc = false;
}
def_window_proc = true;
break;
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;
if(msgwnd)
if (msgwnd)
{
brock.wd_manager.set_focus(msgwnd, false);
bool focused = (brock.focus() == msgwnd);
arg_keyboard arg;
arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1337,18 +1343,26 @@ namespace detail
arg.key = static_cast<nana::char_t>(wParam);
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 if(brock.get_menu())
brock.remove_menu();
else
brock.erase_menu(true);
}
def_window_proc = true;
break;
case WM_SYSKEYUP:
def_window_proc = true;
if(brock.set_keyboard_shortkey(false) == false)
{
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
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.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1356,21 +1370,30 @@ namespace detail
arg.key = static_cast<nana::char_t>(wParam);
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;
}
}
}
def_window_proc = true;
break;
case WM_KEYDOWN:
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();
if(msgwnd)
{
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)
{
brock.wd_manager.set_focus(the_next, false);
@ -1388,6 +1411,17 @@ namespace detail
arg.key = static_cast<nana::char_t>(wParam);
brock.get_key_state(arg);
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);
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))
brock.emit_drawer(event_code::key_char, msgwnd, arg, &context);
@ -1432,6 +1466,8 @@ namespace detail
}
else
brock.set_keyboard_shortkey(false);
brock.delay_restore(2); //Restores while key release
break;
case WM_CLOSE:
{
@ -1449,8 +1485,12 @@ namespace detail
break;
}
case WM_DESTROY:
if(msgwnd->root == brock.get_menu())
brock.empty_menu();
if (msgwnd->root == brock.get_menu())
{
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore not decleared
}
brock.wd_manager.destroy(msgwnd);
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)
{
auto pre = impl_->menu.taken_window;
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;
impl_->menu.taken_window = nullptr;
return wd;
switch (state)
{
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)
@ -1535,7 +1601,7 @@ namespace detail
else
return false;
}
remove_menu();
erase_menu(true);
return true;
}
return false;
@ -1545,7 +1611,7 @@ namespace detail
{
if(menu_wd && impl_->menu.window != menu_wd)
{
remove_menu();
erase_menu(true);
impl_->menu.window = menu_wd;
impl_->menu.owner = native_interface::get_owner_window(menu_wd);
@ -1569,21 +1635,13 @@ namespace detail
return impl_->menu.window;
}
void bedrock::remove_menu()
void bedrock::erase_menu(bool try_destroy)
{
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 (impl_->menu.window)
{
if (try_destroy)
native_interface::close_window(impl_->menu.window);
impl_->menu.window = impl_->menu.owner = nullptr;
impl_->menu.has_keyboard = false;
}

View File

@ -8,7 +8,8 @@
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/detail/window_manager.cpp
*
* @author: Jinhao
* @contributors: Katsuhisa Yuasa
*/
#include <nana/config.hpp>
@ -20,7 +21,6 @@
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/effects_renderer.hpp>
#include <stdexcept>
#include <algorithm>
namespace nana
{
@ -191,7 +191,7 @@ namespace detail
switch(evtid)
{
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;
default:
break;
@ -875,7 +875,16 @@ namespace detail
if (!root_has_been_focused)
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;
}
@ -975,11 +984,15 @@ namespace detail
}
else
{
auto i = std::find_if(attr_cap.begin(), attr_cap.end(),
[wd](const std::pair<core_window_t*, bool> & x){ return (x.first == wd);});
for (auto i = attr_cap.begin(), end = attr_cap.end(); i != end; ++i)
{
if (i->first == wd)
{
attr_cap.erase(i);
break;
}
}
if(i != attr_cap.end())
attr_cap.erase(i);
return attr_.capture.window;
}
return wd;

View File

@ -973,6 +973,7 @@ namespace nana
const nana::char_t * filter;
nana::string filter_holder;
nana::string default_extension;
if(impl_->filters.size())
{
for(auto & f : impl_->filters)
@ -990,6 +991,21 @@ namespace nana
}
filter_holder += fs;
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();
}
@ -1002,6 +1018,10 @@ namespace nana
ofn.lpstrFileTitle = nullptr;
ofn.nMaxFileTitle = 0;
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)))
return false;

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/*
/**
* An Implementation of Place for Layout
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -21,6 +21,7 @@
#include <memory>
#include <limits>
#include <algorithm>
namespace nana
{
@ -558,18 +559,22 @@ namespace nana
return token::identifier;
}
std::string err = "an invalid character '";
err += *sp_;
err += "'";
_m_throw_error(err);
_m_throw_error(*sp_);
return token::error; //Useless, just for syntax correction.
}
private:
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;
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());
}
@ -578,8 +583,7 @@ namespace nana
if (token::equal != read())
_m_throw_error("an equal sign is required after '" + idstr_ + "'");
const char* p = sp_;
for (; *p == ' '; ++p);
const char* p = _m_eat_whitespace(sp_);
auto neg_ptr = p;
if ('-' == *p)
@ -598,8 +602,7 @@ namespace nana
if (token::equal != read())
_m_throw_error("an equal sign is required after '" + idstr + "'");
const char* p = sp_;
for (; *p == ' ' || *p == '\t'; ++p);
const char* p = _m_eat_whitespace(sp_);
reparray_.reset();
auto tk = read();
@ -619,14 +622,7 @@ namespace nana
}
}
void _m_throw_error(const std::string& err)
{
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)
static const char* _m_eat_whitespace(const char* sp)
{
while (*sp && !isgraph(*sp))
++sp;
@ -677,7 +673,7 @@ namespace nana
if (gotcha)
{
for (; *sp == ' ' || *sp == '\t'; ++sp);
sp = _m_eat_whitespace(sp);
if ('%' == *sp)
{
if (number_t::kind::integer == number_.kind_of())
@ -757,6 +753,20 @@ namespace nana
for (auto & e : fastened)
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:
//The defintion is moved after the definition of class division
template<typename Function>
@ -768,15 +778,8 @@ namespace nana
{
return API::events(wd).destroy.connect([this](const arg_destroy& arg)
{
for (auto i = elements.begin(), end = elements.end(); i != end; ++i)
{
if (arg.window_handle == i->handle)
{
elements.erase(i);
break;
}
}
place_ptr_->collocate();
if (erase_element(elements, arg.window_handle))
place_ptr_->collocate();
});
}
@ -815,13 +818,7 @@ namespace nana
//does not change the layout.
auto evt = API::events(wd).destroy([this](const arg_destroy& arg)
{
auto destroyed_wd = 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);
erase_element(fastened, arg.window_handle);
});
fastened.emplace_back(wd, evt);
@ -929,16 +926,9 @@ namespace nana
{
for (auto & child : div->children)
{
if (child->field)
{
if (vsb)
{
if (child->visible)
child->field->visible(true);
}
else
child->field->visible(false);
}
if (child->field && (!vsb || child->visible))
child->field->visible(vsb);
_m_visible_for_child(child.get(), vsb);
}
}
@ -985,7 +975,7 @@ namespace nana
const bool vert = (kind::arrange != kind_of_division);
auto area_margined = margin_area();
area_rotator area(vert, area_margined);
rectangle_rotator area(vert, area_margined);
auto area_px = area.w();
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.
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.y_ref() = area.y();
child_area.h_ref() = area.h();
@ -1510,17 +1500,6 @@ namespace nana
class place::implement::div_splitter
: 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};
public:
div_splitter(place_parts::number_t init_weight)
@ -1533,14 +1512,9 @@ namespace nana
this->weight.assign(splitter_px);
}
void leaf_left(division * d)
void set_leaf(bool is_left, division * d)
{
leaf_left_ = d;
}
void leaf_right(division * d)
{
leaf_right_ = d;
(is_left ? leaf_left_ : leaf_right_) = d;
}
void direction(bool horizontal)
@ -1565,8 +1539,9 @@ namespace nana
auto px_ptr = &nana::rectangle::width;
auto area_left = leaf_left_->margin_area();
auto area_right = leaf_right_->margin_area();
//Use field_area of leaf, not margin_area. Otherwise splitter would be at wrong position
auto area_left = leaf_left_->field_area;
auto area_right = leaf_right_->field_area;
if (nana::cursor::size_we != splitter_cursor_)
{
@ -1590,7 +1565,7 @@ namespace nana
return;
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 total_pixels = static_cast<int>(left_pixels_ + right_pixels_);
@ -1631,8 +1606,8 @@ namespace nana
{
const bool vert = (::nana::cursor::size_we != splitter_cursor_);
area_rotator left(vert, leaf_left_->field_area);
area_rotator right(vert, leaf_right_->field_area);
rectangle_rotator left(vert, leaf_left_->field_area);
rectangle_rotator right(vert, leaf_right_->field_area);
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)));
@ -1642,7 +1617,7 @@ namespace nana
else if (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;
left.w_ref() = static_cast<unsigned>(pos - left.x());
@ -1658,7 +1633,7 @@ namespace nana
leaf_right_->collocate(wd);
//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());
leaf_left_->weight.assign_percent(imd_rate * static_cast<int>(left.w()));
@ -1673,14 +1648,14 @@ namespace nana
splitter_.move(this->field_area);
}
private:
area_rotator _m_update_splitter_range()
rectangle_rotator _m_update_splitter_range()
{
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);
area_rotator right(vert, leaf_right_->field_area);
rectangle_rotator left(vert, leaf_left_->field_area);
rectangle_rotator right(vert, leaf_right_->field_area);
const int left_base = left.x(), right_base = right.right();
int pos = left_base;
@ -1785,7 +1760,7 @@ namespace nana
if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division))
{
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.emplace_back(splitter);
}
@ -1797,7 +1772,7 @@ namespace nana
{
children.back()->div_next = div.get();
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());
}
@ -2182,29 +2157,14 @@ namespace nana
bool recollocate = false;
for (auto & fld : impl_->fields)
{
auto & elements = fld.second->elements;
for (auto i = elements.begin(); i != elements.end();)
auto evt = fld.second->erase_element(fld.second->elements, handle);
if (evt)
{
if (i->handle == handle)
{
API::umake_event(i->evt_destroy);
i = elements.erase(i);
recollocate |= (nullptr != fld.second->attached);
}
else
++i;
API::umake_event(evt);
recollocate |= (nullptr != fld.second->attached);
}
auto i = std::find_if(fld.second->fastened.begin(), fld.second->fastened.end(), [handle](implement::field_impl::element_t& e)
{
return (e.handle == handle);
});
if (i != fld.second->fastened.end())
{
API::umake_event(i->evt_destroy);
fld.second->fastened.erase(i);
}
API::umake_event( fld.second->erase_element(fld.second->fastened, handle));
}
if (recollocate)

View File

@ -1,13 +1,14 @@
/*
* Nana GUI Programming Interface Implementation
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/programming_interface.cpp
* @author: Jinhao
*/
#include <nana/gui/programming_interface.hpp>
@ -15,7 +16,6 @@
#include <nana/system/platform.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/widgets/widget.hpp>
#include <algorithm>
namespace nana
{
@ -53,7 +53,7 @@ namespace API
if (!restrict::window_manager.available(reinterpret_cast<restrict::core_window_t*>(wd)))
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
@ -239,6 +239,11 @@ namespace API
return &reinterpret_cast<restrict::core_window_t*>(wd)->drawer.graphics;
return nullptr;
}
void delay_restore(bool enable)
{
restrict::bedrock.delay_restore(enable ? 0 : 1);
}
}//end namespace dev
//exit
@ -259,8 +264,20 @@ namespace API
if((wd->thread_id == tid) && (wd->root != 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);
}
}
}
@ -598,7 +615,7 @@ namespace API
nana::size window_size(window wd)
{
nana::rectangle r;
API::window_rectangle(wd, r);
API::get_window_rectangle(wd, r);
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);
internal_scope_guard lock;
@ -751,7 +807,7 @@ namespace API
return cursor::arrow;
}
bool is_focus_window(window wd)
bool is_focus_ready(window wd)
{
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
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)
{
auto const iwd = reinterpret_cast<restrict::core_window_t*>(wd);

View File

@ -25,39 +25,22 @@ namespace nana
: public display
{
public:
real_display(std::size_t number)
: 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() = default; //For requirement of vector
real_display(std::size_t number, const ::nana::rectangle& r)
: index_(number), area_(r)
#if defined(NANA_WINDOWS)
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:
//Implementation of display
std::size_t get_index() const override
@ -65,13 +48,25 @@ namespace nana
return index_;
}
bool is_primary_monitor() const override
{
return is_primary_;
}
const ::nana::rectangle& area() const override
{
return area_;
}
const ::nana::rectangle& workarea() const override
{
return workarea_;
}
private:
const std::size_t index_;
std::size_t index_;
bool is_primary_;
::nana::rectangle area_;
::nana::rectangle workarea_;
};
//class screen
@ -92,7 +87,61 @@ namespace nana
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)
typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD);
@ -107,87 +156,47 @@ namespace nana
mi.cbSize = sizeof mi;
if (::GetMonitorInfo(monitor, &mi))
{
DISPLAY_DEVICE disp;
disp.cb = sizeof disp;
DWORD index = 0;
while (::EnumDisplayDevices(nullptr, index++, &disp, 0))
for (auto & disp : impl_->displays)
{
DEVMODE mode;
mode.dmSize = sizeof mode;
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
{
if (mode.dmPosition.x == mi.rcWork.left && mode.dmPosition.y == mi.rcWork.top &&
(static_cast<int>(mode.dmPelsWidth) == mi.rcWork.right - mi.rcWork.left) &&
(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) });
}
}
auto & r = disp.area();
if (r.x == mi.rcMonitor.left && r.y == mi.rcMonitor.top &&
r.width == unsigned(mi.rcMonitor.right - mi.rcMonitor.left) &&
r.height == unsigned(mi.rcMonitor.bottom - mi.rcMonitor.top)
)
return disp;
}
}
}
#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;
API::calc_screen_point(wd, 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;
while (::EnumDisplayDevices(nullptr, index++, &disp, 0));
return static_cast<std::size_t>(index - 1);
#else
return 1;
#endif
display& screen::get_display(std::size_t index) const
{
return impl_->displays.at(index);
}
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
{
#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);
throw std::logic_error("no primary monitor found");
}
void screen::for_each(std::function<void(display&)> fn) const
{
auto n = count();
for (decltype(n) i = 0; i < n; ++i)
{
real_display disp(i);
for (auto & disp : impl_->displays)
fn(disp);
}
}
//end class screen
}

View File

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

View File

@ -1,6 +1,7 @@
/*
* 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.
* (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)
{
auto scr_area = screen::from_point(pos)->area();
if (pos.x + sz.width > scr_area.x + scr_area.width)
pos.x = static_cast<int>(scr_area.x + scr_area.width - sz.width);
auto scr_area = screen().from_point(pos).workarea();
if (pos.x + static_cast<int>(sz.width) > scr_area.right())
pos.x = scr_area.right() - static_cast<int>(sz.width);
if (pos.x < scr_area.x)
pos.x = scr_area.x;
if (pos.y + sz.height >= scr_area.y + scr_area.height)
pos.y = static_cast<int>(scr_area.y + scr_area.height - sz.height);
if (pos.y + static_cast<int>(sz.height) >= scr_area.bottom())
pos.y = scr_area.bottom() - static_cast<int>(sz.height);
else if (!overlap_allowed)
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
{
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 });
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)
{
create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
}
checkbox::checkbox(window wd, const nana::string& text, bool visible)
{
create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
caption(text);
}
checkbox::checkbox(window wd, const nana::char_t* text, bool visible)
{
create(wd, rectangle(), visible);
bgcolor(API::bgcolor(wd));
caption(text);
}
checkbox::checkbox(window wd, const nana::rectangle& r, bool visible)
{
bgcolor(API::bgcolor(wd));
create(wd, r, visible);
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* A Menu implementation
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -106,7 +106,7 @@ namespace nana
sz.width -= 30;
sz.height -= 2;
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);
}
@ -122,17 +122,17 @@ namespace nana
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)
graph.set_pixel(points[i].x, points[i].y);
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))
{
graph.rectangle(r, false, { 0xCD, 0xD3, 0xE6 });
graph.rectangle(r, false, static_cast<color_rgb>(0xCDD3E6));
::nana::color clr(0xE6, 0xEF, 0xF4);
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)
{
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);
tr.render(pos, text.c_str(), text.length(), text_pixels, true);
}
@ -363,59 +363,58 @@ namespace nana
bool goto_next(bool forword)
{
state_.nullify_mouse = true;
if(menu_->items.size())
{
std::size_t index = state_.active;
if (menu_->items.empty())
return false;
bool end = false;
while(true)
auto pos = state_.active;
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)
{
end = true;
index = 0;
}
else
{
index = npos;
break;
}
pos = npos;
break;
}
else
++index;
end = true;
pos = 0;
}
else
{
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;
++pos;
}
if(index != npos && index != state_.active)
else
{
state_.active = index;
state_.sub_window = false;
draw();
return true;
if(pos == 0 || pos == npos)
{
if (end)
break;
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;
}
@ -486,30 +485,32 @@ namespace nana
std::size_t index = 0;
for(auto & m : menu_->items)
{
if(std::tolower(m.hotkey) == key)
if (std::tolower(m.hotkey) != key)
{
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;
++index;
continue;
}
++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;
}
@ -529,53 +530,53 @@ namespace nana
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)
{
if(false == 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
if(m.flags.splitter)
{
graph_->set_color(colors::gray_border);
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph_->width()) - 1, item_r.y });
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:
@ -592,9 +593,9 @@ namespace nana
std::size_t _m_get_index_by_pos(int x, int y) const
{
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>(graph_->height() - detail_.border.y)))
(y > static_cast<int>(graph_->height()) - static_cast<int>(detail_.border.y)))
return npos;
int pos = detail_.border.y;
@ -659,14 +660,14 @@ namespace nana
API::calc_screen_point(*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)
pos.x = static_cast<int>(scr_area.x + scr_area.width - size.width);
if(pos.x + static_cast<int>(size.width) > scr_area.right())
pos.x = scr_area.right() - static_cast<int>(size.width);
if(pos.x < scr_area.x) pos.x = scr_area.x;
if(pos.y + size.height > scr_area.y + scr_area.height)
pos.y = static_cast<int>(scr_area.y + scr_area.height - size.height);
if(pos.y + static_cast<int>(size.height) > scr_area.bottom())
pos.y = scr_area.bottom() - static_cast<int>(size.height);
if(pos.y < scr_area.y) pos.y = scr_area.y;
auto owner = API::get_owner_window(*widget_);
@ -705,7 +706,7 @@ namespace nana
menu_window(window wd, const point& pos, renderer_interface * rdptr)
: 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)
{
caption(STR("nana menu window"));
@ -729,11 +730,6 @@ namespace nana
API::activate_window(this->parent());
API::take_active(this->handle(), false, nullptr);
}
else
{
activate();
focus();
}
if(submenu_.parent == nullptr)
{
@ -753,14 +749,6 @@ namespace nana
pick();
});
if (want_focus_)
{
event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg)
{
_m_focus_changed(arg);
});
}
timer_.interval(100);
timer_.elapse([this]{
this->_m_check_repeatly();
@ -768,6 +756,30 @@ namespace nana
timer_.start();
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)
@ -783,39 +795,33 @@ namespace nana
API::update_window(object->handle());
}
bool goto_submenu()
bool submenu(bool enter)
{
menu_window * object = this;
while(object->submenu_.child)
while (object->submenu_.child)
object = object->submenu_.child;
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;
menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0);
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)
{
menu_window * object = this;
@ -832,62 +838,52 @@ namespace nana
object = object->submenu_.child;
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();
if (menu)
//There is a situation that menu will not call functor if the item style is check_option
//and it is checked before clicking.
bool call_functor = true;
if (checks::highlight == item.style)
{
menu_item_type & item = menu->items.at(active);
if (item.flags.splitter == false && item.sub_menu == nullptr)
item.flags.checked = !item.flags.checked;
}
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
//and it is checked before clicking.
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);
}
if (menu->items.at(--pos).flags.splitter)
break;
}
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)
{
switch(arg.key)
{
case keyboard::os_arrow_up:
this->goto_next(false);
break;
case keyboard::os_arrow_down:
this->goto_next(true);
this->goto_next(keyboard::os_arrow_down == arg.key);
break;
case keyboard::os_arrow_left:
this->exit_submenu();
break;
case keyboard::os_arrow_right:
this->goto_submenu();
this->submenu(keyboard::os_arrow_right == arg.key);
break;
case keyboard::enter:
this->pick();
break;
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();
}
else
goto_submenu();
this->submenu(true);
}
}
@ -1165,7 +1140,7 @@ namespace nana
{
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.kill = false;
return true;
@ -1184,9 +1159,10 @@ namespace nana
menu *menu::create_sub_menu(std::size_t index)
{
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.kill = true;
return sub;
@ -1255,12 +1231,12 @@ namespace nana
bool menu::goto_submen()
{
return (impl_->uiobj ? impl_->uiobj->goto_submenu() : false);
return (impl_->uiobj ? impl_->uiobj->submenu(true) : false);
}
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
@ -1311,21 +1287,17 @@ namespace nana
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)
{
if (impl_->mbuilder.data().items.size())
{
close();
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, point(x, y), &(*impl_->mbuilder.renderer())));
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);
}

View File

@ -1,7 +1,7 @@
/*
* A Menubar implementation
* 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.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -30,21 +30,21 @@ namespace nana
{
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)
{}
nana::string text;
::nana::string text;
unsigned long shortkey;
nana::menu menu_obj;
nana::point pos;
nana::size size;
::nana::menu menu_obj;
::nana::point pos;
::nana::size size;
};
class trigger::itembase
{
public:
typedef std::vector<item_type*> container;
using container = std::vector<item_type*>;
~itembase()
{
@ -52,22 +52,12 @@ namespace nana
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);
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
{
if(shortkey)
@ -98,19 +88,19 @@ namespace nana
: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_);
::nana::color border, body, corner;
switch(state)
switch (item_state)
{
case item_renderer::state_highlight:
case state::highlighted:
border = colors::highlight;
body.from_rgb(0xC0, 0xDD, 0xFC);
corner = body.blend(bground, 0.5);
break;
case item_renderer::state_selected:
case state::selected:
border = colors::dark_border;
body = colors::white;
corner = body.blend(bground, 0.5);
@ -122,17 +112,19 @@ namespace nana
nana::rectangle r(pos, size);
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_pixel(pos.x, pos.y);
graph_.set_pixel(pos.x + size.width - 1, pos.y);
graph_.set_pixel(pos.x, pos.y + size.height - 1);
graph_.set_pixel(pos.x + size.width - 1, pos.y + size.height - 1);
graph_.set_pixel(right, pos.y);
graph_.set_pixel(pos.x, bottom);
graph_.set_pixel(right, bottom);
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
@ -146,23 +138,28 @@ namespace nana
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);
if(shkey)
API::register_shortkey(widget_->handle(), shkey);
auto i = items_->cont().size();
auto pos = items_->cont().size();
items_->append(text, shkey);
_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
@ -219,22 +216,17 @@ namespace nana
void trigger::mouse_down(graph_reference graph, const arg_mouse& arg)
{
state_.nullify_mouse = false;
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;
_m_popup_menu();
}
else
_m_total_close();
}
else if(npos == state_.active)
_m_total_close();
else
_m_popup_menu();
}
else
_m_total_close();
_m_draw();
API::lazy_refresh();
@ -256,7 +248,6 @@ namespace nana
_m_draw();
API::lazy_refresh();
}
}
void trigger::focus(graph_reference, const arg_focus& arg)
@ -281,10 +272,10 @@ namespace nana
switch(arg.key)
{
case keyboard::os_arrow_down:
state_.menu->goto_next(true); break;
case keyboard::backspace:
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:
if(state_.menu->goto_submen() == false)
_m_move(false);
@ -305,17 +296,26 @@ namespace nana
state_.menu->pick();
break;
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();
if(arg.key == 18) //ALT
if (arg.key == 18) //ALT
state_.behavior = state_.behavior_focus;
}
}
else
break;
case 2: //GOTO SUBMENU
state_.menu->goto_submen();
break;
}
break;
}
}
else
@ -323,19 +323,34 @@ namespace nana
switch(arg.key)
{
case keyboard::os_arrow_right:
_m_move(false);
break;
case keyboard::backspace:
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;
case keyboard::escape:
if(state_.behavior == state_.behavior_focus)
{
state_.active= npos;
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()
{
if(state_.menu_active && (state_.menu != items_->get_menu(state_.active)))
{
std::size_t index = state_.active;
_m_close_menu();
state_.active = index;
auto& items = items_->cont();
state_.menu = items_->get_menu(state_.active);
if(state_.menu)
auto pos = state_.active;
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->destroy_answer(std::bind(&trigger::_m_unload_menu_window, this));
menu_accessor::popup(*state_.menu, widget_->handle(), m.pos.x, m.pos.y + m.size.height);
return true;
}
state_.menu = nullptr;
if (state_.passive_close)
{
_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;
}
@ -443,8 +475,6 @@ namespace nana
state_.menu_active = false;
state_.behavior = state_.behavior_none;
API::restore_menubar_taken_window();
auto pos = API::cursor_position();
API::calc_window_point(widget_->handle(), pos);
state_.active = _m_item_by_pos(pos);
@ -463,17 +493,6 @@ namespace nana
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)
{
if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25))
@ -521,9 +540,9 @@ namespace nana
for(auto i : items_->cont())
{
//Transform the text if it contains the hotkey character
nana::string::value_type hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos);
::nana::char_t hotkey;
::nana::string::size_type hotkey_pos;
auto text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos);
nana::size text_s = graph_->text_extent_size(text);
@ -532,10 +551,11 @@ namespace nana
i->pos = item_pos;
i->size = item_s;
item_renderer::state_t state = (index != state_.active ? ird.state_normal : (state_.menu_active ? ird.state_selected : ird.state_highlight));
ird.background(item_pos, item_s, state);
using state = item_renderer::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 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
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)
{
@ -566,7 +586,12 @@ namespace nana
//struct 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 class trigger

View File

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

View File

@ -52,20 +52,11 @@ namespace nana
pos = screen_pos.x;
}
if(scale >= fixedsize * 2)
{
if(pos < static_cast<int>(fixedsize))
return buttons::first;
if(pos > static_cast<int>(scale - fixedsize))
return buttons::second;
}
else
{
if(pos < static_cast<int>(scale / 2))
return buttons::first;
if(pos > static_cast<int>(scale / 2))
return buttons::second;
}
const auto bound_pos = static_cast<int>(scale >= fixedsize * 2 ? fixedsize : scale / 2);
if (pos < bound_pos)
return buttons::first;
if (pos > static_cast<int>(scale) - bound_pos)
return buttons::second;
if(metrics_.scroll_length)
{
@ -100,7 +91,7 @@ namespace nana
metrics_.scroll_pos = pos;
auto value_max = metrics_.peak - metrics_.range;
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 nextpos = static_cast<int>((metrics_.value + 1) * scroll_area / value_max);
@ -115,22 +106,22 @@ namespace nana
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)
{ //backward
if(metrics_.value <= metrics_.range)
metrics_.value = 0;
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;
}
if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range)
metrics_.value = metrics_.peak - metrics_.range;
else
metrics_.value += (metrics_.range-1);
}
}
@ -141,26 +132,20 @@ namespace nana
_m_background(graph);
::nana::rectangle r(graph.size());
if(vertical_)
{
r.y = r.height - fixedsize;
r.height = fixedsize;
}
else
{
r.x = r.width - fixedsize;
r.width = fixedsize;
}
rectangle_rotator r(vertical_, graph.size());
r.x_ref() = static_cast<int>(r.w() - fixedsize);
r.w_ref() = fixedsize;
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);
auto result = r.result();
//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
_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
_m_draw_scroll(graph, (buttons::scroll == what ? moused_state : states::highlight));
@ -171,64 +156,61 @@ namespace nana
{
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;
unsigned width = graph.width(), height = graph.height();
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});
r.x_ref() = static_cast<int>(fixedsize);
r.w_ref() = metrics_.scroll_pos;
}
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)
{
if(state)
if (!state)
return;
::nana::color clr{0x97, 0x97, 0x97}; //highlight
switch(state)
{
::nana::color clr{0x97, 0x97, 0x97}; //highlight
switch(state)
{
case states::actived:
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_);
case states::actived:
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.gradual_rectangle(r, colors::white, clr, !vertical_);
}
bool drawer::_m_check() const
@ -271,20 +253,11 @@ namespace nana
{
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_)
{
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);
_m_button_frame(graph, r.result(), state);
}
}

View File

@ -1,15 +1,15 @@
/*
* A text editor 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/gui/widgets/skeletons/text_editor.cpp
* @description:
*/
* A text editor 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/gui/widgets/skeletons/text_editor.cpp
* @contributors: Ariel Vina-Rodriguez
*/
#include <nana/gui/widgets/skeletons/text_editor.hpp>
#include <nana/gui/widgets/skeletons/textbase_export_interface.hpp>
#include <nana/gui/element.hpp>
@ -18,6 +18,7 @@
#include <numeric>
#include <cwctype>
#include <set>
#include <algorithm>
namespace nana{ namespace widgets
{
@ -314,7 +315,13 @@ namespace nana{ namespace widgets
if (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_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)) };
//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)
{
scrpos.x += (editor_.points_.offset.x - editor_.text_area_.area.x);
@ -676,7 +689,7 @@ namespace nana{ namespace widgets
}
}
else
editor_.render(API::is_focus_window(editor_.window_));
editor_.render(API::is_focus_ready(editor_.window_));
}
void render(const ::nana::color& fgcolor) override
@ -737,17 +750,24 @@ namespace nana{ namespace widgets
nana::point scrpos;
if (0 != pos.x)
{
nana::string str;
for (auto & sec : mtr.line_sections)
{
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)
{
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;
}
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;
}
else
@ -773,13 +793,19 @@ namespace nana{ namespace widgets
return{ 0, static_cast<unsigned>(primary) };
//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;
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;
if (scrpos.x < 0)
scrpos.x = 0;
@ -793,7 +819,7 @@ namespace nana{ namespace widgets
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 += static_cast<unsigned>(ent.begin - str.begin);
res.x += static_cast<unsigned>(ent.begin - str);
return res;
}
scrpos.x -= str_px;
@ -1133,12 +1159,14 @@ namespace nana{ namespace widgets
public:
void parse(const ::nana::string& text, const keywords* kwptr)
{
if (text.empty())
if ( kwptr->kwbase.empty() || text.empty() )
return;
using index = ::nana::string::size_type;
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)
{
@ -1160,53 +1188,48 @@ namespace nana{ namespace widgets
::nana::cistring cistr;
for (auto & ds : kwptr->kwbase)
{
std::size_t pos;
const ::nana::char_t* begin;
const ::nana::char_t* end;
if (ds.case_sensitive)
{
pos = text.find(ds.text);
if (pos == text.npos)
continue;
index pos{0} ;
for (index rest{text.size()}; rest >= ds.text.size() ; ++pos, rest = text.size() - pos)
{
if (ds.case_sensitive)
{
pos = text.find(ds.text, pos);
if (pos == text.npos)
break;
if (ds.whole_word_matched)
{
if (!test_whole_word(pos, ds.text.size()))
continue;
}
if (ds.whole_word_matched)
{
if (!test_whole_word(pos, ds.text.size()))
continue;
}
}
else
{
if (cistr.empty())
cistr.append(text.data(), text.size());
begin = text.data() + pos;
end = begin + ds.text.size();
}
else
{
if (cistr.empty())
cistr.append(text.data(), text.size());
pos = cistr.find(ds.text.data(), pos);
if (pos == cistr.npos)
break;
pos = cistr.find(ds.text.data());
if (pos == cistr.npos)
continue;
if (ds.whole_word_matched)
{
if (!test_whole_word(pos, ds.text.size()))
continue;
}
}
if (ds.whole_word_matched)
{
if (!test_whole_word(pos, ds.text.size()))
continue;
}
begin = text.data() + pos;
end = begin + ds.text.size();
}
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();
}
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 = text.data() + pos;
last.end = last.begin + ds.text.size();
last.scheme = ki->second.get();
}
}
}
if (!entities.empty())
@ -1221,7 +1244,7 @@ namespace nana{ namespace widgets
while(i != entities.end())
{
if (previous->end > i->begin)
i = entities.erase(i);
i = entities.erase(i); // erase overlaping. Left only the first.
else
++i;
}
@ -1326,7 +1349,7 @@ namespace nana{ namespace widgets
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)
{
@ -1377,6 +1400,24 @@ namespace nana{ namespace widgets
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()
{
behavior_->pre_calc_lines(width_pixels());
@ -1407,7 +1448,7 @@ namespace nana{ namespace widgets
move_caret(upoint{});
_m_scrollbar();
render(API::is_focus_window(window_));
render(API::is_focus_ready(window_));
return true;
}
return false;
@ -1425,7 +1466,7 @@ namespace nana{ namespace widgets
_m_reset();
behavior_->pre_calc_lines(width_pixels());
render(API::is_focus_window(window_));
render(API::is_focus_ready(window_));
_m_scrollbar();
return true;
}
@ -1676,7 +1717,7 @@ namespace nana{ namespace widgets
//Set caret position through text coordinate
void text_editor::move_caret(const upoint& crtpos)
{
if (!API::is_focus_window(window_))
if (!API::is_focus_ready(window_))
return;
const unsigned line_pixels = line_height();
@ -1718,7 +1759,7 @@ namespace nana{ namespace widgets
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);
}
@ -1883,7 +1924,7 @@ namespace nana{ namespace widgets
{
behavior_->adjust_caret_into_screen();
reset_caret();
render(API::is_focus_window(window_));
render(API::is_focus_ready(window_));
_m_scrollbar();
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)
{
const bool redraw_required = _m_cancel_select(0);
@ -2528,7 +2550,7 @@ namespace nana{ namespace widgets
//The number of new lines minus one
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')
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 };
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_)
{
nana::string maskstr;
maskstr.append(linestr.size(), mask_char_);
graph_.string(text_pos, maskstr, clr);
return;
}
mask_str.reset(new nana::string(str.size(), mask_char_));
auto & linestr = (if_mask && mask_char_ ? *mask_str : str);
unicode_bidi bidi;
std::vector<unicode_bidi::entity> reordered;

View File

@ -14,6 +14,7 @@
#include <nana/gui/widgets/skeletons/text_editor.hpp>
#include <nana/gui/element.hpp>
#include <nana/gui/timer.hpp>
#include <algorithm>
namespace nana
{
@ -328,7 +329,7 @@ namespace nana
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_);
}
@ -420,7 +421,7 @@ namespace nana
if (!editor_)
return;
if (API::is_focus_window(editor_->window_handle()))
if (API::is_focus_ready(editor_->window_handle()))
editor_->text(range_->value());
else
editor_->text(modifier_.prefix + range_->value() + modifier_.suffix);
@ -559,7 +560,7 @@ namespace nana
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_->draw_spins();
@ -569,7 +570,7 @@ namespace nana
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()))
impl_->draw_spins();

View File

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

View File

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

View File

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

View File

@ -12,6 +12,10 @@
#include <nana/system/dataexch.hpp>
#include <nana/traits.hpp>
#include <nana/paint/graphics.hpp>
#include <vector>
#include <cassert>
#if defined(NANA_WINDOWS)
#include <windows.h>
#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));
}
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)
{
std::size_t size;
@ -78,8 +162,8 @@ namespace nana{ namespace system{
case format::unicode: type = CF_UNICODETEXT; break;
case format::pixmap: type = CF_BITMAP; break;
}
::SetClipboardData(type, g);
res = true;
HANDLE h = ::SetClipboardData(type, g);
res = (h != NULL);
}
::CloseClipboard();
}