From c5025b58a92b4cc60ac042b5348daeb520038f67 Mon Sep 17 00:00:00 2001 From: cnjinhao Date: Sat, 24 Jan 2015 08:06:02 +0800 Subject: [PATCH] Code reviews --- include/nana/gui/widgets/combox.hpp | 2 + .../gui/widgets/skeletons/text_editor.hpp | 2 - source/gui/element.cpp | 2 + source/gui/widgets/combox.cpp | 209 ++++++----- source/gui/widgets/skeletons/text_editor.cpp | 327 ++++++++---------- 5 files changed, 243 insertions(+), 299 deletions(-) diff --git a/include/nana/gui/widgets/combox.hpp b/include/nana/gui/widgets/combox.hpp index 242bfdd6..fdc22ac9 100644 --- a/include/nana/gui/widgets/combox.hpp +++ b/include/nana/gui/widgets/combox.hpp @@ -221,6 +221,8 @@ namespace nana private: item_proxy _m_at_key(std::shared_ptr&&); void _m_erase(nana::detail::key_interface*); + drawerbase::combox::drawer_impl & _m_impl(); + const drawerbase::combox::drawer_impl& _m_impl() const; private: //Overrides widget's virtual functions nana::string _m_caption() const override; diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 4da6c6c6..7b861606 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -271,8 +271,6 @@ namespace nana{ namespace widgets /// Returns the bottom point of text area. int _m_endy() const; - void _m_draw_tip_string() const; - void _m_draw_parse_string(const keyword_parser&, bool rtl, ::nana::point pos, const ::nana::color& fgcolor, const ::nana::char_t*, std::size_t len) const; //_m_draw_string //@brief: Draw a line of string diff --git a/source/gui/element.cpp b/source/gui/element.cpp index 5b6cf192..b8e83508 100644 --- a/source/gui/element.cpp +++ b/source/gui/element.cpp @@ -494,6 +494,8 @@ namespace nana case element_state::pressed: bgcolor = arg_bgcolor.blend(colors::black, 0.8); break; + case element_state::disabled: + bgcolor = colors::dark_gray; default: break; } diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index 9656f1df..57ce2d26 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -10,10 +10,9 @@ * @file: nana/gui/widgets/combox.cpp */ -#include +#include #include #include -#include #include #include #include @@ -71,11 +70,6 @@ namespace nana state_.lister = nullptr; } - ~drawer_impl() - { - clear(); - } - void renderer(drawerbase::float_listbox::item_renderer* ir) { item_renderer_ = ir; @@ -105,11 +99,6 @@ namespace nana API::refresh_window(widget_->handle()); } - parts get_where() const - { - return state_.pointer_where; - } - nana::any * anyobj(std::size_t pos, bool allocate_if_empty) const { if(pos >= items_.size()) @@ -169,7 +158,7 @@ namespace nana bool editable() const { - return (editor_ ? editor_->attr().editable : false); + return (editor_ && editor_->attr().editable); } bool calc_where(graph_reference graph, int x, int y) @@ -183,12 +172,11 @@ namespace nana new_where = parts::text; } - if(new_where != state_.pointer_where) - { - state_.pointer_where = new_where; - return true; - } - return false; + if (new_where == state_.pointer_where) + return false; + + state_.pointer_where = new_where; + return true; } void set_mouse_over(bool mo) @@ -217,9 +205,9 @@ namespace nana return (state_.lister != nullptr); } - void open_lister() + void open_lister_if_push_button_positioned() { - if((nullptr == state_.lister) && !items_.empty()) + if((nullptr == state_.lister) && !items_.empty() && (parts::push_button == state_.pointer_where)) { module_.items.clear(); std::copy(items_.cbegin(), items_.cend(), std::back_inserter(module_.items)); @@ -245,29 +233,30 @@ namespace nana void move_items(bool upwards, bool circle) { - if(nullptr == state_.lister) + if (state_.lister) { - std::size_t orig_i = module_.index; - if(upwards) - { - if(module_.index && (module_.index < items_.size())) - -- module_.index; - else if(circle) - module_.index = items_.size() - 1; - } - else - { - if((module_.index + 1) < items_.size()) - ++ module_.index; - else if(circle) - module_.index = 0; - } - - if(orig_i != module_.index) - option(module_.index, false); + state_.lister->move_items(upwards, circle); + return; + } + + auto pos = module_.index; + if (upwards) + { + if (pos && (pos < items_.size())) + --pos; + else if (circle) + pos = items_.size() - 1; } else - state_.lister->move_items(upwards, circle); + { + if ((pos + 1) < items_.size()) + ++pos; + else if (circle) + pos = 0; + } + + if (pos != module_.index) + option(pos, false); } void draw() @@ -315,7 +304,6 @@ namespace nana _m_draw_push_button(widget_->enabled()); _m_draw_image(); - //Yes, it's safe to static_cast here! widget_->events().selected.emit(::nana::arg_combox(*widget_)); } } @@ -325,9 +313,8 @@ namespace nana std::size_t pos = 0; for (auto & m : items_) { - if (m->key && nana::detail::pred_equal_by_less(m->key.get(), p.get())) + if (m->key && detail::pred_equal_by_less(m->key.get(), p.get())) return pos; - ++pos; } @@ -341,16 +328,17 @@ namespace nana return pos; } - void erase(nana::detail::key_interface * kv) + void erase(detail::key_interface * kv) { - for (auto i = items_.begin(); i != items_.end(); ++i) + std::size_t pos = 0; + for (auto & m : items_) { - if ((*i)->key && nana::detail::pred_equal_by_less((*i)->key.get(), kv)) + if (m->key && detail::pred_equal_by_less(m->key.get(), kv)) { - std::size_t pos = i - items_.begin(); - this->erase(pos); + erase(pos); return; } + ++pos; } } @@ -366,28 +354,22 @@ namespace nana void erase(std::size_t pos) { - if (pos < items_.size()) + if (pos >= items_.size()) + return; + + if (pos == module_.index) { - if (pos == module_.index) - { - module_.index = nana::npos; - this->widget_->caption(L""); - } - else if ((nana::npos != module_.index) && (pos < module_.index)) - --module_.index; - - items_.erase(items_.begin() + pos); - - //Redraw, because the state of push button is changed when the last item is created. - if (items_.empty()) - API::refresh_window(*widget_); + module_.index = ::nana::npos; + this->widget_->caption(L""); } - } + else if ((::nana::npos != module_.index) && (pos < module_.index)) + --module_.index; - void text(nana::string&& str) - { - if (editor_) - editor_->text(std::move(str)); + items_.erase(items_.begin() + pos); + + //Redraw, because the state of push button is changed when the last item is removed. + if (items_.empty()) + API::refresh_window(*widget_); } void image(std::size_t pos, const nana::paint::image& img) @@ -405,12 +387,11 @@ namespace nana bool image_pixels(unsigned px) { - if(image_pixels_ != px) - { - image_pixels_ = px; - return true; - } - return false; + if (image_pixels_ == px) + return false; + + image_pixels_ = px; + return true; } private: void _m_lister_close_sig() @@ -432,19 +413,17 @@ namespace nana void _m_draw_background(graph_reference graph, const rectangle&, const ::nana::color&) { - ::nana::rectangle r(graph.size()); auto clr_from = colors::button_face_shadow_start; auto clr_to = colors::button_face_shadow_end; + int pare_off_px = 1; if (element_state::pressed == state_.button_state) { - r.pare_off(2); + pare_off_px = 2; std::swap(clr_from, clr_to); } - else - r.pare_off(1); - graph.gradual_rectangle(r, clr_from, clr_to, true); + graph.gradual_rectangle(::nana::rectangle(graph.size()).pare_off(pare_off_px), clr_from, clr_to, true); } void _m_draw_push_button(bool enabled) @@ -620,8 +599,7 @@ namespace nana { auto * editor = drawer_->editor(); if(false == editor->mouse_down(arg.left_button, arg.pos)) - if(drawer_impl::parts::push_button == drawer_->get_where()) - drawer_->open_lister(); + drawer_->open_lister_if_push_button_positioned(); drawer_->draw(); if(editor->attr().editable) @@ -768,7 +746,7 @@ namespace nana { if (pos_ == nana::npos) return false; - return (impl_->at(pos_).item_text == static_cast(nana::charset(s))); + return (impl_->at(pos_).item_text == static_cast(nana::charset(s, nana::unicode::utf8))); } bool item_proxy::operator == (const wchar_t * s) const @@ -793,12 +771,11 @@ namespace nana /// Behavior of Iterator item_proxy & item_proxy::operator++() { - if (nana::npos == pos_) - return *this; - - if (++pos_ == impl_->the_number_of_options()) - pos_ = nana::npos; - + if (nana::npos != pos_) + { + if (++pos_ == impl_->the_number_of_options()) + pos_ = nana::npos; + } return *this; } @@ -887,26 +864,26 @@ namespace nana void combox::clear() { internal_scope_guard lock; - get_drawer_trigger().get_drawer_impl().clear(); + _m_impl().clear(); API::refresh_window(handle()); } void combox::editable(bool eb) { internal_scope_guard lock; - get_drawer_trigger().get_drawer_impl().editable(eb); + _m_impl().editable(eb); } bool combox::editable() const { internal_scope_guard lock; - return get_drawer_trigger().get_drawer_impl().editable(); + return _m_impl().editable(); } void combox::set_accept(std::function pred) { internal_scope_guard lock; - auto editor = get_drawer_trigger().get_drawer_impl().editor(); + auto editor = _m_impl().editor(); if(editor) editor->set_accept(std::move(pred)); } @@ -914,45 +891,45 @@ namespace nana combox& combox::push_back(nana::string text) { internal_scope_guard lock; - get_drawer_trigger().get_drawer_impl().insert(std::move(text)); + _m_impl().insert(std::move(text)); return *this; } std::size_t combox::the_number_of_options() const { internal_scope_guard lock; - return get_drawer_trigger().get_drawer_impl().the_number_of_options(); + return _m_impl().the_number_of_options(); } std::size_t combox::option() const { internal_scope_guard lock; - return get_drawer_trigger().get_drawer_impl().option(); + return _m_impl().option(); } - void combox::option(std::size_t i) + void combox::option(std::size_t pos) { internal_scope_guard lock; - get_drawer_trigger().get_drawer_impl().option(i, false); + _m_impl().option(pos, false); API::update_window(handle()); } - nana::string combox::text(std::size_t i) const + nana::string combox::text(std::size_t pos) const { internal_scope_guard lock; - return get_drawer_trigger().get_drawer_impl().at(i).item_text; + return _m_impl().at(pos).item_text; } void combox::erase(std::size_t pos) { internal_scope_guard lock; - get_drawer_trigger().get_drawer_impl().erase(pos); + _m_impl().erase(pos); } void combox::renderer(item_renderer* ir) { internal_scope_guard lock; - get_drawer_trigger().get_drawer_impl().renderer(ir); + _m_impl().renderer(ir); } void combox::image(std::size_t i, const nana::paint::image& img) @@ -960,7 +937,7 @@ namespace nana internal_scope_guard lock; if(empty()) return; - auto & impl = get_drawer_trigger().get_drawer_impl(); + auto & impl = _m_impl(); impl.image(i, img); if(i == impl.option()) API::refresh_window(*this); @@ -969,47 +946,61 @@ namespace nana nana::paint::image combox::image(std::size_t pos) const { internal_scope_guard lock; - return get_drawer_trigger().get_drawer_impl().at(pos).item_image; + return _m_impl().at(pos).item_image; } void combox::image_pixels(unsigned px) { internal_scope_guard lock; - if(get_drawer_trigger().get_drawer_impl().image_pixels(px)) + if (_m_impl().image_pixels(px)) API::refresh_window(*this); } nana::string combox::_m_caption() const { internal_scope_guard lock; - auto editor = get_drawer_trigger().get_drawer_impl().editor(); + auto editor = _m_impl().editor(); return (editor ? editor->text() : nana::string()); } void combox::_m_caption(nana::string&& str) { internal_scope_guard lock; - get_drawer_trigger().get_drawer_impl().text(std::move(str)); + + auto editor = _m_impl().editor(); + if (editor) + editor->text(std::move(str)); + API::refresh_window(*this); } nana::any * combox::_m_anyobj(std::size_t pos, bool alloc_if_empty) const { internal_scope_guard lock; - return get_drawer_trigger().get_drawer_impl().anyobj(pos, alloc_if_empty); + return _m_impl().anyobj(pos, alloc_if_empty); } auto combox::_m_at_key(std::shared_ptr&& p) -> item_proxy { internal_scope_guard lock; - auto & impl = get_drawer_trigger().get_drawer_impl(); + auto & impl = _m_impl(); return item_proxy(&impl, impl.at_key(std::move(p))); } void combox::_m_erase(nana::detail::key_interface* p) { internal_scope_guard lock; - get_drawer_trigger().get_drawer_impl().erase(p); + _m_impl().erase(p); + } + + drawerbase::combox::drawer_impl & combox::_m_impl() + { + return get_drawer_trigger().get_drawer_impl(); + } + + const drawerbase::combox::drawer_impl& combox::_m_impl() const + { + return get_drawer_trigger().get_drawer_impl(); } //end class combox } diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index bf96794e..435e407e 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -291,19 +291,20 @@ namespace nana{ namespace widgets void render(const ::nana::color& fgcolor) override { - auto & points = editor_.points_; + ::nana::upoint str_pos(0, static_cast(editor_.points_.offset.y)); - std::size_t scrlines = editor_.screen_lines() + static_cast(points.offset.y); + std::size_t scrlines = editor_.screen_lines() + str_pos.y; if (scrlines > editor_.textbase_.lines()) scrlines = editor_.textbase_.lines(); - int y = editor_._m_text_top_base(); - const unsigned pixles = editor_.line_height(); - nana::upoint str_pos(0, static_cast(points.offset.y)); - for (unsigned ln = points.offset.y; ln < scrlines; ++ln, y += pixles) + int top = editor_._m_text_top_base(); + const unsigned pixels = editor_.line_height(); + + while( str_pos.y < scrlines) { - editor_._m_draw_string(y, fgcolor, str_pos, editor_.textbase_.getline(ln), true); + editor_._m_draw_string(top, fgcolor, str_pos, editor_.textbase_.getline(str_pos.y), true); ++str_pos.y; + top += pixels; } } @@ -323,48 +324,36 @@ namespace nana{ namespace widgets nana::upoint screen_to_caret(point scrpos) override { - const auto & textbase = editor_.textbase_; - const auto & text_area = editor_.text_area_; - auto & points = editor_.points_; - - nana::upoint res(0, static_cast(_m_textline_from_screen(scrpos.y))); + nana::upoint res{ 0, static_cast(_m_textline_from_screen(scrpos.y)) }; //Convert the screen point to text caret point - const string_type& lnstr = textbase.getline(res.y); - res.x = static_cast(lnstr.size()); - if (res.x) + const string_type& lnstr = editor_.textbase_.getline(res.y); + if (lnstr.size() > 0) { - scrpos.x += (points.offset.x - text_area.area.x); + scrpos.x += (editor_.points_.offset.x - editor_.text_area_.area.x); if (scrpos.x > 0) { unicode_bidi bidi; std::vector reordered; - bidi.linestr(lnstr.c_str(), lnstr.size(), reordered); + bidi.linestr(lnstr.data(), lnstr.size(), reordered); - std::size_t pxbuf_size = 0; - std::unique_ptr pxbuf; - - int xbeg = 0; for (auto & ent : reordered) { std::size_t len = ent.end - ent.begin; - unsigned str_w = editor_._m_text_extent_size(ent.begin, len).width; - if (xbeg <= scrpos.x && scrpos.x < xbeg + static_cast(str_w)) + auto str_px = static_cast(editor_._m_text_extent_size(ent.begin, len).width); + if (scrpos.x < str_px) { - if (len > pxbuf_size) - { - pxbuf_size = len; - pxbuf.reset(new unsigned[len]); - } - res.x = editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), static_cast(str_w), scrpos.x - xbeg, _m_is_right_text(ent)); - res.x += static_cast(ent.begin - lnstr.c_str()); + std::unique_ptr pxbuf(new unsigned[len]); + + res.x = editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), str_px, scrpos.x, _m_is_right_text(ent)); + res.x += static_cast(ent.begin - lnstr.data()); return res; } - xbeg += static_cast(str_w); + scrpos.x -= str_px; } + + res.x = static_cast(lnstr.size()); } - else - res.x = 0; } return res; @@ -383,15 +372,11 @@ namespace nana{ namespace widgets if (points.xpos < points.caret.x) points.caret.x = points.xpos; - bool redraw_required = (static_cast(points.caret.y) < points.offset.y); - - if (static_cast(points.offset.y) > points.caret.y) + bool out_of_screen = (static_cast(points.caret.y) < points.offset.y); + if (out_of_screen) editor_._m_offset_y(static_cast(points.caret.y)); - if (adjust_caret_into_screen()) - redraw_required = true; - - return redraw_required; + return (adjust_caret_into_screen() || out_of_screen); } } else //South @@ -429,15 +414,13 @@ namespace nana{ namespace widgets if (x > lnstr.size()) x = static_cast(lnstr.size()); - unsigned text_w = editor_._m_pixels_by_char(textbase.getline(points.caret.y), x); + unsigned text_w = editor_._m_pixels_by_char(lnstr, x); unsigned area_w = editor_._m_text_area().width; bool adjusted_cond = true; if (static_cast(text_w) < points.offset.x) - { points.offset.x = (text_w > delta_pixels ? text_w - delta_pixels : 0); - } else if (area_w && (text_w >= points.offset.x + area_w)) points.offset.x = text_w - area_w + 2; else @@ -480,7 +463,7 @@ namespace nana{ namespace widgets else y = (y - text_area_top) / static_cast(editor_.line_height()) + offset_top; - return (textlines <= static_cast(y) ? textlines - 1 : static_cast(y)); + return (textlines <= static_cast(y) ? textlines - 1 : static_cast(y)); } private: text_editor& editor_; @@ -545,7 +528,7 @@ namespace nana{ namespace widgets if (pos < linemtr_.size()) { for (std::size_t i = 0; i < lines; ++i) - linemtr_.insert(linemtr_.begin() + pos + i, line_metrics()); + linemtr_.emplace(linemtr_.begin() + pos + i); //textbase is implement by using deque, and the linemtr holds the text pointers //If the textbase is changed, it will check the text pointers. @@ -656,7 +639,7 @@ namespace nana{ namespace widgets const auto lines = editor_.textbase_.lines(); linemtr_.resize(lines); - for (std::remove_const::type i = 0; i < lines; ++i) + for (std::size_t i = 0; i < lines; ++i) pre_calc_line(i, pixels); } @@ -698,8 +681,6 @@ namespace nana{ namespace widgets void render(const ::nana::color& fgcolor) override { - std::size_t scrlines = editor_.screen_lines(); - std::size_t secondary; auto primary = _m_textline_from_screen(0, secondary); if (primary >= linemtr_.size() || secondary >= linemtr_[primary].line_sections.size()) @@ -711,6 +692,7 @@ namespace nana{ namespace widgets int top = editor_._m_text_top_base(); const unsigned pixels = editor_.line_height(); + const std::size_t scrlines = editor_.screen_lines(); for (std::size_t pos = 0; pos < scrlines; ++pos, top += pixels) { if ((primary < linemtr_.size()) && (secondary < linemtr_[primary].line_sections.size())) @@ -775,8 +757,6 @@ namespace nana{ namespace widgets } } } - else - scrpos.x = 0; scrpos.x += editor_.text_area_.area.x; scrpos.y = editor_.text_area_.area.y + static_cast((lines - editor_.points_.offset.y) * editor_.line_height()); @@ -799,31 +779,24 @@ namespace nana{ namespace widgets unicode_bidi bidi; bidi.linestr(str.begin, str.end - str.begin, reordered); - std::size_t pxbuf_size = 0; - std::unique_ptr pxbuf; - nana::upoint res(static_cast(str.begin - mtr.line_sections.front().begin), static_cast(primary)); scrpos.x -= editor_.text_area_.area.x; if (scrpos.x < 0) scrpos.x = 0; - int xbeg = 0; for (auto & ent : reordered) { std::size_t len = ent.end - ent.begin; - unsigned str_w = editor_._m_text_extent_size(ent.begin, len).width; - if (xbeg <= scrpos.x && scrpos.x < xbeg + static_cast(str_w)) + auto str_px = static_cast(editor_._m_text_extent_size(ent.begin, len).width); + if (scrpos.x < str_px) { - if (len > pxbuf_size) - { - pxbuf.reset(new unsigned[len]); - pxbuf_size = len; - } - res.x += editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), static_cast(str_w), scrpos.x - xbeg, _m_is_right_text(ent)); + std::unique_ptr pxbuf(new unsigned[len]); + + res.x += editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), str_px, scrpos.x, _m_is_right_text(ent)); res.x += static_cast(ent.begin - str.begin); return res; } - xbeg += static_cast(str_w); + scrpos.x -= str_px; } res.x = static_cast(editor_.textbase_.getline(res.y).size()); return res; @@ -886,7 +859,7 @@ namespace nana{ namespace widgets } //Use the caret line for the offset line when caret is in front of current offset line. - if (off_primary > points.caret.y || (off_primary == points.caret.y && (off_secondary > caret_secondary))) + if (off_primary > points.caret.y || ((off_primary == points.caret.y) && (off_secondary > caret_secondary))) { //Use the line which was specified by points.caret for the first line. _m_set_offset_by_secondary(points.caret.y, caret_secondary); @@ -900,7 +873,7 @@ namespace nana{ namespace widgets return false; //Do not adjust the offset line if the caret line does not reach the bottom line. - if (points.caret.y < bottom.x || (points.caret.y == bottom.x && caret_secondary <= bottom.y)) + if (points.caret.y < bottom.x || ((points.caret.y == bottom.x) && (caret_secondary <= bottom.y))) return false; _m_advance_secondary(points.caret.y, caret_secondary, -static_cast(scrlines - 1), bottom); @@ -946,14 +919,10 @@ namespace nana{ namespace widgets void _m_set_offset_by_secondary(std::size_t primary, std::size_t secondary) { - std::size_t lines = 0; + for (auto i = linemtr_.begin(), end = linemtr_.begin() + primary; i != end; ++i) + secondary += i->take_lines; - for_each(linemtr_.begin(), linemtr_.begin() + primary, [&lines](const line_metrics& mtr) mutable - { - lines += mtr.take_lines; - }); - - editor_.points_.offset.y = static_cast(lines + secondary); + editor_.points_.offset.y = static_cast(secondary); } bool _m_advance_secondary(std::size_t primary, std::size_t secondary, int distance, nana::upoint& new_sec) @@ -1094,39 +1063,31 @@ namespace nana{ namespace widgets //secondary, index of line that the text was splitted into multilines. std::size_t _m_textline_from_screen(int y, std::size_t & secondary) const { - const auto & textbase = editor_.textbase_; - const auto & text_area = editor_.text_area_; - auto & points = editor_.points_; + const int text_area_top = editor_.text_area_.area.y; + const int offset_top = editor_.points_.offset.y; - secondary = 0; - - if (0 == textbase.lines()) - return 0; - std::size_t screen_line; - if (y < text_area.area.y) + if (0 == editor_.textbase_.lines()) { - screen_line = (text_area.area.y - y) / static_cast(editor_.line_height()); - if (screen_line > static_cast(points.offset.y)) + secondary = 0; + return 0; + } + + std::size_t screen_line; + if (y < text_area_top) + { + screen_line = (text_area_top - y) / static_cast(editor_.line_height()); + if (screen_line > static_cast(offset_top)) screen_line = 0; else - screen_line = static_cast(points.offset.y) - screen_line; + screen_line = static_cast(offset_top)-screen_line; } else - screen_line = static_cast((y - text_area.area.y) / static_cast(editor_.line_height()) + points.offset.y); + screen_line = static_cast((y - text_area_top) / static_cast(editor_.line_height()) + offset_top); - std::size_t primary = 0; - for (auto & mtr : linemtr_) - { - if (mtr.take_lines > screen_line) - { - secondary = screen_line; - return primary; - } - else - screen_line -= mtr.take_lines; + auto primary = _m_textline(screen_line, secondary); + if (primary < linemtr_.size()) + return primary; - ++primary; - } secondary = linemtr_.back().line_sections.size() - 1; return linemtr_.size() - 1; } @@ -1582,12 +1543,11 @@ namespace nana{ namespace widgets if((false == enter) && (false == text_area_.captured)) API::window_cursor(window_, nana::cursor::arrow); - if(API::focus_window() != window_) - { - render(false); - return true; - } - return false; + if(API::focus_window() == window_) + return false; + + render(false); + return true; } bool text_editor::mouse_down(bool left_button, const point& scrpos) @@ -1716,27 +1676,27 @@ namespace nana{ namespace widgets //Set caret position through text coordinate void text_editor::move_caret(const upoint& crtpos) { - if(API::is_focus_window(window_)) + if (!API::is_focus_window(window_)) + return; + + const unsigned line_pixels = line_height(); + auto pos = this->behavior_->caret_to_screen(crtpos); + const int end_y = pos.y + static_cast(line_pixels); + + bool visible = false; + if (hit_text_area(pos) && (end_y > text_area_.area.y)) { - const unsigned line_pixels = line_height(); - auto pos = this->behavior_->caret_to_screen(crtpos); - const int end_y = pos.y + static_cast(line_pixels); - - bool visible = false; - if (hit_text_area(pos) && (end_y > text_area_.area.y)) - { - visible = true; - if (end_y > _m_endy()) - API::caret_size(window_, nana::size(1, line_pixels - (end_y - _m_endy()))); - else if (API::caret_size(window_).height != line_pixels) - reset_caret_height(); - } - - API::caret_visible(window_, visible); - - if(visible) - API::caret_pos(window_, pos); + visible = true; + if (end_y > _m_endy()) + API::caret_size(window_, nana::size(1, line_pixels - (end_y - _m_endy()))); + else if (API::caret_size(window_).height != line_pixels) + reset_caret_height(); } + + API::caret_visible(window_, visible); + + if(visible) + API::caret_pos(window_, pos); } void text_editor::move_caret_end() @@ -1791,7 +1751,7 @@ namespace nana{ namespace widgets } select_.mode_selection = selection::mode_no_selected; - if(_m_cancel_select(0)) + if (_m_cancel_select(0)) { render(true); return true; @@ -1848,11 +1808,13 @@ namespace nana{ namespace widgets unsigned text_editor::width_pixels() const { + unsigned exclude_px; if (attributes_.line_wrapped) - return (text_area_.area.width > text_area_.vscroll ? text_area_.area.width - text_area_.vscroll : 0); + exclude_px = text_area_.vscroll; + else + exclude_px = API::caret_size(window_).width; - auto caret_px = API::caret_size(window_).width; - return (text_area_.area.width > caret_px ? text_area_.area.width - caret_px : 0); + return (text_area_.area.width > exclude_px ? text_area_.area.width - exclude_px : 0); } window text_editor::window_handle() const @@ -1890,10 +1852,12 @@ namespace nana{ namespace widgets if(attributes_.counterpart && !text_area_.area.empty()) attributes_.counterpart.bitblt(nana::rectangle(0, 0, text_area_.area.width, text_area_.area.height), graph_, nana::point(text_area_.area.x, text_area_.area.y)); - if((false == textbase_.empty()) || has_focus) + //Render the content when the text isn't empty or the window has got focus, + //otherwise draw the tip string. + if ((false == textbase_.empty()) || has_focus) behavior_->render(fgcolor); - else - _m_draw_tip_string(); + else //Draw tip string + graph_.string({ text_area_.area.x - points_.offset.x, text_area_.area.y }, attributes_.tip_string, { 0x78, 0x78, 0x78 }); draw_scroll_rectangle(); @@ -2048,9 +2012,9 @@ namespace nana{ namespace widgets { if(textbase_.getline(points_.caret.y).size() > points_.caret.x) { - points_.caret.x++; + ++points_.caret.x; } - else if(textbase_.lines() && (points_.caret.y < textbase_.lines() - 1)) + else if(points_.caret.y + 1 < textbase_.lines()) { //Move to next line points_.caret.x = 0; ++ points_.caret.y; @@ -2170,7 +2134,7 @@ namespace nana{ namespace widgets void text_editor::move_left() { - bool do_render = false; + bool pending = true; if(_m_cancel_select(1) == false) { if(points_.caret.x) @@ -2180,22 +2144,18 @@ namespace nana{ namespace widgets if(is_incomplete(textbase_.getline(points_.caret.y), points_.caret.x)) --points_.caret.x; #endif - bool adjust_y = false; - if (attributes_.line_wrapped) - adjust_y = behavior_->adjust_caret_into_screen(); - - do_render = (_m_move_offset_x_while_over_border(-2) || adjust_y); - } - else if(points_.caret.y) - { //Move to previous line - points_.caret.x = static_cast(textbase_.getline(-- points_.caret.y).size()); - do_render = behavior_->adjust_caret_into_screen(); + pending = false; + bool adjust_y = (attributes_.line_wrapped && behavior_->adjust_caret_into_screen()); + if (_m_move_offset_x_while_over_border(-2) || adjust_y) + render(true); } + else if (points_.caret.y) //Move to previous line + points_.caret.x = static_cast(textbase_.getline(--points_.caret.y).size()); + else + pending = false; } - else - do_render = behavior_->adjust_caret_into_screen(); - if (do_render) + if (pending && behavior_->adjust_caret_into_screen()) render(true); _m_scrollbar(); @@ -2567,9 +2527,10 @@ namespace nana{ namespace widgets begin = text.find_first_not_of(STR("\r\n"), pos + 1); //The number of new lines minus one - auto n = std::count(text.data() + pos, text.data() + (begin == text.npos ? text.size() : begin), '\n') - 1; - for (decltype(n) i = 0; i < n; ++i) - lines.emplace_back(0, 0); + const auto chp_end = text.data() + (begin == text.npos ? text.size() : begin); + for (auto chp = text.data() + (pos + 2); chp != chp_end; ++chp) + if (*chp == '\n') + lines.emplace_back(0, 0); if (text.npos == begin) { @@ -2734,11 +2695,6 @@ namespace nana{ namespace widgets return static_cast(text_area_.area.y + text_area_.area.height - text_area_.hscroll); } - void text_editor::_m_draw_tip_string() const - { - graph_.string({ text_area_.area.x - points_.offset.x, text_area_.area.y }, attributes_.tip_string, {0x78, 0x78, 0x78}); - } - void text_editor::_m_draw_parse_string(const keyword_parser& parser, bool rtl, ::nana::point pos, const ::nana::color& fgcolor, const ::nana::char_t* str, std::size_t len) const { graph_.set_text_color(fgcolor); @@ -3010,8 +2966,12 @@ namespace nana{ namespace widgets text_pos.x += static_cast(str_w); } - if (a.y <= static_cast(str_pos.y) && static_cast(str_pos.y) < b.y) - graph_.rectangle({ text_pos, { whitespace_w, line_h_pixels } }, true); + + if (str_pos.y < b.y) + { + if (a.y < str_pos.y || ((a.y == str_pos.y) && (a.x <= str_pos.x ))) + graph_.rectangle({ text_pos, { whitespace_w, line_h_pixels } }, true); + } } else if (b.y == str_pos.y) { @@ -3094,22 +3054,22 @@ namespace nana{ namespace widgets unsigned text_editor::_m_char_by_pixels(const nana::char_t* str, std::size_t len, unsigned * pxbuf, int str_px, int pixels, bool is_rtl) { - unsigned pos = 0; //Result if (graph_.glyph_pixels(str, len, pxbuf)) { if (is_rtl) { //RTL for (std::size_t u = 0; u < len; ++u) { - int chbeg = (str_px - pxbuf[u]); + auto px = static_cast(pxbuf[u]); + auto chbeg = str_px - px; if (chbeg <= pixels && pixels < str_px) { - pos = static_cast(u); - if ((pxbuf[u] <= 1) || (pixels <= chbeg + static_cast(pxbuf[u] >> 1))) - ++pos; - break; + if ((px < 2) || (pixels <= chbeg + (px >> 1))) + return static_cast(u + 1); + + return static_cast(u); } - str_px -= pxbuf[u]; + str_px = chbeg; } } else @@ -3117,31 +3077,30 @@ namespace nana{ namespace widgets //LTR for (std::size_t u = 0; u < len; ++u) { - if (pixels < static_cast(pxbuf[u])) + auto px = static_cast(pxbuf[u]); + if (pixels < px) { - pos = static_cast(u); - if ((pxbuf[u] > 1) && (pixels > static_cast(pxbuf[u] >> 1))) - ++pos; - - break; + if ((px > 1) && (pixels > (px >> 1))) + return static_cast(u + 1); + return static_cast(u); } - pixels -= static_cast(pxbuf[u]); + pixels -= px; } } } - return pos; + return 0; } unsigned text_editor::_m_pixels_by_char(const nana::string& lnstr, std::size_t pos) const { + if (pos > lnstr.size()) + return 0; + unicode_bidi bidi; std::vector reordered; - bidi.linestr(lnstr.c_str(), lnstr.size(), reordered); + bidi.linestr(lnstr.data(), lnstr.size(), reordered); - const nana::char_t * ch = (pos <= lnstr.size() ? lnstr.c_str() + pos : nullptr); - - std::size_t pxbuf_size = 0; - std::unique_ptr pxbuf; + auto ch = lnstr.data() + pos; unsigned text_w = 0; for (auto & ent : reordered) @@ -3151,22 +3110,14 @@ namespace nana{ namespace widgets { if (_m_is_right_text(ent)) { + //Characters of some bidi languages may transform in a word. //RTL - if (len > pxbuf_size) - { - pxbuf.reset(new unsigned[len]); - pxbuf_size = len; - } - + std::unique_ptr pxbuf(new unsigned[len]); graph_.glyph_pixels(ent.begin, len, pxbuf.get()); - text_w = std::accumulate(pxbuf.get() + (ch - ent.begin), pxbuf.get() + len, text_w); + return std::accumulate(pxbuf.get() + (ch - ent.begin), pxbuf.get() + len, text_w); } - else - { - //LTR - text_w += _m_text_extent_size(ent.begin, ch - ent.begin).width; - } - break; + //LTR + return text_w + _m_text_extent_size(ent.begin, ch - ent.begin).width; } else text_w += _m_text_extent_size(ent.begin, len).width;