Code reviews
This commit is contained in:
parent
02b77d2a26
commit
c5025b58a9
@ -221,6 +221,8 @@ namespace nana
|
||||
private:
|
||||
item_proxy _m_at_key(std::shared_ptr<nana::detail::key_interface>&&);
|
||||
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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -10,10 +10,9 @@
|
||||
* @file: nana/gui/widgets/combox.cpp
|
||||
*/
|
||||
|
||||
#include <nana/gui/wvl.hpp>
|
||||
#include <nana/gui.hpp>
|
||||
#include <nana/gui/widgets/combox.hpp>
|
||||
#include <nana/gui/element.hpp>
|
||||
#include <nana/paint/gadget.hpp>
|
||||
#include <nana/system/dataexch.hpp>
|
||||
#include <nana/gui/widgets/float_listbox.hpp>
|
||||
#include <nana/gui/widgets/skeletons/text_editor.hpp>
|
||||
@ -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::string>(nana::charset(s)));
|
||||
return (impl_->at(pos_).item_text == static_cast<nana::string>(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<bool(nana::char_t)> 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<nana::detail::key_interface>&& 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
|
||||
}
|
||||
|
@ -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<unsigned>(editor_.points_.offset.y));
|
||||
|
||||
std::size_t scrlines = editor_.screen_lines() + static_cast<unsigned>(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<int>(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<unsigned>(_m_textline_from_screen(scrpos.y)));
|
||||
nana::upoint res{ 0, static_cast<unsigned>(_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<int>(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<unicode_bidi::entity> 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<unsigned[]> 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<int>(str_w))
|
||||
auto str_px = static_cast<int>(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<int>(str_w), scrpos.x - xbeg, _m_is_right_text(ent));
|
||||
res.x += static_cast<unsigned>(ent.begin - lnstr.c_str());
|
||||
std::unique_ptr<unsigned[]> 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<unsigned>(ent.begin - lnstr.data());
|
||||
return res;
|
||||
}
|
||||
xbeg += static_cast<int>(str_w);
|
||||
scrpos.x -= str_px;
|
||||
}
|
||||
|
||||
res.x = static_cast<int>(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<int>(points.caret.y) < points.offset.y);
|
||||
|
||||
if (static_cast<unsigned>(points.offset.y) > points.caret.y)
|
||||
bool out_of_screen = (static_cast<int>(points.caret.y) < points.offset.y);
|
||||
if (out_of_screen)
|
||||
editor_._m_offset_y(static_cast<int>(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<unsigned>(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<int>(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<int>(editor_.line_height()) + offset_top;
|
||||
|
||||
return (textlines <= static_cast<unsigned>(y) ? textlines - 1 : static_cast<std::size_t>(y));
|
||||
return (textlines <= static_cast<std::size_t>(y) ? textlines - 1 : static_cast<std::size_t>(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<decltype(lines)>::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<int>((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<unsigned[]> pxbuf;
|
||||
|
||||
nana::upoint res(static_cast<unsigned>(str.begin - mtr.line_sections.front().begin), static_cast<unsigned>(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<int>(str_w))
|
||||
auto str_px = static_cast<int>(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<int>(str_w), scrpos.x - xbeg, _m_is_right_text(ent));
|
||||
std::unique_ptr<unsigned[]> 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<unsigned>(ent.begin - str.begin);
|
||||
return res;
|
||||
}
|
||||
xbeg += static_cast<int>(str_w);
|
||||
scrpos.x -= str_px;
|
||||
}
|
||||
res.x = static_cast<unsigned>(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<int>(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<int>(lines + secondary);
|
||||
editor_.points_.offset.y = static_cast<int>(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<int>(editor_.line_height());
|
||||
if (screen_line > static_cast<std::size_t>(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<int>(editor_.line_height());
|
||||
if (screen_line > static_cast<std::size_t>(offset_top))
|
||||
screen_line = 0;
|
||||
else
|
||||
screen_line = static_cast<std::size_t>(points.offset.y) - screen_line;
|
||||
screen_line = static_cast<std::size_t>(offset_top)-screen_line;
|
||||
}
|
||||
else
|
||||
screen_line = static_cast<std::size_t>((y - text_area.area.y) / static_cast<int>(editor_.line_height()) + points.offset.y);
|
||||
screen_line = static_cast<std::size_t>((y - text_area_top) / static_cast<int>(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<int>(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<int>(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<unsigned>(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<unsigned>(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<int>(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<int>(str_w);
|
||||
}
|
||||
if (a.y <= static_cast<unsigned>(str_pos.y) && static_cast<unsigned>(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<int>(pxbuf[u]);
|
||||
auto chbeg = str_px - px;
|
||||
if (chbeg <= pixels && pixels < str_px)
|
||||
{
|
||||
pos = static_cast<unsigned>(u);
|
||||
if ((pxbuf[u] <= 1) || (pixels <= chbeg + static_cast<int>(pxbuf[u] >> 1)))
|
||||
++pos;
|
||||
break;
|
||||
if ((px < 2) || (pixels <= chbeg + (px >> 1)))
|
||||
return static_cast<unsigned>(u + 1);
|
||||
|
||||
return static_cast<unsigned>(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<int>(pxbuf[u]))
|
||||
auto px = static_cast<int>(pxbuf[u]);
|
||||
if (pixels < px)
|
||||
{
|
||||
pos = static_cast<unsigned>(u);
|
||||
if ((pxbuf[u] > 1) && (pixels > static_cast<int>(pxbuf[u] >> 1)))
|
||||
++pos;
|
||||
|
||||
break;
|
||||
if ((px > 1) && (pixels > (px >> 1)))
|
||||
return static_cast<unsigned>(u + 1);
|
||||
return static_cast<unsigned>(u);
|
||||
}
|
||||
pixels -= static_cast<int>(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<unicode_bidi::entity> 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<unsigned[]> 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<unsigned[]> 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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user