highlight certain lines in a textbox(#194)
This commit is contained in:
@@ -90,6 +90,8 @@ namespace nana{ namespace widgets
|
|||||||
void set_keyword(const ::std::wstring& kw, const std::string& name, bool case_sensitive, bool whole_word_matched);
|
void set_keyword(const ::std::wstring& kw, const std::string& name, bool case_sensitive, bool whole_word_matched);
|
||||||
void erase_keyword(const ::std::wstring& kw);
|
void erase_keyword(const ::std::wstring& kw);
|
||||||
|
|
||||||
|
colored_area_access_interface& colored_area();
|
||||||
|
|
||||||
void set_accept(std::function<bool(char_type)>);
|
void set_accept(std::function<bool(char_type)>);
|
||||||
void set_accept(accepts);
|
void set_accept(accepts);
|
||||||
bool respond_char(const arg_keyboard& arg);
|
bool respond_char(const arg_keyboard& arg);
|
||||||
@@ -211,6 +213,7 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
bool try_refresh();
|
bool try_refresh();
|
||||||
private:
|
private:
|
||||||
|
nana::color _m_draw_colored_area(paint::graphics& graph, std::size_t line_pos);
|
||||||
std::vector<upoint> _m_render_text(const ::nana::color& text_color);
|
std::vector<upoint> _m_render_text(const ::nana::color& text_color);
|
||||||
void _m_pre_calc_lines(std::size_t line_off, std::size_t lines);
|
void _m_pre_calc_lines(std::size_t line_off, std::size_t lines);
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,29 @@ namespace nana
|
|||||||
|
|
||||||
virtual void text_exposed(const std::vector<upoint>&) = 0;
|
virtual void text_exposed(const std::vector<upoint>&) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct colored_area_type
|
||||||
|
{
|
||||||
|
const ::std::size_t begin; ///< The begin line position
|
||||||
|
::std::size_t count; ///< The number of lines
|
||||||
|
|
||||||
|
::nana::color bgcolor;
|
||||||
|
::nana::color fgcolor;
|
||||||
|
};
|
||||||
|
|
||||||
|
class colored_area_access_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using colored_area_type = skeletons::colored_area_type;
|
||||||
|
|
||||||
|
virtual ~colored_area_access_interface();
|
||||||
|
|
||||||
|
virtual std::shared_ptr<colored_area_type> get(std::size_t line_pos) = 0;
|
||||||
|
virtual bool clear() = 0;
|
||||||
|
virtual bool remove(std::size_t line_pos) = 0;
|
||||||
|
virtual std::size_t size() const = 0;
|
||||||
|
virtual std::shared_ptr<colored_area_type> at(std::size_t index) = 0;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,9 +100,12 @@ namespace nana
|
|||||||
:public widget_object<category::widget_tag, drawerbase::textbox::drawer, drawerbase::textbox::textbox_events, ::nana::widgets::skeletons::text_editor_scheme>
|
:public widget_object<category::widget_tag, drawerbase::textbox::drawer, drawerbase::textbox::textbox_events, ::nana::widgets::skeletons::text_editor_scheme>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using text_focus_behavior = widgets::skeletons::text_focus_behavior;
|
using colored_area_type = widgets::skeletons::colored_area_type;
|
||||||
|
using colored_area_access_interface = widgets::skeletons::colored_area_access_interface;
|
||||||
|
|
||||||
|
using text_focus_behavior = widgets::skeletons::text_focus_behavior;
|
||||||
using text_positions = std::vector<upoint>;
|
using text_positions = std::vector<upoint>;
|
||||||
|
|
||||||
/// The default constructor without creating the widget.
|
/// The default constructor without creating the widget.
|
||||||
textbox();
|
textbox();
|
||||||
|
|
||||||
@@ -134,6 +137,8 @@ namespace nana
|
|||||||
void store(std::string file);
|
void store(std::string file);
|
||||||
void store(std::string file, nana::unicode encoding);
|
void store(std::string file, nana::unicode encoding);
|
||||||
|
|
||||||
|
colored_area_access_interface* colored_area_access();
|
||||||
|
|
||||||
/// Enables/disables the textbox to indent a line. Idents a new line when it is created by pressing enter.
|
/// 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.
|
/// @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<std::string()> generator = {});
|
textbox& indention(bool, std::function<std::string()> generator = {});
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
#include <nana/gui/element.hpp>
|
#include <nana/gui/element.hpp>
|
||||||
#include <nana/system/dataexch.hpp>
|
#include <nana/system/dataexch.hpp>
|
||||||
#include <nana/unicode_bidi.hpp>
|
#include <nana/unicode_bidi.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <nana/gui/widgets/widget.hpp>
|
#include <nana/gui/widgets/widget.hpp>
|
||||||
#include "content_view.hpp"
|
#include "content_view.hpp"
|
||||||
|
|
||||||
@@ -395,6 +393,91 @@ namespace nana{ namespace widgets
|
|||||||
lazy_refresh
|
lazy_refresh
|
||||||
};
|
};
|
||||||
|
|
||||||
|
colored_area_access_interface::~colored_area_access_interface(){}
|
||||||
|
|
||||||
|
class colored_area_access
|
||||||
|
: public colored_area_access_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void set_window(window handle)
|
||||||
|
{
|
||||||
|
window_handle_ = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<colored_area_type> find(std::size_t pos) const
|
||||||
|
{
|
||||||
|
for (auto i = colored_areas_.cbegin(); i != colored_areas_.cend(); ++i)
|
||||||
|
{
|
||||||
|
if (i->get()->begin <= pos && pos < i->get()->begin + i->get()->count)
|
||||||
|
return *i;
|
||||||
|
else if (i->get()->begin > pos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return{};
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
//Overrides methods of colored_area_access_interface
|
||||||
|
std::shared_ptr<colored_area_type> get(std::size_t line_pos) override
|
||||||
|
{
|
||||||
|
auto i = colored_areas_.cbegin();
|
||||||
|
for (; i != colored_areas_.cend(); ++i)
|
||||||
|
{
|
||||||
|
auto & area = *(i->get());
|
||||||
|
if (area.begin <= line_pos && line_pos < area.begin + area.count)
|
||||||
|
return *i;
|
||||||
|
|
||||||
|
if (area.begin > line_pos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto iter = colored_areas_.emplace(i, std::make_shared<colored_area_type>(colored_area_type{line_pos}));
|
||||||
|
auto & area = *(iter->get());
|
||||||
|
area.count = 1;
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool clear()
|
||||||
|
{
|
||||||
|
if (colored_areas_.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
colored_areas_.clear();
|
||||||
|
API::refresh_window(window_handle_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(std::size_t pos) override
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
for (auto i = colored_areas_.cbegin(); i != colored_areas_.cend();)
|
||||||
|
{
|
||||||
|
if (i->get()->begin <= pos && pos < i->get()->begin + i->get()->count)
|
||||||
|
{
|
||||||
|
i = colored_areas_.erase(i);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if (i->get()->begin > pos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (changed)
|
||||||
|
API::refresh_window(window_handle_);
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size() const override
|
||||||
|
{
|
||||||
|
return colored_areas_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<colored_area_type> at(std::size_t index) override
|
||||||
|
{
|
||||||
|
return colored_areas_.at(index);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
window window_handle_;
|
||||||
|
std::vector<std::shared_ptr<colored_area_type>> colored_areas_;
|
||||||
|
};
|
||||||
|
|
||||||
struct text_editor::implementation
|
struct text_editor::implementation
|
||||||
{
|
{
|
||||||
@@ -406,6 +489,8 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
sync_graph try_refresh{ sync_graph::none };
|
sync_graph try_refresh{ sync_graph::none };
|
||||||
|
|
||||||
|
colored_area_access colored_area;
|
||||||
|
|
||||||
struct inner_capacities
|
struct inner_capacities
|
||||||
{
|
{
|
||||||
editor_behavior_interface * behavior;
|
editor_behavior_interface * behavior;
|
||||||
@@ -1202,6 +1287,11 @@ namespace nana{ namespace widgets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
colored_area_access_interface& text_editor::colored_area()
|
||||||
|
{
|
||||||
|
return impl_->colored_area;
|
||||||
|
}
|
||||||
|
|
||||||
void text_editor::set_accept(std::function<bool(char_type)> pred)
|
void text_editor::set_accept(std::function<bool(char_type)> pred)
|
||||||
{
|
{
|
||||||
@@ -2558,6 +2648,29 @@ namespace nana{ namespace widgets
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
color text_editor::_m_draw_colored_area(paint::graphics& graph, std::size_t line_pos)
|
||||||
|
{
|
||||||
|
auto area = impl_->colored_area.find(line_pos);
|
||||||
|
if (area)
|
||||||
|
{
|
||||||
|
if (!area->bgcolor.invisible())
|
||||||
|
{
|
||||||
|
auto top = _m_caret_to_screen(upoint{ 0, static_cast<unsigned>(line_pos) }).y;
|
||||||
|
|
||||||
|
const unsigned pixels = line_height();
|
||||||
|
const rectangle area_r = { text_area_.area.x, top, width_pixels(), static_cast<unsigned>(pixels * impl_->capacities.behavior->take_lines(line_pos))};
|
||||||
|
|
||||||
|
if (API::is_transparent_background(this->window_))
|
||||||
|
graph.blend(area_r, area->bgcolor, 1);
|
||||||
|
else
|
||||||
|
graph.rectangle(area_r, true, area->bgcolor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return area->fgcolor;
|
||||||
|
}
|
||||||
|
return{};
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<upoint> text_editor::_m_render_text(const color& text_color)
|
std::vector<upoint> text_editor::_m_render_text(const color& text_color)
|
||||||
{
|
{
|
||||||
std::vector<upoint> line_indexes;
|
std::vector<upoint> line_indexes;
|
||||||
@@ -2584,12 +2697,16 @@ namespace nana{ namespace widgets
|
|||||||
if (row.first >= line_count)
|
if (row.first >= line_count)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
auto fgcolor = _m_draw_colored_area(graph_, row.first);
|
||||||
|
if (fgcolor.invisible())
|
||||||
|
fgcolor = text_color;
|
||||||
|
|
||||||
sections = behavior->line(row.first);
|
sections = behavior->line(row.first);
|
||||||
if (row.second < sections.size())
|
if (row.second < sections.size())
|
||||||
{
|
{
|
||||||
auto const & sct = sections[row.second];
|
auto const & sct = sections[row.second];
|
||||||
|
|
||||||
_m_draw_string(top, text_color, str_pos, sct, true);
|
_m_draw_string(top, fgcolor, str_pos, sct, true);
|
||||||
line_indexes.emplace_back(str_pos);
|
line_indexes.emplace_back(str_pos);
|
||||||
++row.second;
|
++row.second;
|
||||||
if (row.second >= sections.size())
|
if (row.second >= sections.size())
|
||||||
@@ -2817,8 +2934,14 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
const unsigned pixels = line_height();
|
const unsigned pixels = line_height();
|
||||||
const rectangle update_area = { text_area_.area.x, top, width_pixels(), static_cast<unsigned>(pixels * secondary_count_before) };
|
const rectangle update_area = { text_area_.area.x, top, width_pixels(), static_cast<unsigned>(pixels * secondary_count_before) };
|
||||||
|
|
||||||
if (!API::dev::copy_transparent_background(window_, update_area, graph_, update_area.position()))
|
if (!API::dev::copy_transparent_background(window_, update_area, graph_, update_area.position()))
|
||||||
|
{
|
||||||
|
_m_draw_colored_area(graph_, pos);
|
||||||
graph_.rectangle(update_area, true, API::bgcolor(window_));
|
graph_.rectangle(update_area, true, API::bgcolor(window_));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_m_draw_colored_area(graph_, pos);
|
||||||
|
|
||||||
auto fgcolor = API::fgcolor(window_);
|
auto fgcolor = API::fgcolor(window_);
|
||||||
auto text_ptr = textbase().getline(pos).c_str();
|
auto text_ptr = textbase().getline(pos).c_str();
|
||||||
@@ -3407,7 +3530,6 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
helper_pencil pencil(graph_, *this, parser);
|
helper_pencil pencil(graph_, *this, parser);
|
||||||
|
|
||||||
|
|
||||||
graph_.palette(true, clr);
|
graph_.palette(true, clr);
|
||||||
graph_.palette(false, scheme_->selection.get_color());
|
graph_.palette(false, scheme_->selection.get_color());
|
||||||
|
|
||||||
|
|||||||
@@ -251,6 +251,15 @@ namespace drawerbase {
|
|||||||
editor->textbase().store(std::move(file), true, encoding);
|
editor->textbase().store(std::move(file), true, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textbox::colored_area_access_interface* textbox::colored_area_access()
|
||||||
|
{
|
||||||
|
auto editor = get_drawer_trigger().editor();
|
||||||
|
if (editor)
|
||||||
|
return &editor->colored_area();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/// Enables/disables the textbox to indent a line. Idents a new line when it is created by pressing enter.
|
/// 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.
|
/// @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<std::string()> generator)
|
textbox& textbox::indention(bool enb, std::function<std::string()> generator)
|
||||||
|
|||||||
Reference in New Issue
Block a user