From f81b730c5c13f7025d382603d6bea588fd4516b9 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 19 Jul 2016 18:20:43 +0200 Subject: [PATCH 01/32] listbox stable_sort --- source/gui/widgets/listbox.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 85889705..5da2dc15 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -746,7 +746,7 @@ namespace nana if (cat.model_ptr) { - std::sort(bi, ei, [&cat, &weak_ordering_comp, this](std::size_t x, std::size_t y){ + std::stable_sort(bi, ei, [&cat, &weak_ordering_comp, this](std::size_t x, std::size_t y){ //The predicate must be a strict weak ordering. //!comp(x, y) != comp(x, y) auto & mx = cat.items[x]; @@ -773,7 +773,7 @@ namespace nana } else { - std::sort(bi, ei, [&cat, &weak_ordering_comp, this](std::size_t x, std::size_t y){ + std::stable_sort(bi, ei, [&cat, &weak_ordering_comp, this](std::size_t x, std::size_t y){ //The predicate must be a strict weak ordering. //!comp(x, y) != comp(x, y) @@ -804,7 +804,7 @@ namespace nana { if (cat.model_ptr) { - std::sort(std::begin(cat.sorted), std::end(cat.sorted), [&cat, this](std::size_t x, std::size_t y){ + std::stable_sort(std::begin(cat.sorted), std::end(cat.sorted), [&cat, this](std::size_t x, std::size_t y){ auto mx_cells = cat.model_ptr->container()->to_cells(x); auto my_cells = cat.model_ptr->container()->to_cells(y); @@ -828,7 +828,7 @@ namespace nana } else { - std::sort(std::begin(cat.sorted), std::end(cat.sorted), [&cat, this](std::size_t x, std::size_t y){ + std::stable_sort(std::begin(cat.sorted), std::end(cat.sorted), [&cat, this](std::size_t x, std::size_t y){ auto & mx = cat.items[x]; auto & my = cat.items[y]; From 34cca3477337511f6b5d9833da49c4cdc9be2eaa Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 26 Jul 2016 07:32:50 +0800 Subject: [PATCH 02/32] fix the behaviour of clicking menu disabled item --- include/nana/paint/graphics.hpp | 10 ++++ source/gui/widgets/menu.cpp | 86 +++++++++++++++------------------ source/paint/graphics.cpp | 35 ++++++++++++++ 3 files changed, 84 insertions(+), 47 deletions(-) diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp index 7102c500..8e667ef2 100644 --- a/include/nana/paint/graphics.hpp +++ b/include/nana/paint/graphics.hpp @@ -179,6 +179,16 @@ namespace nana pixel_buffer pxbuf_; bool changed_; }; + + class draw + { + public: + draw(graphics& graph); + + void corner(const rectangle& r, unsigned pixels); + private: + graphics& graph_; + }; }//end namespace paint } //end namespace nana #endif diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 2ba13a4d..dd90fdca 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -113,19 +113,15 @@ namespace nana void item(graph_reference graph, const nana::rectangle& r, const attr& at) { + if (!at.enabled) + return; + if(at.item_state == state::active) { graph.rectangle(r, false, static_cast(0xa8d8eb)); - nana::point points[4] = { - nana::point(r.x, r.y), - nana::point(r.x + r.width - 1, r.y), - nana::point(r.x, r.y + r.height - 1), - nana::point(r.x + r.width - 1, r.y + r.height - 1) - }; graph.palette(false, static_cast(0xc0ddfc)); - for(int i = 0; i < 4; ++i) - graph.set_pixel(points[i].x, points[i].y); + paint::draw(graph).corner(r, 1); if(at.enabled) graph.gradual_rectangle(nana::rectangle(r).pare_off(1), static_cast(0xE8F0F4), static_cast(0xDBECF4), true); @@ -785,9 +781,8 @@ namespace nana { if (event_code::mouse_down == arg.evt_code) _m_open_sub(0); //Try to open submenu immediately - else if (event_code::mouse_up == arg.evt_code) - if (arg.button == ::nana::mouse::left_button) - pick(); + else if ((event_code::mouse_up == arg.evt_code) && (mouse::left_button == arg.button)) + pick(); }; events.mouse_down.connect_unignorable(fn); @@ -885,48 +880,45 @@ namespace nana return; menu_item_type & item = menu->items.at(active); - if (item.flags.splitter == false && item.sub_menu == nullptr) + + if ((!item.flags.enabled) || item.flags.splitter || item.sub_menu) + return; + + if (checks::highlight == item.style) { - //There is a situation that menu will not call functor if the item style is check_option - //and it is checked before clicking. - bool call_functor = true; - - if (checks::highlight == item.style) + item.flags.checked = !item.flags.checked; + } + else if (checks::option == item.style) + { + //Forward Looks for a splitter + auto pos = active; + while (pos) { - item.flags.checked = !item.flags.checked; - } - else if (checks::option == item.style) - { - //Forward Looks for a splitter - auto pos = active; - while (pos) - { - if (menu->items.at(--pos).flags.splitter) - break; - } - - for (; pos < menu->items.size(); ++pos) - { - menu_item_type & im = menu->items.at(pos); - if (im.flags.splitter) break; - - if ((checks::option == im.style) && im.flags.checked) - im.flags.checked = false; - } - - item.flags.checked = true; + if (menu->items.at(--pos).flags.splitter) + break; } - this->_m_close_all(); //means deleting this; - //The deleting operation has moved here, because item.functor.operator()(ip) - //may create a window, which make a killing focus for menu window, if so the close_all - //operation preformences after item.functor.operator()(ip), that would be deleting this object twice! - - if (call_functor && item.flags.enabled && item.functor) + for (; pos < menu->items.size(); ++pos) { - item_type::item_proxy ip(active, item); - item.functor.operator()(ip); + menu_item_type & im = menu->items.at(pos); + if (im.flags.splitter) break; + + if ((checks::option == im.style) && im.flags.checked) + im.flags.checked = false; } + + item.flags.checked = true; + } + + this->_m_close_all(); //means deleting this; + //The deleting operation has moved here, because item.functor.operator()(ip) + //may create a window, which make a killing focus for menu window, if so the close_all + //operation preformences after item.functor.operator()(ip), that would be deleting this object twice! + + if (item.functor) + { + item_type::item_proxy ip(active, item); + item.functor.operator()(ip); } } private: diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 15a29c52..40530a18 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -1233,5 +1233,40 @@ namespace paint } //end class graphics + //class draw + draw::draw(graphics& graph) + : graph_(graph) + {} + + void draw::corner(const rectangle& r, unsigned pixels) + { + if (1 == pixels) + { + graph_.set_pixel(r.x, r.y); + graph_.set_pixel(r.right() - 1, r.y); + + graph_.set_pixel(r.x, r.bottom() - 1); + graph_.set_pixel(r.right() - 1, r.bottom() - 1); + return; + } + else if (1 < pixels) + { + graph_.line(r.position(), point(r.x + pixels, r.y)); + graph_.line(r.position(), point(r.x, r.y + pixels)); + + int right = r.right() - 1; + graph_.line(point(right, r.y), point(right - pixels, r.y)); + graph_.line(point(right, r.y), point(right, r.y - pixels)); + + int bottom = r.bottom() - 1; + graph_.line(point(r.x, bottom), point(r.x + pixels, bottom)); + graph_.line(point(r.x, bottom), point(r.x, bottom - pixels)); + + graph_.line(point(right, bottom), point(right - pixels, bottom)); + graph_.line(point(right, bottom), point(right, bottom - pixels)); + } + } + //end class draw + }//end namespace paint }//end namespace nana From df5a786965b5828d16ed344298a97b9da79a0211 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 31 Jul 2016 04:11:39 +0800 Subject: [PATCH 03/32] fix a bug that listbox::cat_proxy::append throws if model enabled --- source/gui/widgets/listbox.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 5da2dc15..91cf6d4e 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -972,6 +972,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; // @@ -5027,9 +5028,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_); } From 6fbc4a7988b3fea45b3023effa7a8d1003acf1d1 Mon Sep 17 00:00:00 2001 From: dankan1890 Date: Mon, 1 Aug 2016 03:20:07 +0200 Subject: [PATCH 04/32] Fixed the behavior of disabled items in the menus when scrolling with the arrows keys. --- source/gui/widgets/menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index dd90fdca..9b80249f 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -475,7 +475,7 @@ namespace nana --pos; } - if(! menu_->items.at(pos).flags.splitter) + if(! menu_->items.at(pos).flags.splitter && menu_->items.at(pos).flags.enabled) break; } From 6e86b6ae6c916951149ec564988a373b1c4fc232 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 10 Aug 2016 01:46:13 +0800 Subject: [PATCH 05/32] refine code fix bug that listbox may throw std::runtime when the modal is enabled fix bug that textbox attachs a wrong event angent --- include/nana/detail/win32/platform_spec.hpp | 14 +- include/nana/gui/detail/element_store.hpp | 27 +- .../nana/gui/detail/inner_fwd_implement.hpp | 4 +- include/nana/gui/detail/window_manager.hpp | 25 +- include/nana/gui/element.hpp | 10 +- include/nana/gui/place.hpp | 1 - include/nana/gui/programming_interface.hpp | 3 +- include/nana/gui/widgets/listbox.hpp | 6 +- .../gui/widgets/skeletons/text_editor.hpp | 169 +---- include/nana/gui/widgets/slider.hpp | 4 +- include/nana/gui/widgets/widget.hpp | 22 +- include/nana/internationalization.hpp | 3 - include/nana/paint/graphics.hpp | 25 +- source/audio/detail/audio_device.cpp | 2 +- source/audio/detail/buffer_preparation.cpp | 6 +- source/detail/platform_spec_windows.cpp | 28 +- source/gui/detail/basic_window.cpp | 2 +- source/gui/detail/bedrock_pi.cpp | 2 +- source/gui/detail/drawer.cpp | 4 +- source/gui/detail/element_store.cpp | 38 +- source/gui/detail/window_layout.cpp | 6 +- source/gui/detail/window_manager.cpp | 201 ++--- source/gui/dragger.cpp | 2 +- source/gui/element.cpp | 259 +++---- source/gui/place.cpp | 7 +- source/gui/programming_interface.cpp | 6 +- source/gui/timer.cpp | 3 +- source/gui/tooltip.cpp | 2 +- source/gui/widgets/checkbox.cpp | 3 +- source/gui/widgets/combox.cpp | 4 +- source/gui/widgets/float_listbox.cpp | 32 +- source/gui/widgets/label.cpp | 22 +- source/gui/widgets/listbox.cpp | 52 +- source/gui/widgets/menu.cpp | 1 + source/gui/widgets/skeletons/text_editor.cpp | 702 +++++++++++------- source/gui/widgets/slider.cpp | 2 +- source/gui/widgets/textbox.cpp | 3 +- source/gui/widgets/treebox.cpp | 1 + source/internationalization.cpp | 20 +- source/paint/graphics.cpp | 388 +++++----- source/paint/text_renderer.cpp | 6 +- source/system/dataexch.cpp | 1 + source/threads/pool.cpp | 4 +- source/unicode_bidi.cpp | 11 +- 44 files changed, 1120 insertions(+), 1013 deletions(-) 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(); From ebfa079f3fd22b82a077a2cc43b4b131464e112b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 11 Aug 2016 02:15:19 +0800 Subject: [PATCH 06/32] fix bug that text_editor throws an exception when undo a backspace --- source/gui/widgets/skeletons/text_editor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 03168ce1..e30248a8 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -2300,6 +2300,8 @@ namespace nana{ namespace widgets } else { + undo_ptr->set_removed(this->_m_make_select_string()); + undo_ptr->set_selected_text(); points_.caret = _m_erase_select(); undo_ptr->set_caret_pos(); From 9b28c96e9bc5be0f0b36e30ad61abfa0e5ff17cf Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 11 Aug 2016 02:26:47 +0800 Subject: [PATCH 07/32] code refine --- .../nana/gui/detail/inner_fwd_implement.hpp | 153 ++++------------ source/detail/platform_spec_posix.cpp | 1 + source/gui/detail/bedrock_pi.cpp | 3 +- source/gui/detail/drawer.cpp | 2 +- .../gui/detail/dynamic_drawing_object.hpp | 0 source/gui/detail/window_manager.cpp | 172 ++++++++++++++++++ source/gui/element.cpp | 2 +- source/gui/widgets/menu.cpp | 2 +- source/gui/widgets/menubar.cpp | 2 +- source/gui/widgets/tabbar.cpp | 7 +- source/paint/graphics.cpp | 6 +- 11 files changed, 225 insertions(+), 125 deletions(-) rename {include/nana => source}/gui/detail/dynamic_drawing_object.hpp (100%) diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/include/nana/gui/detail/inner_fwd_implement.hpp index 4b7d958a..68937148 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/include/nana/gui/detail/inner_fwd_implement.hpp @@ -1,7 +1,7 @@ /* * Implementations of Inner Forward Declaration * 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 @@ -26,87 +26,32 @@ namespace nana{ { class shortkey_container { - struct item_type - { - window handle; - std::vector keys; - }; + struct item_type; + + //Noncopyable + shortkey_container(const shortkey_container&) = delete; + shortkey_container& operator=(const shortkey_container&) = delete; + + shortkey_container& operator=(shortkey_container&&) = delete; public: - void clear() - { - keybase_.clear(); - } + shortkey_container(); - bool make(window wd, unsigned long key) - { - if (wd == nullptr) return false; - if (key < 0x61) key += (0x61 - 0x41); + shortkey_container(shortkey_container&&); - for (auto & m : keybase_) - { - if (m.handle == wd) - { - m.keys.push_back(key); - return true; - } - } + ~shortkey_container(); - item_type m; - m.handle = wd; - m.keys.push_back(key); - keybase_.push_back(m); + void clear(); - return true; - } + bool make(window wd, unsigned long key); - void umake(window wd) - { - if (wd == nullptr) return; + void umake(window wd); - for (auto i = keybase_.begin(), end = keybase_.end(); i != end; ++i) - { - if (i->handle == wd) - { - keybase_.erase(i); - break; - } - } - } + std::vector keys(window wd) const; - std::vector keys(window wd) const - { - std::vector v; - if (wd) - { - for (auto & m : keybase_) - { - if (m.handle == wd) - { - v = m.keys; - break; - } - } - } - return v; - - } - - window find(unsigned long key) const - { - if (key < 0x61) key += (0x61 - 0x41); - - for (auto & m : keybase_) - { - for (auto n : m.keys) - { - if (key == n) - return m.handle; - } - } - return nullptr; - } + window find(unsigned long key) const; private: - std::vector keybase_; + struct implementation; + implementation * impl_; }; @@ -118,57 +63,39 @@ namespace nana{ struct condition_rep { - bool ignore_tab{ false }; //ignore tab when the focus is changed by TAB key. - basic_window* pressed{ nullptr }; //The handle to a window which has been pressed by mouse left button. - basic_window* pressed_by_space{ nullptr }; //The handle to a window which has been pressed by SPACEBAR key. - basic_window* hovered{ nullptr }; //the latest window that mouse moved + bool ignore_tab; //ignore tab when the focus is changed by TAB key. + basic_window* pressed; //The handle to a window which has been pressed by mouse left button. + basic_window* pressed_by_space; //The handle to a window which has been pressed by SPACEBAR key. + basic_window* hovered; //the latest window that mouse moved }condition; - root_misc(basic_window * wd, unsigned width, unsigned height) - : window(wd), - root_graph({ width, height }) - {} + root_misc(root_misc&&); + root_misc(basic_window * wd, unsigned width, unsigned height); };//end struct root_misc + + class root_register { + //Noncopyable + root_register(const root_register&) = delete; + root_register& operator=(const root_register&) = delete; + + //Nonmovable + root_register(root_register&&) = delete; + root_register& operator=(root_register&&) = delete; public: - root_misc* insert(native_window_type wd, root_misc&& misc) - { - recent_ = wd; - auto ret = table_.emplace(wd, std::move(misc)); - misc_ptr_ = &(ret.first->second); - return misc_ptr_; - } + root_register(); + ~root_register(); - root_misc * find(native_window_type wd) - { - if (wd == recent_) - return misc_ptr_; + root_misc* insert(native_window_type, root_misc&&); - recent_ = wd; - - auto i = table_.find(wd); - if (i != table_.end()) - misc_ptr_ = &(i->second); - else - misc_ptr_ = nullptr; + root_misc * find(native_window_type); - return misc_ptr_; - } - - void erase(native_window_type wd) - { - table_.erase(wd); - recent_ = wd; - misc_ptr_ = nullptr; - } + void erase(native_window_type); private: - //Cached - mutable native_window_type recent_{nullptr}; - mutable root_misc * misc_ptr_{nullptr}; - - std::map table_; + struct implementation; + implementation * const impl_; }; } }//end namespace nana diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index 97ce8d19..c737cdf6 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index 64db05cd..c6617bd7 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,6 +25,7 @@ namespace nana { + //class internal_scope_guard internal_scope_guard::internal_scope_guard() { diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index e3b7b2fe..0ab725aa 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -13,9 +13,9 @@ #include #include #include -#include #include #include +#include "dynamic_drawing_object.hpp" #if defined(NANA_X11) #include diff --git a/include/nana/gui/detail/dynamic_drawing_object.hpp b/source/gui/detail/dynamic_drawing_object.hpp similarity index 100% rename from include/nana/gui/detail/dynamic_drawing_object.hpp rename to source/gui/detail/dynamic_drawing_object.hpp diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 3e5d1d23..eb4efaf9 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -32,6 +32,178 @@ namespace nana { + namespace detail + { + //class shortkey_container + struct shortkey_rep + { + window handle; + std::vector keys; + }; + + struct shortkey_container::implementation + { + std::vector base; + }; + + shortkey_container::shortkey_container() + :impl_(new implementation) + {} + + shortkey_container::shortkey_container(shortkey_container&& other) + : impl_(other.impl_) + { + other.impl_ = nullptr; + } + + shortkey_container::~shortkey_container() + { + delete impl_; + } + + void shortkey_container::clear() + { + impl_->base.clear(); + } + + bool shortkey_container::make(window wd, unsigned long key) + { + if (wd == nullptr) return false; + if (key < 0x61) key += (0x61 - 0x41); + + for (auto & m : impl_->base) + { + if (m.handle == wd) + { + m.keys.emplace_back(key); + return true; + } + } + + impl_->base.emplace_back(); + auto & rep = impl_->base.back(); + rep.handle = wd; + rep.keys.emplace_back(key); + + return true; + } + + void shortkey_container::umake(window wd) + { + if (wd == nullptr) return; + + for (auto i = impl_->base.begin(); i != impl_->base.end(); ++i) + { + if (i->handle == wd) + { + impl_->base.erase(i); + break; + } + } + } + + std::vector shortkey_container::keys(window wd) const + { + if (wd) + { + for (auto & m : impl_->base) + { + if (m.handle == wd) + return m.keys; + } + } + return{}; + } + + window shortkey_container::find(unsigned long key) const + { + if (key < 0x61) key += (0x61 - 0x41); + + for (auto & m : impl_->base) + { + for (auto n : m.keys) + { + if (key == n) + return m.handle; + } + } + return nullptr; + } + //end class shortkey_container + + + //struct root_misc + root_misc::root_misc(root_misc&& other): + window(other.window), + root_graph(std::move(other.root_graph)), + shortkeys(std::move(other.shortkeys)), + condition(std::move(other.condition)) + { + } + + root_misc::root_misc(basic_window * wd, unsigned width, unsigned height) + : window(wd), + root_graph({ width, height }) + { + condition.ignore_tab = false; + condition.pressed = nullptr; + condition.pressed_by_space = nullptr; + condition.hovered = nullptr; + } + //end struct root_misc + + //class root_register + struct root_register::implementation + { + //Cached + native_window_type recent_access{ nullptr }; + root_misc * misc_ptr{ nullptr }; + + std::map table; + }; + + root_register::root_register() + : impl_(new implementation) + {} + + root_register::~root_register() + { + delete impl_; + } + + root_misc* root_register::insert(native_window_type wd, root_misc&& misc) + { + impl_->recent_access = wd; + auto ret = impl_->table.emplace(wd, std::move(misc)); + impl_->misc_ptr = &(ret.first->second); + return impl_->misc_ptr; + } + + root_misc * root_register::find(native_window_type wd) + { + if (wd == impl_->recent_access) + return impl_->misc_ptr; + + impl_->recent_access = wd; + + auto i = impl_->table.find(wd); + if (i != impl_->table.end()) + impl_->misc_ptr = &(i->second); + else + impl_->misc_ptr = nullptr; + + return impl_->misc_ptr; + } + + void root_register::erase(native_window_type wd) + { + impl_->table.erase(wd); + impl_->recent_access = wd; + impl_->misc_ptr = nullptr; + } + //end class root_register + } + namespace detail { template diff --git a/source/gui/element.cpp b/source/gui/element.cpp index 3886e1f4..8d31a447 100644 --- a/source/gui/element.cpp +++ b/source/gui/element.cpp @@ -1176,7 +1176,7 @@ namespace nana } bground::bground(const bground& rhs) - : impl_{ new implementation } + : impl_{ new implementation(*rhs.impl_) } { if (impl_->method) impl_->method = impl_->method->clone(); diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 91493d8a..bae7ab51 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -272,7 +272,7 @@ namespace nana if(item.sub_menu == nullptr) { item.sub_menu = ⊂ - sub.owner.push_back(&root_); + sub.owner.emplace_back(&root_); return true; } } diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 10bf8814..9d40d9ec 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -55,7 +55,7 @@ namespace nana void append(const native_string_type& text, unsigned long shortkey) { if(shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41); - cont_.push_back(new item_type(text, shortkey)); + cont_.emplace_back(new item_type(text, shortkey)); } std::size_t find(unsigned long shortkey) const diff --git a/source/gui/widgets/tabbar.cpp b/source/gui/widgets/tabbar.cpp index e731b3ad..61150e9f 100644 --- a/source/gui/widgets/tabbar.cpp +++ b/source/gui/widgets/tabbar.cpp @@ -748,14 +748,13 @@ namespace nana bool _m_add_tab(std::size_t pos) { - item_t m; if((pos == npos) || (pos >= list_.size())) { - this->list_.push_back(m); + this->list_.emplace_back(); pos = static_cast(list_.size() - 1); } else - list_.insert(iterator_at(pos), m); + list_.emplace(iterator_at(pos)); basis_.active = pos; if(evt_agent_) @@ -1505,7 +1504,7 @@ namespace nana for (auto & m : items) { auto ts = graph.bidi_extent_size(m.text); - pxs.push_back(ts.width + 12); + pxs.emplace_back(ts.width + 12); pixels += ts.width + 12; } diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 4eea00c7..2496a295 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -973,7 +973,7 @@ namespace paint #elif defined(NANA_X11) Display* disp = nana::detail::platform_spec::instance().open_display(); impl_->handle->update_color(); - ::XDrawPoint(disp, impl_->handle->pixmap, handle_->context, x, y); + ::XDrawPoint(disp, impl_->handle->pixmap, impl_->handle->context, x, y); #endif if (impl_->changed == false) impl_->changed = true; } @@ -997,7 +997,7 @@ namespace paint auto const end = str + len; auto i = std::find(str, end, '\t'); #if defined(NANA_LINUX) || defined(NANA_MACOS) - handle_->update_text_color(); + impl_->handle->update_text_color(); #endif if (i != end) { @@ -1177,7 +1177,7 @@ namespace paint impl_->pxbuf.paste(impl_->handle, point{}); } #elif defined(NANA_X11) - if (nullptr == handle_) return; + if (nullptr == impl_->handle) return; double deltapx = double(vertical ? rct.height : rct.width); double r, g, b; From 5f0b77430550e676a248d0723e6f2d2eee458655 Mon Sep 17 00:00:00 2001 From: dankan1890 Date: Sun, 14 Aug 2016 23:33:01 +0200 Subject: [PATCH 08/32] Added to .gitignore some of Visual Studio extensions. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e46bb0b6..6580f35b 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ CMakeFiles/ cmake_install.cmake *.DS_Store +*.db +*.opendb From cdba16289742f5aaeecfa91110a18ae5ad67ecf9 Mon Sep 17 00:00:00 2001 From: dankan1890 Date: Sun, 14 Aug 2016 23:48:42 +0200 Subject: [PATCH 09/32] Fixed some 'false' value implicitly cast to the integer type. --- source/gui/widgets/date_chooser.cpp | 2 +- source/paint/graphics.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/gui/widgets/date_chooser.cpp b/source/gui/widgets/date_chooser.cpp index 0085f30b..aa824637 100644 --- a/source/gui/widgets/date_chooser.cpp +++ b/source/gui/widgets/date_chooser.cpp @@ -393,7 +393,7 @@ namespace nana int n = trace_.logic_pos.y * rows + trace_.logic_pos.x + 1; if (page_mode::date == page) { - if (n < 8) return false; //Here is week title bar + if (n < 8) return 0; //Here is week title bar int dw = nana::date::day_of_week(view_month_.year, view_month_.month, 1); n -= (dw ? dw + 7 : 14); } diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 6cbfe571..aa606f4e 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -140,13 +140,13 @@ namespace paint unsigned font::height() const { - if(empty()) return false; + if(empty()) return 0; return (impl_->font_ptr->height); } unsigned font::weight() const { - if(empty()) return false; + if(empty()) return 0; return (impl_->font_ptr->weight); } From 236ba4356ed8fb3309a76f8670f031e2dcbba966 Mon Sep 17 00:00:00 2001 From: dankan1890 Date: Mon, 15 Aug 2016 00:07:55 +0200 Subject: [PATCH 10/32] Removed some useless static_cast. --- source/gui/widgets/button.cpp | 2 +- source/gui/widgets/float_listbox.cpp | 4 ++-- source/gui/widgets/menubar.cpp | 2 +- source/gui/widgets/tabbar.cpp | 2 +- source/paint/graphics.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index f4a1ab3f..3d397ab5 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -235,7 +235,7 @@ namespace nana{ namespace drawerbase if(shortkey) { - unsigned off_w = (shortkey_pos ? graph.text_extent_size(mbstr.c_str(), static_cast(shortkey_pos)).width : 0); + unsigned off_w = (shortkey_pos ? graph.text_extent_size(mbstr.c_str(), shortkey_pos).width : 0); wchar_t keystr[2] = {nana::utf::char_at(mbstr.c_str() + shortkey_pos, 0, 0), 0}; auto shortkey_size = graph.text_extent_size(keystr, 1); diff --git a/source/gui/widgets/float_listbox.cpp b/source/gui/widgets/float_listbox.cpp index d47098cb..0bf42f94 100644 --- a/source/gui/widgets/float_listbox.cpp +++ b/source/gui/widgets/float_listbox.cpp @@ -161,7 +161,7 @@ namespace nana --(state_.index); else if(recycle) { - state_.index = static_cast(module_->items.size() - 1); + state_.index = module_->items.size() - 1; state_.offset_y = last_offset_y; } @@ -179,7 +179,7 @@ namespace nana } if(state_.index >= state_.offset_y + module_->max_items) - state_.offset_y = static_cast(state_.index - module_->max_items + 1); + state_.offset_y = state_.index - module_->max_items + 1; } } else diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 9d40d9ec..7d6d4de1 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -216,7 +216,7 @@ namespace nana if (hotkey) { - unsigned off_w = (hotkey_pos ? graph.text_extent_size(text.c_str(), static_cast(hotkey_pos)).width : 0); + unsigned off_w = (hotkey_pos ? graph.text_extent_size(text.c_str(), hotkey_pos).width : 0); nana::size hotkey_size = graph.text_extent_size(text.c_str() + hotkey_pos, 1); unsigned ascent, descent, inleading; diff --git a/source/gui/widgets/tabbar.cpp b/source/gui/widgets/tabbar.cpp index 61150e9f..b8824f3b 100644 --- a/source/gui/widgets/tabbar.cpp +++ b/source/gui/widgets/tabbar.cpp @@ -751,7 +751,7 @@ namespace nana if((pos == npos) || (pos >= list_.size())) { this->list_.emplace_back(); - pos = static_cast(list_.size() - 1); + pos = list_.size() - 1; } else list_.emplace(iterator_at(pos)); diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index aa606f4e..684a8ca2 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -413,7 +413,7 @@ namespace paint nana::size graphics::text_extent_size(const std::wstring& text) const { - return text_extent_size(text.c_str(), static_cast(text.length())); + return text_extent_size(text.c_str(), text.length()); } nana::size graphics::text_extent_size(const wchar_t* str, std::size_t len) const From c296d433f4cd49378a9c9c71b36fa6bf619bb504 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 16 Aug 2016 07:19:09 +0800 Subject: [PATCH 11/32] fix issue that XCreatePixmap may fail if 0-size window --- source/gui/place.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index a10246f9..6e1e673a 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -816,7 +817,7 @@ namespace nana if ((!child->is_fixed()) && child->max_px.empty() && is_back(child) && (endpos != area.right())) endpos = area.right(); - child_area.w_ref() = static_cast(endpos - child_area.x()); + child_area.w_ref() = static_cast((std::max)(endpos - child_area.x(), 0)); child->field_area = child_area.result(); position += child_px; From d66c4bafcecbe2b72785260f67d66a125f5783a7 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 17 Aug 2016 07:27:41 +0800 Subject: [PATCH 12/32] code refine --- source/gui/widgets/button.cpp | 15 +++++-------- source/gui/widgets/float_listbox.cpp | 32 +++++++++++----------------- source/gui/widgets/listbox.cpp | 14 +++++------- source/gui/widgets/menubar.cpp | 8 ++----- 4 files changed, 25 insertions(+), 44 deletions(-) diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index f4a1ab3f..a12a9415 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -287,14 +287,6 @@ namespace nana{ namespace drawerbase graph.gradual_rectangle(r, from, to, true); } - void draw_corner_point(::nana::paint::graphics& graph, const rectangle& r) - { - graph.set_pixel(r.x, r.y); - graph.set_pixel(r.right() - 1, r.y); - graph.set_pixel(r.right() - 1, r.bottom() - 1); - graph.set_pixel(r.x, r.bottom() - 1); - } - void trigger::_m_draw_border(graph_reference graph) { nana::rectangle r(graph.size()); @@ -303,10 +295,13 @@ namespace nana{ namespace drawerbase graph.frame_rectangle(r, lt, lt, rb, rb); graph.palette(false, colors::button_face); - draw_corner_point(graph, r); + + paint::draw draw(graph); + draw.corner(r, 1); graph.palette(false, static_cast(0x919191)); - draw_corner_point(graph, r.pare_off(1)); + + draw.corner(r.pare_off(1), 1); if (element_state::pressed == attr_.e_state) graph.rectangle(r, false, static_cast(0xc3c3c3)); diff --git a/source/gui/widgets/float_listbox.cpp b/source/gui/widgets/float_listbox.cpp index d47098cb..8ad3c144 100644 --- a/source/gui/widgets/float_listbox.cpp +++ b/source/gui/widgets/float_listbox.cpp @@ -36,28 +36,20 @@ namespace nana { if (state == StateHighlighted) { - ::nana::color clr(static_cast(0xafc7e3)); - graph.rectangle(r, false, clr); + graph.rectangle(r, false, static_cast(0xafc7e3)); - auto right = r.right() - 1; - auto bottom = r.bottom() - 1; graph.palette(false, colors::white); - graph.set_pixel(r.x, r.y); - graph.set_pixel(right, r.y); - graph.set_pixel(r.x, bottom); - graph.set_pixel(right, bottom); - --right; - --bottom; - graph.palette(false, clr); - graph.set_pixel(r.x + 1, r.y + 1); - graph.set_pixel(right, r.y + 1); - graph.set_pixel(r.x + 1, bottom); - graph.set_pixel(right, bottom); + paint::draw draw{ graph }; + draw.corner(r, 1); - nana::rectangle po_r(r); - graph.rectangle(po_r.pare_off(1), false, static_cast(0xEBF4FB)); - graph.gradual_rectangle(po_r.pare_off(1), static_cast(0xDDECFD), static_cast(0xC2DCFD), true); + graph.palette(false, static_cast(0xafc7e3)); + + auto inner_r = r; + draw.corner(inner_r.pare_off(1), 1); + + graph.rectangle(inner_r, false, static_cast(0xEBF4FB)); + graph.gradual_rectangle(inner_r.pare_off(1), static_cast(0xDDECFD), static_cast(0xC2DCFD), true); } else graph.rectangle(r, true, colors::white); @@ -83,7 +75,9 @@ namespace nana unsigned item_pixels(graph_reference graph) const { - return graph.text_extent_size(L"jHWn/?\\{[(0569").height + 4; + unsigned ascent, descent, ileading; + graph.text_metrics(ascent, descent, ileading); + return ascent + descent + 4; } };//end class item_renderer diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 3ccb4fa0..0a3327a2 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3940,18 +3940,14 @@ namespace nana void _m_draw_border(int x, int y, unsigned width) const { //Draw selecting inner rectangle - auto graph = essence_->graph; + rectangle r{ x, y, width, essence_->scheme_ptr->item_height }; - graph->rectangle({ x, y, width, essence_->scheme_ptr->item_height }, false, static_cast(0x99defd)); - graph->rectangle({ x + 1, y + 1, width - 2, essence_->scheme_ptr->item_height - 2 }, false, colors::white); + essence_->graph->rectangle(r, false, static_cast(0x99defd)); - const int right = x + width - 1; - const int bottom = y + essence_->scheme_ptr->item_height - 1; + essence_->graph->palette(false, colors::white); + paint::draw(*essence_->graph).corner(r, 1); - graph->set_pixel(x, y); - graph->set_pixel(x, bottom); - graph->set_pixel(right, y); - graph->set_pixel(right, bottom); + essence_->graph->rectangle(r.pare_off(1), false); } private: essence * const essence_; diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 9d40d9ec..e810d053 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -112,13 +112,9 @@ namespace nana nana::rectangle r(pos, size); graph_.rectangle(r, false, border); - int right = pos.x + static_cast(size.width) - 1; - int bottom = pos.y + static_cast(size.height) - 1; graph_.palette(false, corner); - graph_.set_pixel(pos.x, pos.y); - graph_.set_pixel(right, pos.y); - graph_.set_pixel(pos.x, bottom); - graph_.set_pixel(right, bottom); + + paint::draw{ graph_ }.corner(r, 1); graph_.rectangle(r.pare_off(1), true, body); } From fbdd5224b29e56ad2a72a55624bc4737c8163b69 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 23 Aug 2016 08:01:04 +0800 Subject: [PATCH 13/32] fix a cast --- source/paint/graphics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 684a8ca2..aa606f4e 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -413,7 +413,7 @@ namespace paint nana::size graphics::text_extent_size(const std::wstring& text) const { - return text_extent_size(text.c_str(), text.length()); + return text_extent_size(text.c_str(), static_cast(text.length())); } nana::size graphics::text_extent_size(const wchar_t* str, std::size_t len) const From 1fd0da7d794ec0e728d34392c27298200ec98544 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 23 Aug 2016 08:02:08 +0800 Subject: [PATCH 14/32] fix drawing::erase --- source/gui/drawing.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/gui/drawing.cpp b/source/gui/drawing.cpp index 50626c76..2e6e2142 100644 --- a/source/gui/drawing.cpp +++ b/source/gui/drawing.cpp @@ -80,7 +80,9 @@ namespace nana void drawing::erase(diehard_t d) { - if(API::empty_window(handle_)) + //Fixed by Tumiz + //https://github.com/cnjinhao/nana/issues/153 + if(!API::empty_window(handle_)) restrict::get_drawer(handle_).erase(d); } From b13f0a4ce507069f4e2f486e7234d3764e9585f7 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 27 Aug 2016 05:23:25 +0800 Subject: [PATCH 15/32] fix textbox caret_pos issue --- include/nana/gui/widgets/skeletons/text_editor.hpp | 6 +++++- source/gui/widgets/skeletons/text_editor.cpp | 5 ++++- source/gui/widgets/textbox.cpp | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index d2a10a35..4ebee6ec 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -215,7 +215,11 @@ namespace nana{ namespace widgets std::wstring text() const; /// Sets caret position through text coordinate. - void move_caret(const upoint&); + /** + * @param pos the text position + * @param reset indicates whether to reset the text position by the pos. If this parameter is true, the text position is set by pos. If the parameter is false, it only moves the UI caret to the specified position. + */ + void move_caret(const upoint& pos, bool reset = false); void move_caret_end(); void reset_caret_pixels() const; void reset_caret(); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index e30248a8..b7a4cda0 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1840,8 +1840,11 @@ namespace nana{ namespace widgets //move_caret //Set caret position through text coordinate - void text_editor::move_caret(const upoint& crtpos) + void text_editor::move_caret(const upoint& crtpos, bool reset_caret) { + if (reset_caret) + points_.caret = crtpos; + if (!API::is_focus_ready(window_)) return; diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 12f42872..38d0d1c7 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -345,7 +345,7 @@ namespace drawerbase { auto editor = get_drawer_trigger().editor(); internal_scope_guard lock; if (editor) - editor->move_caret(pos); + editor->move_caret(pos, true); return *this; } From cf995519247e81a92f7c12c851dcdbe1aed8e118 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 27 Aug 2016 09:40:49 +0800 Subject: [PATCH 16/32] fix bug when an invalid pos for textbox.move_caret --- .../gui/widgets/skeletons/text_editor.hpp | 2 +- source/gui/widgets/skeletons/text_editor.cpp | 29 ++++++++++++++----- source/gui/widgets/textbox.cpp | 4 +-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 4ebee6ec..22e099e4 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -219,7 +219,7 @@ namespace nana{ namespace widgets * @param pos the text position * @param reset indicates whether to reset the text position by the pos. If this parameter is true, the text position is set by pos. If the parameter is false, it only moves the UI caret to the specified position. */ - void move_caret(const upoint& pos, bool reset = false); + bool move_caret(const upoint& pos, bool reset = false); void move_caret_end(); void reset_caret_pixels() const; void reset_caret(); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index b7a4cda0..a030471a 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -341,6 +341,9 @@ namespace nana{ namespace widgets text_ptr = &mask_str; } + if (pos.x > text_ptr->size()) + pos.x = text_ptr->size(); + pos.x = editor_._m_pixels_by_char(*text_ptr, pos.x) + editor_.text_area_.area.x; int pos_y = static_cast((pos.y - editor_.points_.offset.y) * editor_.line_height() + editor_._m_text_top_base()); @@ -1840,18 +1843,18 @@ namespace nana{ namespace widgets //move_caret //Set caret position through text coordinate - void text_editor::move_caret(const upoint& crtpos, bool reset_caret) - { - if (reset_caret) - points_.caret = crtpos; - - if (!API::is_focus_ready(window_)) - return; - + bool text_editor::move_caret(const upoint& crtpos, bool reset_caret) + { const unsigned line_pixels = line_height(); auto pos = this->behavior_->caret_to_screen(crtpos); const int line_bottom = pos.y + static_cast(line_pixels); + if (reset_caret) + points_.caret = this->behavior_->screen_to_caret(pos); + + if (!API::is_focus_ready(window_)) + return false; + bool visible = false; if (hit_text_area(pos) && (line_bottom > text_area_.area.y)) { @@ -1868,6 +1871,16 @@ namespace nana{ namespace widgets caret_->visible(visible); if(visible) caret_->position(pos); + + //Adjust the caret into screen when the caret position is modified by this function + if (reset_caret && (!hit_text_area(pos))) + { + behavior_->adjust_caret_into_screen(); + render(true); + caret_->visible(true); + return true; + } + return false; } void text_editor::move_caret_end() diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 38d0d1c7..76aed3ac 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -344,8 +344,8 @@ namespace drawerbase { { auto editor = get_drawer_trigger().editor(); internal_scope_guard lock; - if (editor) - editor->move_caret(pos, true); + if (editor && editor->move_caret(pos, true)) + API::refresh_window(handle()); return *this; } From 001eac9dbf8f19ec42376776275e6fd60a4d2b07 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 2 Sep 2016 01:06:33 +0800 Subject: [PATCH 17/32] fix a filebox error under Linux fixed by buckyeh --- source/gui/filebox.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index c18c7a83..ae57b0f7 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -498,24 +498,26 @@ namespace nana if(name.empty() || (name.front() == '.')) continue; + auto fpath = i->path().native(); + auto fattr = fs::status(fpath); + item_fs m; m.name = name; + m.directory = fs::is_directory(fattr); - auto fattr = fs::status(path + m.name); - - if(fattr.type() != fs::file_type::not_found && fattr.type() != fs::file_type::unknown) - { - m.bytes = fs::file_size(path + m.name); - m.directory = fs::is_directory(fattr); - fs_ext::modified_file_time(path + m.name, m.modified_time); - } - else + switch(fattr.type()) { + case fs::file_type::not_found: + case fs::file_type::unknown: + case fs::file_type::directory: m.bytes = 0; - m.directory = fs::is_directory(*i); - fs_ext::modified_file_time(path + i->path().filename().native(), m.modified_time); + break; + default: + m.bytes = fs::file_size(fpath); } + fs_ext::modified_file_time(fpath, m.modified_time); + file_container_.push_back(m); if(m.directory) From f400c14f9b48de7963648df22116973ec83dc82f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 2 Sep 2016 07:45:47 +0800 Subject: [PATCH 18/32] fix mouse_wheel issue on Linux --- source/gui/detail/bedrock_posix.cpp | 30 +++++++++++++++++---------- source/gui/detail/bedrock_windows.cpp | 5 ----- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index c959b01c..26de1dbc 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -626,30 +626,38 @@ namespace detail if(pressed_wd_space) break; + msgwnd = wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); + if(nullptr == msgwnd) + break; + if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5) { //The hovered window receives the message, unlike in Windows, no redirection is required. - nana::point mspos{xevent.xbutton.x, xevent.xbutton.y}; - while(msgwnd) + auto evt_wd = msgwnd; + while(evt_wd) { - if(msgwnd->annex.events_ptr->mouse_wheel.length() != 0) + if(evt_wd->annex.events_ptr->mouse_wheel.length() != 0) { - mspos -= msgwnd->pos_root; arg_wheel arg; arg.which = arg_wheel::wheel::vertical; - assign_arg(arg, msgwnd, xevent); - brock.emit(event_code::mouse_wheel, msgwnd, arg, true, &context); + assign_arg(arg, evt_wd, xevent); + brock.emit(event_code::mouse_wheel, evt_wd, arg, true, &context); break; } - msgwnd = msgwnd->parent; + evt_wd = evt_wd->parent; + } + + if(msgwnd && (nullptr == evt_wd)) + { + arg_wheel arg; + arg.which = arg_wheel::wheel::vertical; + assign_arg(arg, msgwnd, xevent); + draw_invoker(&drawer::mouse_wheel, msgwnd, arg, &context); + wd_manager.do_lazy_refresh(msgwnd, false); } } else { - msgwnd = wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); - if(nullptr == msgwnd) - break; - msgwnd->set_action(mouse_action::normal); if(msgwnd->flags.enabled) { diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index d6019428..300866f0 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -1124,8 +1124,6 @@ namespace detail if (evt_wd->annex.events_ptr->mouse_wheel.length() != 0) { def_window_proc = false; - nana::point mspos{ scr_pos.x, scr_pos.y }; - wd_manager.calc_window_point(evt_wd, mspos); arg_wheel arg; arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical); @@ -1138,9 +1136,6 @@ namespace detail if (scrolled_wd && (nullptr == evt_wd)) { - nana::point mspos{ scr_pos.x, scr_pos.y }; - wd_manager.calc_window_point(scrolled_wd, mspos); - arg_wheel arg; arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical); assign_arg(arg, scrolled_wd, pmdec); From 6eece91fce7b46984ee62764c643631e8eea28b8 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 2 Sep 2016 07:49:55 +0800 Subject: [PATCH 19/32] fix a crash that deleting a widget in its event handler --- source/gui/detail/window_manager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 2fedf0d7..6611306e 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1535,6 +1535,11 @@ namespace detail wd->annex.caret_ptr = nullptr; } + using effect_renderer = detail::edge_nimbus_renderer; + + //remove the window from edge nimbus effect when it is destroying + effect_renderer::instance().erase(wd); + arg_destroy arg; arg.window_handle = reinterpret_cast(wd); brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); From d6cb631bc2d200c62bf2a15dc5c43e9c98883362 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 3 Sep 2016 07:46:43 +0800 Subject: [PATCH 20/32] add a method to show caret for the uneditable textbox When an uneditable textbox has a caret, user can select the text and copy it. --- .../gui/widgets/skeletons/text_editor.hpp | 9 +++++- include/nana/gui/widgets/textbox.hpp | 3 ++ source/gui/widgets/combox.cpp | 2 +- source/gui/widgets/skeletons/text_editor.cpp | 30 +++++++++++-------- source/gui/widgets/spinbox.cpp | 2 +- source/gui/widgets/textbox.cpp | 11 ++++++- 6 files changed, 41 insertions(+), 16 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index eb246388..ea021411 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -118,7 +118,13 @@ namespace nana{ namespace widgets const attributes & attr() const; bool multi_lines(bool); - void editable(bool); + + /// Enables/disables the editability of text_editor + /** + * @param enable Indicates whether to enable or disable the editability + * @param enable_cart Indicates whether to show or hide the caret when the text_editor is not editable. It is ignored if enable is false. + */ + void editable(bool enable, bool enable_caret); void enable_background(bool); void enable_background_counterpart(bool); @@ -255,6 +261,7 @@ namespace nana{ namespace widgets bool line_wrapped{false}; bool multi_lines{true}; bool editable{true}; + bool enable_caret{ true }; ///< Indicates whether to show or hide caret when text_editor is not editable bool enable_background{true}; }attributes_; diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 12008c37..14b5a9d8 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -184,6 +184,9 @@ namespace nana bool editable() const; textbox& editable(bool); + /// Enables the caret if the textbox current is not editable + textbox& enable_caret(); + void set_accept(std::function); textbox& tip_string(::std::string); diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index 1ea6d1e9..4ec63f52 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -170,7 +170,7 @@ namespace nana { if(editor_) { - editor_->editable(enb); + editor_->editable(enb, false); editor_->show_caret(enb); if (!enb) { diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 01cac45c..a662aadf 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1507,6 +1507,9 @@ namespace nana{ namespace widgets bool text_editor::respond_char(const arg_keyboard& arg) //key is a character of ASCII code { + if (!API::window_enabled(window_)) + return false; + char_type key = arg.key; switch (key) { @@ -1518,7 +1521,7 @@ namespace nana{ namespace widgets return true; } - if (attributes_.editable && API::window_enabled(window_) && (!impl_->capacities.pred_acceptive || impl_->capacities.pred_acceptive(key))) + if (attributes_.editable && (!impl_->capacities.pred_acceptive || impl_->capacities.pred_acceptive(key))) { switch (key) { @@ -1700,9 +1703,10 @@ namespace nana{ namespace widgets return true; } - void text_editor::editable(bool v) + void text_editor::editable(bool enable, bool enable_caret) { - attributes_.editable = v; + attributes_.editable = enable; + attributes_.enable_caret = (enable || enable_caret); } void text_editor::enable_background(bool enb) @@ -1815,12 +1819,12 @@ namespace nana{ namespace widgets bool text_editor::mouse_move(bool left_button, const point& scrpos) { cursor cur = cursor::iterm; - if(((!hit_text_area(scrpos)) && (!text_area_.captured)) || !attributes_.editable || !API::window_enabled(window_)) + if(((!hit_text_area(scrpos)) && (!text_area_.captured)) || !attributes_.enable_caret || !API::window_enabled(window_)) cur = cursor::arrow; API::window_cursor(window_, cur); - if(!attributes_.editable) + if(!attributes_.enable_caret) return false; if(left_button) @@ -1838,7 +1842,7 @@ namespace nana{ namespace widgets bool text_editor::mouse_pressed(const arg_mouse& arg) { - if(!attributes_.editable) + if(!attributes_.enable_caret) return false; if (event_code::mouse_down == arg.evt_code) @@ -1857,7 +1861,9 @@ namespace nana{ namespace widgets if (this->hit_select_area(impl_->capacities.behavior->screen_to_caret(arg.pos), true)) { - select_.mode_selection = selection::mode::move_selected; + //The selected of text can be moved only if it is editable + if (attributes_.editable) + select_.mode_selection = selection::mode::move_selected; } else { @@ -2007,7 +2013,7 @@ namespace nana{ namespace widgets reset_caret_pixels(); } - if(!attributes_.editable) + if(!attributes_.enable_caret) visible = false; caret->visible(visible); @@ -2103,9 +2109,6 @@ namespace nana{ namespace widgets bool text_editor::move_select() { - if (! attributes_.editable) - return false; - if(hit_select_area(points_.caret, true) || (select_.b == points_.caret)) { points_.caret = select_.b; @@ -3206,6 +3209,9 @@ namespace nana{ namespace widgets bool text_editor::_m_move_select(bool record_undo) { + if (!attributes_.editable) + return false; + nana::upoint caret = points_.caret; const auto text = _m_make_select_string(); if (!text.empty()) @@ -3457,7 +3463,7 @@ namespace nana{ namespace widgets const bool text_selected = (sbegin == text_ptr->c_str() && send == text_ptr->c_str() + text_ptr->size()); //The text is not selected or the whole line text is selected - if (!focused || (!sbegin || !send) || text_selected || !attributes_.editable) + if (!focused || (!sbegin || !send) || text_selected || !attributes_.enable_caret) { for (auto & ent : reordered) { diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index 961ddefa..9f63baa2 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -607,7 +607,7 @@ namespace nana internal_scope_guard lock; auto editor = get_drawer_trigger().impl()->editor(); if (editor) - editor->editable(accept); + editor->editable(accept, false); } bool spinbox::editable() const diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 8c33f6e2..a2c07ef4 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -415,7 +415,16 @@ namespace drawerbase { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); if(editor) - editor->editable(able); + editor->editable(able, false); + return *this; + } + + textbox& textbox::enable_caret() + { + internal_scope_guard lock; + auto editor = get_drawer_trigger().editor(); + if (editor) + editor->editable(editor->attr().editable, true); return *this; } From 422f2c768b3bee9f03651cfd5bdb08dab3e44294 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 12 Sep 2016 00:01:12 +0800 Subject: [PATCH 21/32] add a method to textbox a method to get bounds of a text selection --- .../gui/widgets/skeletons/text_editor.hpp | 3 +- include/nana/gui/widgets/textbox.hpp | 8 ++- source/gui/widgets/skeletons/text_editor.cpp | 50 +++++++++---------- source/gui/widgets/textbox.cpp | 12 +++++ 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index ea021411..f5408008 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -151,6 +151,8 @@ namespace nana{ namespace widgets bool selected() const; bool select(bool); + bool get_select_points(nana::upoint&, nana::upoint&) const; + /// Sets the end position of a selected string. void set_end_caret(); @@ -233,7 +235,6 @@ namespace nana{ namespace widgets //@brief: redraw whole line specified by caret pos. //@return: true if caret overs the border bool _m_update_caret_line(std::size_t secondary_before); - bool _m_get_sort_select_points(nana::upoint&, nana::upoint&) const; void _m_offset_y(int y); diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 14b5a9d8..b757260d 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -184,7 +184,7 @@ namespace nana bool editable() const; textbox& editable(bool); - /// Enables the caret if the textbox current is not editable + /// Enables the caret if the textbox currently is not editable textbox& enable_caret(); void set_accept(std::function); @@ -200,6 +200,12 @@ namespace nana /// Selects/unselects all text. void select(bool); + /// Returns the bounds of a text selection + /** + * @return no selection if pair.first == pair.second. + */ + std::pair selection() const; + void copy() const; ///< Copies the selected text into shared memory, such as clipboard under Windows. void paste(); ///< Pastes the text from shared memory. void del(); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index a662aadf..42d98873 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -2081,6 +2081,25 @@ namespace nana{ namespace widgets return false; } + bool text_editor::get_select_points(nana::upoint& a, nana::upoint& b) const + { + if (select_.a == select_.b) + return false; + + if (select_.a < select_.b) + { + a = select_.a; + b = select_.b; + } + else + { + a = select_.b; + b = select_.a; + } + + return true; + } + bool text_editor::hit_text_area(const point& pos) const { return _m_text_area().is_hit(pos); @@ -2089,7 +2108,7 @@ namespace nana{ namespace widgets bool text_editor::hit_select_area(nana::upoint pos, bool ignore_when_select_all) const { nana::upoint a, b; - if(_m_get_sort_select_points(a, b)) + if(get_select_points(a, b)) { if (ignore_when_select_all) { @@ -3006,7 +3025,7 @@ namespace nana{ namespace widgets nana::upoint text_editor::_m_erase_select() { nana::upoint a, b; - if (_m_get_sort_select_points(a, b)) + if (get_select_points(a, b)) { auto & textbase = this->textbase(); if(a.y != b.y) @@ -3037,7 +3056,7 @@ namespace nana{ namespace widgets std::wstring text; nana::upoint a, b; - if (_m_get_sort_select_points(a, b)) + if (get_select_points(a, b)) { auto & textbase = this->textbase(); if (a.y != b.y) @@ -3128,7 +3147,7 @@ namespace nana{ namespace widgets bool text_editor::_m_cancel_select(int align) { nana::upoint a, b; - if(_m_get_sort_select_points(a, b)) + if (get_select_points(a, b)) { switch(align) { @@ -3223,7 +3242,7 @@ namespace nana{ namespace widgets const bool at_left = (select_.b < select_.a); nana::upoint a, b; - _m_get_sort_select_points(a, b); + get_select_points(a, b); if (caret.y < a.y || (caret.y == a.y && caret.x < a.x)) {//forward undo_ptr->set_caret_pos(); @@ -3419,7 +3438,7 @@ namespace nana{ namespace widgets const wchar_t *sbegin = nullptr, *send = nullptr; nana::upoint a, b; - if (_m_get_sort_select_points(a, b)) + if (get_select_points(a, b)) { if (a.y < text_coord.y && text_coord.y < b.y) { @@ -3576,25 +3595,6 @@ namespace nana{ namespace widgets return true; } - bool text_editor::_m_get_sort_select_points(nana::upoint& a, nana::upoint& b) const - { - if (select_.a == select_.b) - return false; - - if (select_.a < select_.b) - { - a = select_.a; - b = select_.b; - } - else - { - a = select_.b; - b = select_.a; - } - - return true; - } - void text_editor::_m_offset_y(int y) { points_.offset.y = y; diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index a2c07ef4..3e20f7ec 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -469,6 +469,18 @@ namespace drawerbase { API::update_window(*this); } + std::pair textbox::selection() const + { + std::pair points; + + internal_scope_guard lock; + auto editor = get_drawer_trigger().editor(); + if (editor) + editor->get_select_points(points.first, points.second); + + return points; + } + void textbox::copy() const { internal_scope_guard lock; From 318f0ec57046c4728c345e08b0a4953d401b0bb5 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 13 Sep 2016 01:24:47 +0800 Subject: [PATCH 22/32] fix issue that event handler remains after closing --- include/nana/gui/widgets/widget.hpp | 25 +++++++++++++++++++++++-- source/gui/detail/basic_window.cpp | 2 -- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index 5e1ad652..992a780f 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -150,8 +150,8 @@ namespace nana ~widget_base(); window handle() const override; - private: - void _m_notify_destroy() override final; + protected: + void _m_notify_destroy() override; protected: window handle_{ nullptr }; }; @@ -228,6 +228,13 @@ namespace nana { return *events_; } + + void _m_notify_destroy() override final + { + widget_base::_m_notify_destroy(); + events_ = std::make_shared(); + API::dev::set_events(handle_, events_); + } private: DrawerTrigger trigger_; std::shared_ptr events_; @@ -281,6 +288,13 @@ namespace nana { return *events_; } + + void _m_notify_destroy() override final + { + widget_base::_m_notify_destroy(); + events_ = std::make_shared(); + API::dev::set_events(handle_, events_); + } private: std::shared_ptr events_; std::unique_ptr scheme_; @@ -415,6 +429,13 @@ namespace nana { return *events_; } + + void _m_notify_destroy() override final + { + widget_base::_m_notify_destroy(); + events_ = std::make_shared(); + API::dev::set_events(handle_, events_); + } private: DrawerTrigger trigger_; std::shared_ptr events_; diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 525f5e57..715f7158 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -442,8 +442,6 @@ namespace nana bool basic_window::set_events(const std::shared_ptr& p) { - if (annex.events_ptr) - return false; annex.events_ptr = p; return true; } From cff816f10bf004f91534f39655d8be42fe0ab518 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 14 Sep 2016 05:51:23 +0800 Subject: [PATCH 23/32] fix listbox multi-selection exception(#154) --- source/gui/widgets/listbox.cpp | 58 +++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 91cf6d4e..5bc8fc5b 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1490,10 +1490,15 @@ namespace nana void select_display_range(index_pair fr_abs, index_pair to_dpl, bool sel) { + const auto already_selected = this->pick_items(true); + index_pair fr_dpl (fr_abs.cat, this->display_order(fr_abs.cat, fr_abs.item)); if (fr_dpl > to_dpl) std::swap(fr_dpl, to_dpl); + const auto begin = fr_dpl; + const auto last = to_dpl; + for (; fr_dpl != to_dpl; forward(fr_dpl, 1, fr_dpl)) { if (fr_dpl.is_item()) @@ -1502,6 +1507,14 @@ namespace nana if (to_dpl.is_item()) item_proxy(ess_, index_pair(to_dpl.cat, absolute( to_dpl ) )).select(sel); + + //Unselects the already selected which is out of range [begin, last] + for (auto index : already_selected) + { + index_pair disp_order{ index.cat, this->display_order(index.cat, index.item) }; + if (begin > disp_order || disp_order > last) + item_proxy(ess_, index_pair(index.cat, absolute(disp_order))).select(false); + } } bool select_for_all(bool sel) @@ -2060,7 +2073,7 @@ namespace nana return i; } public: - index_pair last_selected_abs, last_selected_dpl; + index_pair last_selected_abs; private: essence * ess_{nullptr}; nana::listbox * widget_{nullptr}; @@ -3126,7 +3139,7 @@ namespace nana void es_lister::move_select(bool upwards, bool unselect_previous, bool trace_selected) { - auto next_selected_dpl = relative_pair ( last_selected_abs); // last_selected_dpl; // ?? + auto next_selected_dpl = relative_pair ( last_selected_abs); if (next_selected_dpl.empty()) // has no cat ? (cat == npos) => beging from first cat { bool good = false; @@ -3247,7 +3260,7 @@ namespace nana if (it.selected() != sel) it.select(sel); } - last_selected_abs = last_selected_dpl = index_pair{cat, npos}; + last_selected_abs = index_pair{cat, npos}; } class drawer_header_impl @@ -4165,7 +4178,18 @@ namespace nana if (!lister.single_selection()) { if (arg.shift) - lister.select_display_range(lister.last_selected_abs , item_pos, sel); + { + //Set the first item as the begin of selected item if there + //is not a last selected item.(#154 reported by RenaudAlpes) + if (lister.last_selected_abs.empty() || lister.last_selected_abs.is_category()) + lister.last_selected_abs.set_both(0); + + auto before = lister.last_selected_abs; + + lister.select_display_range(lister.last_selected_abs, item_pos, sel); + + lister.last_selected_abs = before; + } else if (arg.ctrl) sel = !item_proxy(essence_, abs_item_pos).selected(); else @@ -4181,19 +4205,22 @@ namespace nana if(item_ptr) { - item_ptr->flags.selected = sel; - - arg_listbox arg{ item_proxy{ essence_, abs_item_pos } }; - lister.wd_ptr()->events().selected.emit(arg, lister.wd_ptr()->handle()); - - if (item_ptr->flags.selected) + if (item_ptr->flags.selected != sel) { - lister.cancel_others_if_single_enabled(true, abs_item_pos); - essence_->lister.last_selected_abs = abs_item_pos; + item_ptr->flags.selected = sel; + arg_listbox arg{ item_proxy{ essence_, abs_item_pos } }; + lister.wd_ptr()->events().selected.emit(arg, lister.wd_ptr()->handle()); + + if (item_ptr->flags.selected) + { + lister.cancel_others_if_single_enabled(true, abs_item_pos); + essence_->lister.last_selected_abs = abs_item_pos; + + } + else if (essence_->lister.last_selected_abs == abs_item_pos) + essence_->lister.last_selected_abs.set_both(npos); } - else if (essence_->lister.last_selected_abs == abs_item_pos) - essence_->lister.last_selected_abs.set_both(npos); } else if(!lister.single_selection()) lister.categ_selected(item_pos.cat, true); @@ -4772,10 +4799,11 @@ namespace nana for (item_proxy &it : *this ) it.select(sel); - ess_->lister.last_selected_abs = ess_->lister.last_selected_dpl = index_pair {this->pos_, npos}; + ess_->lister.last_selected_abs = index_pair {this->pos_, npos}; return *this; } + bool cat_proxy::selected() const { for (item_proxy &it : *this ) From 07229e566db03cc640a303b432243e7b13ca6435 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 15 Sep 2016 16:35:43 +0800 Subject: [PATCH 24/32] simplify implementation of listbox inline widget --- source/gui/widgets/listbox.cpp | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 5bc8fc5b..90fdcbdf 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2139,7 +2139,6 @@ namespace nana inline_indicator * indicator; index_pair item_pos; //The item index of the inline widget std::size_t column_pos; - ::std::string text; //text in UTF-8 encoded }; std::map>> inline_table, inline_buffered_table; @@ -2986,7 +2985,7 @@ namespace nana : ess_{ ess }, column_pos_{column_pos} { } - + void attach(index_type pos, essence::inline_pane* pane) { for (auto & pn : panes_) @@ -3023,15 +3022,6 @@ namespace nana if (cells[column_pos_].text != value) { - for (auto & pn : panes_) - { - if (pn.first == pos) - { - pn.second->text = value; - break; - } - } - cells[column_pos_].text = value; if (model_cells.size()) @@ -3862,19 +3852,9 @@ namespace nana //To reduce the memory usage, the cells may not be allocated if (cells.size() > column_pos) - { - auto & text = cells[column_pos].text; - if (text != inline_wdg->text) - { - inline_wdg->text = text; - inline_wdg->inline_ptr->set(text); - } - } + inline_wdg->inline_ptr->set(cells[column_pos].text); else - { - inline_wdg->text.clear(); inline_wdg->inline_ptr->set({}); - } API::show_window(inline_wdg->pane_bottom, visible_state); } @@ -3932,7 +3912,9 @@ namespace nana { auto & factory = cat.factories[column_pos]; if (factory) + { return essence_->open_inline(factory.get(), cat.indicators[column_pos].get()); + } } return nullptr; } From d9fb3b3ff9265a3df3b4b1e3cf2536998c0db280 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 17 Sep 2016 03:56:23 +0800 Subject: [PATCH 25/32] add notify_status for listbox inline widget --- .../nana/gui/widgets/detail/inline_widget.hpp | 13 +- include/nana/gui/widgets/listbox.hpp | 8 +- source/gui/widgets/listbox.cpp | 143 ++++++++++++------ 3 files changed, 114 insertions(+), 50 deletions(-) diff --git a/include/nana/gui/widgets/detail/inline_widget.hpp b/include/nana/gui/widgets/detail/inline_widget.hpp index 6b40c7e3..875c2945 100644 --- a/include/nana/gui/widgets/detail/inline_widget.hpp +++ b/include/nana/gui/widgets/detail/inline_widget.hpp @@ -1,7 +1,7 @@ /** * A Inline Widget Interface Definition * 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 @@ -35,6 +35,9 @@ namespace nana /// Returns the host widget of the indicator virtual ::nana::widget& host() const = 0; + /// Returns the position of column + virtual std::size_t column() const = 0; + /// Modifies the value of a item specified by pos virtual void modify(index_type pos, const value_type&) const = 0; @@ -45,7 +48,7 @@ namespace nana virtual void hovered(index_type) = 0; }; - template + template class inline_widget_notifier_interface { public: @@ -55,6 +58,9 @@ namespace nana /// A type to the value of the item using value_type = Value; + /// A type to the status + using status_type = Status; + /// A typedef name of a inline widget indicator using inline_indicator = inline_widget_indicator; @@ -70,6 +76,9 @@ namespace nana /// A message to activate the inline widget to attach a specified item virtual void activate(inline_indicator&, index_type) = 0; + /// A message to change the status + virtual void notify_status(status_type, bool) = 0; + /// A message to resize the inline widget virtual void resize(const size&) = 0; diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index e4b06724..4e414760 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -676,8 +676,14 @@ namespace nana using index_pairs = ::std::vector; - using inline_notifier_interface = detail::inline_widget_notifier_interface; + enum class inline_widget_status{ + checked, + checking, + selected, + selecting + }; + using inline_notifier_interface = detail::inline_widget_notifier_interface; // struct essence //@brief: this struct gives many data for listbox, diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 90fdcbdf..98dd3732 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -678,6 +678,16 @@ namespace nana } }; + struct inline_pane + { + ::nana::panel pane_bottom; //pane for pane_widget + ::nana::panel pane_widget; //pane for placing user-define widget + std::unique_ptr inline_ptr; + inline_indicator * indicator; + index_pair item_pos; //The item index of the inline widget + std::size_t column_pos; + }; + class es_lister { public: @@ -726,6 +736,37 @@ namespace nana std::string to_string(const export_options& exp_opt) const; + inline_pane * get_inline_pane(const index_pair& item_pos) + { + for (auto p : active_panes_) + { + if (p && (p->item_pos == item_pos)) + return p; + } + return nullptr; + } + + void emit_checked(index_pair pos) + { + item_proxy i(ess_, pos); + arg_listbox arg{ i }; + wd_ptr()->events().checked.emit(arg, wd_ptr()->handle()); + + auto pane = get_inline_pane(pos); + if (pane) + pane->inline_ptr->notify_status(inline_widget_status::checking, i.checked()); + } + + void emit_selected(index_pair pos) + { + item_proxy i(ess_, pos); + arg_listbox arg{ i }; + wd_ptr()->events().selected.emit(arg, wd_ptr()->handle()); + + auto pane = get_inline_pane(pos); + if (pane) + pane->inline_ptr->notify_status(inline_widget_status::selecting, i.selected()); + } // Definition is provided after struct essence unsigned column_content_pixels(size_type pos) const; @@ -1121,6 +1162,14 @@ namespace nana return get(pos.cat)->items.at(index); } + void append_active_panes(inline_pane* p) + { + if (nullptr == p) + active_panes_.clear(); + else + active_panes_.push_back(p); + } + // Removes all items of a specified category // It throws when the category is out of range or has an immutable model. void clear(size_type cat) @@ -1463,9 +1512,7 @@ namespace nana if(m.flags.checked != ck) { m.flags.checked = ck; - - arg_listbox arg{ item_proxy{ess_, pos}}; - wd_ptr()->events().checked.emit(arg, wd_ptr()->handle()); + emit_checked(pos); } ++pos.item; } @@ -1531,8 +1578,7 @@ namespace nana changed = true; m.flags.selected = sel; - arg_listbox arg{ item_proxy(ess_, i) }; - wd_ptr()->events().selected.emit(arg, wd_ptr()->handle()); + this->emit_selected(i); if (m.flags.selected) last_selected_abs = i; @@ -1622,18 +1668,17 @@ namespace nana return (for_selection ? m.flags.selected : m.flags.checked); }; - auto do_cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos) + auto do_cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos) { - arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) }; if (for_selection) { m.flags.selected = false; - widget_->events().selected.emit(arg, widget_->handle()); + this->emit_selected(item_pos); } else { m.flags.checked = false; - widget_->events().checked.emit(arg, widget_->handle()); + this->emit_checked(item_pos); } }; @@ -1645,7 +1690,7 @@ namespace nana for (auto & m : i->items) { if ((item_pos != except.item) && pred(m)) - do_cancel(m, except.cat, item_pos); + do_cancel(m, index_pair{ except.cat, item_pos }); ++item_pos; } @@ -1661,7 +1706,7 @@ namespace nana for (auto & m : cat.items) { if (pred(m)) - do_cancel(m, cat_pos, item_pos); + do_cancel(m, index_pair{ cat_pos, item_pos }); ++item_pos; } } @@ -1671,7 +1716,7 @@ namespace nana for (auto & m : cat.items) { if ((item_pos != except.item) && pred(m)) - do_cancel(m, cat_pos, item_pos); + do_cancel(m, index_pair{ cat_pos, item_pos }); ++item_pos; } } @@ -1705,18 +1750,17 @@ namespace nana return (for_selection ? m.flags.selected : m.flags.checked); }; - auto cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos) + auto cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos) { - arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) }; if (for_selection) { m.flags.selected = false; - widget_->events().selected.emit(arg, widget_->handle()); + this->emit_selected(item_pos); } else { m.flags.checked = false; - widget_->events().checked.emit(arg, widget_->handle()); + this->emit_checked(item_pos); } }; @@ -1732,7 +1776,7 @@ namespace nana for (auto end = cat.items.end(); i != end; ++i) { if (pred(*i)) - cancel(*i, cat_pos, i - cat.items.begin()); + cancel(*i, index_pair{ cat_pos, static_cast(i - cat.items.begin()) }); } } ++cat_pos; @@ -1755,7 +1799,7 @@ namespace nana for (++i; i != end; ++i) { if (pred(*i)) - cancel(*i, cat_pos, i - cat.items.begin()); + cancel(*i, index_pair{ cat_pos, static_cast(i - cat.items.begin()) }); } } } @@ -1767,7 +1811,7 @@ namespace nana for (auto & m : cat.items) { if (pred(m)) - cancel(m, cat_pos, item_pos); + cancel(m, index_pair{ cat_pos, item_pos }); ++item_pos; } @@ -1814,10 +1858,7 @@ namespace nana if(m.flags.checked != ck) { m.flags.checked = ck; - - arg_listbox arg{ item_proxy(ess_, index_pair(cat, index)) }; - wd_ptr()->events().checked.emit(arg, widget_->handle()); - + this->emit_checked(index_pair{cat, index}); changed = true; } ++index; @@ -2088,6 +2129,8 @@ namespace nana bool single_selection_category_limited_{ false }; bool single_check_{ false }; bool single_check_category_limited_{ false }; + + std::vector active_panes_; };//end class es_lister @@ -2097,6 +2140,8 @@ namespace nana enum class item_state{normal, highlighted, pressed, grabbed, floated}; enum class parts{unknown = -1, header, lister, checker}; + using inline_pane = inline_pane; + ::nana::listbox* listbox_ptr{nullptr}; ::nana::listbox::scheme_type* scheme_ptr{nullptr}; ::nana::paint::graphics *graph{nullptr}; @@ -2131,16 +2176,6 @@ namespace nana }scroll; - struct inline_pane - { - ::nana::panel pane_bottom; //pane for pane_widget - ::nana::panel pane_widget; //pane for placing user-define widget - std::unique_ptr inline_ptr; - inline_indicator * indicator; - index_pair item_pos; //The item index of the inline widget - std::size_t column_pos; - }; - std::map>> inline_table, inline_buffered_table; essence() @@ -3010,6 +3045,11 @@ namespace nana return *ess_->lister.wd_ptr(); } + std::size_t column() const override + { + return column_pos_; + } + void modify(index_type pos, const value_type& value) const override { ess_->lister.throw_if_immutable_model(pos); @@ -3533,15 +3573,19 @@ namespace nana public: using item_state = essence::item_state; using parts = essence::parts; + using status_type = inline_notifier_interface::status_type; drawer_lister_impl(essence * es) :essence_(es) {} - void draw(const nana::rectangle& rect) const + void draw(const nana::rectangle& rect) { internal_scope_guard lock; + //clear active panes + essence_->lister.append_active_panes(nullptr); + //The count of items to be drawn auto item_count = essence_->number_of_lister_items(true); if (0 == item_count) @@ -3724,7 +3768,7 @@ namespace nana nana::color bgcolor, nana::color fgcolor, item_state state - ) const + ) { auto & item = cat.items[item_pos.item]; @@ -3838,15 +3882,19 @@ namespace nana else visible_state = false; - ::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height }; - inline_wdg->pane_widget.size(sz); - inline_wdg->inline_ptr->resize(sz); draw_column = inline_wdg->inline_ptr->whether_to_draw(); inline_wdg->item_pos = item_pos; inline_wdg->column_pos = column_pos; inline_wdg->inline_ptr->activate(*inline_wdg->indicator, item_pos); + + ::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height }; + inline_wdg->pane_widget.size(sz); + inline_wdg->inline_ptr->resize(sz); + + inline_wdg->inline_ptr->notify_status(status_type::selected, item.flags.selected); + inline_wdg->inline_ptr->notify_status(status_type::checked, item.flags.checked); inline_wdg->indicator->attach(item_pos, inline_wdg); @@ -3857,6 +3905,8 @@ namespace nana inline_wdg->inline_ptr->set({}); API::show_window(inline_wdg->pane_bottom, visible_state); + + essence_->lister.append_active_panes(inline_wdg); } } @@ -4191,14 +4241,12 @@ namespace nana { item_ptr->flags.selected = sel; - arg_listbox arg{ item_proxy{ essence_, abs_item_pos } }; - lister.wd_ptr()->events().selected.emit(arg, lister.wd_ptr()->handle()); + lister.emit_selected(abs_item_pos); if (item_ptr->flags.selected) { lister.cancel_others_if_single_enabled(true, abs_item_pos); essence_->lister.last_selected_abs = abs_item_pos; - } else if (essence_->lister.last_selected_abs == abs_item_pos) essence_->lister.last_selected_abs.set_both(npos); @@ -4213,8 +4261,7 @@ namespace nana { item_ptr->flags.checked = ! item_ptr->flags.checked; - arg_listbox arg{ item_proxy{ essence_, abs_item_pos } }; - lister.wd_ptr()->events().checked.emit(arg, lister.wd_ptr()->handle()); + lister.emit_checked(abs_item_pos); if (item_ptr->flags.checked) lister.cancel_others_if_single_enabled(false, abs_item_pos); @@ -4479,12 +4526,13 @@ namespace nana item_proxy & item_proxy::check(bool ck) { + internal_scope_guard lock; auto & m = cat_->items.at(pos_.item); if(m.flags.checked != ck) { m.flags.checked = ck; - arg_listbox arg{*this}; - ess_->lister.wd_ptr()->events().checked.emit(arg, ess_->lister.wd_ptr()->handle()); + ess_->lister.emit_checked(pos_); + ess_->update(); } return *this; @@ -4498,13 +4546,14 @@ namespace nana /// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected item_proxy & item_proxy::select(bool s) { + internal_scope_guard lock; + //pos_ never represents a category if this item_proxy is available. auto & m = cat_->items.at(pos_.item); // a ref to the real item if(m.flags.selected == s) return *this; // ignore if no change m.flags.selected = s; // actually change selection - arg_listbox arg{*this}; - ess_->lister.wd_ptr()->events().selected.emit(arg, ess_->lister.wd_ptr()->handle()); + ess_->lister.emit_selected(this->pos_); if (m.flags.selected) { From 7ff4762cdbc39a976a753034bb2ea9cc424e3b3c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 21 Sep 2016 07:08:30 +0800 Subject: [PATCH 26/32] add variadic parameters for make_factory --- include/nana/pat/abstract_factory.hpp | 64 ++++++++++++++++++++++++--- include/nana/pat/cloneable.hpp | 6 +-- source/gui/widgets/listbox.cpp | 10 ++--- 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/include/nana/pat/abstract_factory.hpp b/include/nana/pat/abstract_factory.hpp index 9a4b3bfe..8aa44e7f 100644 --- a/include/nana/pat/abstract_factory.hpp +++ b/include/nana/pat/abstract_factory.hpp @@ -15,6 +15,8 @@ #define NANA_PAT_ABSFACTORY_HPP #include "cloneable.hpp" #include +#include +#include namespace nana { @@ -43,21 +45,73 @@ namespace nana namespace detail { - template + template + struct pack{ + using type = pack; + }; + + template + struct make_pack_helper + { // explodes gracefully below 0 + static_assert(!Negative, + "make_integer_sequence requires N to be non-negative."); + }; + + template + struct make_pack_helper, + pack > + : pack + { // ends recursion at 0 + }; + + template + struct make_pack_helper, + pack > + : make_pack_helper, + pack > + { // counts down to 0 + }; + + template + using make_pack = typename make_pack_helper, pack >::type; + + template class abs_factory : public abstract_factory { std::unique_ptr create() override { - return std::unique_ptr{ new T }; + constexpr auto Size = std::tuple_size::value; + return std::unique_ptr{ _m_new(typename make_pack{}) }; } + + template + Interface* _m_new(const pack &) + { + return new T(std::get(args_)...); + } + public: + abs_factory(Args&&... args) + : args_(std::forward(args)...) + { + } + + abs_factory(const Args&... args) + : args_(args...) + { + } + private: + std::tuple args_; }; }//end namespace detail - template - pat::cloneable> make_factory() + template + pat::cloneable> make_factory(Args &&... args) { - return detail::abs_factory(); + return detail::abs_factory::type...>(std::forward(args)...); } }//end namespace pat }//end namespace nana diff --git a/include/nana/pat/cloneable.hpp b/include/nana/pat/cloneable.hpp index c6f5d1c9..350dbe1a 100644 --- a/include/nana/pat/cloneable.hpp +++ b/include/nana/pat/cloneable.hpp @@ -1,7 +1,7 @@ /* * A Generic Cloneable Pattern 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 @@ -106,8 +106,8 @@ namespace nana{ namespace pat{ template::type* = nullptr> cloneable(T&& t) - : cwrapper_(new detail::cloneable_wrapper::type>::type>(std::forward(t)), detail::cloneable_interface_deleter()), - fast_ptr_(reinterpret_cast::type>::type*>(cwrapper_->get())) + : cwrapper_(new detail::cloneable_wrapper::type>(std::forward(t)), detail::cloneable_interface_deleter()), + fast_ptr_(reinterpret_cast::type*>(cwrapper_->get())) {} cloneable(const cloneable& r) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 98dd3732..1dcb7f9d 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2140,8 +2140,6 @@ namespace nana enum class item_state{normal, highlighted, pressed, grabbed, floated}; enum class parts{unknown = -1, header, lister, checker}; - using inline_pane = inline_pane; - ::nana::listbox* listbox_ptr{nullptr}; ::nana::listbox::scheme_type* scheme_ptr{nullptr}; ::nana::paint::graphics *graph{nullptr}; @@ -3021,7 +3019,7 @@ namespace nana { } - void attach(index_type pos, essence::inline_pane* pane) + void attach(index_type pos, inline_pane* pane) { for (auto & pn : panes_) { @@ -3093,7 +3091,7 @@ namespace nana private: essence * const ess_; const std::size_t column_pos_; - std::vector> panes_; + std::vector> panes_; }; void es_lister::scroll(const index_pair& pos, bool to_bottom) @@ -3956,7 +3954,7 @@ namespace nana _m_draw_border(content_r.x, y, show_w); } - essence::inline_pane * _m_get_inline_pane(const category_t& cat, std::size_t column_pos) const + inline_pane * _m_get_inline_pane(const category_t& cat, std::size_t column_pos) const { if (column_pos < cat.factories.size()) { @@ -3969,7 +3967,7 @@ namespace nana return nullptr; } - essence::inline_pane* _m_find_inline_pane(const index_pair& pos, std::size_t column_pos) const + inline_pane* _m_find_inline_pane(const index_pair& pos, std::size_t column_pos) const { auto & cat = *essence_->lister.get(pos.cat); From 74e113b2cce2cc90e3503b9d44b83a70d9793613 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 21 Sep 2016 08:19:00 +0800 Subject: [PATCH 27/32] returns not only one inline widget --- source/gui/widgets/listbox.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 1dcb7f9d..a37e20c9 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -736,14 +736,17 @@ namespace nana std::string to_string(const export_options& exp_opt) const; - inline_pane * get_inline_pane(const index_pair& item_pos) + std::vector get_inline_pane(const index_pair& item_pos) { + std::vector panes; for (auto p : active_panes_) { if (p && (p->item_pos == item_pos)) - return p; + { + panes.emplace_back(p); + } } - return nullptr; + return panes; } void emit_checked(index_pair pos) @@ -752,9 +755,9 @@ namespace nana arg_listbox arg{ i }; wd_ptr()->events().checked.emit(arg, wd_ptr()->handle()); - auto pane = get_inline_pane(pos); - if (pane) - pane->inline_ptr->notify_status(inline_widget_status::checking, i.checked()); + auto panes = get_inline_pane(pos); + for (auto p : panes) + p->inline_ptr->notify_status(inline_widget_status::checking, i.checked()); } void emit_selected(index_pair pos) @@ -763,9 +766,9 @@ namespace nana arg_listbox arg{ i }; wd_ptr()->events().selected.emit(arg, wd_ptr()->handle()); - auto pane = get_inline_pane(pos); - if (pane) - pane->inline_ptr->notify_status(inline_widget_status::selecting, i.selected()); + auto panes = get_inline_pane(pos); + for (auto p : panes) + p->inline_ptr->notify_status(inline_widget_status::selecting, i.selected()); } // Definition is provided after struct essence From c916d0ace30a3bc686570a0813e4131538524251 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 22 Sep 2016 08:03:30 +0800 Subject: [PATCH 28/32] add textbox::set_undo_queue_length a new method for setting the undo queue length --- include/nana/gui/widgets/skeletons/text_editor.hpp | 9 +++++++++ include/nana/gui/widgets/textbox.hpp | 6 ++++++ source/gui/widgets/skeletons/text_editor.cpp | 5 +++++ source/gui/widgets/textbox.cpp | 8 ++++++++ 4 files changed, 28 insertions(+) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 22e099e4..a6904e2e 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -52,7 +52,15 @@ namespace nana{ namespace widgets { max_steps_ = maxs; if (maxs && (commands_.size() >= maxs)) + { + auto move = commands_.size() - pos_; commands_.erase(commands_.begin(), commands_.begin() + (commands_.size() - maxs + 1)); + pos_ = commands_.size() - std::min(move, commands_.size()); + } + else if (0 == maxs) + { + clear(); + } } std::size_t max_steps() const @@ -258,6 +266,7 @@ namespace nana{ namespace widgets void del(); void backspace(bool record_undo = true); void undo(bool reverse); + void set_undo_queue_length(std::size_t len); void move_ns(bool to_north); //Moves up and down void move_left(); void move_right(); diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 12008c37..b10425f7 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -228,6 +228,12 @@ namespace nana /// E.g. Whether caret moves to left of selected content or moves to left of last position when left arrow key is pressed. /// @param move_to_end determines whether to move caret to left of selected_content or to left of last position. void select_behavior(bool move_to_end); + + /// Sets the undo/redo queue length + /** + * @param len The length of the queue. If this parameter is zero, the undo/redo is disabled. + */ + void set_undo_queue_length(std::size_t len); protected: //Overrides widget's virtual functions native_string_type _m_caption() const throw() override; diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index a030471a..3cda2d81 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -2348,6 +2348,11 @@ namespace nana{ namespace widgets _m_scrollbar(); } + void text_editor::set_undo_queue_length(std::size_t len) + { + undo_.max_steps(len); + } + void text_editor::move_ns(bool to_north) { const bool redraw_required = _m_cancel_select(0); diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 76aed3ac..dcc2b702 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -606,6 +606,14 @@ namespace drawerbase { editor->select_behavior(move_to_end); } + void textbox::set_undo_queue_length(std::size_t len) + { + internal_scope_guard lock; + auto editor = get_drawer_trigger().editor(); + if (editor) + editor->set_undo_queue_length(len); + } + //Override _m_caption for caption() auto textbox::_m_caption() const throw() -> native_string_type { From 8dccccc420d01b630d781114d19ac05b00cefc4a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 22 Sep 2016 08:10:24 +0800 Subject: [PATCH 29/32] fix a syntax error --- include/nana/pat/abstract_factory.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nana/pat/abstract_factory.hpp b/include/nana/pat/abstract_factory.hpp index 8aa44e7f..bf1769e2 100644 --- a/include/nana/pat/abstract_factory.hpp +++ b/include/nana/pat/abstract_factory.hpp @@ -85,7 +85,7 @@ namespace nana std::unique_ptr create() override { constexpr auto Size = std::tuple_size::value; - return std::unique_ptr{ _m_new(typename make_pack{}) }; + return std::unique_ptr{ _m_new(make_pack{}) }; } template From 0e6ea358580c8db2cea89d3568bbd4496129aa88 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 24 Sep 2016 08:15:44 +0800 Subject: [PATCH 30/32] fix wrong order of widget deletion --- include/nana/gui/widgets/widget.hpp | 22 ++++++++++++++++++++-- source/gui/widgets/widget.cpp | 6 ------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index 992a780f..3b6ec2ae 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -147,8 +147,6 @@ namespace nana : public widget { public: - ~widget_base(); - window handle() const override; protected: void _m_notify_destroy() override; @@ -172,6 +170,11 @@ namespace nana scheme_{ API::dev::make_scheme() } {} + ~widget_object() + { + API::close_window(handle()); + } + event_type& events() const { return *events_; @@ -255,6 +258,11 @@ namespace nana : events_{ std::make_shared() }, scheme_{ API::dev::make_scheme() } {} + ~widget_object() + { + API::close_window(handle()); + } + event_type& events() const { return *events_; @@ -329,6 +337,11 @@ namespace nana _m_bind_and_attach(); } + ~widget_object() + { + API::close_window(handle()); + } + event_type& events() const { return *events_; @@ -461,6 +474,11 @@ namespace nana : events_{ std::make_shared() }, scheme_{ API::dev::make_scheme() } {} + ~widget_object() + { + API::close_window(handle()); + } + event_type& events() const { return *events_; diff --git a/source/gui/widgets/widget.cpp b/source/gui/widgets/widget.cpp index ac50687b..183768ab 100644 --- a/source/gui/widgets/widget.cpp +++ b/source/gui/widgets/widget.cpp @@ -382,12 +382,6 @@ namespace nana } //class widget_base - widget_base::~widget_base() - { - if (handle_) - API::close_window(handle_); - } - window widget_base::handle() const { return handle_; From db663a0faeda98952ef4fca2de4e6c47d45f075b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 25 Sep 2016 09:33:54 +0800 Subject: [PATCH 31/32] fix a compiler warning --- source/gui/widgets/skeletons/text_editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 7f35a167..28429f8f 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -442,7 +442,7 @@ namespace nana{ namespace widgets } if (pos.x > text_ptr->size()) - pos.x = text_ptr->size(); + pos.x = static_cast(text_ptr->size()); pos.x = editor_._m_pixels_by_char(*text_ptr, pos.x) + editor_.text_area_.area.x; int pos_y = static_cast((pos.y - editor_.points_.offset.y) * editor_.line_height() + editor_._m_text_top_base()); From 8b652ee308121e524da0ec35850832b4aef0a5ce Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 25 Sep 2016 20:11:50 +0800 Subject: [PATCH 32/32] fix i18n for msgbox --- include/nana/pat/abstract_factory.hpp | 2 +- source/gui/msgbox.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/nana/pat/abstract_factory.hpp b/include/nana/pat/abstract_factory.hpp index e7083a40..27966fe2 100644 --- a/include/nana/pat/abstract_factory.hpp +++ b/include/nana/pat/abstract_factory.hpp @@ -1,7 +1,7 @@ /* * A Generic Abstract Factory Pattern 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 diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index d53c9ff5..4bafd225 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -1,7 +1,7 @@ /* * A Message Box Class * 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 @@ -61,14 +61,14 @@ namespace nana { _m_click(arg); }); - yes_.caption("OK"); + yes_.i18n(i18n_eval("OK")); width_pixel += 77; if(msgbox::yes_no == btn || msgbox::yes_no_cancel == btn) { - yes_.caption("Yes"); + yes_.i18n(i18n_eval("Yes")); no_.create(*this); - no_.caption("No"); + no_.i18n(i18n_eval("No")); no_.events().click.connect_unignorable([this](const arg_click& arg) { _m_click(arg); @@ -79,7 +79,7 @@ namespace nana if(msgbox::yes_no_cancel == btn) { cancel_.create(*this); - cancel_.caption("Cancel"); + cancel_.i18n(i18n_eval("Cancel")); cancel_.events().click.connect_unignorable([this](const arg_click& arg) { _m_click(arg);