From 1822fafd791ab8fb708b9770aa0c98e07838dbc9 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 14 Jun 2015 21:48:35 +0800 Subject: [PATCH 1/7] construct the inline widget for listbox --- include/nana/gui/detail/basic_window.hpp | 2 + include/nana/gui/detail/bedrock.hpp | 2 + include/nana/gui/programming_interface.hpp | 1 + .../nana/gui/widgets/detail/inline_widget.hpp | 52 ++++ .../widgets/detail/inline_widget_manager.hpp | 89 +++++++ include/nana/gui/widgets/listbox.hpp | 110 +++++---- include/nana/gui/widgets/scroll.hpp | 17 +- include/nana/pat/abstract_factory.hpp | 52 ++++ source/gui/detail/basic_window.cpp | 9 + source/gui/detail/bedrock_pi.cpp | 32 ++- source/gui/detail/win32/bedrock.cpp | 2 - source/gui/detail/window_layout.cpp | 12 +- source/gui/detail/window_manager.cpp | 8 +- source/gui/programming_interface.cpp | 33 +-- source/gui/widgets/listbox.cpp | 230 +++++++++++------- 15 files changed, 472 insertions(+), 179 deletions(-) create mode 100644 include/nana/gui/widgets/detail/inline_widget.hpp create mode 100644 include/nana/gui/widgets/detail/inline_widget_manager.hpp create mode 100644 include/nana/pat/abstract_factory.hpp diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index ef4d5038..9be7aa26 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -115,6 +115,8 @@ namespace detail bool belong_to_lazy() const; bool is_draw_through() const; ///< Determines whether it is a draw-through window. + + basic_window * seek_non_lite_widget_ancestor() const; public: //Override event_holder bool set_events(const std::shared_ptr&) override; diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 1ae2a41d..ebf53dbd 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -40,6 +40,8 @@ namespace detail struct thread_context; + class flag_guard; + ~bedrock(); void pump_event(window, bool is_modal); void map_thread_root_buffer(core_window_t*, bool forced); diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 5606def9..0b66d0f3 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -116,6 +116,7 @@ namespace API void window_icon(window, const paint::image&); bool empty_window(window); ///< Determines whether a window is existing. bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. + bool is_destroying(window); ///< Determines whether a window is destroying void enable_dropfiles(window, bool); /// \brief Retrieves the native window of a Nana.GUI window. diff --git a/include/nana/gui/widgets/detail/inline_widget.hpp b/include/nana/gui/widgets/detail/inline_widget.hpp new file mode 100644 index 00000000..124b6a7a --- /dev/null +++ b/include/nana/gui/widgets/detail/inline_widget.hpp @@ -0,0 +1,52 @@ +/** + * A Inline Widget Interface Definition + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/detail/inline_widget.hpp + * + */ + +#ifndef NANA_GUI_INLINE_WIDGETS_HPP +#define NANA_GUI_INLINE_WIDGETS_HPP +#include "../../basis.hpp" + +namespace nana +{ + namespace detail + { + template + class inline_widget_indicator + { + public: + using index_type = Index; + using value_type = Value; + virtual ~inline_widget_indicator() = default; + private: + virtual void modify(index_type, const value_type&) const = 0; + }; + + template + class inline_widget_interface + { + public: + using index_type = Index; + using value_type = Value; + using inline_indicator = inline_widget_indicator; + using factory_interface = inline_widget_interface; + + virtual ~inline_widget_interface() = default; + + virtual void create(window) = 0; + virtual void activate(inline_indicator&, index_type) = 0; + virtual void resize(const size&) = 0; + virtual void set(const value_type&) = 0; + }; + } +} + +#endif \ No newline at end of file diff --git a/include/nana/gui/widgets/detail/inline_widget_manager.hpp b/include/nana/gui/widgets/detail/inline_widget_manager.hpp new file mode 100644 index 00000000..ef5ec65b --- /dev/null +++ b/include/nana/gui/widgets/detail/inline_widget_manager.hpp @@ -0,0 +1,89 @@ +/** + * A Inline Widget Manager Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/detail/inline_widget_manager.hpp + * + */ + +#ifndef NANA_GUI_INLINE_WIDGET_MANAGER_HPP +#define NANA_GUI_INLINE_WIDGET_MANAGER_HPP +#include "inline_widget.hpp" +#include +#include "../panel.hpp" + +#include + +namespace nana +{ + namespace detail + { + + template + class inline_widget_manager + { + using index_type = Index; + using value_type = Value; + using indicator_type = inline_widget_indicator; + using inline_widget = inline_widget_interface; + using factory = pat::abstract_factory; + + struct widget_holder + { + panel docker; + std::unique_ptr widget_ptr; + }; + public: + void set_window(window wd) + { + window_handle_ = wd; + } + + void set_factory(std::unique_ptr fac) + { + factory_.swap(fac); + } + + void place(point pos, const size& dimension, const size & visible_size, const indicator_type& indicator, index_type index) + { + auto holder = _m_append(); + holder->docker.move({ pos, visible_size }); + holder->widget_ptr->move({ point(), dimension }); + + holder->widget_ptr->activate(indicator, index); + } + private: + widget_holder* _m_append() + { + if (swap_widgets_.empty()) + { + widgets_.emplace_back(); + widgets_.back().swap(swap_widgets_.back()); + swap_widgets_.pop_back(); + } + else + { + + widgets_.emplace_back(new widget_holder); + auto & holder = widgets_.back(); + holder->docker.create(window_handle_, false); + holder->widget_ptr.swap(factory_->create()); + holder->widget_ptr->create(holder->docker->handle()); + } + return widgets_.back().get(); + } + private: + window window_handle_{nullptr}; + std::unique_ptr factory_; + std::vector> widgets_; + std::vector> swap_widgets_; + }; + } +} + +#endif diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 8a2f1938..adb3cdb7 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -15,9 +15,10 @@ #ifndef NANA_GUI_WIDGETS_LISTBOX_HPP #define NANA_GUI_WIDGETS_LISTBOX_HPP #include "widget.hpp" +#include "detail/inline_widget.hpp" +#include #include #include -//#include #include #include @@ -29,7 +30,58 @@ namespace nana { namespace listbox { - using size_type = std::size_t ; + using size_type = std::size_t; + + /// usefull for both absolute and display (sorted) positions + struct index_pair + { + size_type cat; //The pos of category + size_type item; //the pos of item in a category. + + index_pair(size_type cat_pos = 0, size_type item_pos = 0) + : cat(cat_pos), + item(item_pos) + {} + + bool empty() const + { + return (npos == cat); + } + + void set_both(size_type n) + { + cat = item = n; + } + + bool is_category() const + { + return (npos != cat && npos == item); + } + + bool is_item() const + { + return (npos != cat && npos != item); + } + + bool operator==(const index_pair& r) const + { + return (r.cat == cat && r.item == item); + } + + bool operator!=(const index_pair& r) const + { + return !this->operator==(r); + } + + bool operator>(const index_pair& r) const + { + return (cat > r.cat) || (cat == r.cat && item > r.item); + } + }; + + using selection = std::vector; + + using inline_interface = detail::inline_widget_interface; struct cell { @@ -114,55 +166,6 @@ namespace nana std::size_t pos_{0}; }; - /// usefull for both absolute and display (sorted) positions - struct index_pair - { - size_type cat; //The pos of category - size_type item; //the pos of item in a category. - - index_pair(size_type cat_pos = 0, size_type item_pos = 0) - : cat(cat_pos), - item(item_pos) - {} - - bool empty() const - { - return (npos == cat); - } - - void set_both(size_type n) - { - cat = item = n; - } - - bool is_category() const - { - return (npos != cat && npos == item); - } - - bool is_item() const - { - return (npos != cat && npos != item); - } - - bool operator==(const index_pair& r) const - { - return (r.cat == cat && r.item == item); - } - - bool operator!=(const index_pair& r) const - { - return !this->operator==(r); - } - - bool operator>(const index_pair& r) const - { - return (cat > r.cat) || (cat == r.cat && item > r.item); - } - }; - - typedef std::vector selection; - //struct essence_t //@brief: this struct gives many data for listbox, // the state of the struct does not effect on member funcions, therefore all data members are public. @@ -344,6 +347,8 @@ namespace nana : public std::iterator < std::input_iterator_tag, cat_proxy > { public: + using inline_interface = drawerbase::listbox::inline_interface; + cat_proxy() = default; cat_proxy(essence_t*, size_type pos); cat_proxy(essence_t*, category_t*); @@ -423,6 +428,8 @@ namespace nana /// Behavior of Iterator bool operator!=(const cat_proxy&) const; + + void inline_factory(size_type column, pat::cloneable> factory); private: void _m_append(std::vector && cells); void _m_cat_by_pos(); @@ -499,6 +506,7 @@ By \a clicking on a header the list get \a reordered, first up, and then down al using cell = drawerbase::listbox::cell; using export_options= drawerbase::listbox::export_options; using columns_indexs= drawerbase::listbox::size_type; + using inline_interface = drawerbase::listbox::inline_interface; public: listbox() = default; listbox(window, bool visible); diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index 39491da6..54a04de0 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -19,16 +19,15 @@ namespace nana { - template class scroll; + template class scroll; //forward declaration - template struct arg_scroll : public event_arg { - scroll & widget; + window window_handle; - arg_scroll(scroll & wdg) - : widget(wdg) + arg_scroll(window wd) + : window_handle{ wd } {} }; @@ -36,11 +35,10 @@ namespace nana { namespace scroll { - template struct scroll_events : public general_events { - basic_event> value_changed; + basic_event value_changed; }; enum class buttons @@ -313,7 +311,7 @@ namespace nana private: void _m_emit_value_changed() { - widget_->events().value_changed.emit(::nana::arg_scroll(*widget_)); + widget_->events().value_changed.emit({ widget_->handle() }); } void _m_tick() @@ -335,7 +333,7 @@ namespace nana /// Provides a way to display an object which is larger than the window's client area. template class scroll // add a widget scheme? - : public widget_object, drawerbase::scroll::scroll_events> + : public widget_object, drawerbase::scroll::scroll_events> { typedef widget_object > base_type; public: @@ -448,7 +446,6 @@ namespace nana { return this->make_step(forward, range() - 1); } - };//end class scroll }//end namespace nana #endif diff --git a/include/nana/pat/abstract_factory.hpp b/include/nana/pat/abstract_factory.hpp new file mode 100644 index 00000000..df2f8d6c --- /dev/null +++ b/include/nana/pat/abstract_factory.hpp @@ -0,0 +1,52 @@ +/* + * A Generic Abstract Factory Pattern Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/pat/abstract_factory.hpp + * @description: A generic easy-to-use abstract factory pattern implementation + */ + +#ifndef NANA_PAT_ABSFACTORY_HPP +#define NANA_PAT_ABSFACTORY_HPP +#include + +namespace nana +{ + namespace pat + { + template + class abstract_factory + { + public: + using interface_type = Interface; + + virtual ~abstract_factory() = default; + virtual std::unique_ptr create() = 0; + }; + + namespace detail + { + template + class abs_factory + : public abstract_factory + { + std::unique_ptr create() override + { + return std::unique_ptr{ new T }; + } + }; + }//end namespace detail + + template + pat::cloneable> make_factory() + { + return detail::abs_factory(); + } + }//end namespace pat +}//end namespace nana +#endif diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index f0525e50..7948564b 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -298,6 +298,15 @@ namespace nana return false; } + basic_window * basic_window::seek_non_lite_widget_ancestor() const + { + auto anc = this->parent; + while (anc && (category::flags::lite_widget == anc->other.category)) + anc = anc->parent; + + return anc; + } + void basic_window::_m_init_pos_and_size(basic_window* parent, const rectangle& r) { pos_owner = pos_root = r; diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index 1bcd66e4..c73d4cde 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -64,6 +64,26 @@ namespace nana bedrock::instance().evt_operation.cancel(evt); } + class bedrock::flag_guard + { + public: + flag_guard(bedrock* brock, core_window_t * wd) + : brock_{ brock }, wd_(wd) + { + wd_->flags.refreshing = true; + } + + ~flag_guard() + { + if (brock_->wd_manager.available((wd_))) + wd_->flags.refreshing = false; + } + private: + bedrock *const brock_; + core_window_t *const wd_; + + }; + void bedrock::event_expose(core_window_t * wd, bool exposed) { if (nullptr == wd) return; @@ -79,11 +99,8 @@ namespace nana { if (category::flags::root != wd->other.category) { - //If the wd->parent is a lite_widget then find a parent until it is not a lite_widget - wd = wd->parent; - - while (category::flags::lite_widget == wd->other.category) - wd = wd->parent; + //find an ancestor until it is not a lite_widget + wd = wd->seek_non_lite_widget_ancestor(); } else if (category::flags::frame == wd->other.category) wd = wd_manager.find_window(wd->root, wd->pos_root.x, wd->pos_root.y); @@ -162,6 +179,9 @@ namespace nana auto retain = wd->together.events_ptr; auto evts_ptr = retain.get(); + //enable refreshing flag, this is a RAII class for exception-safe + flag_guard fguard(this, wd); + switch (evt_code) { case event_code::click: @@ -214,9 +234,9 @@ namespace nana } (wd->drawer.*drawer_event_fn)(*arg); + if (!draw_only) evt_addr->emit(*arg); - break; } case event_code::mouse_wheel: diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 2085a00d..994bd7f4 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1473,9 +1473,7 @@ namespace detail brock.erase_menu(false); brock.delay_restore(3); //Restores if delay_restore not decleared } - brock.wd_manager.destroy(msgwnd); - nana::detail::platform_spec::instance().release_window_icon(msgwnd->root); break; case WM_NCDESTROY: diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 99ab04ab..a0f025a0 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -1,7 +1,7 @@ /* * Window Layout Implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -24,12 +24,14 @@ namespace nana //class window_layout void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed) { + + if (wd->flags.refreshing) + return; + if (nullptr == wd->effect.bground) { if (is_redraw) { - if (wd->flags.refreshing) return; - wd->flags.refreshing = true; wd->drawer.refresh(); wd->flags.refreshing = false; @@ -42,6 +44,10 @@ namespace nana bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool is_child_refreshed) { + auto check_opaque = wd->seek_non_lite_widget_ancestor(); + if (check_opaque && check_opaque->flags.refreshing) + return true; + nana::rectangle vr; if (read_visual_rectangle(wd, vr)) { diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 63840e0a..fdfc4e30 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1333,14 +1333,16 @@ namespace detail delete wd->together.caret; wd->together.caret = nullptr; } + + arg_destroy arg; + arg.window_handle = reinterpret_cast(wd); + brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); + //Delete the children widgets. for (auto i = wd->children.rbegin(), end = wd->children.rend(); i != end; ++i) _m_destroy(*i); wd->children.clear(); - arg_destroy arg; - arg.window_handle = reinterpret_cast(wd); - brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); _m_disengage(wd, nullptr); wndlayout_type::enable_effects_bground(wd, false); diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 83d27d0d..1ed89214 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -374,6 +374,16 @@ namespace API return restrict::window_manager.available(reinterpret_cast(wd)); } + bool is_destroying(window wd) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (!restrict::window_manager.available(iwd)) + return false; + + return iwd->flags.destroying; + } + void enable_dropfiles(window wd, bool enb) { internal_scope_guard lock; @@ -534,12 +544,9 @@ namespace API internal_scope_guard lock; if(restrict::window_manager.move(iwd, x, y, false)) { - if(category::flags::root != iwd->other.category) - { - do{ - iwd = iwd->parent; - } while (category::flags::lite_widget == iwd->other.category); - } + if (category::flags::root != iwd->other.category) + iwd = iwd->seek_non_lite_widget_ancestor(); + restrict::window_manager.update(iwd, false, false); } } @@ -551,11 +558,8 @@ namespace API if(restrict::window_manager.move(iwd, r)) { if (category::flags::root != iwd->other.category) - { - do{ - iwd = iwd->parent; - } while (category::flags::lite_widget == iwd->other.category); - } + iwd = iwd->seek_non_lite_widget_ancestor(); + restrict::window_manager.update(iwd, false, false); } } @@ -624,11 +628,8 @@ namespace API if(restrict::window_manager.size(iwd, sz, false, false)) { if (category::flags::root != iwd->other.category) - { - do{ - iwd = iwd->parent; - } while (category::flags::lite_widget == iwd->other.category); - } + iwd = iwd->seek_non_lite_widget_ancestor(); + restrict::window_manager.update(iwd, false, false); } } diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 4a98d200..f95ee337 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -408,9 +409,6 @@ namespace nana void item_width(size_type pos, unsigned width) { - if (pos >= cont_.size()) - return; - for(auto & m : cont_) { if(m.index == pos) @@ -661,6 +659,8 @@ namespace nana //A cat may have a key object to identify the category std::shared_ptr key_ptr; + std::deque>> factories; + category_t() = default; category_t(nana::string str) @@ -946,9 +946,15 @@ namespace nana return _m_at(pos.cat)->items.at(index); } + const category_t::container::value_type& at(const index_pair& pos) const { - return at(pos); + auto index = pos.item; + + if (sorted_index_ != npos) + index = absolute(pos); + + return _m_at(pos.cat)->items.at(index); } void clear(size_type cat) @@ -1879,6 +1885,7 @@ namespace nana bool single_check_category_limited_{ false }; };//end class es_lister + //struct essence_t //@brief: this struct gives many data for listbox, // the state of the struct does not effect on member funcions, therefore all data members are public. @@ -1887,6 +1894,23 @@ namespace nana enum class item_state{normal, highlighted, pressed, grabbed, floated}; enum class parts{unknown = -1, header, lister, checker}; + class inline_indicator + : public ::nana::detail::inline_widget_indicator + { + public: + inline_indicator(essence_t* ess) + : ess_{ess} + { + } + + void modify(index_type pos, const value_type& value) const override + { + ess_->lister.at(pos).cells; + } + private: + essence_t * const ess_; + }; + ::nana::listbox::scheme_type* scheme_ptr{nullptr}; ::nana::paint::graphics *graph{nullptr}; bool auto_draw{true}; @@ -1923,6 +1947,15 @@ namespace nana nana::scroll h; }scroll; + + struct inline_pane + { + ::nana::panel pane; + std::unique_ptr inline_ptr; + }; + + std::map>> inline_table, inline_buffered_table; + essence_t() { scroll.offset_x = 0; @@ -2107,11 +2140,11 @@ namespace nana { scroll.h.create(wd, r); API::take_active(scroll.h.handle(), false, wd); - scroll.h.events().mouse_move.connect_unignorable([this](const nana::arg_mouse& arg){ - _m_answer_scroll(arg); - }); - scroll.h.events().mouse_up.connect_unignorable([this](const nana::arg_mouse& arg){ - _m_answer_scroll(arg); + + scroll.h.events().value_changed.connect_unignorable([this](const ::nana::arg_scroll& arg) + { + scroll.offset_x = static_cast(scroll.h.value()); + API::refresh_window(this->lister.wd_ptr()->handle()); }); } else @@ -2126,13 +2159,20 @@ namespace nana if(scroll.v.empty()) { scroll.v.create(wd, r); - API::take_active(scroll.v.handle(), false, wd); // install value_changed() not mouse_move ???? + API::take_active(scroll.v.handle(), false, wd); - scroll.v.events().value_changed([this](const ::nana::arg_scroll& arg) + scroll.v.events().value_changed([this](const ::nana::arg_scroll& arg) { - _m_answer_scroll_value(arg); - }); + index_pair item; + if (!lister.forward(item, scroll.v.value(), item)) return; + if (item == scroll.offset_y_dpl) + return; + + set_scroll_y_dpl(item); + + API::refresh_window(this->lister.wd_ptr()->handle()); + }); } else scroll.v.move(r); @@ -2141,7 +2181,7 @@ namespace nana else if(!scroll.v.empty()) { scroll.v.close(); - set_scroll_y_dpl({0,0}); // scroll.offset_y.set_both(0); + set_scroll_y_dpl({0,0}); nana::rectangle r; if(rect_header(r)) @@ -2311,63 +2351,43 @@ namespace nana for(const auto& hd : header.cont()) { if(false == hd.visible) continue; - x += hd.pixels; + x += static_cast(hd.pixels); if(x > 0) seqs.push_back(hd.index); if(x >= static_cast(lister_w)) break; } } - private: - void _m_answer_scroll(const arg_mouse& arg) - { - if(arg.evt_code == event_code::mouse_move && arg.left_button == false) return; - bool update = false; - if(arg.window_handle == scroll.v.handle()) + inline_pane * open_inline(pat::abstract_factory* factory) + { + std::unique_ptr pane_ptr; + auto i = inline_buffered_table.find(factory); + if (i != inline_buffered_table.end()) { - index_pair item; - if(lister.forward(item, scroll.v.value(), item)) - { - if (item != scroll.offset_y_dpl) - { - set_scroll_y_dpl ( item ); - update = true; - } - } - } - else if(arg.window_handle == scroll.h.handle()) - { - if(scroll.offset_x != static_cast(scroll.h.value())) - { - scroll.offset_x = static_cast(scroll.h.value()); - update = true; - } + if (!i->second.empty()) + pane_ptr = std::move(i->second.front()); } - if(update) - API::refresh_window(lister.wd_ptr()->handle()); + if (!pane_ptr) + { + pane_ptr.reset(new inline_pane); + pane_ptr->pane.create(this->lister.wd_ptr()->handle()); + pane_ptr->inline_ptr = factory->create(); + pane_ptr->inline_ptr->create(pane_ptr->pane); + } + + auto ptr = pane_ptr.get(); + inline_table[factory].emplace_back(std::move(pane_ptr)); + return ptr; } - void _m_answer_scroll_value(const ::nana::arg_scroll& arg) - { - index_pair item; - if( !lister.forward(item, scroll.v.value(), item)) return; - - if (item == scroll.offset_y_dpl) - return; - - set_scroll_y_dpl ( item ); - - API::refresh_window(lister.wd_ptr()->handle()); - } - -}; + }; void es_lister::scroll_refresh() { ess_->scroll_y_dpl_refresh(); - } + 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; // ?? @@ -2709,8 +2729,6 @@ namespace nana void draw(const nana::rectangle& rect) const { - // essence_->scroll_y_dpl_refresh() ; // ???? - internal_scope_guard lock; size_type n = essence_->number_of_lister_items(true); @@ -2752,6 +2770,8 @@ namespace nana auto state = item_state::normal; + essence_->inline_buffered_table.swap(essence_->inline_table); + //Here we draw the root categ (0) or a first item if the first drawing is not a categ.(item!=npos)) if(idx.cat == 0 || !idx.is_category()) { @@ -2767,7 +2787,7 @@ namespace nana if(n-- == 0) break; state = (tracker == idx ? item_state::highlighted : item_state::normal); - _m_draw_item(i_categ->items[lister.absolute(index_pair(idx.cat, offs)) ], x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state); + _m_draw_item(*i_categ, i_categ->items[lister.absolute(index_pair(idx.cat, offs)) ], x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state); y += essence_->item_size; } @@ -2794,12 +2814,14 @@ namespace nana if(n-- == 0) break; state = (idx == tracker ? item_state::highlighted : item_state::normal); - _m_draw_item(i_categ->items[ lister.absolute(index_pair(idx.cat, pos))], x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); + _m_draw_item(*i_categ, i_categ->items[ lister.absolute(index_pair(idx.cat, pos))], x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); y += essence_->item_size; ++idx.item; } } + essence_->inline_buffered_table.clear(); + if (y < rect.y + static_cast(rect.height)) { essence_->graph->set_color(bgcolor); @@ -2848,7 +2870,7 @@ namespace nana } } - void _m_draw_item(const item_t& item, int x, int y, int txtoff, unsigned width, const nana::rectangle& r, const std::vector& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const + void _m_draw_item(const category_t& cat, const item_t& item, const int x, const int y, const int txtoff, unsigned width, const nana::rectangle& r, const std::vector& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const { if (item.flags.selected) // fetch the "def" colors bgcolor = essence_->scheme_ptr->item_selected; @@ -2858,7 +2880,6 @@ namespace nana if(!item.fgcolor.invisible()) fgcolor = item.fgcolor; - auto graph = essence_->graph; if (item_state::highlighted == state) // and blend it if "highlighted" { if (item.flags.selected) @@ -2870,6 +2891,7 @@ namespace nana unsigned show_w = width - essence_->scroll.offset_x; if(show_w >= r.width) show_w = r.width; + auto graph = essence_->graph; //draw the background graph->set_color(bgcolor); graph->rectangle(rectangle{ r.x, y, show_w, essence_->item_size }, true); @@ -2878,12 +2900,11 @@ namespace nana unsigned extreme_text = x; bool first = true; - - for(size_type display_order{0}; display_order < seqs.size(); ++display_order) // get the cell (column) index in the order headers are displayed + for (size_type display_order{ 0 }; display_order < seqs.size(); ++display_order) // get the cell (column) index in the order headers are displayed { auto index = seqs[display_order]; - const auto & header = essence_->header.column(index); // deduce the corresponding header which is in a kind of dislay order - auto it_bgcolor = bgcolor; + const auto & header = essence_->header.column(index); // deduce the corresponding header which is in a kind of dislay order + auto it_bgcolor = bgcolor; if ((item.cells.size() > index) && (header.pixels > 5)) // process only if the cell is visible { @@ -2893,27 +2914,28 @@ namespace nana if (m_cell.custom_format && (!m_cell.custom_format->bgcolor.invisible())) // adapt to costum format if need { - it_bgcolor = m_cell.custom_format->bgcolor; - if (item.flags.selected) - it_bgcolor = it_bgcolor.blend( bgcolor , 0.5) ; + it_bgcolor = m_cell.custom_format->bgcolor; + if (item.flags.selected) + it_bgcolor = it_bgcolor.blend(bgcolor, 0.5); if (item_state::highlighted == state) - it_bgcolor = it_bgcolor.blend(::nana::color(0x99, 0xde, 0xfd), 0.8); - - graph->set_color(it_bgcolor); + it_bgcolor = it_bgcolor.blend(static_cast(0x99defd), 0.8); + + graph->set_color(it_bgcolor); + graph->rectangle(rectangle{ item_xpos, y, header.pixels, essence_->item_size }, true); cell_txtcolor = m_cell.custom_format->fgcolor; } int ext_w = 5; - if(first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?) + if (first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?) { ext_w += 18; element_state estate = element_state::normal; - if(essence_->pointer_where.first == parts::checker) + if (essence_->pointer_where.first == parts::checker) { - switch(state) + switch (state) { case item_state::highlighted: estate = element_state::hovered; break; @@ -2924,7 +2946,7 @@ namespace nana } using state = facade::state; - crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked); + crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked); crook_renderer_.draw(*graph, bgcolor, fgcolor, essence_->checkarea(item_xpos, y), estate); } @@ -2933,7 +2955,7 @@ namespace nana if (item.img) { nana::rectangle img_r(item.img_show_size); - img_r.x = static_cast(ext_w) + item_xpos + static_cast(16 - item.img_show_size.width) / 2; + img_r.x = static_cast(ext_w)+item_xpos + static_cast(16 - item.img_show_size.width) / 2; img_r.y = y + static_cast(essence_->item_size - item.img_show_size.height) / 2; item.img.stretch(item.img.size(), *graph, img_r); } @@ -2946,27 +2968,34 @@ namespace nana if (ts.width + ext_w > header.pixels) // it was an excess { //The text is painted over the next subitem // here beging the ... - int xpos = item_xpos + static_cast(header.pixels) - static_cast(essence_->suspension_width); + int xpos = item_xpos + static_cast(header.pixels) - static_cast(essence_->suspension_width); graph->set_color(it_bgcolor); // litter rect with the item bg end ... - graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true); - graph->set_text_color(cell_txtcolor); + graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true); graph->string(point{ xpos, y + 2 }, STR("...")); //Erase the part that over the next subitem. - if ( display_order + 1 < seqs.size() ) // this is not the last column - { - graph->set_color(bgcolor); // we need to erase the excess, because some cell may not draw text over - graph->rectangle(rectangle{item_xpos + static_cast(header.pixels), y + 2, - ts.width + ext_w - header.pixels, essence_->item_size - 4}, true); - } - extreme_text = std::max (extreme_text, item_xpos + ext_w + ts.width); + if (display_order + 1 < seqs.size()) // this is not the last column + { + graph->set_color(bgcolor); // we need to erase the excess, because some cell may not draw text over + graph->rectangle(rectangle{ item_xpos + static_cast(header.pixels), y + 2, + ts.width + ext_w - header.pixels, essence_->item_size - 4 }, true); + } + extreme_text = std::max(extreme_text, item_xpos + ext_w + ts.width); } } - graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, { 0xEB, 0xF4, 0xF9 }); + graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, static_cast(0xEBF4F9)); - item_xpos += header.pixels; + auto inline_wdg = _m_get_pane(cat, index); + if (inline_wdg) + { + inline_wdg->pane.move({ item_xpos, y, header.pixels, essence_->item_size }); + inline_wdg->inline_ptr->resize({ header.pixels, essence_->item_size }); + //inline_wdg->inline_ptr->activate() + } + + item_xpos += static_cast(header.pixels); if (display_order + 1 >= seqs.size() && static_cast(extreme_text) > item_xpos) { graph->set_color(item.bgcolor); @@ -2980,6 +3009,17 @@ namespace nana _m_draw_border(r.x, y, show_w); } + essence_t::inline_pane * _m_get_pane(const category_t& cat, std::size_t pos) const + { + if (pos < cat.factories.size()) + { + auto & factory = cat.factories[pos]; + if (factory) + return essence_->open_inline(factory.get()); + } + return nullptr; + } + void _m_draw_border(int x, int y, unsigned width) const { //Draw selecting inner rectangle @@ -3024,6 +3064,9 @@ namespace nana void trigger::draw() { + if (API::is_destroying(essence_->lister.wd_ptr()->handle())) + return; + nana::rectangle r; if(essence_->header.visible() && essence_->rect_header(r)) @@ -3890,6 +3933,17 @@ namespace nana return ! this->operator==(r); } + void cat_proxy::inline_factory(size_type column, pat::cloneable> factory) + { + if (column >= ess_->header.cont().size()) + throw std::out_of_range("listbox.cat_proxy.inline_factory: invalid column index"); + + if (column >= cat_->factories.size()) + cat_->factories.resize(column + 1); + + cat_->factories[column] = std::move(factory); + } + void cat_proxy::_m_append(std::vector && cells) { //check invalid cells From c761aced0355b05e86e309427969c4cd8bbc376f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 18 Jun 2015 01:45:45 +0800 Subject: [PATCH 2/7] fix inline widget position issue --- source/gui/widgets/listbox.cpp | 36 ++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index f95ee337..e4391f11 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1950,7 +1950,8 @@ namespace nana struct inline_pane { - ::nana::panel pane; + ::nana::panel pane_bottom; //pane for pane_widget + ::nana::panel pane_widget; //pane for placing user-define widget std::unique_ptr inline_ptr; }; @@ -2372,9 +2373,10 @@ namespace nana if (!pane_ptr) { pane_ptr.reset(new inline_pane); - pane_ptr->pane.create(this->lister.wd_ptr()->handle()); + pane_ptr->pane_bottom.create(this->lister.wd_ptr()->handle()); + pane_ptr->pane_widget.create(pane_ptr->pane_bottom); pane_ptr->inline_ptr = factory->create(); - pane_ptr->inline_ptr->create(pane_ptr->pane); + pane_ptr->inline_ptr->create(pane_ptr->pane_widget); } auto ptr = pane_ptr.get(); @@ -2870,7 +2872,9 @@ namespace nana } } - void _m_draw_item(const category_t& cat, const item_t& item, const int x, const int y, const int txtoff, unsigned width, const nana::rectangle& r, const std::vector& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const + //Draws an item + //@param content_r the rectangle of list content + void _m_draw_item(const category_t& cat, const item_t& item, const int x, const int y, const int txtoff, unsigned width, const nana::rectangle& content_r, const std::vector& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const { if (item.flags.selected) // fetch the "def" colors bgcolor = essence_->scheme_ptr->item_selected; @@ -2889,12 +2893,12 @@ namespace nana } unsigned show_w = width - essence_->scroll.offset_x; - if(show_w >= r.width) show_w = r.width; + if(show_w >= content_r.width) show_w = content_r.width; auto graph = essence_->graph; //draw the background graph->set_color(bgcolor); - graph->rectangle(rectangle{ r.x, y, show_w, essence_->item_size }, true); + graph->rectangle(rectangle{ content_r.x, y, show_w, essence_->item_size }, true); int item_xpos = x; unsigned extreme_text = x; @@ -2990,7 +2994,23 @@ namespace nana auto inline_wdg = _m_get_pane(cat, index); if (inline_wdg) { - inline_wdg->pane.move({ item_xpos, y, header.pixels, essence_->item_size }); + rectangle pane_r; + if (::nana::overlap(content_r, { item_xpos, y, header.pixels, essence_->item_size }, pane_r)) + { + ::nana::point pane_pos; + if (item_xpos < content_r.x) + pane_pos.x = item_xpos - content_r.x; + + if (y < content_r.y) + pane_pos.y = y - content_r.y; + + inline_wdg->pane_widget.move(pane_pos); + inline_wdg->pane_bottom.move(pane_r); + } + else + inline_wdg->pane_bottom.hide(); + + inline_wdg->pane_widget.size({ header.pixels, essence_->item_size }); inline_wdg->inline_ptr->resize({ header.pixels, essence_->item_size }); //inline_wdg->inline_ptr->activate() } @@ -3006,7 +3026,7 @@ namespace nana //Draw selecting inner rectangle if(item.flags.selected) - _m_draw_border(r.x, y, show_w); + _m_draw_border(content_r.x, y, show_w); } essence_t::inline_pane * _m_get_pane(const category_t& cat, std::size_t pos) const From 1bb9a09a8a07730fd2532c2f3fc220ccfb7532f9 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 21 Jun 2015 04:44:49 +0800 Subject: [PATCH 3/7] develop inline widgets for listbox --- include/nana/basic_types.hpp | 6 +- .../nana/gui/widgets/detail/inline_widget.hpp | 39 +++++++-- include/nana/gui/widgets/listbox.hpp | 8 +- include/nana/gui/widgets/widget.hpp | 1 + source/gui/animation.cpp | 2 +- source/gui/detail/window_layout.cpp | 1 - source/gui/detail/window_manager.cpp | 20 ++--- source/gui/widgets/listbox.cpp | 80 ++++++++++++++----- source/gui/widgets/widget.cpp | 7 ++ 9 files changed, 121 insertions(+), 43 deletions(-) diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp index a48d9ece..475f652e 100644 --- a/include/nana/basic_types.hpp +++ b/include/nana/basic_types.hpp @@ -406,10 +406,10 @@ namespace nana struct rectangle { - rectangle(); ///< a zero-size rectangle at (0, 0). + rectangle(); ///< a zero-size rectangle at (0, 0). rectangle(int x, int y, unsigned width, unsigned height); - rectangle(const size &); ///< a rectangle with specified size at coordinate (0, 0). - rectangle(const point&, const size& = size()); + explicit rectangle(const size &); ///< a rectangle with specified size at coordinate (0, 0). + explicit rectangle(const point&, const size& = size()); bool operator==(const rectangle& rhs) const; bool operator!=(const rectangle& rhs) const; diff --git a/include/nana/gui/widgets/detail/inline_widget.hpp b/include/nana/gui/widgets/detail/inline_widget.hpp index 124b6a7a..24c1671f 100644 --- a/include/nana/gui/widgets/detail/inline_widget.hpp +++ b/include/nana/gui/widgets/detail/inline_widget.hpp @@ -23,29 +23,56 @@ namespace nana class inline_widget_indicator { public: + /// A type to index a item using index_type = Index; + + /// A type to the value of the item using value_type = Value; + + /// The destructor virtual ~inline_widget_indicator() = default; - private: - virtual void modify(index_type, const value_type&) const = 0; + + /// Modifies the value of a item specified by pos + virtual void modify(index_type pos, const value_type&) const = 0; + + /// Sends a signal that a specified item is selected + virtual void selected(index_type) = 0; + + /// Sends a signal that a specified item is hovered + virtual void hovered(index_type) = 0; }; template - class inline_widget_interface + class inline_widget_notifier_interface { public: + /// A type to index a item using index_type = Index; + + /// A type to the value of the item using value_type = Value; + + /// A typedef name of a inline widget indicator using inline_indicator = inline_widget_indicator; - using factory_interface = inline_widget_interface; - virtual ~inline_widget_interface() = default; + /// A type to the notifier interface that will be refered by the abstract factory pattern + using factory_interface = inline_widget_notifier_interface; + /// The destructor + virtual ~inline_widget_notifier_interface() = default; + + /// A message to create the inline widget virtual void create(window) = 0; + + /// A message to activate the inline widget to attach a specified item virtual void activate(inline_indicator&, index_type) = 0; + + /// A message to resize the inline widget virtual void resize(const size&) = 0; + + /// A message to set the value from a item virtual void set(const value_type&) = 0; - }; + }; //end class inline_widget_notifier_interface } } diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index adb3cdb7..eac5ec29 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -81,7 +81,7 @@ namespace nana using selection = std::vector; - using inline_interface = detail::inline_widget_interface; + using inline_notifier_interface = detail::inline_widget_notifier_interface; struct cell { @@ -347,7 +347,7 @@ namespace nana : public std::iterator < std::input_iterator_tag, cat_proxy > { public: - using inline_interface = drawerbase::listbox::inline_interface; + using inline_notifier_interface = drawerbase::listbox::inline_notifier_interface; cat_proxy() = default; cat_proxy(essence_t*, size_type pos); @@ -429,7 +429,7 @@ namespace nana /// Behavior of Iterator bool operator!=(const cat_proxy&) const; - void inline_factory(size_type column, pat::cloneable> factory); + void inline_factory(size_type column, pat::cloneable> factory); private: void _m_append(std::vector && cells); void _m_cat_by_pos(); @@ -506,7 +506,7 @@ By \a clicking on a header the list get \a reordered, first up, and then down al using cell = drawerbase::listbox::cell; using export_options= drawerbase::listbox::export_options; using columns_indexs= drawerbase::listbox::size_type; - using inline_interface = drawerbase::listbox::inline_interface; + using inline_notifier_interface = drawerbase::listbox::inline_notifier_interface; public: listbox() = default; listbox(window, bool visible); diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index 98e87cc3..9f7cac45 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -76,6 +76,7 @@ namespace nana point pos() const; void move(int x, int y); + //void move(const point&); void move(const rectangle&); void fgcolor(const nana::color&); diff --git a/source/gui/animation.cpp b/source/gui/animation.cpp index 9ed5a7ea..16b21dae 100644 --- a/source/gui/animation.cpp +++ b/source/gui/animation.cpp @@ -208,7 +208,7 @@ namespace nana good_frame_by_frmbuilder = frmobj.u.frbuilder->frbuilder(pos_in_this_frame, framegraph, framegraph_dimension); if(good_frame_by_frmbuilder) { - nana::rectangle r = framegraph_dimension; + nana::rectangle r(framegraph_dimension); _m_render(outs, [&r, &framegraph](paint::graphics& tar, const nana::point& pos) mutable { r.x = pos.x; diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index a0f025a0..46670951 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -24,7 +24,6 @@ namespace nana //class window_layout void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed) { - if (wd->flags.refreshing) return; diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index fdfc4e30..f6053bce 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -689,16 +689,18 @@ namespace detail { if(forced || (false == wd->belong_to_lazy())) { - wndlayout_type::paint(wd, redraw, false); - this->map(wd, forced); - } - else - { - if(redraw) - wndlayout_type::paint(wd, true, false); - if(wd->other.upd_state == core_window_t::update_state::lazy) - wd->other.upd_state = core_window_t::update_state::refresh; + if (!wd->flags.refreshing) + { + wndlayout_type::paint(wd, redraw, false); + this->map(wd, forced); + return true; + } } + else if(redraw) + wndlayout_type::paint(wd, true, false); + + if (wd->other.upd_state == core_window_t::update_state::lazy) + wd->other.upd_state = core_window_t::update_state::refresh; } return true; } diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index e4391f11..e32908e0 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -659,7 +659,7 @@ namespace nana //A cat may have a key object to identify the category std::shared_ptr key_ptr; - std::deque>> factories; + std::deque>> factories; category_t() = default; @@ -1907,6 +1907,23 @@ namespace nana { ess_->lister.at(pos).cells; } + + void selected(index_type pos) override + { + if (ess_->lister.at(pos).flags.selected) + return; + ess_->lister.select_for_all(false); + cat_proxy(ess_, pos.cat).at(pos.item).select(true); + } + + void hovered(index_type pos) override + { + auto offset = ess_->lister.distance(ess_->scroll.offset_y_dpl, pos); + ess_->pointer_where.first = parts::lister; + ess_->pointer_where.second = offset; + + ess_->update(); + } private: essence_t * const ess_; }; @@ -1920,7 +1937,10 @@ namespace nana unsigned item_size{24}; unsigned text_height{0}; unsigned suspension_width{0}; - ::nana::listbox::export_options def_exp_options ; + + inline_indicator indicator{ this }; + + ::nana::listbox::export_options def_exp_options; ::nana::listbox::export_options& def_export_options() { @@ -1952,7 +1972,7 @@ namespace nana { ::nana::panel pane_bottom; //pane for pane_widget ::nana::panel pane_widget; //pane for placing user-define widget - std::unique_ptr inline_ptr; + std::unique_ptr inline_ptr; }; std::map>> inline_table, inline_buffered_table; @@ -2360,7 +2380,7 @@ namespace nana } } - inline_pane * open_inline(pat::abstract_factory* factory) + inline_pane * open_inline(pat::abstract_factory* factory) { std::unique_ptr pane_ptr; auto i = inline_buffered_table.find(factory); @@ -2634,7 +2654,6 @@ namespace nana void _m_draw(const Container& cont, const nana::rectangle& rect) { graph_reference graph = *(essence_->graph); - int txtop = (rect.height - essence_->text_height) / 2 + rect.y; auto txtcolor = essence_->lister.wd_ptr()->fgcolor(); @@ -2654,7 +2673,7 @@ namespace nana int next_x = x + static_cast(i.pixels); if(next_x > rect.x) { - _m_draw_item(graph, x, rect.y, height, txtop, txtcolor, i, (i.index == essence_->pointer_where.second ? state : item_state::normal)); + _m_draw_header_item(graph, x, rect.y, height, txtop, txtcolor, i, (i.index == essence_->pointer_where.second ? state : item_state::normal)); graph.line({ next_x - 1, rect.y }, { next_x - 1, bottom_y }, _m_border_color()); } @@ -2669,7 +2688,7 @@ namespace nana } template - void _m_draw_item(graph_reference graph, int x, int y, unsigned height, int txtop, const ::nana::color& fgcolor, const Item& item, item_state state) + void _m_draw_header_item(graph_reference graph, int x, int y, unsigned height, int txtop, const ::nana::color& fgcolor, const Item& item, item_state state) { essence_->scheme_ptr->header_bgcolor.get_color(); ::nana::color bgcolor; @@ -2701,10 +2720,10 @@ namespace nana ext_graph.typeface(essence_->graph->typeface()); int txtop = (essence_->header_size - essence_->text_height) / 2; - _m_draw_item(ext_graph, 0, 0, essence_->header_size, txtop, colors::white, item, item_state::floated); + _m_draw_header_item(ext_graph, 0, 0, essence_->header_size, txtop, colors::white, item, item_state::floated); int xpos = essence_->header.item_pos(item.index, nullptr) + pos.x - ref_xpos_; - ext_graph.blend(ext_graph.size(), *(essence_->graph), nana::point(xpos - essence_->scroll.offset_x + rect.x, rect.y), 0.5); + ext_graph.blend(rectangle{ ext_graph.size() }, *(essence_->graph), nana::point(xpos - essence_->scroll.offset_x + rect.x, rect.y), 0.5); } private: @@ -2749,7 +2768,7 @@ namespace nana es_lister & lister = essence_->lister; //The Tracker indicates the item where mouse placed. index_pair tracker(npos, npos); - auto & ptr_where = essence_->pointer_where; + auto & ptr_where = essence_->pointer_where; //if where == lister || where == checker, 'second' indicates the offset to the relative display-order pos of the scroll offset_y which stands for the first item to be displayed in lister. if((ptr_where.first == parts::lister || ptr_where.first == parts::checker) && ptr_where.second != npos) @@ -2784,12 +2803,16 @@ namespace nana } std::size_t size = i_categ->items.size(); + index_pair item_index{ idx.cat, 0 }; for(std::size_t offs = essence_->scroll.offset_y_dpl.item; offs < size; ++offs, ++idx.item) { if(n-- == 0) break; state = (tracker == idx ? item_state::highlighted : item_state::normal); - _m_draw_item(*i_categ, i_categ->items[lister.absolute(index_pair(idx.cat, offs)) ], x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state); + item_index.item = offs; + item_index = lister.absolute_pair(item_index); + + _m_draw_item(*i_categ, item_index, x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state); y += essence_->item_size; } @@ -2811,12 +2834,16 @@ namespace nana continue; auto size = i_categ->items.size(); + index_pair item_pos{ idx.cat, 0 }; for(decltype(size) pos = 0; pos < size; ++pos) { if(n-- == 0) break; state = (idx == tracker ? item_state::highlighted : item_state::normal); - _m_draw_item(*i_categ, i_categ->items[ lister.absolute(index_pair(idx.cat, pos))], x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); + item_pos.item = pos; + item_pos.item = lister.absolute(item_pos); + + _m_draw_item(*i_categ, item_pos, x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state); y += essence_->item_size; ++idx.item; } @@ -2874,8 +2901,10 @@ namespace nana //Draws an item //@param content_r the rectangle of list content - void _m_draw_item(const category_t& cat, const item_t& item, const int x, const int y, const int txtoff, unsigned width, const nana::rectangle& content_r, const std::vector& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const + void _m_draw_item(const category_t& cat, const index_pair& item_pos, const int x, const int y, const int txtoff, unsigned width, const nana::rectangle& content_r, const std::vector& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const { + auto & item = cat.items[item_pos.item]; + if (item.flags.selected) // fetch the "def" colors bgcolor = essence_->scheme_ptr->item_selected; else if (!item.bgcolor.invisible()) @@ -2961,7 +2990,7 @@ namespace nana nana::rectangle img_r(item.img_show_size); img_r.x = static_cast(ext_w)+item_xpos + static_cast(16 - item.img_show_size.width) / 2; img_r.y = y + static_cast(essence_->item_size - item.img_show_size.height) / 2; - item.img.stretch(item.img.size(), *graph, img_r); + item.img.stretch(rectangle{ item.img.size() }, *graph, img_r); } ext_w += 18; } @@ -2994,6 +3023,7 @@ namespace nana auto inline_wdg = _m_get_pane(cat, index); if (inline_wdg) { + //Make sure the user-define inline widgets in right visible rectangle. rectangle pane_r; if (::nana::overlap(content_r, { item_xpos, y, header.pixels, essence_->item_size }, pane_r)) { @@ -3004,7 +3034,7 @@ namespace nana if (y < content_r.y) pane_pos.y = y - content_r.y; - inline_wdg->pane_widget.move(pane_pos); + inline_wdg->pane_widget.move(pane_pos.x, pane_pos.y); inline_wdg->pane_bottom.move(pane_r); } else @@ -3012,7 +3042,7 @@ namespace nana inline_wdg->pane_widget.size({ header.pixels, essence_->item_size }); inline_wdg->inline_ptr->resize({ header.pixels, essence_->item_size }); - //inline_wdg->inline_ptr->activate() + inline_wdg->inline_ptr->activate(essence_->indicator, item_pos); } item_xpos += static_cast(header.pixels); @@ -3199,7 +3229,16 @@ namespace nana } } - switch(update) + if (update) + { + if (2 == update) + draw(); + + API::lazy_refresh(); + } + + /* + switch(update) //deprecated { case 1: API::update_window(essence_->lister.wd_ptr()->handle()); @@ -3209,6 +3248,7 @@ namespace nana API::lazy_refresh(); break; } + */ } void trigger::mouse_leave(graph_reference graph, const arg_mouse&) @@ -3261,7 +3301,7 @@ namespace nana else if (arg.ctrl) sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); else - lister.select_for_all(false); + lister.select_for_all(false); //cancel all selections } else sel = !item_proxy(essence_, index_pair (item_pos.cat, lister.absolute(item_pos))).selected(); @@ -3560,6 +3600,8 @@ namespace nana } else if (ess_->lister.last_selected_abs == pos_) ess_->lister.last_selected_abs.set_both(npos); + + ess_->update(); return *this; } @@ -3953,7 +3995,7 @@ namespace nana return ! this->operator==(r); } - void cat_proxy::inline_factory(size_type column, pat::cloneable> factory) + void cat_proxy::inline_factory(size_type column, pat::cloneable> factory) { if (column >= ess_->header.cont().size()) throw std::out_of_range("listbox.cat_proxy.inline_factory: invalid column index"); diff --git a/source/gui/widgets/widget.cpp b/source/gui/widgets/widget.cpp index cd504eac..f5075c52 100644 --- a/source/gui/widgets/widget.cpp +++ b/source/gui/widgets/widget.cpp @@ -173,6 +173,13 @@ namespace nana _m_move(x, y); } + /* + void widget::move(const point& pos) //deprecated + { + _m_move(pos); + } + */ + void widget::move(const rectangle& r) { _m_move(r); From 28413b7f259308870ebc8c04934ea315012108d3 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 22 Jun 2015 11:30:14 +0800 Subject: [PATCH 4/7] explicit conversion from point/size to rectangle --- include/nana/gui/detail/effects_renderer.hpp | 6 ++--- include/nana/gui/detail/general_events.hpp | 2 +- .../widgets/skeletons/text_token_stream.hpp | 2 +- include/nana/gui/widgets/widget.hpp | 2 +- source/gui/detail/bedrock_pi.cpp | 2 -- source/gui/detail/drawer.cpp | 2 +- source/gui/detail/native_window_interface.cpp | 2 +- source/gui/detail/window_layout.cpp | 4 +-- source/gui/effects.cpp | 4 +-- source/gui/layout_utility.cpp | 6 +++-- source/gui/widgets/button.cpp | 2 +- source/gui/widgets/combox.cpp | 2 +- source/gui/widgets/date_chooser.cpp | 4 +-- source/gui/widgets/float_listbox.cpp | 2 +- source/gui/widgets/listbox.cpp | 19 +++++++++----- source/gui/widgets/picture.cpp | 6 ++--- source/gui/widgets/progress.cpp | 2 +- source/gui/widgets/scroll.cpp | 6 ++--- source/gui/widgets/skeletons/text_editor.cpp | 26 +++++++++---------- source/gui/widgets/slider.cpp | 4 +-- source/gui/widgets/tabbar.cpp | 4 +-- source/gui/widgets/toolbar.cpp | 6 ++--- source/gui/widgets/treebox.cpp | 2 +- source/gui/widgets/widget.cpp | 6 ++--- .../paint/detail/native_paint_interface.cpp | 6 ++--- source/paint/graphics.cpp | 6 ++--- source/paint/image.cpp | 2 +- source/paint/pixel_buffer.cpp | 22 ++++++++-------- 28 files changed, 82 insertions(+), 77 deletions(-) diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp index 91daf849..f44ceb93 100644 --- a/include/nana/gui/detail/effects_renderer.hpp +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -98,10 +98,10 @@ namespace nana{ void _m_render_edge_nimbus(core_window_t* wd, const nana::rectangle & visual) { - nana::rectangle r(visual); + auto r = visual; r.pare_off(-static_cast(weight())); - nana::rectangle good_r; - if(overlap(r, wd->root_graph->size(), good_r)) + rectangle good_r; + if (overlap(r, rectangle{ wd->root_graph->size() }, good_r)) { if( (good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || (good_r.x + good_r.width > visual.x + visual.width) || (good_r.y + good_r.height > visual.y + visual.height)) diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 1a4bf972..618115dc 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -46,7 +46,7 @@ namespace nana class event_arg { public: - virtual ~event_arg(); + virtual ~event_arg() = default; /// ignorable handlers behind the current one in a chain of event handlers will not get called. void stop_propagation() const; diff --git a/include/nana/gui/widgets/skeletons/text_token_stream.hpp b/include/nana/gui/widgets/skeletons/text_token_stream.hpp index 024c12ce..beae23ee 100644 --- a/include/nana/gui/widgets/skeletons/text_token_stream.hpp +++ b/include/nana/gui/widgets/skeletons/text_token_stream.hpp @@ -574,7 +574,7 @@ namespace nana{ namespace widgets{ namespace skeletons virtual void nontext_render(graph_reference graph, int x, int y) override { if(size_ != image_.size()) - image_.stretch(image_.size(), graph, nana::rectangle(x, y, size_.width, size_.height)); + image_.stretch(::nana::rectangle{ image_.size() }, graph, nana::rectangle(x, y, size_.width, size_.height)); else image_.paste(graph, x, y); } diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index 9f7cac45..67bb3cc8 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -76,7 +76,7 @@ namespace nana point pos() const; void move(int x, int y); - //void move(const point&); + void move(const point&); void move(const rectangle&); void fgcolor(const nana::color&); diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index c73d4cde..c102c20a 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -39,8 +39,6 @@ namespace nana //end class internal_scope_guard //class event_arg - event_arg::~event_arg(){} - void event_arg::stop_propagation() const { stop_propagation_ = true; diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 3b9702a3..fe5695b7 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -368,7 +368,7 @@ namespace nana void drawer::_m_bground_end() { if(core_window_->effect.bground && core_window_->effect.bground_fade_rate >= 0.01) - core_window_->other.glass_buffer.blend(core_window_->other.glass_buffer.size(), graphics, nana::point(), core_window_->effect.bground_fade_rate); + core_window_->other.glass_buffer.blend(::nana::rectangle{ core_window_->other.glass_buffer.size() }, graphics, nana::point(), core_window_->effect.bground_fade_rate); } void drawer::_m_draw_dynamic_drawing_object() diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 0101a804..8d33f2b1 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -174,7 +174,7 @@ namespace nana{ } } #endif - return primary_monitor_size(); + return rectangle{ primary_monitor_size() }; } //platform-dependent diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 46670951..e8cd1f60 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -210,7 +210,7 @@ namespace nana beg = beg->parent; } - glass_buffer.bitblt(wd->dimension, beg->drawer.graphics, wd->pos_root - beg->pos_root); + glass_buffer.bitblt(::nana::rectangle{ wd->dimension }, beg->drawer.graphics, wd->pos_root - beg->pos_root); nana::rectangle r(wd->pos_owner, wd->dimension); for (auto i = layers.rbegin(), layers_rend = layers.rend(); i != layers_rend; ++i) @@ -240,7 +240,7 @@ namespace nana } } else - glass_buffer.bitblt(wd->dimension, wd->parent->drawer.graphics, wd->pos_owner); + glass_buffer.bitblt(::nana::rectangle{ wd->dimension }, wd->parent->drawer.graphics, wd->pos_owner); const rectangle r_of_wd{ wd->pos_owner, wd->dimension }; for (auto child : wd->parent->children) diff --git a/source/gui/effects.cpp b/source/gui/effects.cpp index 3570fa21..7ab15482 100644 --- a/source/gui/effects.cpp +++ b/source/gui/effects.cpp @@ -26,7 +26,7 @@ namespace nana { if(fade_rate_ < 0.001) return; - graph.blend(graph.size(), API::bgcolor(wd), fade_rate_); + graph.blend(::nana::rectangle{ graph.size() }, API::bgcolor(wd), fade_rate_); } private: const double fade_rate_; @@ -42,7 +42,7 @@ namespace nana void take_effect(window, graph_reference graph) const { - graph.blur(graph.size(), radius_); + graph.blur(::nana::rectangle{ graph.size() }, radius_); } private: const std::size_t radius_; diff --git a/source/gui/layout_utility.cpp b/source/gui/layout_utility.cpp index 8ab4c9b9..c81273b3 100644 --- a/source/gui/layout_utility.cpp +++ b/source/gui/layout_utility.cpp @@ -52,11 +52,13 @@ namespace nana bool overlap(const rectangle& ir, const size& valid_input_area, const rectangle & dr, const size& valid_dst_area, rectangle& op_ir, rectangle& op_dr) { - if(overlap(ir, valid_input_area, op_ir) == false) + rectangle valid_r{ valid_input_area }; + if (overlap(ir, valid_r, op_ir) == false) return false; + valid_r = valid_dst_area; rectangle good_dr; - if(overlap(dr, valid_dst_area, good_dr) == false) + if (overlap(dr, valid_r, good_dr) == false) return false; zoom(ir, op_ir, dr, op_dr); diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 63d8e810..f1c24564 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -282,7 +282,7 @@ namespace nana{ namespace drawerbase else e_state = element_state::disabled; - if (false == cite_.draw(graph, attr_.bgcolor, attr_.fgcolor, graph.size(), e_state)) + if (false == cite_.draw(graph, attr_.bgcolor, attr_.fgcolor, ::nana::rectangle{ graph.size() }, e_state)) { if (bground_mode::basic != API::effects_bground_mode(wdg_->handle())) { diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index b1d401f5..5f8498f7 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -521,7 +521,7 @@ namespace nana } nana::point pos((image_pixels_ - imgsz.width) / 2 + 2, (vpix - imgsz.height) / 2 + 2); - img.stretch(img.size(), *graph_, nana::rectangle(pos, imgsz)); + img.stretch(::nana::rectangle{ img.size() }, *graph_, nana::rectangle(pos, imgsz)); } private: std::vector> items_; diff --git a/source/gui/widgets/date_chooser.cpp b/source/gui/widgets/date_chooser.cpp index 3f1818ca..6679d3d0 100644 --- a/source/gui/widgets/date_chooser.cpp +++ b/source/gui/widgets/date_chooser.cpp @@ -414,7 +414,7 @@ namespace nana r.y = static_cast(newbuf.height() - r.height) / 2; newbuf.stretch(nzbuf, r); - nzbuf.blend(nzbuf.size(), dzbuf, nana::point(), fade * (count - i)); + nzbuf.blend(::nana::rectangle{ nzbuf.size() }, dzbuf, nana::point(), fade * (count - i)); graph.bitblt(refpos.x, refpos.y, dzbuf); API::update_window(*widget_); @@ -442,7 +442,7 @@ namespace nana nzbuf.rectangle(true, colors::white); newbuf.stretch(nzbuf, r); - nzbuf.blend(nzbuf.size(), dzbuf, nana::point(), fade * (count - i)); + nzbuf.blend(::nana::rectangle{ nzbuf.size() }, dzbuf, nana::point(), fade * (count - i)); graph.bitblt(refpos.x, refpos.y, dzbuf); API::update_window(*widget_); diff --git a/source/gui/widgets/float_listbox.cpp b/source/gui/widgets/float_listbox.cpp index 8af19e43..5cdd2cf2 100644 --- a/source/gui/widgets/float_listbox.cpp +++ b/source/gui/widgets/float_listbox.cpp @@ -99,7 +99,7 @@ namespace nana nana::point to_pos(x, r.y + 2); to_pos.x += (image_pixels_ - imgsz.width) / 2; to_pos.y += (vpix - imgsz.height) / 2; - item->image().stretch(item->image().size(), graph, nana::rectangle(to_pos, imgsz)); + item->image().stretch(::nana::rectangle{ item->image().size() }, graph, nana::rectangle(to_pos, imgsz)); } x += (image_pixels_ + 2); } diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index e32908e0..556e1faf 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1919,10 +1919,13 @@ namespace nana void hovered(index_type pos) override { auto offset = ess_->lister.distance(ess_->scroll.offset_y_dpl, pos); - ess_->pointer_where.first = parts::lister; - ess_->pointer_where.second = offset; - ess_->update(); + if (ess_->pointer_where.first != parts::lister || ess_->pointer_where.second != offset) + { + ess_->pointer_where.first = parts::lister; + ess_->pointer_where.second = offset; + ess_->update(); + } } private: essence_t * const ess_; @@ -2386,8 +2389,12 @@ namespace nana auto i = inline_buffered_table.find(factory); if (i != inline_buffered_table.end()) { - if (!i->second.empty()) - pane_ptr = std::move(i->second.front()); + auto & panes = i->second; + if (!panes.empty()) + { + pane_ptr = std::move(panes.front()); + panes.pop_front(); + } } if (!pane_ptr) @@ -3034,7 +3041,7 @@ namespace nana if (y < content_r.y) pane_pos.y = y - content_r.y; - inline_wdg->pane_widget.move(pane_pos.x, pane_pos.y); + inline_wdg->pane_widget.move(pane_pos); inline_wdg->pane_bottom.move(pane_r); } else diff --git a/source/gui/widgets/picture.cpp b/source/gui/widgets/picture.cpp index 64903ed5..707edce5 100644 --- a/source/gui/widgets/picture.cpp +++ b/source/gui/widgets/picture.cpp @@ -112,7 +112,7 @@ namespace nana _m_draw_background(fit_size.width, fit_size.height); - backimg.image.stretch(valid_area, graph, { pos, fit_size }); + backimg.image.stretch(valid_area, graph, ::nana::rectangle{ pos, fit_size }); } else { @@ -151,7 +151,7 @@ namespace nana _m_draw_background(graphsize.width, graphsize.height); color invalid_clr_for_call; - backimg.bground->draw(graph, invalid_clr_for_call, invalid_clr_for_call, graphsize, element_state::normal); + backimg.bground->draw(graph, invalid_clr_for_call, invalid_clr_for_call, rectangle{ graphsize }, element_state::normal); } graph.setsta(); @@ -171,7 +171,7 @@ namespace nana else if (bground.gradual_from == bground.gradual_to) graph->rectangle(true, bground.gradual_from); else - graph->gradual_rectangle(graph->size(), bground.gradual_from, bground.gradual_to, !bground.horizontal); + graph->gradual_rectangle(::nana::rectangle{ graph->size() }, bground.gradual_from, bground.gradual_to, !bground.horizontal); } } } diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp index 4459ddb1..3baaf0d0 100644 --- a/source/gui/widgets/progress.cpp +++ b/source/gui/widgets/progress.cpp @@ -106,7 +106,7 @@ namespace nana void trigger::_m_draw_box(graph_reference graph) { - rectangle r = graph.size(); + rectangle r{ graph.size() }; graph.gradual_rectangle(r, colors::button_face_shadow_end, colors::button_face_shadow_start, true); ::nana::color lt{ colors::gray }, rb{colors::white}; graph.frame_rectangle(r, lt, lt, rb, rb); diff --git a/source/gui/widgets/scroll.cpp b/source/gui/widgets/scroll.cpp index b6d466fb..6c85a2ad 100644 --- a/source/gui/widgets/scroll.cpp +++ b/source/gui/widgets/scroll.cpp @@ -132,7 +132,7 @@ namespace nana _m_background(graph); - rectangle_rotator r(vertical_, graph.size()); + rectangle_rotator r(vertical_, ::nana::rectangle{ graph.size() }); r.x_ref() = static_cast(r.w() - fixedsize); r.w_ref() = fixedsize; @@ -159,7 +159,7 @@ namespace nana if (!metrics_.pressed || !_m_check()) return; - nana::rectangle_rotator r(vertical_, graph.size()); + nana::rectangle_rotator r(vertical_, ::nana::rectangle{ graph.size() }); if(metrics_.what == buttons::forward) { r.x_ref() = static_cast(fixedsize); @@ -253,7 +253,7 @@ namespace nana { if(_m_check()) { - rectangle_rotator r(vertical_, graph.size()); + rectangle_rotator r(vertical_, rectangle{ graph.size() }); r.x_ref() = static_cast(fixedsize + metrics_.scroll_pos); r.w_ref() = static_cast(metrics_.scroll_length); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 0a2f9261..a7f05a56 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1285,7 +1285,7 @@ namespace nana{ namespace widgets if (!API::widget_borderless(this->window_)) { ::nana::facade facade; - facade.draw(graph, bgcolor, API::fgcolor(this->window_), API::window_size(this->window_), API::element_state(this->window_)); + facade.draw(graph, bgcolor, API::fgcolor(this->window_), ::nana::rectangle{ API::window_size(this->window_) }, API::element_state(this->window_)); } }; } @@ -2775,12 +2775,12 @@ namespace nana{ namespace widgets { //draw the whole text if it is a RTL text, because Arbic language is transformable. canvas.string({}, str, len); - graph_.bitblt({ ent_pos, ::nana::size{ ent_pixels, canvas.height() } }, canvas, ::nana::point{ ent_off, 0 }); + graph_.bitblt(::nana::rectangle{ ent_pos, ::nana::size{ ent_pixels, canvas.height() } }, canvas, ::nana::point{ ent_off, 0 }); } else { canvas.string({}, ent_begin, ent_end - ent_begin); - graph_.bitblt({ ent_pos, ::nana::size{ ent_pixels, canvas.height() } }, canvas); + graph_.bitblt(::nana::rectangle{ ent_pos, ::nana::size{ ent_pixels, canvas.height() } }, canvas); } } } @@ -2830,7 +2830,7 @@ namespace nana{ namespace widgets if (selected) { graph_.set_text_color(scheme_->selection_text.get_color()); - graph_.rectangle({ text_pos, { str_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ text_pos, { str_w, line_h_pixels } }, true); graph_.string(text_pos, ent.begin, len); } else @@ -2839,7 +2839,7 @@ namespace nana{ namespace widgets text_pos.x += static_cast(str_w); } if (selected) - graph_.rectangle({ text_pos, { whitespace_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ text_pos, { whitespace_w, line_h_pixels } }, true); } else { @@ -2876,7 +2876,7 @@ namespace nana{ namespace widgets //selected all if (a.x <= pos && str_end <= b.x) { - graph_.rectangle({ text_pos, { str_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ text_pos, { str_w, line_h_pixels } }, true); graph_.set_text_color(scheme_->selection_text.get_color()); graph_.string(text_pos, ent.begin, len); } @@ -2906,7 +2906,7 @@ namespace nana{ namespace widgets part_pos.x += static_cast(head_w); //Draw selected part - graph_.rectangle({ part_pos, { sel_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ part_pos, { sel_w, line_h_pixels } }, true); graph_.set_text_color(scheme_->selection_text.get_color()); graph_.string(part_pos, ent.begin + (a.x - pos), endpos - a.x); @@ -2931,7 +2931,7 @@ namespace nana{ namespace widgets else { //LTR //Draw selected part - graph_.rectangle({ text_pos, { sel_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ text_pos, { sel_w, line_h_pixels } }, true); graph_.set_text_color(scheme_->selection_text.get_color()); graph_.string(text_pos, ent.begin, endpos - pos); @@ -2957,7 +2957,7 @@ namespace nana{ namespace widgets if (a.x < pos) { //Draw selected all - graph_.rectangle({ text_pos, { str_w, line_h_pixels } }, true, { 0x33, 0x99, 0xFF }); + graph_.rectangle(::nana::rectangle{ text_pos, { str_w, line_h_pixels } }, true, static_cast(0x3399FF)); graph_.set_text_color(scheme_->selection_text.get_color()); graph_.string(text_pos, ent.begin, len); } @@ -2978,7 +2978,7 @@ namespace nana{ namespace widgets ::nana::point part_pos{ text_pos.x + static_cast(head_w), text_pos.y }; //Draw selected part - graph_.rectangle({ part_pos, {str_w - head_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ part_pos, {str_w - head_w, line_h_pixels } }, true); graph_.set_text_color(scheme_->selection_text.get_color()); graph_.string(part_pos, ent.begin + a.x - pos, len - (a.x - pos)); } @@ -2991,7 +2991,7 @@ namespace nana{ namespace widgets if (str_pos.y < b.y) { if (a.y < str_pos.y || ((a.y == str_pos.y) && (a.x <= str_pos.x ))) - graph_.rectangle({ text_pos, { whitespace_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ text_pos, { whitespace_w, line_h_pixels } }, true); } } else if (b.y == str_pos.y) @@ -3007,7 +3007,7 @@ namespace nana{ namespace widgets if (pos + len <= b.x) { //Draw selected part - graph_.rectangle({ text_pos, { str_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ text_pos, { str_w, line_h_pixels } }, true); graph_.set_text_color(scheme_->selection_text.get_color()); graph_.string(text_pos, ent.begin, len); } @@ -3021,7 +3021,7 @@ namespace nana{ namespace widgets else { //draw selected part - graph_.rectangle({ text_pos, { sel_w, line_h_pixels } }, true); + graph_.rectangle(::nana::rectangle{ text_pos, { sel_w, line_h_pixels } }, true); graph_.set_text_color(scheme_->selection_text.get_color()); graph_.string(text_pos, ent.begin, b.x - pos); diff --git a/source/gui/widgets/slider.cpp b/source/gui/widgets/slider.cpp index 23af12a4..a83f3f2f 100644 --- a/source/gui/widgets/slider.cpp +++ b/source/gui/widgets/slider.cpp @@ -55,7 +55,7 @@ namespace nana virtual void slider(window, graph_reference graph, const slider_t& s) { - nana::rectangle r = graph.size(); + nana::rectangle r{ graph.size() }; if(s.horizontal) { r.x = s.pos; @@ -390,7 +390,7 @@ namespace nana nana::rectangle _m_bar_area() const { auto sz = other_.graph->size(); - nana::rectangle r = sz; + nana::rectangle r{ sz }; if(style::horizontal == attr_.dir) { r.x = attr_.slider_scale / 2 - attr_.border; diff --git a/source/gui/widgets/tabbar.cpp b/source/gui/widgets/tabbar.cpp index 9d69b7b6..7a4aaf02 100644 --- a/source/gui/widgets/tabbar.cpp +++ b/source/gui/widgets/tabbar.cpp @@ -947,7 +947,7 @@ namespace nana auto bgcolor = API::bgcolor(basis_.wd); auto fgcolor = API::fgcolor(basis_.wd); - item_renderer::item_t m = { basis_.graph->size() }; + item_renderer::item_t m{ ::nana::rectangle{ basis_.graph->size() } }; basis_.renderer->background(*basis_.graph, m.r, bgcolor); @@ -985,7 +985,7 @@ namespace nana } if(false == item.img.empty()) - item.img.stretch(item.img.size(), *basis_.graph, nana::rectangle(m.r.x + 4, (m.r.height - 16) / 2, 16, 16)); + item.img.stretch(::nana::rectangle{ item.img.size() }, *basis_.graph, nana::rectangle(m.r.x + 4, (m.r.height - 16) / 2, 16, 16)); if(item.text.size()) { diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index 3936cfce..81b75c7f 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -174,11 +174,11 @@ namespace nana pos.x += static_cast(scale + extra_size - size.width) / 2; pos.y += static_cast(height - size.height) / 2; - item.image.paste(size, graph, pos); + item.image.paste(::nana::rectangle{ size }, graph, pos); if(item.enable == false) { nana::paint::graphics gh(size); - gh.bitblt(size, graph, pos); + gh.bitblt(::nana::rectangle{ size }, graph, pos); gh.rgb_to_wb(); gh.paste(graph, pos.x, pos.y); } @@ -400,7 +400,7 @@ namespace nana void drawer::_m_draw_background(const ::nana::color& clr) { - graph_->gradual_rectangle(graph_->size(), clr.blend(colors::white, 0.9), clr.blend(colors::black, 0.95), true); + graph_->gradual_rectangle(::nana::rectangle{ graph_->size() }, clr.blend(colors::white, 0.9), clr.blend(colors::black, 0.95), true); } void drawer::_m_draw() diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index a4e51a0b..7e026e6c 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -1260,7 +1260,7 @@ namespace nana attr.area.x += (attr.area.width - fit_size.width) / 2; attr.area.y += (attr.area.height - fit_size.height) / 2; attr.area = fit_size; - img->stretch(size, graph, attr.area); + img->stretch(::nana::rectangle{ size }, graph, attr.area); } else img->paste(graph, attr.area.x + static_cast(attr.area.width - size.width) / 2, attr.area.y + static_cast(attr.area.height - size.height) / 2); diff --git a/source/gui/widgets/widget.cpp b/source/gui/widgets/widget.cpp index f5075c52..d4d20387 100644 --- a/source/gui/widgets/widget.cpp +++ b/source/gui/widgets/widget.cpp @@ -173,12 +173,10 @@ namespace nana _m_move(x, y); } - /* - void widget::move(const point& pos) //deprecated + void widget::move(const point& pos) { - _m_move(pos); + _m_move(pos.x, pos.y); } - */ void widget::move(const rectangle& r) { diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index 7c96f7b6..3aea449d 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -98,13 +98,13 @@ namespace detail return bgcolor; } - void blend(drawable_type dw, const nana::rectangle& area, pixel_color_t color, double fade_rate) + void blend(drawable_type dw, const rectangle& area, pixel_color_t color, double fade_rate) { if(fade_rate <= 0) return; if(fade_rate > 1) fade_rate = 1; - nana::rectangle r; - if(false == nana::overlap(drawable_size(dw), area, r)) + rectangle r; + if (false == ::nana::overlap(rectangle{ drawable_size(dw) }, area, r)) return; unsigned red = static_cast((color.value & 0xFF0000) * fade_rate); diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 8e61e8dd..76e9aefc 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -604,7 +604,7 @@ namespace paint if(dst.handle_ && handle_ && (dst.handle_ != handle_)) { pixel_buffer s_pixbuf; - s_pixbuf.attach(handle_, size()); + s_pixbuf.attach(handle_, ::nana::rectangle{ size() }); s_pixbuf.blend(s_r, dst.handle_, d_pos, fade_rate); @@ -1022,13 +1022,13 @@ namespace paint void graphics::rectangle(bool solid) { - rectangle(size(), solid); + rectangle(::nana::rectangle{ size() }, solid); } void graphics::rectangle(bool solid, const ::nana::color& clr) { set_color(clr); - rectangle(size(), solid); + rectangle(::nana::rectangle{ size() }, solid); } void graphics::rectangle(const ::nana::rectangle& r, bool solid) diff --git a/source/paint/image.cpp b/source/paint/image.cpp index a6fcd598..39aac942 100644 --- a/source/paint/image.cpp +++ b/source/paint/image.cpp @@ -263,7 +263,7 @@ namespace paint void image::paste(graphics& dst, int x, int y) const { if(image_ptr_) - image_ptr_->paste(image_ptr_->size(), dst, x, y); + image_ptr_->paste(::nana::rectangle{ image_ptr_->size() }, dst, x, y); } void image::paste(const nana::rectangle& r_src, graphics & dst, const nana::point& p_dst) const diff --git a/source/paint/pixel_buffer.cpp b/source/paint/pixel_buffer.cpp index bbb34b59..787d2532 100644 --- a/source/paint/pixel_buffer.cpp +++ b/source/paint/pixel_buffer.cpp @@ -22,10 +22,10 @@ namespace nana{ namespace paint { - nana::rectangle valid_rectangle(const nana::size& s, const nana::rectangle& r) + nana::rectangle valid_rectangle(const size& s, const rectangle& r) { nana::rectangle good_r; - nana::overlap(s, r, good_r); + nana::overlap(rectangle{ s }, r, good_r); return good_r; } @@ -384,13 +384,13 @@ namespace nana{ namespace paint close(); } - void pixel_buffer::attach(drawable_type drawable, const nana::rectangle& want_r) + void pixel_buffer::attach(drawable_type drawable, const ::nana::rectangle& want_r) { storage_.reset(); if(drawable) { nana::rectangle r; - if(nana::overlap(nana::paint::detail::drawable_size(drawable), want_r, r)) + if (::nana::overlap(::nana::rectangle{ nana::paint::detail::drawable_size(drawable) }, want_r, r)) storage_ = std::make_shared(drawable, r); } } @@ -429,16 +429,16 @@ namespace nana{ namespace paint bool pixel_buffer::open(drawable_type drawable, const nana::rectangle & want_rectangle) { - nana::size sz = nana::paint::detail::drawable_size(drawable); + auto sz = nana::paint::detail::drawable_size(drawable); if(want_rectangle.x >= static_cast(sz.width) || want_rectangle.y >= static_cast(sz.height)) return false; - nana::rectangle want_r = want_rectangle; + auto want_r = want_rectangle; if(want_r.width == 0) want_r.width = sz.width - want_r.x; if(want_r.height == 0) want_r.height = sz.height - want_r.y; - nana::rectangle r; - if(false == overlap(sz, want_r, r)) + ::nana::rectangle r; + if (false == overlap(::nana::rectangle{ sz }, want_r, r)) return false; #if defined(NANA_WINDOWS) BITMAPINFO bmpinfo; @@ -1039,13 +1039,13 @@ namespace nana{ namespace paint } } - void pixel_buffer::blur(const nana::rectangle& r, std::size_t radius) + void pixel_buffer::blur(const ::nana::rectangle& r, std::size_t radius) { auto sp = storage_.get(); if(nullptr == sp || radius < 1) return; - nana::rectangle good_r; - if(overlap(r, this->size(), good_r)) + ::nana::rectangle good_r; + if (overlap(r, ::nana::rectangle{ this->size() }, good_r)) (*(sp->img_pro.blur))->process(*this, good_r, radius); } }//end namespace paint From 76ebf52739caef7fab4638938e514647d6fafd37 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 23 Jun 2015 02:25:59 +0800 Subject: [PATCH 5/7] add whether_to_draw to determine draw widget background --- .../nana/gui/widgets/detail/inline_widget.hpp | 5 +- include/nana/pat/abstract_factory.hpp | 11 + source/gui/widgets/listbox.cpp | 333 ++++++++++++------ 3 files changed, 250 insertions(+), 99 deletions(-) diff --git a/include/nana/gui/widgets/detail/inline_widget.hpp b/include/nana/gui/widgets/detail/inline_widget.hpp index 24c1671f..6dae9c1c 100644 --- a/include/nana/gui/widgets/detail/inline_widget.hpp +++ b/include/nana/gui/widgets/detail/inline_widget.hpp @@ -70,8 +70,11 @@ namespace nana /// A message to resize the inline widget virtual void resize(const size&) = 0; - /// A message to set the value from a item + /// A message to set the value from the item virtual void set(const value_type&) = 0; + + /// Determines whether to draw the background of the widget + virtual bool whether_to_draw() const = 0; }; //end class inline_widget_notifier_interface } } diff --git a/include/nana/pat/abstract_factory.hpp b/include/nana/pat/abstract_factory.hpp index df2f8d6c..cfdc7dfb 100644 --- a/include/nana/pat/abstract_factory.hpp +++ b/include/nana/pat/abstract_factory.hpp @@ -19,8 +19,19 @@ namespace nana { namespace pat { + namespace detail + { + //A Base class for abstract factory, avoids decorated name length exceeding for a class template. + class abstract_factory_base + { + public: + virtual ~abstract_factory_base() = default; + }; + } + template class abstract_factory + : public detail::abstract_factory_base { public: using interface_type = Interface; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 556e1faf..82eabec0 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -728,8 +728,6 @@ namespace nana if((sorted_index_ == npos) || (!resort_)) return; - - auto weak_ordering_comp = fetch_ordering_comparer(sorted_index_); if(weak_ordering_comp) { @@ -936,6 +934,11 @@ namespace nana return npos ; } + category_t& at(std::size_t cat_pos) + { + return *(_m_at(cat_pos)); + } + /// return a ref to the real item object at display!!! position pos using current sorting only if it is active, and at absolute position if no sorting is currently active. category_t::container::value_type& at(const index_pair& pos) { @@ -1851,7 +1854,7 @@ namespace nana container::iterator _m_at(size_type index) { if(index >= list_.size()) - throw std::out_of_range("Nana.GUI.Listbox: invalid category index"); + throw std::out_of_range("nana::listbox: invalid category index"); auto i = list_.begin(); std::advance(i, index); @@ -1861,7 +1864,7 @@ namespace nana container::const_iterator _m_at(size_type index) const { if(index >= list_.size()) - throw std::out_of_range("Nana.GUI.Listbox: invalid category index"); + throw std::out_of_range("nana::listbox: invalid category index"); auto i = list_.cbegin(); std::advance(i, index); @@ -1976,9 +1979,11 @@ namespace nana ::nana::panel pane_bottom; //pane for pane_widget ::nana::panel pane_widget; //pane for placing user-define widget std::unique_ptr inline_ptr; + index_pair item_pos; //The item index of the inline widget + std::size_t column_pos; }; - std::map>> inline_table, inline_buffered_table; + std::map>> inline_table, inline_buffered_table; essence_t() { @@ -2938,118 +2943,228 @@ namespace nana int item_xpos = x; unsigned extreme_text = x; - bool first = true; + //bool first = true; //deprecated for (size_type display_order{ 0 }; display_order < seqs.size(); ++display_order) // get the cell (column) index in the order headers are displayed { - auto index = seqs[display_order]; - const auto & header = essence_->header.column(index); // deduce the corresponding header which is in a kind of dislay order + const auto column_pos = seqs[display_order]; + const auto & header = essence_->header.column(column_pos); // deduce the corresponding header which is in a kind of dislay order auto it_bgcolor = bgcolor; - if ((item.cells.size() > index) && (header.pixels > 5)) // process only if the cell is visible + if (header.pixels > 5) { - auto cell_txtcolor = fgcolor; - auto & m_cell = item.cells[index]; - nana::size ts = graph->text_extent_size(m_cell.text); // precalcule text geometry + int content_pos = 5; - if (m_cell.custom_format && (!m_cell.custom_format->bgcolor.invisible())) // adapt to costum format if need + //Draw the image in the 1st column in display order + if (0 == display_order) { - it_bgcolor = m_cell.custom_format->bgcolor; - if (item.flags.selected) - it_bgcolor = it_bgcolor.blend(bgcolor, 0.5); - if (item_state::highlighted == state) - it_bgcolor = it_bgcolor.blend(static_cast(0x99defd), 0.8); + if (essence_->checkable) + { + content_pos += 18; - graph->set_color(it_bgcolor); + element_state estate = element_state::normal; + if (essence_->pointer_where.first == parts::checker) + { + switch (state) + { + case item_state::highlighted: + estate = element_state::hovered; break; + case item_state::grabbed: + estate = element_state::pressed; break; + default: break; + } + } - graph->rectangle(rectangle{ item_xpos, y, header.pixels, essence_->item_size }, true); + using state = facade::state; + crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked); + crook_renderer_.draw(*graph, bgcolor, fgcolor, essence_->checkarea(item_xpos, y), estate); + } - cell_txtcolor = m_cell.custom_format->fgcolor; + if (essence_->if_image) + { + //Draw the image in the 1st column in display order + if (item.img) + { + nana::rectangle img_r(item.img_show_size); + img_r.x = content_pos + item_xpos + static_cast(16 - item.img_show_size.width) / 2; + img_r.y = y + static_cast(essence_->item_size - item.img_show_size.height) / 2; + item.img.stretch(rectangle{ item.img.size() }, *graph, img_r); + } + content_pos += 18; + } } - int ext_w = 5; - if (first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?) - { - ext_w += 18; + bool draw_column = true; - element_state estate = element_state::normal; - if (essence_->pointer_where.first == parts::checker) + if (static_cast(content_pos) < header.pixels) + { + auto inline_wdg = _m_get_inline_pane(cat, column_pos); + if (inline_wdg) { - switch (state) + //Make sure the user-define inline widgets in right visible rectangle. + rectangle pane_r; + auto wdg_x = item_xpos + content_pos; + auto wdg_w = header.pixels - static_cast(content_pos); + if (::nana::overlap(content_r, { wdg_x, y, wdg_w, essence_->item_size }, pane_r)) { - case item_state::highlighted: - estate = element_state::hovered; break; - case item_state::grabbed: - estate = element_state::pressed; break; - default: break; + ::nana::point pane_pos; + if (wdg_x < content_r.x) + pane_pos.x = wdg_x - content_r.x; + + if (y < content_r.y) + pane_pos.y = y - content_r.y; + + inline_wdg->pane_widget.move(pane_pos); + inline_wdg->pane_bottom.move(pane_r); + } + else + inline_wdg->pane_bottom.hide(); + + ::nana::size sz{ wdg_w, essence_->item_size }; + inline_wdg->pane_widget.size(sz); + inline_wdg->inline_ptr->resize(sz); + inline_wdg->item_pos = item_pos; + inline_wdg->column_pos = column_pos; + inline_wdg->inline_ptr->activate(essence_->indicator, item_pos); + + draw_column = inline_wdg->inline_ptr->whether_to_draw(); + + //To reduce the memory usage, the cells may not be allocated + if (item.cells.size() > column_pos) + inline_wdg->inline_ptr->set(item.cells[column_pos].text); + else + inline_wdg->inline_ptr->set({}); + } + } + + if (item.cells.size() > column_pos) // process only if the cell is visible + { + auto cell_txtcolor = fgcolor; + auto & m_cell = item.cells[column_pos]; + nana::size ts = graph->text_extent_size(m_cell.text); // precalcule text geometry + + if (m_cell.custom_format && (!m_cell.custom_format->bgcolor.invisible())) // adapt to costum format if need + { + it_bgcolor = m_cell.custom_format->bgcolor; + if (item.flags.selected) + it_bgcolor = it_bgcolor.blend(bgcolor, 0.5); + if (item_state::highlighted == state) + it_bgcolor = it_bgcolor.blend(static_cast(0x99defd), 0.8); + + graph->set_color(it_bgcolor); + + graph->rectangle(rectangle{ item_xpos, y, header.pixels, essence_->item_size }, true); + + cell_txtcolor = m_cell.custom_format->fgcolor; + } + + /* //deprecated + if ((0 == display_order) && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?) + { + content_pos += 18; + + element_state estate = element_state::normal; + if (essence_->pointer_where.first == parts::checker) + { + switch (state) + { + case item_state::highlighted: + estate = element_state::hovered; break; + case item_state::grabbed: + estate = element_state::pressed; break; + default: break; + } + } + + using state = facade::state; + crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked); + crook_renderer_.draw(*graph, bgcolor, fgcolor, essence_->checkarea(item_xpos, y), estate); + } + */ + + /* + if ((0 == display_order) && essence_->if_image) //deprecated + { + //Draw the image in the 1st column in display order + if (item.img) + { + nana::rectangle img_r(item.img_show_size); + img_r.x = content_pos + item_xpos + static_cast(16 - item.img_show_size.width) / 2; + img_r.y = y + static_cast(essence_->item_size - item.img_show_size.height) / 2; + item.img.stretch(rectangle{ item.img.size() }, *graph, img_r); + } + content_pos += 18; + } + */ + + if (draw_column) + { + graph->set_text_color(cell_txtcolor); + graph->string(point{ item_xpos + content_pos, y + txtoff }, m_cell.text); // draw full text of the cell index (column) + + if (ts.width + static_cast(content_pos) > header.pixels) // it was an excess + { + //The text is painted over the next subitem // here beging the ... + int xpos = item_xpos + static_cast(header.pixels) - static_cast(essence_->suspension_width); + + graph->set_color(it_bgcolor); // litter rect with the item bg end ... + graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true); + graph->string(point{ xpos, y + 2 }, STR("...")); + + //Erase the part that over the next subitem. + if (display_order + 1 < seqs.size()) // this is not the last column + { + graph->set_color(bgcolor); // we need to erase the excess, because some cell may not draw text over + graph->rectangle(rectangle{ item_xpos + static_cast(header.pixels), y + 2, + ts.width + static_cast(content_pos)-header.pixels, essence_->item_size - 4 }, true); + } + extreme_text = std::max(extreme_text, item_xpos + content_pos + ts.width); } } - - using state = facade::state; - crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked); - crook_renderer_.draw(*graph, bgcolor, fgcolor, essence_->checkarea(item_xpos, y), estate); } - if ((0 == index) && essence_->if_image) // draw the image if need, ??only before the first column?? (display_order=0 ?) + graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, static_cast(0xEBF4F9)); + + /* + if (static_cast(content_pos) < header.pixels) //deprecated { - if (item.img) + auto inline_wdg = _m_get_inline_pane(cat, column_pos); + if (inline_wdg) { - nana::rectangle img_r(item.img_show_size); - img_r.x = static_cast(ext_w)+item_xpos + static_cast(16 - item.img_show_size.width) / 2; - img_r.y = y + static_cast(essence_->item_size - item.img_show_size.height) / 2; - item.img.stretch(rectangle{ item.img.size() }, *graph, img_r); + //Make sure the user-define inline widgets in right visible rectangle. + rectangle pane_r; + auto wdg_x = item_xpos + content_pos; + auto wdg_w = header.pixels - static_cast(content_pos); + if (::nana::overlap(content_r, { wdg_x, y, wdg_w, essence_->item_size }, pane_r)) + { + ::nana::point pane_pos; + if (wdg_x < content_r.x) + pane_pos.x = wdg_x - content_r.x; + + if (y < content_r.y) + pane_pos.y = y - content_r.y; + + inline_wdg->pane_widget.move(pane_pos); + inline_wdg->pane_bottom.move(pane_r); + } + else + inline_wdg->pane_bottom.hide(); + + ::nana::size sz{ wdg_w, essence_->item_size }; + inline_wdg->pane_widget.size(sz); + inline_wdg->inline_ptr->resize(sz); + inline_wdg->item_pos = item_pos; + inline_wdg->column_pos = column_pos; + inline_wdg->inline_ptr->activate(essence_->indicator, item_pos); + + //To reduce the memory usage, the cells may not be allocated + if (item.cells.size() > column_pos) + inline_wdg->inline_ptr->set(item.cells[column_pos].text); + else + inline_wdg->inline_ptr->set({}); } - ext_w += 18; } - - graph->set_text_color(cell_txtcolor); - graph->string(point{ item_xpos + ext_w, y + txtoff }, m_cell.text); // draw full text of the cell index (column) - - if (ts.width + ext_w > header.pixels) // it was an excess - { - //The text is painted over the next subitem // here beging the ... - int xpos = item_xpos + static_cast(header.pixels) - static_cast(essence_->suspension_width); - - graph->set_color(it_bgcolor); // litter rect with the item bg end ... - graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true); - graph->string(point{ xpos, y + 2 }, STR("...")); - - //Erase the part that over the next subitem. - if (display_order + 1 < seqs.size()) // this is not the last column - { - graph->set_color(bgcolor); // we need to erase the excess, because some cell may not draw text over - graph->rectangle(rectangle{ item_xpos + static_cast(header.pixels), y + 2, - ts.width + ext_w - header.pixels, essence_->item_size - 4 }, true); - } - extreme_text = std::max(extreme_text, item_xpos + ext_w + ts.width); - } - } - - graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, static_cast(0xEBF4F9)); - - auto inline_wdg = _m_get_pane(cat, index); - if (inline_wdg) - { - //Make sure the user-define inline widgets in right visible rectangle. - rectangle pane_r; - if (::nana::overlap(content_r, { item_xpos, y, header.pixels, essence_->item_size }, pane_r)) - { - ::nana::point pane_pos; - if (item_xpos < content_r.x) - pane_pos.x = item_xpos - content_r.x; - - if (y < content_r.y) - pane_pos.y = y - content_r.y; - - inline_wdg->pane_widget.move(pane_pos); - inline_wdg->pane_bottom.move(pane_r); - } - else - inline_wdg->pane_bottom.hide(); - - inline_wdg->pane_widget.size({ header.pixels, essence_->item_size }); - inline_wdg->inline_ptr->resize({ header.pixels, essence_->item_size }); - inline_wdg->inline_ptr->activate(essence_->indicator, item_pos); + */ } item_xpos += static_cast(header.pixels); @@ -3058,7 +3173,7 @@ namespace nana graph->set_color(item.bgcolor); graph->rectangle(rectangle{item_xpos , y + 2, extreme_text - item_xpos, essence_->item_size - 4}, true); } - first = false; + //first = false; //deprecated } //Draw selecting inner rectangle @@ -3066,17 +3181,40 @@ namespace nana _m_draw_border(content_r.x, y, show_w); } - essence_t::inline_pane * _m_get_pane(const category_t& cat, std::size_t pos) const + essence_t::inline_pane * _m_get_inline_pane(const category_t& cat, std::size_t column_pos) const { - if (pos < cat.factories.size()) + if (column_pos < cat.factories.size()) { - auto & factory = cat.factories[pos]; + auto & factory = cat.factories[column_pos]; if (factory) return essence_->open_inline(factory.get()); } return nullptr; } + essence_t::inline_pane* _m_find_inline_pane(const index_pair& pos, std::size_t column_pos) const + { + auto & cat = essence_->lister.at(pos.cat); + + if (column_pos >= cat.factories.size()) + return nullptr; + + auto& factory = cat.factories[column_pos]; + if (!factory) + return nullptr; + + auto i = essence_->inline_table.find(factory.get()); + if (i == essence_->inline_table.end()) + return nullptr; + + for (auto & inl_widget : i->second) + { + if (inl_widget->item_pos == pos && inl_widget->column_pos == column_pos) + return inl_widget.get(); + } + return nullptr; + } + void _m_draw_border(int x, int y, unsigned width) const { //Draw selecting inner rectangle @@ -4063,7 +4201,6 @@ namespace nana arg_listbox::arg_listbox(const drawerbase::listbox::item_proxy& m, bool selected) : item(m), selected(selected) { - } //class listbox From 6c554ceab2bda565875f3b34933deb28a16cb792 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 24 Jun 2015 02:14:36 +0800 Subject: [PATCH 6/7] inline widget for listbox is ready --- source/gui/widgets/listbox.cpp | 100 +++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 82eabec0..d9264412 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -647,6 +647,8 @@ namespace nana } }; + class inline_indicator; + struct category_t { using container = std::deque; @@ -660,6 +662,7 @@ namespace nana std::shared_ptr key_ptr; std::deque>> factories; + std::deque> indicators; category_t() = default; @@ -1897,43 +1900,6 @@ namespace nana enum class item_state{normal, highlighted, pressed, grabbed, floated}; enum class parts{unknown = -1, header, lister, checker}; - class inline_indicator - : public ::nana::detail::inline_widget_indicator - { - public: - inline_indicator(essence_t* ess) - : ess_{ess} - { - } - - void modify(index_type pos, const value_type& value) const override - { - ess_->lister.at(pos).cells; - } - - void selected(index_type pos) override - { - if (ess_->lister.at(pos).flags.selected) - return; - ess_->lister.select_for_all(false); - cat_proxy(ess_, pos.cat).at(pos.item).select(true); - } - - void hovered(index_type pos) override - { - auto offset = ess_->lister.distance(ess_->scroll.offset_y_dpl, pos); - - if (ess_->pointer_where.first != parts::lister || ess_->pointer_where.second != offset) - { - ess_->pointer_where.first = parts::lister; - ess_->pointer_where.second = offset; - ess_->update(); - } - } - private: - essence_t * const ess_; - }; - ::nana::listbox::scheme_type* scheme_ptr{nullptr}; ::nana::paint::graphics *graph{nullptr}; bool auto_draw{true}; @@ -1944,8 +1910,6 @@ namespace nana unsigned text_height{0}; unsigned suspension_width{0}; - inline_indicator indicator{ this }; - ::nana::listbox::export_options def_exp_options; ::nana::listbox::export_options& def_export_options() @@ -1979,6 +1943,7 @@ namespace nana ::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; }; @@ -2388,7 +2353,7 @@ namespace nana } } - inline_pane * open_inline(pat::abstract_factory* factory) + inline_pane * open_inline(pat::abstract_factory* factory, inline_indicator* indicator) { std::unique_ptr pane_ptr; auto i = inline_buffered_table.find(factory); @@ -2405,6 +2370,7 @@ namespace nana if (!pane_ptr) { pane_ptr.reset(new inline_pane); + pane_ptr->indicator = indicator; pane_ptr->pane_bottom.create(this->lister.wd_ptr()->handle()); pane_ptr->pane_widget.create(pane_ptr->pane_bottom); pane_ptr->inline_ptr = factory->create(); @@ -2417,6 +2383,52 @@ namespace nana } }; + class inline_indicator + : public ::nana::detail::inline_widget_indicator + { + public: + using parts = essence_t::parts; + + inline_indicator(essence_t* ess, std::size_t column_pos) + : ess_{ ess }, column_pos_{column_pos} + { + } + + void modify(index_type pos, const value_type& value) const override + { + auto & cells = ess_->lister.at(pos).cells; + if (cells.size() <= column_pos_) + cells.resize(column_pos_ + 1); + + cells[column_pos_].text = value; + ess_->update(); + } + + void selected(index_type pos) override + { + if (ess_->lister.at(pos).flags.selected) + return; + ess_->lister.select_for_all(false); + cat_proxy(ess_, pos.cat).at(pos.item).select(true); + } + + void hovered(index_type pos) override + { + auto offset = ess_->lister.distance(ess_->scroll.offset_y_dpl, pos); + + if (ess_->pointer_where.first != parts::lister || ess_->pointer_where.second != offset) + { + ess_->pointer_where.first = parts::lister; + ess_->pointer_where.second = offset; + ess_->update(); + } + } + private: + essence_t * const ess_; + const std::size_t column_pos_; + }; + + void es_lister::scroll_refresh() { ess_->scroll_y_dpl_refresh(); @@ -3025,7 +3037,7 @@ namespace nana inline_wdg->inline_ptr->resize(sz); inline_wdg->item_pos = item_pos; inline_wdg->column_pos = column_pos; - inline_wdg->inline_ptr->activate(essence_->indicator, item_pos); + inline_wdg->inline_ptr->activate(*inline_wdg->indicator, item_pos); draw_column = inline_wdg->inline_ptr->whether_to_draw(); @@ -3187,7 +3199,7 @@ namespace nana { auto & factory = cat.factories[column_pos]; if (factory) - return essence_->open_inline(factory.get()); + return essence_->open_inline(factory.get(), cat.indicators[column_pos].get()); } return nullptr; } @@ -4146,9 +4158,13 @@ namespace nana throw std::out_of_range("listbox.cat_proxy.inline_factory: invalid column index"); if (column >= cat_->factories.size()) + { cat_->factories.resize(column + 1); + cat_->indicators.resize(column + 1); + } cat_->factories[column] = std::move(factory); + cat_->indicators[column].reset(new inline_indicator(ess_, column)); } void cat_proxy::_m_append(std::vector && cells) From a6455bcbe01a5aed140faeb37ccbb3dea254d9ef Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 6 Jul 2015 03:27:41 +0800 Subject: [PATCH 7/7] inline widget for listbox is ready to launch --- .../nana/gui/widgets/detail/inline_widget.hpp | 3 + source/gui/widgets/listbox.cpp | 192 ++++-------------- 2 files changed, 42 insertions(+), 153 deletions(-) diff --git a/include/nana/gui/widgets/detail/inline_widget.hpp b/include/nana/gui/widgets/detail/inline_widget.hpp index 6dae9c1c..6b40c7e3 100644 --- a/include/nana/gui/widgets/detail/inline_widget.hpp +++ b/include/nana/gui/widgets/detail/inline_widget.hpp @@ -32,6 +32,9 @@ namespace nana /// The destructor virtual ~inline_widget_indicator() = default; + /// Returns the host widget of the indicator + virtual ::nana::widget& host() const = 0; + /// Modifies the value of a item specified by pos virtual void modify(index_type pos, const value_type&) const = 0; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index d9264412..a83485bf 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1740,74 +1740,45 @@ namespace nana { return {pos.cat, relative( pos )}; } - - /// all arg are relative to display order, or all are absolute, but not mixed + + /// all arg are relative to display order, or all are absolute, but not mixed bool forward(index_pair from, size_type offs, index_pair& item) const { - if(!good_item(from, from)) + if (!good_item(from, from)) return false; - if(offs == 0) + auto cat = _m_at(from.cat); + auto cat_end = list_.end(); + + auto items_left = (cat->expand ? cat->items.size() : 0); + + if (from.is_category()) + items_left += 1; //add 1 category bar + else if (items_left >= from.item) + items_left -= from.item; + else + return false; //invalid argument + + while (offs) { - item = from; - return true; - } - - if(list_.size() <= from.cat) return false; - - if(from.is_category()) - { - // this is a category, so... - // and offs is not 0, this category would not be candidated. - // the algorithm above to calc the offset item is always starting with a item. - --offs; - from.item = 0; - } - - auto icat = _m_at(from.cat); // an iterator to category from.cat - - if(icat->expand) - { - std::size_t item_left_in_this_cat = icat->items.size() -1- from.item; - if(offs <= item_left_in_this_cat ) - { - item = from; - item.item += offs; // use absolute to know the real item - return true; // allways return here when we have only one cat. - } - else - { - offs -= item_left_in_this_cat ; - item = from; - item.item += item_left_in_this_cat ; - } - } - - ++from.cat; - ++icat; - for(; icat != list_.end(); ++icat, ++from.cat) - { - item.cat = from.cat; - item.item = npos; - - if(offs-- == 0) + if (items_left > offs) { + item.cat = from.cat; + item.item = (npos == from.item ? offs - 1 : from.item + offs); return true; } - if(icat->expand) - { - if(offs < icat->items.size()) - { - //item.cat = from.cat; - item.item = offs; - return true; - } - else - offs -= icat->items.size(); - } + offs -= items_left; + if (++cat == cat_end) + return false; + + ++from.cat; + from.item = npos; + items_left = (cat->expand ? cat->items.size() + 1 : 1); } - return false; + + item = from; + return true; } /// all arg are relative to display order, or all are absolute, but not mixed @@ -2394,6 +2365,11 @@ namespace nana { } + ::nana::widget& host() const override + { + return *ess_->lister.wd_ptr(); + } + void modify(index_type pos, const value_type& value) const override { auto & cells = ess_->lister.at(pos).cells; @@ -2955,7 +2931,6 @@ namespace nana int item_xpos = x; unsigned extreme_text = x; - //bool first = true; //deprecated for (size_type display_order{ 0 }; display_order < seqs.size(); ++display_order) // get the cell (column) index in the order headers are displayed { @@ -3017,6 +2992,8 @@ namespace nana rectangle pane_r; auto wdg_x = item_xpos + content_pos; auto wdg_w = header.pixels - static_cast(content_pos); + + bool visible_state = true; if (::nana::overlap(content_r, { wdg_x, y, wdg_w, essence_->item_size }, pane_r)) { ::nana::point pane_pos; @@ -3030,7 +3007,7 @@ namespace nana inline_wdg->pane_bottom.move(pane_r); } else - inline_wdg->pane_bottom.hide(); + visible_state = false; ::nana::size sz{ wdg_w, essence_->item_size }; inline_wdg->pane_widget.size(sz); @@ -3046,6 +3023,8 @@ namespace nana inline_wdg->inline_ptr->set(item.cells[column_pos].text); else inline_wdg->inline_ptr->set({}); + + API::show_window(inline_wdg->pane_bottom, visible_state); } } @@ -3070,45 +3049,6 @@ namespace nana cell_txtcolor = m_cell.custom_format->fgcolor; } - /* //deprecated - if ((0 == display_order) && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?) - { - content_pos += 18; - - element_state estate = element_state::normal; - if (essence_->pointer_where.first == parts::checker) - { - switch (state) - { - case item_state::highlighted: - estate = element_state::hovered; break; - case item_state::grabbed: - estate = element_state::pressed; break; - default: break; - } - } - - using state = facade::state; - crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked); - crook_renderer_.draw(*graph, bgcolor, fgcolor, essence_->checkarea(item_xpos, y), estate); - } - */ - - /* - if ((0 == display_order) && essence_->if_image) //deprecated - { - //Draw the image in the 1st column in display order - if (item.img) - { - nana::rectangle img_r(item.img_show_size); - img_r.x = content_pos + item_xpos + static_cast(16 - item.img_show_size.width) / 2; - img_r.y = y + static_cast(essence_->item_size - item.img_show_size.height) / 2; - item.img.stretch(rectangle{ item.img.size() }, *graph, img_r); - } - content_pos += 18; - } - */ - if (draw_column) { graph->set_text_color(cell_txtcolor); @@ -3137,46 +3077,6 @@ namespace nana graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast(essence_->item_size) - 1 }, static_cast(0xEBF4F9)); - /* - if (static_cast(content_pos) < header.pixels) //deprecated - { - auto inline_wdg = _m_get_inline_pane(cat, column_pos); - if (inline_wdg) - { - //Make sure the user-define inline widgets in right visible rectangle. - rectangle pane_r; - auto wdg_x = item_xpos + content_pos; - auto wdg_w = header.pixels - static_cast(content_pos); - if (::nana::overlap(content_r, { wdg_x, y, wdg_w, essence_->item_size }, pane_r)) - { - ::nana::point pane_pos; - if (wdg_x < content_r.x) - pane_pos.x = wdg_x - content_r.x; - - if (y < content_r.y) - pane_pos.y = y - content_r.y; - - inline_wdg->pane_widget.move(pane_pos); - inline_wdg->pane_bottom.move(pane_r); - } - else - inline_wdg->pane_bottom.hide(); - - ::nana::size sz{ wdg_w, essence_->item_size }; - inline_wdg->pane_widget.size(sz); - inline_wdg->inline_ptr->resize(sz); - inline_wdg->item_pos = item_pos; - inline_wdg->column_pos = column_pos; - inline_wdg->inline_ptr->activate(essence_->indicator, item_pos); - - //To reduce the memory usage, the cells may not be allocated - if (item.cells.size() > column_pos) - inline_wdg->inline_ptr->set(item.cells[column_pos].text); - else - inline_wdg->inline_ptr->set({}); - } - } - */ } item_xpos += static_cast(header.pixels); @@ -3185,7 +3085,6 @@ namespace nana graph->set_color(item.bgcolor); graph->rectangle(rectangle{item_xpos , y + 2, extreme_text - item_xpos, essence_->item_size - 4}, true); } - //first = false; //deprecated } //Draw selecting inner rectangle @@ -3393,19 +3292,6 @@ namespace nana API::lazy_refresh(); } - - /* - switch(update) //deprecated - { - case 1: - API::update_window(essence_->lister.wd_ptr()->handle()); - break; - case 2: - draw(); - API::lazy_refresh(); - break; - } - */ } void trigger::mouse_leave(graph_reference graph, const arg_mouse&)