highlight certain lines in a textbox(#194)
This commit is contained in:
parent
94bb4103f8
commit
f261fa296e
@ -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 erase_keyword(const ::std::wstring& kw);
|
||||
|
||||
colored_area_access_interface& colored_area();
|
||||
|
||||
void set_accept(std::function<bool(char_type)>);
|
||||
void set_accept(accepts);
|
||||
bool respond_char(const arg_keyboard& arg);
|
||||
@ -211,6 +213,7 @@ namespace nana{ namespace widgets
|
||||
|
||||
bool try_refresh();
|
||||
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);
|
||||
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;
|
||||
};
|
||||
|
||||
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:
|
||||
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>;
|
||||
|
||||
/// The default constructor without creating the widget.
|
||||
textbox();
|
||||
|
||||
@ -134,6 +137,8 @@ namespace nana
|
||||
void store(std::string file);
|
||||
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.
|
||||
/// @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 = {});
|
||||
|
@ -15,8 +15,6 @@
|
||||
#include <nana/gui/element.hpp>
|
||||
#include <nana/system/dataexch.hpp>
|
||||
#include <nana/unicode_bidi.hpp>
|
||||
|
||||
|
||||
#include <nana/gui/widgets/widget.hpp>
|
||||
#include "content_view.hpp"
|
||||
|
||||
@ -395,6 +393,91 @@ namespace nana{ namespace widgets
|
||||
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
|
||||
{
|
||||
@ -406,6 +489,8 @@ namespace nana{ namespace widgets
|
||||
|
||||
sync_graph try_refresh{ sync_graph::none };
|
||||
|
||||
colored_area_access colored_area;
|
||||
|
||||
struct inner_capacities
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -2558,6 +2648,29 @@ namespace nana{ namespace widgets
|
||||
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> line_indexes;
|
||||
@ -2584,12 +2697,16 @@ namespace nana{ namespace widgets
|
||||
if (row.first >= line_count)
|
||||
break;
|
||||
|
||||
auto fgcolor = _m_draw_colored_area(graph_, row.first);
|
||||
if (fgcolor.invisible())
|
||||
fgcolor = text_color;
|
||||
|
||||
sections = behavior->line(row.first);
|
||||
if (row.second < sections.size())
|
||||
{
|
||||
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);
|
||||
++row.second;
|
||||
if (row.second >= sections.size())
|
||||
@ -2817,8 +2934,14 @@ namespace nana{ namespace widgets
|
||||
|
||||
const unsigned pixels = line_height();
|
||||
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()))
|
||||
{
|
||||
_m_draw_colored_area(graph_, pos);
|
||||
graph_.rectangle(update_area, true, API::bgcolor(window_));
|
||||
}
|
||||
else
|
||||
_m_draw_colored_area(graph_, pos);
|
||||
|
||||
auto fgcolor = API::fgcolor(window_);
|
||||
auto text_ptr = textbase().getline(pos).c_str();
|
||||
@ -3407,7 +3530,6 @@ namespace nana{ namespace widgets
|
||||
|
||||
helper_pencil pencil(graph_, *this, parser);
|
||||
|
||||
|
||||
graph_.palette(true, clr);
|
||||
graph_.palette(false, scheme_->selection.get_color());
|
||||
|
||||
|
@ -251,6 +251,15 @@ namespace drawerbase {
|
||||
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.
|
||||
/// @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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user