diff --git a/include/nana/stdc++.hpp b/include/nana/stdc++.hpp index fc2d6568..8730d806 100644 --- a/include/nana/stdc++.hpp +++ b/include/nana/stdc++.hpp @@ -1,7 +1,7 @@ /** * Standard Library for C++11/14/17 * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 863c4a6d..d5e71b54 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -725,6 +725,13 @@ namespace nana std::size_t column_pos; }; + enum class view_action + { + auto_view, + top_view, + bottom_view, + }; + class es_lister { public: @@ -980,7 +987,12 @@ namespace nana return prstatus; } - void scroll(const index_pair& abs_pos, bool to_bottom); +#if 0 + void scroll(const index_pair& abs_pos, bool to_bottom); //deprecated +#endif + + /// Scroll the selected item into the view + void scroll_into_view(const index_pair& abs_pos, view_action vw_act); /// Append a new category with a specified name and return a pointer to it. category_t* create_cat(native_string_type&& text) @@ -1681,7 +1693,7 @@ namespace nana ///typeface()); + unsigned as, ds, ileading; + graph.text_metrics(as, ds, ileading); + + max_font_px = (std::max)(as + ds, max_font_px); + } + return max_font_px; } @@ -2920,7 +2942,8 @@ namespace nana std::vector> panes_; }; - void es_lister::scroll(const index_pair& abs_pos, bool to_bottom) +#if 0 + void es_lister::scroll(const index_pair& abs_pos, bool to_bottom) //deprecated { auto& cat = *get(abs_pos.cat); @@ -2964,6 +2987,63 @@ namespace nana if(ess_->content_view->move_origin(origin - ess_->content_view->origin())) ess_->content_view->sync(false); } +#endif + + void es_lister::scroll_into_view(const index_pair& abs_pos, view_action vw_act) + { + auto& cat = *get(abs_pos.cat); + + if ((abs_pos.item != nana::npos) && (abs_pos.item >= cat.items.size())) + throw std::invalid_argument("listbox: invalid pos to scroll"); + + if (!cat.expand) + { + this->expand(abs_pos.cat, true); + ess_->calc_content_size(); + } + else if (!ess_->auto_draw) + { + //force a update of content size and scrollbar status when auto_draw is false to make + //sure that the scroll function works fine. + ess_->calc_content_size(); + } + + auto origin = ess_->content_view->origin(); + + auto off = this->distance(this->first(), this->index_cast(abs_pos, false)) * ess_->item_height(); + + auto screen_px = ess_->content_view->view_area().height; + + if (view_action::auto_view == vw_act) + { + if (static_cast(off) < origin.y) + vw_act = view_action::top_view; + else if (static_cast(off) >= static_cast(origin.y + ess_->content_view->view_area().height)) + vw_act = view_action::bottom_view; + else + return; + } + + origin.y = 0; + + if (view_action::bottom_view == vw_act) + { + off += ess_->item_height(); + if (off >= screen_px) + origin.y = static_cast(off - screen_px); + } + else + { + auto last_off = this->distance(this->first(), this->last()) * ess_->item_height(); + if (last_off - off >= screen_px) + origin.y = static_cast(off); + else if (last_off >= screen_px) + origin.y = static_cast(last_off - screen_px); + } + + if (ess_->content_view->move_origin(origin - ess_->content_view->origin())) + ess_->content_view->sync(false); + } void es_lister::erase(const index_pair& pos) { @@ -2983,7 +3063,7 @@ namespace nana } } - void es_lister::move_select(bool upwards, bool unselect_previous, bool /*trace_selected*/) noexcept + void es_lister::move_select(bool upwards, bool unselect_previous, bool into_view) noexcept { auto next_selected_dpl = index_cast_noexcpt(latest_selected_abs, false); //convert absolute position to display position @@ -3063,6 +3143,9 @@ namespace nana } else break; } + + if (into_view && !latest_selected_abs.empty()) + this->scroll_into_view(latest_selected_abs, view_action::auto_view); } std::string es_lister::to_string(const export_options& exp_opt) const @@ -4469,7 +4552,7 @@ namespace nana //Check if it scrolls in current screen window //condition: top of target item is not less than top edge of content view and //the bottom of target item is not greater than bottom edge of content view. - if ((screen_top + item_px <= logic_top) && (logic_top + item_px + item_px <= screen_bottom)) + if ((screen_top + static_cast(item_px) <= logic_top) && (logic_top + static_cast(item_px) + static_cast(item_px) <= screen_bottom)) { int offset = (static_cast(upward ? screen_top : screen_bottom - item_px) - logic_top) / static_cast(item_px); target_idx = list.advance(init_idx, offset); @@ -4561,8 +4644,11 @@ namespace nana } else item_proxy::from_display(essence_, pos).select(true); + + list.scroll_into_view(pos, view_action::auto_view); } } + } break; default: @@ -4658,7 +4744,7 @@ namespace nana ess_->lister.get(pos_.cat)->expand = false; if (!this->displayed()) - ess_->lister.scroll(pos_, !(ess_->first_display() > this->to_display())); + ess_->lister.scroll_into_view(pos_, (ess_->first_display() > this->to_display() ? view_action::top_view : view_action::bottom_view)); } ess_->update(); @@ -4696,7 +4782,7 @@ namespace nana ess_->lister.latest_selected_abs.set_both(npos); if (scroll_view && (!this->displayed())) - ess_->lister.scroll(pos_, !(ess_->first_display() > this->to_display())); + ess_->lister.scroll_into_view(pos_, (ess_->first_display() > this->to_display() ? view_action::top_view : view_action::bottom_view)); ess_->update(); return *this; @@ -5364,13 +5450,13 @@ namespace nana else pos.item = ess.lister.size_item(cat_pos) ? 0 : ::nana::npos; - ess.lister.scroll(pos, to_bottom); - ess.update(); + this->scroll(to_bottom, pos); } void listbox::scroll(bool to_bottom, const index_pair& abs_pos) { - _m_ess().lister.scroll(abs_pos, to_bottom); + using view_action = drawerbase::listbox::view_action; + _m_ess().lister.scroll_into_view(abs_pos, (to_bottom ? view_action::bottom_view : view_action::top_view)); _m_ess().update(); } @@ -5742,7 +5828,7 @@ namespace nana void listbox::move_select(bool upwards) ///