diff --git a/include/nana/gui/widgets/detail/inline_widget.hpp b/include/nana/gui/widgets/detail/inline_widget.hpp index 6b40c7e3..875c2945 100644 --- a/include/nana/gui/widgets/detail/inline_widget.hpp +++ b/include/nana/gui/widgets/detail/inline_widget.hpp @@ -1,7 +1,7 @@ /** * A Inline Widget Interface Definition * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -35,6 +35,9 @@ namespace nana /// Returns the host widget of the indicator virtual ::nana::widget& host() const = 0; + /// Returns the position of column + virtual std::size_t column() const = 0; + /// Modifies the value of a item specified by pos virtual void modify(index_type pos, const value_type&) const = 0; @@ -45,7 +48,7 @@ namespace nana virtual void hovered(index_type) = 0; }; - template + template class inline_widget_notifier_interface { public: @@ -55,6 +58,9 @@ namespace nana /// A type to the value of the item using value_type = Value; + /// A type to the status + using status_type = Status; + /// A typedef name of a inline widget indicator using inline_indicator = inline_widget_indicator; @@ -70,6 +76,9 @@ namespace nana /// A message to activate the inline widget to attach a specified item virtual void activate(inline_indicator&, index_type) = 0; + /// A message to change the status + virtual void notify_status(status_type, bool) = 0; + /// A message to resize the inline widget virtual void resize(const size&) = 0; diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index e4b06724..4e414760 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -676,8 +676,14 @@ namespace nana using index_pairs = ::std::vector; - using inline_notifier_interface = detail::inline_widget_notifier_interface; + enum class inline_widget_status{ + checked, + checking, + selected, + selecting + }; + using inline_notifier_interface = detail::inline_widget_notifier_interface; // struct essence //@brief: this struct gives many data for listbox, diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 90fdcbdf..98dd3732 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -678,6 +678,16 @@ namespace nana } }; + struct inline_pane + { + ::nana::panel pane_bottom; //pane for pane_widget + ::nana::panel pane_widget; //pane for placing user-define widget + std::unique_ptr inline_ptr; + inline_indicator * indicator; + index_pair item_pos; //The item index of the inline widget + std::size_t column_pos; + }; + class es_lister { public: @@ -726,6 +736,37 @@ namespace nana std::string to_string(const export_options& exp_opt) const; + inline_pane * get_inline_pane(const index_pair& item_pos) + { + for (auto p : active_panes_) + { + if (p && (p->item_pos == item_pos)) + return p; + } + return nullptr; + } + + void emit_checked(index_pair pos) + { + item_proxy i(ess_, pos); + arg_listbox arg{ i }; + wd_ptr()->events().checked.emit(arg, wd_ptr()->handle()); + + auto pane = get_inline_pane(pos); + if (pane) + pane->inline_ptr->notify_status(inline_widget_status::checking, i.checked()); + } + + void emit_selected(index_pair pos) + { + item_proxy i(ess_, pos); + arg_listbox arg{ i }; + wd_ptr()->events().selected.emit(arg, wd_ptr()->handle()); + + auto pane = get_inline_pane(pos); + if (pane) + pane->inline_ptr->notify_status(inline_widget_status::selecting, i.selected()); + } // Definition is provided after struct essence unsigned column_content_pixels(size_type pos) const; @@ -1121,6 +1162,14 @@ namespace nana return get(pos.cat)->items.at(index); } + void append_active_panes(inline_pane* p) + { + if (nullptr == p) + active_panes_.clear(); + else + active_panes_.push_back(p); + } + // Removes all items of a specified category // It throws when the category is out of range or has an immutable model. void clear(size_type cat) @@ -1463,9 +1512,7 @@ namespace nana if(m.flags.checked != ck) { m.flags.checked = ck; - - arg_listbox arg{ item_proxy{ess_, pos}}; - wd_ptr()->events().checked.emit(arg, wd_ptr()->handle()); + emit_checked(pos); } ++pos.item; } @@ -1531,8 +1578,7 @@ namespace nana changed = true; m.flags.selected = sel; - arg_listbox arg{ item_proxy(ess_, i) }; - wd_ptr()->events().selected.emit(arg, wd_ptr()->handle()); + this->emit_selected(i); if (m.flags.selected) last_selected_abs = i; @@ -1622,18 +1668,17 @@ namespace nana return (for_selection ? m.flags.selected : m.flags.checked); }; - auto do_cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos) + auto do_cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos) { - arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) }; if (for_selection) { m.flags.selected = false; - widget_->events().selected.emit(arg, widget_->handle()); + this->emit_selected(item_pos); } else { m.flags.checked = false; - widget_->events().checked.emit(arg, widget_->handle()); + this->emit_checked(item_pos); } }; @@ -1645,7 +1690,7 @@ namespace nana for (auto & m : i->items) { if ((item_pos != except.item) && pred(m)) - do_cancel(m, except.cat, item_pos); + do_cancel(m, index_pair{ except.cat, item_pos }); ++item_pos; } @@ -1661,7 +1706,7 @@ namespace nana for (auto & m : cat.items) { if (pred(m)) - do_cancel(m, cat_pos, item_pos); + do_cancel(m, index_pair{ cat_pos, item_pos }); ++item_pos; } } @@ -1671,7 +1716,7 @@ namespace nana for (auto & m : cat.items) { if ((item_pos != except.item) && pred(m)) - do_cancel(m, cat_pos, item_pos); + do_cancel(m, index_pair{ cat_pos, item_pos }); ++item_pos; } } @@ -1705,18 +1750,17 @@ namespace nana return (for_selection ? m.flags.selected : m.flags.checked); }; - auto cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos) + auto cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos) { - arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) }; if (for_selection) { m.flags.selected = false; - widget_->events().selected.emit(arg, widget_->handle()); + this->emit_selected(item_pos); } else { m.flags.checked = false; - widget_->events().checked.emit(arg, widget_->handle()); + this->emit_checked(item_pos); } }; @@ -1732,7 +1776,7 @@ namespace nana for (auto end = cat.items.end(); i != end; ++i) { if (pred(*i)) - cancel(*i, cat_pos, i - cat.items.begin()); + cancel(*i, index_pair{ cat_pos, static_cast(i - cat.items.begin()) }); } } ++cat_pos; @@ -1755,7 +1799,7 @@ namespace nana for (++i; i != end; ++i) { if (pred(*i)) - cancel(*i, cat_pos, i - cat.items.begin()); + cancel(*i, index_pair{ cat_pos, static_cast(i - cat.items.begin()) }); } } } @@ -1767,7 +1811,7 @@ namespace nana for (auto & m : cat.items) { if (pred(m)) - cancel(m, cat_pos, item_pos); + cancel(m, index_pair{ cat_pos, item_pos }); ++item_pos; } @@ -1814,10 +1858,7 @@ namespace nana if(m.flags.checked != ck) { m.flags.checked = ck; - - arg_listbox arg{ item_proxy(ess_, index_pair(cat, index)) }; - wd_ptr()->events().checked.emit(arg, widget_->handle()); - + this->emit_checked(index_pair{cat, index}); changed = true; } ++index; @@ -2088,6 +2129,8 @@ namespace nana bool single_selection_category_limited_{ false }; bool single_check_{ false }; bool single_check_category_limited_{ false }; + + std::vector active_panes_; };//end class es_lister @@ -2097,6 +2140,8 @@ namespace nana enum class item_state{normal, highlighted, pressed, grabbed, floated}; enum class parts{unknown = -1, header, lister, checker}; + using inline_pane = inline_pane; + ::nana::listbox* listbox_ptr{nullptr}; ::nana::listbox::scheme_type* scheme_ptr{nullptr}; ::nana::paint::graphics *graph{nullptr}; @@ -2131,16 +2176,6 @@ namespace nana }scroll; - struct inline_pane - { - ::nana::panel pane_bottom; //pane for pane_widget - ::nana::panel pane_widget; //pane for placing user-define widget - std::unique_ptr inline_ptr; - inline_indicator * indicator; - index_pair item_pos; //The item index of the inline widget - std::size_t column_pos; - }; - std::map>> inline_table, inline_buffered_table; essence() @@ -3010,6 +3045,11 @@ namespace nana return *ess_->lister.wd_ptr(); } + std::size_t column() const override + { + return column_pos_; + } + void modify(index_type pos, const value_type& value) const override { ess_->lister.throw_if_immutable_model(pos); @@ -3533,15 +3573,19 @@ namespace nana public: using item_state = essence::item_state; using parts = essence::parts; + using status_type = inline_notifier_interface::status_type; drawer_lister_impl(essence * es) :essence_(es) {} - void draw(const nana::rectangle& rect) const + void draw(const nana::rectangle& rect) { internal_scope_guard lock; + //clear active panes + essence_->lister.append_active_panes(nullptr); + //The count of items to be drawn auto item_count = essence_->number_of_lister_items(true); if (0 == item_count) @@ -3724,7 +3768,7 @@ namespace nana nana::color bgcolor, nana::color fgcolor, item_state state - ) const + ) { auto & item = cat.items[item_pos.item]; @@ -3838,15 +3882,19 @@ namespace nana else visible_state = false; - ::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height }; - inline_wdg->pane_widget.size(sz); - inline_wdg->inline_ptr->resize(sz); draw_column = inline_wdg->inline_ptr->whether_to_draw(); inline_wdg->item_pos = item_pos; inline_wdg->column_pos = column_pos; inline_wdg->inline_ptr->activate(*inline_wdg->indicator, item_pos); + + ::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height }; + inline_wdg->pane_widget.size(sz); + inline_wdg->inline_ptr->resize(sz); + + inline_wdg->inline_ptr->notify_status(status_type::selected, item.flags.selected); + inline_wdg->inline_ptr->notify_status(status_type::checked, item.flags.checked); inline_wdg->indicator->attach(item_pos, inline_wdg); @@ -3857,6 +3905,8 @@ namespace nana inline_wdg->inline_ptr->set({}); API::show_window(inline_wdg->pane_bottom, visible_state); + + essence_->lister.append_active_panes(inline_wdg); } } @@ -4191,14 +4241,12 @@ namespace nana { item_ptr->flags.selected = sel; - arg_listbox arg{ item_proxy{ essence_, abs_item_pos } }; - lister.wd_ptr()->events().selected.emit(arg, lister.wd_ptr()->handle()); + lister.emit_selected(abs_item_pos); if (item_ptr->flags.selected) { lister.cancel_others_if_single_enabled(true, abs_item_pos); essence_->lister.last_selected_abs = abs_item_pos; - } else if (essence_->lister.last_selected_abs == abs_item_pos) essence_->lister.last_selected_abs.set_both(npos); @@ -4213,8 +4261,7 @@ namespace nana { item_ptr->flags.checked = ! item_ptr->flags.checked; - arg_listbox arg{ item_proxy{ essence_, abs_item_pos } }; - lister.wd_ptr()->events().checked.emit(arg, lister.wd_ptr()->handle()); + lister.emit_checked(abs_item_pos); if (item_ptr->flags.checked) lister.cancel_others_if_single_enabled(false, abs_item_pos); @@ -4479,12 +4526,13 @@ namespace nana item_proxy & item_proxy::check(bool ck) { + internal_scope_guard lock; auto & m = cat_->items.at(pos_.item); if(m.flags.checked != ck) { m.flags.checked = ck; - arg_listbox arg{*this}; - ess_->lister.wd_ptr()->events().checked.emit(arg, ess_->lister.wd_ptr()->handle()); + ess_->lister.emit_checked(pos_); + ess_->update(); } return *this; @@ -4498,13 +4546,14 @@ namespace nana /// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected item_proxy & item_proxy::select(bool s) { + internal_scope_guard lock; + //pos_ never represents a category if this item_proxy is available. auto & m = cat_->items.at(pos_.item); // a ref to the real item if(m.flags.selected == s) return *this; // ignore if no change m.flags.selected = s; // actually change selection - arg_listbox arg{*this}; - ess_->lister.wd_ptr()->events().selected.emit(arg, ess_->lister.wd_ptr()->handle()); + ess_->lister.emit_selected(this->pos_); if (m.flags.selected) {