diff --git a/include/nana/detail/win32/platform_spec.hpp b/include/nana/detail/win32/platform_spec.hpp index 23abd002..c681d8a3 100644 --- a/include/nana/detail/win32/platform_spec.hpp +++ b/include/nana/detail/win32/platform_spec.hpp @@ -17,13 +17,11 @@ #ifndef NANA_DETAIL_PLATFORM_SPEC_HPP #define NANA_DETAIL_PLATFORM_SPEC_HPP -#include #include #include #include #include -#include #include #include @@ -174,6 +172,12 @@ namespace detail 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: typedef drawable_impl_type::font_ptr_t font_ptr_t; typedef ::nana::event_code event_code; @@ -194,7 +198,7 @@ namespace detail ::nana::paint::image big_icon; }; - platform_spec(); + ~platform_spec(); const font_ptr_t& default_native_font() const; 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 release_window_icon(native_window_type); private: - font_ptr_t def_font_ptr_; - std::map iconbase_; + struct implementation; + implementation * const impl_; }; }//end namespace detail diff --git a/include/nana/gui/detail/element_store.hpp b/include/nana/gui/detail/element_store.hpp index 3ac5b242..72df9fbb 100644 --- a/include/nana/gui/detail/element_store.hpp +++ b/include/nana/gui/detail/element_store.hpp @@ -1,7 +1,7 @@ /* * The Store for the Storage Of Elements * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -16,9 +16,7 @@ #include #include -#include #include - #include @@ -28,27 +26,20 @@ namespace detail { class element_store { - typedef ::nana::element::element_interface element_interface; - typedef pat::cloneable< ::nana::element::element_interface> cloneable_element; + using element_interface = ::nana::element::element_interface; + using cloneable_element = pat::cloneable< ::nana::element::element_interface>; - struct data - { - cloneable_element object; - ::nana::element::element_interface * fast_ptr; - - data(); - }; - - struct store - { - std::map table; - }; + struct data; public: + element_store(); + ~element_store(); + element_interface * const * bground(const std::string&); void bground(const std::string&, const pat::cloneable&); void bground(const std::string&, pat::cloneable&&); private: - store bground_; + struct implementation; + std::unique_ptr impl_; }; }//end namespace detail } diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/include/nana/gui/detail/inner_fwd_implement.hpp index a1bc1aaf..4b7d958a 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/include/nana/gui/detail/inner_fwd_implement.hpp @@ -133,10 +133,10 @@ namespace nana{ class root_register { public: - root_misc* insert(native_window_type wd, const root_misc& misc) + root_misc* insert(native_window_type wd, root_misc&& misc) { recent_ = wd; - auto ret = table_.insert(std::make_pair(wd, misc)); + auto ret = table_.emplace(wd, std::move(misc)); misc_ptr_ = &(ret.first->second); return misc_ptr_; } diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index 268547c0..1548b79f 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -20,18 +20,11 @@ #include -#include #include "window_layout.hpp" #include "event_code.hpp" #include "inner_fwd.hpp" #include -#if defined(STD_THREAD_NOT_SUPPORTED) - #include -#else - #include -#endif - namespace nana { class widget; //forward declaration @@ -51,15 +44,14 @@ namespace detail class window_manager { class revertible_mutex - : public std::recursive_mutex { - struct thr_refcnt - { - unsigned tid; - std::size_t refcnt; - }; + revertible_mutex(const revertible_mutex&) = delete; + revertible_mutex& operator=(const revertible_mutex&) = delete; + revertible_mutex(revertible_mutex&&) = delete; + revertible_mutex& operator=(revertible_mutex&&) = delete; public: revertible_mutex(); + ~revertible_mutex(); void lock(); bool try_lock(); @@ -68,8 +60,8 @@ namespace detail void revert(); void forward(); private: - thr_refcnt thr_; - std::vector stack_; + struct implementation; + implementation * const impl_; }; public: using native_window = native_window_type; @@ -90,7 +82,6 @@ namespace detail bool available(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_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&); - root_misc* root_runtime(native_window_type) const; + root_misc* root_runtime(native_window) const; bool register_shortkey(core_window_t*, unsigned long key); void unregister_shortkey(core_window_t*, bool with_children); diff --git a/include/nana/gui/element.hpp b/include/nana/gui/element.hpp index 0ecfdad1..bb76656d 100644 --- a/include/nana/gui/element.hpp +++ b/include/nana/gui/element.hpp @@ -16,7 +16,6 @@ #include #include #include -#include namespace nana { @@ -338,13 +337,8 @@ namespace nana struct draw_image; struct draw_graph; - draw_method * method_; - bool vertical_; - nana::rectangle valid_area_; - std::vector states_; - std::map join_; - bool stretch_all_; - unsigned left_, top_, right_, bottom_; + struct implementation; + std::unique_ptr impl_; }; //end class bground }//end namespace element }//end namespace nana diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index 4f674cf2..dbc12111 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -17,7 +17,6 @@ #define NANA_GUI_PLACE_HPP #include #include -#include #include #include diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 62125e65..06ff5716 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -347,7 +347,8 @@ namespace API * 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 - * @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 open_caret(window window_handle, bool disable_throw = false); diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index e4b06724..f0547918 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -720,7 +720,7 @@ namespace nana class iresolver { public: - iresolver(const std::vector&); + iresolver(std::vector); iresolver& operator>>(bool&); iresolver& operator>>(short&); @@ -740,7 +740,7 @@ namespace nana iresolver& operator>>(cell&); iresolver& operator>>(std::nullptr_t); private: - const std::vector& cells_; + std::vector cells_; std::size_t pos_{0}; }; @@ -918,7 +918,7 @@ namespace nana //Undocumented method essence * _m_ess() const; private: - std::vector & _m_cells() const; + std::vector _m_cells() const; nana::any * _m_value(bool alloc_if_empty); const nana::any * _m_value() const; private: diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index d2a10a35..eb246388 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -17,109 +17,26 @@ #include "textbase.hpp" #include "text_editor_part.hpp" -#include #include +//#include +#include + +#include + +namespace nana +{ + namespace paint + { + // Forward declaration + class graphics; + } +} + namespace nana{ namespace widgets { namespace skeletons { - template - 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 - class undoable - { - public: - using command = EnumCommand; - using container = std::deque < std::unique_ptr> >; - - 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> && 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 { struct attributes; @@ -136,9 +53,14 @@ namespace nana{ namespace widgets class undo_input_text; class undo_move_text; - struct keywords; class keyword_parser; 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: using char_type = wchar_t; using size_type = textbase::size_type; @@ -148,9 +70,10 @@ namespace nana{ namespace widgets using graph_reference = ::nana::paint::graphics&; - struct ext_renderer_tag + struct renderers { - std::function background; + std::function background; ///< a customized background renderer + std::function border; ///< a customized border renderer }; enum class accepts @@ -178,11 +101,10 @@ namespace nana{ namespace widgets /// Determine whether the text_editor is line wrapped. bool line_wrapped() const; + /// Set the text_editor whether it is line wrapped, it returns false if the state is not changed. bool line_wrapped(bool); - void border_renderer(std::function); - bool load(const char*); /// Sets the text area. @@ -205,7 +127,7 @@ namespace nana{ namespace widgets void undo_max_steps(std::size_t); std::size_t undo_max_steps() const; - ext_renderer_tag& ext_renderer() const; + renderers& customized_renderers(); unsigned line_height() const; unsigned screen_lines() const; @@ -267,8 +189,8 @@ namespace nana{ namespace widgets bool mouse_move(bool left_button, const point& screen_pos); bool mouse_pressed(const arg_mouse& arg); - skeletons::textbase& textbase(); - const skeletons::textbase& textbase() const; + skeletons::textbase& textbase(); + const skeletons::textbase& textbase() const; private: void _m_pre_calc_lines(std::size_t line_off, std::size_t lines); @@ -276,7 +198,9 @@ namespace nana{ namespace widgets ::nana::color _m_bgcolor() const; bool _m_scroll_text(bool vertical); void _m_scrollbar(); - ::nana::size _m_text_area() const; + + ::nana::rectangle _m_text_area() const; + void _m_get_scrollbar_size(); void _m_reset(); ::nana::upoint _m_put(::std::wstring); @@ -295,9 +219,6 @@ namespace nana{ namespace widgets 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; //_m_draw_string //@brief: Draw a line of string @@ -313,47 +234,28 @@ namespace nana{ namespace widgets unsigned _m_char_by_pixels(const unicode_bidi::entity&, unsigned pos); 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: - std::unique_ptr behavior_; - undoable undo_; + struct implementation; + implementation * const impl_; + nana::window window_; - std::unique_ptr caret_; graph_reference graph_; const text_editor_scheme* scheme_; event_interface * event_handler_{ nullptr }; - std::unique_ptr keywords_; - skeletons::textbase textbase_; wchar_t mask_char_{0}; - mutable ext_renderer_tag ext_renderer_; - - std::vector text_position_; //position of text from last rendering. - - struct indent_rep - { - bool enabled{ false }; - std::function generator; - }indent_; - struct attributes { - accepts acceptive{ accepts::no_restrict }; - std::function pred_acceptive; - ::std::string tip_string; bool line_wrapped{false}; bool multi_lines{true}; bool editable{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> vscroll; - std::unique_ptr> hscroll; }attributes_; struct text_area_type @@ -365,7 +267,6 @@ namespace nana{ namespace widgets unsigned scroll_pixels; unsigned vscroll; unsigned hscroll; - std::function border_renderer; }text_area_; struct selection diff --git a/include/nana/gui/widgets/slider.hpp b/include/nana/gui/widgets/slider.hpp index 9adb512c..8ce9602b 100644 --- a/include/nana/gui/widgets/slider.hpp +++ b/include/nana/gui/widgets/slider.hpp @@ -1,7 +1,7 @@ /** * A Slider Implementation * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -134,7 +134,7 @@ namespace nana }//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 : public widget_object { diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index 5e1ad652..585e83e3 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -28,14 +28,25 @@ namespace nana /// Abstract class for defining the capacity interface. class widget - : nana::noncopyable, nana::nonmovable { friend class detail::widget_notifier_interface; class inner_widget_notifier; 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: using native_string_type = detail::native_string_type; + widget() = default; + virtual ~widget() = default; 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. @@ -298,15 +309,8 @@ namespace nana using event_type = Events; 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 = {}) diff --git a/include/nana/internationalization.hpp b/include/nana/internationalization.hpp index 3e6c967b..7aec20a8 100644 --- a/include/nana/internationalization.hpp +++ b/include/nana/internationalization.hpp @@ -12,7 +12,6 @@ #ifndef NANA_INTERNATIONALIZATION_HPP #define NANA_INTERNATIONALIZATION_HPP -#include "basic_types.hpp" #include #include #include @@ -186,9 +185,7 @@ namespace nana void _m_add_args(const 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(std::wstring&&); private: std::string msgid_; std::vector> args_; diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp index 7102c500..1877dd51 100644 --- a/include/nana/paint/graphics.hpp +++ b/include/nana/paint/graphics.hpp @@ -1,7 +1,7 @@ /* * Paint Graphics Implementation * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -17,7 +17,6 @@ #include "../basic_types.hpp" #include "../gui/basis.hpp" -#include "pixel_buffer.hpp" namespace nana { @@ -72,12 +71,16 @@ namespace nana class graphics { public: - typedef ::nana::native_window_type native_window_type; - graphics(); 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& operator=(const graphics&); + + graphics(graphics&&); + graphics& operator=(graphics&&); + + ~graphics(); + 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. operator const void*() const; @@ -129,10 +132,10 @@ namespace nana void flush(); - unsigned width() const; - unsigned height() const; ///< Returns the height of the off-screen buffer. + unsigned width() const; ///< Returns the width of the off-screen buffer. + unsigned height() const; ///< Returns the height of the off-screen buffer. ::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 release(); @@ -172,12 +175,8 @@ namespace nana 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); private: - std::shared_ptr< ::nana::detail::drawable_impl_type> dwptr_; - font font_shadow_; - drawable_type handle_; - ::nana::size size_; - pixel_buffer pxbuf_; - bool changed_; + struct implementation; + std::unique_ptr impl_; }; }//end namespace paint } //end namespace nana diff --git a/source/audio/detail/audio_device.cpp b/source/audio/detail/audio_device.cpp index 6ae40f2c..32e1e1d0 100644 --- a/source/audio/detail/audio_device.cpp +++ b/source/audio/detail/audio_device.cpp @@ -184,7 +184,7 @@ namespace nana{namespace audio { #if defined(NANA_WINDOWS) std::lock_guard lock(queue_lock_); - done_queue_.push_back(m); + done_queue_.emplace_back(m); if(m->dwFlags & WHDR_PREPARED) wave_native_if.out_unprepare(handle_, m, sizeof(WAVEHDR)); diff --git a/source/audio/detail/buffer_preparation.cpp b/source/audio/detail/buffer_preparation.cpp index f9f830ff..acd0aaa3 100644 --- a/source/audio/detail/buffer_preparation.cpp +++ b/source/audio/detail/buffer_preparation.cpp @@ -30,7 +30,7 @@ namespace nana{ namespace audio m->bufsize = ck.nAvgBytesPerSec; m->buf = rawbuf + sizeof(meta); #endif - prepared_.push_back(m); + prepared_.emplace_back(m); } thr_ = std::move(std::thread([this](){this->_m_prepare_routine();})); @@ -79,7 +79,7 @@ namespace nana{ namespace audio { std::lock_guard lock(token_prepared_); bool if_signal = prepared_.empty(); - prepared_.push_back(m); + prepared_.emplace_back(m); if(if_signal) cond_prepared_.notify_one(); } @@ -148,7 +148,7 @@ namespace nana{ namespace audio m->bufsize = buffered; #endif std::lock_guard lock(token_buffer_); - buffer_.push_back(m); + buffer_.emplace_back(m); if(wait_for_buffer_) { cond_buffer_.notify_one(); diff --git a/source/detail/platform_spec_windows.cpp b/source/detail/platform_spec_windows.cpp index 7d1ae510..df3e1195 100644 --- a/source/detail/platform_spec_windows.cpp +++ b/source/detail/platform_spec_windows.cpp @@ -16,10 +16,10 @@ #if defined(NANA_WINDOWS) -#include #include +#include - +#include /////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -352,7 +352,14 @@ namespace detail } } + struct platform_spec::implementation + { + font_ptr_t def_font_ptr; + std::map iconbase; + }; + platform_spec::platform_spec() + : impl_{ new implementation} { //Create default font object. NONCLIENTMETRICS metrics = {}; @@ -370,17 +377,22 @@ namespace detail #endif #endif ::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 { - return def_font_ptr_; + return impl_->def_font_ptr; } 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 @@ -409,7 +421,7 @@ namespace detail if (name && *name) std::wcscpy(logfont.lfFaceName, to_wstring(name).c_str()); 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; 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) { - auto & icons = iconbase_[wd]; + auto & icons = impl_->iconbase[wd]; icons.sml_icon = sml_icon; icons.big_icon = big_icon; } void platform_spec::release_window_icon(native_window_type wd) { - iconbase_.erase(wd); + impl_->iconbase.erase(wd); } }//end namespace detail }//end namespace nana diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 525f5e57..7471ba0a 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -402,7 +402,7 @@ namespace nana root = agrparent->root; root_graph = agrparent->root_graph; index = static_cast(agrparent->children.size()); - agrparent->children.push_back(this); + agrparent->children.emplace_back(this); } predef_cursor = cursor::arrow; diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index c0e37ae4..64db05cd 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -600,7 +600,7 @@ namespace nana { root = wd->root; if (roots.cend() == std::find(roots.cbegin(), roots.cend(), root)) - roots.push_back(root); + roots.emplace_back(root); } } diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index fdf569aa..e3b7b2fe 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -338,7 +338,7 @@ namespace nana for (auto p : data_impl_->draws) { if(p->diehard()) - then.push_back(p); + then.emplace_back(p); else delete p; } @@ -351,7 +351,7 @@ namespace nana if(f) { 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 nullptr; diff --git a/source/gui/detail/element_store.cpp b/source/gui/detail/element_store.cpp index 39608754..95b0d959 100644 --- a/source/gui/detail/element_store.cpp +++ b/source/gui/detail/element_store.cpp @@ -1,7 +1,7 @@ /* * The Store for the Storage Of Elements * 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. * (See accompanying file LICENSE_1_0.txt or copy at @@ -11,35 +11,53 @@ */ #include +#include + namespace nana { namespace detail { //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 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) { - element_interface * const * addr = &(bground_.table[name].fast_ptr); + element_interface * const * addr = &(impl_->table[name].fast_ptr); return addr; } void element_store::bground(const std::string& name, const pat::cloneable& rhs) { - auto & store = bground_.table[name]; + auto & store = impl_->table[name]; - store.object = rhs; - store.fast_ptr = store.object.get(); + store.entity = rhs; + store.fast_ptr = store.entity.get(); } void element_store::bground(const std::string& name, pat::cloneable&& rv) { - auto & store = bground_.table[name]; + auto & store = impl_->table[name]; - store.object = std::move(rv); - store.fast_ptr = store.object.get(); + store.entity = std::move(rv); + store.fast_ptr = store.entity.get(); } }//end namespace detail } diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index ea574baa..ec69baa3 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -221,8 +221,8 @@ namespace nana continue; core_window_t * term = ((i + 1 != layers_rend) ? *(i + 1) : wd); - r.x = wd->pos_root.x - pre->pos_root.x; - r.y = wd->pos_root.y - pre->pos_root.y; + r.position(wd->pos_root - pre->pos_root); + for (auto child : pre->children) { 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 (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.y += wd->pos_root.y; diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 2fedf0d7..3e5d1d23 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -23,6 +23,12 @@ #include #include +#if defined(STD_THREAD_NOT_SUPPORTED) +#include +#else +#include +#endif + namespace nana { @@ -36,9 +42,7 @@ namespace detail Key first; Value second; - key_value_rep() - : first{}, second{} - {} + key_value_rep() = default; key_value_rep(const Key& k) : first(k), second{} @@ -69,19 +73,9 @@ namespace detail return table_.end(); } - iterator erase(iterator pos) + std::vector& table() { - return table_.erase(pos); - } - - iterator begin() - { - return table_.begin(); - } - - iterator end() - { - return table_.end(); + return table_; } private: std::vector table_; @@ -109,27 +103,50 @@ namespace detail //end struct wdm_private_impl //class revertible_mutex - window_manager::revertible_mutex::revertible_mutex() + struct thread_refcount { - thr_.tid = 0; - thr_.refcnt = 0; + unsigned tid; + std::size_t ref; + }; + + struct window_manager::revertible_mutex::implementation + { + std::recursive_mutex mutex; + + thread_refcount thread; + std::vector 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() { - std::recursive_mutex::lock(); - if(0 == thr_.tid) - thr_.tid = nana::system::this_thread_id(); - ++thr_.refcnt; + impl_->mutex.lock(); + + if(0 == impl_->thread.tid) + impl_->thread.tid = nana::system::this_thread_id(); + + ++(impl_->thread.ref); } bool window_manager::revertible_mutex::try_lock() { - if(std::recursive_mutex::try_lock()) + if(impl_->mutex.try_lock()) { - if(0 == thr_.tid) - thr_.tid = nana::system::this_thread_id(); - ++thr_.refcnt; + if (0 == impl_->thread.tid) + impl_->thread.tid = nana::system::this_thread_id(); + + ++(impl_->thread.ref); return true; } return false; @@ -137,44 +154,45 @@ namespace detail void window_manager::revertible_mutex::unlock() { - if(thr_.tid == nana::system::this_thread_id()) - if(0 == --thr_.refcnt) - thr_.tid = 0; - std::recursive_mutex::unlock(); + if(impl_->thread.tid == nana::system::this_thread_id()) + if(0 == --(impl_->thread.ref)) + impl_->thread.tid = 0; + + impl_->mutex.unlock(); } 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_); - thr_.tid = 0; - thr_.refcnt = 0; + impl_->invoke_stack.push_back(impl_->thread); + impl_->thread.tid = 0; + impl_->thread.ref = 0; - for(std::size_t i = 0; i < cnt; ++i) - std::recursive_mutex::unlock(); + for (std::size_t i = 0; i < cnt; ++i) + impl_->mutex.unlock(); } } void window_manager::revertible_mutex::forward() { - std::recursive_mutex::lock(); - if(stack_.size()) + impl_->mutex.lock(); + if(impl_->invoke_stack.size()) { - auto thr = stack_.back(); + auto thr = impl_->invoke_stack.back(); if(thr.tid == nana::system::this_thread_id()) { - stack_.pop_back(); - for(std::size_t i = 0; i < thr.refcnt; ++i) - std::recursive_mutex::lock(); - thr_ = thr; + impl_->invoke_stack.pop_back(); + for (std::size_t i = 0; i < thr.ref; ++i) + impl_->mutex.lock(); + impl_->thread = thr; } else throw std::runtime_error("Nana.GUI: The forward is not matched."); } - std::recursive_mutex::unlock(); + impl_->mutex.unlock(); } //end class revertible_mutex @@ -254,23 +272,13 @@ namespace detail return (impl_->wd_register.available(a) && impl_->wd_register.available(b)); } - bool window_manager::available(native_window_type wd) - { - if(wd) - { - std::lock_guard 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) { native_window_type native = nullptr; if (owner) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(owner)) { @@ -306,11 +314,10 @@ namespace detail wd->title = native_interface::window_caption(result.native_handle); //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); //create Root graphics Buffer and manage it - root_misc misc(wd, result.width, result.height); - auto* value = impl_->misc_register.insert(result.native_handle, misc); + auto* value = impl_->misc_register.insert(result.native_handle, root_misc(wd, result.width, result.height)); 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); @@ -331,7 +338,7 @@ namespace detail window_manager::core_window_t* window_manager::create_frame(core_window_t* parent, const rectangle& r, widget* wdg) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(parent) == false) return nullptr; @@ -350,7 +357,7 @@ namespace detail if(frame) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if(category::flags::frame == frame->other.category) frame->other.attribute.frame->attach.push_back(wd); return true; @@ -363,7 +370,7 @@ namespace detail if(frame) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if(category::flags::frame == frame->other.category) { if (impl_->wd_register.available(wd) && (category::flags::root == wd->other.category) && wd->root != frame->root) @@ -380,7 +387,7 @@ namespace detail window_manager::core_window_t* window_manager::create_widget(core_window_t* parent, const rectangle& r, bool is_lite, widget* wdg) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(parent) == false) throw std::invalid_argument("invalid parent/owner handle"); @@ -401,7 +408,7 @@ namespace detail void window_manager::close(core_window_t *wd) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd) == false) return; if (wd->flags.destroying) @@ -443,7 +450,7 @@ namespace detail void window_manager::destroy(core_window_t* wd) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd) == false) return; rectangle update_area(wd->pos_owner, wd->dimension); @@ -467,7 +474,7 @@ namespace detail void window_manager::destroy_handle(core_window_t* wd) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd) == false) return; #ifndef WIDGET_FRAME_DEPRECATED @@ -491,7 +498,7 @@ namespace detail { if(!big_icon.empty() || !small_icon.empty()) { - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { if(category::flags::root == wd->other.category) @@ -505,7 +512,7 @@ namespace detail bool window_manager::show(core_window_t* wd, bool visible) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (!impl_->wd_register.available(wd)) return false; @@ -548,7 +555,7 @@ namespace detail if((false == attr_.capture.ignore_children) || (nullptr == attr_.capture.window) || (attr_.capture.window->root != root)) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); auto rrt = root_runtime(root); point pos{ x, y }; if (rrt && _m_effective(rrt->window, pos)) @@ -561,7 +568,7 @@ namespace detail bool window_manager::move(core_window_t* wd, int x, int y, bool passive) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { if (category::flags::root != wd->other.category) @@ -606,7 +613,7 @@ namespace detail bool window_manager::move(core_window_t* wd, const rectangle& r) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (!impl_->wd_register.available(wd)) return false; @@ -680,7 +687,7 @@ namespace detail bool window_manager::size(core_window_t* wd, nana::size sz, bool passive, bool ask_update) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (!impl_->wd_register.available(wd)) return false; @@ -767,7 +774,7 @@ namespace detail if(cache.first == wd) return cache.second; //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); auto rrt = root_runtime(wd); if(rrt) @@ -783,7 +790,7 @@ namespace detail void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd) && !wd->is_draw_through()) { auto parent = wd->parent; @@ -805,7 +812,7 @@ namespace detail bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd) == false) return false; if (wd->displayed()) @@ -837,7 +844,7 @@ namespace detail void window_manager::refresh_tree(core_window_t* wd) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); //It's not worthy to redraw if visible is false if (impl_->wd_register.available(wd) && wd->displayed()) @@ -850,7 +857,7 @@ namespace detail bool window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (false == impl_->wd_register.available(wd)) return false; @@ -888,7 +895,7 @@ namespace detail bool window_manager::get_graphics(core_window_t* wd, nana::paint::graphics& result) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (!impl_->wd_register.available(wd)) return false; @@ -901,7 +908,7 @@ namespace detail bool window_manager::get_visual_rectangle(core_window_t* wd, nana::rectangle& r) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); return (impl_->wd_register.available(wd) ? window_layer::read_visual_rectangle(wd, r) : false); @@ -909,7 +916,7 @@ namespace detail std::vector window_manager::get_children(core_window_t* wd) const { - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) return wd->children; return{}; @@ -918,7 +925,7 @@ namespace detail bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (!impl_->wd_register.available(wd)) return false; @@ -945,7 +952,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) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (!impl_->wd_register.available(wd)) return nullptr; @@ -1051,7 +1058,7 @@ namespace detail if(wd != attr_.capture.window) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { @@ -1112,7 +1119,7 @@ namespace detail void window_manager::enable_tabstop(core_window_t* wd) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd) && (detail::tab_type::none == wd->flags.tab)) { wd->root_widget->other.attribute.root->tabstop.push_back(wd); @@ -1156,7 +1163,7 @@ namespace detail auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t* { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (!impl_->wd_register.available(wd)) return nullptr; @@ -1198,7 +1205,7 @@ namespace detail bool window_manager::enable_effects_bground(core_window_t* wd, bool enabled) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) return window_layer::enable_effects_bground(wd, enabled); @@ -1208,7 +1215,7 @@ namespace detail bool window_manager::calc_window_point(core_window_t* wd, nana::point& pos) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { if(native_interface::calc_window_point(wd->root, pos)) @@ -1220,7 +1227,7 @@ namespace detail 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); } @@ -1228,7 +1235,7 @@ namespace detail bool window_manager::register_shortkey(core_window_t* wd, unsigned long key) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { auto object = root_runtime(wd->root); @@ -1241,7 +1248,7 @@ namespace detail void window_manager::unregister_shortkey(core_window_t* wd, bool with_children) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd) == false) return; auto root_rt = root_runtime(wd->root); @@ -1261,7 +1268,7 @@ namespace detail std::vector> result; //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { auto root_rt = root_runtime(wd->root); @@ -1290,7 +1297,7 @@ namespace detail if(native_window) { //Thread-Safe Required! - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); auto object = root_runtime(native_window); if(object) return reinterpret_cast(object->shortkeys.find(key)); @@ -1302,7 +1309,7 @@ namespace detail { if (fn) { - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); if (!available(wd)) return; @@ -1312,21 +1319,21 @@ namespace detail void window_manager::call_safe_place(unsigned thread_id) { - std::lock_guard lock(mutex_); + std::lock_guard 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) { for (auto & fn : i->second) fn(); - i = impl_->safe_place.erase(i); + i = safe_place.erase(i); } else ++i; } - } bool check_tree(basic_window* wd, basic_window* const cond) diff --git a/source/gui/dragger.cpp b/source/gui/dragger.cpp index 459d9833..44ea2254 100644 --- a/source/gui/dragger.cpp +++ b/source/gui/dragger.cpp @@ -159,7 +159,7 @@ namespace nana } }); - triggers_.push_back(tg); + triggers_.emplace_back(tg); } private: static void _m_check_restrict_area(nana::point & pos, const nana::size & size, const nana::rectangle& restr_area) diff --git a/source/gui/element.cpp b/source/gui/element.cpp index 48adbbfc..3886e1f4 100644 --- a/source/gui/element.cpp +++ b/source/gui/element.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #if defined(STD_THREAD_NOT_SUPPORTED) #include @@ -599,7 +598,6 @@ namespace nana { using element_type = ElementInterface; using factory_interface = pat::cloneable; - public: ~element_object() { @@ -1156,46 +1154,48 @@ namespace nana } }; + + struct bground::implementation + { + draw_method * method{ nullptr }; + + bool vert{ false }; + rectangle valid_area; + std::vector states; + std::map join; + + bool stretch_all{ true }; + unsigned left{ 0 }, top{ 0 }, right{ 0 }, bottom{ 0 }; + }; + + bground::bground() - : method_(nullptr), - vertical_(false), - stretch_all_(true), - left_(0), top_(0), right_(0), bottom_(0) + : impl_{ new implementation } { reset_states(); } bground::bground(const bground& rhs) - : method_(rhs.method_ ? rhs.method_->clone() : nullptr), - 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_) + : impl_{ new implementation } { + if (impl_->method) + impl_->method = impl_->method->clone(); } bground::~bground() { - delete method_; + delete impl_->method; } bground& bground::operator=(const bground& rhs) { if (this != &rhs) { - delete method_; - method_ = (rhs.method_ ? rhs.method_->clone() : nullptr); - 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_; + delete impl_->method; + + impl_.reset(new implementation(*rhs.impl_)); + if (impl_->method) + impl_->method = impl_->method->clone(); } return *this; } @@ -1203,106 +1203,110 @@ namespace nana //Set a picture for the background bground& bground::image(const paint::image& img, bool vertical, const nana::rectangle& valid_area) { - delete method_; - method_ = new draw_image(img); - vertical_ = vertical; + delete impl_->method; + impl_->method = new draw_image(img); + impl_->vert = vertical; if (valid_area.width && valid_area.height) - valid_area_ = valid_area; + impl_->valid_area = valid_area; else - valid_area_ = nana::rectangle(img.size()); + impl_->valid_area = nana::rectangle(img.size()); return *this; } bground& bground::image(const paint::graphics& graph, bool vertical, const nana::rectangle& valid_area) { - delete method_; - method_ = new draw_graph(graph); - vertical_ = vertical; + delete impl_->method; + impl_->method = new draw_graph(graph); + impl_->vert = vertical; if (valid_area.width && valid_area.height) - valid_area_ = valid_area; + impl_->valid_area = valid_area; else - valid_area_ = nana::rectangle(graph.size()); + impl_->valid_area = nana::rectangle(graph.size()); return *this; } //Set the state sequence of the background picture. void bground::states(const std::vector & s) { - states_ = s; + impl_->states = s; } void bground::states(std::vector && s) { - states_ = std::move(s); + impl_->states = std::move(s); } void bground::reset_states() { - states_.clear(); - states_.push_back(element_state::normal); - states_.push_back(element_state::hovered); - states_.push_back(element_state::focus_normal); - states_.push_back(element_state::focus_hovered); - states_.push_back(element_state::pressed); - states_.push_back(element_state::disabled); - join_.clear(); + auto & st = impl_->states; + + st.clear(); + st.push_back(element_state::normal); + st.push_back(element_state::hovered); + st.push_back(element_state::focus_normal); + st.push_back(element_state::focus_hovered); + st.push_back(element_state::pressed); + st.push_back(element_state::disabled); + impl_->join.clear(); } 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) { - left_ = left; - top_ = top; - right_ = right; - bottom_ = bottom; + impl_->left = left; + impl_->right = right; + impl_->top = top; + impl_->bottom = bottom; - stretch_all_ = !(left || right || top || bottom); + impl_->stretch_all = !(left || right || top || bottom); } //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) { - if (nullptr == method_) + const auto method = impl_->method; + + if (nullptr == method) return false; - auto mi = join_.find(state); - if (mi != join_.end()) + auto mi = impl_->join.find(state); + if (mi != impl_->join.end()) state = mi->second; 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; } - if (pos == states_.size()) + if (pos == impl_->states.size()) return false; - nana::rectangle from_r = valid_area_; - if (vertical_) + nana::rectangle from_r = impl_->valid_area; + if (impl_->vert) { - from_r.height /= static_cast(states_.size()); + from_r.height /= static_cast(impl_->states.size()); from_r.y += static_cast(from_r.height * pos); } else { - from_r.width /= static_cast(states_.size()); + from_r.width /= static_cast(impl_->states.size()); from_r.x += static_cast(from_r.width * pos); } - if (stretch_all_) + if (impl_->stretch_all) { 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 - method_->stretch(from_r, dst, to_r); + method->stretch(from_r, dst, to_r); return true; } @@ -1311,118 +1315,123 @@ namespace nana auto perf_from_r = from_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; - src_r.y += static_cast(top_); - src_r.height -= top_ + bottom_; + src_r.y += static_cast(top); + src_r.height -= top + bottom; nana::rectangle dst_r = to_r; - dst_r.y += static_cast(top_); - dst_r.height -= top_ + bottom_; + dst_r.y += static_cast(top); + dst_r.height -= top + bottom; - if (left_) + if (left) { - src_r.width = left_; - dst_r.width = left_; + src_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(left_); - perf_from_r.width -= left_; - perf_to_r.x += static_cast(left_); - perf_to_r.width -= left_; + perf_from_r.x += static_cast(left); + perf_from_r.width -= left; + perf_to_r.x += static_cast(left); + perf_to_r.width -= left; } - if (right_) + if (right) { - src_r.x += (static_cast(from_r.width) - static_cast(right_)); - src_r.width = right_; + src_r.x += (static_cast(from_r.width) - static_cast(right)); + src_r.width = right; - dst_r.x += (static_cast(to_r.width) - static_cast(right_)); - dst_r.width = right_; + dst_r.x += (static_cast(to_r.width) - static_cast(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_to_r.width -= right_; + perf_from_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; - src_r.x += static_cast(left_); - src_r.width -= left_ + right_; + src_r.x += static_cast(left); + src_r.width -= left + right; nana::rectangle dst_r = to_r; - dst_r.x += static_cast(left_); - dst_r.width -= left_ + right_; + dst_r.x += static_cast(left); + dst_r.width -= left + right; - if (top_) + if (top) { - src_r.height = top_; - dst_r.height = top_; + src_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(top_); - perf_to_r.y += static_cast(top_); + perf_from_r.y += static_cast(top); + perf_to_r.y += static_cast(top); } - if (bottom_) + if (bottom) { - src_r.y += static_cast(from_r.height - bottom_); - src_r.height = bottom_; + src_r.y += static_cast(from_r.height - bottom); + src_r.height = bottom; - dst_r.y += static_cast(to_r.height - bottom_); - dst_r.height = bottom_; + dst_r.y += static_cast(to_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_to_r.height -= (top_ + bottom_); + perf_from_r.height -= (top + bottom); + perf_to_r.height -= (top + bottom); } - if (left_) + if (left) { nana::rectangle src_r = from_r; - src_r.width = left_; - if (top_) + src_r.width = left; + if (top) { - src_r.height = top_; - method_->paste(src_r, dst, to_r.position()); + src_r.height = top; + method->paste(src_r, dst, to_r.position()); } - if (bottom_) + if (bottom) { - src_r.y += static_cast(from_r.height) - static_cast(bottom_); - src_r.height = bottom_; - method_->paste(src_r, dst, nana::point(to_r.x, to_r.y + static_cast(to_r.height - bottom_))); + src_r.y += static_cast(from_r.height) - static_cast(bottom); + src_r.height = bottom; + method->paste(src_r, dst, nana::point(to_r.x, to_r.y + static_cast(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; - src_r.x += static_cast(src_r.width) - static_cast(right_); - src_r.width = right_; - if (top_) + src_r.x += static_cast(src_r.width) - static_cast(right); + src_r.width = right; + if (top) { - src_r.height = top_; - method_->paste(src_r, dst, nana::point(to_x, to_r.y)); + src_r.height = top; + method->paste(src_r, dst, nana::point(to_x, to_r.y)); } - if (bottom_) + if (bottom) { - src_r.y += (static_cast(from_r.height) - static_cast(bottom_)); - src_r.height = bottom_; - method_->paste(src_r, dst, nana::point(to_x, to_r.y + int(to_r.height - bottom_))); + src_r.y += (static_cast(from_r.height) - static_cast(bottom)); + src_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; } //end class bground diff --git a/source/gui/place.cpp b/source/gui/place.cpp index a10246f9..d6b6e7e3 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -661,13 +661,14 @@ namespace nana //This is a splitter, it only checks when it is being displayed if (dsp) { + //Left field of splitterbar auto left = this->previous(); if (left && !left->display) left->set_display(true); - auto right = div_next; - if (right && !right->display) - right->set_display(true); + //Right field of splitterbar + if (div_next && !div_next->display) + div_next->set_display(true); } } } diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 787a2183..94446c8b 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -104,7 +104,7 @@ namespace API { 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(static_cast(en) | static_cast(iwd->effect.edge_nimbus)); } @@ -365,7 +365,7 @@ namespace API } if (!exists) - roots.push_back(root); + roots.emplace_back(root); } } @@ -401,7 +401,7 @@ namespace API } if (!exists) - roots.push_back(root); + roots.emplace_back(root); } } diff --git a/source/gui/timer.cpp b/source/gui/timer.cpp index 589d0107..bb165436 100644 --- a/source/gui/timer.cpp +++ b/source/gui/timer.cpp @@ -47,8 +47,7 @@ namespace nana friend class timer_core; - timer_driver() - {} + timer_driver() = default; public: static timer_driver& instance() { diff --git a/source/gui/tooltip.cpp b/source/gui/tooltip.cpp index e4a03634..847fbab0 100644 --- a/source/gui/tooltip.cpp +++ b/source/gui/tooltip.cpp @@ -60,7 +60,7 @@ namespace nana typedef widget_object base_type; public: tip_form() - : base_type(nana::rectangle(), appear::bald()), + : base_type(nullptr, false, rectangle(), appear::bald()), duration_(0) { API::take_active(this->handle(), false, nullptr); diff --git a/source/gui/widgets/checkbox.cpp b/source/gui/widgets/checkbox.cpp index f5980da9..b1a2fe88 100644 --- a/source/gui/widgets/checkbox.cpp +++ b/source/gui/widgets/checkbox.cpp @@ -285,8 +285,7 @@ namespace nana{ namespace drawerbase } }); - - ui_container_.push_back(el); + ui_container_.emplace_back(el); } std::size_t radio_group::checked() const diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index 3b494683..1ea6d1e9 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -174,7 +174,7 @@ namespace nana editor_->show_caret(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_to = colors::button_face_shadow_end; @@ -190,7 +190,7 @@ namespace nana }; } else - editor_->ext_renderer().background = nullptr; + editor_->customized_renderers().background = nullptr; editor_->enable_background(enb); editor_->enable_background_counterpart(!enb); diff --git a/source/gui/widgets/float_listbox.cpp b/source/gui/widgets/float_listbox.cpp index 34c5a03f..d47098cb 100644 --- a/source/gui/widgets/float_listbox.cpp +++ b/source/gui/widgets/float_listbox.cpp @@ -13,6 +13,8 @@ #include #include +#include + namespace nana { namespace drawerbase{ @@ -66,35 +68,7 @@ namespace nana unsigned vpix = (r.height - 4); if(item->image()) { - nana::size imgsz = item->image().size(); - 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; - } - } + auto imgsz = nana::fit_zoom(item->image().size(), {image_pixels_, vpix}); nana::point to_pos(x, r.y + 2); to_pos.x += (image_pixels_ - imgsz.width) / 2; diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index d500eed9..93a1d9a1 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -206,15 +206,13 @@ namespace nana { if(fbp->target.size() || fbp->url.size()) { - traceable tr; + traceable_.emplace_back(); + auto & tr = traceable_.back(); tr.r.x = x; tr.r.y = y; - tr.r.width = sz.width; - tr.r.height = sz.height; + tr.r.dimension(sz); tr.target = fbp->target; tr.url = fbp->url; - - traceable_.push_back(tr); } } @@ -331,7 +329,7 @@ namespace nana px.pixels = def_line_pixels; px.x_base = 0; - rs.pixels.push_back(px); + rs.pixels.emplace_back(px); return 0; } @@ -374,7 +372,7 @@ namespace nana if(max_ascent < as) max_ascent = as; if(max_descent < ds) max_descent = ds; if(max_px < sz.height) max_px = sz.height; - line_values.push_back(i); + line_values.emplace_back(i); } else { @@ -393,13 +391,13 @@ namespace nana px.baseline = max_ascent; px.values.swap(line_values); - rs.pixels.push_back(px); + rs.pixels.emplace_back(px); w = sz.width; max_px = sz.height; max_ascent = as; max_descent = ds; - line_values.push_back(i); + line_values.emplace_back(i); } else { @@ -409,9 +407,9 @@ namespace nana px.pixels = sz.height; 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_ascent = max_descent = 0; } @@ -432,7 +430,7 @@ namespace nana px.pixels = max_px; px.baseline = max_ascent; px.values.swap(line_values); - rs.pixels.push_back(px); + rs.pixels.emplace_back(px); } return total_w; } diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 5da2dc15..3ccb4fa0 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace nana { @@ -972,6 +973,7 @@ namespace nana if (catobj.model_ptr) { + throw_if_immutable_model(catobj.model_ptr.get()); auto container = catobj.model_ptr->container(); std::size_t item_index; // @@ -1249,28 +1251,17 @@ namespace nana return n; } - std::vector& get_cells(category_t * cat, std::size_t pos) const + std::vector get_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 disallow to get item cells, because there are model cells"); + return cat->model_ptr->container()->to_cells(pos); return *(cat->items.at(pos).cells); } - std::vector 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) { if ((col < columns) && (pos < cat->items.size())) @@ -2868,8 +2859,8 @@ namespace nana return *this; } - iresolver::iresolver(const std::vector& cl) - : cells_(cl) + iresolver::iresolver(std::vector cl) + : cells_(std::move(cl)) {} iresolver& iresolver::operator>>(cell& cl) @@ -4565,14 +4556,6 @@ namespace nana 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; } @@ -4692,7 +4675,7 @@ namespace nana return pos_; } - auto item_proxy::_m_cells() const -> std::vector& + auto item_proxy::_m_cells() const -> std::vector { return ess_->lister.get_cells(cat_, pos_.item); } @@ -5027,9 +5010,24 @@ namespace nana internal_scope_guard lock; - cat_->sorted.push_back(cat_->items.size()); - cells.resize(columns()); - cat_->items.emplace_back(std::move(cells)); + if (cat_->model_ptr) + { + 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_); } diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 2ba13a4d..91493d8a 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -18,6 +18,7 @@ #include #include #include //introduces tolower +#include namespace nana { diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 03168ce1..d650c59d 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -13,17 +13,117 @@ #include #include #include +#include #include #include + #include #include #include #include +#include namespace nana{ namespace widgets { namespace skeletons { + + template + 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 + class undoable + { + public: + using command = EnumCommand; + using container = std::deque < std::unique_ptr> >; + + 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> && 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 }; + }; + template using undo_command_ptr = std::unique_ptr > ; @@ -105,7 +205,7 @@ namespace nana{ namespace widgets editor_.backspace(false); } else - editor_.textbase_.erase(pos_.y, pos_.x, selected_text_.size()); + editor_.textbase().erase(pos_.y, pos_.x, selected_text_.size()); } } else @@ -184,7 +284,7 @@ namespace nana{ namespace widgets editor_.select_.a = editor_.select_.b; } else - editor_.textbase_.erase(pos_.y, pos_.x, text_.size()); //undo + editor_.textbase().erase(pos_.y, pos_.x, text_.size()); //undo if (!selected_text_.empty()) { @@ -291,7 +391,7 @@ namespace nana{ namespace widgets std::size_t take_lines() const override { - return editor_.textbase_.lines(); + return editor_.textbase().lines(); } std::size_t take_lines(std::size_t) const override @@ -303,7 +403,7 @@ namespace nana{ namespace widgets { int top = editor_._m_text_top_base() + static_cast(editor_.line_height() * (textline - editor_.points_.offset.y)); editor_.graph_.rectangle({ editor_.text_area_.area.x, top, editor_.text_area_.area.width, editor_.line_height() }, true, API::bgcolor(editor_.window_)); - editor_._m_draw_string(top, API::fgcolor(editor_.window_), nana::upoint(0, editor_.points_.caret.y), editor_.textbase_.getline(textline), true); + editor_._m_draw_string(top, API::fgcolor(editor_.window_), nana::upoint(0, editor_.points_.caret.y), editor_.textbase().getline(textline), true); } std::vector render(const ::nana::color& fgcolor) override @@ -312,15 +412,15 @@ namespace nana{ namespace widgets ::nana::upoint str_pos(0, static_cast(editor_.points_.offset.y)); - const auto scrlines = (std::min)(editor_.screen_lines() + str_pos.y, static_cast(editor_.textbase_.lines())); + const auto scrlines = (std::min)(editor_.screen_lines() + str_pos.y, static_cast(editor_.textbase().lines())); int top = editor_._m_text_top_base(); const unsigned pixels = editor_.line_height(); while( str_pos.y < scrlines) { - editor_._m_draw_string(top, fgcolor, str_pos, editor_.textbase_.getline(str_pos.y), true); - line_index.push_back(str_pos); + editor_._m_draw_string(top, fgcolor, str_pos, editor_.textbase().getline(str_pos.y), true); + line_index.emplace_back(str_pos); ++str_pos.y; top += pixels; } @@ -330,9 +430,9 @@ namespace nana{ namespace widgets nana::point caret_to_screen(nana::upoint pos) override { - pos.y = (std::min)(pos.y, static_cast(editor_.textbase_.lines())); + pos.y = (std::min)(pos.y, static_cast(editor_.textbase().lines())); - auto text_ptr = &editor_.textbase_.getline(pos.y); + auto text_ptr = &editor_.textbase().getline(pos.y); std::wstring mask_str; if (editor_.mask_char_) @@ -353,7 +453,7 @@ namespace nana{ namespace widgets //Convert the screen point to text caret point - auto text_ptr = &editor_.textbase_.getline(res.y); + auto text_ptr = &editor_.textbase().getline(res.y); std::wstring mask_str; if (editor_.mask_char_) @@ -394,12 +494,14 @@ namespace nana{ namespace widgets { auto & points = editor_.points_; + auto & textbase = editor_.textbase(); + if (to_north) //North { if (points.caret.y) { points.caret.x = (std::min)(points.xpos, - static_cast(editor_.textbase_.getline(--points.caret.y).size()) + static_cast(textbase.getline(--points.caret.y).size()) ); bool out_of_screen = (static_cast(points.caret.y) < points.offset.y); @@ -411,10 +513,10 @@ namespace nana{ namespace widgets } else //South { - if (points.caret.y + 1 < editor_.textbase_.lines()) + if (points.caret.y + 1 < textbase.lines()) { points.caret.x = (std::min)(points.xpos, - static_cast(editor_.textbase_.getline(++points.caret.y).size()) + static_cast(textbase.getline(++points.caret.y).size()) ); return adjust_caret_into_screen(); @@ -433,7 +535,7 @@ namespace nana{ namespace widgets return false; auto& points = editor_.points_; - auto& textbase = editor_.textbase_; + auto& textbase = editor_.textbase(); editor_._m_get_scrollbar_size(); @@ -480,7 +582,7 @@ namespace nana{ namespace widgets private: std::size_t _m_textline_from_screen(int y) const { - const std::size_t textlines = editor_.textbase_.lines(); + const std::size_t textlines = editor_.textbase().lines(); const auto line_px = static_cast(editor_.line_height()); if ((0 == textlines) || (0 == line_px)) return 0; @@ -542,7 +644,7 @@ namespace nana{ namespace widgets std::size_t line = 0; for (auto & mtr: linemtr_) { - auto& linestr = editor_.textbase_.getline(line); + auto& linestr = editor_.textbase().getline(line); auto p = mtr.line_sections.front().begin; if (p < linestr.c_str() || (linestr.c_str() + linestr.size() < p)) pre_calc_line(line, editor_.width_pixels()); @@ -565,7 +667,7 @@ namespace nana{ namespace widgets { if (line < pos || (pos + lines) <= line) { - auto & linestr = editor_.textbase_.getline(line); + auto & linestr = editor_.textbase().getline(line); auto p = mtr.line_sections.front().begin; if (p < linestr.c_str() || (linestr.c_str() + linestr.size() < p)) pre_calc_line(line, editor_.width_pixels()); @@ -577,7 +679,7 @@ namespace nana{ namespace widgets void pre_calc_line(std::size_t line, unsigned pixels) override { - const string_type& lnstr = editor_.textbase_.getline(line); + const string_type& lnstr = editor_.textbase().getline(line); if (lnstr.empty()) { auto & mtr = linemtr_[line]; @@ -660,7 +762,7 @@ namespace nana{ namespace widgets void pre_calc_lines(unsigned pixels) override { - const auto lines = editor_.textbase_.lines(); + const auto lines = editor_.textbase().lines(); linemtr_.resize(lines); for (std::size_t i = 0; i < lines; ++i) @@ -691,7 +793,7 @@ namespace nana{ namespace widgets editor_.graph_.rectangle({ editor_.text_area_.area.x, top, editor_.width_pixels(), static_cast(pixels * secondary_before) }, true, API::bgcolor(editor_.window_)); auto fgcolor = API::fgcolor(editor_.window_); - auto text_ptr = editor_.textbase_.getline(textline).c_str(); + auto text_ptr = editor_.textbase().getline(textline).c_str(); for (std::size_t pos = 0; pos < secondary_before; ++pos, top+=pixels) { @@ -712,7 +814,7 @@ namespace nana{ namespace widgets return line_index; nana::upoint str_pos(0, static_cast(row.first)); - str_pos.x = static_cast(linemtr_[row.first].line_sections[row.second].begin - editor_.textbase_.getline(row.first).c_str()); + str_pos.x = static_cast(linemtr_[row.first].line_sections[row.second].begin - editor_.textbase().getline(row.first).c_str()); int top = editor_._m_text_top_base(); const unsigned pixels = editor_.line_height(); @@ -727,7 +829,7 @@ namespace nana{ namespace widgets std::wstring text(section.begin, section.end); editor_._m_draw_string(top, fgcolor, str_pos, text, true); - line_index.push_back(str_pos); + line_index.emplace_back(str_pos); ++row.second; if (row.second >= mtr.line_sections.size()) { @@ -838,7 +940,7 @@ namespace nana{ namespace widgets } scrpos.x -= str_px; } - res.x = static_cast(editor_.textbase_.getline(res.y).size()); + res.x = static_cast(editor_.textbase().getline(res.y).size()); return res; } @@ -868,7 +970,7 @@ namespace nana{ namespace widgets if (secondary_pos.y >= take_lines(points.caret.y)) { secondary_pos.y = 0; - if (points.caret.y + 1 >= editor_.textbase_.lines()) + if (points.caret.y + 1 >= editor_.textbase().lines()) return false; ++points.caret.y; @@ -1050,7 +1152,7 @@ namespace nana{ namespace widgets auto & section = mtr.line_sections[secondary.y]; auto chptr = section.begin + (std::min)(secondary.x, static_cast(section.end - section.begin)); - pos = static_cast(chptr - editor_.textbase_.getline(textline).c_str()); + pos = static_cast(chptr - editor_.textbase().getline(textline).c_str()); return true; } @@ -1102,7 +1204,7 @@ namespace nana{ namespace widgets row_coordinate coord; const auto line_px = static_cast(editor_.line_height()); - if ((0 == editor_.textbase_.lines()) || (0 == line_px)) + if ((0 == editor_.textbase().lines()) || (0 == line_px)) return coord; const int text_area_top = editor_.text_area_.area.y; @@ -1146,11 +1248,13 @@ namespace nana{ namespace widgets {} }; + /* struct text_editor::keywords { std::map> schemes; std::deque kwbase; }; + */ struct entity { @@ -1159,12 +1263,56 @@ namespace nana{ namespace widgets const keyword_scheme * scheme; }; + + struct text_editor::implementation + { + undoable undo; //undo command + renderers customized_renderers; + std::vector text_position; //positions of text since last rendering. + + skeletons::textbase textbase; + + struct inner_capacities + { + editor_behavior_interface * behavior; + + accepts acceptive{ accepts::no_restrict }; + std::function pred_acceptive; + }capacities; + + struct inner_counterpart + { + bool enabled{ false }; + paint::graphics buffer; //A offscreen buffer which keeps the background that painted by external part. + }counterpart; + + + struct indent_rep + { + bool enabled{ false }; + std::function generator; + }indent; + + + struct inner_keywords + { + std::map> schemes; + std::deque base; + }keywords; + + struct inner_widgets + { + std::unique_ptr> vscroll; + std::unique_ptr> hscroll; + }widgets; + }; + class text_editor::keyword_parser { public: - void parse(const std::wstring& text, const keywords* kwptr) + void parse(const std::wstring& text, const implementation::inner_keywords& keywords) { - if ( kwptr->kwbase.empty() || text.empty() ) + if ( keywords.base.empty() || text.empty() ) return; using index = std::wstring::size_type; @@ -1172,7 +1320,7 @@ namespace nana{ namespace widgets std::vector entities; ::nana::ciwstring cistr; - for (auto & ds : kwptr->kwbase) + for (auto & ds : keywords.base) { index pos{0} ; for (index rest{text.size()}; rest >= ds.text.size() ; ++pos, rest = text.size() - pos) @@ -1205,8 +1353,8 @@ namespace nana{ namespace widgets } } - auto ki = kwptr->schemes.find(ds.scheme); - if (ki != kwptr->schemes.end() && ki->second) + auto ki = keywords.schemes.find(ds.scheme); + if (ki != keywords.schemes.end() && ki->second) { entities.emplace_back(); auto & last = entities.back(); @@ -1267,13 +1415,15 @@ namespace nana{ namespace widgets }; //class text_editor + text_editor::text_editor(window wd, graph_reference graph, const text_editor_scheme* schm) - : behavior_(new behavior_normal(*this)), + : impl_(new implementation), window_(wd), - caret_(API::open_caret(wd, true)), graph_(graph), - scheme_(schm), keywords_(new keywords) + scheme_(schm) { + impl_->capacities.behavior = new behavior_normal(*this); + text_area_.area.dimension(graph.size()); text_area_.captured = false; text_area_.tab_space = 4; @@ -1288,44 +1438,38 @@ namespace nana{ namespace widgets API::create_caret(wd, { 1, line_height() }); API::bgcolor(wd, colors::white); API::fgcolor(wd, colors::black); - - text_area_.border_renderer = [this](graph_reference graph, const ::nana::color& bgcolor) - { - if (!API::widget_borderless(this->window_)) - { - ::nana::facade facade; - facade.draw(graph, bgcolor, API::fgcolor(this->window_), ::nana::rectangle{ API::window_size(this->window_) }, API::element_state(this->window_)); - } - }; } text_editor::~text_editor() { //For instance of unique_ptr pimpl idiom. + + delete impl_->capacities.behavior; + delete impl_; } void text_editor::set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor) { if (fgcolor.invisible() && bgcolor.invisible()) { - keywords_->schemes.erase(name); + impl_->keywords.schemes.erase(name); return; } auto sp = std::make_shared(); sp->fgcolor = fgcolor; sp->bgcolor = bgcolor; - keywords_->schemes[name].swap(sp); + impl_->keywords.schemes[name].swap(sp); } void text_editor::erase_highlight(const std::string& name) { - keywords_->schemes.erase(name); + impl_->keywords.schemes.erase(name); } void text_editor::set_keyword(const ::std::wstring& kw, const std::string& name, bool case_sensitive, bool whole_word_matched) { - for (auto & ds : keywords_->kwbase) + for(auto & ds : impl_->keywords.base) { if (ds.text == kw) { @@ -1336,16 +1480,16 @@ namespace nana{ namespace widgets } } - keywords_->kwbase.emplace_back(kw, name, case_sensitive, whole_word_matched); + impl_->keywords.base.emplace_back(kw, name, case_sensitive, whole_word_matched); } void text_editor::erase_keyword(const ::std::wstring& kw) { - for (auto i = keywords_->kwbase.begin(); i != keywords_->kwbase.end(); ++i) + for (auto i = impl_->keywords.base.begin(); i != impl_->keywords.base.end(); ++i) { - if (i->text == kw) + if (kw == i->text) { - keywords_->kwbase.erase(i); + impl_->keywords.base.erase(i); return; } } @@ -1353,12 +1497,12 @@ namespace nana{ namespace widgets void text_editor::set_accept(std::function pred) { - attributes_.pred_acceptive = std::move(pred); + impl_->capacities.pred_acceptive = std::move(pred); } void text_editor::set_accept(accepts acceptive) { - attributes_.acceptive = acceptive; + impl_->capacities.acceptive = acceptive; } bool text_editor::respond_char(const arg_keyboard& arg) //key is a character of ASCII code @@ -1374,7 +1518,7 @@ namespace nana{ namespace widgets return true; } - if (attributes_.editable && API::window_enabled(window_) && (!attributes_.pred_acceptive || attributes_.pred_acceptive(key))) + if (attributes_.editable && API::window_enabled(window_) && (!impl_->capacities.pred_acceptive || impl_->capacities.pred_acceptive(key))) { switch (key) { @@ -1421,7 +1565,7 @@ namespace nana{ namespace widgets case keyboard::os_end: case keyboard::os_pageup: case keyboard::os_pagedown: - _handle_move_key(arg); + _m_handle_move_key(arg); break; case keyboard::os_del: if (this->attr().editable) @@ -1435,13 +1579,17 @@ namespace nana{ namespace widgets void text_editor::typeface_changed() { - behavior_->pre_calc_lines(width_pixels()); + impl_->capacities.behavior->pre_calc_lines(width_pixels()); } void text_editor::indent(bool enb, std::function generator) { + /* indent_.enabled = enb; indent_.generator = std::move(generator); + */ + impl_->indent.enabled = enb; + impl_->indent.generator = std::move(generator); } void text_editor::set_event(event_interface* ptr) @@ -1459,20 +1607,22 @@ namespace nana{ namespace widgets if (autl != attributes_.line_wrapped) { attributes_.line_wrapped = autl; + + delete impl_->capacities.behavior; if (autl) { - behavior_.reset(new behavior_linewrapped(*this)); + impl_->capacities.behavior = new behavior_linewrapped(*this); text_area_.vscroll = text_area_.scroll_pixels; text_area_.hscroll = 0; - behavior_->pre_calc_lines(width_pixels()); + impl_->capacities.behavior->pre_calc_lines(width_pixels()); } else - behavior_.reset(new behavior_normal(*this)); + impl_->capacities.behavior = new behavior_normal(*this); points_.offset.x = 0; _m_offset_y(0); move_caret(upoint{}); - + _m_scrollbar(); render(API::is_focus_ready(window_)); return true; @@ -1480,18 +1630,13 @@ namespace nana{ namespace widgets return false; } - void text_editor::border_renderer(std::function f) - { - text_area_.border_renderer = f; - } - bool text_editor::load(const char* fs) { - if (!textbase_.load(fs)) + if (!impl_->textbase.load(fs)) return false; _m_reset(); - behavior_->pre_calc_lines(width_pixels()); + impl_->capacities.behavior->pre_calc_lines(width_pixels()); render(API::is_focus_ready(window_)); _m_scrollbar(); @@ -1504,10 +1649,11 @@ namespace nana{ namespace widgets return false; text_area_.area = r; - if(attributes_.enable_counterpart) - attributes_.counterpart.make({ r.width, r.height }); - behavior_->pre_calc_lines(width_pixels()); + if (impl_->counterpart.enabled) + impl_->counterpart.buffer.make(r.dimension()); + + impl_->capacities.behavior->pre_calc_lines(width_pixels()); _m_scrollbar(); move_caret(points_.caret); @@ -1516,13 +1662,7 @@ namespace nana{ namespace widgets rectangle text_editor::text_area(bool including_scroll) const { - auto r = text_area_.area; - if (!including_scroll) - { - r.width = r.width > text_area_.vscroll ? r.width - text_area_.vscroll : 0; - r.height = r.height > text_area_.hscroll ? r.height - text_area_.hscroll : 0; - } - return r; + return (including_scroll ? _m_text_area() : text_area_.area); } bool text_editor::tip_string(::std::string&& str) @@ -1544,7 +1684,7 @@ namespace nana{ namespace widgets if((ml == false) && attributes_.multi_lines) { //retain the first line and remove the extra lines - if (textbase_.erase(1, textbase_.lines() - 1)) + if (impl_->textbase.erase(1, impl_->textbase.lines() - 1)) _m_reset(); } @@ -1572,41 +1712,45 @@ namespace nana{ namespace widgets void text_editor::enable_background_counterpart(bool enb) { - attributes_.enable_counterpart = enb; - if(enb) - attributes_.counterpart.make({ text_area_.area.width, text_area_.area.height }); + impl_->counterpart.enabled = enb; + if (enb) + impl_->counterpart.buffer.make(text_area_.area.dimension()); else - attributes_.counterpart.release(); + impl_->counterpart.buffer.release(); } void text_editor::undo_enabled(bool enb) { - undo_.enable(enb); + impl_->undo.enable(enb); } bool text_editor::undo_enabled() const { - return undo_.enabled(); + return impl_->undo.enabled(); } void text_editor::undo_max_steps(std::size_t maxs) { - undo_.max_steps(maxs); + impl_->undo.max_steps(maxs); } std::size_t text_editor::undo_max_steps() const { - return undo_.max_steps(); + return impl_->undo.max_steps(); } - text_editor::ext_renderer_tag& text_editor::ext_renderer() const + auto text_editor::customized_renderers() -> renderers& { - return ext_renderer_; + return impl_->customized_renderers; } unsigned text_editor::line_height() const { - return (graph_ ? (graph_.text_extent_size(L"jH{").height) : 0); + unsigned ascent, descent, internal_leading; + if (graph_.text_metrics(ascent, descent, internal_leading)) + return ascent + descent; + + return 0; } unsigned text_editor::screen_lines() const @@ -1686,7 +1830,7 @@ namespace nana{ namespace widgets if (selection::mode::mouse_selected == select_.mode_selection || selection::mode::method_selected == select_.mode_selection) set_end_caret(); - text_area_.border_renderer(graph_, _m_bgcolor()); + _m_draw_border(); return true; } return false; @@ -1711,7 +1855,7 @@ namespace nana{ namespace widgets text_area_.captured = true; - if (this->hit_select_area(behavior_->screen_to_caret(arg.pos), true)) + if (this->hit_select_area(impl_->capacities.behavior->screen_to_caret(arg.pos), true)) { select_.mode_selection = selection::mode::move_selected; } @@ -1740,7 +1884,7 @@ namespace nana{ namespace widgets } } - text_area_.border_renderer(graph_, _m_bgcolor()); + _m_draw_border(); return true; } else if (event_code::mouse_up == arg.evt_code) @@ -1766,39 +1910,39 @@ namespace nana{ namespace widgets if (hit_text_area(arg.pos) == false) API::window_cursor(window_, nana::cursor::arrow); - text_area_.border_renderer(graph_, _m_bgcolor()); + _m_draw_border(); return updated; } return false; } - textbase & text_editor::textbase() + textbase & text_editor::textbase() { - return textbase_; + return impl_->textbase; } - const textbase & text_editor::textbase() const + const textbase & text_editor::textbase() const { - return textbase_; + return impl_->textbase; } bool text_editor::getline(std::size_t pos, std::wstring& text) const { - if (textbase_.lines() <= pos) + if (impl_->textbase.lines() <= pos) return false; - text = textbase_.getline(pos); + text = impl_->textbase.getline(pos); return true; } void text_editor::text(std::wstring str, bool end_caret) { - undo_.clear(); + impl_->undo.clear(); - textbase_.erase_all(); + impl_->textbase.erase_all(); _m_reset(); - behavior_->pre_calc_lines(width_pixels()); + impl_->capacities.behavior->pre_calc_lines(width_pixels()); if (!end_caret) { auto undo_ptr = std::unique_ptr{ new undo_input_text(*this, str) }; @@ -1806,11 +1950,11 @@ namespace nana{ namespace widgets _m_put(std::move(str)); - undo_.push(std::move(undo_ptr)); + impl_->undo.push(std::move(undo_ptr)); if (graph_) { - behavior_->adjust_caret_into_screen(); + impl_->capacities.behavior->adjust_caret_into_screen(); reset_caret(); render(API::is_focus_ready(window_)); _m_scrollbar(); @@ -1825,14 +1969,14 @@ namespace nana{ namespace widgets std::wstring text_editor::text() const { std::wstring str; - std::size_t lines = textbase_.lines(); + std::size_t lines = impl_->textbase.lines(); if(lines > 0) { - str = textbase_.getline(0); + str = impl_->textbase.getline(0); for(std::size_t i = 1; i < lines; ++i) { str += L"\n\r"; - str += textbase_.getline(i); + str += impl_->textbase.getline(i); } } return str; @@ -1846,37 +1990,41 @@ namespace nana{ namespace widgets return; const unsigned line_pixels = line_height(); - auto pos = this->behavior_->caret_to_screen(crtpos); + auto pos = impl_->capacities.behavior->caret_to_screen(crtpos); const int line_bottom = pos.y + static_cast(line_pixels); + auto caret = API::open_caret(window_, true); + + auto text_area = _m_text_area(); + bool visible = false; - if (hit_text_area(pos) && (line_bottom > text_area_.area.y)) + if (text_area.is_hit(pos) && (line_bottom > text_area.y)) { visible = true; - if (line_bottom > _m_end_pos(false)) - caret_->dimension(nana::size(1, line_pixels - (line_bottom - _m_end_pos(false)))); - else if (caret_->dimension().height != line_pixels) + if (line_bottom > text_area.bottom()) + caret->dimension(nana::size(1, line_pixels - (line_bottom - text_area.bottom()))); + else if (caret->dimension().height != line_pixels) reset_caret_pixels(); } if(!attributes_.editable) visible = false; - caret_->visible(visible); + caret->visible(visible); if(visible) - caret_->position(pos); + caret->position(pos); } void text_editor::move_caret_end() { - points_.caret.y = static_cast(textbase_.lines()); + points_.caret.y = static_cast(impl_->textbase.lines()); if(points_.caret.y) --points_.caret.y; - points_.caret.x = static_cast(textbase_.getline(points_.caret.y).size()); + points_.caret.x = static_cast(impl_->textbase.getline(points_.caret.y).size()); } void text_editor::reset_caret_pixels() const { - caret_->dimension({ 1, line_height() }); + API::open_caret(window_, true)->dimension({ 1, line_height() }); } void text_editor::reset_caret() @@ -1887,7 +2035,7 @@ namespace nana{ namespace widgets void text_editor::show_caret(bool isshow) { if(isshow == false || API::is_focus_ready(window_)) - caret_->visible(isshow); + API::open_caret(window_, true)->visible(isshow); } bool text_editor::selected() const @@ -1901,7 +2049,7 @@ namespace nana{ namespace widgets select_.b = points_.caret; points_.xpos = points_.caret.x; - if (new_sel_end || behavior_->adjust_caret_into_screen()) + if (new_sel_end || impl_->capacities.behavior->adjust_caret_into_screen()) render(true); } @@ -1910,9 +2058,9 @@ namespace nana{ namespace widgets if(yes) { select_.a.x = select_.a.y = 0; - select_.b.y = static_cast(textbase_.lines()); + select_.b.y = static_cast(impl_->textbase.lines()); if(select_.b.y) --select_.b.y; - select_.b.x = static_cast(textbase_.getline(select_.b.y).size()); + select_.b.x = static_cast(impl_->textbase.getline(select_.b.y).size()); select_.mode_selection = selection::mode::method_selected; render(true); return true; @@ -1929,7 +2077,7 @@ namespace nana{ namespace widgets bool text_editor::hit_text_area(const point& pos) const { - return ((text_area_.area.x <= pos.x && pos.x < _m_end_pos(true)) && (text_area_.area.y <= pos.y && pos.y < _m_end_pos(false))); + return _m_text_area().is_hit(pos); } bool text_editor::hit_select_area(nana::upoint pos, bool ignore_when_select_all) const @@ -1939,10 +2087,10 @@ namespace nana{ namespace widgets { if (ignore_when_select_all) { - if (a.x == 0 && a.y == 0 && (b.y + 1) == static_cast(textbase_.lines())) + if (a.x == 0 && a.y == 0 && (b.y + 1) == static_cast(textbase().lines())) { //is select all - if (b.x == static_cast(textbase_.getline(b.y).size())) + if (b.x == static_cast(textbase().getline(b.y).size())) return false; } } @@ -1962,7 +2110,7 @@ namespace nana{ namespace widgets { points_.caret = select_.b; - if (behavior_->adjust_caret_into_screen()) + if (impl_->capacities.behavior->adjust_caret_into_screen()) render(true); reset_caret(); @@ -1971,7 +2119,7 @@ namespace nana{ namespace widgets if (_m_move_select(true)) { - behavior_->adjust_caret_into_screen(); + impl_->capacities.behavior->adjust_caret_into_screen(); render(true); return true; } @@ -1993,7 +2141,7 @@ namespace nana{ namespace widgets if (attributes_.line_wrapped) exclude_px = text_area_.vscroll; else - exclude_px = caret_->dimension().width; + exclude_px = API::open_caret(window_, true)->dimension().width; return (text_area_.area.width > exclude_px ? text_area_.area.width - exclude_px : 0); } @@ -2005,7 +2153,7 @@ namespace nana{ namespace widgets const std::vector& text_editor::text_position() const { - return text_position_; + return impl_->text_position; } void text_editor::focus_behavior(text_focus_behavior behavior) @@ -2042,37 +2190,37 @@ namespace nana{ namespace widgets if(attributes_.enable_background) graph_.rectangle(text_area_.area, true, bgcolor); - if(ext_renderer_.background) - ext_renderer_.background(graph_, text_area_.area, bgcolor); + if (impl_->customized_renderers.background) + impl_->customized_renderers.background(graph_, text_area_.area, bgcolor); - if(attributes_.counterpart && !text_area_.area.empty()) - attributes_.counterpart.bitblt(rectangle{ text_area_.area.dimension() }, graph_, text_area_.area.position()); + if(impl_->counterpart.buffer && !text_area_.area.empty()) + impl_->counterpart.buffer.bitblt(rectangle{ text_area_.area.dimension() }, graph_, text_area_.area.position()); //Render the content when the text isn't empty or the window has got focus, //otherwise draw the tip string. - if ((false == textbase_.empty()) || has_focus) + if ((false == textbase().empty()) || has_focus) { - auto text_pos = behavior_->render(fgcolor); + auto text_pos = impl_->capacities.behavior->render(fgcolor); if (text_pos.empty()) - text_pos.push_back(upoint{}); + text_pos.emplace_back(upoint{}); - if (text_pos != text_position_) + if (text_pos != impl_->text_position) { - text_position_.swap(text_pos); + impl_->text_position.swap(text_pos); if (event_handler_) - event_handler_->text_exposed(text_position_); + event_handler_->text_exposed(impl_->text_position); } } else //Draw tip string graph_.string({ text_area_.area.x - points_.offset.x, text_area_.area.y }, attributes_.tip_string, static_cast(0x787878)); - if (text_position_.empty()) - text_position_.push_back(upoint{}); + if (impl_->text_position.empty()) + impl_->text_position.emplace_back(upoint{}); draw_corner(); - text_area_.border_renderer(graph_, bgcolor); + _m_draw_border(); } //public: void text_editor::put(std::wstring text) @@ -2091,11 +2239,11 @@ namespace nana{ namespace widgets undo_ptr->set_caret_pos(); points_.caret = _m_put(std::move(text)); - undo_.push(std::move(undo_ptr)); + impl_->undo.push(std::move(undo_ptr)); if(graph_) { - behavior_->adjust_caret_into_screen(); + impl_->capacities.behavior->adjust_caret_into_screen(); reset_caret(); render(API::is_focus_ready(window_)); _m_scrollbar(); @@ -2108,7 +2256,7 @@ namespace nana{ namespace widgets { std::wstring ch_str(1, ch); - auto undo_ptr = std::unique_ptr < undo_input_text > {new undo_input_text(*this, ch_str)}; + auto undo_ptr = std::unique_ptr{new undo_input_text(*this, ch_str)}; bool refresh = (select_.a != select_.b); undo_ptr->set_selected_text(); @@ -2116,10 +2264,11 @@ namespace nana{ namespace widgets points_.caret = _m_erase_select(); undo_ptr->set_caret_pos(); - undo_.push(std::move(undo_ptr)); - auto secondary_before = behavior_->take_lines(points_.caret.y); - textbase_.insert(points_.caret, std::move(ch_str)); + impl_->undo.push(std::move(undo_ptr)); + + auto secondary_before = impl_->capacities.behavior->take_lines(points_.caret.y); + textbase().insert(points_.caret, std::move(ch_str)); _m_pre_calc_lines(points_.caret.y, 1); points_.caret.x ++; @@ -2153,7 +2302,7 @@ namespace nana{ namespace widgets nana::system::dataexch().get(text); //If it is required check the acceptable - if (accepts::no_restrict != attributes_.acceptive) + if (accepts::no_restrict != impl_->capacities.acceptive) { for (auto i = text.begin(); i != text.end(); ++i) { @@ -2182,46 +2331,49 @@ namespace nana{ namespace widgets points_.caret = _m_erase_select(); undo_ptr->set_caret_pos(); - const string_type& lnstr = textbase_.getline(points_.caret.y); + + auto & textbase = this->textbase(); + + const string_type& lnstr = textbase.getline(points_.caret.y); ++points_.caret.y; if(lnstr.size() > points_.caret.x) { //Breaks the line and moves the rest part to a new line auto rest_part_len = lnstr.size() - points_.caret.x; //Firstly get the length of rest part, because lnstr may be invalid after insertln - textbase_.insertln(points_.caret.y, lnstr.substr(points_.caret.x)); - textbase_.erase(points_.caret.y - 1, points_.caret.x, rest_part_len); + textbase.insertln(points_.caret.y, lnstr.substr(points_.caret.x)); + textbase.erase(points_.caret.y - 1, points_.caret.x, rest_part_len); } else { - if (textbase_.lines() == 0) - textbase_.insertln(0, std::wstring{}); - textbase_.insertln(points_.caret.y, std::wstring{}); + if (textbase.lines() == 0) + textbase.insertln(0, std::wstring{}); + textbase.insertln(points_.caret.y, std::wstring{}); } if (record_undo) - undo_.push(std::move(undo_ptr)); + impl_->undo.push(std::move(undo_ptr)); - behavior_->add_lines(points_.caret.y - 1, 1); + impl_->capacities.behavior->add_lines(points_.caret.y - 1, 1); _m_pre_calc_lines(points_.caret.y - 1, 2); points_.caret.x = 0; - if(points_.offset.x || (points_.caret.y < textbase_.lines()) || textbase_.getline(points_.caret.y).size()) + if(points_.offset.x || (points_.caret.y < textbase.lines()) || textbase.getline(points_.caret.y).size()) { points_.offset.x = 0; need_refresh = true; } - if (indent_.enabled) + if (impl_->indent.enabled) { - if (indent_.generator) + if (impl_->indent.generator) { - put(to_wstring(indent_.generator())); + put(to_wstring(impl_->indent.generator())); } else { - auto & text = textbase_.getline(points_.caret.y - 1); + auto & text = textbase.getline(points_.caret.y - 1); auto indent_pos = text.find_first_not_of(L"\t "); if (indent_pos != std::wstring::npos) put(text.substr(0, indent_pos)); @@ -2230,7 +2382,7 @@ namespace nana{ namespace widgets } } - if (behavior_->adjust_caret_into_screen() || need_refresh) + if (impl_->capacities.behavior->adjust_caret_into_screen() || need_refresh) render(true); _m_scrollbar(); @@ -2242,11 +2394,11 @@ namespace nana{ namespace widgets if(select_.a == select_.b) { - if(textbase_.getline(points_.caret.y).size() > points_.caret.x) + if(textbase().getline(points_.caret.y).size() > points_.caret.x) { ++points_.caret.x; } - else if(points_.caret.y + 1 < textbase_.lines()) + else if(points_.caret.y + 1 < textbase().lines()) { //Move to next line points_.caret.x = 0; ++ points_.caret.y; @@ -2267,31 +2419,32 @@ namespace nana{ namespace widgets bool has_to_redraw = true; if(select_.a == select_.b) { + auto & textbase = this->textbase(); if(points_.caret.x) { unsigned erase_number = 1; --points_.caret.x; - auto& lnstr = textbase_.getline(points_.caret.y); + auto& lnstr = textbase.getline(points_.caret.y); undo_ptr->set_caret_pos(); undo_ptr->set_removed(lnstr.substr(points_.caret.x, erase_number)); - auto secondary = behavior_->take_lines(points_.caret.y); - textbase_.erase(points_.caret.y, points_.caret.x, erase_number); + auto secondary = impl_->capacities.behavior->take_lines(points_.caret.y); + textbase.erase(points_.caret.y, points_.caret.x, erase_number); _m_pre_calc_lines(points_.caret.y, 1); if(_m_move_offset_x_while_over_border(-2) == false) { - behavior_->update_line(points_.caret.y, secondary); + impl_->capacities.behavior->update_line(points_.caret.y, secondary); draw_corner(); has_to_redraw = false; } } else if (points_.caret.y) { - points_.caret.x = static_cast(textbase_.getline(--points_.caret.y).size()); - textbase_.merge(points_.caret.y); - behavior_->merge_lines(points_.caret.y, points_.caret.y + 1); + points_.caret.x = static_cast(textbase.getline(--points_.caret.y).size()); + textbase.merge(points_.caret.y); + impl_->capacities.behavior->merge_lines(points_.caret.y, points_.caret.y + 1); undo_ptr->set_caret_pos(); undo_ptr->set_removed(std::wstring(1, '\n')); } @@ -2306,12 +2459,12 @@ namespace nana{ namespace widgets } if (record_undo) - undo_.push(std::move(undo_ptr)); + impl_->undo.push(std::move(undo_ptr)); if(has_to_redraw) { - behavior_->pre_calc_lines(width_pixels()); - behavior_->adjust_caret_into_screen(); + impl_->capacities.behavior->pre_calc_lines(width_pixels()); + impl_->capacities.behavior->adjust_caret_into_screen(); render(true); } _m_scrollbar(); @@ -2320,12 +2473,12 @@ namespace nana{ namespace widgets void text_editor::undo(bool reverse) { if (reverse) - undo_.redo(); + impl_->undo.redo(); else - undo_.undo(); + impl_->undo.undo(); - behavior_->pre_calc_lines(width_pixels()); - behavior_->adjust_caret_into_screen(); + impl_->capacities.behavior->pre_calc_lines(width_pixels()); + impl_->capacities.behavior->adjust_caret_into_screen(); render(true); _m_scrollbar(); } @@ -2333,7 +2486,7 @@ namespace nana{ namespace widgets void text_editor::move_ns(bool to_north) { const bool redraw_required = _m_cancel_select(0); - if (behavior_->move_caret_ns(to_north) || redraw_required) + if (impl_->capacities.behavior->move_caret_ns(to_north) || redraw_required) render(true); _m_scrollbar(); } @@ -2348,17 +2501,17 @@ namespace nana{ namespace widgets --points_.caret.x; pending = false; - bool adjust_y = (attributes_.line_wrapped && behavior_->adjust_caret_into_screen()); + bool adjust_y = (attributes_.line_wrapped && impl_->capacities.behavior->adjust_caret_into_screen()); if (_m_move_offset_x_while_over_border(-2) || adjust_y) render(true); } else if (points_.caret.y) //Move to previous line - points_.caret.x = static_cast(textbase_.getline(--points_.caret.y).size()); + points_.caret.x = static_cast(textbase().getline(--points_.caret.y).size()); else pending = false; } - if (pending && behavior_->adjust_caret_into_screen()) + if (pending && impl_->capacities.behavior->adjust_caret_into_screen()) render(true); _m_scrollbar(); @@ -2370,23 +2523,23 @@ namespace nana{ namespace widgets bool do_render = false; if(_m_cancel_select(2) == false) { - auto lnstr = textbase_.getline(points_.caret.y); + auto lnstr = textbase().getline(points_.caret.y); if(lnstr.size() > points_.caret.x) { ++points_.caret.x; - bool adjust_y = (attributes_.line_wrapped && behavior_->adjust_caret_into_screen()); + bool adjust_y = (attributes_.line_wrapped && impl_->capacities.behavior->adjust_caret_into_screen()); do_render = (_m_move_offset_x_while_over_border(2) || adjust_y); } - else if(textbase_.lines() && (points_.caret.y < textbase_.lines() - 1)) + else if(points_.caret.y + 1 < textbase().lines()) { //Move to next line points_.caret.x = 0; ++ points_.caret.y; - do_render = behavior_->adjust_caret_into_screen(); + do_render = impl_->capacities.behavior->adjust_caret_into_screen(); } } else - do_render = behavior_->adjust_caret_into_screen(); + do_render = impl_->capacities.behavior->adjust_caret_into_screen(); if (do_render) render(true); @@ -2395,7 +2548,7 @@ namespace nana{ namespace widgets points_.xpos = points_.caret.x; } - void text_editor::_handle_move_key(const arg_keyboard& arg) + void text_editor::_m_handle_move_key(const arg_keyboard& arg) { if (arg.shift && (select_.a == select_.b)) select_.a = select_.b = points_.caret; @@ -2403,7 +2556,7 @@ namespace nana{ namespace widgets bool changed = false; nana::upoint caret = points_.caret; wchar_t key = arg.key; - size_t nlines = textbase_.lines(); + size_t nlines = textbase().lines(); if (arg.ctrl) { switch (key) { case keyboard::os_arrow_left: @@ -2425,7 +2578,7 @@ namespace nana{ namespace widgets break; } } - size_t lnsz = textbase_.getline(caret.y).size(); + size_t lnsz = textbase().getline(caret.y).size(); switch (key) { case keyboard::os_arrow_left: if (select_.move_to_end && (select_.a != select_.b) && (!arg.shift)) @@ -2442,7 +2595,7 @@ namespace nana{ namespace widgets else { if (caret.y != 0) { --caret.y; - caret.x = static_cast(textbase_.getline(caret.y).size()); + caret.x = static_cast(textbase().getline(caret.y).size()); changed = true; } } @@ -2472,13 +2625,13 @@ namespace nana{ namespace widgets case keyboard::os_arrow_up: case keyboard::os_arrow_down: { - auto screen_pt = behavior_->caret_to_screen(caret); + auto screen_pt = impl_->capacities.behavior->caret_to_screen(caret); int offset = line_height(); if (key == keyboard::os_arrow_up) { offset = -offset; } screen_pt.y += offset; - auto new_caret = behavior_->screen_to_caret(screen_pt); + auto new_caret = impl_->capacities.behavior->screen_to_caret(screen_pt); if (new_caret != caret) { caret = new_caret; if (screen_pt.y < 0) { @@ -2508,7 +2661,7 @@ namespace nana{ namespace widgets } break; case keyboard::os_pagedown: - if (caret.y + screen_lines() <= behavior_->take_lines()) { + if (caret.y + screen_lines() <= impl_->capacities.behavior->take_lines()) { points_.offset.y += screen_lines(); caret.y += screen_lines(); changed = true; @@ -2540,18 +2693,34 @@ namespace nana{ namespace widgets select_.a = caret; } points_.caret = caret; - behavior_->adjust_caret_into_screen(); + impl_->capacities.behavior->adjust_caret_into_screen(); render(true); _m_scrollbar(); points_.xpos = points_.caret.x; } } + void text_editor::_m_draw_border() + { + if (!API::widget_borderless(this->window_)) + { + if (impl_->customized_renderers.border) + { + impl_->customized_renderers.border(graph_, _m_bgcolor()); + } + else + { + ::nana::facade facade; + facade.draw(graph_, _m_bgcolor(), API::fgcolor(this->window_), ::nana::rectangle{ API::window_size(this->window_) }, API::element_state(this->window_)); + } + } + } + const upoint& text_editor::mouse_caret(const point& scrpos) //From screen position { - points_.caret = behavior_->screen_to_caret(scrpos); + points_.caret = impl_->capacities.behavior->screen_to_caret(scrpos); - if (behavior_->adjust_caret_into_screen()) + if (impl_->capacities.behavior->adjust_caret_into_screen()) render(true); move_caret(points_.caret); @@ -2565,14 +2734,14 @@ namespace nana{ namespace widgets point text_editor::caret_screen_pos() const { - return behavior_->caret_to_screen(points_.caret); + return impl_->capacities.behavior->caret_to_screen(points_.caret); } bool text_editor::scroll(bool upwards, bool vert) { - if(vert && attributes_.vscroll) + if(vert && impl_->widgets.vscroll) { - attributes_.vscroll->make_step(!upwards, this->scheme_->mouse_wheel.lines); + impl_->widgets.vscroll->make_step(!upwards, this->scheme_->mouse_wheel.lines); if(_m_scroll_text(true)) { render(true); @@ -2586,12 +2755,13 @@ namespace nana{ namespace widgets { unsigned width_px = width_pixels(); for (auto pos = line_off, end = line_off + lines; pos != end; ++pos) - this->behavior_->pre_calc_line(pos, width_px); + this->impl_->capacities.behavior->pre_calc_line(pos, width_px); } + bool text_editor::_m_accepts(char_type ch) const { - if (accepts::no_restrict == attributes_.acceptive) + if(accepts::no_restrict == impl_->capacities.acceptive) return true; //Checks the input whether it meets the requirement for a numeric. @@ -2600,12 +2770,13 @@ namespace nana{ namespace widgets if ('+' == ch || '-' == ch) return str.empty(); - if ((accepts::real == attributes_.acceptive) && ('.' == ch)) + if((accepts::real == impl_->capacities.acceptive) && ('.' == ch)) return (str.find(L'.') == str.npos); return ('0' <= ch && ch <= '9'); } + ::nana::color text_editor::_m_bgcolor() const { return (!API::window_enabled(window_) ? static_cast(0xE0E0E0) : API::bgcolor(window_)); @@ -2615,9 +2786,9 @@ namespace nana{ namespace widgets { if (vert) { - if (attributes_.vscroll) + if (impl_->widgets.vscroll) { - auto sv = static_cast(attributes_.vscroll->value()); + auto sv = static_cast(impl_->widgets.vscroll->value()); if (sv != points_.offset.y) { _m_offset_y(sv); @@ -2625,9 +2796,9 @@ namespace nana{ namespace widgets } } } - else if(attributes_.hscroll) + else if(impl_->widgets.hscroll) { - auto sv = static_cast(attributes_.hscroll->value()); + auto sv = static_cast(impl_->widgets.hscroll->value()); if(sv != points_.offset.x) { points_.offset.x = sv; @@ -2640,14 +2811,14 @@ namespace nana{ namespace widgets void text_editor::_m_scrollbar() { _m_get_scrollbar_size(); - nana::size tx_area = _m_text_area(); + auto tx_area = _m_text_area(); auto scroll_fn = [this](const arg_mouse& arg) { if ((arg.evt_code == event_code::mouse_move) && (arg.left_button == false)) return; - bool vert = (attributes_.vscroll && (attributes_.vscroll->handle() == arg.window_handle)); + bool vert = (impl_->widgets.vscroll && (impl_->widgets.vscroll->handle() == arg.window_handle)); if (_m_scroll_text(vert)) { render(true); @@ -2659,11 +2830,11 @@ namespace nana{ namespace widgets if (text_area_.vscroll) { const int x = text_area_.area.x + static_cast(tx_area.width); - auto wdptr = attributes_.vscroll.get(); + auto wdptr = impl_->widgets.vscroll.get(); if (!wdptr) { - attributes_.vscroll.reset(new nana::scroll); - wdptr = attributes_.vscroll.get(); + impl_->widgets.vscroll.reset(new nana::scroll); + wdptr = impl_->widgets.vscroll.get(); wdptr->create(window_, nana::rectangle(x, text_area_.area.y, text_area_.vscroll, tx_area.height)); auto & evts = wdptr->events(); @@ -2674,8 +2845,8 @@ namespace nana{ namespace widgets API::take_active(wdptr->handle(), false, window_); } - if (behavior_->take_lines() != wdptr->amount()) - wdptr->amount(static_cast(behavior_->take_lines())); + if (impl_->capacities.behavior->take_lines() != wdptr->amount()) + wdptr->amount(static_cast(impl_->capacities.behavior->take_lines())); if (screen_lines() != wdptr->range()) wdptr->range(screen_lines()); @@ -2686,17 +2857,17 @@ namespace nana{ namespace widgets wdptr->move(rectangle{ x, text_area_.area.y, text_area_.vscroll, tx_area.height }); } else - attributes_.vscroll.reset(); + impl_->widgets.vscroll.reset(); //HScroll if(text_area_.hscroll) { - auto wdptr = attributes_.hscroll.get(); + auto wdptr = impl_->widgets.hscroll.get(); int y = text_area_.area.y + static_cast(tx_area.height); if(nullptr == wdptr) { - attributes_.hscroll.reset(new nana::scroll); - wdptr = attributes_.hscroll.get(); + impl_->widgets.hscroll.reset(new nana::scroll); + wdptr = impl_->widgets.hscroll.get(); wdptr->create(window_, nana::rectangle(text_area_.area.x, y, tx_area.width, text_area_.hscroll)); auto & evts = wdptr->events(); @@ -2707,8 +2878,8 @@ namespace nana{ namespace widgets wdptr->step(20); API::take_active(wdptr->handle(), false, window_); } - auto maxline = textbase_.max_line(); - nana::size text_size = _m_text_extent_size(textbase_.getline(maxline.first).c_str(), maxline.second); + auto maxline = textbase().max_line(); + nana::size text_size = _m_text_extent_size(textbase().getline(maxline.first).c_str(), maxline.second); text_size.width += 1; if(text_size.width > wdptr->amount()) @@ -2721,13 +2892,23 @@ namespace nana{ namespace widgets wdptr->move(rectangle{ text_area_.area.x, y, tx_area.width, text_area_.hscroll }); } else - attributes_.hscroll.reset(); + impl_->widgets.hscroll.reset(); } - nana::size text_editor::_m_text_area() const + rectangle text_editor::_m_text_area() const { - return nana::size((text_area_.area.width > text_area_.vscroll ? text_area_.area.width - text_area_.vscroll : 0), - (text_area_.area.height > text_area_.hscroll ? text_area_.area.height - text_area_.hscroll : 0)); + auto area = text_area_.area; + if (area.width > text_area_.vscroll) + area.width -= text_area_.vscroll; + else + area.width = 0; + + if (area.height > text_area_.hscroll) + area.height -= text_area_.hscroll; + else + area.height = 0; + + return area; } void text_editor::_m_get_scrollbar_size() @@ -2747,15 +2928,17 @@ namespace nana{ namespace widgets return; } - text_area_.vscroll = (textbase_.lines() > screen_lines() ? text_area_.scroll_pixels : 0); + const bool text_overflow = (textbase().lines() > screen_lines()); - auto max_line = textbase_.max_line(); + text_area_.vscroll = (text_overflow ? text_area_.scroll_pixels : 0); + + auto max_line = textbase().max_line(); if(max_line.second) { - if(points_.offset.x || _m_text_extent_size(textbase_.getline(max_line.first).c_str(), max_line.second).width > _m_text_area().width) + if(points_.offset.x || _m_text_extent_size(textbase().getline(max_line.first).c_str(), max_line.second).width > _m_text_area().width) { text_area_.hscroll = text_area_.scroll_pixels; - if((text_area_.vscroll == 0) && (textbase_.lines() > screen_lines())) + if((text_area_.vscroll == 0) && text_overflow) text_area_.vscroll = text_area_.scroll_pixels; } } @@ -2771,32 +2954,33 @@ namespace nana{ namespace widgets nana::upoint text_editor::_m_put(std::wstring text) { + auto & textbase = this->textbase(); auto crtpos = points_.caret; std::vector> lines; if (_m_resolve_text(text, lines) && attributes_.multi_lines) { - auto str_orig = textbase_.getline(crtpos.y); + auto str_orig = textbase.getline(crtpos.y); auto x_orig = crtpos.x; auto subpos = lines.front(); auto substr = text.substr(subpos.first, subpos.second - subpos.first); if (str_orig.size() == x_orig) - textbase_.insert(crtpos, std::move(substr)); + textbase.insert(crtpos, std::move(substr)); else - textbase_.replace(crtpos.y, str_orig.substr(0, x_orig) + substr); + textbase.replace(crtpos.y, str_orig.substr(0, x_orig) + substr); //There are at least 2 elements in lines for (auto i = lines.begin() + 1, end = lines.end() - 1; i != end; ++i) { - textbase_.insertln(++crtpos.y, text.substr(i->first, i->second - i->first)); + textbase.insertln(++crtpos.y, text.substr(i->first, i->second - i->first)); } auto backpos = lines.back(); - textbase_.insertln(++crtpos.y, text.substr(backpos.first, backpos.second - backpos.first) + str_orig.substr(x_orig)); + textbase.insertln(++crtpos.y, text.substr(backpos.first, backpos.second - backpos.first) + str_orig.substr(x_orig)); crtpos.x = static_cast(backpos.second - backpos.first); - behavior_->add_lines(points_.caret.y, lines.size() - 1); + impl_->capacities.behavior->add_lines(points_.caret.y, lines.size() - 1); _m_pre_calc_lines(points_.caret.y, lines.size()); } else @@ -2806,7 +2990,7 @@ namespace nana{ namespace widgets text = text.substr(lines.front().first, lines.front().second - lines.front().first); auto length = text.size(); - textbase_.insert(crtpos, std::move(text)); + textbase.insert(crtpos, std::move(text)); crtpos.x += static_cast(length); _m_pre_calc_lines(crtpos.y, 1); @@ -2819,19 +3003,20 @@ namespace nana{ namespace widgets nana::upoint a, b; if (_m_get_sort_select_points(a, b)) { + auto & textbase = this->textbase(); if(a.y != b.y) { - textbase_.erase(a.y, a.x, std::wstring::npos); - textbase_.erase(a.y + 1, b.y - a.y - 1); + textbase.erase(a.y, a.x, std::wstring::npos); + textbase.erase(a.y + 1, b.y - a.y - 1); - textbase_.erase(a.y + 1, 0, b.x); - textbase_.merge(a.y); + textbase.erase(a.y + 1, 0, b.x); + textbase.merge(a.y); - behavior_->merge_lines(a.y, b.y); + impl_->capacities.behavior->merge_lines(a.y, b.y); } else { - textbase_.erase(a.y, a.x, b.x - a.x); + textbase.erase(a.y, a.x, b.x - a.x); _m_pre_calc_lines(a.y, 1); } @@ -2849,19 +3034,20 @@ namespace nana{ namespace widgets nana::upoint a, b; if (_m_get_sort_select_points(a, b)) { + auto & textbase = this->textbase(); if (a.y != b.y) { - text = textbase_.getline(a.y).substr(a.x); + text = textbase.getline(a.y).substr(a.x); text += L"\r\n"; for (unsigned i = a.y + 1; i < b.y; ++i) { - text += textbase_.getline(i); + text += textbase.getline(i); text += L"\r\n"; } - text += textbase_.getline(b.y).substr(0, b.x); + text += textbase.getline(b.y).substr(0, b.x); } else - text = textbase_.getline(a.y).substr(a.x, b.x - a.x); + text = textbase.getline(a.y).substr(a.x, b.x - a.x); } return text; @@ -2985,7 +3171,7 @@ namespace nana{ namespace widgets if (attributes_.line_wrapped || (0 == many)) return false; - const string_type& lnstr = textbase_.getline(points_.caret.y); + const string_type& lnstr = textbase().getline(points_.caret.y); unsigned width = _m_text_extent_size(lnstr.c_str(), points_.caret.x).width; const auto count = static_cast(std::abs(many)); @@ -3002,10 +3188,12 @@ namespace nana{ namespace widgets } else { + const int right_pos = _m_text_area().right(); + width += text_area_.area.x; - if(static_cast(width) - points_.offset.x >= _m_end_pos(true)) + if(static_cast(width) - points_.offset.x >= right_pos) { //Out of screen text area - points_.offset.x = static_cast(width) -_m_end_pos(false) + 1; + points_.offset.x = static_cast(width) - right_pos + 1; auto rest_size = lnstr.size() - points_.caret.x; points_.offset.x += static_cast(_m_text_extent_size(lnstr.c_str() + points_.caret.x, (rest_size >= static_cast(many) ? static_cast(many) : rest_size)).width); return true; @@ -3058,7 +3246,7 @@ namespace nana{ namespace widgets if (record_undo) { undo_ptr->set_destination(select_.a, select_.b); - undo_.push(std::move(undo_ptr)); + impl_->undo.push(std::move(undo_ptr)); } points_.caret = select_.b; @@ -3079,14 +3267,6 @@ namespace nana{ namespace widgets return text_area_.area.y; } - int text_editor::_m_end_pos(bool right) const - { - if(right) - return static_cast(text_area_.area.x + text_area_.area.width - text_area_.vscroll); - - return static_cast(text_area_.area.y + text_area_.area.height - text_area_.hscroll); - } - void text_editor::_m_draw_parse_string(const keyword_parser& parser, bool rtl, ::nana::point pos, const ::nana::color& fgcolor, const wchar_t* str, std::size_t len) const { graph_.palette(true, fgcolor); @@ -3216,7 +3396,7 @@ namespace nana{ namespace widgets //Parse highlight keywords keyword_parser parser; - parser.parse(*text_ptr, keywords_.get()); + parser.parse(*text_ptr, impl_->keywords); const auto line_h_pixels = line_height(); @@ -3377,11 +3557,11 @@ namespace nana{ namespace widgets bool text_editor::_m_update_caret_line(std::size_t secondary_before) { - if (false == behavior_->adjust_caret_into_screen()) + if (false == impl_->capacities.behavior->adjust_caret_into_screen()) { - if (behavior_->caret_to_screen(points_.caret).x < _m_end_pos(true)) + if (impl_->capacities.behavior->caret_to_screen(points_.caret).x < _m_text_area().right()) { - behavior_->update_line(points_.caret.y, secondary_before); + impl_->capacities.behavior->update_line(points_.caret.y, secondary_before); return false; } } diff --git a/source/gui/widgets/slider.cpp b/source/gui/widgets/slider.cpp index e89e210f..b66b141c 100644 --- a/source/gui/widgets/slider.cpp +++ b/source/gui/widgets/slider.cpp @@ -1,5 +1,6 @@ #include +#include #include //memcpy namespace nana @@ -645,7 +646,6 @@ namespace nana { adorn.bound.x = static_cast(attr_.adorn_pos + attr_.slider.border_weight + bar.area.y); adorn.bound.y = static_cast(graph.height()) - static_cast(attr_.slider.border_weight + bar.area.y); - //adorn.bound.x = } else { diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 12f42872..8c33f6e2 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -65,7 +65,6 @@ namespace drawerbase { { auto wd = wdg.handle(); widget_ = &wdg; - evt_agent_.reset(new event_agent(static_cast<::nana::textbox&>(wdg), editor_->text_position())); auto scheme = API::dev::get_scheme(wdg); @@ -73,6 +72,8 @@ namespace drawerbase { editor_->textbase().set_event_agent(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()); API::tabstop(wd); diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index b0895943..c75aea52 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace nana { diff --git a/source/internationalization.cpp b/source/internationalization.cpp index 02f6c72f..345ae62c 100644 --- a/source/internationalization.cpp +++ b/source/internationalization.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include @@ -486,32 +486,22 @@ namespace nana 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) { - 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) { - args_.emplace_back(new arg_string(nana::charset(std::move(str)))); - } - - void i18n_eval::_m_add_args(std::wstring& str) - { - args_.emplace_back(new arg_string(nana::charset(str))); + args_.emplace_back(new arg_string(std::move(str))); } void i18n_eval::_m_add_args(const std::wstring& str) { - args_.emplace_back(new arg_string(nana::charset(str))); - } - - void i18n_eval::_m_add_args(std::wstring&& str) - { - args_.emplace_back(new arg_string(nana::charset(std::move(str)))); + args_.emplace_back(new arg_string(to_utf8(str))); } //end class i18n_eval } diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 15a29c52..4eea00c7 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -194,76 +194,106 @@ namespace paint //end class font //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() - :handle_(nullptr), changed_(false) + : impl_(new implementation) {} graphics::graphics(const nana::size& sz) - :handle_(nullptr), changed_(true) + : impl_(new implementation) { make(sz); } 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) { if(this != &rhs) { - size_ = rhs.size_; - dwptr_ = rhs.dwptr_; - handle_ = rhs.handle_; - if(changed_ == false) changed_ = true; + *impl_ = *rhs.impl_; + impl_->changed = true; } 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 { - return handle_; + return impl_->handle; } drawable_type graphics::handle() const { - return handle_; + return impl_->handle; } const void* graphics::pixmap() const { //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. - return (handle_? reinterpret_cast(handle_->pixmap) : nullptr); + return (impl_->handle ? reinterpret_cast(impl_->handle->pixmap) : nullptr); } const void* graphics::context() const { - return (handle_? handle_->context : nullptr); + return (impl_->handle ? impl_->handle->context : nullptr); } 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. drawable_type dw = new nana::detail::drawable_impl_type; //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->string.tab_length = reuse->string.tab_length; } else - dw->font = font_shadow_.impl_->font_ptr; + dw->font = impl_->font_shadow.impl_->font_ptr; #if defined(NANA_WINDOWS) HDC hdc = ::GetDC(0); @@ -319,21 +349,22 @@ namespace paint #else dw->update_text_color(); #endif - dwptr_.reset(dw, detail::drawable_deleter{}); - handle_ = dw; - size_ = sz; + impl_->platform_drawable.reset(dw, detail::drawable_deleter{}); + impl_->handle = dw; + impl_->size = sz; - handle_->string.tab_pixels = detail::raw_text_extent_size(handle_, L"\t", 1).width; - handle_->string.whitespace_pixels = detail::raw_text_extent_size(handle_, L" ", 1).width; + impl_->handle->string.tab_pixels = detail::raw_text_extent_size(impl_->handle, L"\t", 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) { - graphics duplicate(*this); + graphics duplicate(std::move(*this)); make(sz); 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 //of a widget is zero. - font_shadow_ = f; - if(handle_ && (false == f.empty())) + impl_->font_shadow = f; + if(impl_->handle && (false == f.empty())) { - handle_->font = f.impl_->font_ptr; + impl_->handle->font = f.impl_->font_ptr; #if defined(NANA_WINDOWS) - ::SelectObject(handle_->context, reinterpret_cast(f.impl_->font_ptr->handle)); + ::SelectObject(impl_->handle->context, reinterpret_cast(f.impl_->font_ptr->handle)); #endif - handle_->string.tab_pixels = detail::raw_text_extent_size(handle_, L"\t", 1).width; - handle_->string.whitespace_pixels = detail::raw_text_extent_size(handle_, L" ", 1).width; - if(changed_ == false) changed_ = true; + impl_->handle->string.tab_pixels = detail::raw_text_extent_size(impl_->handle, L"\t", 1).width; + impl_->handle->string.whitespace_pixels = detail::raw_text_extent_size(impl_->handle, L" ", 1).width; + + if (impl_->changed == false) + impl_->changed = true; } } @@ -359,7 +392,7 @@ namespace paint { //The font may be set when the graphics is still 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 @@ -385,26 +418,26 @@ namespace paint 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 { - 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 { 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; #if defined(NANA_WINDOWS) int * dx = new int[len]; SIZE extents; - ::GetTextExtentExPoint(handle_->context, str, static_cast(len), 0, 0, dx, &extents); + ::GetTextExtentExPoint(impl_->handle->context, str, static_cast(len), 0, 0, dx, &extents); 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; 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 { - 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; - 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) int * dx = new int[len]; SIZE extents; - ::GetTextExtentExPoint(handle_->context, str, static_cast(len), 0, 0, dx, &extents); + ::GetTextExtentExPoint(impl_->handle->context, str, static_cast(len), 0, 0, dx, &extents); pxbuf[0] = (str[0] == '\t' ? tab_pixels : dx[0]); @@ -445,7 +478,7 @@ namespace paint #elif defined(NANA_X11) && defined(NANA_USE_XFT) Display * disp = nana::detail::platform_spec::instance().open_display(); - XftFont * xft = handle_->font->handle; + XftFont * xft = impl_->handle->font->handle; XGlyphInfo extents; 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 sz; - if(handle_ && handle_->context && str.size()) + if(impl_->handle && impl_->handle->context && str.size()) { std::vector reordered; unicode_bidi bidi; @@ -489,25 +522,25 @@ namespace paint bool graphics::text_metrics(unsigned & ascent, unsigned& descent, unsigned& internal_leading) const { - if(handle_) + if(impl_->handle) { #if defined(NANA_WINDOWS) ::TEXTMETRIC tm; - ::GetTextMetrics(handle_->context, &tm); + ::GetTextMetrics(impl_->handle->context, &tm); ascent = static_cast(tm.tmAscent); descent = static_cast(tm.tmDescent); internal_leading = static_cast(tm.tmInternalLeading); return true; #elif defined(NANA_X11) - if(handle_->font) + if(impl_->handle->font) { #if defined(NANA_USE_XFT) - XftFont * fs = reinterpret_cast(handle_->font->handle); + XftFont * fs = reinterpret_cast(impl_->handle->font->handle); ascent = fs->ascent; descent = fs->descent; internal_leading = 0; #else - XFontSet fs = reinterpret_cast(handle_->font->handle); + XFontSet fs = reinterpret_cast(impl_->handle->font->handle); XFontSetExtents * ext = ::XExtentsOfFontSet(fs); XFontStruct ** fontstructs; char ** font_names; @@ -532,13 +565,13 @@ namespace paint void graphics::line_begin(int x, int y) { - if(!handle_) return; + if(!impl_->handle) return; #if defined(NANA_WINDOWS) - ::MoveToEx(handle_->context, x, y, 0); + ::MoveToEx(impl_->handle->context, x, y, 0); #elif defined(NANA_X11) - handle_->line_begin_pos.x = x; - handle_->line_begin_pos.y = y; + impl_->handle->line_begin_pos.x = x; + impl_->handle->line_begin_pos.y = y; #endif } @@ -552,94 +585,94 @@ namespace paint void graphics::bitblt(const nana::rectangle& r_dst, native_window_type src) { - if(handle_) + if(impl_->handle) { #if defined(NANA_WINDOWS) HDC dc = ::GetDC(reinterpret_cast(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(src), dc); #elif defined(NANA_X11) ::XCopyArea(nana::detail::platform_spec::instance().open_display(), - reinterpret_cast(src), handle_->pixmap, handle_->context, + reinterpret_cast(src), impl_->handle->pixmap, impl_->handle->context, 0, 0, r_dst.width, r_dst.height, r_dst.x, r_dst.y); #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) { - if(handle_) + if(impl_->handle) { #if defined(NANA_WINDOWS) HDC dc = ::GetDC(reinterpret_cast(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(src), dc); #elif defined(NANA_X11) ::XCopyArea(nana::detail::platform_spec::instance().open_display(), - reinterpret_cast(src), handle_->pixmap, handle_->context, + reinterpret_cast(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); #endif - if(changed_ == false) changed_ = true; + if (impl_->changed == false) impl_->changed = true; } } 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) - ::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) ::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); #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) { - if(handle_ && src.handle_) + if(impl_->handle && src.impl_->handle) { #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) ::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); #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 { - if(dst.handle_ && handle_ && (dst.handle_ != handle_)) + if(dst.impl_->handle && impl_->handle && (dst.impl_->handle != impl_->handle)) { 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) { - if(handle_) + if(impl_->handle) { - pixel_buffer pixbuf(handle_, 0, 0); + pixel_buffer pixbuf(impl_->handle, 0, 0); pixbuf.blur(r, radius); - pixbuf.paste(handle_, point{}); + pixbuf.paste(impl_->handle, point{}); } } void graphics::rgb_to_wb() { - if(handle_) + if(impl_->handle) { //Create the color table for perfermance float* tablebuf = new float[0x100 * 3]; @@ -654,11 +687,11 @@ namespace paint 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); - 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 length_align4 = sz.width - rest; @@ -692,26 +725,26 @@ namespace paint } delete [] tablebuf; - pixbuf.paste(handle_, point{}); - if(changed_ == false) changed_ = true; + pixbuf.paste(impl_->handle, point{}); + if (impl_->changed == false) impl_->changed = true; } } 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) - ::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) Display* display = nana::detail::platform_spec::instance().open_display(); ::XCopyArea(display, - handle_->pixmap, dst.handle_->pixmap, handle_->context, - 0, 0, size_.width, size_.height, x, y); + impl_->handle->pixmap, dst.impl_->handle->pixmap, impl_->handle->context, + 0, 0, impl_->size.width, impl_->size.height, x, y); ::XFlush(display); #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 { - if(handle_) + if(impl_->handle) { #if defined(NANA_WINDOWS) HDC dc = ::GetDC(reinterpret_cast(dst)); 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(dst), dc); } #elif defined(NANA_X11) Display * display = nana::detail::platform_spec::instance().open_display(); ::XCopyArea(display, - handle_->pixmap, reinterpret_cast(dst), handle_->context, + impl_->handle->pixmap, reinterpret_cast(dst), impl_->handle->context, sx, sy, width, height, dx, dy); ::XMapWindow(display, reinterpret_cast(dst)); @@ -745,15 +778,15 @@ namespace paint 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) - ::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) Display * display = nana::detail::platform_spec::instance().open_display(); ::XCopyArea(display, - handle_->pixmap, dst->pixmap, handle_->context, - 0, 0, size_.width, size_.height, x, y); + impl_->handle->pixmap, dst->pixmap, impl_->handle->context, + 0, 0, impl_->size.width, impl_->size.height, x, y); ::XFlush(display); #endif } @@ -762,14 +795,14 @@ namespace paint 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) - ::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) Display* display = nana::detail::platform_spec::instance().open_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); ::XFlush(display); @@ -779,10 +812,10 @@ namespace paint 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); - pixbuf.stretch(src_r, dst.handle_, r); + pixel_buffer pixbuf(impl_->handle, 0, 0); + pixbuf.stretch(src_r, dst.impl_->handle, r); } } @@ -799,58 +832,58 @@ namespace paint } unsigned graphics::width() const{ - return size_.width; + return impl_->size.width; } unsigned graphics::height() const{ - return size_.height; + return impl_->size.height; } nana::size graphics::size() const{ - return this->size_; + return this->impl_->size; } void graphics::setsta() { - changed_ = false; + impl_->changed = false; } void graphics::set_changed() { - changed_ = true; + impl_->changed = true; } void graphics::release() { - dwptr_.reset(); - handle_ = nullptr; - size_.width = size_.height = 0; + impl_->platform_drawable.reset(); + impl_->handle = nullptr; + impl_->size.width = impl_->size.height = 0; } void graphics::save_as_file(const char* file_utf8) const throw() { - if(handle_) + if(impl_->handle) { #if defined(NANA_WINDOWS) - int iWidth = static_cast(size_.width); - int iHeight = static_cast(size_.height); + const int iWidth = static_cast(impl_->size.width); + const int iHeight = static_cast(impl_->size.height); BITMAPINFO bmpInfo = {}; bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader); - bmpInfo.bmiHeader.biWidth = static_cast(size_.width); - bmpInfo.bmiHeader.biHeight = static_cast(size_.height); + bmpInfo.bmiHeader.biWidth = iWidth; + bmpInfo.bmiHeader.biHeight = iHeight; bmpInfo.bmiHeader.biPlanes = 1; bmpInfo.bmiHeader.biBitCount = 24; const size_t lineBytes = ((bmpInfo.bmiHeader.biWidth * 3) + 3) & (~3); const size_t imageBytes = iHeight * lineBytes; - HDC hdcMem = ::CreateCompatibleDC(handle_->context); + HDC hdcMem = ::CreateCompatibleDC(impl_->handle->context); BYTE *pData = nullptr; HBITMAP hBmp = ::CreateDIBSection(hdcMem, &bmpInfo, DIB_RGB_COLORS, reinterpret_cast(&pData), 0, 0); ::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 }; bmFileHeader.bfType = 0x4d42; //bmp @@ -874,20 +907,20 @@ namespace paint ::nana::color graphics::palette(bool for_text) const { - if (handle_) - return static_cast(for_text ? handle_->get_text_color() : handle_->get_color()); + if (impl_->handle) + return static_cast(for_text ? impl_->handle->get_text_color() : impl_->handle->get_color()); return{}; } graphics& graphics::palette(bool for_text, const ::nana::color& clr) { - if (handle_) + if (impl_->handle) { if (for_text) - handle_->set_text_color(clr); + impl_->handle->set_text_color(clr); else - handle_->set_color(clr); + impl_->handle->set_color(clr); } return *this; @@ -915,34 +948,34 @@ namespace paint 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); - if (changed_ == false) changed_ = true; + nana::paint::detail::blend(impl_->handle, r, clr.px_color(), fade_rate); + if (impl_->changed == false) impl_->changed = true; } } 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); } } void graphics::set_pixel(int x, int y) { - if (handle_) + if (impl_->handle) { #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) Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->update_color(); - ::XDrawPoint(disp, handle_->pixmap, handle_->context, x, y); + impl_->handle->update_color(); + ::XDrawPoint(disp, impl_->handle->pixmap, handle_->context, x, y); #endif - if (changed_ == false) changed_ = true; + if (impl_->changed == false) impl_->changed = true; } } @@ -959,7 +992,7 @@ namespace paint 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 i = std::find(str, end, '\t'); @@ -968,15 +1001,15 @@ namespace paint #endif 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) { len = i - str; if (len) { //Render a part that does not contains a tab - detail::draw_string(handle_, pos, str, len); - pos.x += detail::raw_text_extent_size(handle_, str, len).width; + detail::draw_string(impl_->handle, pos, str, len); + pos.x += detail::raw_text_extent_size(impl_->handle, str, len).width; } str = i; @@ -994,8 +1027,8 @@ namespace paint } } else - detail::draw_string(handle_, pos, str, len); - if (changed_ == false) changed_ = true; + detail::draw_string(impl_->handle, pos, str, len); + if (impl_->changed == false) impl_->changed = true; } } @@ -1017,21 +1050,21 @@ namespace paint void graphics::line(const nana::point& pos1, const nana::point& pos2) { - if (!handle_) return; + if (!impl_->handle) return; #if defined(NANA_WINDOWS) - handle_->update_pen(); + impl_->handle->update_pen(); if (pos1 != pos2) { - ::MoveToEx(handle_->context, pos1.x, pos1.y, 0); - ::LineTo(handle_->context, pos2.x, pos2.y); + ::MoveToEx(impl_->handle->context, pos1.x, pos1.y, 0); + ::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) Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->update_color(); - ::XDrawLine(disp, handle_->pixmap, handle_->context, pos1.x, pos1.y, pos2.x, pos2.y); + impl_->handle->update_color(); + ::XDrawLine(disp, impl_->handle->pixmap, impl_->handle->context, pos1.x, pos1.y, pos2.x, pos2.y); #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) @@ -1042,26 +1075,26 @@ namespace paint void graphics::line_to(const point& pos, const color& clr) { - if (!handle_) return; - handle_->set_color(clr); + if (!impl_->handle) return; + impl_->handle->set_color(clr); line_to(pos); } void graphics::line_to(const point& pos) { - if (!handle_) return; + if (!impl_->handle) return; #if defined(NANA_WINDOWS) - handle_->update_pen(); - ::LineTo(handle_->context, pos.x, pos.y); + impl_->handle->update_pen(); + ::LineTo(impl_->handle->context, pos.x, pos.y); #elif defined(NANA_X11) Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->update_color(); - ::XDrawLine(disp, handle_->pixmap, handle_->context, - handle_->line_begin_pos.x, handle_->line_begin_pos.y, + impl_->handle->update_color(); + ::XDrawLine(disp, impl_->handle->pixmap, impl_->handle->context, + impl_->handle->line_begin_pos.x, impl_->handle->line_begin_pos.y, pos.x, pos.y); - handle_->line_begin_pos = pos; + impl_->handle->line_begin_pos = pos; #endif - if (changed_ == false) changed_ = true; + if (impl_->changed == false) impl_->changed = true; } void graphics::rectangle(bool solid) @@ -1077,21 +1110,21 @@ namespace paint 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) ::RECT native_r = { r.x, r.y, r.right(), r.bottom()}; - handle_->update_brush(); - (solid ? ::FillRect : ::FrameRect)(handle_->context, &native_r, handle_->brush.handle); + impl_->handle->update_brush(); + (solid ? ::FillRect : ::FrameRect)(impl_->handle->context, &native_r, impl_->handle->brush.handle); #elif defined(NANA_X11) Display* disp = nana::detail::platform_spec::instance().open_display(); - handle_->update_color(); + impl_->handle->update_color(); 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 - ::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 - if (changed_ == false) changed_ = true; + if (impl_->changed == false) impl_->changed = true; } } @@ -1138,10 +1171,10 @@ namespace paint void graphics::gradual_rectangle(const ::nana::rectangle& rct, const ::nana::color& from, const ::nana::color& to, bool vertical) { #if defined(NANA_WINDOWS) - if (pxbuf_.open(handle_)) + if (impl_->pxbuf.open(impl_->handle)) { - pxbuf_.gradual_rectangle(rct, from, to, 0.0, vertical); - pxbuf_.paste(handle_, point{}); + impl_->pxbuf.gradual_rectangle(rct, from, to, 0.0, vertical); + impl_->pxbuf.paste(impl_->handle, point{}); } #elif defined(NANA_X11) if (nullptr == handle_) return; @@ -1155,7 +1188,7 @@ namespace paint unsigned last_color = (int(r) << 16) | (int(g) << 8) | int(b); Display * disp = nana::detail::platform_spec::instance().open_display(); - handle_->fgcolor(static_cast(last_color)); + impl_->handle->fgcolor(static_cast(last_color)); const int endpos = deltapx + (vertical ? rct.y : rct.x); if (endpos > 0) { @@ -1165,12 +1198,12 @@ namespace paint auto y = rct.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); if (new_color != last_color) { last_color = new_color; - handle_->fgcolor(static_cast(last_color)); + impl_->handle->fgcolor(static_cast(last_color)); } } } @@ -1180,39 +1213,40 @@ namespace paint auto x = rct.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); if (new_color != last_color) { last_color = new_color; - handle_->fgcolor(static_cast(last_color)); + impl_->handle->fgcolor(static_cast(last_color)); } } } } #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) { - if (handle_) + if (impl_->handle) { #if defined(NANA_WINDOWS) - handle_->set_color(clr); + impl_->handle->set_color(clr); if (solid) { - handle_->update_pen(); - handle_->brush.set(handle_->context, handle_->brush.Solid, solid_clr.px_color().value); - ::RoundRect(handle_->context, r.x, r.y, r.right(), r.bottom(), static_cast(radius_x * 2), static_cast(radius_y * 2)); + impl_->handle->update_pen(); + impl_->handle->brush.set(impl_->handle->context, impl_->handle->brush.Solid, solid_clr.px_color().value); + ::RoundRect(impl_->handle->context, r.x, r.y, r.right(), r.bottom(), static_cast(radius_x * 2), static_cast(radius_y * 2)); } else { - handle_->update_brush(); - handle_->round_region.set(r, radius_x, radius_y); - ::FrameRgn(handle_->context, handle_->round_region.handle, handle_->brush.handle, 1, 1); + impl_->handle->update_brush(); + impl_->handle->round_region.set(r, radius_x, radius_y); + ::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) if(solid && (clr == solid_clr)) { diff --git a/source/paint/text_renderer.cpp b/source/paint/text_renderer.cpp index 825639c6..878b3ce0 100644 --- a/source/paint/text_renderer.cpp +++ b/source/paint/text_renderer.cpp @@ -70,7 +70,7 @@ namespace nana auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin); if(ts.height > pixels) pixels = ts.height; lenpx += ts.width; - widths.push_back(ts.width); + widths.emplace_back(ts.width); } pos.x += (endpos - pos.x - static_cast(lenpx))/2; @@ -199,7 +199,7 @@ namespace nana { nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); if(ts.height > pixels) pixels = ts.height; - ts_keeper.push_back(ts); + ts_keeper.emplace_back(ts); str_w += ts.width; } @@ -417,7 +417,7 @@ namespace nana for(auto & i : reordered) { 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; } diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index cb8ecb97..b647e1ec 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/source/threads/pool.cpp b/source/threads/pool.cpp index c7af1e47..f1237887 100644 --- a/source/threads/pool.cpp +++ b/source/threads/pool.cpp @@ -94,7 +94,7 @@ namespace threads pto->suspended = false; ::pthread_create(&(pto->handle), 0, reinterpret_cast(&impl::_m_thr_starter), pto); #endif - container_.threads.push_back(pto); + container_.threads.emplace_back(pto); } } @@ -168,7 +168,7 @@ namespace threads else { std::lock_guard lock(mutex_); - container_.tasks.push_back(taskptr); + container_.tasks.emplace_back(taskptr); } } diff --git a/source/unicode_bidi.cpp b/source/unicode_bidi.cpp index f92bd5ee..b98c6f29 100644 --- a/source/unicode_bidi.cpp +++ b/source/unicode_bidi.cpp @@ -536,7 +536,8 @@ namespace nana } else if (LRE <= *c && *c <= RLO) { - stack.push_back(cur); + stack.emplace_back(cur); + if (begin_character) { _m_push_entity(begin_character, c, cur.level, begin_char_type); @@ -607,19 +608,21 @@ namespace nana 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.end = end; e.level = level; e.bidi_char_type = bidi_char_type; - levels_.push_back(e); - } + } + std::vector::iterator unicode_bidi::_m_search_first_character() { return levels_.begin(); } + auto unicode_bidi::_m_eor(std::vector::iterator i) ->bidi_char { const auto end = levels_.end();