1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 03:47:35 +00:00

GTextEditor: Make the cursor blink while the editor is focused.

This commit is contained in:
Andreas Kling 2019-03-07 01:05:35 +01:00
parent ca65ca2f2d
commit 1f92636c6d
2 changed files with 45 additions and 8 deletions

View file

@ -62,7 +62,7 @@ void GTextEditor::resize_event(GResizeEvent& event)
void GTextEditor::update_scrollbar_ranges() void GTextEditor::update_scrollbar_ranges()
{ {
int available_height = height() - m_horizontal_scrollbar->height(); int available_height = height() - m_horizontal_scrollbar->height();
int excess_height = max(0, (line_count() * font().glyph_height()) - available_height); int excess_height = max(0, (line_count() * line_height()) - available_height);
m_vertical_scrollbar->set_range(0, excess_height); m_vertical_scrollbar->set_range(0, excess_height);
int available_width = width() - m_vertical_scrollbar->width(); int available_width = width() - m_vertical_scrollbar->width();
@ -97,10 +97,11 @@ void GTextEditor::paint_event(GPaintEvent& event)
for (int i = 0; i < line_count(); ++i) { for (int i = 0; i < line_count(); ++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);
painter.draw_text(line_rect, line.text(), TextAlignment::TopLeft, Color::Black); painter.draw_text(line_rect, line.text(), TextAlignment::CenterLeft, Color::Black);
} }
painter.fill_rect(cursor_content_rect(), Color::Red); if (is_focused() && m_cursor_state)
painter.fill_rect(cursor_content_rect(), Color::Red);
painter.translate(-padding(), -padding()); painter.translate(-padding(), -padding());
painter.translate(m_horizontal_scrollbar->value(), m_vertical_scrollbar->value()); painter.translate(m_horizontal_scrollbar->value(), m_vertical_scrollbar->value());
@ -159,14 +160,23 @@ Rect GTextEditor::visible_content_rect() const
Rect GTextEditor::cursor_content_rect() const Rect GTextEditor::cursor_content_rect() const
{ {
ASSERT(m_cursor.is_valid()); if (!m_cursor.is_valid())
return { };
ASSERT(!m_lines.is_empty()); ASSERT(!m_lines.is_empty());
auto& line = m_lines[m_cursor.line()]; auto& line = m_lines[m_cursor.line()];
ASSERT(m_cursor.column() <= (line.text().length() + 1)); ASSERT(m_cursor.column() <= (line.text().length() + 1));
int x = 0; int x = 0;
for (int i = 0; i < m_cursor.column(); ++i) for (int i = 0; i < m_cursor.column(); ++i)
x += font().glyph_width(line.text()[i]); x += font().glyph_width(line.text()[i]);
return { x, m_cursor.line() * font().glyph_height(), 1, font().glyph_height() }; return { x, m_cursor.line() * line_height(), 1, line_height() };
}
Rect GTextEditor::cursor_widget_rect() const
{
ASSERT(m_horizontal_scrollbar);
ASSERT(m_vertical_scrollbar);
auto rect = cursor_content_rect();
return rect.translated(-(m_horizontal_scrollbar->value() - padding()), -(m_vertical_scrollbar->value() - padding()));
} }
void GTextEditor::scroll_into_view(const GTextPosition& position, Orientation orientation) void GTextEditor::scroll_into_view(const GTextPosition& position, Orientation orientation)
@ -195,15 +205,15 @@ Rect GTextEditor::line_content_rect(int line_index) const
auto& line = m_lines[line_index]; auto& line = m_lines[line_index];
return { return {
0, 0,
line_index * font().glyph_height(), line_index * line_height(),
line.width(font()), line.width(font()),
font().glyph_height() line_height()
}; };
} }
void GTextEditor::update_cursor() void GTextEditor::update_cursor()
{ {
update(); update(cursor_widget_rect());
} }
void GTextEditor::set_cursor(int line, int column) void GTextEditor::set_cursor(int line, int column)
@ -212,11 +222,30 @@ void GTextEditor::set_cursor(int line, int column)
return; return;
update_cursor(); update_cursor();
m_cursor = GTextPosition(line, column); m_cursor = GTextPosition(line, column);
m_cursor_state = true;
update_cursor(); update_cursor();
if (on_cursor_change) if (on_cursor_change)
on_cursor_change(*this); on_cursor_change(*this);
} }
void GTextEditor::focusin_event(GEvent&)
{
update_cursor();
start_timer(500);
}
void GTextEditor::focusout_event(GEvent&)
{
stop_timer();
}
void GTextEditor::timer_event(GTimerEvent&)
{
m_cursor_state = !m_cursor_state;
if (is_focused())
update_cursor();
}
void GTextEditor::Line::set_text(const String& text) void GTextEditor::Line::set_text(const String& text)
{ {
if (text == m_text) if (text == m_text)

View file

@ -40,6 +40,8 @@ public:
Rect visible_content_rect() const; Rect visible_content_rect() const;
void scroll_into_view(const GTextPosition&, Orientation); void scroll_into_view(const GTextPosition&, Orientation);
int line_count() const { return m_lines.size(); } int line_count() const { return m_lines.size(); }
int line_spacing() const { return m_line_spacing; }
int line_height() const { return font().glyph_height() + m_line_spacing; }
int padding() const { return 2; } int padding() const { return 2; }
GTextPosition cursor() const { return m_cursor; } GTextPosition cursor() const { return m_cursor; }
@ -48,11 +50,15 @@ private:
virtual void resize_event(GResizeEvent&) override; virtual void resize_event(GResizeEvent&) override;
virtual void mousedown_event(GMouseEvent&) override; virtual void mousedown_event(GMouseEvent&) override;
virtual void keydown_event(GKeyEvent&) override; virtual void keydown_event(GKeyEvent&) override;
virtual void focusin_event(GEvent&) override;
virtual void focusout_event(GEvent&) override;
virtual void timer_event(GTimerEvent&) override;
virtual bool accepts_focus() const override { return true; } virtual bool accepts_focus() const override { return true; }
void update_scrollbar_ranges(); void update_scrollbar_ranges();
Rect line_content_rect(int item_index) const; Rect line_content_rect(int item_index) const;
Rect cursor_content_rect() const; Rect cursor_content_rect() const;
Rect cursor_widget_rect() const;
void update_cursor(); void update_cursor();
void set_cursor(int line, int column); void set_cursor(int line, int column);
@ -74,4 +80,6 @@ private:
}; };
Vector<Line> m_lines; Vector<Line> m_lines;
GTextPosition m_cursor; GTextPosition m_cursor;
bool m_cursor_state { true };
int m_line_spacing { 2 };
}; };