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