From 0c7e8a8ca2198fb7e35c811d2b60856bae57d79f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 21 Apr 2018 03:49:15 +0800 Subject: [PATCH] add scroll_operation_interface --- include/nana/gui/basis.hpp | 13 ++ include/nana/gui/widgets/listbox.hpp | 1 + .../gui/widgets/skeletons/text_editor.hpp | 4 +- include/nana/gui/widgets/textbox.hpp | 3 +- include/nana/gui/widgets/treebox.hpp | 5 +- include/nana/gui/widgets/widget.hpp | 5 +- source/gui/widgets/listbox.cpp | 209 ++++++------------ source/gui/widgets/skeletons/content_view.cpp | 143 ++++++++---- source/gui/widgets/skeletons/content_view.hpp | 7 +- source/gui/widgets/skeletons/text_editor.cpp | 7 +- source/gui/widgets/textbox.cpp | 12 +- source/gui/widgets/treebox.cpp | 40 +++- source/gui/widgets/widget.cpp | 12 +- 13 files changed, 258 insertions(+), 203 deletions(-) diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index cc31f862..4153d439 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -297,6 +297,19 @@ that return a corresponding nana::appearance with predefined values. virtual bool visible() const = 0; };//end class caret_interface + /// Interface for scroll operations + /** + * This interface provides methods to operate the scrollbars that are contained + * in a specific widget, such as listbox and treebox + */ + class scroll_operation_interface + { + public: + virtual ~scroll_operation_interface() = default; + + virtual bool visible(bool vert) const = 0; + }; + namespace parameters { /// The system-wide parameters for mouse wheel diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 0202d028..3f2caab6 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1541,6 +1541,7 @@ the nana::detail::basic_window member pointer scheme nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const override; drawerbase::listbox::category_t* _m_assoc(std::shared_ptr, bool create_if_not_exists); void _m_erase_key(nana::detail::key_interface*) noexcept; + std::shared_ptr _m_scroll_operation(); }; }//end namespace nana diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index a2ab3ea7..d3536182 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -1,7 +1,7 @@ /* * A text editor implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -219,6 +219,8 @@ namespace nana{ namespace widgets const skeletons::textbase& textbase() const; bool try_refresh(); + + std::shared_ptr scroll_operation() const; private: nana::color _m_draw_colored_area(paint::graphics& graph, const std::pair& row, bool whole_line); std::vector _m_render_text(const ::nana::color& text_color); diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 5f6dbc91..de70728c 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -1,7 +1,7 @@ /** * A Textbox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -279,6 +279,7 @@ namespace nana native_string_type _m_caption() const throw() override; void _m_caption(native_string_type&&) override; void _m_typeface(const paint::font&) override; + std::shared_ptr _m_scroll_operation() const; }; }//end namespace nana #include diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 08548dd4..75be5da0 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -1,7 +1,7 @@ /** * A Tree Box Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at @@ -445,6 +445,9 @@ namespace nana item_proxy selected() const; ///< returns the selected node + private: + std::shared_ptr _m_scroll_operation() const; + };//end class treebox }//end namespace nana diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index 0ee37703..10a3e352 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -1,7 +1,7 @@ /** * The fundamental widget class implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -83,6 +83,8 @@ namespace nana void focus(); bool focused() const; + std::shared_ptr scroll_operation(); + void show(); ///< Sets the window visible. void hide(); ///< Sets the window invisible. bool visible() const; @@ -137,6 +139,7 @@ namespace nana virtual void _m_close(); virtual bool _m_enabled() const; virtual void _m_enabled(bool); + virtual std::shared_ptr _m_scroll_operation(); virtual bool _m_show(bool); virtual bool _m_visible() const; virtual void _m_size(const nana::size&); diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index d26143ea..7bdfc2b6 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -797,8 +797,8 @@ namespace nana void emit_cs(const index_pair& pos, bool for_selection) { - item_proxy i(ess_, pos); - arg_listbox arg{ i }; + item_proxy item(ess_, pos); + arg_listbox arg{ item }; auto & events = wd_ptr()->events(); @@ -813,9 +813,9 @@ namespace nana if (p && (p->item_pos == pos)) { if (for_selection) - p->inline_ptr->notify_status(inline_widget_status::selecting, i.selected()); + p->inline_ptr->notify_status(inline_widget_status::selecting, item.selected()); else - p->inline_ptr->notify_status(inline_widget_status::checking, i.checked()); + p->inline_ptr->notify_status(inline_widget_status::checking, item.checked()); } } } @@ -954,7 +954,7 @@ namespace nana */ bool sort_column(std::size_t pos, const bool * reverse) { - if (npos == pos) + if (nana::npos == pos) { sort_attrs_.column = npos; return false; @@ -992,22 +992,12 @@ namespace nana return prstatus; } -#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) - { - categories_.emplace_back(std::move(text)); - return &categories_.back(); - } /// will use the key to insert new cat before the first cat with compare less than the key, or at the end of the list of cat and return a ref to that new cat. ? - category_t* create_cat(std::shared_ptr& ptr) + category_t* create_category(std::shared_ptr& ptr) { //A workaround for old version of libstdc++ //Some operations of vector provided by libstdc++ don't accept const iterator. @@ -1038,9 +1028,15 @@ namespace nana return &(categories_.back()); } - /// add a new cat created at "pos" and return a ref to it - category_t* create_cat(std::size_t pos, native_string_type&& text) + /// Inserts a new category at position specified by pos + category_t* create_category(native_string_type&& text, std::size_t pos = nana::npos) { + if (::nana::npos == pos) + { + categories_.emplace_back(std::move(text)); + return &categories_.back(); + } + return &(*categories_.emplace(this->get(pos), std::move(text))); } @@ -1094,22 +1090,13 @@ namespace nana */ index_pair index_cast(const index_pair& from, bool from_display_order) const { - auto cat = get(from.cat); - if (from.item < cat->sorted.size()) - { - if (from_display_order) - return index_pair{ from.cat, static_cast(cat->sorted[from.item]) }; - - for (size_type i = 0; i < cat->sorted.size(); ++i) - { - if (from.item == cat->sorted[i]) - return index_pair{ from.cat, i }; - } - } - throw std::out_of_range("listbox: invalid item position"); + auto target = index_cast_noexcept(from, from_display_order); + if (target.empty()) + throw std::out_of_range("listbox: invalid element position"); + return target; } - index_pair index_cast_noexcpt(const index_pair& from, bool from_display_order, const index_pair& default_value = index_pair{npos, npos}) const noexcept + index_pair index_cast_noexcept(const index_pair& from, bool from_display_order, const index_pair& default_value = index_pair{npos, npos}) const noexcept { if (from.cat < categories_.size()) { @@ -1677,11 +1664,19 @@ namespace nana } /// return absolute positions, no relative to display - index_pairs pick_items(bool for_selection, bool find_first = false) const + /** + * @param for_selection Indicates whether the selected items or checked items to be returned. + * @param find_first Indicates whether or not to return the first item which + * @param items_status a pointer refers to a bool object to receive the status whethe the picked items are all selected or all checked, in contrast to for_selection + */ + index_pairs pick_items(bool for_selection, bool find_first = false, bool * items_status = nullptr) const { index_pairs results; index_pair id; + if (items_status) + *items_status = true; + for (auto & cat : categories_) { id.item = 0; @@ -1689,6 +1684,9 @@ namespace nana { if (for_selection ? m.flags.selected : m.flags.checked) { + if (items_status && *items_status) + *items_status = (for_selection ? m.flags.checked : m.flags.selected); + results.push_back(id); // absolute positions, no relative to display if (find_first) return results; @@ -1700,31 +1698,6 @@ namespace nana return results; } - /// return absolute positions, no relative to display - bool item_selected_all_checked(index_pairs& vec) const - { - index_pair id; - bool ck = true; - - for (auto & cat : categories_) - { - id.item = 0; - for (auto & m : cat.items) - { - if (m.flags.selected) - { - vec.push_back(id); // absolute positions, no relative to display - ck &= m.flags.checked; - } - ++id.item; - } - ++id.cat; - } - - //Just returns true when the all selected items are checked. - return ck; - } - /// header_seq(unsigned lister_w) const + std::vector ordered_columns(unsigned lister_w) const { std::vector seqs; int x = -content_view->origin().x; @@ -2496,10 +2469,12 @@ namespace nana x += col.width_px; if (x > 0) - seqs.push_back(col.index); + { + if (x >= static_cast(lister_w)) + break; - if (x >= static_cast(lister_w)) - break; + seqs.push_back(col.index); + } } return seqs; } @@ -2965,53 +2940,6 @@ namespace nana std::vector> panes_; }; -#if 0 - void es_lister::scroll(const index_pair& abs_pos, bool to_bottom) //deprecated - { - 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(); - origin.y = 0; - - 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 (to_bottom) - { - 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); - } -#endif - void es_lister::scroll_into_view(const index_pair& abs_pos, view_action vw_act) { auto& cat = *get(abs_pos.cat); @@ -3088,7 +3016,7 @@ namespace nana 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 + auto next_selected_dpl = index_cast_noexcept(latest_selected_abs, false); //convert absolute position to display position if (next_selected_dpl.empty()) // has no cat ? (cat == npos) => beging from first cat { @@ -3274,15 +3202,13 @@ namespace nana { if(col.visible_state) { - auto col_pixels = static_cast(col.width_px); - - if ((col_pixels < x + static_cast(essence_->scheme_ptr->header_splitter_area_before)) - && (x < col_pixels + static_cast(essence_->scheme_ptr->header_splitter_area_after))) + if ((static_cast(col.width_px) < x + static_cast(essence_->scheme_ptr->header_splitter_area_before)) + && (x < static_cast(col.width_px) + static_cast(essence_->scheme_ptr->header_splitter_area_after))) { grabs_.splitter = col.index; // original index return true; } - x -= col_pixels; + x -= static_cast(col.width_px); } } } @@ -3637,12 +3563,12 @@ namespace nana hoverred_pos = lister.advance(first_disp, static_cast(ptr_where.second)); } - auto subitems = essence_->header_seq(rect.width); + auto const columns = essence_->ordered_columns(rect.width); - if (subitems.empty()) + if (columns.empty()) return; - int txtoff = essence_->scheme_ptr->item_height_ex / 2; + auto const txtoff = static_cast(essence_->scheme_ptr->item_height_ex) / 2; auto i_categ = lister.get(first_disp.cat); @@ -3672,7 +3598,7 @@ namespace nana auto item_pos = lister.index_cast(index_pair{ idx.cat, offs }, true); //convert display position to absolute position - _m_draw_item(*i_categ, item_pos, item_coord, txtoff, header_w, rect, subitems, bgcolor, fgcolor, + _m_draw_item(*i_categ, item_pos, item_coord, txtoff, header_w, rect, columns, bgcolor, fgcolor, (hoverred_pos == idx ? item_state::highlighted : item_state::normal) ); @@ -3706,7 +3632,7 @@ namespace nana auto item_pos = lister.index_cast(index_pair{ idx.cat, pos }, true); //convert display position to absolute position - _m_draw_item(*i_categ, item_pos, item_coord, txtoff, header_w, rect, subitems, bgcolor, fgcolor, + _m_draw_item(*i_categ, item_pos, item_coord, txtoff, header_w, rect, columns, bgcolor, fgcolor, (idx == hoverred_pos ? item_state::highlighted : item_state::normal) ); @@ -3729,7 +3655,7 @@ namespace nana } //Draw mouse selection - //Check if the mouse selection box is present. + //Check if the mouse selection box presents. if (essence_->mouse_selection.begin_position != essence_->mouse_selection.end_position) { point box_position{ @@ -4297,7 +4223,7 @@ namespace nana { auto * item_ptr = (item_pos.is_category() ? nullptr : &lister.at(item_pos)); - const auto abs_item_pos = lister.index_cast_noexcpt(item_pos, true, item_pos); //convert display position to absolute position + const auto abs_item_pos = lister.index_cast_noexcept(item_pos, true, item_pos); //convert display position to absolute position if(ptr_where.first == parts::list) { @@ -4549,10 +4475,11 @@ namespace nana break; case L' ': { - index_pairs s; - bool ck = ! list.item_selected_all_checked(s); - for(auto i : s) - item_proxy(essence_, i).check(ck); + bool items_checked{ false }; + auto items = list.pick_items(true, false, &items_checked); + items_checked = !items_checked; + for (auto i : items) + item_proxy(essence_, i).check(items_checked); } break; case keyboard::os_pageup : @@ -4601,10 +4528,7 @@ namespace nana target_idx = list.last(); origin.y = static_cast((list.distance(list.first(), target_idx) + 1) * item_px); - if (origin.y >= static_cast(screen_bottom - screen_top)) - origin.y -= static_cast(screen_bottom - screen_top); - else - origin.y = 0; + origin.y = (std::max)(origin.y - static_cast(screen_bottom - screen_top), 0); } essence_->content_view->move_origin(origin - essence_->content_view->origin()); @@ -5514,7 +5438,7 @@ namespace nana { internal_scope_guard lock; auto & ess = _m_ess(); - auto new_cat_ptr = ess.lister.create_cat(to_nstring(std::move(s))); + auto new_cat_ptr = ess.lister.create_category(to_nstring(std::move(s))); ess.update(); return cat_proxy{ &ess, new_cat_ptr }; @@ -5524,7 +5448,7 @@ namespace nana { internal_scope_guard lock; auto & ess = _m_ess(); - auto new_cat_ptr = ess.lister.create_cat(to_nstring(std::move(s))); + auto new_cat_ptr = ess.lister.create_category(to_nstring(std::move(s))); ess.update(); return cat_proxy{ &ess, new_cat_ptr }; } @@ -5535,7 +5459,7 @@ namespace nana auto & ess = _m_ess(); for (auto & arg : categories) - ess.lister.create_cat(native_string_type(to_nstring(arg))); + ess.lister.create_category(native_string_type(to_nstring(arg))); ess.update(); } @@ -5545,7 +5469,7 @@ namespace nana auto & ess = _m_ess(); for (auto & arg : categories) - ess.lister.create_cat(native_string_type(to_nstring(arg))); + ess.lister.create_category(native_string_type(to_nstring(arg))); ess.update(); } @@ -5562,7 +5486,7 @@ namespace nana { internal_scope_guard lock; auto & ess = _m_ess(); - auto new_cat_ptr = ess.lister.create_cat(cat.position(), to_nstring(std::move(str))); + auto new_cat_ptr = ess.lister.create_category(to_nstring(std::move(str)), cat.position()); return cat_proxy{ &ess, new_cat_ptr }; } @@ -5570,7 +5494,7 @@ namespace nana { internal_scope_guard lock; auto & ess = _m_ess(); - auto new_cat_ptr = ess.lister.create_cat(cat.position(), to_nstring(std::move(str))); + auto new_cat_ptr = ess.lister.create_category(to_nstring(std::move(str)), cat.position()); return cat_proxy{ &ess, new_cat_ptr }; } @@ -5915,7 +5839,6 @@ namespace nana return *this; } - drawerbase::listbox::essence & listbox::_m_ess() const { return get_drawer_trigger().ess(); @@ -5945,11 +5868,11 @@ namespace nana if (ess.lister.enable_ordered()) { - cat = ess.lister.create_cat(ptr); + cat = ess.lister.create_category(ptr); } else { - cat = ess.lister.create_cat(native_string_type{}); + cat = ess.lister.create_category(native_string_type{}); cat->key_ptr = ptr; } ess.update(); @@ -5970,5 +5893,11 @@ namespace nana } } } + + std::shared_ptr listbox::_m_scroll_operation() + { + internal_scope_guard lock; + return _m_ess().content_view->scroll_operation(); + } //end class listbox }//end namespace nana diff --git a/source/gui/widgets/skeletons/content_view.cpp b/source/gui/widgets/skeletons/content_view.cpp index b279dc21..b7d8f722 100644 --- a/source/gui/widgets/skeletons/content_view.cpp +++ b/source/gui/widgets/skeletons/content_view.cpp @@ -1,7 +1,7 @@ /* * A Content View Implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2017 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2017-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -19,6 +19,39 @@ namespace nana { namespace widgets { namespace skeletons { + struct cv_scroll_rep + { + content_view::scrolls enabled_scrolls{ content_view::scrolls::both }; + nana::scroll horz; + nana::scroll vert; + + scroll_interface* scroll(arg_wheel::wheel whl) + { + if (arg_wheel::wheel::horizontal == whl) + return &horz; + else if (arg_wheel::wheel::vertical == whl) + return | + return nullptr; + } + }; + + class scroll_operation + : public scroll_operation_interface + { + public: + scroll_operation(std::shared_ptr& impl) + : cv_scroll_(impl) + { + } + private: + bool visible(bool vert) const override + { + return !(vert ? cv_scroll_->vert.empty() : cv_scroll_->horz.empty()); + } + private: + std::shared_ptr const cv_scroll_; + }; + struct content_view::implementation { content_view& view; @@ -35,9 +68,13 @@ namespace nana { bool drag_started{ false }; point origin; - scrolls enabled_scrolls{scrolls::both}; + /* + scrolls enabled_scrolls{scrolls::both}; //deprecated nana::scroll horz; nana::scroll vert; + */ + + std::shared_ptr cv_scroll; timer tmr; @@ -50,9 +87,11 @@ namespace nana { implementation(content_view& v, window handle) : view(v), - window_handle(handle) + window_handle(handle), + cv_scroll(std::make_shared()) { API::events(handle).mouse_wheel.connect_unignorable([this](const arg_wheel& arg) { +#if 0 scroll_interface * scroll = nullptr; switch (arg.which) { @@ -66,6 +105,11 @@ namespace nana { //Other button is not unsupported. return; } +#else + auto const scroll = cv_scroll->scroll(arg.which); + if (nullptr == scroll) + return; +#endif if (!API::empty_window(arg.window_handle)) { @@ -159,11 +203,11 @@ namespace nana { auto speed_horz = 0; if (skew.x) - speed_horz = skew.x / (std::max)(1, static_cast(horz.step())) + (skew.x < 0 ? -1 : 1); + speed_horz = skew.x / (std::max)(1, static_cast(cv_scroll->horz.step())) + (skew.x < 0 ? -1 : 1); auto speed_vert = 0; if (skew.y) - speed_vert = skew.y / (std::max)(1, static_cast(vert.step())) + (skew.y < 0 ? -1 : 1); + speed_vert = skew.y / (std::max)(1, static_cast(cv_scroll->vert.step())) + (skew.y < 0 ? -1 : 1); speed_horz = (std::min)(5, (std::max)(speed_horz, -5)); speed_vert = (std::min)(5, (std::max)(speed_vert, -5)); @@ -180,10 +224,10 @@ namespace nana { //event hander for scrollbars auto event_fn = [this](const arg_scroll& arg) { - if (arg.window_handle == this->vert.handle()) - origin.y = static_cast(this->vert.value()); + if (arg.window_handle == cv_scroll->vert.handle()) + origin.y = static_cast(cv_scroll->vert.value()); else - origin.x = static_cast(this->horz.value()); + origin.x = static_cast(cv_scroll->horz.value()); if (this->events.scrolled) this->events.scrolled(); @@ -194,33 +238,33 @@ namespace nana { this->passive = passive; - bool const vert_allowed = (enabled_scrolls == scrolls::vert || enabled_scrolls == scrolls::both); - bool const horz_allowed = (enabled_scrolls == scrolls::horz || enabled_scrolls == scrolls::both); + bool const vert_allowed = (cv_scroll->enabled_scrolls == scrolls::vert || cv_scroll->enabled_scrolls == scrolls::both); + bool const horz_allowed = (cv_scroll->enabled_scrolls == scrolls::horz || cv_scroll->enabled_scrolls == scrolls::both); if ((imd_area.width != disp_area.width) && vert_allowed) { - if (vert.empty()) + if (cv_scroll->vert.empty()) { - vert.create(window_handle); - vert.events().value_changed.connect_unignorable(event_fn); - API::take_active(vert, false, window_handle); + cv_scroll->vert.create(window_handle); + cv_scroll->vert.events().value_changed.connect_unignorable(event_fn); + API::take_active(cv_scroll->vert, false, window_handle); this->passive = false; } - vert.move({ + cv_scroll->vert.move({ disp_area.x + static_cast(imd_area.width) + skew_vert.x, disp_area.y + skew_vert.y, space(), imd_area.height + extra_px.height }); - vert.amount(content_size.height); - vert.range(imd_area.height); - vert.value(origin.y); + cv_scroll->vert.amount(content_size.height); + cv_scroll->vert.range(imd_area.height); + cv_scroll->vert.value(origin.y); } else { - vert.close(); + cv_scroll->vert.close(); //If vert is allowed, it indicates the vertical origin is not moved //Make sure the v origin is zero @@ -230,28 +274,28 @@ namespace nana { if ((imd_area.height != disp_area.height) && horz_allowed) { - if (horz.empty()) + if (cv_scroll->horz.empty()) { - horz.create(window_handle); - horz.events().value_changed.connect_unignorable(event_fn); - API::take_active(horz, false, window_handle); + cv_scroll->horz.create(window_handle); + cv_scroll->horz.events().value_changed.connect_unignorable(event_fn); + API::take_active(cv_scroll->horz, false, window_handle); this->passive = false; } - horz.move({ + cv_scroll->horz.move({ disp_area.x + skew_horz.x, disp_area.y + static_cast(imd_area.height) + skew_horz.y, imd_area.width + extra_px.width, space() }); - horz.amount(content_size.width); - horz.range(imd_area.width); - horz.value(origin.x); + cv_scroll->horz.amount(content_size.width); + cv_scroll->horz.range(imd_area.width); + cv_scroll->horz.value(origin.x); } else { - horz.close(); + cv_scroll->horz.close(); //If horz is allowed, it indicates the horzontal origin is not moved //Make sure the x origin is zero if (horz_allowed) @@ -279,20 +323,25 @@ namespace nana { bool content_view::enable_scrolls(scrolls which) { - if (impl_->enabled_scrolls == which) + if (impl_->cv_scroll->enabled_scrolls == which) return false; - impl_->enabled_scrolls = which; + impl_->cv_scroll->enabled_scrolls = which; impl_->size_changed(false); return true; } + std::shared_ptr content_view::scroll_operation() const + { + return std::make_shared(impl_->cv_scroll); + } + void content_view::step(unsigned step_value, bool horz) { if (horz) - impl_->horz.step(step_value); + impl_->cv_scroll->horz.step(step_value); else - impl_->vert.step(step_value); + impl_->cv_scroll->vert.step(step_value); } bool content_view::scroll(bool forwards, bool horz) @@ -306,17 +355,17 @@ namespace nana { } if (horz) - return impl_->horz.make_step(forwards, speed); + return impl_->cv_scroll->horz.make_step(forwards, speed); - return impl_->vert.make_step(forwards, speed); + return impl_->cv_scroll->vert.make_step(forwards, speed); } bool content_view::turn_page(bool forwards, bool horz) { if (horz) - return impl_->horz.make_page_scroll(forwards); + return impl_->cv_scroll->horz.make_page_scroll(forwards); else - return impl_->vert.make_page_scroll(forwards); + return impl_->cv_scroll->vert.make_page_scroll(forwards); } void content_view::disp_area(const rectangle& da, const point& skew_horz, const point& skew_vert, const size& extra_px, bool try_update) @@ -404,7 +453,7 @@ namespace nana { void content_view::draw_corner(graph_reference graph) { auto r = corner(); - if ((!r.empty()) && (scrolls::both == impl_->enabled_scrolls)) + if ((!r.empty()) && (scrolls::both == impl_->cv_scroll->enabled_scrolls)) graph.rectangle(r, true, colors::button_face); } @@ -415,8 +464,8 @@ namespace nana { rectangle content_view::view_area(const size& alt_content_size) const { - bool const vert_allowed = (impl_->enabled_scrolls == scrolls::vert || impl_->enabled_scrolls == scrolls::both); - bool const horz_allowed = (impl_->enabled_scrolls == scrolls::horz || impl_->enabled_scrolls == scrolls::both); + bool const vert_allowed = (impl_->cv_scroll->enabled_scrolls == scrolls::vert || impl_->cv_scroll->enabled_scrolls == scrolls::both); + bool const horz_allowed = (impl_->cv_scroll->enabled_scrolls == scrolls::horz || impl_->cv_scroll->enabled_scrolls == scrolls::both); unsigned extra_horz = (horz_allowed && (impl_->disp_area.width < alt_content_size.width) ? space() : 0); unsigned extra_vert = (vert_allowed && (impl_->disp_area.height < alt_content_size.height + extra_horz) ? space() : 0); @@ -435,13 +484,13 @@ namespace nana { unsigned content_view::extra_space(bool horz) const { - return ((horz ? impl_->horz.empty() : impl_->vert.empty()) ? 0 : space()); + return ((horz ? impl_->cv_scroll->horz.empty() : impl_->cv_scroll->vert.empty()) ? 0 : space()); } void content_view::change_position(int pos, bool aligned, bool horz) { if (aligned) - pos -= (pos % static_cast(horz ? impl_->horz.step() : impl_->vert.step())); + pos -= (pos % static_cast(horz ? impl_->cv_scroll->horz.step() : impl_->cv_scroll->vert.step())); auto imd_size = this->view_area(); @@ -490,8 +539,8 @@ namespace nana { void content_view::sync(bool passive) { impl_->passive = passive; - impl_->horz.value(impl_->origin.x); - impl_->vert.value(impl_->origin.y); + impl_->cv_scroll->horz.value(impl_->origin.x); + impl_->cv_scroll->vert.value(impl_->origin.y); impl_->passive = true; } @@ -520,15 +569,15 @@ namespace nana { impl_->origin.y = 0; bool changed = false; - if (!impl_->horz.empty() && (static_cast(impl_->horz.value()) != impl_->origin.x)) + if (!impl_->cv_scroll->horz.empty() && (static_cast(impl_->cv_scroll->horz.value()) != impl_->origin.x)) { - impl_->horz.value(impl_->origin.x); + impl_->cv_scroll->horz.value(impl_->origin.x); changed = true; } - if ((!impl_->vert.empty()) && (static_cast(impl_->vert.value()) != impl_->origin.y)) + if ((!impl_->cv_scroll->vert.empty()) && (static_cast(impl_->cv_scroll->vert.value()) != impl_->origin.y)) { - impl_->vert.value(impl_->origin.y); + impl_->cv_scroll->vert.value(impl_->origin.y); changed = true; } diff --git a/source/gui/widgets/skeletons/content_view.hpp b/source/gui/widgets/skeletons/content_view.hpp index c5bcc3da..40ee84df 100644 --- a/source/gui/widgets/skeletons/content_view.hpp +++ b/source/gui/widgets/skeletons/content_view.hpp @@ -1,7 +1,7 @@ /* * A Content View Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2017-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -16,6 +16,7 @@ #include #include +#include namespace nana { @@ -58,6 +59,8 @@ namespace skeletons bool enable_scrolls(scrolls which); + std::shared_ptr scroll_operation() const; + void step(unsigned step_value, bool horz); bool scroll(bool forwards, bool horz); bool turn_page(bool forwards, bool horz); @@ -92,7 +95,7 @@ namespace skeletons return 16; } private: - implementation * const impl_; + implementation* const impl_; }; } } diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index fefaf1ed..6ee30fb5 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1,7 +1,7 @@ /* * A text editor implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -1954,6 +1954,11 @@ namespace nana{ namespace widgets return impl_->capacities.behavior->take_lines(); } + std::shared_ptr text_editor::scroll_operation() const + { + return impl_->cview->scroll_operation(); + } + void text_editor::draw_corner() { impl_->cview->draw_corner(graph_); diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index de6e2dd9..265a8e28 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -1,7 +1,7 @@ /* * A Textbox Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -816,6 +816,16 @@ namespace drawerbase { if(editor) editor->reset_caret_pixels(); } + + std::shared_ptr textbox::_m_scroll_operation() const + { + internal_scope_guard lock; + auto editor = get_drawer_trigger().editor(); + if (editor) + return editor->scroll_operation(); + + return {}; + } //end class textbox }//end namespace nana diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index ac4c2799..4dcf0d57 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -29,6 +29,25 @@ namespace nana { using node_type = trigger::node_type; + class exclusive_scroll_operation + : public scroll_operation_interface + { + public: + exclusive_scroll_operation(std::shared_ptr>& scroll_wdg) + :scroll_(scroll_wdg) + {} + + bool visible(bool vert) const override + { + if (vert) + return !scroll_->empty(); + + return false; + } + private: + std::shared_ptr> scroll_; + }; + bool no_sensitive_compare(const std::string& text, const char *pattern, std::size_t len) { if(len <= text.length()) @@ -214,7 +233,7 @@ namespace nana struct shape_tag { nana::upoint border; - nana::scroll scroll; + std::shared_ptr> scroll; mutable std::map image_table; @@ -261,6 +280,7 @@ namespace nana shape.first = nullptr; shape.indent_pixels = 10; shape.offset_x = 0; + shape.scroll = std::make_shared>(); attr.auto_draw = true; @@ -598,7 +618,7 @@ namespace nana std::size_t max_allow = max_allowed(); std::size_t visual_items = visual_item_size(); - auto & scroll = shape.scroll; + auto & scroll = *shape.scroll; if(visual_items <= max_allow) { if(!scroll.empty()) @@ -618,7 +638,7 @@ namespace nana adjust.scroll_timestamp = nana::system::timestamp(); adjust.timer.start(); - shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll.value(), pred_allow_child{}); + shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll->value(), pred_allow_child{}); draw(false, false, true); }); } @@ -641,7 +661,7 @@ namespace nana if(!data.graph) return 0; - return static_cast(data.graph->width() - (shape.scroll.empty() ? 0 : shape.scroll.size().width)); + return static_cast(data.graph->width() - (shape.scroll->empty() ? 0 : shape.scroll->size().width)); } unsigned node_w_pixels(const node_type *node) const @@ -1901,7 +1921,7 @@ namespace nana void trigger::mouse_wheel(graph_reference, const arg_wheel& arg) { - auto & scroll = impl_->shape.scroll; + auto & scroll = *impl_->shape.scroll; if (scroll.empty()) return; @@ -1935,10 +1955,10 @@ namespace nana impl_->draw(false); API::dev::lazy_refresh(); impl_->show_scroll(); - if(!impl_->shape.scroll.empty()) + if(!impl_->shape.scroll->empty()) { nana::size s = impl_->data.graph->size(); - impl_->shape.scroll.move(rectangle{ static_cast(s.width) - 16, 0, 16, s.height }); + impl_->shape.scroll->move(rectangle{ static_cast(s.width) - 16, 0, 16, s.height }); } } @@ -2213,5 +2233,11 @@ namespace nana { return item_proxy(const_cast(&get_drawer_trigger()), get_drawer_trigger().selected()); } + + std::shared_ptr treebox::_m_scroll_operation() const + { + internal_scope_guard lock; + return std::make_shared(get_drawer_trigger().impl()->shape.scroll); + } //end class treebox }//end namespace nana diff --git a/source/gui/widgets/widget.cpp b/source/gui/widgets/widget.cpp index 183768ab..3e3ab2cd 100644 --- a/source/gui/widgets/widget.cpp +++ b/source/gui/widgets/widget.cpp @@ -1,6 +1,6 @@ /* * The fundamental widget class implementation - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -158,6 +158,11 @@ namespace nana return (API::focus_window() == handle()); } + std::shared_ptr widget::scroll_operation() + { + return _m_scroll_operation(); + } + void widget::show() { _m_show(true); @@ -317,6 +322,11 @@ namespace nana API::window_enabled(handle(), value); } + std::shared_ptr widget::_m_scroll_operation() + { + return {}; + } + bool widget::_m_show(bool visible) { API::show_window(handle(), visible);