new features of listbox

text line number and line indent
This commit is contained in:
Jinhao
2015-10-21 01:39:11 +08:00
parent c6f2f28f81
commit 5590dd293b
9 changed files with 232 additions and 20 deletions

View File

@@ -252,7 +252,7 @@ namespace nana{ namespace widgets
virtual std::size_t take_lines(std::size_t pos) const = 0;
virtual void update_line(std::size_t textline, std::size_t secondary_before) = 0;
virtual void render(const ::nana::color& fgcolor) = 0;
virtual std::vector<::nana::upoint> render(const ::nana::color& fgcolor) = 0;
virtual nana::point caret_to_screen(upoint) = 0;
virtual nana::upoint screen_to_caret(point scrpos) = 0;
virtual bool move_caret_ns(bool to_north) = 0;
@@ -290,8 +290,10 @@ namespace nana{ namespace widgets
editor_._m_draw_string(top, API::fgcolor(editor_.window_), nana::upoint(0, editor_.points_.caret.y), editor_.textbase_.getline(textline), true);
}
void render(const ::nana::color& fgcolor) override
std::vector<upoint> render(const ::nana::color& fgcolor) override
{
std::vector<upoint> line_index;
::nana::upoint str_pos(0, static_cast<unsigned>(editor_.points_.offset.y));
std::size_t scrlines = editor_.screen_lines() + str_pos.y;
@@ -304,9 +306,12 @@ namespace nana{ namespace widgets
while( str_pos.y < scrlines)
{
editor_._m_draw_string(top, fgcolor, str_pos, editor_.textbase_.getline(str_pos.y), true);
line_index.push_back(str_pos);
++str_pos.y;
top += pixels;
}
return line_index;
}
nana::point caret_to_screen(nana::upoint pos) override
@@ -692,12 +697,14 @@ namespace nana{ namespace widgets
editor_.render(API::is_focus_ready(editor_.window_));
}
void render(const ::nana::color& fgcolor) override
std::vector<upoint> render(const ::nana::color& fgcolor) override
{
std::vector<upoint> line_index;
std::size_t secondary;
auto primary = _m_textline_from_screen(0, secondary);
if (primary >= linemtr_.size() || secondary >= linemtr_[primary].line_sections.size())
return;
return line_index;
nana::upoint str_pos(0, static_cast<unsigned>(primary));
str_pos.x = static_cast<unsigned>(linemtr_[primary].line_sections[secondary].begin - editor_.textbase_.getline(primary).data());
@@ -715,6 +722,7 @@ namespace nana{ namespace widgets
nana::string text(section.begin, section.end);
editor_._m_draw_string(top, fgcolor, str_pos, text, true);
line_index.push_back(str_pos);
++secondary;
if (secondary >= mtr.line_sections.size())
{
@@ -729,6 +737,8 @@ namespace nana{ namespace widgets
else
break;
}
return line_index;
}
nana::point caret_to_screen(upoint pos) override
@@ -1436,6 +1446,17 @@ namespace nana{ namespace widgets
behavior_->pre_calc_lines(width_pixels());
}
void text_editor::indent(bool enb, std::function<nana::string()> generator)
{
indent_.enabled = enb;
indent_.generator.swap(generator);
}
void text_editor::set_event(event_interface* ptr)
{
event_handler_ = ptr;
}
bool text_editor::line_wrapped() const
{
return attributes_.line_wrapped;
@@ -1500,6 +1521,18 @@ namespace nana{ namespace widgets
return true;
}
rectangle text_editor::text_area(bool including_scroll) const
{
if (including_scroll)
return text_area_.area;
auto r = text_area_.area;
r.width = text_area_.area.width > text_area_.vscroll ? text_area_.area.width - text_area_.vscroll : 0;
r.height = text_area_.area.height > text_area_.hscroll ? text_area_.area.height - text_area_.hscroll : 0;
return r;
}
bool text_editor::tip_string(nana::string&& str)
{
if(attributes_.tip_string == str)
@@ -1873,7 +1906,17 @@ namespace nana{ namespace widgets
return window_;
}
void text_editor::draw_scroll_rectangle()
const std::vector<upoint>& text_editor::text_position() const
{
return text_position_;
}
void text_editor::set_text_position_changed(std::function<void(const std::vector<upoint>&)> fn)
{
text_position_function_.swap(fn);
}
void text_editor::draw_corner()
{
if(text_area_.vscroll && text_area_.hscroll)
{
@@ -1906,11 +1949,27 @@ namespace nana{ namespace widgets
//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 //Draw tip string
graph_.string({ text_area_.area.x - points_.offset.x, text_area_.area.y }, attributes_.tip_string, { 0x78, 0x78, 0x78 });
{
auto && text_pos = behavior_->render(fgcolor);
draw_scroll_rectangle();
if (text_pos.empty())
text_pos.push_back({ 0, 0 });
if (text_pos != text_position_)
{
text_position_.swap(text_pos);
if (event_handler_)
event_handler_->text_position_changed(text_position_);
}
}
else //Draw tip string
graph_.string({ text_area_.area.x - points_.offset.x, text_area_.area.y }, attributes_.tip_string, static_cast<color_rgb>(0x787878));
if (text_position_.empty())
text_position_.push_back({ 0, 0 });
draw_corner();
text_area_.border_renderer(graph_, bgcolor);
}
@@ -1961,7 +2020,7 @@ namespace nana{ namespace widgets
if (refresh || _m_update_caret_line(secondary_before))
render(true);
else
draw_scroll_rectangle();
draw_corner();
_m_scrollbar();
@@ -2049,6 +2108,29 @@ namespace nana{ namespace widgets
need_refresh = true;
}
if (indent_.enabled)
{
nana::string indent_text;
if (indent_.generator)
{
indent_text = indent_.generator();
}
else
{
auto & text = textbase_.getline(points_.caret.y - 1);
auto indent_pos = text.find_first_not_of(L"\t ");
if (indent_pos != std::wstring::npos)
indent_text = text.substr(0, indent_pos);
else
indent_text = text;
}
if (indent_text.size())
put(indent_text);
}
if (behavior_->adjust_caret_into_screen() || need_refresh)
render(true);
@@ -2108,7 +2190,7 @@ namespace nana{ namespace widgets
if(_m_move_offset_x_while_over_border(-2) == false)
{
behavior_->update_line(points_.caret.y, secondary);
draw_scroll_rectangle();
draw_corner();
has_to_redraw = false;
}
}

View File

@@ -410,7 +410,7 @@ namespace nana
{
auto spins_r = _m_spins_area();
if (spins_r.x == 0)
editor_->text_area({});
editor_->text_area(rectangle{});
else
editor_->text_area({ 2, 2, graph_->width() - spins_r.width - 2, spins_r.height - 2 });
}

View File

@@ -24,6 +24,12 @@ namespace nana
: widget(wdg)
{}
arg_textbox_text_position::arg_textbox_text_position(textbox& wdg, const std::vector<upoint>& text_pos)
: widget(wdg),
text_position(text_pos)
{
}
namespace drawerbase {
namespace textbox
{
@@ -41,6 +47,12 @@ namespace drawerbase {
{
widget_.events().text_changed.emit(::nana::arg_textbox{ widget_ });
}
void event_agent::text_position_changed(const std::vector<upoint>& text_pos)
{
::nana::arg_textbox_text_position arg(widget_, text_pos);
widget_.events().text_position_changed.emit(arg);
}
//end class event_agent
//class draweer
@@ -69,6 +81,7 @@ namespace drawerbase {
editor_ = new text_editor(wd, graph, dynamic_cast<::nana::widgets::skeletons::text_editor_scheme*>(scheme));
editor_->textbase().set_event_agent(evt_agent_.get());
editor_->set_event(evt_agent_.get());
_m_text_area(graph.width(), graph.height());
@@ -240,6 +253,16 @@ namespace drawerbase {
editor->textbase().store(std::move(file), encoding);
}
/// 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.
void textbox::enable_indent(bool enb, std::function<nana::string()> generator)
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
editor->indent(enb, generator);
}
textbox& textbox::reset(nana::string str)
{
internal_scope_guard lock;
@@ -495,6 +518,7 @@ namespace drawerbase {
void textbox::set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor)
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
editor->set_highlight(name, fgcolor, bgcolor);
@@ -502,6 +526,7 @@ namespace drawerbase {
void textbox::erase_highlight(const std::string& name)
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
editor->erase_highlight(name);
@@ -509,6 +534,7 @@ namespace drawerbase {
void textbox::set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list<nana::string> kw_list)
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
{
@@ -519,6 +545,7 @@ namespace drawerbase {
void textbox::set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list<std::string> kw_list_utf8)
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
{
@@ -529,11 +556,39 @@ namespace drawerbase {
void textbox::erase_keyword(const nana::string& kw)
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
editor->erase_keyword(kw);
}
std::vector<upoint> textbox::text_position() const
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
return editor->text_position();
return{};
}
rectangle textbox::text_area() const
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
return editor->text_area(false);
return{};
}
unsigned textbox::line_pixels() const
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
return (editor ? editor->line_height() : 0);
}
//Override _m_caption for caption()
nana::string textbox::_m_caption() const throw()
{