From 8729d14c7ab230aab5bf54dfab5f13e33d2255d8 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 11 Jul 2017 21:56:42 +0800 Subject: [PATCH 01/17] fix bug that place margin would generate bad value --- source/gui/place_parts.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 3dde6ca9..4511dc95 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -557,7 +557,10 @@ namespace nana }value_; };//end class number_t - + /// Margin attribute + /** + * Definition at https://github.com/cnjinhao/nana/wiki/Div-Text#margin + */ class margin { public: @@ -598,7 +601,7 @@ namespace nana { case 0: break; case 1: //top - il = ir = it = ib = 0; + it = 0; break; case 2://top,bottom and left,right it = ib = 0; @@ -624,7 +627,7 @@ namespace nana case 3: //left pos = il; break; default: - return number_t{}; + return {}; } return (-1 == pos ? number_t{} : margins_[pos]); @@ -652,7 +655,7 @@ namespace nana { case 0: break; case 1: //top - il = ir = it = ib = 0; + it = 0; break; case 2://top,bottom and left,right it = ib = 0; From d1d03c9c0a8895e3ec4feac103b966be57cbe8bd Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 11 Jul 2017 23:27:45 +0800 Subject: [PATCH 02/17] code refined --- include/nana/gui/msgbox.hpp | 2 +- source/gui/msgbox.cpp | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/include/nana/gui/msgbox.hpp b/include/nana/gui/msgbox.hpp index bb17c448..e23c043e 100644 --- a/include/nana/gui/msgbox.hpp +++ b/include/nana/gui/msgbox.hpp @@ -1,7 +1,7 @@ /* * A Message Box Class * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2017 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/msgbox.cpp b/source/gui/msgbox.cpp index 6560fe93..d6620c7a 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -1,7 +1,7 @@ /* * A Message Box Class * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -511,7 +510,6 @@ namespace nana unsigned height = 20 + desc_extent.height + 10 + 38; - place_.bind(*this); std::stringstream ss_content; ss_content << "<"<>"; - place_.div(ss.str().data()); - place_["desc"] << desc_; - place_["buttons"] << btn_ok_ << btn_cancel_; + auto& place = this->get_place(); + place.div(ss.str().c_str()); + place["desc"] << desc_; + place["buttons"] << btn_ok_ << btn_cancel_; const char * img_fields[4] = {"img_top", "img_bottom", "img_left", "img_right"}; @@ -611,11 +610,10 @@ namespace nana images_[i].create(*this, true); images_[i].load(imgs[i], valid_areas[i]); images_[i].stretchable(0, 0, 0, 0); - place_[img_fields[i]] << images_[i]; - place_.field_display(img_fields[i], true); + place[img_fields[i]] << images_[i]; } - else - place_.field_display(img_fields[i], false); + + place.field_display(img_fields[i], imgs[i]); } move(API::make_center(this->owner(), desc_extent.width, height)); @@ -626,14 +624,14 @@ namespace nana { verifier_ = std::move(verifier); - std::size_t index = 0; + unsigned index = 0; for (auto wd : inputs) { std::stringstream ss; ss << "input_" << index++; - place_[ss.str().data()] << wd; + this->operator[](ss.str().data()) << wd; } - place_.collocate(); + this->collocate(); show(); } @@ -646,7 +644,6 @@ namespace nana ::nana::button btn_ok_; ::nana::button btn_cancel_; bool valid_input_{ false }; - ::nana::place place_; std::function verifier_; ::nana::picture images_[4]; }; From e8755e62832d640a5c19d2a7878ad7a6c2faa831 Mon Sep 17 00:00:00 2001 From: Oleg Smolsky Date: Wed, 12 Jul 2017 10:45:04 -0700 Subject: [PATCH 03/17] Added Windows-style mouse double-click to the textbox - the word under cursor is selected with double-click now - tested in both editable and read-only modes This addresses #226. --- .../gui/widgets/skeletons/text_editor.hpp | 1 + include/nana/gui/widgets/textbox.hpp | 1 + source/gui/widgets/skeletons/text_editor.cpp | 65 +++++++++++++++---- source/gui/widgets/textbox.cpp | 6 ++ 4 files changed, 59 insertions(+), 14 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index cf8ee302..e0113fed 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -211,6 +211,7 @@ namespace nana{ namespace widgets bool mouse_enter(bool entering); bool mouse_move(bool left_button, const point& screen_pos); void mouse_pressed(const arg_mouse& arg); + bool select_word(const arg_mouse& arg); skeletons::textbase& textbase(); const skeletons::textbase& textbase() const; diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 591b4e7e..71c23e0d 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -80,6 +80,7 @@ namespace nana void mouse_up(graph_reference, const arg_mouse&) override; void mouse_enter(graph_reference, const arg_mouse&) override; void mouse_leave(graph_reference, const arg_mouse&) override; + void dbl_click(graph_reference, const arg_mouse&) override; void key_press(graph_reference, const arg_keyboard&)override; void key_char(graph_reference, const arg_keyboard&) override; void mouse_wheel(graph_reference, const arg_wheel&) override; diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index a461137e..8832cc25 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -440,7 +440,7 @@ namespace nana{ namespace widgets break; } - return *colored_areas_.emplace(i, + return *colored_areas_.emplace(i, std::make_shared(colored_area_type{line_pos, 1, color{}, color{}}) ); } @@ -1129,7 +1129,7 @@ namespace nana{ namespace widgets } } } - + colored_area_access_interface& text_editor::colored_area() { return impl_->colored_area; @@ -1580,6 +1580,43 @@ namespace nana{ namespace widgets } } + bool text_editor::select_word(const arg_mouse& arg) + { + if(!attributes_.enable_caret) + return false; + + auto is_whitespace = [](wchar_t c) { + switch (c) { + case L' ': + case L'\t': + case L'\n': + case L'\r': + return true; + default: + return false; + } + }; + + // Set caret pos by screen point and get the caret pos. + mouse_caret(arg.pos, true); + + // Set the initial selection: it is an empty range. + select_.a = select_.b = points_.caret; + const auto& line = impl_->textbase.getline(select_.b.y); + + // Expand the selection forward to the word's end. + while (select_.b.x < line.size() && !is_whitespace(line[select_.b.x])) + ++select_.b.x; + + // Expand the selection backward to the word's start. + while (select_.a.x > 0 && !is_whitespace(line[select_.a.x - 1])) + --select_.a.x; + + select_.mode_selection = selection::mode::method_selected; + impl_->try_refresh = sync_graph::refresh; + return true; + } + textbase & text_editor::textbase() { return impl_->textbase; @@ -1661,7 +1698,7 @@ namespace nana{ namespace widgets } bool text_editor::move_caret(const upoint& crtpos, bool reset_caret) - { + { const unsigned line_pixels = line_height(); //The coordinate of caret @@ -1766,7 +1803,7 @@ namespace nana{ namespace widgets impl_->try_refresh = sync_graph::refresh; return true; } - + select_.mode_selection = selection::mode::no_selected; if (_m_cancel_select(0)) { @@ -1914,10 +1951,10 @@ namespace nana{ namespace widgets if ((false == textbase().empty()) || has_focus) { auto text_pos = _m_render_text(fgcolor); - + if (text_pos.empty()) text_pos.emplace_back(upoint{}); - + if (text_pos != impl_->text_position) { impl_->text_position.swap(text_pos); @@ -2276,7 +2313,7 @@ namespace nana{ namespace widgets //The number of charecters in the line of caret auto const text_length = textbase().getline(points_.caret.y).size(); - + switch (key) { case keyboard::os_arrow_left: if (select_.move_to_end && (select_.a != select_.b) && (!arg.shift)) @@ -2460,7 +2497,7 @@ namespace nana{ namespace widgets lines = impl_->capacities.behavior->take_lines(row.first); else top += static_cast(height * row.second); - + const rectangle area_r = { text_area_.area.x, top, width_pixels(), static_cast(height * lines) }; if (API::is_transparent_background(this->window_)) @@ -2757,7 +2794,7 @@ namespace nana{ namespace widgets const unsigned pixels = line_height(); const rectangle update_area = { text_area_.area.x, top, width_pixels(), static_cast(pixels * secondary_count_before) }; - + if (!API::dev::copy_transparent_background(window_, update_area, graph_, update_area.position())) { _m_draw_colored_area(graph_, { pos, 0 }, true); @@ -3047,7 +3084,7 @@ namespace nana{ namespace widgets this->points_.caret = (1 == align ? a : b); this->_m_adjust_view(); } - + select_.a = select_.b = points_.caret; reset_caret(); return true; @@ -3195,7 +3232,7 @@ namespace nana{ namespace widgets auto px = static_cast(line_height()); return (px ? (impl_->cview->origin().y / px) : px); } - + int text_editor::_m_text_x(const text_section& sct) const { auto const behavior = impl_->capacities.behavior; @@ -3292,7 +3329,7 @@ namespace nana{ namespace widgets void write_selection(const point& text_pos, unsigned text_px, const wchar_t* text, std::size_t len, bool has_focused) { graph_.palette(true, editor_.scheme_->selection_text.get_color()); - graph_.rectangle(::nana::rectangle{ text_pos, { text_px, line_px_ } }, true, + graph_.rectangle(::nana::rectangle{ text_pos, { text_px, line_px_ } }, true, has_focused ? editor_.scheme_->selection.get_color() : editor_.scheme_->selection_unfocused.get_color()); graph_.string(text_pos, text, len); } @@ -3345,7 +3382,7 @@ namespace nana{ namespace widgets const auto line_h_pixels = line_height(); helper_pencil pencil(graph_, *this, parser); - + graph_.palette(true, clr); graph_.palette(false, scheme_->selection.get_color()); @@ -3567,7 +3604,7 @@ namespace nana{ namespace widgets return 0; auto const reordered = unicode_reorder(lnstr.c_str(), lnstr.size()); - + auto target = lnstr.c_str() + pos; unsigned text_w = 0; diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 1be973ea..5e936a96 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -143,6 +143,12 @@ namespace drawerbase { API::dev::lazy_refresh(); } + void drawer::dbl_click(graph_reference, const arg_mouse& arg) + { + if(editor_->select_word(arg)) + API::dev::lazy_refresh(); + } + void drawer::key_press(graph_reference, const arg_keyboard& arg) { editor_->respond_key(arg); From eef08b8a28fb2ac6c269bccb2556c4887f5bf176 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 13 Jul 2017 03:29:40 +0800 Subject: [PATCH 04/17] fix bug that es_lister::scroll wouldn't work well --- source/gui/widgets/listbox.cpp | 44 +++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 078cd6c8..4a23a9f0 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1434,7 +1434,8 @@ namespace nana bool expand(size_type cat, bool exp) noexcept { - if(good(cat) && cat) + //It is allowed to expand the 1st category. + if(good(cat) && (cat || exp)) { auto & expanded = get(cat)->expand; if(expanded != exp) @@ -2849,7 +2850,32 @@ namespace nana ess_->calc_content_size(); } - ess_->content_view->turn_page(to_bottom, false); + auto origin = ess_->content_view->origin(); + origin.y = 0; + + auto off = this->distance(this->first(), pos) * 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); + } + + auto off_origin = origin - ess_->content_view->origin(); + ess_->content_view->move_origin(origin - ess_->content_view->origin()); + + ess_->content_view->sync(false); } void es_lister::erase(const index_pair& pos) @@ -4488,8 +4514,10 @@ namespace nana //pos_ never represents a category if this item_proxy is available. auto & m = cat_->items.at(pos_.item); // a ref to the real item + + //ignore if no change if(m.flags.selected == s) - return *this; // ignore if no change + return *this; m.flags.selected = s; // actually change selection @@ -4503,14 +4531,8 @@ namespace nana else if (ess_->lister.latest_selected_abs == pos_) ess_->lister.latest_selected_abs.set_both(npos); - if (scroll_view) - { - if (ess_->lister.get(pos_.cat)->expand) - ess_->lister.get(pos_.cat)->expand = false; - - if (!this->displayed()) - ess_->lister.scroll(pos_, !(ess_->first_display() > this->to_display())); - } + if (scroll_view && (!this->displayed())) + ess_->lister.scroll(pos_, !(ess_->first_display() > this->to_display())); ess_->update(); return *this; From f160710c9222f0de4433a2555edba6dbe4f2525a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 14 Jul 2017 07:49:16 +0800 Subject: [PATCH 05/17] fix bug that scroll() wouldn't work when avoid_drawing --- source/gui/widgets/listbox.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 4a23a9f0..6685f828 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2849,6 +2849,12 @@ namespace nana this->expand(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; From 887554b1b94a2f1ab0528f4cad67a730390533ea Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 15 Jul 2017 11:53:06 +0800 Subject: [PATCH 06/17] fix bug that _m_paste_children wouldn't work well in refresh_tree added contributor information --- include/nana/gui/detail/window_layout.hpp | 16 ++++++++++++---- .../nana/gui/widgets/skeletons/text_editor.hpp | 2 +- source/gui/detail/window_layout.cpp | 10 ++++------ source/gui/widgets/skeletons/text_editor.cpp | 4 +++- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/include/nana/gui/detail/window_layout.hpp b/include/nana/gui/detail/window_layout.hpp index da099cf5..9d628946 100644 --- a/include/nana/gui/detail/window_layout.hpp +++ b/include/nana/gui/detail/window_layout.hpp @@ -1,6 +1,6 @@ /* * Window Layout Implementation - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -72,9 +72,17 @@ namespace detail static void make_bground(core_window_t* const); private: - //_m_paste_children - //@brief:paste children window to the root graphics directly. just paste the visual rectangle - static void _m_paste_children(core_window_t*, bool have_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); + /// _m_paste_children + /** + * Pastes children window to the root graphics directly. just paste the visual rectangle + * @param window A handle to the window whose child windows will be pasted to the graph. + * @param has_refreshed Indicates whethere the window has been refreshed. + * @param request_refresh_children A flag indicates whether to refresh its child windows. + * @param parent_rect The child windows which are overlapped with the rectangle will be pasted + * @param graph A graphics object to which the child windows are pasted. + * @param graph_rpos The reference point to the graph. + */ + static void _m_paste_children(core_window_t* window, bool has_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); static void _m_paint_glass_window(core_window_t*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other); diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index e0113fed..fbd4d428 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -211,7 +211,7 @@ namespace nana{ namespace widgets bool mouse_enter(bool entering); bool mouse_move(bool left_button, const point& screen_pos); void mouse_pressed(const arg_mouse& arg); - bool select_word(const arg_mouse& arg); + bool select_word(const arg_mouse& arg); skeletons::textbase& textbase(); const skeletons::textbase& textbase() const; diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 2596f67e..72195e66 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-2016 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -266,8 +266,6 @@ namespace nana wd->effect.bground->take_effect(reinterpret_cast(wd), glass_buffer); } - //_m_paste_children - //@brief:paste children window to the root graphics directly. just paste the visual rectangle void window_layout::_m_paste_children(core_window_t* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) { nana::rectangle rect; @@ -287,12 +285,10 @@ namespace nana { if (overlap(nana::rectangle{ child->pos_root, child->dimension }, parent_rect, rect)) { - bool have_child_refreshed = false; if (category::flags::lite_widget != child->other.category) { if (req_refresh_children && (false == child->flags.refreshing)) { - have_child_refreshed = true; child->flags.refreshing = true; child->drawer.refresh(); child->flags.refreshing = false; @@ -301,7 +297,9 @@ namespace nana graph.bitblt(nana::rectangle(rect.x - graph_rpos.x, rect.y - graph_rpos.y, rect.width, rect.height), child->drawer.graphics, nana::point(rect.x - child->pos_root.x, rect.y - child->pos_root.y)); } - _m_paste_children(child, req_refresh_children, have_child_refreshed, rect, graph, graph_rpos); + //req_refresh_children determines whether the child has been refreshed, and also determines whether + //the children of child to be refreshed. + _m_paste_children(child, req_refresh_children, req_refresh_children, rect, graph, graph_rpos); } } else diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 8832cc25..1331322f 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -8,7 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/skeletons/text_editor.cpp - * @contributors: Ariel Vina-Rodriguez + * @contributors: Ariel Vina-Rodriguez, Oleg Smolsky */ #include #include @@ -1580,6 +1580,8 @@ namespace nana{ namespace widgets } } + //Added Windows-style mouse double-click to the textbox(https://github.com/cnjinhao/nana/pull/229) + //Oleg Smolsky bool text_editor::select_word(const arg_mouse& arg) { if(!attributes_.enable_caret) From a7bfc61007628a417c5b070b0b797861afcb1652 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 16 Jul 2017 11:26:28 +0800 Subject: [PATCH 07/17] fix bug that text_editor wouldn't reset scrollbar when paste --- source/gui/widgets/skeletons/text_editor.cpp | 4 +++- source/gui/widgets/textbox.cpp | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 1331322f..fad04de2 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1677,6 +1677,7 @@ namespace nana{ namespace widgets //_m_put calcs the lines _m_reset_content_size(false); + impl_->cview->sync(false); } } else @@ -1998,7 +1999,8 @@ namespace nana{ namespace widgets if(graph_) { - this->_m_adjust_view(); + if(this->_m_adjust_view()) + impl_->cview->sync(false); reset_caret(); impl_->try_refresh = sync_graph::refresh; diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 5e936a96..8343b7ca 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -8,6 +8,7 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/textbox.hpp + * @contributors: Oleg Smolsky */ #include @@ -143,6 +144,8 @@ namespace drawerbase { API::dev::lazy_refresh(); } + //Added Windows-style mouse double-click to the textbox(https://github.com/cnjinhao/nana/pull/229) + //Oleg Smolsky void drawer::dbl_click(graph_reference, const arg_mouse& arg) { if(editor_->select_word(arg)) From 822a762804345a7ac0a9bdd0d67e27ba63a231dc Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 16 Jul 2017 21:42:24 +0800 Subject: [PATCH 08/17] fix bug that textbox::caret_pos() doesn't move the caret --- .../gui/widgets/skeletons/text_editor.hpp | 7 ++-- include/nana/gui/widgets/textbox.hpp | 3 ++ source/gui/widgets/skeletons/text_editor.cpp | 38 ++++++++++++++----- source/gui/widgets/textbox.cpp | 10 +++++ 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index fbd4d428..9e91712c 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -149,12 +149,13 @@ namespace nana{ namespace widgets void text(std::wstring, bool end_caret); std::wstring text() const; - /// Sets caret position through text coordinate. + /// Moves the caret at specified position /** * @param pos the text position - * @param reset indicates whether to reset the text position by the pos. If this parameter is true, the text position is set by pos. If the parameter is false, it only moves the UI caret to the specified position. + * @param stay_in_view Indicates whether to adjust the view to make the caret in view. This parameter is ignored if the caret is already in view. + * @return true indicates a refresh is required. */ - bool move_caret(const upoint& pos, bool reset = false); + bool move_caret(upoint pos, bool stay_in_view = false); void move_caret_end(bool update); void reset_caret_pixels() const; void reset_caret(bool stay_in_view = false); diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 71c23e0d..ad4a1b2f 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -175,6 +175,9 @@ namespace nana /// Returns true if the caret is in the area of display, false otherwise. bool caret_pos(point& pos, bool text_coordinate) const; + /// Gets the caret position, in text coordinate + upoint caret_pos() const; + /// Sets the caret position with a text position textbox& caret_pos(const upoint&); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index fad04de2..038cdf49 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -234,7 +234,7 @@ namespace nana{ namespace widgets } } - editor_.move_caret(editor_.points_.caret); + editor_.reset_caret(); } }; @@ -302,7 +302,7 @@ namespace nana{ namespace widgets editor_.select_.b = sel_b_; } } - editor_.move_caret(editor_.points_.caret); + editor_.reset_caret(); } private: std::wstring text_; @@ -1273,7 +1273,7 @@ namespace nana{ namespace widgets if (impl_->cview->content_size().empty() || this->attributes_.line_wrapped) _m_reset_content_size(true); - move_caret(points_.caret); + reset_caret(); return true; } @@ -1564,7 +1564,6 @@ namespace nana{ namespace widgets { //no move occurs select(false); - move_caret(_m_coordinate_to_caret(arg.pos)); } @@ -1700,10 +1699,29 @@ namespace nana{ namespace widgets return str; } - bool text_editor::move_caret(const upoint& crtpos, bool reset_caret) + bool text_editor::move_caret(upoint crtpos, bool stay_in_view) { const unsigned line_pixels = line_height(); + if (crtpos != points_.caret) + { + //Check and make the crtpos available + if (crtpos.y < impl_->textbase.lines()) + { + crtpos.x = (std::min)(impl_->textbase.getline(crtpos.y).size(), crtpos.x); + } + else + { + crtpos.y = impl_->textbase.lines(); + if (crtpos.y > 0) + --crtpos.y; + + crtpos.x = impl_->textbase.getline(crtpos.y).size(); + } + + points_.caret = crtpos; + } + //The coordinate of caret auto coord = _m_caret_to_coordinate(crtpos); @@ -1734,9 +1752,11 @@ namespace nana{ namespace widgets caret->position(coord); //Adjust the caret into screen when the caret position is modified by this function - if (reset_caret && (!hit_text_area(coord))) + if (stay_in_view && (!hit_text_area(coord))) { - this->_m_adjust_view(); + if (_m_adjust_view()) + impl_->cview->sync(false); + impl_->try_refresh = sync_graph::refresh; caret->visible(true); return true; @@ -1751,7 +1771,7 @@ namespace nana{ namespace widgets points_.caret.x = static_cast(impl_->textbase.getline(points_.caret.y).size()); if (update) - this->move_caret(points_.caret, false); + this->reset_caret(); } void text_editor::reset_caret_pixels() const @@ -2465,7 +2485,7 @@ namespace nana{ namespace widgets if (stay_in_view && this->_m_adjust_view()) impl_->try_refresh = sync_graph::refresh; - move_caret(points_.caret); + reset_caret(); return points_.caret; } diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 8343b7ca..3366d84b 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -390,6 +390,16 @@ namespace drawerbase { return editor->hit_text_area(scr_pos); } + upoint textbox::caret_pos() const + { + auto editor = get_drawer_trigger().editor(); + internal_scope_guard lock; + if (editor) + return editor->caret(); + + return{}; + } + textbox& textbox::caret_pos(const upoint& pos) { auto editor = get_drawer_trigger().editor(); From 87698de126d04675a96469c174167e3b1f04042c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 16 Jul 2017 23:30:05 +0800 Subject: [PATCH 09/17] fix a compiler error in text_editor.cpp --- source/gui/widgets/skeletons/text_editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 038cdf49..ea7f59b5 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1708,7 +1708,7 @@ namespace nana{ namespace widgets //Check and make the crtpos available if (crtpos.y < impl_->textbase.lines()) { - crtpos.x = (std::min)(impl_->textbase.getline(crtpos.y).size(), crtpos.x); + crtpos.x = (std::min)(static_cast(impl_->textbase.getline(crtpos.y).size()), crtpos.x); } else { From cb6191cc8868b01482260dd5639440d7a5283187 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 17 Jul 2017 00:37:30 +0800 Subject: [PATCH 10/17] fix crash error when operate a closed treebox --- include/nana/gui/widgets/treebox.hpp | 1 + source/gui/widgets/treebox.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index a05f52f3..1ddb448d 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -140,6 +140,7 @@ namespace nana private: //Overrides drawer_trigger methods void attached(widget_reference, graph_reference) override; + void detached() override; void refresh(graph_reference) override; void dbl_click(graph_reference, const arg_mouse&) override; void mouse_down(graph_reference, const arg_mouse&) override; diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index c84e66d2..906bd969 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -1781,6 +1781,11 @@ namespace nana widget.caption("nana treebox"); } + void trigger::detached() + { + impl_->data.graph = nullptr; + } + void trigger::refresh(graph_reference) { //Don't reset the scroll and update the window From 130ba79705f6adc63869740253d6af3c6530a21e Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 17 Jul 2017 07:10:58 +0800 Subject: [PATCH 11/17] remove unused variable --- source/gui/widgets/listbox.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 6685f828..3126ce6d 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2878,10 +2878,8 @@ namespace nana origin.y = static_cast(last_off - screen_px); } - auto off_origin = origin - ess_->content_view->origin(); - ess_->content_view->move_origin(origin - ess_->content_view->origin()); - - ess_->content_view->sync(false); + if(ess_->content_view->move_origin(origin - ess_->content_view->origin())) + ess_->content_view->sync(false); } void es_lister::erase(const index_pair& pos) From 64dbd2100c6421d4f5d1c09710f9592251690275 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 17 Jul 2017 22:31:29 +0800 Subject: [PATCH 12/17] fix bug that graphics::make({0, 0}) behaves differently between Windows and Linux --- include/nana/paint/graphics.hpp | 6 +++++- source/paint/graphics.cpp | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp index 4eafffa2..8843a03f 100644 --- a/include/nana/paint/graphics.hpp +++ b/include/nana/paint/graphics.hpp @@ -91,7 +91,11 @@ namespace nana const void* pixmap() const; const void* context() const; - void make(const ::nana::size&); ///< Creates a bitmap resource that size is width by height in pixel + /// Creates a graphics/drawable resource + /** + * @param sz The dimension of the graphics to be requested. If sz is empty, it performs as release(). + */ + void make(const ::nana::size& sz); void resize(const ::nana::size&); void typeface(const font&); ///< Selects a specified font type into the graphics object. font typeface() const; diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 62940369..7fdadcea 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -291,6 +291,12 @@ namespace paint { if(impl_->handle == nullptr || impl_->size != sz) { + if (sz.empty()) + { + release(); + return; + } + //The object will be delete while dwptr_ is performing a release. drawable_type dw = new nana::detail::drawable_impl_type; //Reuse the old font @@ -342,7 +348,7 @@ namespace paint Display* disp = spec.open_display(); int screen = DefaultScreen(disp); Window root = ::XRootWindow(disp, screen); - dw->pixmap = ::XCreatePixmap(disp, root, (sz.width ? sz.width : 1), (sz.height ? sz.height : 1), DefaultDepth(disp, screen)); + dw->pixmap = ::XCreatePixmap(disp, root, sz.width, sz.height, DefaultDepth(disp, screen)); dw->context = ::XCreateGC(disp, dw->pixmap, 0, 0); #if defined(NANA_USE_XFT) dw->xftdraw = ::XftDrawCreate(disp, dw->pixmap, spec.screen_visual(), spec.colormap()); From 0d99cb26dcdb33ce1a4461a7ccfa360f9e38b0ef Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 19 Jul 2017 08:01:19 +0800 Subject: [PATCH 13/17] fix bug that render incorrent when text_editor selection isn't focused --- source/gui/widgets/skeletons/text_editor.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index ea7f59b5..4a656482 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -3350,9 +3350,15 @@ namespace nana{ namespace widgets line_px_( editor.line_height() ) {} + color selection_text_color(bool has_focused) const + { + return (has_focused ? editor_.scheme_->selection_text : editor_.scheme_->foreground).get_color(); + } + void write_selection(const point& text_pos, unsigned text_px, const wchar_t* text, std::size_t len, bool has_focused) { - graph_.palette(true, editor_.scheme_->selection_text.get_color()); + graph_.palette(true, selection_text_color(has_focused)); + graph_.rectangle(::nana::rectangle{ text_pos, { text_px, line_px_ } }, true, has_focused ? editor_.scheme_->selection.get_color() : editor_.scheme_->selection_unfocused.get_color()); graph_.string(text_pos, text, len); @@ -3360,7 +3366,7 @@ namespace nana{ namespace widgets void rtl_string(point strpos, const wchar_t* str, std::size_t len, std::size_t str_px, unsigned glyph_front, unsigned glyph_selected, bool has_focused) { - editor_._m_draw_parse_string(parser_, true, strpos, editor_.scheme_->selection_text.get_color(), str, len); + editor_._m_draw_parse_string(parser_, true, strpos, selection_text_color(has_focused), str, len); //Draw selected part paint::graphics graph({ glyph_selected, line_px_ }); @@ -3369,7 +3375,7 @@ namespace nana{ namespace widgets int sel_xpos = static_cast(str_px - (glyph_front + glyph_selected)); - graph.palette(true, editor_.scheme_->selection_text.get_color()); + graph.palette(true, selection_text_color(has_focused)); graph.string({ -sel_xpos, 0 }, str, len); graph_.bitblt(nana::rectangle(strpos.x + sel_xpos, strpos.y, glyph_selected, line_px_), graph); }; @@ -3457,9 +3463,11 @@ namespace nana{ namespace widgets //A text editor feature, it draws an extra block at end of line if the end of line is in range of selection. bool extra_space = false; + //Create a flag for indicating whether the whole line is selected const bool text_selected = (sbegin == text_ptr && send == text_ptr+ text_len); + //The text is not selected or the whole line text is selected - if (!focused || (!sbegin || !send) || text_selected || !attributes_.enable_caret) + if ((!sbegin || !send) || text_selected) { for (auto & ent : reordered) { From d53254b89a2a816e87a829e27d2097d761c73466 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 20 Jul 2017 23:44:03 +0800 Subject: [PATCH 14/17] fix bug that single-line text_editor still shows scrollbar --- source/gui/widgets/skeletons/content_view.cpp | 38 +++++++++++++++---- source/gui/widgets/skeletons/content_view.hpp | 7 ++++ source/gui/widgets/skeletons/text_editor.cpp | 4 ++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/source/gui/widgets/skeletons/content_view.cpp b/source/gui/widgets/skeletons/content_view.cpp index 8995944a..b279dc21 100644 --- a/source/gui/widgets/skeletons/content_view.cpp +++ b/source/gui/widgets/skeletons/content_view.cpp @@ -35,6 +35,7 @@ namespace nana { bool drag_started{ false }; point origin; + scrolls enabled_scrolls{scrolls::both}; nana::scroll horz; nana::scroll vert; @@ -193,7 +194,10 @@ namespace nana { this->passive = passive; - if (imd_area.width != disp_area.width) + bool const vert_allowed = (enabled_scrolls == scrolls::vert || enabled_scrolls == scrolls::both); + bool const horz_allowed = (enabled_scrolls == scrolls::horz || enabled_scrolls == scrolls::both); + + if ((imd_area.width != disp_area.width) && vert_allowed) { if (vert.empty()) { @@ -217,10 +221,14 @@ namespace nana { else { vert.close(); - origin.y = 0; + + //If vert is allowed, it indicates the vertical origin is not moved + //Make sure the v origin is zero + if (vert_allowed) + origin.y = 0; } - if (imd_area.height != disp_area.height) + if ((imd_area.height != disp_area.height) && horz_allowed) { if (horz.empty()) { @@ -244,7 +252,10 @@ namespace nana { else { horz.close(); - origin.x = 0; + //If horz is allowed, it indicates the horzontal origin is not moved + //Make sure the x origin is zero + if (horz_allowed) + origin.x = 0; } this->passive = true; @@ -266,6 +277,16 @@ namespace nana { return impl_->events; } + bool content_view::enable_scrolls(scrolls which) + { + if (impl_->enabled_scrolls == which) + return false; + + impl_->enabled_scrolls = which; + impl_->size_changed(false); + return true; + } + void content_view::step(unsigned step_value, bool horz) { if (horz) @@ -383,7 +404,7 @@ namespace nana { void content_view::draw_corner(graph_reference graph) { auto r = corner(); - if(!r.empty()) + if ((!r.empty()) && (scrolls::both == impl_->enabled_scrolls)) graph.rectangle(r, true, colors::button_face); } @@ -394,8 +415,11 @@ namespace nana { rectangle content_view::view_area(const size& alt_content_size) const { - unsigned extra_horz = (impl_->disp_area.width < alt_content_size.width ? space() : 0); - unsigned extra_vert = (impl_->disp_area.height < alt_content_size.height + extra_horz ? space() : 0); + 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); + + 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); if ((0 == extra_horz) && extra_vert) extra_horz = (impl_->disp_area.width < alt_content_size.width + extra_vert ? space() : 0); diff --git a/source/gui/widgets/skeletons/content_view.hpp b/source/gui/widgets/skeletons/content_view.hpp index 9abd59a4..c5bcc3da 100644 --- a/source/gui/widgets/skeletons/content_view.hpp +++ b/source/gui/widgets/skeletons/content_view.hpp @@ -40,6 +40,11 @@ namespace skeletons public: using graph_reference = paint::graphics&; + enum class scrolls + { + none, horz, vert, both + }; + struct events_type { ::std::function hover_outside; @@ -51,6 +56,8 @@ namespace skeletons events_type& events(); + bool enable_scrolls(scrolls which); + void step(unsigned step_value, bool horz); bool scroll(bool forwards, bool horz); bool turn_page(bool forwards, bool horz); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 4a656482..e48498d0 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1337,6 +1337,10 @@ namespace nana{ namespace widgets line_wrapped(false); _m_reset_content_size(); + impl_->cview->enable_scrolls(ml ? content_view::scrolls::both : content_view::scrolls::none); + impl_->cview->move_origin(point{} -impl_->cview->origin()); + + impl_->try_refresh = sync_graph::refresh; return true; } From 0cfd06b23f02b238df920fe01a701fec1fcffe3e Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 20 Jul 2017 23:46:20 +0800 Subject: [PATCH 15/17] add new inputbox::boolean other fixes for width of inputbox's elements --- include/nana/gui/msgbox.hpp | 21 ++++++ source/gui/msgbox.cpp | 130 ++++++++++++++++++++++++++++++------ 2 files changed, 129 insertions(+), 22 deletions(-) diff --git a/include/nana/gui/msgbox.hpp b/include/nana/gui/msgbox.hpp index e23c043e..a53e2264 100644 --- a/include/nana/gui/msgbox.hpp +++ b/include/nana/gui/msgbox.hpp @@ -109,6 +109,24 @@ namespace nana virtual unsigned fixed_pixels() const; }; public: + class boolean + : public abstract_content + { + struct implement; + public: + boolean(::std::string label, bool initial_value); + ~boolean(); + + bool value() const; + private: + //Implementation of abstract_content + const ::std::string& label() const override; + window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; + private: + std::unique_ptr impl_; + }; + class integer : public abstract_content { @@ -122,6 +140,7 @@ namespace nana //Implementation of abstract_content const ::std::string& label() const override; window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; private: std::unique_ptr impl_; }; @@ -139,6 +158,7 @@ namespace nana //Implementation of abstract_content const ::std::string& label() const override; window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; private: std::unique_ptr impl_; }; @@ -166,6 +186,7 @@ namespace nana //Implementation of abstract_content const ::std::string& label() const override; window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; private: std::unique_ptr impl_; }; diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index d6620c7a..1034585b 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -526,8 +527,8 @@ namespace nana ss_content << ">>>"; - if (desc_extent.width < 170) - desc_extent.width = 170; + if (desc_extent.width < 200) + desc_extent.width = 200; //Make sure the complete display of input extent if (desc_extent.width < fixed_pixels) @@ -653,6 +654,70 @@ namespace nana return 0; } + //class boolean + struct inputbox::boolean::implement + { + bool value; + ::std::string empty_label_text; + ::std::string label_text; + ::nana::panel dock; + ::nana::checkbox checkbox; + }; + + inputbox::boolean::boolean(::std::string label, bool initial_value) + : impl_(new implement) + { + impl_->value = initial_value; + impl_->label_text = std::move(label); + impl_->empty_label_text = " "; + } + + inputbox::boolean::~boolean() + {} + + bool inputbox::boolean::value() const + { + return (impl_->checkbox.empty() ? impl_->value : impl_->checkbox.checked()); + } + + //Implementation of abstract_content + const ::std::string& inputbox::boolean::label() const + { + return impl_->empty_label_text; + } + + window inputbox::boolean::create(window owner, unsigned label_px) + { + auto impl = impl_.get(); + + impl->dock.create(owner); + + paint::graphics graph{ ::nana::size{ 10, 10 } }; + auto value_px = graph.text_extent_size(impl->label_text).width + 20; + + impl->checkbox.create(impl->dock, rectangle{ (std::max)(static_cast(label_px) - 18, 0), 0, value_px, 0 }); + impl->checkbox.check(impl->value); + impl->checkbox.caption(impl->label_text); + + impl->dock.events().resized.connect_unignorable([impl, value_px](const ::nana::arg_resized&) + { + impl->checkbox.size({ value_px, 24 }); + }); + + impl->checkbox.events().destroy.connect_unignorable([impl](const arg_destroy&) + { + impl->value = impl->checkbox.checked(); + }); + + return impl->dock; + } + + unsigned inputbox::boolean::fixed_pixels() const + { + paint::graphics graph{ ::nana::size{ 10, 10 } }; + return graph.text_extent_size(impl_->label_text).width; + } + //class integer struct inputbox::integer::implement { @@ -705,10 +770,7 @@ namespace nana impl->label.caption(impl->label_text); impl->label.format(true); - //get the longest value - int longest = (std::abs(static_cast(impl->begin < 0 ? impl->begin * 10 : impl->begin)) < std::abs(static_cast(impl->last < 0 ? impl->last * 10 : impl->last)) ? impl->last : impl->begin); - paint::graphics graph{ ::nana::size{ 10, 10 } }; - auto value_px = graph.text_extent_size(std::to_wstring(longest)).width + 34; + auto const value_px = fixed_pixels(); impl->spinbox.create(impl->dock, rectangle{ static_cast(label_px + 10), 0, value_px, 0 }); impl->spinbox.range(impl->begin, impl->last, impl->step); @@ -728,6 +790,14 @@ namespace nana return impl->dock; } + + unsigned inputbox::integer::fixed_pixels() const + { + //get the longest value + int longest = (std::abs(static_cast(impl_->begin < 0 ? impl_->begin * 10 : impl_->begin)) < std::abs(static_cast(impl_->last < 0 ? impl_->last * 10 : impl_->last)) ? impl_->last : impl_->begin); + paint::graphics graph{ ::nana::size{ 10, 10 } }; + return graph.text_extent_size(std::to_wstring(longest)).width + 34; + } //end class integer @@ -783,10 +853,7 @@ namespace nana impl->label.caption(impl->label_text); impl->label.format(true); - //get the longest value - auto longest = (std::abs(static_cast(impl->begin < 0 ? impl->begin * 10 : impl->begin)) < std::abs(static_cast(impl->last < 0 ? impl->last * 10 : impl->last)) ? impl->last : impl->begin); - paint::graphics graph{ ::nana::size{ 10, 10 } }; - auto value_px = graph.text_extent_size(std::to_wstring(longest)).width + 34; + auto value_px = fixed_pixels(); impl->spinbox.create(impl->dock, rectangle{ static_cast(label_px + 10), 0, value_px, 0 }); impl->spinbox.range(impl->begin, impl->last, impl->step); @@ -806,6 +873,14 @@ namespace nana return impl->dock; } + + unsigned inputbox::real::fixed_pixels() const + { + //get the longest value + auto longest = (std::abs(static_cast(impl_->begin < 0 ? impl_->begin * 10 : impl_->begin)) < std::abs(static_cast(impl_->last < 0 ? impl_->last * 10 : impl_->last)) ? impl_->last : impl_->begin); + paint::graphics graph{ ::nana::size{ 10, 10 } }; + return graph.text_extent_size(std::to_wstring(longest)).width + 34; + } //end class real @@ -887,7 +962,7 @@ namespace nana impl->label.caption(impl->label_text); impl->label.format(true); - unsigned value_px = 0; + unsigned const value_px = fixed_pixels(); if (impl->options.empty()) { impl->textbox.create(impl->dock, rectangle{ static_cast(label_px + 10), 0, 0, 0 }); @@ -898,16 +973,6 @@ namespace nana } else { - //get the longest value - paint::graphics graph{ ::nana::size{ 10, 10 } }; - for (auto & s : impl->options) - { - auto px = graph.text_extent_size(s).width; - if (px > value_px) - value_px = px; - } - value_px += 34; - impl->combox.create(impl->dock, rectangle{ static_cast(label_px + 10), 0, value_px, 0 }); for (auto & s : impl->options) @@ -919,7 +984,7 @@ namespace nana impl->dock.events().resized.connect_unignorable([impl, label_px, value_px](const ::nana::arg_resized& arg) { impl->label.size({ label_px, arg.height }); - if (value_px) + if (impl->textbox.empty()) impl->combox.size({ value_px, 24 }); else impl->textbox.size({arg.width - label_px - 10, 24}); @@ -932,6 +997,24 @@ namespace nana }); return impl->dock; } + + unsigned inputbox::text::fixed_pixels() const + { + if (impl_->options.empty()) + return 0; + + paint::graphics graph{ ::nana::size{ 10, 10 } }; + unsigned long_px = 0; + //get the longest value + for (auto & s : impl_->options) + { + auto px = graph.text_extent_size(s).width; + if (px > long_px) + long_px = px; + } + + return long_px + 34; + } //end class text @@ -1212,6 +1295,9 @@ namespace nana each_pixels.push_back(px.height); } + //if (fixed_px < 150) + // fixed_px = 150; + inputbox_window input_wd(owner_, images_, valid_areas_, description_, title_, contents.size(), label_px + 10 + fixed_px, each_pixels); std::vector inputs; From a4f7d46eee2b6e497a006209b99a986a75fb5825 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 22 Jul 2017 23:04:43 +0800 Subject: [PATCH 16/17] add new features to listbox a method to enable/disable the number of items methods about expanding category methods about category icons --- include/nana/gui/widgets/listbox.hpp | 29 ++++++++ source/gui/widgets/listbox.cpp | 98 +++++++++++++++++++++++----- 2 files changed, 110 insertions(+), 17 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 6215d276..212be2f7 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1052,6 +1052,19 @@ namespace nana cat_proxy & select(bool); bool selected() const; + /// Enables/disables the number of items in the category to be displayed behind the category title + cat_proxy& display_number(bool display); + + /// Determines whether the category is expanded. + bool expanded() const; + + /// Expands/collapses the category + /** + * @param expand Indicates whether to expand or collapse the category. If this parameter is true, it expands the category. If the parameter is false, it collapses the category. + * @return the reference of *this. + */ + cat_proxy& expanded(bool expand); + /// Behavior of a container void push_back(std::string text_utf8); @@ -1484,6 +1497,22 @@ the nana::detail::basic_window member pointer scheme void enable_single(bool for_selection, bool category_limited); void disable_single(bool for_selection); export_options& def_export_options(); + + + /// Sets a renderer for category icon + /** + * @param icon_renderer The renderer of category icon + * @return the reference of *this. + */ + listbox& category_icon(std::function icon_renderer); + + /// Sets category icons + /** + * @param img_expanded An icon displayed in front of category title when the category is expanded. + * @param img_collapsed An icon displayed in front of category title when the category is collapsed. + * @return the reference of *this. + */ + listbox& category_icon(const paint::image& img_expanded, const paint::image&& img_collapsed); private: drawerbase::listbox::essence & _m_ess() const; nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const override; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 3126ce6d..5bb523a9 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -659,7 +659,8 @@ namespace nana std::unique_ptr model_ptr; - bool expand{true}; + bool expand{ true }; + bool display_number{ true }; //A cat may have a key object to identify the category std::shared_ptr key_ptr; @@ -1938,6 +1939,8 @@ namespace nana std::unique_ptr content_view; + std::function ctg_icon_renderer; ///< Renderer for the category icon + struct mouse_selection_part { bool started{ false }; @@ -3544,27 +3547,36 @@ namespace nana color txt_color{ static_cast(0x3399) }; - facade arrow("double"); - arrow.direction(categ.expand ? ::nana::direction::north : ::nana::direction::south); - arrow.draw( *graph, {}, txt_color, - { x + 5, y + static_cast(item_height - 16) / 2, 16, 16 }, - element_state::normal); + //Area of category icon + rectangle rt_ctg_icon{ x + 5, y + static_cast(item_height - 16) / 2, 16, 16 }; + + if (essence_->ctg_icon_renderer) + { + essence_->ctg_icon_renderer(*graph, rt_ctg_icon, categ.expand); + } + else + { + facade arrow("double"); + arrow.direction(categ.expand ? ::nana::direction::south : ::nana::direction::east); + arrow.draw(*graph, {}, txt_color, rt_ctg_icon, element_state::normal); + } graph->string({ x + 20, y + txtoff }, categ.text, txt_color); - native_string_type str = to_nstring('(' + std::to_string(categ.items.size()) + ')'); - - auto text_s = graph->text_extent_size(categ.text).width; - auto extend_text_w = text_s + graph->text_extent_size(str).width; - - graph->string({ x + 25 + static_cast(text_s), y + txtoff }, str); - - if (35 + extend_text_w < width) + auto text_px = graph->text_extent_size(categ.text).width; + if (categ.display_number) { - ::nana::point pos{ x + 30 + static_cast(extend_text_w), y + static_cast(item_height) / 2 }; + //Display the number of items in the category + native_string_type str = to_nstring('(' + std::to_string(categ.items.size()) + ')'); + graph->string({ x + 25 + static_cast(text_px), y + txtoff }, str); + text_px += graph->text_extent_size(str).width; + } - graph->line(pos, { x + static_cast(width) - 5, pos.y }, - txt_color); + if (35 + text_px < width) + { + ::nana::point pos{ x + 30 + static_cast(text_px), y + static_cast(item_height) / 2 }; + + graph->line(pos, { x + static_cast(width) - 5, pos.y }, txt_color); } //Draw selecting inner rectangle @@ -4814,6 +4826,32 @@ namespace nana return true; } + cat_proxy& cat_proxy::display_number(bool display) + { + if (cat_->display_number != display) + { + cat_->display_number = display; + ess_->update(); + } + return *this; + } + + bool cat_proxy::expanded() const + { + return cat_->expand; + } + + cat_proxy& cat_proxy::expanded(bool expand) + { + //The first category isn't allowed to be collapsed + if ((expand != cat_->expand) && pos_) + { + cat_->expand = expand; + ess_->update(); + } + return *this; + } + auto cat_proxy::columns() const -> size_type { return ess_->header.cont().size(); @@ -5585,6 +5623,32 @@ namespace nana return _m_ess().def_exp_options; } + listbox& listbox::category_icon(std::function icon_renderer) + { + _m_ess().ctg_icon_renderer.swap(icon_renderer); + _m_ess().update(); + return *this; + } + + listbox& listbox::category_icon(const paint::image& img_expanded, const paint::image&& img_collapsed) + { + _m_ess().ctg_icon_renderer = [img_expanded, img_collapsed](paint::graphics& graph, const rectangle& rt_icon, bool expanded) + { + if (expanded) + { + img_expanded.stretch(rectangle{ img_expanded.size() }, graph, rt_icon); + } + else + { + img_collapsed.stretch(rectangle{ img_collapsed.size() }, graph, rt_icon); + } + }; + + _m_ess().update(); + return *this; + } + + drawerbase::listbox::essence & listbox::_m_ess() const { return get_drawer_trigger().ess(); From 7371bd05253f815c5e089a4de273f68336daa87a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 23 Jul 2017 22:57:01 +0800 Subject: [PATCH 17/17] add comment --- include/nana/gui/widgets/toolbar.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index 24f27b32..d92c7f8a 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -94,6 +94,7 @@ namespace nana void enable(size_type index, bool enable_state); void scale(unsigned s); ///< Sets the scale of control button. + /// Enable to place buttons at right part. After calling it, every new button is right aligned. void go_right(); bool detached() { return detached_; };