1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 07:08:10 +00:00

GTextEditor: Only paint lines inside the dirty rect.

This dramatically improves performance in large documents. :^)
This commit is contained in:
Andreas Kling 2019-03-07 15:03:38 +01:00
parent 3ee0e82206
commit b4df33e453
2 changed files with 25 additions and 8 deletions

View file

@ -86,15 +86,21 @@ int GTextEditor::content_width() const
return max_width; return max_width;
} }
void GTextEditor::mousedown_event(GMouseEvent& event) GTextPosition GTextEditor::text_position_at(const Point& a_position) const
{ {
auto position = event.position(); auto position = a_position;
position.move_by(m_horizontal_scrollbar->value(), m_vertical_scrollbar->value()); position.move_by(m_horizontal_scrollbar->value(), m_vertical_scrollbar->value());
position.move_by(-padding(), -padding()); position.move_by(-padding(), -padding());
int line_index = position.y() / line_height(); int line_index = position.y() / line_height();
int column_index = position.x() / glyph_width(); int column_index = position.x() / glyph_width();
line_index = min(line_index, line_count() - 1);
column_index = min(column_index, m_lines[line_index].length()); column_index = min(column_index, m_lines[line_index].length());
set_cursor(line_index, column_index); return { line_index, column_index };
}
void GTextEditor::mousedown_event(GMouseEvent& event)
{
set_cursor(text_position_at(event.position()));
} }
void GTextEditor::paint_event(GPaintEvent& event) void GTextEditor::paint_event(GPaintEvent& event)
@ -106,7 +112,10 @@ void GTextEditor::paint_event(GPaintEvent& event)
painter.translate(padding(), padding()); painter.translate(padding(), padding());
int exposed_width = max(content_width(), width()); int exposed_width = max(content_width(), width());
for (int i = 0; i < line_count(); ++i) { int first_visible_line = text_position_at(event.rect().top_left()).line();
int last_visible_line = text_position_at(event.rect().bottom_right()).line();
for (int i = first_visible_line; i <= last_visible_line; ++i) {
auto& line = m_lines[i]; auto& line = m_lines[i];
auto line_rect = line_content_rect(i); auto line_rect = line_content_rect(i);
line_rect.set_width(exposed_width); line_rect.set_width(exposed_width);
@ -258,10 +267,15 @@ void GTextEditor::update_cursor()
void GTextEditor::set_cursor(int line, int column) void GTextEditor::set_cursor(int line, int column)
{ {
if (m_cursor.line() == line && m_cursor.column() == column) set_cursor({ line, column });
}
void GTextEditor::set_cursor(const GTextPosition& position)
{
if (m_cursor == position)
return; return;
auto old_cursor_line_rect = line_widget_rect(m_cursor.line()); auto old_cursor_line_rect = line_widget_rect(m_cursor.line());
m_cursor = GTextPosition(line, column); m_cursor = position;
m_cursor_state = true; m_cursor_state = true;
scroll_cursor_into_view(); scroll_cursor_into_view();
update(old_cursor_line_rect); update(old_cursor_line_rect);

View file

@ -23,6 +23,8 @@ public:
void set_line(int line) { m_line = line; } void set_line(int line) { m_line = line; }
void set_column(int column) { m_column = column; } void set_column(int column) { m_column = column; }
bool operator==(const GTextPosition& other) const { return m_line == other.m_line && m_column == other.m_column; }
private: private:
int m_line { -1 }; int m_line { -1 };
int m_column { -1 }; int m_column { -1 };
@ -57,8 +59,6 @@ private:
virtual void timer_event(GTimerEvent&) override; virtual void timer_event(GTimerEvent&) override;
virtual bool accepts_focus() const override { return true; } virtual bool accepts_focus() const override { return true; }
void insert_at_cursor(char);
class Line { class Line {
public: public:
Line(); Line();
@ -79,8 +79,11 @@ private:
Rect cursor_content_rect() const; Rect cursor_content_rect() const;
void update_cursor(); void update_cursor();
void set_cursor(int line, int column); void set_cursor(int line, int column);
void set_cursor(const GTextPosition&);
Line& current_line() { return m_lines[m_cursor.line()]; } Line& current_line() { return m_lines[m_cursor.line()]; }
const Line& current_line() const { return m_lines[m_cursor.line()]; } const Line& current_line() const { return m_lines[m_cursor.line()]; }
GTextPosition text_position_at(const Point&) const;
void insert_at_cursor(char);
GScrollBar* m_vertical_scrollbar { nullptr }; GScrollBar* m_vertical_scrollbar { nullptr };
GScrollBar* m_horizontal_scrollbar { nullptr }; GScrollBar* m_horizontal_scrollbar { nullptr };