Merge branch 'develop'

This commit is contained in:
Jinhao 2016-09-25 22:24:22 +08:00
commit 61832c0a7c
62 changed files with 1910 additions and 1430 deletions

2
.gitignore vendored
View File

@ -43,3 +43,5 @@ CMakeFiles/
cmake_install.cmake cmake_install.cmake
*.DS_Store *.DS_Store
*.db
*.opendb

View File

@ -17,13 +17,11 @@
#ifndef NANA_DETAIL_PLATFORM_SPEC_HPP #ifndef NANA_DETAIL_PLATFORM_SPEC_HPP
#define NANA_DETAIL_PLATFORM_SPEC_HPP #define NANA_DETAIL_PLATFORM_SPEC_HPP
#include <nana/deploy.hpp>
#include <nana/gui/basis.hpp> #include <nana/gui/basis.hpp>
#include <nana/paint/image.hpp> #include <nana/paint/image.hpp>
#include <nana/gui/detail/event_code.hpp> #include <nana/gui/detail/event_code.hpp>
#include <windows.h> #include <windows.h>
#include <map>
#include <memory> #include <memory>
#include <functional> #include <functional>
@ -174,6 +172,12 @@ namespace detail
class platform_spec class platform_spec
{ {
platform_spec();
platform_spec(const platform_spec&) = delete;
platform_spec& operator=(const platform_spec&) = delete;
platform_spec(platform_spec&&) = delete;
platform_spec& operator=(platform_spec&&) = delete;
public: public:
typedef drawable_impl_type::font_ptr_t font_ptr_t; typedef drawable_impl_type::font_ptr_t font_ptr_t;
typedef ::nana::event_code event_code; typedef ::nana::event_code event_code;
@ -194,7 +198,7 @@ namespace detail
::nana::paint::image big_icon; ::nana::paint::image big_icon;
}; };
platform_spec(); ~platform_spec();
const font_ptr_t& default_native_font() const; const font_ptr_t& default_native_font() const;
void default_native_font(const font_ptr_t&); void default_native_font(const font_ptr_t&);
@ -207,8 +211,8 @@ namespace detail
void keep_window_icon(native_window_type, const paint::image&sml_icon, const paint::image& big_icon); void keep_window_icon(native_window_type, const paint::image&sml_icon, const paint::image& big_icon);
void release_window_icon(native_window_type); void release_window_icon(native_window_type);
private: private:
font_ptr_t def_font_ptr_; struct implementation;
std::map<native_window_type, window_icons> iconbase_; implementation * const impl_;
}; };
}//end namespace detail }//end namespace detail

View File

@ -1,7 +1,7 @@
/* /*
* The Store for the Storage Of Elements * The Store for the Storage Of Elements
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -16,9 +16,7 @@
#include <nana/gui/element.hpp> #include <nana/gui/element.hpp>
#include <nana/pat/cloneable.hpp> #include <nana/pat/cloneable.hpp>
#include <map>
#include <string> #include <string>
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>
@ -28,27 +26,20 @@ namespace detail
{ {
class element_store class element_store
{ {
typedef ::nana::element::element_interface element_interface; using element_interface = ::nana::element::element_interface;
typedef pat::cloneable< ::nana::element::element_interface> cloneable_element; using cloneable_element = pat::cloneable< ::nana::element::element_interface>;
struct data struct data;
{
cloneable_element object;
::nana::element::element_interface * fast_ptr;
data();
};
struct store
{
std::map<std::string, data> table;
};
public: public:
element_store();
~element_store();
element_interface * const * bground(const std::string&); element_interface * const * bground(const std::string&);
void bground(const std::string&, const pat::cloneable<element_interface>&); void bground(const std::string&, const pat::cloneable<element_interface>&);
void bground(const std::string&, pat::cloneable<element_interface>&&); void bground(const std::string&, pat::cloneable<element_interface>&&);
private: private:
store bground_; struct implementation;
std::unique_ptr<implementation> impl_;
}; };
}//end namespace detail }//end namespace detail
} }

View File

@ -1,7 +1,7 @@
/* /*
* Implementations of Inner Forward Declaration * Implementations of Inner Forward Declaration
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -26,87 +26,32 @@ namespace nana{
{ {
class shortkey_container class shortkey_container
{ {
struct item_type struct item_type;
{
window handle; //Noncopyable
std::vector<unsigned long> keys; shortkey_container(const shortkey_container&) = delete;
}; shortkey_container& operator=(const shortkey_container&) = delete;
shortkey_container& operator=(shortkey_container&&) = delete;
public: public:
void clear() shortkey_container();
{
keybase_.clear();
}
bool make(window wd, unsigned long key) shortkey_container(shortkey_container&&);
{
if (wd == nullptr) return false;
if (key < 0x61) key += (0x61 - 0x41);
for (auto & m : keybase_) ~shortkey_container();
{
if (m.handle == wd)
{
m.keys.push_back(key);
return true;
}
}
item_type m; void clear();
m.handle = wd;
m.keys.push_back(key);
keybase_.push_back(m);
return true; bool make(window wd, unsigned long key);
}
void umake(window wd) void umake(window wd);
{
if (wd == nullptr) return;
for (auto i = keybase_.begin(), end = keybase_.end(); i != end; ++i) std::vector<unsigned long> keys(window wd) const;
{
if (i->handle == wd)
{
keybase_.erase(i);
break;
}
}
}
std::vector<unsigned long> keys(window wd) const window find(unsigned long key) const;
{
std::vector<unsigned long> v;
if (wd)
{
for (auto & m : keybase_)
{
if (m.handle == wd)
{
v = m.keys;
break;
}
}
}
return v;
}
window find(unsigned long key) const
{
if (key < 0x61) key += (0x61 - 0x41);
for (auto & m : keybase_)
{
for (auto n : m.keys)
{
if (key == n)
return m.handle;
}
}
return nullptr;
}
private: private:
std::vector<item_type> keybase_; struct implementation;
implementation * impl_;
}; };
@ -118,57 +63,39 @@ namespace nana{
struct condition_rep struct condition_rep
{ {
bool ignore_tab{ false }; //ignore tab when the focus is changed by TAB key. bool ignore_tab; //ignore tab when the focus is changed by TAB key.
basic_window* pressed{ nullptr }; //The handle to a window which has been pressed by mouse left button. basic_window* pressed; //The handle to a window which has been pressed by mouse left button.
basic_window* pressed_by_space{ nullptr }; //The handle to a window which has been pressed by SPACEBAR key. basic_window* pressed_by_space; //The handle to a window which has been pressed by SPACEBAR key.
basic_window* hovered{ nullptr }; //the latest window that mouse moved basic_window* hovered; //the latest window that mouse moved
}condition; }condition;
root_misc(basic_window * wd, unsigned width, unsigned height) root_misc(root_misc&&);
: window(wd), root_misc(basic_window * wd, unsigned width, unsigned height);
root_graph({ width, height })
{}
};//end struct root_misc };//end struct root_misc
class root_register class root_register
{ {
//Noncopyable
root_register(const root_register&) = delete;
root_register& operator=(const root_register&) = delete;
//Nonmovable
root_register(root_register&&) = delete;
root_register& operator=(root_register&&) = delete;
public: public:
root_misc* insert(native_window_type wd, const root_misc& misc) root_register();
{ ~root_register();
recent_ = wd;
auto ret = table_.insert(std::make_pair(wd, misc));
misc_ptr_ = &(ret.first->second);
return misc_ptr_;
}
root_misc * find(native_window_type wd) root_misc* insert(native_window_type, root_misc&&);
{
if (wd == recent_)
return misc_ptr_;
recent_ = wd; root_misc * find(native_window_type);
auto i = table_.find(wd); void erase(native_window_type);
if (i != table_.end())
misc_ptr_ = &(i->second);
else
misc_ptr_ = nullptr;
return misc_ptr_;
}
void erase(native_window_type wd)
{
table_.erase(wd);
recent_ = wd;
misc_ptr_ = nullptr;
}
private: private:
//Cached struct implementation;
mutable native_window_type recent_{nullptr}; implementation * const impl_;
mutable root_misc * misc_ptr_{nullptr};
std::map<native_window_type, root_misc> table_;
}; };
} }
}//end namespace nana }//end namespace nana

View File

@ -20,18 +20,11 @@
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>
#include <vector>
#include "window_layout.hpp" #include "window_layout.hpp"
#include "event_code.hpp" #include "event_code.hpp"
#include "inner_fwd.hpp" #include "inner_fwd.hpp"
#include <functional> #include <functional>
#if defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp>
#else
#include <mutex>
#endif
namespace nana namespace nana
{ {
class widget; //forward declaration class widget; //forward declaration
@ -51,15 +44,14 @@ namespace detail
class window_manager class window_manager
{ {
class revertible_mutex class revertible_mutex
: public std::recursive_mutex
{ {
struct thr_refcnt revertible_mutex(const revertible_mutex&) = delete;
{ revertible_mutex& operator=(const revertible_mutex&) = delete;
unsigned tid; revertible_mutex(revertible_mutex&&) = delete;
std::size_t refcnt; revertible_mutex& operator=(revertible_mutex&&) = delete;
};
public: public:
revertible_mutex(); revertible_mutex();
~revertible_mutex();
void lock(); void lock();
bool try_lock(); bool try_lock();
@ -68,8 +60,8 @@ namespace detail
void revert(); void revert();
void forward(); void forward();
private: private:
thr_refcnt thr_; struct implementation;
std::vector<thr_refcnt> stack_; implementation * const impl_;
}; };
public: public:
using native_window = native_window_type; using native_window = native_window_type;
@ -90,7 +82,6 @@ namespace detail
bool available(core_window_t*); bool available(core_window_t*);
bool available(core_window_t *, core_window_t*); bool available(core_window_t *, core_window_t*);
bool available(native_window_type);
core_window_t* create_root(core_window_t*, bool nested, rectangle, const appearance&, widget*); core_window_t* create_root(core_window_t*, bool nested, rectangle, const appearance&, widget*);
core_window_t* create_widget(core_window_t*, const rectangle&, bool is_lite, widget*); core_window_t* create_widget(core_window_t*, const rectangle&, bool is_lite, widget*);
@ -157,7 +148,7 @@ namespace detail
bool calc_window_point(core_window_t*, nana::point&); bool calc_window_point(core_window_t*, nana::point&);
root_misc* root_runtime(native_window_type) const; root_misc* root_runtime(native_window) const;
bool register_shortkey(core_window_t*, unsigned long key); bool register_shortkey(core_window_t*, unsigned long key);
void unregister_shortkey(core_window_t*, bool with_children); void unregister_shortkey(core_window_t*, bool with_children);

View File

@ -16,7 +16,6 @@
#include <nana/paint/graphics.hpp> #include <nana/paint/graphics.hpp>
#include <nana/pat/cloneable.hpp> #include <nana/pat/cloneable.hpp>
#include <vector> #include <vector>
#include <map>
namespace nana namespace nana
{ {
@ -338,13 +337,8 @@ namespace nana
struct draw_image; struct draw_image;
struct draw_graph; struct draw_graph;
draw_method * method_; struct implementation;
bool vertical_; std::unique_ptr<implementation> impl_;
nana::rectangle valid_area_;
std::vector<element_state> states_;
std::map<element_state, element_state> join_;
bool stretch_all_;
unsigned left_, top_, right_, bottom_;
}; //end class bground }; //end class bground
}//end namespace element }//end namespace element
}//end namespace nana }//end namespace nana

View File

@ -17,7 +17,6 @@
#define NANA_GUI_PLACE_HPP #define NANA_GUI_PLACE_HPP
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>
#include <nana/gui/basis.hpp> #include <nana/gui/basis.hpp>
#include <utility>
#include <memory> #include <memory>
#include <functional> #include <functional>

View File

@ -347,7 +347,8 @@ namespace API
* When you are finished with the caret, be sure to reset the pointer. * When you are finished with the caret, be sure to reset the pointer.
* *
* @param window_handle A handle to a window whose caret is to be retrieved * @param window_handle A handle to a window whose caret is to be retrieved
* @return a pointer to the caret proxy. nullptr if the window doesn't have a caret. * @return a pointer to the caret proxy.
* @except throws std::runtime if the window doesn't have a caret when disable_throw is false
*/ */
::std::unique_ptr<caret_interface> open_caret(window window_handle, bool disable_throw = false); ::std::unique_ptr<caret_interface> open_caret(window window_handle, bool disable_throw = false);

View File

@ -1,7 +1,7 @@
/** /**
* A Inline Widget Interface Definition * A Inline Widget Interface Definition
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -35,6 +35,9 @@ namespace nana
/// Returns the host widget of the indicator /// Returns the host widget of the indicator
virtual ::nana::widget& host() const = 0; virtual ::nana::widget& host() const = 0;
/// Returns the position of column
virtual std::size_t column() const = 0;
/// Modifies the value of a item specified by pos /// Modifies the value of a item specified by pos
virtual void modify(index_type pos, const value_type&) const = 0; virtual void modify(index_type pos, const value_type&) const = 0;
@ -45,7 +48,7 @@ namespace nana
virtual void hovered(index_type) = 0; virtual void hovered(index_type) = 0;
}; };
template<typename Index, typename Value> template<typename Index, typename Status, typename Value>
class inline_widget_notifier_interface class inline_widget_notifier_interface
{ {
public: public:
@ -55,6 +58,9 @@ namespace nana
/// A type to the value of the item /// A type to the value of the item
using value_type = Value; using value_type = Value;
/// A type to the status
using status_type = Status;
/// A typedef name of a inline widget indicator /// A typedef name of a inline widget indicator
using inline_indicator = inline_widget_indicator<index_type, value_type>; using inline_indicator = inline_widget_indicator<index_type, value_type>;
@ -70,6 +76,9 @@ namespace nana
/// A message to activate the inline widget to attach a specified item /// A message to activate the inline widget to attach a specified item
virtual void activate(inline_indicator&, index_type) = 0; virtual void activate(inline_indicator&, index_type) = 0;
/// A message to change the status
virtual void notify_status(status_type, bool) = 0;
/// A message to resize the inline widget /// A message to resize the inline widget
virtual void resize(const size&) = 0; virtual void resize(const size&) = 0;

View File

@ -676,8 +676,14 @@ namespace nana
using index_pairs = ::std::vector<index_pair>; using index_pairs = ::std::vector<index_pair>;
using inline_notifier_interface = detail::inline_widget_notifier_interface<index_pair, ::std::string>; enum class inline_widget_status{
checked,
checking,
selected,
selecting
};
using inline_notifier_interface = detail::inline_widget_notifier_interface<index_pair, inline_widget_status, ::std::string>;
// struct essence // struct essence
//@brief: this struct gives many data for listbox, //@brief: this struct gives many data for listbox,
@ -720,7 +726,7 @@ namespace nana
class iresolver class iresolver
{ {
public: public:
iresolver(const std::vector<cell>&); iresolver(std::vector<cell>);
iresolver& operator>>(bool&); iresolver& operator>>(bool&);
iresolver& operator>>(short&); iresolver& operator>>(short&);
@ -740,7 +746,7 @@ namespace nana
iresolver& operator>>(cell&); iresolver& operator>>(cell&);
iresolver& operator>>(std::nullptr_t); iresolver& operator>>(std::nullptr_t);
private: private:
const std::vector<cell>& cells_; std::vector<cell> cells_;
std::size_t pos_{0}; std::size_t pos_{0};
}; };
@ -918,7 +924,7 @@ namespace nana
//Undocumented method //Undocumented method
essence * _m_ess() const; essence * _m_ess() const;
private: private:
std::vector<cell> & _m_cells() const; std::vector<cell> _m_cells() const;
nana::any * _m_value(bool alloc_if_empty); nana::any * _m_value(bool alloc_if_empty);
const nana::any * _m_value() const; const nana::any * _m_value() const;
private: private:

View File

@ -17,109 +17,26 @@
#include "textbase.hpp" #include "textbase.hpp"
#include "text_editor_part.hpp" #include "text_editor_part.hpp"
#include <nana/gui/widgets/scroll.hpp>
#include <nana/unicode_bidi.hpp> #include <nana/unicode_bidi.hpp>
//#include <nana/paint/graphics.hpp>
#include <nana/gui/detail/general_events.hpp>
#include <functional>
namespace nana
{
namespace paint
{
// Forward declaration
class graphics;
}
}
namespace nana{ namespace widgets namespace nana{ namespace widgets
{ {
namespace skeletons namespace skeletons
{ {
template<typename EnumCommand>
class undoable_command_interface
{
public:
virtual ~undoable_command_interface() = default;
virtual EnumCommand get() const = 0;
virtual bool merge(const undoable_command_interface&) = 0;
virtual void execute(bool redo) = 0;
};
template<typename EnumCommand>
class undoable
{
public:
using command = EnumCommand;
using container = std::deque < std::unique_ptr<undoable_command_interface<command>> >;
void clear()
{
commands_.clear();
pos_ = 0;
}
void max_steps(std::size_t maxs)
{
max_steps_ = maxs;
if (maxs && (commands_.size() >= maxs))
commands_.erase(commands_.begin(), commands_.begin() + (commands_.size() - maxs + 1));
}
std::size_t max_steps() const
{
return max_steps_;
}
void enable(bool enb)
{
enabled_ = enb;
if (!enb)
clear();
}
bool enabled() const
{
return enabled_;
}
void push(std::unique_ptr<undoable_command_interface<command>> && ptr)
{
if (!ptr || !enabled_)
return;
if (pos_ < commands_.size())
commands_.erase(commands_.begin() + pos_, commands_.end());
else if (max_steps_ && (commands_.size() >= max_steps_))
commands_.erase(commands_.begin(), commands_.begin() + (commands_.size() - max_steps_ + 1));
pos_ = commands_.size();
if (!commands_.empty())
{
if (commands_.back().get()->merge(*ptr))
return;
}
commands_.emplace_back(std::move(ptr));
++pos_;
}
std::size_t count(bool is_undo) const
{
return (is_undo ? pos_ : commands_.size() - pos_);
}
void undo()
{
if (pos_ > 0)
{
--pos_;
commands_[pos_].get()->execute(false);
}
}
void redo()
{
if (pos_ != commands_.size())
commands_[pos_++].get()->execute(true);
}
private:
container commands_;
bool enabled_{ true };
std::size_t max_steps_{ 30 };
std::size_t pos_{ 0 };
};
class text_editor class text_editor
{ {
struct attributes; struct attributes;
@ -136,9 +53,14 @@ namespace nana{ namespace widgets
class undo_input_text; class undo_input_text;
class undo_move_text; class undo_move_text;
struct keywords;
class keyword_parser; class keyword_parser;
class helper_pencil; class helper_pencil;
text_editor(const text_editor&) = delete;
text_editor& operator=(const text_editor&) = delete;
text_editor(text_editor&&) = delete;
text_editor& operator=(text_editor&&) = delete;
public: public:
using char_type = wchar_t; using char_type = wchar_t;
using size_type = textbase<char_type>::size_type; using size_type = textbase<char_type>::size_type;
@ -148,9 +70,10 @@ namespace nana{ namespace widgets
using graph_reference = ::nana::paint::graphics&; using graph_reference = ::nana::paint::graphics&;
struct ext_renderer_tag struct renderers
{ {
std::function<void(graph_reference, const nana::rectangle& text_area, const ::nana::color&)> background; std::function<void(graph_reference, const nana::rectangle& text_area, const ::nana::color&)> background; ///< a customized background renderer
std::function<void(graph_reference, const ::nana::color&)> border; ///< a customized border renderer
}; };
enum class accepts enum class accepts
@ -178,11 +101,10 @@ namespace nana{ namespace widgets
/// Determine whether the text_editor is line wrapped. /// Determine whether the text_editor is line wrapped.
bool line_wrapped() const; bool line_wrapped() const;
/// Set the text_editor whether it is line wrapped, it returns false if the state is not changed. /// Set the text_editor whether it is line wrapped, it returns false if the state is not changed.
bool line_wrapped(bool); bool line_wrapped(bool);
void border_renderer(std::function<void(graph_reference, const ::nana::color& bgcolor)>);
bool load(const char*); bool load(const char*);
/// Sets the text area. /// Sets the text area.
@ -196,7 +118,13 @@ namespace nana{ namespace widgets
const attributes & attr() const; const attributes & attr() const;
bool multi_lines(bool); bool multi_lines(bool);
void editable(bool);
/// Enables/disables the editability of text_editor
/**
* @param enable Indicates whether to enable or disable the editability
* @param enable_cart Indicates whether to show or hide the caret when the text_editor is not editable. It is ignored if enable is false.
*/
void editable(bool enable, bool enable_caret);
void enable_background(bool); void enable_background(bool);
void enable_background_counterpart(bool); void enable_background_counterpart(bool);
@ -205,7 +133,7 @@ namespace nana{ namespace widgets
void undo_max_steps(std::size_t); void undo_max_steps(std::size_t);
std::size_t undo_max_steps() const; std::size_t undo_max_steps() const;
ext_renderer_tag& ext_renderer() const; renderers& customized_renderers();
unsigned line_height() const; unsigned line_height() const;
unsigned screen_lines() const; unsigned screen_lines() const;
@ -215,7 +143,11 @@ namespace nana{ namespace widgets
std::wstring text() const; std::wstring text() const;
/// Sets caret position through text coordinate. /// Sets caret position through text coordinate.
void move_caret(const upoint&); /**
* @param pos the text position
* @param reset indicates whether to reset the text position by the pos. If this parameter is true, the text position is set by pos. If the parameter is false, it only moves the UI caret to the specified position.
*/
bool move_caret(const upoint& pos, bool reset = false);
void move_caret_end(); void move_caret_end();
void reset_caret_pixels() const; void reset_caret_pixels() const;
void reset_caret(); void reset_caret();
@ -223,6 +155,8 @@ namespace nana{ namespace widgets
bool selected() const; bool selected() const;
bool select(bool); bool select(bool);
bool get_select_points(nana::upoint&, nana::upoint&) const;
/// Sets the end position of a selected string. /// Sets the end position of a selected string.
void set_end_caret(); void set_end_caret();
@ -254,6 +188,7 @@ namespace nana{ namespace widgets
void del(); void del();
void backspace(bool record_undo = true); void backspace(bool record_undo = true);
void undo(bool reverse); void undo(bool reverse);
void set_undo_queue_length(std::size_t len);
void move_ns(bool to_north); //Moves up and down void move_ns(bool to_north); //Moves up and down
void move_left(); void move_left();
void move_right(); void move_right();
@ -267,8 +202,8 @@ namespace nana{ namespace widgets
bool mouse_move(bool left_button, const point& screen_pos); bool mouse_move(bool left_button, const point& screen_pos);
bool mouse_pressed(const arg_mouse& arg); bool mouse_pressed(const arg_mouse& arg);
skeletons::textbase<wchar_t>& textbase(); skeletons::textbase<char_type>& textbase();
const skeletons::textbase<wchar_t>& textbase() const; const skeletons::textbase<char_type>& textbase() const;
private: private:
void _m_pre_calc_lines(std::size_t line_off, std::size_t lines); void _m_pre_calc_lines(std::size_t line_off, std::size_t lines);
@ -276,7 +211,9 @@ namespace nana{ namespace widgets
::nana::color _m_bgcolor() const; ::nana::color _m_bgcolor() const;
bool _m_scroll_text(bool vertical); bool _m_scroll_text(bool vertical);
void _m_scrollbar(); void _m_scrollbar();
::nana::size _m_text_area() const;
::nana::rectangle _m_text_area() const;
void _m_get_scrollbar_size(); void _m_get_scrollbar_size();
void _m_reset(); void _m_reset();
::nana::upoint _m_put(::std::wstring); ::nana::upoint _m_put(::std::wstring);
@ -295,9 +232,6 @@ namespace nana{ namespace widgets
int _m_text_top_base() const; int _m_text_top_base() const;
/// Returns the right/bottom point of text area.
int _m_end_pos(bool right) const;
void _m_draw_parse_string(const keyword_parser&, bool rtl, ::nana::point pos, const ::nana::color& fgcolor, const wchar_t*, std::size_t len) const; void _m_draw_parse_string(const keyword_parser&, bool rtl, ::nana::point pos, const ::nana::color& fgcolor, const wchar_t*, std::size_t len) const;
//_m_draw_string //_m_draw_string
//@brief: Draw a line of string //@brief: Draw a line of string
@ -306,54 +240,35 @@ namespace nana{ namespace widgets
//@brief: redraw whole line specified by caret pos. //@brief: redraw whole line specified by caret pos.
//@return: true if caret overs the border //@return: true if caret overs the border
bool _m_update_caret_line(std::size_t secondary_before); bool _m_update_caret_line(std::size_t secondary_before);
bool _m_get_sort_select_points(nana::upoint&, nana::upoint&) const;
void _m_offset_y(int y); void _m_offset_y(int y);
unsigned _m_char_by_pixels(const unicode_bidi::entity&, unsigned pos); unsigned _m_char_by_pixels(const unicode_bidi::entity&, unsigned pos);
unsigned _m_pixels_by_char(const ::std::wstring&, ::std::size_t pos) const; unsigned _m_pixels_by_char(const ::std::wstring&, ::std::size_t pos) const;
void _handle_move_key(const arg_keyboard& arg); void _m_handle_move_key(const arg_keyboard& arg);
void _m_draw_border();
private: private:
std::unique_ptr<editor_behavior_interface> behavior_; struct implementation;
undoable<command> undo_; implementation * const impl_;
nana::window window_; nana::window window_;
std::unique_ptr<caret_interface> caret_;
graph_reference graph_; graph_reference graph_;
const text_editor_scheme* scheme_; const text_editor_scheme* scheme_;
event_interface * event_handler_{ nullptr }; event_interface * event_handler_{ nullptr };
std::unique_ptr<keywords> keywords_;
skeletons::textbase<wchar_t> textbase_;
wchar_t mask_char_{0}; wchar_t mask_char_{0};
mutable ext_renderer_tag ext_renderer_;
std::vector<upoint> text_position_; //position of text from last rendering.
struct indent_rep
{
bool enabled{ false };
std::function<std::string()> generator;
}indent_;
struct attributes struct attributes
{ {
accepts acceptive{ accepts::no_restrict };
std::function<bool(char_type)> pred_acceptive;
::std::string tip_string; ::std::string tip_string;
bool line_wrapped{false}; bool line_wrapped{false};
bool multi_lines{true}; bool multi_lines{true};
bool editable{true}; bool editable{true};
bool enable_caret{ true }; ///< Indicates whether to show or hide caret when text_editor is not editable
bool enable_background{true}; bool enable_background{true};
bool enable_counterpart{false};
nana::paint::graphics counterpart; //this is used to keep the background that painted by external part.
std::unique_ptr<nana::scroll<true>> vscroll;
std::unique_ptr<nana::scroll<false>> hscroll;
}attributes_; }attributes_;
struct text_area_type struct text_area_type
@ -365,7 +280,6 @@ namespace nana{ namespace widgets
unsigned scroll_pixels; unsigned scroll_pixels;
unsigned vscroll; unsigned vscroll;
unsigned hscroll; unsigned hscroll;
std::function<void(nana::paint::graphics&, const ::nana::color&)> border_renderer;
}text_area_; }text_area_;
struct selection struct selection

View File

@ -1,7 +1,7 @@
/** /**
* A Slider Implementation * A Slider Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -134,7 +134,7 @@ namespace nana
}//end namespace drawerbase }//end namespace drawerbase
/// A slider widget wich the user can drag for tracking \todo add scheme ? /// A slider widget wich the user can drag for tracking
class slider class slider
: public widget_object<category::widget_tag, drawerbase::slider::trigger, drawerbase::slider::slider_events, drawerbase::slider::scheme_impl> : public widget_object<category::widget_tag, drawerbase::slider::trigger, drawerbase::slider::slider_events, drawerbase::slider::scheme_impl>
{ {

View File

@ -184,6 +184,9 @@ namespace nana
bool editable() const; bool editable() const;
textbox& editable(bool); textbox& editable(bool);
/// Enables the caret if the textbox currently is not editable
textbox& enable_caret();
void set_accept(std::function<bool(wchar_t)>); void set_accept(std::function<bool(wchar_t)>);
textbox& tip_string(::std::string); textbox& tip_string(::std::string);
@ -197,6 +200,12 @@ namespace nana
/// Selects/unselects all text. /// Selects/unselects all text.
void select(bool); void select(bool);
/// Returns the bounds of a text selection
/**
* @return no selection if pair.first == pair.second.
*/
std::pair<upoint, upoint> selection() const;
void copy() const; ///< Copies the selected text into shared memory, such as clipboard under Windows. void copy() const; ///< Copies the selected text into shared memory, such as clipboard under Windows.
void paste(); ///< Pastes the text from shared memory. void paste(); ///< Pastes the text from shared memory.
void del(); void del();
@ -228,6 +237,12 @@ namespace nana
/// E.g. Whether caret moves to left of selected content or moves to left of last position when left arrow key is pressed. /// E.g. Whether caret moves to left of selected content or moves to left of last position when left arrow key is pressed.
/// @param move_to_end determines whether to move caret to left of selected_content or to left of last position. /// @param move_to_end determines whether to move caret to left of selected_content or to left of last position.
void select_behavior(bool move_to_end); void select_behavior(bool move_to_end);
/// Sets the undo/redo queue length
/**
* @param len The length of the queue. If this parameter is zero, the undo/redo is disabled.
*/
void set_undo_queue_length(std::size_t len);
protected: protected:
//Overrides widget's virtual functions //Overrides widget's virtual functions
native_string_type _m_caption() const throw() override; native_string_type _m_caption() const throw() override;

View File

@ -28,14 +28,25 @@ namespace nana
/// Abstract class for defining the capacity interface. /// Abstract class for defining the capacity interface.
class widget class widget
: nana::noncopyable, nana::nonmovable
{ {
friend class detail::widget_notifier_interface; friend class detail::widget_notifier_interface;
class inner_widget_notifier; class inner_widget_notifier;
typedef void(*dummy_bool_type)(widget* (*)(const widget&)); typedef void(*dummy_bool_type)(widget* (*)(const widget&));
//Noncopyable
widget(const widget&) = delete;
widget& operator=(const widget&) = delete;
//Nonmovable
widget(widget&&) = delete;
widget& operator=(widget&&) = delete;
public: public:
using native_string_type = detail::native_string_type; using native_string_type = detail::native_string_type;
widget() = default;
virtual ~widget() = default; virtual ~widget() = default;
virtual window handle() const = 0; ///< Returns the handle of window, returns 0 if window is not created. virtual window handle() const = 0; ///< Returns the handle of window, returns 0 if window is not created.
bool empty() const; ///< Determines whether the manipulator is handling a window. bool empty() const; ///< Determines whether the manipulator is handling a window.
@ -147,11 +158,9 @@ namespace nana
: public widget : public widget
{ {
public: public:
~widget_base();
window handle() const override; window handle() const override;
private: protected:
void _m_notify_destroy() override final; void _m_notify_destroy() override;
protected: protected:
window handle_{ nullptr }; window handle_{ nullptr };
}; };
@ -172,6 +181,11 @@ namespace nana
scheme_{ API::dev::make_scheme<Scheme>() } scheme_{ API::dev::make_scheme<Scheme>() }
{} {}
~widget_object()
{
API::close_window(handle());
}
event_type& events() const event_type& events() const
{ {
return *events_; return *events_;
@ -228,6 +242,13 @@ namespace nana
{ {
return *events_; return *events_;
} }
void _m_notify_destroy() override final
{
widget_base::_m_notify_destroy();
events_ = std::make_shared<Events>();
API::dev::set_events(handle_, events_);
}
private: private:
DrawerTrigger trigger_; DrawerTrigger trigger_;
std::shared_ptr<Events> events_; std::shared_ptr<Events> events_;
@ -248,6 +269,11 @@ namespace nana
: events_{ std::make_shared<Events>() }, scheme_{ API::dev::make_scheme<scheme_type>() } : events_{ std::make_shared<Events>() }, scheme_{ API::dev::make_scheme<scheme_type>() }
{} {}
~widget_object()
{
API::close_window(handle());
}
event_type& events() const event_type& events() const
{ {
return *events_; return *events_;
@ -281,6 +307,13 @@ namespace nana
{ {
return *events_; return *events_;
} }
void _m_notify_destroy() override final
{
widget_base::_m_notify_destroy();
events_ = std::make_shared<Events>();
API::dev::set_events(handle_, events_);
}
private: private:
std::shared_ptr<Events> events_; std::shared_ptr<Events> events_;
std::unique_ptr<scheme_type> scheme_; std::unique_ptr<scheme_type> scheme_;
@ -298,15 +331,8 @@ namespace nana
using event_type = Events; using event_type = Events;
widget_object() widget_object()
: widget_object(nullptr, false, API::make_center(300, 150), appearance(), this)
{ {
handle_ = API::dev::create_window(nullptr, false, API::make_center(300, 150), appearance(), this);
_m_bind_and_attach();
}
widget_object(const rectangle& r, const appearance& apr = {})
{
handle_ = API::dev::create_window(nullptr, false, r, apr, this);
_m_bind_and_attach();
} }
widget_object(window owner, bool nested, const rectangle& r = {}, const appearance& apr = {}) widget_object(window owner, bool nested, const rectangle& r = {}, const appearance& apr = {})
@ -315,6 +341,11 @@ namespace nana
_m_bind_and_attach(); _m_bind_and_attach();
} }
~widget_object()
{
API::close_window(handle());
}
event_type& events() const event_type& events() const
{ {
return *events_; return *events_;
@ -415,6 +446,13 @@ namespace nana
{ {
return *events_; return *events_;
} }
void _m_notify_destroy() override final
{
widget_base::_m_notify_destroy();
events_ = std::make_shared<Events>();
API::dev::set_events(handle_, events_);
}
private: private:
DrawerTrigger trigger_; DrawerTrigger trigger_;
std::shared_ptr<Events> events_; std::shared_ptr<Events> events_;
@ -440,6 +478,11 @@ namespace nana
: events_{ std::make_shared<Events>() }, scheme_{ API::dev::make_scheme<scheme_type>() } : events_{ std::make_shared<Events>() }, scheme_{ API::dev::make_scheme<scheme_type>() }
{} {}
~widget_object()
{
API::close_window(handle());
}
event_type& events() const event_type& events() const
{ {
return *events_; return *events_;

View File

@ -12,7 +12,6 @@
#ifndef NANA_INTERNATIONALIZATION_HPP #ifndef NANA_INTERNATIONALIZATION_HPP
#define NANA_INTERNATIONALIZATION_HPP #define NANA_INTERNATIONALIZATION_HPP
#include "basic_types.hpp"
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <functional> #include <functional>
@ -186,9 +185,7 @@ namespace nana
void _m_add_args(const std::string&); void _m_add_args(const std::string&);
void _m_add_args(std::string&&); void _m_add_args(std::string&&);
void _m_add_args(std::wstring&);
void _m_add_args(const std::wstring&); void _m_add_args(const std::wstring&);
void _m_add_args(std::wstring&&);
private: private:
std::string msgid_; std::string msgid_;
std::vector<std::unique_ptr<eval_arg>> args_; std::vector<std::unique_ptr<eval_arg>> args_;

View File

@ -1,7 +1,7 @@
/* /*
* Paint Graphics Implementation * Paint Graphics Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -17,7 +17,6 @@
#include "../basic_types.hpp" #include "../basic_types.hpp"
#include "../gui/basis.hpp" #include "../gui/basis.hpp"
#include "pixel_buffer.hpp"
namespace nana namespace nana
{ {
@ -72,12 +71,16 @@ namespace nana
class graphics class graphics
{ {
public: public:
typedef ::nana::native_window_type native_window_type;
graphics(); graphics();
graphics(const ::nana::size&); ///< size in pixel graphics(const ::nana::size&); ///< size in pixel
graphics(const graphics&); ///< the resource is not copyed, the two graphics objects refer to the *SAME* resource graphics(const graphics&); ///< the resource is not copyed, the two graphics objects refer to the *SAME* resource
graphics& operator=(const graphics&); graphics& operator=(const graphics&);
graphics(graphics&&);
graphics& operator=(graphics&&);
~graphics();
bool changed() const; ///< Returns true if the graphics object is operated bool changed() const; ///< Returns true if the graphics object is operated
bool empty() const; ///< Returns true if the graphics object does not refer to any resource. bool empty() const; ///< Returns true if the graphics object does not refer to any resource.
operator const void*() const; operator const void*() const;
@ -129,10 +132,10 @@ namespace nana
void flush(); void flush();
unsigned width() const; unsigned width() const; ///< Returns the width of the off-screen buffer.
unsigned height() const; ///< Returns the height of the off-screen buffer. unsigned height() const; ///< Returns the height of the off-screen buffer.
::nana::size size() const; ::nana::size size() const;
void setsta(); ///< Clears the status if the graphics object had been changed void setsta(); ///< Clears the status if the graphics object had been changed
void set_changed(); void set_changed();
void release(); void release();
@ -172,12 +175,18 @@ namespace nana
void gradual_rectangle(const ::nana::rectangle&, const color& from, const color& to, bool vertical); void gradual_rectangle(const ::nana::rectangle&, const color& from, const color& to, bool vertical);
void round_rectangle(const ::nana::rectangle&, unsigned radius_x, unsigned radius_y, const color&, bool solid, const color& color_if_solid); void round_rectangle(const ::nana::rectangle&, unsigned radius_x, unsigned radius_y, const color&, bool solid, const color& color_if_solid);
private: private:
std::shared_ptr< ::nana::detail::drawable_impl_type> dwptr_; struct implementation;
font font_shadow_; std::unique_ptr<implementation> impl_;
drawable_type handle_; };
::nana::size size_;
pixel_buffer pxbuf_; class draw
bool changed_; {
public:
draw(graphics& graph);
void corner(const rectangle& r, unsigned pixels);
private:
graphics& graph_;
}; };
}//end namespace paint }//end namespace paint
} //end namespace nana } //end namespace nana

View File

@ -1,7 +1,7 @@
/* /*
* A Generic Abstract Factory Pattern Implementation * A Generic Abstract Factory Pattern Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -15,6 +15,8 @@
#define NANA_PAT_ABSFACTORY_HPP #define NANA_PAT_ABSFACTORY_HPP
#include "cloneable.hpp" #include "cloneable.hpp"
#include <memory> #include <memory>
#include <tuple>
#include <type_traits>
namespace nana namespace nana
{ {
@ -43,21 +45,68 @@ namespace nana
namespace detail namespace detail
{ {
template<typename T, typename Interface> template<typename Useless, std::size_t ...Index>
struct pack{
using type = pack;
};
template<bool Negative, bool Zero, class IntConst, class Pack>
struct make_pack_helper
{ // explodes gracefully below 0
static_assert(!Negative,
"make_integer_sequence<T, N> requires N to be non-negative.");
};
template<typename Useless, std::size_t ... Vals>
struct make_pack_helper<false, true,
std::integral_constant<std::size_t, 0>,
pack<Useless, Vals...> >
: pack<Useless, Vals...>
{ // ends recursion at 0
};
template<typename Useless, std::size_t X, std::size_t... Vals>
struct make_pack_helper<false, false,
std::integral_constant<std::size_t, X>,
pack<Useless, Vals...> >
: make_pack_helper<false, X == 1,
std::integral_constant<std::size_t, X - 1>,
pack<Useless, X - 1, Vals...> >
{ // counts down to 0
};
template<std::size_t Size>
using make_pack = typename make_pack_helper<Size < 0, Size == 0, std::integral_constant<std::size_t, Size>, pack<int> >::type;
template<typename T, typename Interface, typename ...Args>
class abs_factory class abs_factory
: public abstract_factory<Interface> : public abstract_factory<Interface>
{ {
std::unique_ptr<Interface> create() override std::unique_ptr<Interface> create() override
{ {
return std::unique_ptr<Interface>{ new T }; constexpr auto Size = std::tuple_size<decltype(args_)>::value;
return std::unique_ptr<Interface>{ _m_new(make_pack<Size>{}) };
} }
template<std::size_t ... Index>
Interface* _m_new(const pack<int, Index...> &)
{
return new T(std::get<Index>(args_)...);
}
public:
abs_factory(const Args&... args)
: args_(args...)
{
}
private:
std::tuple<Args...> args_;
}; };
}//end namespace detail }//end namespace detail
template<typename Type> template<typename Type, typename ...Args>
pat::cloneable<abstract_factory<typename Type::factory_interface>> make_factory() pat::cloneable<abstract_factory<typename Type::factory_interface>> make_factory(Args &&... args)
{ {
return detail::abs_factory<Type, typename Type::factory_interface>(); return detail::abs_factory<Type, typename Type::factory_interface, typename std::decay<Args>::type...>(std::forward<Args>(args)...);
} }
}//end namespace pat }//end namespace pat
}//end namespace nana }//end namespace nana

View File

@ -1,7 +1,7 @@
/* /*
* A Generic Cloneable Pattern Implementation * A Generic Cloneable Pattern Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -106,8 +106,8 @@ namespace nana{ namespace pat{
template<typename T, typename member_enabled<T>::type* = nullptr> template<typename T, typename member_enabled<T>::type* = nullptr>
cloneable(T&& t) cloneable(T&& t)
: cwrapper_(new detail::cloneable_wrapper<typename std::remove_cv<typename std::remove_reference<T>::type>::type>(std::forward<T>(t)), detail::cloneable_interface_deleter()), : cwrapper_(new detail::cloneable_wrapper<typename std::decay<T>::type>(std::forward<T>(t)), detail::cloneable_interface_deleter()),
fast_ptr_(reinterpret_cast<typename std::remove_cv<typename std::remove_reference<T>::type>::type*>(cwrapper_->get())) fast_ptr_(reinterpret_cast<typename std::decay<T>::type*>(cwrapper_->get()))
{} {}
cloneable(const cloneable& r) cloneable(const cloneable& r)

View File

@ -184,7 +184,7 @@ namespace nana{namespace audio
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
std::lock_guard<decltype(queue_lock_)> lock(queue_lock_); std::lock_guard<decltype(queue_lock_)> lock(queue_lock_);
done_queue_.push_back(m); done_queue_.emplace_back(m);
if(m->dwFlags & WHDR_PREPARED) if(m->dwFlags & WHDR_PREPARED)
wave_native_if.out_unprepare(handle_, m, sizeof(WAVEHDR)); wave_native_if.out_unprepare(handle_, m, sizeof(WAVEHDR));

View File

@ -30,7 +30,7 @@ namespace nana{ namespace audio
m->bufsize = ck.nAvgBytesPerSec; m->bufsize = ck.nAvgBytesPerSec;
m->buf = rawbuf + sizeof(meta); m->buf = rawbuf + sizeof(meta);
#endif #endif
prepared_.push_back(m); prepared_.emplace_back(m);
} }
thr_ = std::move(std::thread([this](){this->_m_prepare_routine();})); thr_ = std::move(std::thread([this](){this->_m_prepare_routine();}));
@ -79,7 +79,7 @@ namespace nana{ namespace audio
{ {
std::lock_guard<decltype(token_prepared_)> lock(token_prepared_); std::lock_guard<decltype(token_prepared_)> lock(token_prepared_);
bool if_signal = prepared_.empty(); bool if_signal = prepared_.empty();
prepared_.push_back(m); prepared_.emplace_back(m);
if(if_signal) if(if_signal)
cond_prepared_.notify_one(); cond_prepared_.notify_one();
} }
@ -148,7 +148,7 @@ namespace nana{ namespace audio
m->bufsize = buffered; m->bufsize = buffered;
#endif #endif
std::lock_guard<decltype(token_buffer_)> lock(token_buffer_); std::lock_guard<decltype(token_buffer_)> lock(token_buffer_);
buffer_.push_back(m); buffer_.emplace_back(m);
if(wait_for_buffer_) if(wait_for_buffer_)
{ {
cond_buffer_.notify_one(); cond_buffer_.notify_one();

View File

@ -29,6 +29,7 @@
#include <nana/gui/detail/basic_window.hpp> #include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/window_manager.hpp> #include <nana/gui/detail/window_manager.hpp>
#include <nana/system/platform.hpp> #include <nana/system/platform.hpp>
#include <nana/paint/pixel_buffer.hpp>
#include <errno.h> #include <errno.h>
#include <sstream> #include <sstream>

View File

@ -16,10 +16,10 @@
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
#include <shellapi.h>
#include <stdexcept> #include <stdexcept>
#include <map>
#include <shellapi.h>
/////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////
@ -352,7 +352,14 @@ namespace detail
} }
} }
struct platform_spec::implementation
{
font_ptr_t def_font_ptr;
std::map<native_window_type, window_icons> iconbase;
};
platform_spec::platform_spec() platform_spec::platform_spec()
: impl_{ new implementation}
{ {
//Create default font object. //Create default font object.
NONCLIENTMETRICS metrics = {}; NONCLIENTMETRICS metrics = {};
@ -370,17 +377,22 @@ namespace detail
#endif #endif
#endif #endif
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof metrics, &metrics, 0); ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof metrics, &metrics, 0);
def_font_ptr_ = make_native_font(to_utf8(metrics.lfMessageFont.lfFaceName).c_str(), font_size_to_height(9), 400, false, false, false); impl_->def_font_ptr = make_native_font(to_utf8(metrics.lfMessageFont.lfFaceName).c_str(), font_size_to_height(9), 400, false, false, false);
}
platform_spec::~platform_spec()
{
delete impl_;
} }
const platform_spec::font_ptr_t& platform_spec::default_native_font() const const platform_spec::font_ptr_t& platform_spec::default_native_font() const
{ {
return def_font_ptr_; return impl_->def_font_ptr;
} }
void platform_spec::default_native_font(const font_ptr_t& fp) void platform_spec::default_native_font(const font_ptr_t& fp)
{ {
def_font_ptr_ = fp; impl_->def_font_ptr = fp;
} }
unsigned platform_spec::font_size_to_height(unsigned size) const unsigned platform_spec::font_size_to_height(unsigned size) const
@ -409,7 +421,7 @@ namespace detail
if (name && *name) if (name && *name)
std::wcscpy(logfont.lfFaceName, to_wstring(name).c_str()); std::wcscpy(logfont.lfFaceName, to_wstring(name).c_str());
else else
std::wcscpy(logfont.lfFaceName, def_font_ptr_->name.c_str()); std::wcscpy(logfont.lfFaceName, impl_->def_font_ptr->name.c_str());
logfont.lfCharSet = DEFAULT_CHARSET; logfont.lfCharSet = DEFAULT_CHARSET;
HDC hdc = ::GetDC(0); HDC hdc = ::GetDC(0);
@ -448,14 +460,14 @@ namespace detail
void platform_spec::keep_window_icon(native_window_type wd, const paint::image& sml_icon, const paint::image& big_icon) void platform_spec::keep_window_icon(native_window_type wd, const paint::image& sml_icon, const paint::image& big_icon)
{ {
auto & icons = iconbase_[wd]; auto & icons = impl_->iconbase[wd];
icons.sml_icon = sml_icon; icons.sml_icon = sml_icon;
icons.big_icon = big_icon; icons.big_icon = big_icon;
} }
void platform_spec::release_window_icon(native_window_type wd) void platform_spec::release_window_icon(native_window_type wd)
{ {
iconbase_.erase(wd); impl_->iconbase.erase(wd);
} }
}//end namespace detail }//end namespace detail
}//end namespace nana }//end namespace nana

View File

@ -402,7 +402,7 @@ namespace nana
root = agrparent->root; root = agrparent->root;
root_graph = agrparent->root_graph; root_graph = agrparent->root_graph;
index = static_cast<unsigned>(agrparent->children.size()); index = static_cast<unsigned>(agrparent->children.size());
agrparent->children.push_back(this); agrparent->children.emplace_back(this);
} }
predef_cursor = cursor::arrow; predef_cursor = cursor::arrow;
@ -442,8 +442,6 @@ namespace nana
bool basic_window::set_events(const std::shared_ptr<general_events>& p) bool basic_window::set_events(const std::shared_ptr<general_events>& p)
{ {
if (annex.events_ptr)
return false;
annex.events_ptr = p; annex.events_ptr = p;
return true; return true;
} }

View File

@ -17,7 +17,7 @@
#include <sstream> #include <sstream>
#include <nana/system/timepiece.hpp> #include <nana/system/timepiece.hpp>
#include <nana/gui/wvl.hpp> #include <nana/gui/wvl.hpp>
#include <nana/gui/detail/inner_fwd_implement.hpp> #include <nana/gui/detail/basic_window.hpp>
#include <nana/gui/detail/native_window_interface.hpp> #include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp> #include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/element_store.hpp> #include <nana/gui/detail/element_store.hpp>
@ -25,6 +25,7 @@
namespace nana namespace nana
{ {
//class internal_scope_guard //class internal_scope_guard
internal_scope_guard::internal_scope_guard() internal_scope_guard::internal_scope_guard()
{ {
@ -600,7 +601,7 @@ namespace nana
{ {
root = wd->root; root = wd->root;
if (roots.cend() == std::find(roots.cbegin(), roots.cend(), root)) if (roots.cend() == std::find(roots.cbegin(), roots.cend(), root))
roots.push_back(root); roots.emplace_back(root);
} }
} }

View File

@ -626,30 +626,38 @@ namespace detail
if(pressed_wd_space) if(pressed_wd_space)
break; break;
msgwnd = wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y);
if(nullptr == msgwnd)
break;
if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5) if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5)
{ {
//The hovered window receives the message, unlike in Windows, no redirection is required. //The hovered window receives the message, unlike in Windows, no redirection is required.
nana::point mspos{xevent.xbutton.x, xevent.xbutton.y}; auto evt_wd = msgwnd;
while(msgwnd) while(evt_wd)
{ {
if(msgwnd->annex.events_ptr->mouse_wheel.length() != 0) if(evt_wd->annex.events_ptr->mouse_wheel.length() != 0)
{ {
mspos -= msgwnd->pos_root;
arg_wheel arg; arg_wheel arg;
arg.which = arg_wheel::wheel::vertical; arg.which = arg_wheel::wheel::vertical;
assign_arg(arg, msgwnd, xevent); assign_arg(arg, evt_wd, xevent);
brock.emit(event_code::mouse_wheel, msgwnd, arg, true, &context); brock.emit(event_code::mouse_wheel, evt_wd, arg, true, &context);
break; break;
} }
msgwnd = msgwnd->parent; evt_wd = evt_wd->parent;
}
if(msgwnd && (nullptr == evt_wd))
{
arg_wheel arg;
arg.which = arg_wheel::wheel::vertical;
assign_arg(arg, msgwnd, xevent);
draw_invoker(&drawer::mouse_wheel, msgwnd, arg, &context);
wd_manager.do_lazy_refresh(msgwnd, false);
} }
} }
else else
{ {
msgwnd = wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y);
if(nullptr == msgwnd)
break;
msgwnd->set_action(mouse_action::normal); msgwnd->set_action(mouse_action::normal);
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {

View File

@ -1124,8 +1124,6 @@ namespace detail
if (evt_wd->annex.events_ptr->mouse_wheel.length() != 0) if (evt_wd->annex.events_ptr->mouse_wheel.length() != 0)
{ {
def_window_proc = false; def_window_proc = false;
nana::point mspos{ scr_pos.x, scr_pos.y };
wd_manager.calc_window_point(evt_wd, mspos);
arg_wheel arg; arg_wheel arg;
arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical); arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical);
@ -1138,9 +1136,6 @@ namespace detail
if (scrolled_wd && (nullptr == evt_wd)) if (scrolled_wd && (nullptr == evt_wd))
{ {
nana::point mspos{ scr_pos.x, scr_pos.y };
wd_manager.calc_window_point(scrolled_wd, mspos);
arg_wheel arg; arg_wheel arg;
arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical); arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical);
assign_arg(arg, scrolled_wd, pmdec); assign_arg(arg, scrolled_wd, pmdec);

View File

@ -13,9 +13,9 @@
#include <nana/config.hpp> #include <nana/config.hpp>
#include <nana/gui/detail/bedrock.hpp> #include <nana/gui/detail/bedrock.hpp>
#include <nana/gui/detail/drawer.hpp> #include <nana/gui/detail/drawer.hpp>
#include <nana/gui/detail/dynamic_drawing_object.hpp>
#include <nana/gui/detail/effects_renderer.hpp> #include <nana/gui/detail/effects_renderer.hpp>
#include <nana/gui/detail/basic_window.hpp> #include <nana/gui/detail/basic_window.hpp>
#include "dynamic_drawing_object.hpp"
#if defined(NANA_X11) #if defined(NANA_X11)
#include <nana/detail/linux_X11/platform_spec.hpp> #include <nana/detail/linux_X11/platform_spec.hpp>
@ -338,7 +338,7 @@ namespace nana
for (auto p : data_impl_->draws) for (auto p : data_impl_->draws)
{ {
if(p->diehard()) if(p->diehard())
then.push_back(p); then.emplace_back(p);
else else
delete p; delete p;
} }
@ -351,7 +351,7 @@ namespace nana
if(f) if(f)
{ {
auto p = new dynamic_drawing::user_draw_function(std::move(f), diehard); auto p = new dynamic_drawing::user_draw_function(std::move(f), diehard);
data_impl_->draws.push_back(p); data_impl_->draws.emplace_back(p);
return (diehard ? p : nullptr); return (diehard ? p : nullptr);
} }
return nullptr; return nullptr;

View File

@ -1,7 +1,7 @@
/* /*
* The Store for the Storage Of Elements * The Store for the Storage Of Elements
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -11,35 +11,53 @@
*/ */
#include <nana/gui/detail/element_store.hpp> #include <nana/gui/detail/element_store.hpp>
#include <map>
namespace nana namespace nana
{ {
namespace detail namespace detail
{ {
//class element_store //class element_store
element_store::data::data()
: fast_ptr(nullptr) struct element_store::data
{
cloneable_element entity;
::nana::element::element_interface * fast_ptr{ nullptr };
};
struct element_store::implementation
{
std::map<std::string, data> table;
};
element_store::element_store()
: impl_(new implementation)
{}
//Empty destructor for instance of impl
element_store::~element_store()
{} {}
nana::element::element_interface * const * element_store::bground(const std::string& name) nana::element::element_interface * const * element_store::bground(const std::string& name)
{ {
element_interface * const * addr = &(bground_.table[name].fast_ptr); element_interface * const * addr = &(impl_->table[name].fast_ptr);
return addr; return addr;
} }
void element_store::bground(const std::string& name, const pat::cloneable<element_interface>& rhs) void element_store::bground(const std::string& name, const pat::cloneable<element_interface>& rhs)
{ {
auto & store = bground_.table[name]; auto & store = impl_->table[name];
store.object = rhs; store.entity = rhs;
store.fast_ptr = store.object.get(); store.fast_ptr = store.entity.get();
} }
void element_store::bground(const std::string& name, pat::cloneable<element_interface>&& rv) void element_store::bground(const std::string& name, pat::cloneable<element_interface>&& rv)
{ {
auto & store = bground_.table[name]; auto & store = impl_->table[name];
store.object = std::move(rv); store.entity = std::move(rv);
store.fast_ptr = store.object.get(); store.fast_ptr = store.entity.get();
} }
}//end namespace detail }//end namespace detail
} }

View File

@ -221,8 +221,8 @@ namespace nana
continue; continue;
core_window_t * term = ((i + 1 != layers_rend) ? *(i + 1) : wd); core_window_t * term = ((i + 1 != layers_rend) ? *(i + 1) : wd);
r.x = wd->pos_root.x - pre->pos_root.x; r.position(wd->pos_root - pre->pos_root);
r.y = wd->pos_root.y - pre->pos_root.y;
for (auto child : pre->children) for (auto child : pre->children)
{ {
if (child->index >= term->index) if (child->index >= term->index)
@ -253,7 +253,7 @@ namespace nana
if (child->visible && overlap(r_of_wd, rectangle{ child->pos_owner, child->dimension }, ovlp)) if (child->visible && overlap(r_of_wd, rectangle{ child->pos_owner, child->dimension }, ovlp))
{ {
if (category::flags::lite_widget != child->other.category) if (category::flags::lite_widget != child->other.category)
glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, child->drawer.graphics, nana::point(ovlp.x - child->pos_owner.x, ovlp.y - child->pos_owner.y)); glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, child->drawer.graphics, {ovlp.position() - child->pos_owner});
ovlp.x += wd->pos_root.x; ovlp.x += wd->pos_root.x;
ovlp.y += wd->pos_root.y; ovlp.y += wd->pos_root.y;

View File

@ -23,9 +23,187 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#if defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp>
#else
#include <mutex>
#endif
namespace nana namespace nana
{ {
namespace detail
{
//class shortkey_container
struct shortkey_rep
{
window handle;
std::vector<unsigned long> keys;
};
struct shortkey_container::implementation
{
std::vector<shortkey_rep> base;
};
shortkey_container::shortkey_container()
:impl_(new implementation)
{}
shortkey_container::shortkey_container(shortkey_container&& other)
: impl_(other.impl_)
{
other.impl_ = nullptr;
}
shortkey_container::~shortkey_container()
{
delete impl_;
}
void shortkey_container::clear()
{
impl_->base.clear();
}
bool shortkey_container::make(window wd, unsigned long key)
{
if (wd == nullptr) return false;
if (key < 0x61) key += (0x61 - 0x41);
for (auto & m : impl_->base)
{
if (m.handle == wd)
{
m.keys.emplace_back(key);
return true;
}
}
impl_->base.emplace_back();
auto & rep = impl_->base.back();
rep.handle = wd;
rep.keys.emplace_back(key);
return true;
}
void shortkey_container::umake(window wd)
{
if (wd == nullptr) return;
for (auto i = impl_->base.begin(); i != impl_->base.end(); ++i)
{
if (i->handle == wd)
{
impl_->base.erase(i);
break;
}
}
}
std::vector<unsigned long> shortkey_container::keys(window wd) const
{
if (wd)
{
for (auto & m : impl_->base)
{
if (m.handle == wd)
return m.keys;
}
}
return{};
}
window shortkey_container::find(unsigned long key) const
{
if (key < 0x61) key += (0x61 - 0x41);
for (auto & m : impl_->base)
{
for (auto n : m.keys)
{
if (key == n)
return m.handle;
}
}
return nullptr;
}
//end class shortkey_container
//struct root_misc
root_misc::root_misc(root_misc&& other):
window(other.window),
root_graph(std::move(other.root_graph)),
shortkeys(std::move(other.shortkeys)),
condition(std::move(other.condition))
{
}
root_misc::root_misc(basic_window * wd, unsigned width, unsigned height)
: window(wd),
root_graph({ width, height })
{
condition.ignore_tab = false;
condition.pressed = nullptr;
condition.pressed_by_space = nullptr;
condition.hovered = nullptr;
}
//end struct root_misc
//class root_register
struct root_register::implementation
{
//Cached
native_window_type recent_access{ nullptr };
root_misc * misc_ptr{ nullptr };
std::map<native_window_type, root_misc> table;
};
root_register::root_register()
: impl_(new implementation)
{}
root_register::~root_register()
{
delete impl_;
}
root_misc* root_register::insert(native_window_type wd, root_misc&& misc)
{
impl_->recent_access = wd;
auto ret = impl_->table.emplace(wd, std::move(misc));
impl_->misc_ptr = &(ret.first->second);
return impl_->misc_ptr;
}
root_misc * root_register::find(native_window_type wd)
{
if (wd == impl_->recent_access)
return impl_->misc_ptr;
impl_->recent_access = wd;
auto i = impl_->table.find(wd);
if (i != impl_->table.end())
impl_->misc_ptr = &(i->second);
else
impl_->misc_ptr = nullptr;
return impl_->misc_ptr;
}
void root_register::erase(native_window_type wd)
{
impl_->table.erase(wd);
impl_->recent_access = wd;
impl_->misc_ptr = nullptr;
}
//end class root_register
}
namespace detail namespace detail
{ {
template<typename Key, typename Value> template<typename Key, typename Value>
@ -36,9 +214,7 @@ namespace detail
Key first; Key first;
Value second; Value second;
key_value_rep() key_value_rep() = default;
: first{}, second{}
{}
key_value_rep(const Key& k) key_value_rep(const Key& k)
: first(k), second{} : first(k), second{}
@ -69,19 +245,9 @@ namespace detail
return table_.end(); return table_.end();
} }
iterator erase(iterator pos) std::vector<key_value_rep>& table()
{ {
return table_.erase(pos); return table_;
}
iterator begin()
{
return table_.begin();
}
iterator end()
{
return table_.end();
} }
private: private:
std::vector<key_value_rep> table_; std::vector<key_value_rep> table_;
@ -109,27 +275,50 @@ namespace detail
//end struct wdm_private_impl //end struct wdm_private_impl
//class revertible_mutex //class revertible_mutex
window_manager::revertible_mutex::revertible_mutex() struct thread_refcount
{ {
thr_.tid = 0; unsigned tid;
thr_.refcnt = 0; std::size_t ref;
};
struct window_manager::revertible_mutex::implementation
{
std::recursive_mutex mutex;
thread_refcount thread;
std::vector<thread_refcount> invoke_stack;
};
window_manager::revertible_mutex::revertible_mutex()
: impl_(new implementation)
{
impl_->thread.tid = 0;
impl_->thread.ref = 0;
}
window_manager::revertible_mutex::~revertible_mutex()
{
delete impl_;
} }
void window_manager::revertible_mutex::lock() void window_manager::revertible_mutex::lock()
{ {
std::recursive_mutex::lock(); impl_->mutex.lock();
if(0 == thr_.tid)
thr_.tid = nana::system::this_thread_id(); if(0 == impl_->thread.tid)
++thr_.refcnt; impl_->thread.tid = nana::system::this_thread_id();
++(impl_->thread.ref);
} }
bool window_manager::revertible_mutex::try_lock() bool window_manager::revertible_mutex::try_lock()
{ {
if(std::recursive_mutex::try_lock()) if(impl_->mutex.try_lock())
{ {
if(0 == thr_.tid) if (0 == impl_->thread.tid)
thr_.tid = nana::system::this_thread_id(); impl_->thread.tid = nana::system::this_thread_id();
++thr_.refcnt;
++(impl_->thread.ref);
return true; return true;
} }
return false; return false;
@ -137,44 +326,45 @@ namespace detail
void window_manager::revertible_mutex::unlock() void window_manager::revertible_mutex::unlock()
{ {
if(thr_.tid == nana::system::this_thread_id()) if(impl_->thread.tid == nana::system::this_thread_id())
if(0 == --thr_.refcnt) if(0 == --(impl_->thread.ref))
thr_.tid = 0; impl_->thread.tid = 0;
std::recursive_mutex::unlock();
impl_->mutex.unlock();
} }
void window_manager::revertible_mutex::revert() void window_manager::revertible_mutex::revert()
{ {
if(thr_.refcnt && (thr_.tid == nana::system::this_thread_id())) if(impl_->thread.ref && (impl_->thread.tid == nana::system::this_thread_id()))
{ {
std::size_t cnt = thr_.refcnt; std::size_t cnt = impl_->thread.ref;
stack_.push_back(thr_); impl_->invoke_stack.push_back(impl_->thread);
thr_.tid = 0; impl_->thread.tid = 0;
thr_.refcnt = 0; impl_->thread.ref = 0;
for(std::size_t i = 0; i < cnt; ++i) for (std::size_t i = 0; i < cnt; ++i)
std::recursive_mutex::unlock(); impl_->mutex.unlock();
} }
} }
void window_manager::revertible_mutex::forward() void window_manager::revertible_mutex::forward()
{ {
std::recursive_mutex::lock(); impl_->mutex.lock();
if(stack_.size()) if(impl_->invoke_stack.size())
{ {
auto thr = stack_.back(); auto thr = impl_->invoke_stack.back();
if(thr.tid == nana::system::this_thread_id()) if(thr.tid == nana::system::this_thread_id())
{ {
stack_.pop_back(); impl_->invoke_stack.pop_back();
for(std::size_t i = 0; i < thr.refcnt; ++i) for (std::size_t i = 0; i < thr.ref; ++i)
std::recursive_mutex::lock(); impl_->mutex.lock();
thr_ = thr; impl_->thread = thr;
} }
else else
throw std::runtime_error("Nana.GUI: The forward is not matched."); throw std::runtime_error("Nana.GUI: The forward is not matched.");
} }
std::recursive_mutex::unlock(); impl_->mutex.unlock();
} }
//end class revertible_mutex //end class revertible_mutex
@ -254,23 +444,13 @@ namespace detail
return (impl_->wd_register.available(a) && impl_->wd_register.available(b)); return (impl_->wd_register.available(a) && impl_->wd_register.available(b));
} }
bool window_manager::available(native_window_type wd)
{
if(wd)
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return (impl_->misc_register.find(wd) != nullptr);
}
return false;
}
window_manager::core_window_t* window_manager::create_root(core_window_t* owner, bool nested, rectangle r, const appearance& app, widget* wdg) window_manager::core_window_t* window_manager::create_root(core_window_t* owner, bool nested, rectangle r, const appearance& app, widget* wdg)
{ {
native_window_type native = nullptr; native_window_type native = nullptr;
if (owner) if (owner)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(owner)) if (impl_->wd_register.available(owner))
{ {
@ -306,11 +486,10 @@ namespace detail
wd->title = native_interface::window_caption(result.native_handle); wd->title = native_interface::window_caption(result.native_handle);
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
//create Root graphics Buffer and manage it //create Root graphics Buffer and manage it
root_misc misc(wd, result.width, result.height); auto* value = impl_->misc_register.insert(result.native_handle, root_misc(wd, result.width, result.height));
auto* value = impl_->misc_register.insert(result.native_handle, misc);
wd->bind_native_window(result.native_handle, result.width, result.height, result.extra_width, result.extra_height, value->root_graph); wd->bind_native_window(result.native_handle, result.width, result.height, result.extra_width, result.extra_height, value->root_graph);
impl_->wd_register.insert(wd, wd->thread_id); impl_->wd_register.insert(wd, wd->thread_id);
@ -331,7 +510,7 @@ namespace detail
window_manager::core_window_t* window_manager::create_frame(core_window_t* parent, const rectangle& r, widget* wdg) window_manager::core_window_t* window_manager::create_frame(core_window_t* parent, const rectangle& r, widget* wdg)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(parent) == false) return nullptr; if (impl_->wd_register.available(parent) == false) return nullptr;
@ -350,7 +529,7 @@ namespace detail
if(frame) if(frame)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if(category::flags::frame == frame->other.category) if(category::flags::frame == frame->other.category)
frame->other.attribute.frame->attach.push_back(wd); frame->other.attribute.frame->attach.push_back(wd);
return true; return true;
@ -363,7 +542,7 @@ namespace detail
if(frame) if(frame)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if(category::flags::frame == frame->other.category) if(category::flags::frame == frame->other.category)
{ {
if (impl_->wd_register.available(wd) && (category::flags::root == wd->other.category) && wd->root != frame->root) if (impl_->wd_register.available(wd) && (category::flags::root == wd->other.category) && wd->root != frame->root)
@ -380,7 +559,7 @@ namespace detail
window_manager::core_window_t* window_manager::create_widget(core_window_t* parent, const rectangle& r, bool is_lite, widget* wdg) window_manager::core_window_t* window_manager::create_widget(core_window_t* parent, const rectangle& r, bool is_lite, widget* wdg)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(parent) == false) if (impl_->wd_register.available(parent) == false)
throw std::invalid_argument("invalid parent/owner handle"); throw std::invalid_argument("invalid parent/owner handle");
@ -401,7 +580,7 @@ namespace detail
void window_manager::close(core_window_t *wd) void window_manager::close(core_window_t *wd)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) == false) return; if (impl_->wd_register.available(wd) == false) return;
if (wd->flags.destroying) if (wd->flags.destroying)
@ -443,7 +622,7 @@ namespace detail
void window_manager::destroy(core_window_t* wd) void window_manager::destroy(core_window_t* wd)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) == false) return; if (impl_->wd_register.available(wd) == false) return;
rectangle update_area(wd->pos_owner, wd->dimension); rectangle update_area(wd->pos_owner, wd->dimension);
@ -467,7 +646,7 @@ namespace detail
void window_manager::destroy_handle(core_window_t* wd) void window_manager::destroy_handle(core_window_t* wd)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) == false) return; if (impl_->wd_register.available(wd) == false) return;
#ifndef WIDGET_FRAME_DEPRECATED #ifndef WIDGET_FRAME_DEPRECATED
@ -491,7 +670,7 @@ namespace detail
{ {
if(!big_icon.empty() || !small_icon.empty()) if(!big_icon.empty() || !small_icon.empty())
{ {
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd)) if (impl_->wd_register.available(wd))
{ {
if(category::flags::root == wd->other.category) if(category::flags::root == wd->other.category)
@ -505,7 +684,7 @@ namespace detail
bool window_manager::show(core_window_t* wd, bool visible) bool window_manager::show(core_window_t* wd, bool visible)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (!impl_->wd_register.available(wd)) if (!impl_->wd_register.available(wd))
return false; return false;
@ -548,7 +727,7 @@ namespace detail
if((false == attr_.capture.ignore_children) || (nullptr == attr_.capture.window) || (attr_.capture.window->root != root)) if((false == attr_.capture.ignore_children) || (nullptr == attr_.capture.window) || (attr_.capture.window->root != root))
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
auto rrt = root_runtime(root); auto rrt = root_runtime(root);
point pos{ x, y }; point pos{ x, y };
if (rrt && _m_effective(rrt->window, pos)) if (rrt && _m_effective(rrt->window, pos))
@ -561,7 +740,7 @@ namespace detail
bool window_manager::move(core_window_t* wd, int x, int y, bool passive) bool window_manager::move(core_window_t* wd, int x, int y, bool passive)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd)) if (impl_->wd_register.available(wd))
{ {
if (category::flags::root != wd->other.category) if (category::flags::root != wd->other.category)
@ -606,7 +785,7 @@ namespace detail
bool window_manager::move(core_window_t* wd, const rectangle& r) bool window_manager::move(core_window_t* wd, const rectangle& r)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (!impl_->wd_register.available(wd)) if (!impl_->wd_register.available(wd))
return false; return false;
@ -680,7 +859,7 @@ namespace detail
bool window_manager::size(core_window_t* wd, nana::size sz, bool passive, bool ask_update) bool window_manager::size(core_window_t* wd, nana::size sz, bool passive, bool ask_update)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (!impl_->wd_register.available(wd)) if (!impl_->wd_register.available(wd))
return false; return false;
@ -767,7 +946,7 @@ namespace detail
if(cache.first == wd) return cache.second; if(cache.first == wd) return cache.second;
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
auto rrt = root_runtime(wd); auto rrt = root_runtime(wd);
if(rrt) if(rrt)
@ -783,7 +962,7 @@ namespace detail
void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area) void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) && !wd->is_draw_through()) if (impl_->wd_register.available(wd) && !wd->is_draw_through())
{ {
auto parent = wd->parent; auto parent = wd->parent;
@ -805,7 +984,7 @@ namespace detail
bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area) bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) == false) return false; if (impl_->wd_register.available(wd) == false) return false;
if (wd->displayed()) if (wd->displayed())
@ -837,7 +1016,7 @@ namespace detail
void window_manager::refresh_tree(core_window_t* wd) void window_manager::refresh_tree(core_window_t* wd)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
//It's not worthy to redraw if visible is false //It's not worthy to redraw if visible is false
if (impl_->wd_register.available(wd) && wd->displayed()) if (impl_->wd_register.available(wd) && wd->displayed())
@ -850,7 +1029,7 @@ namespace detail
bool window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree) bool window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (false == impl_->wd_register.available(wd)) if (false == impl_->wd_register.available(wd))
return false; return false;
@ -888,7 +1067,7 @@ namespace detail
bool window_manager::get_graphics(core_window_t* wd, nana::paint::graphics& result) bool window_manager::get_graphics(core_window_t* wd, nana::paint::graphics& result)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (!impl_->wd_register.available(wd)) if (!impl_->wd_register.available(wd))
return false; return false;
@ -901,7 +1080,7 @@ namespace detail
bool window_manager::get_visual_rectangle(core_window_t* wd, nana::rectangle& r) bool window_manager::get_visual_rectangle(core_window_t* wd, nana::rectangle& r)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
return (impl_->wd_register.available(wd) ? return (impl_->wd_register.available(wd) ?
window_layer::read_visual_rectangle(wd, r) : window_layer::read_visual_rectangle(wd, r) :
false); false);
@ -909,7 +1088,7 @@ namespace detail
std::vector<window_manager::core_window_t*> window_manager::get_children(core_window_t* wd) const std::vector<window_manager::core_window_t*> window_manager::get_children(core_window_t* wd) const
{ {
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd)) if (impl_->wd_register.available(wd))
return wd->children; return wd->children;
return{}; return{};
@ -918,7 +1097,7 @@ namespace detail
bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa) bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (!impl_->wd_register.available(wd)) if (!impl_->wd_register.available(wd))
return false; return false;
@ -945,7 +1124,7 @@ namespace detail
window_manager::core_window_t* window_manager::set_focus(core_window_t* wd, bool root_has_been_focused, arg_focus::reason reason) window_manager::core_window_t* window_manager::set_focus(core_window_t* wd, bool root_has_been_focused, arg_focus::reason reason)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (!impl_->wd_register.available(wd)) if (!impl_->wd_register.available(wd))
return nullptr; return nullptr;
@ -1051,7 +1230,7 @@ namespace detail
if(wd != attr_.capture.window) if(wd != attr_.capture.window)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd)) if (impl_->wd_register.available(wd))
{ {
@ -1112,7 +1291,7 @@ namespace detail
void window_manager::enable_tabstop(core_window_t* wd) void window_manager::enable_tabstop(core_window_t* wd)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) && (detail::tab_type::none == wd->flags.tab)) if (impl_->wd_register.available(wd) && (detail::tab_type::none == wd->flags.tab))
{ {
wd->root_widget->other.attribute.root->tabstop.push_back(wd); wd->root_widget->other.attribute.root->tabstop.push_back(wd);
@ -1156,7 +1335,7 @@ namespace detail
auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t* auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t*
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (!impl_->wd_register.available(wd)) if (!impl_->wd_register.available(wd))
return nullptr; return nullptr;
@ -1198,7 +1377,7 @@ namespace detail
bool window_manager::enable_effects_bground(core_window_t* wd, bool enabled) bool window_manager::enable_effects_bground(core_window_t* wd, bool enabled)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd)) if (impl_->wd_register.available(wd))
return window_layer::enable_effects_bground(wd, enabled); return window_layer::enable_effects_bground(wd, enabled);
@ -1208,7 +1387,7 @@ namespace detail
bool window_manager::calc_window_point(core_window_t* wd, nana::point& pos) bool window_manager::calc_window_point(core_window_t* wd, nana::point& pos)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd)) if (impl_->wd_register.available(wd))
{ {
if(native_interface::calc_window_point(wd->root, pos)) if(native_interface::calc_window_point(wd->root, pos))
@ -1220,7 +1399,7 @@ namespace detail
return false; return false;
} }
root_misc* window_manager::root_runtime(native_window_type native_wd) const root_misc* window_manager::root_runtime(native_window native_wd) const
{ {
return impl_->misc_register.find(native_wd); return impl_->misc_register.find(native_wd);
} }
@ -1228,7 +1407,7 @@ namespace detail
bool window_manager::register_shortkey(core_window_t* wd, unsigned long key) bool window_manager::register_shortkey(core_window_t* wd, unsigned long key)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd)) if (impl_->wd_register.available(wd))
{ {
auto object = root_runtime(wd->root); auto object = root_runtime(wd->root);
@ -1241,7 +1420,7 @@ namespace detail
void window_manager::unregister_shortkey(core_window_t* wd, bool with_children) void window_manager::unregister_shortkey(core_window_t* wd, bool with_children)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd) == false) return; if (impl_->wd_register.available(wd) == false) return;
auto root_rt = root_runtime(wd->root); auto root_rt = root_runtime(wd->root);
@ -1261,7 +1440,7 @@ namespace detail
std::vector<std::pair<core_window_t*, unsigned long>> result; std::vector<std::pair<core_window_t*, unsigned long>> result;
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (impl_->wd_register.available(wd)) if (impl_->wd_register.available(wd))
{ {
auto root_rt = root_runtime(wd->root); auto root_rt = root_runtime(wd->root);
@ -1290,7 +1469,7 @@ namespace detail
if(native_window) if(native_window)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
auto object = root_runtime(native_window); auto object = root_runtime(native_window);
if(object) if(object)
return reinterpret_cast<core_window_t*>(object->shortkeys.find(key)); return reinterpret_cast<core_window_t*>(object->shortkeys.find(key));
@ -1302,7 +1481,7 @@ namespace detail
{ {
if (fn) if (fn)
{ {
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (!available(wd)) if (!available(wd))
return; return;
@ -1312,21 +1491,21 @@ namespace detail
void window_manager::call_safe_place(unsigned thread_id) void window_manager::call_safe_place(unsigned thread_id)
{ {
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
for (auto i = impl_->safe_place.begin(); i != impl_->safe_place.end();) auto& safe_place = impl_->safe_place.table();
for (auto i = safe_place.begin(); i != safe_place.end();)
{ {
if (i->first->thread_id == thread_id) if (i->first->thread_id == thread_id)
{ {
for (auto & fn : i->second) for (auto & fn : i->second)
fn(); fn();
i = impl_->safe_place.erase(i); i = safe_place.erase(i);
} }
else else
++i; ++i;
} }
} }
bool check_tree(basic_window* wd, basic_window* const cond) bool check_tree(basic_window* wd, basic_window* const cond)
@ -1535,6 +1714,11 @@ namespace detail
wd->annex.caret_ptr = nullptr; wd->annex.caret_ptr = nullptr;
} }
using effect_renderer = detail::edge_nimbus_renderer<basic_window>;
//remove the window from edge nimbus effect when it is destroying
effect_renderer::instance().erase(wd);
arg_destroy arg; arg_destroy arg;
arg.window_handle = reinterpret_cast<window>(wd); arg.window_handle = reinterpret_cast<window>(wd);
brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context());

View File

@ -159,7 +159,7 @@ namespace nana
} }
}); });
triggers_.push_back(tg); triggers_.emplace_back(tg);
} }
private: private:
static void _m_check_restrict_area(nana::point & pos, const nana::size & size, const nana::rectangle& restr_area) static void _m_check_restrict_area(nana::point & pos, const nana::size & size, const nana::rectangle& restr_area)

View File

@ -80,7 +80,9 @@ namespace nana
void drawing::erase(diehard_t d) void drawing::erase(diehard_t d)
{ {
if(API::empty_window(handle_)) //Fixed by Tumiz
//https://github.com/cnjinhao/nana/issues/153
if(!API::empty_window(handle_))
restrict::get_drawer(handle_).erase(d); restrict::get_drawer(handle_).erase(d);
} }

View File

@ -15,7 +15,6 @@
#include <nana/gui/detail/element_store.hpp> #include <nana/gui/detail/element_store.hpp>
#include <nana/paint/image.hpp> #include <nana/paint/image.hpp>
#include <map> #include <map>
#include <string>
#if defined(STD_THREAD_NOT_SUPPORTED) #if defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp> #include <nana/std_mutex.hpp>
@ -599,7 +598,6 @@ namespace nana
{ {
using element_type = ElementInterface; using element_type = ElementInterface;
using factory_interface = pat::cloneable<element::detail::factory_abstract>; using factory_interface = pat::cloneable<element::detail::factory_abstract>;
public: public:
~element_object() ~element_object()
{ {
@ -1156,46 +1154,48 @@ namespace nana
} }
}; };
struct bground::implementation
{
draw_method * method{ nullptr };
bool vert{ false };
rectangle valid_area;
std::vector<element_state> states;
std::map<element_state, element_state> join;
bool stretch_all{ true };
unsigned left{ 0 }, top{ 0 }, right{ 0 }, bottom{ 0 };
};
bground::bground() bground::bground()
: method_(nullptr), : impl_{ new implementation }
vertical_(false),
stretch_all_(true),
left_(0), top_(0), right_(0), bottom_(0)
{ {
reset_states(); reset_states();
} }
bground::bground(const bground& rhs) bground::bground(const bground& rhs)
: method_(rhs.method_ ? rhs.method_->clone() : nullptr), : impl_{ new implementation(*rhs.impl_) }
vertical_(rhs.vertical_),
valid_area_(rhs.valid_area_),
states_(rhs.states_),
join_(rhs.join_),
stretch_all_(rhs.stretch_all_),
left_(rhs.left_), top_(rhs.top_), right_(rhs.right_), bottom_(rhs.bottom_)
{ {
if (impl_->method)
impl_->method = impl_->method->clone();
} }
bground::~bground() bground::~bground()
{ {
delete method_; delete impl_->method;
} }
bground& bground::operator=(const bground& rhs) bground& bground::operator=(const bground& rhs)
{ {
if (this != &rhs) if (this != &rhs)
{ {
delete method_; delete impl_->method;
method_ = (rhs.method_ ? rhs.method_->clone() : nullptr);
vertical_ = rhs.vertical_; impl_.reset(new implementation(*rhs.impl_));
valid_area_ = rhs.valid_area_; if (impl_->method)
states_ = rhs.states_; impl_->method = impl_->method->clone();
join_ = rhs.join_;
stretch_all_ = rhs.stretch_all_;
left_ = rhs.left_;
top_ = rhs.top_;
right_ = rhs.right_;
bottom_ = rhs.bottom_;
} }
return *this; return *this;
} }
@ -1203,106 +1203,110 @@ namespace nana
//Set a picture for the background //Set a picture for the background
bground& bground::image(const paint::image& img, bool vertical, const nana::rectangle& valid_area) bground& bground::image(const paint::image& img, bool vertical, const nana::rectangle& valid_area)
{ {
delete method_; delete impl_->method;
method_ = new draw_image(img); impl_->method = new draw_image(img);
vertical_ = vertical; impl_->vert = vertical;
if (valid_area.width && valid_area.height) if (valid_area.width && valid_area.height)
valid_area_ = valid_area; impl_->valid_area = valid_area;
else else
valid_area_ = nana::rectangle(img.size()); impl_->valid_area = nana::rectangle(img.size());
return *this; return *this;
} }
bground& bground::image(const paint::graphics& graph, bool vertical, const nana::rectangle& valid_area) bground& bground::image(const paint::graphics& graph, bool vertical, const nana::rectangle& valid_area)
{ {
delete method_; delete impl_->method;
method_ = new draw_graph(graph); impl_->method = new draw_graph(graph);
vertical_ = vertical; impl_->vert = vertical;
if (valid_area.width && valid_area.height) if (valid_area.width && valid_area.height)
valid_area_ = valid_area; impl_->valid_area = valid_area;
else else
valid_area_ = nana::rectangle(graph.size()); impl_->valid_area = nana::rectangle(graph.size());
return *this; return *this;
} }
//Set the state sequence of the background picture. //Set the state sequence of the background picture.
void bground::states(const std::vector<element_state> & s) void bground::states(const std::vector<element_state> & s)
{ {
states_ = s; impl_->states = s;
} }
void bground::states(std::vector<element_state> && s) void bground::states(std::vector<element_state> && s)
{ {
states_ = std::move(s); impl_->states = std::move(s);
} }
void bground::reset_states() void bground::reset_states()
{ {
states_.clear(); auto & st = impl_->states;
states_.push_back(element_state::normal);
states_.push_back(element_state::hovered); st.clear();
states_.push_back(element_state::focus_normal); st.push_back(element_state::normal);
states_.push_back(element_state::focus_hovered); st.push_back(element_state::hovered);
states_.push_back(element_state::pressed); st.push_back(element_state::focus_normal);
states_.push_back(element_state::disabled); st.push_back(element_state::focus_hovered);
join_.clear(); st.push_back(element_state::pressed);
st.push_back(element_state::disabled);
impl_->join.clear();
} }
void bground::join(element_state target, element_state joiner) void bground::join(element_state target, element_state joiner)
{ {
join_[joiner] = target; impl_->join[joiner] = target;
} }
void bground::stretch_parts(unsigned left, unsigned top, unsigned right, unsigned bottom) void bground::stretch_parts(unsigned left, unsigned top, unsigned right, unsigned bottom)
{ {
left_ = left; impl_->left = left;
top_ = top; impl_->right = right;
right_ = right; impl_->top = top;
bottom_ = bottom; impl_->bottom = bottom;
stretch_all_ = !(left || right || top || bottom); impl_->stretch_all = !(left || right || top || bottom);
} }
//Implement the methods of bground_interface. //Implement the methods of bground_interface.
bool bground::draw(graph_reference dst, const ::nana::color&, const ::nana::color&, const nana::rectangle& to_r, element_state state) bool bground::draw(graph_reference dst, const ::nana::color&, const ::nana::color&, const nana::rectangle& to_r, element_state state)
{ {
if (nullptr == method_) const auto method = impl_->method;
if (nullptr == method)
return false; return false;
auto mi = join_.find(state); auto mi = impl_->join.find(state);
if (mi != join_.end()) if (mi != impl_->join.end())
state = mi->second; state = mi->second;
std::size_t pos = 0; std::size_t pos = 0;
for (; pos < states_.size(); ++pos) for (; pos < impl_->states.size(); ++pos)
{ {
if (states_[pos] == state) if (impl_->states[pos] == state)
break; break;
} }
if (pos == states_.size()) if (pos == impl_->states.size())
return false; return false;
nana::rectangle from_r = valid_area_; nana::rectangle from_r = impl_->valid_area;
if (vertical_) if (impl_->vert)
{ {
from_r.height /= static_cast<unsigned>(states_.size()); from_r.height /= static_cast<unsigned>(impl_->states.size());
from_r.y += static_cast<int>(from_r.height * pos); from_r.y += static_cast<int>(from_r.height * pos);
} }
else else
{ {
from_r.width /= static_cast<unsigned>(states_.size()); from_r.width /= static_cast<unsigned>(impl_->states.size());
from_r.x += static_cast<int>(from_r.width * pos); from_r.x += static_cast<int>(from_r.width * pos);
} }
if (stretch_all_) if (impl_->stretch_all)
{ {
if (from_r.width == to_r.width && from_r.height == to_r.height) if (from_r.width == to_r.width && from_r.height == to_r.height)
method_->paste(from_r, dst, to_r.position()); method->paste(from_r, dst, to_r.position());
else else
method_->stretch(from_r, dst, to_r); method->stretch(from_r, dst, to_r);
return true; return true;
} }
@ -1311,118 +1315,123 @@ namespace nana
auto perf_from_r = from_r; auto perf_from_r = from_r;
auto perf_to_r = to_r; auto perf_to_r = to_r;
if (left_ + right_ < to_r.width) const auto left = impl_->left;
const auto right = impl_->right;
const auto top = impl_->top;
const auto bottom = impl_->bottom;
if (left + right < to_r.width)
{ {
nana::rectangle src_r = from_r; nana::rectangle src_r = from_r;
src_r.y += static_cast<int>(top_); src_r.y += static_cast<int>(top);
src_r.height -= top_ + bottom_; src_r.height -= top + bottom;
nana::rectangle dst_r = to_r; nana::rectangle dst_r = to_r;
dst_r.y += static_cast<int>(top_); dst_r.y += static_cast<int>(top);
dst_r.height -= top_ + bottom_; dst_r.height -= top + bottom;
if (left_) if (left)
{ {
src_r.width = left_; src_r.width = left;
dst_r.width = left_; dst_r.width = left;
method_->stretch(src_r, dst, dst_r); method->stretch(src_r, dst, dst_r);
perf_from_r.x += static_cast<int>(left_); perf_from_r.x += static_cast<int>(left);
perf_from_r.width -= left_; perf_from_r.width -= left;
perf_to_r.x += static_cast<int>(left_); perf_to_r.x += static_cast<int>(left);
perf_to_r.width -= left_; perf_to_r.width -= left;
} }
if (right_) if (right)
{ {
src_r.x += (static_cast<int>(from_r.width) - static_cast<int>(right_)); src_r.x += (static_cast<int>(from_r.width) - static_cast<int>(right));
src_r.width = right_; src_r.width = right;
dst_r.x += (static_cast<int>(to_r.width) - static_cast<int>(right_)); dst_r.x += (static_cast<int>(to_r.width) - static_cast<int>(right));
dst_r.width = right_; dst_r.width = right;
method_->stretch(src_r, dst, dst_r); method->stretch(src_r, dst, dst_r);
perf_from_r.width -= right_; perf_from_r.width -= right;
perf_to_r.width -= right_; perf_to_r.width -= right;
} }
} }
if (top_ + bottom_ < to_r.height) if (top + bottom < to_r.height)
{ {
nana::rectangle src_r = from_r; nana::rectangle src_r = from_r;
src_r.x += static_cast<int>(left_); src_r.x += static_cast<int>(left);
src_r.width -= left_ + right_; src_r.width -= left + right;
nana::rectangle dst_r = to_r; nana::rectangle dst_r = to_r;
dst_r.x += static_cast<int>(left_); dst_r.x += static_cast<int>(left);
dst_r.width -= left_ + right_; dst_r.width -= left + right;
if (top_) if (top)
{ {
src_r.height = top_; src_r.height = top;
dst_r.height = top_; dst_r.height = top;
method_->stretch(src_r, dst, dst_r); method->stretch(src_r, dst, dst_r);
perf_from_r.y += static_cast<int>(top_); perf_from_r.y += static_cast<int>(top);
perf_to_r.y += static_cast<int>(top_); perf_to_r.y += static_cast<int>(top);
} }
if (bottom_) if (bottom)
{ {
src_r.y += static_cast<int>(from_r.height - bottom_); src_r.y += static_cast<int>(from_r.height - bottom);
src_r.height = bottom_; src_r.height = bottom;
dst_r.y += static_cast<int>(to_r.height - bottom_); dst_r.y += static_cast<int>(to_r.height - bottom);
dst_r.height = bottom_; dst_r.height = bottom;
method_->stretch(src_r, dst, dst_r); method->stretch(src_r, dst, dst_r);
} }
perf_from_r.height -= (top_ + bottom_); perf_from_r.height -= (top + bottom);
perf_to_r.height -= (top_ + bottom_); perf_to_r.height -= (top + bottom);
} }
if (left_) if (left)
{ {
nana::rectangle src_r = from_r; nana::rectangle src_r = from_r;
src_r.width = left_; src_r.width = left;
if (top_) if (top)
{ {
src_r.height = top_; src_r.height = top;
method_->paste(src_r, dst, to_r.position()); method->paste(src_r, dst, to_r.position());
} }
if (bottom_) if (bottom)
{ {
src_r.y += static_cast<int>(from_r.height) - static_cast<int>(bottom_); src_r.y += static_cast<int>(from_r.height) - static_cast<int>(bottom);
src_r.height = bottom_; src_r.height = bottom;
method_->paste(src_r, dst, nana::point(to_r.x, to_r.y + static_cast<int>(to_r.height - bottom_))); method->paste(src_r, dst, nana::point(to_r.x, to_r.y + static_cast<int>(to_r.height - bottom)));
} }
} }
if (right_) if (right)
{ {
const int to_x = to_r.x + int(to_r.width - right_); const int to_x = to_r.x + int(to_r.width - right);
nana::rectangle src_r = from_r; nana::rectangle src_r = from_r;
src_r.x += static_cast<int>(src_r.width) - static_cast<int>(right_); src_r.x += static_cast<int>(src_r.width) - static_cast<int>(right);
src_r.width = right_; src_r.width = right;
if (top_) if (top)
{ {
src_r.height = top_; src_r.height = top;
method_->paste(src_r, dst, nana::point(to_x, to_r.y)); method->paste(src_r, dst, nana::point(to_x, to_r.y));
} }
if (bottom_) if (bottom)
{ {
src_r.y += (static_cast<int>(from_r.height) - static_cast<int>(bottom_)); src_r.y += (static_cast<int>(from_r.height) - static_cast<int>(bottom));
src_r.height = bottom_; src_r.height = bottom;
method_->paste(src_r, dst, nana::point(to_x, to_r.y + int(to_r.height - bottom_))); method->paste(src_r, dst, nana::point(to_x, to_r.y + int(to_r.height - bottom)));
} }
} }
method_->stretch(perf_from_r, dst, perf_to_r); method->stretch(perf_from_r, dst, perf_to_r);
return true; return true;
} }
//end class bground //end class bground

View File

@ -498,24 +498,26 @@ namespace nana
if(name.empty() || (name.front() == '.')) if(name.empty() || (name.front() == '.'))
continue; continue;
auto fpath = i->path().native();
auto fattr = fs::status(fpath);
item_fs m; item_fs m;
m.name = name; m.name = name;
m.directory = fs::is_directory(fattr);
auto fattr = fs::status(path + m.name); switch(fattr.type())
if(fattr.type() != fs::file_type::not_found && fattr.type() != fs::file_type::unknown)
{
m.bytes = fs::file_size(path + m.name);
m.directory = fs::is_directory(fattr);
fs_ext::modified_file_time(path + m.name, m.modified_time);
}
else
{ {
case fs::file_type::not_found:
case fs::file_type::unknown:
case fs::file_type::directory:
m.bytes = 0; m.bytes = 0;
m.directory = fs::is_directory(*i); break;
fs_ext::modified_file_time(path + i->path().filename().native(), m.modified_time); default:
m.bytes = fs::file_size(fpath);
} }
fs_ext::modified_file_time(fpath, m.modified_time);
file_container_.push_back(m); file_container_.push_back(m);
if(m.directory) if(m.directory)

View File

@ -1,7 +1,7 @@
/* /*
* A Message Box Class * A Message Box Class
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -61,14 +61,14 @@ namespace nana
{ {
_m_click(arg); _m_click(arg);
}); });
yes_.caption("OK"); yes_.i18n(i18n_eval("OK"));
width_pixel += 77; width_pixel += 77;
if(msgbox::yes_no == btn || msgbox::yes_no_cancel == btn) if(msgbox::yes_no == btn || msgbox::yes_no_cancel == btn)
{ {
yes_.caption("Yes"); yes_.i18n(i18n_eval("Yes"));
no_.create(*this); no_.create(*this);
no_.caption("No"); no_.i18n(i18n_eval("No"));
no_.events().click.connect_unignorable([this](const arg_click& arg) no_.events().click.connect_unignorable([this](const arg_click& arg)
{ {
_m_click(arg); _m_click(arg);
@ -79,7 +79,7 @@ namespace nana
if(msgbox::yes_no_cancel == btn) if(msgbox::yes_no_cancel == btn)
{ {
cancel_.create(*this); cancel_.create(*this);
cancel_.caption("Cancel"); cancel_.i18n(i18n_eval("Cancel"));
cancel_.events().click.connect_unignorable([this](const arg_click& arg) cancel_.events().click.connect_unignorable([this](const arg_click& arg)
{ {
_m_click(arg); _m_click(arg);

View File

@ -15,6 +15,7 @@
#include <cmath> #include <cmath>
#include <map> #include <map>
#include <deque> #include <deque>
#include <algorithm>
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>
#include <nana/deploy.hpp> #include <nana/deploy.hpp>
#include <nana/gui/place.hpp> #include <nana/gui/place.hpp>
@ -661,13 +662,14 @@ namespace nana
//This is a splitter, it only checks when it is being displayed //This is a splitter, it only checks when it is being displayed
if (dsp) if (dsp)
{ {
//Left field of splitterbar
auto left = this->previous(); auto left = this->previous();
if (left && !left->display) if (left && !left->display)
left->set_display(true); left->set_display(true);
auto right = div_next; //Right field of splitterbar
if (right && !right->display) if (div_next && !div_next->display)
right->set_display(true); div_next->set_display(true);
} }
} }
} }
@ -816,7 +818,7 @@ namespace nana
if ((!child->is_fixed()) && child->max_px.empty() && is_back(child) && (endpos != area.right())) if ((!child->is_fixed()) && child->max_px.empty() && is_back(child) && (endpos != area.right()))
endpos = area.right(); endpos = area.right();
child_area.w_ref() = static_cast<unsigned>(endpos - child_area.x()); child_area.w_ref() = static_cast<unsigned>((std::max)(endpos - child_area.x(), 0));
child->field_area = child_area.result(); child->field_area = child_area.result();
position += child_px; position += child_px;

View File

@ -104,7 +104,7 @@ namespace API
{ {
if (iwd->effect.edge_nimbus == effects::edge_nimbus::none) if (iwd->effect.edge_nimbus == effects::edge_nimbus::none)
{ {
cont.push_back(basic_window::edge_nimbus_action{ iwd, false}); cont.emplace_back(basic_window::edge_nimbus_action{ iwd, false});
} }
iwd->effect.edge_nimbus = static_cast<effects::edge_nimbus>(static_cast<unsigned>(en) | static_cast<unsigned>(iwd->effect.edge_nimbus)); iwd->effect.edge_nimbus = static_cast<effects::edge_nimbus>(static_cast<unsigned>(en) | static_cast<unsigned>(iwd->effect.edge_nimbus));
} }
@ -365,7 +365,7 @@ namespace API
} }
if (!exists) if (!exists)
roots.push_back(root); roots.emplace_back(root);
} }
} }
@ -401,7 +401,7 @@ namespace API
} }
if (!exists) if (!exists)
roots.push_back(root); roots.emplace_back(root);
} }
} }

View File

@ -47,8 +47,7 @@ namespace nana
friend class timer_core; friend class timer_core;
timer_driver() timer_driver() = default;
{}
public: public:
static timer_driver& instance() static timer_driver& instance()
{ {

View File

@ -60,7 +60,7 @@ namespace nana
typedef widget_object<category::root_tag, drawer> base_type; typedef widget_object<category::root_tag, drawer> base_type;
public: public:
tip_form() tip_form()
: base_type(nana::rectangle(), appear::bald<appear::floating>()), : base_type(nullptr, false, rectangle(), appear::bald<appear::floating>()),
duration_(0) duration_(0)
{ {
API::take_active(this->handle(), false, nullptr); API::take_active(this->handle(), false, nullptr);

View File

@ -235,7 +235,7 @@ namespace nana{ namespace drawerbase
if(shortkey) if(shortkey)
{ {
unsigned off_w = (shortkey_pos ? graph.text_extent_size(mbstr.c_str(), static_cast<unsigned>(shortkey_pos)).width : 0); unsigned off_w = (shortkey_pos ? graph.text_extent_size(mbstr.c_str(), shortkey_pos).width : 0);
wchar_t keystr[2] = {nana::utf::char_at(mbstr.c_str() + shortkey_pos, 0, 0), 0}; wchar_t keystr[2] = {nana::utf::char_at(mbstr.c_str() + shortkey_pos, 0, 0), 0};
auto shortkey_size = graph.text_extent_size(keystr, 1); auto shortkey_size = graph.text_extent_size(keystr, 1);
@ -287,14 +287,6 @@ namespace nana{ namespace drawerbase
graph.gradual_rectangle(r, from, to, true); graph.gradual_rectangle(r, from, to, true);
} }
void draw_corner_point(::nana::paint::graphics& graph, const rectangle& r)
{
graph.set_pixel(r.x, r.y);
graph.set_pixel(r.right() - 1, r.y);
graph.set_pixel(r.right() - 1, r.bottom() - 1);
graph.set_pixel(r.x, r.bottom() - 1);
}
void trigger::_m_draw_border(graph_reference graph) void trigger::_m_draw_border(graph_reference graph)
{ {
nana::rectangle r(graph.size()); nana::rectangle r(graph.size());
@ -303,10 +295,13 @@ namespace nana{ namespace drawerbase
graph.frame_rectangle(r, lt, lt, rb, rb); graph.frame_rectangle(r, lt, lt, rb, rb);
graph.palette(false, colors::button_face); graph.palette(false, colors::button_face);
draw_corner_point(graph, r);
paint::draw draw(graph);
draw.corner(r, 1);
graph.palette(false, static_cast<color_rgb>(0x919191)); graph.palette(false, static_cast<color_rgb>(0x919191));
draw_corner_point(graph, r.pare_off(1));
draw.corner(r.pare_off(1), 1);
if (element_state::pressed == attr_.e_state) if (element_state::pressed == attr_.e_state)
graph.rectangle(r, false, static_cast<color_rgb>(0xc3c3c3)); graph.rectangle(r, false, static_cast<color_rgb>(0xc3c3c3));

View File

@ -285,8 +285,7 @@ namespace nana{ namespace drawerbase
} }
}); });
ui_container_.emplace_back(el);
ui_container_.push_back(el);
} }
std::size_t radio_group::checked() const std::size_t radio_group::checked() const

View File

@ -170,11 +170,11 @@ namespace nana
{ {
if(editor_) if(editor_)
{ {
editor_->editable(enb); editor_->editable(enb, false);
editor_->show_caret(enb); editor_->show_caret(enb);
if (!enb) if (!enb)
{ {
editor_->ext_renderer().background = [this](graph_reference graph, const ::nana::rectangle&, const ::nana::color&) editor_->customized_renderers().background = [this](graph_reference graph, const ::nana::rectangle&, const ::nana::color&)
{ {
auto clr_from = colors::button_face_shadow_start; auto clr_from = colors::button_face_shadow_start;
auto clr_to = colors::button_face_shadow_end; auto clr_to = colors::button_face_shadow_end;
@ -190,7 +190,7 @@ namespace nana
}; };
} }
else else
editor_->ext_renderer().background = nullptr; editor_->customized_renderers().background = nullptr;
editor_->enable_background(enb); editor_->enable_background(enb);
editor_->enable_background_counterpart(!enb); editor_->enable_background_counterpart(!enb);

View File

@ -393,7 +393,7 @@ namespace nana
int n = trace_.logic_pos.y * rows + trace_.logic_pos.x + 1; int n = trace_.logic_pos.y * rows + trace_.logic_pos.x + 1;
if (page_mode::date == page) if (page_mode::date == page)
{ {
if (n < 8) return false; //Here is week title bar if (n < 8) return 0; //Here is week title bar
int dw = nana::date::day_of_week(view_month_.year, view_month_.month, 1); int dw = nana::date::day_of_week(view_month_.year, view_month_.month, 1);
n -= (dw ? dw + 7 : 14); n -= (dw ? dw + 7 : 14);
} }

View File

@ -13,6 +13,8 @@
#include <nana/gui/widgets/float_listbox.hpp> #include <nana/gui/widgets/float_listbox.hpp>
#include <nana/gui/widgets/scroll.hpp> #include <nana/gui/widgets/scroll.hpp>
#include <nana/gui/layout_utility.hpp>
namespace nana namespace nana
{ {
namespace drawerbase{ namespace drawerbase{
@ -34,28 +36,20 @@ namespace nana
{ {
if (state == StateHighlighted) if (state == StateHighlighted)
{ {
::nana::color clr(static_cast<color_rgb>(0xafc7e3)); graph.rectangle(r, false, static_cast<color_rgb>(0xafc7e3));
graph.rectangle(r, false, clr);
auto right = r.right() - 1;
auto bottom = r.bottom() - 1;
graph.palette(false, colors::white); graph.palette(false, colors::white);
graph.set_pixel(r.x, r.y);
graph.set_pixel(right, r.y);
graph.set_pixel(r.x, bottom);
graph.set_pixel(right, bottom);
--right; paint::draw draw{ graph };
--bottom; draw.corner(r, 1);
graph.palette(false, clr);
graph.set_pixel(r.x + 1, r.y + 1);
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.palette(false, static_cast<color_rgb>(0xafc7e3));
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); auto inner_r = r;
draw.corner(inner_r.pare_off(1), 1);
graph.rectangle(inner_r, false, static_cast<color_rgb>(0xEBF4FB));
graph.gradual_rectangle(inner_r.pare_off(1), static_cast<color_rgb>(0xDDECFD), static_cast<color_rgb>(0xC2DCFD), true);
} }
else else
graph.rectangle(r, true, colors::white); graph.rectangle(r, true, colors::white);
@ -66,35 +60,7 @@ namespace nana
unsigned vpix = (r.height - 4); unsigned vpix = (r.height - 4);
if(item->image()) if(item->image())
{ {
nana::size imgsz = item->image().size(); auto imgsz = nana::fit_zoom(item->image().size(), {image_pixels_, vpix});
if(imgsz.width > image_pixels_)
{
unsigned new_h = image_pixels_ * imgsz.height / imgsz.width;
if(new_h > vpix)
{
imgsz.width = vpix * imgsz.width / imgsz.height;
imgsz.height = vpix;
}
else
{
imgsz.width = image_pixels_;
imgsz.height = new_h;
}
}
else if(imgsz.height > vpix)
{
unsigned new_w = vpix * imgsz.width / imgsz.height;
if(new_w > image_pixels_)
{
imgsz.height = image_pixels_ * imgsz.height / imgsz.width;
imgsz.width = image_pixels_;
}
else
{
imgsz.height = vpix;
imgsz.width = new_w;
}
}
nana::point to_pos(x, r.y + 2); nana::point to_pos(x, r.y + 2);
to_pos.x += (image_pixels_ - imgsz.width) / 2; to_pos.x += (image_pixels_ - imgsz.width) / 2;
@ -109,7 +75,9 @@ namespace nana
unsigned item_pixels(graph_reference graph) const unsigned item_pixels(graph_reference graph) const
{ {
return graph.text_extent_size(L"jHWn/?\\{[(0569").height + 4; unsigned ascent, descent, ileading;
graph.text_metrics(ascent, descent, ileading);
return ascent + descent + 4;
} }
};//end class item_renderer };//end class item_renderer
@ -187,7 +155,7 @@ namespace nana
--(state_.index); --(state_.index);
else if(recycle) else if(recycle)
{ {
state_.index = static_cast<unsigned>(module_->items.size() - 1); state_.index = module_->items.size() - 1;
state_.offset_y = last_offset_y; state_.offset_y = last_offset_y;
} }
@ -205,7 +173,7 @@ namespace nana
} }
if(state_.index >= state_.offset_y + module_->max_items) if(state_.index >= state_.offset_y + module_->max_items)
state_.offset_y = static_cast<unsigned>(state_.index - module_->max_items + 1); state_.offset_y = state_.index - module_->max_items + 1;
} }
} }
else else

View File

@ -206,15 +206,13 @@ namespace nana
{ {
if(fbp->target.size() || fbp->url.size()) if(fbp->target.size() || fbp->url.size())
{ {
traceable tr; traceable_.emplace_back();
auto & tr = traceable_.back();
tr.r.x = x; tr.r.x = x;
tr.r.y = y; tr.r.y = y;
tr.r.width = sz.width; tr.r.dimension(sz);
tr.r.height = sz.height;
tr.target = fbp->target; tr.target = fbp->target;
tr.url = fbp->url; tr.url = fbp->url;
traceable_.push_back(tr);
} }
} }
@ -331,7 +329,7 @@ namespace nana
px.pixels = def_line_pixels; px.pixels = def_line_pixels;
px.x_base = 0; px.x_base = 0;
rs.pixels.push_back(px); rs.pixels.emplace_back(px);
return 0; return 0;
} }
@ -374,7 +372,7 @@ namespace nana
if(max_ascent < as) max_ascent = as; if(max_ascent < as) max_ascent = as;
if(max_descent < ds) max_descent = ds; if(max_descent < ds) max_descent = ds;
if(max_px < sz.height) max_px = sz.height; if(max_px < sz.height) max_px = sz.height;
line_values.push_back(i); line_values.emplace_back(i);
} }
else else
{ {
@ -393,13 +391,13 @@ namespace nana
px.baseline = max_ascent; px.baseline = max_ascent;
px.values.swap(line_values); px.values.swap(line_values);
rs.pixels.push_back(px); rs.pixels.emplace_back(px);
w = sz.width; w = sz.width;
max_px = sz.height; max_px = sz.height;
max_ascent = as; max_ascent = as;
max_descent = ds; max_descent = ds;
line_values.push_back(i); line_values.emplace_back(i);
} }
else else
{ {
@ -409,9 +407,9 @@ namespace nana
px.pixels = sz.height; px.pixels = sz.height;
px.baseline = as; px.baseline = as;
px.values.push_back(i); px.values.emplace_back(i);
rs.pixels.push_back(px); rs.pixels.emplace_back(px);
max_px = 0; max_px = 0;
max_ascent = max_descent = 0; max_ascent = max_descent = 0;
} }
@ -432,7 +430,7 @@ namespace nana
px.pixels = max_px; px.pixels = max_px;
px.baseline = max_ascent; px.baseline = max_ascent;
px.values.swap(line_values); px.values.swap(line_values);
rs.pixels.push_back(px); rs.pixels.emplace_back(px);
} }
return total_w; return total_w;
} }

View File

@ -32,6 +32,7 @@
#include <nana/system/dataexch.hpp> #include <nana/system/dataexch.hpp>
#include <cassert> #include <cassert>
#include <mutex> #include <mutex>
#include <map>
namespace nana namespace nana
{ {
@ -678,6 +679,16 @@ namespace nana
} }
}; };
struct inline_pane
{
::nana::panel<false> pane_bottom; //pane for pane_widget
::nana::panel<false> pane_widget; //pane for placing user-define widget
std::unique_ptr<inline_notifier_interface> inline_ptr;
inline_indicator * indicator;
index_pair item_pos; //The item index of the inline widget
std::size_t column_pos;
};
class es_lister class es_lister
{ {
public: public:
@ -726,6 +737,40 @@ namespace nana
std::string to_string(const export_options& exp_opt) const; std::string to_string(const export_options& exp_opt) const;
std::vector<inline_pane*> get_inline_pane(const index_pair& item_pos)
{
std::vector<inline_pane*> panes;
for (auto p : active_panes_)
{
if (p && (p->item_pos == item_pos))
{
panes.emplace_back(p);
}
}
return panes;
}
void emit_checked(index_pair pos)
{
item_proxy i(ess_, pos);
arg_listbox arg{ i };
wd_ptr()->events().checked.emit(arg, wd_ptr()->handle());
auto panes = get_inline_pane(pos);
for (auto p : panes)
p->inline_ptr->notify_status(inline_widget_status::checking, i.checked());
}
void emit_selected(index_pair pos)
{
item_proxy i(ess_, pos);
arg_listbox arg{ i };
wd_ptr()->events().selected.emit(arg, wd_ptr()->handle());
auto panes = get_inline_pane(pos);
for (auto p : panes)
p->inline_ptr->notify_status(inline_widget_status::selecting, i.selected());
}
// Definition is provided after struct essence // Definition is provided after struct essence
unsigned column_content_pixels(size_type pos) const; unsigned column_content_pixels(size_type pos) const;
@ -746,7 +791,7 @@ namespace nana
if (cat.model_ptr) if (cat.model_ptr)
{ {
std::sort(bi, ei, [&cat, &weak_ordering_comp, this](std::size_t x, std::size_t y){ std::stable_sort(bi, ei, [&cat, &weak_ordering_comp, this](std::size_t x, std::size_t y){
//The predicate must be a strict weak ordering. //The predicate must be a strict weak ordering.
//!comp(x, y) != comp(x, y) //!comp(x, y) != comp(x, y)
auto & mx = cat.items[x]; auto & mx = cat.items[x];
@ -773,7 +818,7 @@ namespace nana
} }
else else
{ {
std::sort(bi, ei, [&cat, &weak_ordering_comp, this](std::size_t x, std::size_t y){ std::stable_sort(bi, ei, [&cat, &weak_ordering_comp, this](std::size_t x, std::size_t y){
//The predicate must be a strict weak ordering. //The predicate must be a strict weak ordering.
//!comp(x, y) != comp(x, y) //!comp(x, y) != comp(x, y)
@ -804,7 +849,7 @@ namespace nana
{ {
if (cat.model_ptr) if (cat.model_ptr)
{ {
std::sort(std::begin(cat.sorted), std::end(cat.sorted), [&cat, this](std::size_t x, std::size_t y){ std::stable_sort(std::begin(cat.sorted), std::end(cat.sorted), [&cat, this](std::size_t x, std::size_t y){
auto mx_cells = cat.model_ptr->container()->to_cells(x); auto mx_cells = cat.model_ptr->container()->to_cells(x);
auto my_cells = cat.model_ptr->container()->to_cells(y); auto my_cells = cat.model_ptr->container()->to_cells(y);
@ -828,7 +873,7 @@ namespace nana
} }
else else
{ {
std::sort(std::begin(cat.sorted), std::end(cat.sorted), [&cat, this](std::size_t x, std::size_t y){ std::stable_sort(std::begin(cat.sorted), std::end(cat.sorted), [&cat, this](std::size_t x, std::size_t y){
auto & mx = cat.items[x]; auto & mx = cat.items[x];
auto & my = cat.items[y]; auto & my = cat.items[y];
@ -972,6 +1017,7 @@ namespace nana
if (catobj.model_ptr) if (catobj.model_ptr)
{ {
throw_if_immutable_model(catobj.model_ptr.get());
auto container = catobj.model_ptr->container(); auto container = catobj.model_ptr->container();
std::size_t item_index; std::size_t item_index;
// //
@ -1120,6 +1166,14 @@ namespace nana
return get(pos.cat)->items.at(index); return get(pos.cat)->items.at(index);
} }
void append_active_panes(inline_pane* p)
{
if (nullptr == p)
active_panes_.clear();
else
active_panes_.push_back(p);
}
// Removes all items of a specified category // Removes all items of a specified category
// It throws when the category is out of range or has an immutable model. // It throws when the category is out of range or has an immutable model.
void clear(size_type cat) void clear(size_type cat)
@ -1249,28 +1303,17 @@ namespace nana
return n; return n;
} }
std::vector<cell>& get_cells(category_t * cat, std::size_t pos) const std::vector<cell> get_cells(category_t * cat, std::size_t pos) const
{ {
if (!cat) if (!cat)
throw std::out_of_range("nana::listbox: category is null"); throw std::out_of_range("nana::listbox: category is null");
if (cat->model_ptr) if (cat->model_ptr)
throw std::runtime_error("nana::listbox disallow to get item cells, because there are model cells"); return cat->model_ptr->container()->to_cells(pos);
return *(cat->items.at(pos).cells); return *(cat->items.at(pos).cells);
} }
std::vector<cell> get_model_cells(category_t* cat, std::size_t pos) const
{
if (!cat)
throw std::out_of_range("nana::listbox: category is null");
if (!(cat->model_ptr))
throw std::runtime_error("nana::listbox: the category hasn't a model");
return cat->model_ptr->container()->to_cells(pos);
}
void text(category_t* cat, size_type pos, size_type col, cell&& cl, size_type columns) void text(category_t* cat, size_type pos, size_type col, cell&& cl, size_type columns)
{ {
if ((col < columns) && (pos < cat->items.size())) if ((col < columns) && (pos < cat->items.size()))
@ -1462,9 +1505,7 @@ namespace nana
if(m.flags.checked != ck) if(m.flags.checked != ck)
{ {
m.flags.checked = ck; m.flags.checked = ck;
emit_checked(pos);
arg_listbox arg{ item_proxy{ess_, pos}};
wd_ptr()->events().checked.emit(arg, wd_ptr()->handle());
} }
++pos.item; ++pos.item;
} }
@ -1489,10 +1530,15 @@ namespace nana
void select_display_range(index_pair fr_abs, index_pair to_dpl, bool sel) void select_display_range(index_pair fr_abs, index_pair to_dpl, bool sel)
{ {
const auto already_selected = this->pick_items(true);
index_pair fr_dpl (fr_abs.cat, this->display_order(fr_abs.cat, fr_abs.item)); index_pair fr_dpl (fr_abs.cat, this->display_order(fr_abs.cat, fr_abs.item));
if (fr_dpl > to_dpl) if (fr_dpl > to_dpl)
std::swap(fr_dpl, to_dpl); std::swap(fr_dpl, to_dpl);
const auto begin = fr_dpl;
const auto last = to_dpl;
for (; fr_dpl != to_dpl; forward(fr_dpl, 1, fr_dpl)) for (; fr_dpl != to_dpl; forward(fr_dpl, 1, fr_dpl))
{ {
if (fr_dpl.is_item()) if (fr_dpl.is_item())
@ -1501,6 +1547,14 @@ namespace nana
if (to_dpl.is_item()) if (to_dpl.is_item())
item_proxy(ess_, index_pair(to_dpl.cat, absolute( to_dpl ) )).select(sel); item_proxy(ess_, index_pair(to_dpl.cat, absolute( to_dpl ) )).select(sel);
//Unselects the already selected which is out of range [begin, last]
for (auto index : already_selected)
{
index_pair disp_order{ index.cat, this->display_order(index.cat, index.item) };
if (begin > disp_order || disp_order > last)
item_proxy(ess_, index_pair(index.cat, absolute(disp_order))).select(false);
}
} }
bool select_for_all(bool sel) bool select_for_all(bool sel)
@ -1517,8 +1571,7 @@ namespace nana
changed = true; changed = true;
m.flags.selected = sel; m.flags.selected = sel;
arg_listbox arg{ item_proxy(ess_, i) }; this->emit_selected(i);
wd_ptr()->events().selected.emit(arg, wd_ptr()->handle());
if (m.flags.selected) if (m.flags.selected)
last_selected_abs = i; last_selected_abs = i;
@ -1608,18 +1661,17 @@ namespace nana
return (for_selection ? m.flags.selected : m.flags.checked); return (for_selection ? m.flags.selected : m.flags.checked);
}; };
auto do_cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos) auto do_cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos)
{ {
arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) };
if (for_selection) if (for_selection)
{ {
m.flags.selected = false; m.flags.selected = false;
widget_->events().selected.emit(arg, widget_->handle()); this->emit_selected(item_pos);
} }
else else
{ {
m.flags.checked = false; m.flags.checked = false;
widget_->events().checked.emit(arg, widget_->handle()); this->emit_checked(item_pos);
} }
}; };
@ -1631,7 +1683,7 @@ namespace nana
for (auto & m : i->items) for (auto & m : i->items)
{ {
if ((item_pos != except.item) && pred(m)) if ((item_pos != except.item) && pred(m))
do_cancel(m, except.cat, item_pos); do_cancel(m, index_pair{ except.cat, item_pos });
++item_pos; ++item_pos;
} }
@ -1647,7 +1699,7 @@ namespace nana
for (auto & m : cat.items) for (auto & m : cat.items)
{ {
if (pred(m)) if (pred(m))
do_cancel(m, cat_pos, item_pos); do_cancel(m, index_pair{ cat_pos, item_pos });
++item_pos; ++item_pos;
} }
} }
@ -1657,7 +1709,7 @@ namespace nana
for (auto & m : cat.items) for (auto & m : cat.items)
{ {
if ((item_pos != except.item) && pred(m)) if ((item_pos != except.item) && pred(m))
do_cancel(m, cat_pos, item_pos); do_cancel(m, index_pair{ cat_pos, item_pos });
++item_pos; ++item_pos;
} }
} }
@ -1691,18 +1743,17 @@ namespace nana
return (for_selection ? m.flags.selected : m.flags.checked); return (for_selection ? m.flags.selected : m.flags.checked);
}; };
auto cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos) auto cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos)
{ {
arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) };
if (for_selection) if (for_selection)
{ {
m.flags.selected = false; m.flags.selected = false;
widget_->events().selected.emit(arg, widget_->handle()); this->emit_selected(item_pos);
} }
else else
{ {
m.flags.checked = false; m.flags.checked = false;
widget_->events().checked.emit(arg, widget_->handle()); this->emit_checked(item_pos);
} }
}; };
@ -1718,7 +1769,7 @@ namespace nana
for (auto end = cat.items.end(); i != end; ++i) for (auto end = cat.items.end(); i != end; ++i)
{ {
if (pred(*i)) if (pred(*i))
cancel(*i, cat_pos, i - cat.items.begin()); cancel(*i, index_pair{ cat_pos, static_cast<size_type>(i - cat.items.begin()) });
} }
} }
++cat_pos; ++cat_pos;
@ -1741,7 +1792,7 @@ namespace nana
for (++i; i != end; ++i) for (++i; i != end; ++i)
{ {
if (pred(*i)) if (pred(*i))
cancel(*i, cat_pos, i - cat.items.begin()); cancel(*i, index_pair{ cat_pos, static_cast<std::size_t>(i - cat.items.begin()) });
} }
} }
} }
@ -1753,7 +1804,7 @@ namespace nana
for (auto & m : cat.items) for (auto & m : cat.items)
{ {
if (pred(m)) if (pred(m))
cancel(m, cat_pos, item_pos); cancel(m, index_pair{ cat_pos, item_pos });
++item_pos; ++item_pos;
} }
@ -1800,10 +1851,7 @@ namespace nana
if(m.flags.checked != ck) if(m.flags.checked != ck)
{ {
m.flags.checked = ck; m.flags.checked = ck;
this->emit_checked(index_pair{cat, index});
arg_listbox arg{ item_proxy(ess_, index_pair(cat, index)) };
wd_ptr()->events().checked.emit(arg, widget_->handle());
changed = true; changed = true;
} }
++index; ++index;
@ -2059,7 +2107,7 @@ namespace nana
return i; return i;
} }
public: public:
index_pair last_selected_abs, last_selected_dpl; index_pair last_selected_abs;
private: private:
essence * ess_{nullptr}; essence * ess_{nullptr};
nana::listbox * widget_{nullptr}; nana::listbox * widget_{nullptr};
@ -2074,6 +2122,8 @@ namespace nana
bool single_selection_category_limited_{ false }; bool single_selection_category_limited_{ false };
bool single_check_{ false }; bool single_check_{ false };
bool single_check_category_limited_{ false }; bool single_check_category_limited_{ false };
std::vector<inline_pane*> active_panes_;
};//end class es_lister };//end class es_lister
@ -2117,17 +2167,6 @@ namespace nana
}scroll; }scroll;
struct inline_pane
{
::nana::panel<false> pane_bottom; //pane for pane_widget
::nana::panel<false> pane_widget; //pane for placing user-define widget
std::unique_ptr<inline_notifier_interface> inline_ptr;
inline_indicator * indicator;
index_pair item_pos; //The item index of the inline widget
std::size_t column_pos;
::std::string text; //text in UTF-8 encoded
};
std::map<pat::detail::abstract_factory_base*, std::deque<std::unique_ptr<inline_pane>>> inline_table, inline_buffered_table; std::map<pat::detail::abstract_factory_base*, std::deque<std::unique_ptr<inline_pane>>> inline_table, inline_buffered_table;
essence() essence()
@ -2868,8 +2907,8 @@ namespace nana
return *this; return *this;
} }
iresolver::iresolver(const std::vector<cell>& cl) iresolver::iresolver(std::vector<cell> cl)
: cells_(cl) : cells_(std::move(cl))
{} {}
iresolver& iresolver::operator>>(cell& cl) iresolver& iresolver::operator>>(cell& cl)
@ -2973,7 +3012,7 @@ namespace nana
{ {
} }
void attach(index_type pos, essence::inline_pane* pane) void attach(index_type pos, inline_pane* pane)
{ {
for (auto & pn : panes_) for (auto & pn : panes_)
{ {
@ -2997,6 +3036,11 @@ namespace nana
return *ess_->lister.wd_ptr(); return *ess_->lister.wd_ptr();
} }
std::size_t column() const override
{
return column_pos_;
}
void modify(index_type pos, const value_type& value) const override void modify(index_type pos, const value_type& value) const override
{ {
ess_->lister.throw_if_immutable_model(pos); ess_->lister.throw_if_immutable_model(pos);
@ -3009,15 +3053,6 @@ namespace nana
if (cells[column_pos_].text != value) if (cells[column_pos_].text != value)
{ {
for (auto & pn : panes_)
{
if (pn.first == pos)
{
pn.second->text = value;
break;
}
}
cells[column_pos_].text = value; cells[column_pos_].text = value;
if (model_cells.size()) if (model_cells.size())
@ -3049,7 +3084,7 @@ namespace nana
private: private:
essence * const ess_; essence * const ess_;
const std::size_t column_pos_; const std::size_t column_pos_;
std::vector<std::pair<index_type, essence::inline_pane*>> panes_; std::vector<std::pair<index_type, inline_pane*>> panes_;
}; };
void es_lister::scroll(const index_pair& pos, bool to_bottom) void es_lister::scroll(const index_pair& pos, bool to_bottom)
@ -3125,7 +3160,7 @@ namespace nana
void es_lister::move_select(bool upwards, bool unselect_previous, bool trace_selected) void es_lister::move_select(bool upwards, bool unselect_previous, bool trace_selected)
{ {
auto next_selected_dpl = relative_pair ( last_selected_abs); // last_selected_dpl; // ?? auto next_selected_dpl = relative_pair ( last_selected_abs);
if (next_selected_dpl.empty()) // has no cat ? (cat == npos) => beging from first cat if (next_selected_dpl.empty()) // has no cat ? (cat == npos) => beging from first cat
{ {
bool good = false; bool good = false;
@ -3246,7 +3281,7 @@ namespace nana
if (it.selected() != sel) if (it.selected() != sel)
it.select(sel); it.select(sel);
} }
last_selected_abs = last_selected_dpl = index_pair{cat, npos}; last_selected_abs = index_pair{cat, npos};
} }
class drawer_header_impl class drawer_header_impl
@ -3529,15 +3564,19 @@ namespace nana
public: public:
using item_state = essence::item_state; using item_state = essence::item_state;
using parts = essence::parts; using parts = essence::parts;
using status_type = inline_notifier_interface::status_type;
drawer_lister_impl(essence * es) drawer_lister_impl(essence * es)
:essence_(es) :essence_(es)
{} {}
void draw(const nana::rectangle& rect) const void draw(const nana::rectangle& rect)
{ {
internal_scope_guard lock; internal_scope_guard lock;
//clear active panes
essence_->lister.append_active_panes(nullptr);
//The count of items to be drawn //The count of items to be drawn
auto item_count = essence_->number_of_lister_items(true); auto item_count = essence_->number_of_lister_items(true);
if (0 == item_count) if (0 == item_count)
@ -3720,7 +3759,7 @@ namespace nana
nana::color bgcolor, nana::color bgcolor,
nana::color fgcolor, nana::color fgcolor,
item_state state item_state state
) const )
{ {
auto & item = cat.items[item_pos.item]; auto & item = cat.items[item_pos.item];
@ -3834,9 +3873,6 @@ namespace nana
else else
visible_state = false; visible_state = false;
::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height };
inline_wdg->pane_widget.size(sz);
inline_wdg->inline_ptr->resize(sz);
draw_column = inline_wdg->inline_ptr->whether_to_draw(); draw_column = inline_wdg->inline_ptr->whether_to_draw();
@ -3844,25 +3880,24 @@ namespace nana
inline_wdg->column_pos = column_pos; inline_wdg->column_pos = column_pos;
inline_wdg->inline_ptr->activate(*inline_wdg->indicator, item_pos); inline_wdg->inline_ptr->activate(*inline_wdg->indicator, item_pos);
::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height };
inline_wdg->pane_widget.size(sz);
inline_wdg->inline_ptr->resize(sz);
inline_wdg->inline_ptr->notify_status(status_type::selected, item.flags.selected);
inline_wdg->inline_ptr->notify_status(status_type::checked, item.flags.checked);
inline_wdg->indicator->attach(item_pos, inline_wdg); inline_wdg->indicator->attach(item_pos, inline_wdg);
//To reduce the memory usage, the cells may not be allocated //To reduce the memory usage, the cells may not be allocated
if (cells.size() > column_pos) if (cells.size() > column_pos)
{ inline_wdg->inline_ptr->set(cells[column_pos].text);
auto & text = cells[column_pos].text;
if (text != inline_wdg->text)
{
inline_wdg->text = text;
inline_wdg->inline_ptr->set(text);
}
}
else else
{
inline_wdg->text.clear();
inline_wdg->inline_ptr->set({}); inline_wdg->inline_ptr->set({});
}
API::show_window(inline_wdg->pane_bottom, visible_state); API::show_window(inline_wdg->pane_bottom, visible_state);
essence_->lister.append_active_panes(inline_wdg);
} }
} }
@ -3912,18 +3947,20 @@ namespace nana
_m_draw_border(content_r.x, y, show_w); _m_draw_border(content_r.x, y, show_w);
} }
essence::inline_pane * _m_get_inline_pane(const category_t& cat, std::size_t column_pos) const inline_pane * _m_get_inline_pane(const category_t& cat, std::size_t column_pos) const
{ {
if (column_pos < cat.factories.size()) if (column_pos < cat.factories.size())
{ {
auto & factory = cat.factories[column_pos]; auto & factory = cat.factories[column_pos];
if (factory) if (factory)
{
return essence_->open_inline(factory.get(), cat.indicators[column_pos].get()); return essence_->open_inline(factory.get(), cat.indicators[column_pos].get());
}
} }
return nullptr; return nullptr;
} }
essence::inline_pane* _m_find_inline_pane(const index_pair& pos, std::size_t column_pos) const inline_pane* _m_find_inline_pane(const index_pair& pos, std::size_t column_pos) const
{ {
auto & cat = *essence_->lister.get(pos.cat); auto & cat = *essence_->lister.get(pos.cat);
@ -3949,18 +3986,14 @@ namespace nana
void _m_draw_border(int x, int y, unsigned width) const void _m_draw_border(int x, int y, unsigned width) const
{ {
//Draw selecting inner rectangle //Draw selecting inner rectangle
auto graph = essence_->graph; rectangle r{ x, y, width, essence_->scheme_ptr->item_height };
graph->rectangle({ x, y, width, essence_->scheme_ptr->item_height }, false, static_cast<color_rgb>(0x99defd)); essence_->graph->rectangle(r, false, static_cast<color_rgb>(0x99defd));
graph->rectangle({ x + 1, y + 1, width - 2, essence_->scheme_ptr->item_height - 2 }, false, colors::white);
const int right = x + width - 1; essence_->graph->palette(false, colors::white);
const int bottom = y + essence_->scheme_ptr->item_height - 1; paint::draw(*essence_->graph).corner(r, 1);
graph->set_pixel(x, y); essence_->graph->rectangle(r.pare_off(1), false);
graph->set_pixel(x, bottom);
graph->set_pixel(right, y);
graph->set_pixel(right, bottom);
} }
private: private:
essence * const essence_; essence * const essence_;
@ -4164,7 +4197,18 @@ namespace nana
if (!lister.single_selection()) if (!lister.single_selection())
{ {
if (arg.shift) if (arg.shift)
lister.select_display_range(lister.last_selected_abs , item_pos, sel); {
//Set the first item as the begin of selected item if there
//is not a last selected item.(#154 reported by RenaudAlpes)
if (lister.last_selected_abs.empty() || lister.last_selected_abs.is_category())
lister.last_selected_abs.set_both(0);
auto before = lister.last_selected_abs;
lister.select_display_range(lister.last_selected_abs, item_pos, sel);
lister.last_selected_abs = before;
}
else if (arg.ctrl) else if (arg.ctrl)
sel = !item_proxy(essence_, abs_item_pos).selected(); sel = !item_proxy(essence_, abs_item_pos).selected();
else else
@ -4180,19 +4224,20 @@ namespace nana
if(item_ptr) if(item_ptr)
{ {
item_ptr->flags.selected = sel; if (item_ptr->flags.selected != sel)
arg_listbox arg{ item_proxy{ essence_, abs_item_pos } };
lister.wd_ptr()->events().selected.emit(arg, lister.wd_ptr()->handle());
if (item_ptr->flags.selected)
{ {
lister.cancel_others_if_single_enabled(true, abs_item_pos); item_ptr->flags.selected = sel;
essence_->lister.last_selected_abs = abs_item_pos;
lister.emit_selected(abs_item_pos);
if (item_ptr->flags.selected)
{
lister.cancel_others_if_single_enabled(true, abs_item_pos);
essence_->lister.last_selected_abs = abs_item_pos;
}
else if (essence_->lister.last_selected_abs == abs_item_pos)
essence_->lister.last_selected_abs.set_both(npos);
} }
else if (essence_->lister.last_selected_abs == abs_item_pos)
essence_->lister.last_selected_abs.set_both(npos);
} }
else if(!lister.single_selection()) else if(!lister.single_selection())
lister.categ_selected(item_pos.cat, true); lister.categ_selected(item_pos.cat, true);
@ -4203,8 +4248,7 @@ namespace nana
{ {
item_ptr->flags.checked = ! item_ptr->flags.checked; item_ptr->flags.checked = ! item_ptr->flags.checked;
arg_listbox arg{ item_proxy{ essence_, abs_item_pos } }; lister.emit_checked(abs_item_pos);
lister.wd_ptr()->events().checked.emit(arg, lister.wd_ptr()->handle());
if (item_ptr->flags.checked) if (item_ptr->flags.checked)
lister.cancel_others_if_single_enabled(false, abs_item_pos); lister.cancel_others_if_single_enabled(false, abs_item_pos);
@ -4469,12 +4513,13 @@ namespace nana
item_proxy & item_proxy::check(bool ck) item_proxy & item_proxy::check(bool ck)
{ {
internal_scope_guard lock;
auto & m = cat_->items.at(pos_.item); auto & m = cat_->items.at(pos_.item);
if(m.flags.checked != ck) if(m.flags.checked != ck)
{ {
m.flags.checked = ck; m.flags.checked = ck;
arg_listbox arg{*this}; ess_->lister.emit_checked(pos_);
ess_->lister.wd_ptr()->events().checked.emit(arg, ess_->lister.wd_ptr()->handle());
ess_->update(); ess_->update();
} }
return *this; return *this;
@ -4488,13 +4533,14 @@ namespace nana
/// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected /// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected
item_proxy & item_proxy::select(bool s) item_proxy & item_proxy::select(bool s)
{ {
internal_scope_guard lock;
//pos_ never represents a category if this item_proxy is available. //pos_ never represents a category if this item_proxy is available.
auto & m = cat_->items.at(pos_.item); // a ref to the real item auto & m = cat_->items.at(pos_.item); // a ref to the real item
if(m.flags.selected == s) return *this; // ignore if no change if(m.flags.selected == s) return *this; // ignore if no change
m.flags.selected = s; // actually change selection m.flags.selected = s; // actually change selection
arg_listbox arg{*this}; ess_->lister.emit_selected(this->pos_);
ess_->lister.wd_ptr()->events().selected.emit(arg, ess_->lister.wd_ptr()->handle());
if (m.flags.selected) if (m.flags.selected)
{ {
@ -4565,14 +4611,6 @@ namespace nana
std::string item_proxy::text(size_type col) const std::string item_proxy::text(size_type col) const
{ {
if (cat_->model_ptr)
{
auto cells = cat_->model_ptr->container()->to_cells(pos_.item);
if (col < cells.size())
return cells[col].text;
return{};
}
return ess_->lister.get_cells(cat_, pos_.item).at(col).text; return ess_->lister.get_cells(cat_, pos_.item).at(col).text;
} }
@ -4692,7 +4730,7 @@ namespace nana
return pos_; return pos_;
} }
auto item_proxy::_m_cells() const -> std::vector<cell>& auto item_proxy::_m_cells() const -> std::vector<cell>
{ {
return ess_->lister.get_cells(cat_, pos_.item); return ess_->lister.get_cells(cat_, pos_.item);
} }
@ -4771,10 +4809,11 @@ namespace nana
for (item_proxy &it : *this ) for (item_proxy &it : *this )
it.select(sel); it.select(sel);
ess_->lister.last_selected_abs = ess_->lister.last_selected_dpl = index_pair {this->pos_, npos}; ess_->lister.last_selected_abs = index_pair {this->pos_, npos};
return *this; return *this;
} }
bool cat_proxy::selected() const bool cat_proxy::selected() const
{ {
for (item_proxy &it : *this ) for (item_proxy &it : *this )
@ -5027,9 +5066,24 @@ namespace nana
internal_scope_guard lock; internal_scope_guard lock;
cat_->sorted.push_back(cat_->items.size()); if (cat_->model_ptr)
cells.resize(columns()); {
cat_->items.emplace_back(std::move(cells)); es_lister::throw_if_immutable_model(cat_->model_ptr.get());
auto container = cat_->model_ptr->container();
auto item_index = container->size();
cat_->items.emplace_back();
container->emplace_back();
container->assign(item_index, cells);
}
else
{
cat_->sorted.push_back(cat_->items.size());
cells.resize(columns());
cat_->items.emplace_back(std::move(cells));
}
assign_colors_for_last(ess_, cat_); assign_colors_for_last(ess_, cat_);
} }

View File

@ -18,6 +18,7 @@
#include <nana/gui/wvl.hpp> #include <nana/gui/wvl.hpp>
#include <nana/paint/text_renderer.hpp> #include <nana/paint/text_renderer.hpp>
#include <cctype> //introduces tolower #include <cctype> //introduces tolower
#include <map>
namespace nana namespace nana
{ {
@ -113,19 +114,15 @@ namespace nana
void item(graph_reference graph, const nana::rectangle& r, const attr& at) void item(graph_reference graph, const nana::rectangle& r, const attr& at)
{ {
if (!at.enabled)
return;
if(at.item_state == state::active) if(at.item_state == state::active)
{ {
graph.rectangle(r, false, static_cast<color_rgb>(0xa8d8eb)); graph.rectangle(r, false, static_cast<color_rgb>(0xa8d8eb));
nana::point points[4] = {
nana::point(r.x, r.y),
nana::point(r.x + r.width - 1, r.y),
nana::point(r.x, r.y + r.height - 1),
nana::point(r.x + r.width - 1, r.y + r.height - 1)
};
graph.palette(false, static_cast<color_rgb>(0xc0ddfc)); graph.palette(false, static_cast<color_rgb>(0xc0ddfc));
for(int i = 0; i < 4; ++i) paint::draw(graph).corner(r, 1);
graph.set_pixel(points[i].x, points[i].y);
if(at.enabled) if(at.enabled)
graph.gradual_rectangle(nana::rectangle(r).pare_off(1), static_cast<color_rgb>(0xE8F0F4), static_cast<color_rgb>(0xDBECF4), true); graph.gradual_rectangle(nana::rectangle(r).pare_off(1), static_cast<color_rgb>(0xE8F0F4), static_cast<color_rgb>(0xDBECF4), true);
@ -271,7 +268,7 @@ namespace nana
if(item.sub_menu == nullptr) if(item.sub_menu == nullptr)
{ {
item.sub_menu = &sub; item.sub_menu = &sub;
sub.owner.push_back(&root_); sub.owner.emplace_back(&root_);
return true; return true;
} }
} }
@ -479,7 +476,7 @@ namespace nana
--pos; --pos;
} }
if(! menu_->items.at(pos).flags.splitter) if(! menu_->items.at(pos).flags.splitter && menu_->items.at(pos).flags.enabled)
break; break;
} }
@ -785,9 +782,8 @@ namespace nana
{ {
if (event_code::mouse_down == arg.evt_code) if (event_code::mouse_down == arg.evt_code)
_m_open_sub(0); //Try to open submenu immediately _m_open_sub(0); //Try to open submenu immediately
else if (event_code::mouse_up == arg.evt_code) else if ((event_code::mouse_up == arg.evt_code) && (mouse::left_button == arg.button))
if (arg.button == ::nana::mouse::left_button) pick();
pick();
}; };
events.mouse_down.connect_unignorable(fn); events.mouse_down.connect_unignorable(fn);
@ -885,48 +881,45 @@ namespace nana
return; return;
menu_item_type & item = menu->items.at(active); menu_item_type & item = menu->items.at(active);
if (item.flags.splitter == false && item.sub_menu == nullptr)
if ((!item.flags.enabled) || item.flags.splitter || item.sub_menu)
return;
if (checks::highlight == item.style)
{ {
//There is a situation that menu will not call functor if the item style is check_option item.flags.checked = !item.flags.checked;
//and it is checked before clicking. }
bool call_functor = true; else if (checks::option == item.style)
{
if (checks::highlight == item.style) //Forward Looks for a splitter
auto pos = active;
while (pos)
{ {
item.flags.checked = !item.flags.checked; if (menu->items.at(--pos).flags.splitter)
} break;
else if (checks::option == item.style)
{
//Forward Looks for a splitter
auto pos = active;
while (pos)
{
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; for (; pos < menu->items.size(); ++pos)
//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); menu_item_type & im = menu->items.at(pos);
item.functor.operator()(ip); 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 (item.functor)
{
item_type::item_proxy ip(active, item);
item.functor.operator()(ip);
} }
} }
private: private:

View File

@ -55,7 +55,7 @@ namespace nana
void append(const native_string_type& text, unsigned long shortkey) void append(const native_string_type& text, unsigned long shortkey)
{ {
if(shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41); if(shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41);
cont_.push_back(new item_type(text, shortkey)); cont_.emplace_back(new item_type(text, shortkey));
} }
std::size_t find(unsigned long shortkey) const std::size_t find(unsigned long shortkey) const
@ -112,13 +112,9 @@ namespace nana
nana::rectangle r(pos, size); nana::rectangle r(pos, size);
graph_.rectangle(r, false, border); graph_.rectangle(r, false, border);
int right = pos.x + static_cast<int>(size.width) - 1;
int bottom = pos.y + static_cast<int>(size.height) - 1;
graph_.palette(false, corner); graph_.palette(false, corner);
graph_.set_pixel(pos.x, pos.y);
graph_.set_pixel(right, pos.y); paint::draw{ graph_ }.corner(r, 1);
graph_.set_pixel(pos.x, bottom);
graph_.set_pixel(right, bottom);
graph_.rectangle(r.pare_off(1), true, body); graph_.rectangle(r.pare_off(1), true, body);
} }
@ -216,7 +212,7 @@ namespace nana
if (hotkey) if (hotkey)
{ {
unsigned off_w = (hotkey_pos ? graph.text_extent_size(text.c_str(), static_cast<unsigned>(hotkey_pos)).width : 0); unsigned off_w = (hotkey_pos ? graph.text_extent_size(text.c_str(), hotkey_pos).width : 0);
nana::size hotkey_size = graph.text_extent_size(text.c_str() + hotkey_pos, 1); nana::size hotkey_size = graph.text_extent_size(text.c_str() + hotkey_pos, 1);
unsigned ascent, descent, inleading; unsigned ascent, descent, inleading;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include <nana/gui/widgets/slider.hpp> #include <nana/gui/widgets/slider.hpp>
#include <nana/paint/pixel_buffer.hpp>
#include <cstring> //memcpy #include <cstring> //memcpy
namespace nana namespace nana
@ -645,7 +646,6 @@ namespace nana
{ {
adorn.bound.x = static_cast<int>(attr_.adorn_pos + attr_.slider.border_weight + bar.area.y); adorn.bound.x = static_cast<int>(attr_.adorn_pos + attr_.slider.border_weight + bar.area.y);
adorn.bound.y = static_cast<int>(graph.height()) - static_cast<int>(attr_.slider.border_weight + bar.area.y); adorn.bound.y = static_cast<int>(graph.height()) - static_cast<int>(attr_.slider.border_weight + bar.area.y);
//adorn.bound.x =
} }
else else
{ {

View File

@ -607,7 +607,7 @@ namespace nana
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().impl()->editor(); auto editor = get_drawer_trigger().impl()->editor();
if (editor) if (editor)
editor->editable(accept); editor->editable(accept, false);
} }
bool spinbox::editable() const bool spinbox::editable() const

View File

@ -748,14 +748,13 @@ namespace nana
bool _m_add_tab(std::size_t pos) bool _m_add_tab(std::size_t pos)
{ {
item_t m;
if((pos == npos) || (pos >= list_.size())) if((pos == npos) || (pos >= list_.size()))
{ {
this->list_.push_back(m); this->list_.emplace_back();
pos = static_cast<unsigned>(list_.size() - 1); pos = list_.size() - 1;
} }
else else
list_.insert(iterator_at(pos), m); list_.emplace(iterator_at(pos));
basis_.active = pos; basis_.active = pos;
if(evt_agent_) if(evt_agent_)
@ -1505,7 +1504,7 @@ namespace nana
for (auto & m : items) for (auto & m : items)
{ {
auto ts = graph.bidi_extent_size(m.text); auto ts = graph.bidi_extent_size(m.text);
pxs.push_back(ts.width + 12); pxs.emplace_back(ts.width + 12);
pixels += ts.width + 12; pixels += ts.width + 12;
} }

View File

@ -65,7 +65,6 @@ namespace drawerbase {
{ {
auto wd = wdg.handle(); auto wd = wdg.handle();
widget_ = &wdg; widget_ = &wdg;
evt_agent_.reset(new event_agent(static_cast<::nana::textbox&>(wdg), editor_->text_position()));
auto scheme = API::dev::get_scheme(wdg); auto scheme = API::dev::get_scheme(wdg);
@ -73,6 +72,8 @@ namespace drawerbase {
editor_->textbase().set_event_agent(evt_agent_.get()); editor_->textbase().set_event_agent(evt_agent_.get());
editor_->set_event(evt_agent_.get()); editor_->set_event(evt_agent_.get());
evt_agent_.reset(new event_agent(static_cast<::nana::textbox&>(wdg), editor_->text_position()));
_m_text_area(graph.width(), graph.height()); _m_text_area(graph.width(), graph.height());
API::tabstop(wd); API::tabstop(wd);
@ -344,8 +345,8 @@ namespace drawerbase {
{ {
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
internal_scope_guard lock; internal_scope_guard lock;
if (editor) if (editor && editor->move_caret(pos, true))
editor->move_caret(pos); API::refresh_window(handle());
return *this; return *this;
} }
@ -414,7 +415,16 @@ namespace drawerbase {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if(editor) if(editor)
editor->editable(able); editor->editable(able, false);
return *this;
}
textbox& textbox::enable_caret()
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
editor->editable(editor->attr().editable, true);
return *this; return *this;
} }
@ -459,6 +469,18 @@ namespace drawerbase {
API::update_window(*this); API::update_window(*this);
} }
std::pair<upoint, upoint> textbox::selection() const
{
std::pair<upoint, upoint> points;
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
editor->get_select_points(points.first, points.second);
return points;
}
void textbox::copy() const void textbox::copy() const
{ {
internal_scope_guard lock; internal_scope_guard lock;
@ -606,6 +628,14 @@ namespace drawerbase {
editor->select_behavior(move_to_end); editor->select_behavior(move_to_end);
} }
void textbox::set_undo_queue_length(std::size_t len)
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
editor->set_undo_queue_length(len);
}
//Override _m_caption for caption() //Override _m_caption for caption()
auto textbox::_m_caption() const throw() -> native_string_type auto textbox::_m_caption() const throw() -> native_string_type
{ {

View File

@ -15,6 +15,7 @@
#include <nana/gui/layout_utility.hpp> #include <nana/gui/layout_utility.hpp>
#include <nana/system/platform.hpp> #include <nana/system/platform.hpp>
#include <stdexcept> #include <stdexcept>
#include <map>
namespace nana namespace nana
{ {

View File

@ -382,12 +382,6 @@ namespace nana
} }
//class widget_base //class widget_base
widget_base::~widget_base()
{
if (handle_)
API::close_window(handle_);
}
window widget_base::handle() const window widget_base::handle() const
{ {
return handle_; return handle_;

View File

@ -13,7 +13,7 @@
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>
#include <nana/internationalization.hpp> #include <nana/internationalization.hpp>
#include <nana/gui/widgets/widget.hpp> #include <nana/gui/programming_interface.hpp>
#include <unordered_map> #include <unordered_map>
#include <fstream> #include <fstream>
@ -486,32 +486,22 @@ namespace nana
void i18n_eval::_m_add_args(std::string& str) void i18n_eval::_m_add_args(std::string& str)
{ {
args_.emplace_back(new arg_string(nana::charset(str))); args_.emplace_back(new arg_string(str));
} }
void i18n_eval::_m_add_args(const std::string& str) void i18n_eval::_m_add_args(const std::string& str)
{ {
args_.emplace_back(new arg_string(nana::charset(str))); args_.emplace_back(new arg_string(str));
} }
void i18n_eval::_m_add_args(std::string&& str) void i18n_eval::_m_add_args(std::string&& str)
{ {
args_.emplace_back(new arg_string(nana::charset(std::move(str)))); args_.emplace_back(new arg_string(std::move(str)));
}
void i18n_eval::_m_add_args(std::wstring& str)
{
args_.emplace_back(new arg_string(nana::charset(str)));
} }
void i18n_eval::_m_add_args(const std::wstring& str) void i18n_eval::_m_add_args(const std::wstring& str)
{ {
args_.emplace_back(new arg_string(nana::charset(str))); args_.emplace_back(new arg_string(to_utf8(str)));
}
void i18n_eval::_m_add_args(std::wstring&& str)
{
args_.emplace_back(new arg_string(nana::charset(std::move(str))));
} }
//end class i18n_eval //end class i18n_eval
} }

View File

@ -140,13 +140,13 @@ namespace paint
unsigned font::height() const unsigned font::height() const
{ {
if(empty()) return false; if(empty()) return 0;
return (impl_->font_ptr->height); return (impl_->font_ptr->height);
} }
unsigned font::weight() const unsigned font::weight() const
{ {
if(empty()) return false; if(empty()) return 0;
return (impl_->font_ptr->weight); return (impl_->font_ptr->weight);
} }
@ -194,76 +194,106 @@ namespace paint
//end class font //end class font
//class graphics //class graphics
struct graphics::implementation
{
std::shared_ptr<::nana::detail::drawable_impl_type> platform_drawable;
font font_shadow;
drawable_type handle{ nullptr };
::nana::size size;
pixel_buffer pxbuf;
bool changed{ false };
};
graphics::graphics() graphics::graphics()
:handle_(nullptr), changed_(false) : impl_(new implementation)
{} {}
graphics::graphics(const nana::size& sz) graphics::graphics(const nana::size& sz)
:handle_(nullptr), changed_(true) : impl_(new implementation)
{ {
make(sz); make(sz);
} }
graphics::graphics(const graphics& rhs) graphics::graphics(const graphics& rhs)
:dwptr_(rhs.dwptr_), handle_(rhs.handle_), size_(rhs.size_), changed_(true) : impl_(new implementation(*rhs.impl_))
{} {}
graphics& graphics::operator=(const graphics& rhs) graphics& graphics::operator=(const graphics& rhs)
{ {
if(this != &rhs) if(this != &rhs)
{ {
size_ = rhs.size_; *impl_ = *rhs.impl_;
dwptr_ = rhs.dwptr_; impl_->changed = true;
handle_ = rhs.handle_;
if(changed_ == false) changed_ = true;
} }
return *this; return *this;
} }
bool graphics::changed() const
graphics::graphics(graphics&& other)
: impl_(std::move(other.impl_))
{ {
return this->changed_;
} }
bool graphics::empty() const { return (handle_ == nullptr); } graphics& graphics::operator=(graphics&& other)
{
if (this != &other)
impl_ = std::move(other.impl_);
return *this;
}
graphics::~graphics()
{
//For instance of unique_ptr pimpl
}
bool graphics::changed() const
{
return impl_->changed;
}
bool graphics::empty() const
{
return (!impl_->handle);
}
graphics::operator const void *() const graphics::operator const void *() const
{ {
return handle_; return impl_->handle;
} }
drawable_type graphics::handle() const drawable_type graphics::handle() const
{ {
return handle_; return impl_->handle;
} }
const void* graphics::pixmap() const const void* graphics::pixmap() const
{ {
//The reinterpret_cast is used for same platform. Under Windows, the type //The reinterpret_cast is used for same platform. Under Windows, the type
//of pixmap can be conversed into void* directly, but under X11, the type is not a pointer. //of pixmap can be conversed into void* directly, but under X11, the type is not a pointer.
return (handle_? reinterpret_cast<void*>(handle_->pixmap) : nullptr); return (impl_->handle ? reinterpret_cast<void*>(impl_->handle->pixmap) : nullptr);
} }
const void* graphics::context() const const void* graphics::context() const
{ {
return (handle_? handle_->context : nullptr); return (impl_->handle ? impl_->handle->context : nullptr);
} }
void graphics::make(const ::nana::size& sz) void graphics::make(const ::nana::size& sz)
{ {
if(handle_ == nullptr || size_ != sz) if(impl_->handle == nullptr || impl_->size != sz)
{ {
//The object will be delete while dwptr_ is performing a release. //The object will be delete while dwptr_ is performing a release.
drawable_type dw = new nana::detail::drawable_impl_type; drawable_type dw = new nana::detail::drawable_impl_type;
//Reuse the old font //Reuse the old font
if(dwptr_) if(impl_->platform_drawable)
{ {
drawable_type reuse = dwptr_.get(); drawable_type reuse = impl_->platform_drawable.get();
dw->font = reuse->font; dw->font = reuse->font;
dw->string.tab_length = reuse->string.tab_length; dw->string.tab_length = reuse->string.tab_length;
} }
else else
dw->font = font_shadow_.impl_->font_ptr; dw->font = impl_->font_shadow.impl_->font_ptr;
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
HDC hdc = ::GetDC(0); HDC hdc = ::GetDC(0);
@ -319,21 +349,22 @@ namespace paint
#else #else
dw->update_text_color(); dw->update_text_color();
#endif #endif
dwptr_.reset(dw, detail::drawable_deleter{}); impl_->platform_drawable.reset(dw, detail::drawable_deleter{});
handle_ = dw; impl_->handle = dw;
size_ = sz; impl_->size = sz;
handle_->string.tab_pixels = detail::raw_text_extent_size(handle_, L"\t", 1).width; impl_->handle->string.tab_pixels = detail::raw_text_extent_size(impl_->handle, L"\t", 1).width;
handle_->string.whitespace_pixels = detail::raw_text_extent_size(handle_, L" ", 1).width; impl_->handle->string.whitespace_pixels = detail::raw_text_extent_size(impl_->handle, L" ", 1).width;
} }
} }
if(changed_ == false) changed_ = true; if(impl_->changed == false)
impl_->changed = true;
} }
void graphics::resize(const ::nana::size& sz) void graphics::resize(const ::nana::size& sz)
{ {
graphics duplicate(*this); graphics duplicate(std::move(*this));
make(sz); make(sz);
bitblt(0, 0, duplicate); bitblt(0, 0, duplicate);
} }
@ -342,16 +373,18 @@ namespace paint
{ {
//Keep the font as a shadow, even if the graphics is empty. Setting the font is futile when the size //Keep the font as a shadow, even if the graphics is empty. Setting the font is futile when the size
//of a widget is zero. //of a widget is zero.
font_shadow_ = f; impl_->font_shadow = f;
if(handle_ && (false == f.empty())) if(impl_->handle && (false == f.empty()))
{ {
handle_->font = f.impl_->font_ptr; impl_->handle->font = f.impl_->font_ptr;
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::SelectObject(handle_->context, reinterpret_cast<HFONT>(f.impl_->font_ptr->handle)); ::SelectObject(impl_->handle->context, reinterpret_cast<HFONT>(f.impl_->font_ptr->handle));
#endif #endif
handle_->string.tab_pixels = detail::raw_text_extent_size(handle_, L"\t", 1).width; impl_->handle->string.tab_pixels = detail::raw_text_extent_size(impl_->handle, L"\t", 1).width;
handle_->string.whitespace_pixels = detail::raw_text_extent_size(handle_, L" ", 1).width; impl_->handle->string.whitespace_pixels = detail::raw_text_extent_size(impl_->handle, L" ", 1).width;
if(changed_ == false) changed_ = true;
if (impl_->changed == false)
impl_->changed = true;
} }
} }
@ -359,7 +392,7 @@ namespace paint
{ {
//The font may be set when the graphics is still empty. //The font may be set when the graphics is still empty.
//it should return the shadow font when the graphics is empty. //it should return the shadow font when the graphics is empty.
return (handle_ ? font(handle_) : font_shadow_); return (impl_->handle ? font(impl_->handle) : impl_->font_shadow);
} }
::nana::size graphics::text_extent_size(const ::std::string& text) const ::nana::size graphics::text_extent_size(const ::std::string& text) const
@ -385,26 +418,26 @@ namespace paint
nana::size graphics::text_extent_size(const wchar_t* str, std::size_t len) const nana::size graphics::text_extent_size(const wchar_t* str, std::size_t len) const
{ {
return detail::text_extent_size(handle_, str, len); return detail::text_extent_size(impl_->handle, str, len);
} }
nana::size graphics::text_extent_size(const std::wstring& str, std::size_t len) const nana::size graphics::text_extent_size(const std::wstring& str, std::size_t len) const
{ {
return detail::text_extent_size(handle_, str.c_str(), len); return detail::text_extent_size(impl_->handle, str.c_str(), len);
} }
nana::size graphics::glyph_extent_size(const wchar_t * str, std::size_t len, std::size_t begin, std::size_t end) const nana::size graphics::glyph_extent_size(const wchar_t * str, std::size_t len, std::size_t begin, std::size_t end) const
{ {
if(len < end) end = len; if(len < end) end = len;
if (nullptr == handle_ || nullptr == str || 0 == len || begin >= end) return{}; if (nullptr == impl_->handle || nullptr == str || 0 == len || begin >= end) return{};
nana::size sz; nana::size sz;
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
int * dx = new int[len]; int * dx = new int[len];
SIZE extents; SIZE extents;
::GetTextExtentExPoint(handle_->context, str, static_cast<int>(len), 0, 0, dx, &extents); ::GetTextExtentExPoint(impl_->handle->context, str, static_cast<int>(len), 0, 0, dx, &extents);
sz.width = dx[end - 1] - (begin ? dx[begin - 1] : 0); sz.width = dx[end - 1] - (begin ? dx[begin - 1] : 0);
unsigned tab_pixels = handle_->string.tab_length * handle_->string.whitespace_pixels; unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels;
const wchar_t * pend = str + end; const wchar_t * pend = str + end;
for(const wchar_t * p = str + begin; p != pend; ++p) for(const wchar_t * p = str + begin; p != pend; ++p)
{ {
@ -426,14 +459,14 @@ namespace paint
bool graphics::glyph_pixels(const wchar_t * str, std::size_t len, unsigned* pxbuf) const bool graphics::glyph_pixels(const wchar_t * str, std::size_t len, unsigned* pxbuf) const
{ {
if(nullptr == handle_ || nullptr == handle_->context || nullptr == str || nullptr == pxbuf) return false; if(nullptr == impl_->handle || nullptr == impl_->handle->context || nullptr == str || nullptr == pxbuf) return false;
if(len == 0) return true; if(len == 0) return true;
unsigned tab_pixels = handle_->string.tab_length * handle_->string.whitespace_pixels; unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels;
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
int * dx = new int[len]; int * dx = new int[len];
SIZE extents; SIZE extents;
::GetTextExtentExPoint(handle_->context, str, static_cast<int>(len), 0, 0, dx, &extents); ::GetTextExtentExPoint(impl_->handle->context, str, static_cast<int>(len), 0, 0, dx, &extents);
pxbuf[0] = (str[0] == '\t' ? tab_pixels : dx[0]); pxbuf[0] = (str[0] == '\t' ? tab_pixels : dx[0]);
@ -445,7 +478,7 @@ namespace paint
#elif defined(NANA_X11) && defined(NANA_USE_XFT) #elif defined(NANA_X11) && defined(NANA_USE_XFT)
Display * disp = nana::detail::platform_spec::instance().open_display(); Display * disp = nana::detail::platform_spec::instance().open_display();
XftFont * xft = handle_->font->handle; XftFont * xft = impl_->handle->font->handle;
XGlyphInfo extents; XGlyphInfo extents;
for(std::size_t i = 0; i < len; ++i) for(std::size_t i = 0; i < len; ++i)
@ -466,7 +499,7 @@ namespace paint
nana::size graphics::bidi_extent_size(const std::wstring& str) const nana::size graphics::bidi_extent_size(const std::wstring& str) const
{ {
nana::size sz; nana::size sz;
if(handle_ && handle_->context && str.size()) if(impl_->handle && impl_->handle->context && str.size())
{ {
std::vector<unicode_bidi::entity> reordered; std::vector<unicode_bidi::entity> reordered;
unicode_bidi bidi; unicode_bidi bidi;
@ -489,25 +522,25 @@ namespace paint
bool graphics::text_metrics(unsigned & ascent, unsigned& descent, unsigned& internal_leading) const bool graphics::text_metrics(unsigned & ascent, unsigned& descent, unsigned& internal_leading) const
{ {
if(handle_) if(impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::TEXTMETRIC tm; ::TEXTMETRIC tm;
::GetTextMetrics(handle_->context, &tm); ::GetTextMetrics(impl_->handle->context, &tm);
ascent = static_cast<unsigned>(tm.tmAscent); ascent = static_cast<unsigned>(tm.tmAscent);
descent = static_cast<unsigned>(tm.tmDescent); descent = static_cast<unsigned>(tm.tmDescent);
internal_leading = static_cast<unsigned>(tm.tmInternalLeading); internal_leading = static_cast<unsigned>(tm.tmInternalLeading);
return true; return true;
#elif defined(NANA_X11) #elif defined(NANA_X11)
if(handle_->font) if(impl_->handle->font)
{ {
#if defined(NANA_USE_XFT) #if defined(NANA_USE_XFT)
XftFont * fs = reinterpret_cast<XftFont*>(handle_->font->handle); XftFont * fs = reinterpret_cast<XftFont*>(impl_->handle->font->handle);
ascent = fs->ascent; ascent = fs->ascent;
descent = fs->descent; descent = fs->descent;
internal_leading = 0; internal_leading = 0;
#else #else
XFontSet fs = reinterpret_cast<XFontSet>(handle_->font->handle); XFontSet fs = reinterpret_cast<XFontSet>(impl_->handle->font->handle);
XFontSetExtents * ext = ::XExtentsOfFontSet(fs); XFontSetExtents * ext = ::XExtentsOfFontSet(fs);
XFontStruct ** fontstructs; XFontStruct ** fontstructs;
char ** font_names; char ** font_names;
@ -532,13 +565,13 @@ namespace paint
void graphics::line_begin(int x, int y) void graphics::line_begin(int x, int y)
{ {
if(!handle_) return; if(!impl_->handle) return;
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::MoveToEx(handle_->context, x, y, 0); ::MoveToEx(impl_->handle->context, x, y, 0);
#elif defined(NANA_X11) #elif defined(NANA_X11)
handle_->line_begin_pos.x = x; impl_->handle->line_begin_pos.x = x;
handle_->line_begin_pos.y = y; impl_->handle->line_begin_pos.y = y;
#endif #endif
} }
@ -552,94 +585,94 @@ namespace paint
void graphics::bitblt(const nana::rectangle& r_dst, native_window_type src) void graphics::bitblt(const nana::rectangle& r_dst, native_window_type src)
{ {
if(handle_) if(impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
HDC dc = ::GetDC(reinterpret_cast<HWND>(src)); HDC dc = ::GetDC(reinterpret_cast<HWND>(src));
::BitBlt(handle_->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, dc, 0, 0, SRCCOPY); ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, dc, 0, 0, SRCCOPY);
::ReleaseDC(reinterpret_cast<HWND>(src), dc); ::ReleaseDC(reinterpret_cast<HWND>(src), dc);
#elif defined(NANA_X11) #elif defined(NANA_X11)
::XCopyArea(nana::detail::platform_spec::instance().open_display(), ::XCopyArea(nana::detail::platform_spec::instance().open_display(),
reinterpret_cast<Window>(src), handle_->pixmap, handle_->context, reinterpret_cast<Window>(src), impl_->handle->pixmap, impl_->handle->context,
0, 0, r_dst.width, r_dst.height, r_dst.x, r_dst.y); 0, 0, r_dst.width, r_dst.height, r_dst.x, r_dst.y);
#endif #endif
if(changed_ == false) changed_ = true; if(impl_->changed == false) impl_->changed = true;
} }
} }
void graphics::bitblt(const nana::rectangle& r_dst, native_window_type src, const nana::point& p_src) void graphics::bitblt(const nana::rectangle& r_dst, native_window_type src, const nana::point& p_src)
{ {
if(handle_) if(impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
HDC dc = ::GetDC(reinterpret_cast<HWND>(src)); HDC dc = ::GetDC(reinterpret_cast<HWND>(src));
::BitBlt(handle_->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, dc, p_src.x, p_src.y, SRCCOPY); ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, dc, p_src.x, p_src.y, SRCCOPY);
::ReleaseDC(reinterpret_cast<HWND>(src), dc); ::ReleaseDC(reinterpret_cast<HWND>(src), dc);
#elif defined(NANA_X11) #elif defined(NANA_X11)
::XCopyArea(nana::detail::platform_spec::instance().open_display(), ::XCopyArea(nana::detail::platform_spec::instance().open_display(),
reinterpret_cast<Window>(src), handle_->pixmap, handle_->context, reinterpret_cast<Window>(src), impl_->handle->pixmap, impl_->handle->context,
p_src.x, p_src.y, r_dst.width, r_dst.height, r_dst.x, r_dst.y); p_src.x, p_src.y, r_dst.width, r_dst.height, r_dst.x, r_dst.y);
#endif #endif
if(changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
} }
void graphics::bitblt(const nana::rectangle& r_dst, const graphics& src) void graphics::bitblt(const nana::rectangle& r_dst, const graphics& src)
{ {
if(handle_ && src.handle_) if(impl_->handle && src.impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::BitBlt(handle_->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, src.handle_->context, 0, 0, SRCCOPY); ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, src.impl_->handle->context, 0, 0, SRCCOPY);
#elif defined(NANA_X11) #elif defined(NANA_X11)
::XCopyArea(nana::detail::platform_spec::instance().open_display(), ::XCopyArea(nana::detail::platform_spec::instance().open_display(),
src.handle_->pixmap, handle_->pixmap, handle_->context, src.impl_->handle->pixmap, impl_->handle->pixmap, impl_->handle->context,
0, 0, r_dst.width, r_dst.height, r_dst.x, r_dst.y); 0, 0, r_dst.width, r_dst.height, r_dst.x, r_dst.y);
#endif #endif
if(changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
} }
void graphics::bitblt(const nana::rectangle& r_dst, const graphics& src, const nana::point& p_src) void graphics::bitblt(const nana::rectangle& r_dst, const graphics& src, const nana::point& p_src)
{ {
if(handle_ && src.handle_) if(impl_->handle && src.impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::BitBlt(handle_->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, src.handle_->context, p_src.x, p_src.y, SRCCOPY); ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, src.impl_->handle->context, p_src.x, p_src.y, SRCCOPY);
#elif defined(NANA_X11) #elif defined(NANA_X11)
::XCopyArea(nana::detail::platform_spec::instance().open_display(), ::XCopyArea(nana::detail::platform_spec::instance().open_display(),
src.handle_->pixmap, handle_->pixmap, handle_->context, src.impl_->handle->pixmap, impl_->handle->pixmap, impl_->handle->context,
p_src.x, p_src.y, r_dst.width, r_dst.height, r_dst.x, r_dst.y); p_src.x, p_src.y, r_dst.width, r_dst.height, r_dst.x, r_dst.y);
#endif #endif
if(changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
} }
void graphics::blend(const nana::rectangle& s_r, graphics& dst, const nana::point& d_pos, double fade_rate) const void graphics::blend(const nana::rectangle& s_r, graphics& dst, const nana::point& d_pos, double fade_rate) const
{ {
if(dst.handle_ && handle_ && (dst.handle_ != handle_)) if(dst.impl_->handle && impl_->handle && (dst.impl_->handle != impl_->handle))
{ {
pixel_buffer s_pixbuf; pixel_buffer s_pixbuf;
s_pixbuf.attach(handle_, ::nana::rectangle{ size() }); s_pixbuf.attach(impl_->handle, ::nana::rectangle{ size() });
s_pixbuf.blend(s_r, dst.handle_, d_pos, fade_rate); s_pixbuf.blend(s_r, dst.impl_->handle, d_pos, fade_rate);
if(dst.changed_ == false) dst.changed_ = true; if(dst.impl_->changed == false) dst.impl_->changed = true;
} }
} }
void graphics::blur(const nana::rectangle& r, std::size_t radius) void graphics::blur(const nana::rectangle& r, std::size_t radius)
{ {
if(handle_) if(impl_->handle)
{ {
pixel_buffer pixbuf(handle_, 0, 0); pixel_buffer pixbuf(impl_->handle, 0, 0);
pixbuf.blur(r, radius); pixbuf.blur(r, radius);
pixbuf.paste(handle_, point{}); pixbuf.paste(impl_->handle, point{});
} }
} }
void graphics::rgb_to_wb() void graphics::rgb_to_wb()
{ {
if(handle_) if(impl_->handle)
{ {
//Create the color table for perfermance //Create the color table for perfermance
float* tablebuf = new float[0x100 * 3]; float* tablebuf = new float[0x100 * 3];
@ -654,11 +687,11 @@ namespace paint
table_blue[i] = (i * 0.11f); table_blue[i] = (i * 0.11f);
} }
pixel_buffer pixbuf(handle_, 0, 0); pixel_buffer pixbuf(impl_->handle, 0, 0);
auto pixels = pixbuf.raw_ptr(0); auto pixels = pixbuf.raw_ptr(0);
const nana::size sz = paint::detail::drawable_size(handle_); const nana::size sz = paint::detail::drawable_size(impl_->handle);
const int rest = sz.width % 4; const int rest = sz.width % 4;
const int length_align4 = sz.width - rest; const int length_align4 = sz.width - rest;
@ -692,26 +725,26 @@ namespace paint
} }
delete [] tablebuf; delete [] tablebuf;
pixbuf.paste(handle_, point{}); pixbuf.paste(impl_->handle, point{});
if(changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
} }
void graphics::paste(graphics& dst, int x, int y) const void graphics::paste(graphics& dst, int x, int y) const
{ {
if(handle_ && dst.handle_ && handle_ != dst.handle_) if(impl_->handle && dst.impl_->handle && impl_->handle != dst.impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::BitBlt(dst.handle_->context, x, y, size_.width, size_.height, handle_->context, 0, 0, SRCCOPY); ::BitBlt(dst.impl_->handle->context, x, y, impl_->size.width, impl_->size.height, impl_->handle->context, 0, 0, SRCCOPY);
#elif defined(NANA_X11) #elif defined(NANA_X11)
Display* display = nana::detail::platform_spec::instance().open_display(); Display* display = nana::detail::platform_spec::instance().open_display();
::XCopyArea(display, ::XCopyArea(display,
handle_->pixmap, dst.handle_->pixmap, handle_->context, impl_->handle->pixmap, dst.impl_->handle->pixmap, impl_->handle->context,
0, 0, size_.width, size_.height, x, y); 0, 0, impl_->size.width, impl_->size.height, x, y);
::XFlush(display); ::XFlush(display);
#endif #endif
dst.changed_ = true; dst.impl_->changed = true;
} }
} }
@ -722,19 +755,19 @@ namespace paint
void graphics::paste(native_window_type dst, int dx, int dy, unsigned width, unsigned height, int sx, int sy) const void graphics::paste(native_window_type dst, int dx, int dy, unsigned width, unsigned height, int sx, int sy) const
{ {
if(handle_) if(impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
HDC dc = ::GetDC(reinterpret_cast<HWND>(dst)); HDC dc = ::GetDC(reinterpret_cast<HWND>(dst));
if(dc) if(dc)
{ {
::BitBlt(dc, dx, dy, width, height, handle_->context, sx, sy, SRCCOPY); ::BitBlt(dc, dx, dy, width, height, impl_->handle->context, sx, sy, SRCCOPY);
::ReleaseDC(reinterpret_cast<HWND>(dst), dc); ::ReleaseDC(reinterpret_cast<HWND>(dst), dc);
} }
#elif defined(NANA_X11) #elif defined(NANA_X11)
Display * display = nana::detail::platform_spec::instance().open_display(); Display * display = nana::detail::platform_spec::instance().open_display();
::XCopyArea(display, ::XCopyArea(display,
handle_->pixmap, reinterpret_cast<Window>(dst), handle_->context, impl_->handle->pixmap, reinterpret_cast<Window>(dst), impl_->handle->context,
sx, sy, width, height, dx, dy); sx, sy, width, height, dx, dy);
::XMapWindow(display, reinterpret_cast<Window>(dst)); ::XMapWindow(display, reinterpret_cast<Window>(dst));
@ -745,15 +778,15 @@ namespace paint
void graphics::paste(drawable_type dst, int x, int y) const void graphics::paste(drawable_type dst, int x, int y) const
{ {
if(handle_ && dst && handle_ != dst) if(impl_->handle && dst && impl_->handle != dst)
{ {
#if defined (NANA_WINDOWS) #if defined (NANA_WINDOWS)
::BitBlt(dst->context, x, y, size_.width, size_.height, handle_->context, 0, 0, SRCCOPY); ::BitBlt(dst->context, x, y, impl_->size.width, impl_->size.height, impl_->handle->context, 0, 0, SRCCOPY);
#elif defined(NANA_X11) #elif defined(NANA_X11)
Display * display = nana::detail::platform_spec::instance().open_display(); Display * display = nana::detail::platform_spec::instance().open_display();
::XCopyArea(display, ::XCopyArea(display,
handle_->pixmap, dst->pixmap, handle_->context, impl_->handle->pixmap, dst->pixmap, impl_->handle->context,
0, 0, size_.width, size_.height, x, y); 0, 0, impl_->size.width, impl_->size.height, x, y);
::XFlush(display); ::XFlush(display);
#endif #endif
} }
@ -762,14 +795,14 @@ namespace paint
void graphics::paste(const nana::rectangle& r_src, graphics& dst, int x, int y) const void graphics::paste(const nana::rectangle& r_src, graphics& dst, int x, int y) const
{ {
if(handle_ && dst.handle_ && handle_ != dst.handle_) if(impl_->handle && dst.impl_->handle && impl_->handle != dst.impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::BitBlt(dst.handle_->context, x, y, r_src.width, r_src.height, handle_->context, r_src.x, r_src.y, SRCCOPY); ::BitBlt(dst.impl_->handle->context, x, y, r_src.width, r_src.height, impl_->handle->context, r_src.x, r_src.y, SRCCOPY);
#elif defined(NANA_X11) #elif defined(NANA_X11)
Display* display = nana::detail::platform_spec::instance().open_display(); Display* display = nana::detail::platform_spec::instance().open_display();
::XCopyArea(display, ::XCopyArea(display,
handle_->pixmap, dst.handle_->pixmap, handle_->context, impl_->handle->pixmap, dst.impl_->handle->pixmap, impl_->handle->context,
r_src.x, r_src.y, r_src.width, r_src.height, x, y); r_src.x, r_src.y, r_src.width, r_src.height, x, y);
::XFlush(display); ::XFlush(display);
@ -779,10 +812,10 @@ namespace paint
void graphics::stretch(const nana::rectangle& src_r, graphics& dst, const nana::rectangle& r) const void graphics::stretch(const nana::rectangle& src_r, graphics& dst, const nana::rectangle& r) const
{ {
if(handle_ && dst.handle_ && (handle_ != dst.handle_)) if(impl_->handle && dst.impl_->handle && (impl_->handle != dst.impl_->handle))
{ {
pixel_buffer pixbuf(handle_, 0, 0); pixel_buffer pixbuf(impl_->handle, 0, 0);
pixbuf.stretch(src_r, dst.handle_, r); pixbuf.stretch(src_r, dst.impl_->handle, r);
} }
} }
@ -799,58 +832,58 @@ namespace paint
} }
unsigned graphics::width() const{ unsigned graphics::width() const{
return size_.width; return impl_->size.width;
} }
unsigned graphics::height() const{ unsigned graphics::height() const{
return size_.height; return impl_->size.height;
} }
nana::size graphics::size() const{ nana::size graphics::size() const{
return this->size_; return this->impl_->size;
} }
void graphics::setsta() void graphics::setsta()
{ {
changed_ = false; impl_->changed = false;
} }
void graphics::set_changed() void graphics::set_changed()
{ {
changed_ = true; impl_->changed = true;
} }
void graphics::release() void graphics::release()
{ {
dwptr_.reset(); impl_->platform_drawable.reset();
handle_ = nullptr; impl_->handle = nullptr;
size_.width = size_.height = 0; impl_->size.width = impl_->size.height = 0;
} }
void graphics::save_as_file(const char* file_utf8) const throw() void graphics::save_as_file(const char* file_utf8) const throw()
{ {
if(handle_) if(impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
int iWidth = static_cast<int>(size_.width); const int iWidth = static_cast<int>(impl_->size.width);
int iHeight = static_cast<int>(size_.height); const int iHeight = static_cast<int>(impl_->size.height);
BITMAPINFO bmpInfo = {}; BITMAPINFO bmpInfo = {};
bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader); bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
bmpInfo.bmiHeader.biWidth = static_cast<int>(size_.width); bmpInfo.bmiHeader.biWidth = iWidth;
bmpInfo.bmiHeader.biHeight = static_cast<int>(size_.height); bmpInfo.bmiHeader.biHeight = iHeight;
bmpInfo.bmiHeader.biPlanes = 1; bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24; bmpInfo.bmiHeader.biBitCount = 24;
const size_t lineBytes = ((bmpInfo.bmiHeader.biWidth * 3) + 3) & (~3); const size_t lineBytes = ((bmpInfo.bmiHeader.biWidth * 3) + 3) & (~3);
const size_t imageBytes = iHeight * lineBytes; const size_t imageBytes = iHeight * lineBytes;
HDC hdcMem = ::CreateCompatibleDC(handle_->context); HDC hdcMem = ::CreateCompatibleDC(impl_->handle->context);
BYTE *pData = nullptr; BYTE *pData = nullptr;
HBITMAP hBmp = ::CreateDIBSection(hdcMem, &bmpInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&pData), 0, 0); HBITMAP hBmp = ::CreateDIBSection(hdcMem, &bmpInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&pData), 0, 0);
::SelectObject(hdcMem, hBmp); ::SelectObject(hdcMem, hBmp);
BitBlt(hdcMem, 0, 0, iWidth, iHeight, handle_->context, 0, 0, SRCCOPY); BitBlt(hdcMem, 0, 0, iWidth, iHeight, impl_->handle->context, 0, 0, SRCCOPY);
BITMAPFILEHEADER bmFileHeader = { 0 }; BITMAPFILEHEADER bmFileHeader = { 0 };
bmFileHeader.bfType = 0x4d42; //bmp bmFileHeader.bfType = 0x4d42; //bmp
@ -874,20 +907,20 @@ namespace paint
::nana::color graphics::palette(bool for_text) const ::nana::color graphics::palette(bool for_text) const
{ {
if (handle_) if (impl_->handle)
return static_cast<color_rgb>(for_text ? handle_->get_text_color() : handle_->get_color()); return static_cast<color_rgb>(for_text ? impl_->handle->get_text_color() : impl_->handle->get_color());
return{}; return{};
} }
graphics& graphics::palette(bool for_text, const ::nana::color& clr) graphics& graphics::palette(bool for_text, const ::nana::color& clr)
{ {
if (handle_) if (impl_->handle)
{ {
if (for_text) if (for_text)
handle_->set_text_color(clr); impl_->handle->set_text_color(clr);
else else
handle_->set_color(clr); impl_->handle->set_color(clr);
} }
return *this; return *this;
@ -915,34 +948,34 @@ namespace paint
void graphics::blend(const nana::rectangle& r, const ::nana::color& clr, double fade_rate) void graphics::blend(const nana::rectangle& r, const ::nana::color& clr, double fade_rate)
{ {
if (handle_) if (impl_->handle)
{ {
nana::paint::detail::blend(handle_, r, clr.px_color(), fade_rate); nana::paint::detail::blend(impl_->handle, r, clr.px_color(), fade_rate);
if (changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
} }
void graphics::set_pixel(int x, int y, const ::nana::color& clr) void graphics::set_pixel(int x, int y, const ::nana::color& clr)
{ {
if (handle_) if (impl_->handle)
{ {
handle_->set_color(clr); impl_->handle->set_color(clr);
set_pixel(x, y); set_pixel(x, y);
} }
} }
void graphics::set_pixel(int x, int y) void graphics::set_pixel(int x, int y)
{ {
if (handle_) if (impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::SetPixel(handle_->context, x, y, NANA_RGB(handle_->get_color())); ::SetPixel(impl_->handle->context, x, y, NANA_RGB(impl_->handle->get_color()));
#elif defined(NANA_X11) #elif defined(NANA_X11)
Display* disp = nana::detail::platform_spec::instance().open_display(); Display* disp = nana::detail::platform_spec::instance().open_display();
handle_->update_color(); impl_->handle->update_color();
::XDrawPoint(disp, handle_->pixmap, handle_->context, x, y); ::XDrawPoint(disp, impl_->handle->pixmap, impl_->handle->context, x, y);
#endif #endif
if (changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
} }
@ -959,24 +992,24 @@ namespace paint
void graphics::string(nana::point pos, const wchar_t* str, std::size_t len) void graphics::string(nana::point pos, const wchar_t* str, std::size_t len)
{ {
if (handle_ && str && len) if (impl_->handle && str && len)
{ {
auto const end = str + len; auto const end = str + len;
auto i = std::find(str, end, '\t'); auto i = std::find(str, end, '\t');
#if defined(NANA_LINUX) || defined(NANA_MACOS) #if defined(NANA_LINUX) || defined(NANA_MACOS)
handle_->update_text_color(); impl_->handle->update_text_color();
#endif #endif
if (i != end) if (i != end)
{ {
std::size_t tab_pixels = handle_->string.tab_length * handle_->string.tab_pixels; std::size_t tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.tab_pixels;
while (true) while (true)
{ {
len = i - str; len = i - str;
if (len) if (len)
{ {
//Render a part that does not contains a tab //Render a part that does not contains a tab
detail::draw_string(handle_, pos, str, len); detail::draw_string(impl_->handle, pos, str, len);
pos.x += detail::raw_text_extent_size(handle_, str, len).width; pos.x += detail::raw_text_extent_size(impl_->handle, str, len).width;
} }
str = i; str = i;
@ -994,8 +1027,8 @@ namespace paint
} }
} }
else else
detail::draw_string(handle_, pos, str, len); detail::draw_string(impl_->handle, pos, str, len);
if (changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
} }
@ -1017,21 +1050,21 @@ namespace paint
void graphics::line(const nana::point& pos1, const nana::point& pos2) void graphics::line(const nana::point& pos1, const nana::point& pos2)
{ {
if (!handle_) return; if (!impl_->handle) return;
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
handle_->update_pen(); impl_->handle->update_pen();
if (pos1 != pos2) if (pos1 != pos2)
{ {
::MoveToEx(handle_->context, pos1.x, pos1.y, 0); ::MoveToEx(impl_->handle->context, pos1.x, pos1.y, 0);
::LineTo(handle_->context, pos2.x, pos2.y); ::LineTo(impl_->handle->context, pos2.x, pos2.y);
} }
::SetPixel(handle_->context, pos2.x, pos2.y, NANA_RGB(handle_->pen.color)); ::SetPixel(impl_->handle->context, pos2.x, pos2.y, NANA_RGB(impl_->handle->pen.color));
#elif defined(NANA_X11) #elif defined(NANA_X11)
Display* disp = nana::detail::platform_spec::instance().open_display(); Display* disp = nana::detail::platform_spec::instance().open_display();
handle_->update_color(); impl_->handle->update_color();
::XDrawLine(disp, handle_->pixmap, handle_->context, pos1.x, pos1.y, pos2.x, pos2.y); ::XDrawLine(disp, impl_->handle->pixmap, impl_->handle->context, pos1.x, pos1.y, pos2.x, pos2.y);
#endif #endif
if (changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
void graphics::line(const point& pos_a, const point& pos_b, const color& clr) void graphics::line(const point& pos_a, const point& pos_b, const color& clr)
@ -1042,26 +1075,26 @@ namespace paint
void graphics::line_to(const point& pos, const color& clr) void graphics::line_to(const point& pos, const color& clr)
{ {
if (!handle_) return; if (!impl_->handle) return;
handle_->set_color(clr); impl_->handle->set_color(clr);
line_to(pos); line_to(pos);
} }
void graphics::line_to(const point& pos) void graphics::line_to(const point& pos)
{ {
if (!handle_) return; if (!impl_->handle) return;
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
handle_->update_pen(); impl_->handle->update_pen();
::LineTo(handle_->context, pos.x, pos.y); ::LineTo(impl_->handle->context, pos.x, pos.y);
#elif defined(NANA_X11) #elif defined(NANA_X11)
Display* disp = nana::detail::platform_spec::instance().open_display(); Display* disp = nana::detail::platform_spec::instance().open_display();
handle_->update_color(); impl_->handle->update_color();
::XDrawLine(disp, handle_->pixmap, handle_->context, ::XDrawLine(disp, impl_->handle->pixmap, impl_->handle->context,
handle_->line_begin_pos.x, handle_->line_begin_pos.y, impl_->handle->line_begin_pos.x, impl_->handle->line_begin_pos.y,
pos.x, pos.y); pos.x, pos.y);
handle_->line_begin_pos = pos; impl_->handle->line_begin_pos = pos;
#endif #endif
if (changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
void graphics::rectangle(bool solid) void graphics::rectangle(bool solid)
@ -1077,21 +1110,21 @@ namespace paint
void graphics::rectangle(const ::nana::rectangle& r, bool solid) void graphics::rectangle(const ::nana::rectangle& r, bool solid)
{ {
if (r.width && r.height && handle_ && r.right() > 0 && r.bottom() > 0) if (r.width && r.height && impl_->handle && r.right() > 0 && r.bottom() > 0)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
::RECT native_r = { r.x, r.y, r.right(), r.bottom()}; ::RECT native_r = { r.x, r.y, r.right(), r.bottom()};
handle_->update_brush(); impl_->handle->update_brush();
(solid ? ::FillRect : ::FrameRect)(handle_->context, &native_r, handle_->brush.handle); (solid ? ::FillRect : ::FrameRect)(impl_->handle->context, &native_r, impl_->handle->brush.handle);
#elif defined(NANA_X11) #elif defined(NANA_X11)
Display* disp = nana::detail::platform_spec::instance().open_display(); Display* disp = nana::detail::platform_spec::instance().open_display();
handle_->update_color(); impl_->handle->update_color();
if (solid) if (solid)
::XFillRectangle(disp, handle_->pixmap, handle_->context, r.x, r.y, r.width, r.height); ::XFillRectangle(disp, impl_->handle->pixmap, impl_->handle->context, r.x, r.y, r.width, r.height);
else else
::XDrawRectangle(disp, handle_->pixmap, handle_->context, r.x, r.y, r.width - 1, r.height - 1); ::XDrawRectangle(disp, impl_->handle->pixmap, impl_->handle->context, r.x, r.y, r.width - 1, r.height - 1);
#endif #endif
if (changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
} }
@ -1138,13 +1171,13 @@ namespace paint
void graphics::gradual_rectangle(const ::nana::rectangle& rct, const ::nana::color& from, const ::nana::color& to, bool vertical) void graphics::gradual_rectangle(const ::nana::rectangle& rct, const ::nana::color& from, const ::nana::color& to, bool vertical)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
if (pxbuf_.open(handle_)) if (impl_->pxbuf.open(impl_->handle))
{ {
pxbuf_.gradual_rectangle(rct, from, to, 0.0, vertical); impl_->pxbuf.gradual_rectangle(rct, from, to, 0.0, vertical);
pxbuf_.paste(handle_, point{}); impl_->pxbuf.paste(impl_->handle, point{});
} }
#elif defined(NANA_X11) #elif defined(NANA_X11)
if (nullptr == handle_) return; if (nullptr == impl_->handle) return;
double deltapx = double(vertical ? rct.height : rct.width); double deltapx = double(vertical ? rct.height : rct.width);
double r, g, b; double r, g, b;
@ -1155,7 +1188,7 @@ namespace paint
unsigned last_color = (int(r) << 16) | (int(g) << 8) | int(b); unsigned last_color = (int(r) << 16) | (int(g) << 8) | int(b);
Display * disp = nana::detail::platform_spec::instance().open_display(); Display * disp = nana::detail::platform_spec::instance().open_display();
handle_->fgcolor(static_cast<color_rgb>(last_color)); impl_->handle->fgcolor(static_cast<color_rgb>(last_color));
const int endpos = deltapx + (vertical ? rct.y : rct.x); const int endpos = deltapx + (vertical ? rct.y : rct.x);
if (endpos > 0) if (endpos > 0)
{ {
@ -1165,12 +1198,12 @@ namespace paint
auto y = rct.y; auto y = rct.y;
for (; y < endpos; ++y) for (; y < endpos; ++y)
{ {
::XDrawLine(disp, handle_->pixmap, handle_->context, x1, y, x2, y); ::XDrawLine(disp, impl_->handle->pixmap, impl_->handle->context, x1, y, x2, y);
unsigned new_color = (int(r += delta_r) << 16) | (int(g += delta_g) << 8) | int(b += delta_b); unsigned new_color = (int(r += delta_r) << 16) | (int(g += delta_g) << 8) | int(b += delta_b);
if (new_color != last_color) if (new_color != last_color)
{ {
last_color = new_color; last_color = new_color;
handle_->fgcolor(static_cast<color_rgb>(last_color)); impl_->handle->fgcolor(static_cast<color_rgb>(last_color));
} }
} }
} }
@ -1180,39 +1213,40 @@ namespace paint
auto x = rct.x; auto x = rct.x;
for (; x < endpos; ++x) for (; x < endpos; ++x)
{ {
::XDrawLine(disp, handle_->pixmap, handle_->context, x, y1, x, y2); ::XDrawLine(disp, impl_->handle->pixmap, impl_->handle->context, x, y1, x, y2);
unsigned new_color = (int(r += delta_r) << 16) | (int(g += delta_g) << 8) | int(b += delta_b); unsigned new_color = (int(r += delta_r) << 16) | (int(g += delta_g) << 8) | int(b += delta_b);
if (new_color != last_color) if (new_color != last_color)
{ {
last_color = new_color; last_color = new_color;
handle_->fgcolor(static_cast<color_rgb>(last_color)); impl_->handle->fgcolor(static_cast<color_rgb>(last_color));
} }
} }
} }
} }
#endif #endif
if (changed_ == false) changed_ = true; if (impl_->changed == false) impl_->changed = true;
} }
void graphics::round_rectangle(const ::nana::rectangle& r, unsigned radius_x, unsigned radius_y, const color& clr, bool solid, const color& solid_clr) void graphics::round_rectangle(const ::nana::rectangle& r, unsigned radius_x, unsigned radius_y, const color& clr, bool solid, const color& solid_clr)
{ {
if (handle_) if (impl_->handle)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
handle_->set_color(clr); impl_->handle->set_color(clr);
if (solid) if (solid)
{ {
handle_->update_pen(); impl_->handle->update_pen();
handle_->brush.set(handle_->context, handle_->brush.Solid, solid_clr.px_color().value); impl_->handle->brush.set(impl_->handle->context, impl_->handle->brush.Solid, solid_clr.px_color().value);
::RoundRect(handle_->context, r.x, r.y, r.right(), r.bottom(), static_cast<int>(radius_x * 2), static_cast<int>(radius_y * 2)); ::RoundRect(impl_->handle->context, r.x, r.y, r.right(), r.bottom(), static_cast<int>(radius_x * 2), static_cast<int>(radius_y * 2));
} }
else else
{ {
handle_->update_brush(); impl_->handle->update_brush();
handle_->round_region.set(r, radius_x, radius_y); impl_->handle->round_region.set(r, radius_x, radius_y);
::FrameRgn(handle_->context, handle_->round_region.handle, handle_->brush.handle, 1, 1); ::FrameRgn(impl_->handle->context, impl_->handle->round_region.handle, impl_->handle->brush.handle, 1, 1);
} }
if(changed_ == false) changed_ = true;
if (impl_->changed == false) impl_->changed = true;
#elif defined(NANA_X11) #elif defined(NANA_X11)
if(solid && (clr == solid_clr)) if(solid && (clr == solid_clr))
{ {
@ -1233,5 +1267,40 @@ namespace paint
} }
//end class graphics //end class graphics
//class draw
draw::draw(graphics& graph)
: graph_(graph)
{}
void draw::corner(const rectangle& r, unsigned pixels)
{
if (1 == pixels)
{
graph_.set_pixel(r.x, r.y);
graph_.set_pixel(r.right() - 1, r.y);
graph_.set_pixel(r.x, r.bottom() - 1);
graph_.set_pixel(r.right() - 1, r.bottom() - 1);
return;
}
else if (1 < pixels)
{
graph_.line(r.position(), point(r.x + pixels, r.y));
graph_.line(r.position(), point(r.x, r.y + pixels));
int right = r.right() - 1;
graph_.line(point(right, r.y), point(right - pixels, r.y));
graph_.line(point(right, r.y), point(right, r.y - pixels));
int bottom = r.bottom() - 1;
graph_.line(point(r.x, bottom), point(r.x + pixels, bottom));
graph_.line(point(r.x, bottom), point(r.x, bottom - pixels));
graph_.line(point(right, bottom), point(right - pixels, bottom));
graph_.line(point(right, bottom), point(right, bottom - pixels));
}
}
//end class draw
}//end namespace paint }//end namespace paint
}//end namespace nana }//end namespace nana

View File

@ -70,7 +70,7 @@ namespace nana
auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin); auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin);
if(ts.height > pixels) pixels = ts.height; if(ts.height > pixels) pixels = ts.height;
lenpx += ts.width; lenpx += ts.width;
widths.push_back(ts.width); widths.emplace_back(ts.width);
} }
pos.x += (endpos - pos.x - static_cast<int>(lenpx))/2; pos.x += (endpos - pos.x - static_cast<int>(lenpx))/2;
@ -199,7 +199,7 @@ namespace nana
{ {
nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin);
if(ts.height > pixels) pixels = ts.height; if(ts.height > pixels) pixels = ts.height;
ts_keeper.push_back(ts); ts_keeper.emplace_back(ts);
str_w += ts.width; str_w += ts.width;
} }
@ -417,7 +417,7 @@ namespace nana
for(auto & i : reordered) for(auto & i : reordered)
{ {
nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin);
ts_keeper.push_back(ts); ts_keeper.emplace_back(ts);
str_w += ts.width; str_w += ts.width;
} }

View File

@ -13,6 +13,7 @@
#include <nana/system/dataexch.hpp> #include <nana/system/dataexch.hpp>
#include <nana/traits.hpp> #include <nana/traits.hpp>
#include <nana/paint/graphics.hpp> #include <nana/paint/graphics.hpp>
#include <nana/paint/pixel_buffer.hpp>
#include <vector> #include <vector>
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>

View File

@ -94,7 +94,7 @@ namespace threads
pto->suspended = false; pto->suspended = false;
::pthread_create(&(pto->handle), 0, reinterpret_cast<void*(*)(void*)>(&impl::_m_thr_starter), pto); ::pthread_create(&(pto->handle), 0, reinterpret_cast<void*(*)(void*)>(&impl::_m_thr_starter), pto);
#endif #endif
container_.threads.push_back(pto); container_.threads.emplace_back(pto);
} }
} }
@ -168,7 +168,7 @@ namespace threads
else else
{ {
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<decltype(mutex_)> lock(mutex_);
container_.tasks.push_back(taskptr); container_.tasks.emplace_back(taskptr);
} }
} }

View File

@ -536,7 +536,8 @@ namespace nana
} }
else if (LRE <= *c && *c <= RLO) else if (LRE <= *c && *c <= RLO)
{ {
stack.push_back(cur); stack.emplace_back(cur);
if (begin_character) if (begin_character)
{ {
_m_push_entity(begin_character, c, cur.level, begin_char_type); _m_push_entity(begin_character, c, cur.level, begin_char_type);
@ -607,12 +608,13 @@ namespace nana
void unicode_bidi::_m_push_entity(const char_type * begin, const char_type *end, unsigned level, bidi_char bidi_char_type) void unicode_bidi::_m_push_entity(const char_type * begin, const char_type *end, unsigned level, bidi_char bidi_char_type)
{ {
entity e; levels_.emplace_back();
auto & e = levels_.back();
e.begin = begin; e.begin = begin;
e.end = end; e.end = end;
e.level = level; e.level = level;
e.bidi_char_type = bidi_char_type; e.bidi_char_type = bidi_char_type;
levels_.push_back(e);
} }
std::vector<unicode_bidi::entity>::iterator unicode_bidi::_m_search_first_character() std::vector<unicode_bidi::entity>::iterator unicode_bidi::_m_search_first_character()
@ -620,6 +622,7 @@ namespace nana
return levels_.begin(); return levels_.begin();
} }
auto unicode_bidi::_m_eor(std::vector<entity>::iterator i) ->bidi_char auto unicode_bidi::_m_eor(std::vector<entity>::iterator i) ->bidi_char
{ {
const auto end = levels_.end(); const auto end = levels_.end();