From 7cb27951e0fd2829c18b11e7e6ca22c5be4db87f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 30 Sep 2015 17:09:55 +0800 Subject: [PATCH] fix 2 listbox issues inline widget modifies a wrong item when the listbox is sorted a crash issue when erasing the last item if the listbox is sorted --- source/gui/widgets/listbox.cpp | 203 ++++++++++++--------------------- 1 file changed, 75 insertions(+), 128 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index c9402b8c..422f778a 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -438,14 +438,6 @@ namespace nana return pixels; } - /* - /// return the original order or index previous to any list reorganization of the current column "n". - size_type index(size_type n) const //deprecated - { - return (n < cont_.size() ? cont_[n].index : npos); - } - */ - const container& cont() const { return cont_; @@ -565,19 +557,6 @@ namespace nana return; } } - /* - auto i = std::find_if(cont_.begin(), cont_.end(), [index](container::value_type& m){return (index == m.index);}); //deprecated - - if (i == cont_.end()) - return; - - column_t from = std::move(*i); //move - cont_.erase(i); - - i = std::find_if(cont_.begin(), cont_.end(), [to](const container::value_type& m)->bool{ return (to == m.index); } ); - if(i != cont_.end()) - cont_.insert((front ? i : ++i), from); - */ } private: bool visible_{true}; @@ -961,6 +940,11 @@ namespace nana return *(_m_at(cat_pos)); } + category_t::container::value_type& at_abs(const index_pair& pos) + { + return _m_at(pos.cat)->items.at(pos.item); + } + /// 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) { @@ -1142,16 +1126,7 @@ namespace nana } } - void erase(const index_pair& pos) - { - auto & catobj = *_m_at(pos.cat); - if(pos.item < catobj.items.size()) - { - catobj.items.erase(catobj.items.begin() + pos.item); - catobj.sorted.erase(std::find(catobj.sorted.begin(), catobj.sorted.end(), catobj.items.size())); - sort(); - } - } + void erase(const index_pair& pos); void erase(size_type cat) { @@ -1709,37 +1684,40 @@ namespace nana auto & catobj = *_m_at(display_pos.cat); - if(catobj.items.size()==0) + if(catobj.items.empty()) return (display_pos == index_pair{0,0} ? 0 : npos); - return catobj.sorted[display_pos.item] ; + return (display_pos.item < catobj.sorted.size() ? catobj.sorted[display_pos.item] : npos); } index_pair absolute_pair(const index_pair& display_pos) const { - return {display_pos.cat, absolute( display_pos )}; + //Returns an empty pos if item pos npos + auto item_pos = absolute(display_pos); + return {item_pos != npos ? display_pos.cat : npos, item_pos}; } ///Translate absolute position (original data order) into relative position (position in display) size_type relative(const index_pair& pos) const { if (sorted_index_ == npos) - return pos.item ; + return pos.item ; - auto & catobj = *_m_at(pos.cat); + auto & catobj = *_m_at(pos.cat); - for (size_type i=0; i 0 ? npos : 0); - scroll.offset_y_dpl = scroll.offset_y_abs ; - return ; - } - scroll_y_dpl_refresh() ; + { + scroll.offset_y_abs.item = (pos_abs.cat > 0 ? npos : 0); + scroll.offset_y_dpl = scroll.offset_y_abs ; + return ; + } + scroll_y_dpl_refresh() ; } void scroll_y_rel(const index_pair& pos_rel) { - scroll_y_abs(lister.relative_pair(pos_rel) ); + scroll_y_abs(lister.relative_pair(pos_rel) ); } - void set_scroll_y_abs(const index_pair& pos_abs) - { - scroll.offset_y_abs=pos_abs; - scroll_y_dpl_refresh() ; - } - /// directly set a tested relative display pos + /// directly set a tested relative display pos void set_scroll_y_dpl(const index_pair& pos_dpl) - { - scroll.offset_y_dpl=pos_dpl; - scroll.offset_y_abs = lister.absolute_pair(pos_dpl); - } + { + scroll.offset_y_dpl = pos_dpl; + scroll.offset_y_abs = lister.absolute_pair(pos_dpl); + + if (scroll.offset_y_abs.empty()) + throw std::invalid_argument("nana.listbox.set_scroll_y_dpl's exception is due to invalid item, please report a bug"); + } //number_of_lister_item @@ -2038,15 +2014,6 @@ namespace nana trace_item_abs(lister.last_selected_abs); } - /* - void trace_first_selected_item() //deprecated - { - auto fs=lister.find_first_selected(); - if( ! fs.empty() ) - trace_item_abs( fs ); - } - */ - void update() { if(auto_draw && lister.wd_ptr()) @@ -2374,6 +2341,7 @@ namespace nana auto ptr = pane_ptr.get(); inline_table[factory].emplace_back(std::move(pane_ptr)); + ptr->inline_ptr->whether_to_draw(); return ptr; } }; @@ -2396,12 +2364,15 @@ namespace nana void modify(index_type pos, const value_type& value) const override { - auto & cells = ess_->lister.at(pos).cells; + auto & cells = ess_->lister.at_abs(pos).cells; if (cells.size() <= column_pos_) cells.resize(column_pos_ + 1); - cells[column_pos_].text = value; - ess_->update(); + if (cells[column_pos_].text != value) + { + cells[column_pos_].text = value; + ess_->update(); + } } void selected(index_type pos) override @@ -2428,6 +2399,18 @@ namespace nana const std::size_t column_pos_; }; + void es_lister::erase(const index_pair& pos) + { + auto & catobj = *_m_at(pos.cat); + if (pos.item < catobj.items.size()) + { + catobj.items.erase(catobj.items.begin() + pos.item); + catobj.sorted.erase(std::find(catobj.sorted.begin(), catobj.sorted.end(), catobj.items.size())); + + sort(); + } + } + void es_lister::scroll_refresh() { ess_->scroll_y_dpl_refresh(); @@ -2639,8 +2622,6 @@ namespace nana void draw(const nana::rectangle& r) { - //_m_draw(essence_->header.cont(), r); //deprecated - graph_reference graph = *(essence_->graph); int text_top = (r.height - essence_->text_height) / 2 + r.y; @@ -2716,44 +2697,6 @@ namespace nana } return npos; } - /* - template - void _m_draw(const Container& cont, const nana::rectangle& rect) //deprecated - { - graph_reference graph = *(essence_->graph); - - int txtop = (rect.height - essence_->text_height) / 2 + rect.y; - auto txtcolor = essence_->lister.wd_ptr()->fgcolor(); - - auto state = item_state::normal; - //check whether grabing an item, if item_spliter_ != npos, that indicates the grab item is a spliter. - if(essence_->pointer_where.first == parts::header && (item_spliter_ == npos)) - state = essence_->ptr_state; - - const unsigned height = rect.height - 1; - const int bottom_y = rect.bottom() - 2; - int x = rect.x - essence_->scroll.offset_x; - for(auto & i: cont) - { - if(i.visible) - { - int next_x = x + static_cast(i.pixels); - if(next_x > rect.x) - { - _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()); - } - - x = next_x; - if (x > rect.right()) - break; - } - } - - if (x < rect.right()) - graph.rectangle({ x, rect.y, static_cast(rect.right() - x), height }, true, essence_->scheme_ptr->header_bgcolor); - } - */ template 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) @@ -3226,13 +3169,6 @@ namespace nana delete essence_; } - /* - essence_t& trigger::essence() //deprecated - { - return *essence_; - } - */ - essence_t& trigger::essence() const { return *essence_; @@ -4411,18 +4347,29 @@ namespace nana auto * ess = ip._m_ess(); auto _where = ip.pos(); + + auto pos_before = ess->scroll_y_dpl(); ess->lister.erase(_where); auto pos = ess->scroll_y_dpl(); - if((pos.cat == _where.cat) && (_where.item <= pos.item)) + if (!pos.empty()) { - if(pos.item == 0) + if ((pos.cat == _where.cat) && (_where.item <= pos.item)) { - if(ess->lister.size_item(_where.cat) == 0) - pos.item = (pos.cat > 0 ? npos : 0); + if (pos.item == 0) + { + if (ess->lister.size_item(_where.cat) == 0) + pos.item = (pos.cat > 0 ? npos : 0); + } + else + --pos.item; + ess->set_scroll_y_dpl(pos); } - else - --pos.item; - ess->set_scroll_y_dpl(pos); + } + else + { + if (pos_before.item) + --pos_before.item; + ess->set_scroll_y_dpl(pos_before); } ess->update(); if(_where.item < ess->lister.size_item(_where.cat))