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/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index a4f3e91c..0f4845cb 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1056,6 +1056,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); @@ -1488,6 +1501,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/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 9e91712c..a2ab3ea7 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -86,6 +86,7 @@ namespace nana{ namespace widgets ~text_editor(); size caret_size() const; + const point& content_origin() const; void set_highlight(const ::std::string& name, const ::nana::color&, const ::nana::color&); void erase_highlight(const ::std::string& name); diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index ad4a1b2f..d0ac2f67 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -140,6 +140,8 @@ namespace nana colored_area_access_interface* colored_area_access(); + point content_origin() const; + /// Enables/disables the textbox to indent a line. Idents a new line when it is created by pressing enter. /// @param generator generates text for identing a line. If it is empty, textbox indents the line according to last line. textbox& indention(bool, std::function generator = {}); 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_; }; diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index d6620c7a..f978bf1a 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -519,15 +520,15 @@ namespace nana if (each_height[i] > 27) px = each_height[i]; - ss_content << ""; + ss_content << ""; height += px + 1; } 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,20 +770,17 @@ 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); impl->spinbox.value(std::to_string(impl->value)); - impl->dock.events().resized.connect_unignorable([impl, label_px, value_px](const ::nana::arg_resized&) + impl->dock.events().resized.connect_unignorable([impl, label_px, value_px](const ::nana::arg_resized& arg) { - impl->label.size({ label_px, 24 }); - impl->spinbox.size({ value_px, 24 }); + impl->label.size({ label_px, arg.height }); + impl->spinbox.move({static_cast(label_px + 10), (static_cast(arg.height) - 25) / 2, value_px, 24 }); }); impl->spinbox.events().destroy.connect_unignorable([impl](const arg_destroy&) @@ -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,20 +853,17 @@ 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); impl->spinbox.value(std::to_string(impl->value)); - impl->dock.events().resized.connect_unignorable([impl, label_px, value_px](const ::nana::arg_resized&) + impl->dock.events().resized.connect_unignorable([impl, label_px, value_px](const ::nana::arg_resized& arg) { - impl->label.size(::nana::size{ label_px, 24 }); - impl->spinbox.size(::nana::size{ value_px, 24 }); + impl->label.size({ label_px, arg.height }); + impl->spinbox.move({ static_cast(label_px + 10), (static_cast(arg.height) - 25) / 2, value_px, 24 }); }); impl->spinbox.events().destroy.connect_unignorable([impl](const arg_destroy&) @@ -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,10 +984,10 @@ 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) - impl->combox.size({ value_px, 24 }); + if (impl->textbox.empty()) + impl->combox.move({static_cast(label_px + 10), (static_cast(arg.height) - 25) / 2, value_px, 24 }); else - impl->textbox.size({arg.width - label_px - 10, 24}); + impl->textbox.move({ static_cast(label_px + 10), (static_cast(arg.height) - 25) / 2, arg.width - label_px - 10, 24 }); }); auto & wdg = (value_px ? static_cast(impl->combox) : static_cast(impl->textbox)); @@ -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 @@ -1028,17 +1111,18 @@ namespace nana impl->dock.events().resized.connect_unignorable([impl, label_px](const ::nana::arg_resized& arg) { impl->label.size({ label_px, arg.height }); - auto sz = impl->wdg_month.size(); - sz.height = 24; - impl->wdg_month.size(sz); - sz = impl->wdg_day.size(); - sz.height = 24; - impl->wdg_day.size(sz); + rectangle rt{static_cast(label_px + 10), (static_cast(arg.height) - 25) / 2, 94, 24}; - sz = impl->wdg_year.size(); - sz.height = 24; - impl->wdg_year.size(sz); + impl->wdg_month.move(rt); + + rt.x += 104; + rt.width = 38; + impl->wdg_day.move(rt); + + rt.x += 48; + rt.width = 50; + impl->wdg_year.move(rt); }); auto destroy_fn = [impl](const arg_destroy& arg) @@ -1152,8 +1236,13 @@ namespace nana impl->dock.events().resized.connect_unignorable([impl, label_px](const ::nana::arg_resized& arg) { impl->label.size({ label_px, arg.height }); - impl->path_edit.size({arg.width - label_px - 75, arg.height}); - impl->browse.move({static_cast(arg.width - 60), 0, 60, arg.height}); + + rectangle rt{ static_cast(label_px)+10, (static_cast(arg.height) - 25), arg.width - label_px - 75, 24}; + impl->path_edit.move(rt); + + rt.x = static_cast(arg.width - 60); + rt.width = 60; + impl->browse.move(rt); }); impl->path_edit.events().destroy.connect_unignorable([impl](const arg_destroy&) @@ -1199,6 +1288,8 @@ namespace nana std::vector each_pixels; unsigned label_px = 0, fixed_px = 0; paint::graphics graph({ 5, 5 }); + + bool has_0_fixed_px = false; for (auto p : contents) { auto px = label::measure(graph, p->label(), 150, true, align::right, align_v::center); @@ -1206,12 +1297,17 @@ namespace nana label_px = px.width; px.width = p->fixed_pixels(); + has_0_fixed_px |= (px.width == 0); if (px.width > fixed_px) fixed_px = px.width; each_pixels.push_back(px.height); } + //Adjust the fixed_px for good looking + if (has_0_fixed_px && (fixed_px < 100)) + fixed_px = 100; + inputbox_window input_wd(owner_, images_, valid_areas_, description_, title_, contents.size(), label_px + 10 + fixed_px, each_pixels); std::vector inputs; 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(); 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..452cf5fe 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -497,6 +497,7 @@ namespace nana{ namespace widgets undoable undo; //undo command renderers customized_renderers; std::vector text_position; //positions of text since last rendering. + int text_position_origin{ -1 }; //origin when last text_exposed skeletons::textbase textbase; @@ -1083,6 +1084,11 @@ namespace nana{ namespace widgets return { 1, line_height() }; } + const point& text_editor::content_origin() const + { + return impl_->cview->origin(); + } + void text_editor::set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor) { if (fgcolor.invisible() && bgcolor.invisible()) @@ -1337,6 +1343,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; } @@ -1978,8 +1988,9 @@ namespace nana{ namespace widgets if (text_pos.empty()) text_pos.emplace_back(upoint{}); - if (text_pos != impl_->text_position) + if ((impl_->text_position_origin != impl_->cview->origin().y) || (text_pos != impl_->text_position)) { + impl_->text_position_origin = impl_->cview->origin().y; impl_->text_position.swap(text_pos); if (event_handler_) event_handler_->text_exposed(impl_->text_position); @@ -3350,32 +3361,37 @@ namespace nana{ namespace widgets line_px_( editor.line_height() ) {} - color selection_text_color(bool has_focused) const + color selection_color(bool fgcolor, bool focused) const { - return (has_focused ? editor_.scheme_->selection_text : editor_.scheme_->foreground).get_color(); + if (fgcolor) + return (focused ? editor_.scheme_->selection_text : editor_.scheme_->foreground).get_color(); + + return (focused ? editor_.scheme_->selection : editor_.scheme_->selection_unfocused).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, selection_text_color(has_focused)); + graph_.palette(true, selection_color(true, 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()); + selection_color(false, has_focused)); + graph_.string(text_pos, text, len); } 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, selection_text_color(has_focused), str, len); + editor_._m_draw_parse_string(parser_, true, strpos, selection_color(true, has_focused), str, len); //Draw selected part paint::graphics graph({ glyph_selected, line_px_ }); graph.typeface(this->graph_.typeface()); - graph.rectangle(true, (has_focused ? editor_.scheme_->selection.get_color() : editor_.scheme_->selection_unfocused.get_color())); + graph.rectangle(true, selection_color(false, has_focused)); int sel_xpos = static_cast(str_px - (glyph_front + glyph_selected)); - graph.palette(true, selection_text_color(has_focused)); + graph.palette(true, selection_color(true, has_focused)); + graph.string({ -sel_xpos, 0 }, str, len); graph_.bitblt(nana::rectangle(strpos.x + sel_xpos, strpos.y, glyph_selected, line_px_), graph); }; diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 3366d84b..e29b0d88 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -269,6 +269,15 @@ namespace drawerbase { return nullptr; } + point textbox::content_origin() const + { + auto editor = get_drawer_trigger().editor(); + if (editor) + return editor->content_origin(); + + return{}; + } + /// Enables/disables the textbox to indent a line. Idents a new line when it is created by pressing enter. /// @param generator generates text for identing a line. If it is empty, textbox indents the line according to last line. textbox& textbox::indention(bool enb, std::function generator)