From ec8bffb06d9d4e7609f6aa0969e77f16731d7ea5 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 16 Mar 2019 23:16:37 +0100 Subject: [PATCH] LibGUI: Let GTextEditor deal with its horizontal padding internally. I originally wanted to have the padding concept in GScrollableWidget but it's really finicky with the ruler and everything. --- LibGUI/GScrollableWidget.cpp | 16 ++++------------ LibGUI/GScrollableWidget.h | 12 ++++-------- LibGUI/GTextEditor.cpp | 23 ++++++++++++++--------- LibGUI/GTextEditor.h | 3 ++- 4 files changed, 24 insertions(+), 30 deletions(-) diff --git a/LibGUI/GScrollableWidget.cpp b/LibGUI/GScrollableWidget.cpp index 0292f966fc..8e34fa0732 100644 --- a/LibGUI/GScrollableWidget.cpp +++ b/LibGUI/GScrollableWidget.cpp @@ -42,11 +42,11 @@ void GScrollableWidget::resize_event(GResizeEvent& event) void GScrollableWidget::update_scrollbar_ranges() { int available_height = height() - m_size_occupied_by_fixed_elements.height() - height_occupied_by_horizontal_scrollbar(); - int excess_height = max(0, (m_content_size.height() + m_padding.height() * 2) - available_height); + int excess_height = max(0, m_content_size.height() - available_height); m_vertical_scrollbar->set_range(0, excess_height); int available_width = width() - m_size_occupied_by_fixed_elements.width() - width_occupied_by_vertical_scrollbar(); - int excess_width = max(0, (m_content_size.width() + m_padding.height() * 2) - available_width); + int excess_width = max(0, m_content_size.width() - available_width); m_horizontal_scrollbar->set_range(0, excess_width); m_vertical_scrollbar->set_big_step(visible_content_rect().height() - m_vertical_scrollbar->step()); @@ -68,14 +68,6 @@ void GScrollableWidget::set_size_occupied_by_fixed_elements(const Size& size) update_scrollbar_ranges(); } -void GScrollableWidget::set_padding(const Size& size) -{ - if (m_padding == size) - return; - m_padding = size; - update_scrollbar_ranges(); -} - int GScrollableWidget::height_occupied_by_horizontal_scrollbar() const { return m_horizontal_scrollbar->is_visible() ? m_horizontal_scrollbar->height() : 0; @@ -91,8 +83,8 @@ Rect GScrollableWidget::visible_content_rect() const return { m_horizontal_scrollbar->value(), m_vertical_scrollbar->value(), - width() - width_occupied_by_vertical_scrollbar() - padding().width() * 2 - m_size_occupied_by_fixed_elements.width(), - height() - height_occupied_by_horizontal_scrollbar() - padding().height() * 2 - m_size_occupied_by_fixed_elements.height() + width() - width_occupied_by_vertical_scrollbar() - m_size_occupied_by_fixed_elements.width(), + height() - height_occupied_by_horizontal_scrollbar() - m_size_occupied_by_fixed_elements.height() }; } diff --git a/LibGUI/GScrollableWidget.h b/LibGUI/GScrollableWidget.h index d48bf5b793..8efb70dcd6 100644 --- a/LibGUI/GScrollableWidget.h +++ b/LibGUI/GScrollableWidget.h @@ -8,19 +8,18 @@ class GScrollableWidget : public GWidget { public: virtual ~GScrollableWidget() override; - virtual const char* class_name() const override { return "GScrollableWidget"; } - Size content_size() const { return m_content_size; } int content_width() const { return m_content_size.width(); } int content_height() const { return m_content_size.height(); } - Size padding() const { return m_padding; } - Rect visible_content_rect() const; void scroll_into_view(const Rect&, Orientation); void scroll_into_view(const Rect&, bool scroll_horizontally, bool scroll_vertically); + void set_scrollbars_enabled(bool); + bool is_scrollbars_enabled() const { return m_scrollbars_enabled; } + GScrollBar& vertical_scrollbar() { return *m_vertical_scrollbar; } const GScrollBar& vertical_scrollbar() const { return *m_vertical_scrollbar; } GScrollBar& horizontal_scrollbar() { return *m_horizontal_scrollbar; } @@ -28,15 +27,13 @@ public: GWidget& corner_widget() { return *m_corner_widget; } const GWidget& corner_widget() const { return *m_corner_widget; } - void set_scrollbars_enabled(bool); - bool is_scrollbars_enabled() const { return m_scrollbars_enabled; } + virtual const char* class_name() const override { return "GScrollableWidget"; } protected: explicit GScrollableWidget(GWidget* parent); virtual void resize_event(GResizeEvent&) override; void set_content_size(const Size&); void set_size_occupied_by_fixed_elements(const Size&); - void set_padding(const Size&); int width_occupied_by_vertical_scrollbar() const; int height_occupied_by_horizontal_scrollbar() const; @@ -49,6 +46,5 @@ private: GWidget* m_corner_widget { nullptr }; Size m_content_size; Size m_size_occupied_by_fixed_elements; - Size m_padding; bool m_scrollbars_enabled { true }; }; diff --git a/LibGUI/GTextEditor.cpp b/LibGUI/GTextEditor.cpp index 2a815d22b2..f8d1c02a10 100644 --- a/LibGUI/GTextEditor.cpp +++ b/LibGUI/GTextEditor.cpp @@ -13,7 +13,6 @@ GTextEditor::GTextEditor(Type type, GWidget* parent) : GScrollableWidget(parent) , m_type(type) { - set_padding({ 3, 3 }); set_scrollbars_enabled(is_multi_line()); m_ruler_visible = is_multi_line(); set_font(GFontDatabase::the().get_by_name("Csilla Thin")); @@ -53,6 +52,7 @@ void GTextEditor::update_content_size() int content_width = 0; for (auto& line : m_lines) content_width = max(line->width(font()), content_width); + content_width += m_horizontal_content_padding * 2; int content_height = line_count() * line_height(); set_content_size({ content_width, content_height }); set_size_occupied_by_fixed_elements({ ruler_width(), 0 }); @@ -62,7 +62,7 @@ GTextPosition GTextEditor::text_position_at(const Point& a_position) const { auto position = a_position; position.move_by(horizontal_scrollbar().value(), vertical_scrollbar().value()); - position.move_by(-(padding().width() + ruler_width()), -padding().height()); + position.move_by(-(m_horizontal_content_padding + ruler_width()), 0); int line_index = position.y() / line_height(); int column_index = position.x() / glyph_width(); line_index = max(0, min(line_index, line_count() - 1)); @@ -133,7 +133,7 @@ Rect GTextEditor::ruler_content_rect(int line_index) const if (!m_ruler_visible) return { }; return { - 0 - ruler_width() - padding().width() + horizontal_scrollbar().value(), + 0 - ruler_width() + horizontal_scrollbar().value(), line_index * line_height(), ruler_width(), line_height() @@ -158,7 +158,7 @@ void GTextEditor::paint_event(GPaintEvent& event) painter.save(); painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); - painter.translate(padding().width() + ruler_width(), padding().height()); + painter.translate(ruler_width(), 0); int exposed_width = max(content_width(), width()); int first_visible_line = text_position_at(event.rect().top_left()).line(); @@ -194,7 +194,7 @@ void GTextEditor::paint_event(GPaintEvent& event) if (line_has_selection) { int selection_start_column_on_line = selection.start().line() == i ? selection.start().column() : 0; int selection_end_column_on_line = selection.end().line() == i ? selection.end().column() : line.length(); - int selection_left = selection_start_column_on_line * font().glyph_width('x'); + int selection_left = m_horizontal_content_padding + selection_start_column_on_line * font().glyph_width('x'); int selection_right = line_rect.left() + selection_end_column_on_line * font().glyph_width('x'); Rect selection_rect { selection_left, line_rect.y(), selection_right - selection_left, line_rect.height() }; painter.fill_rect(selection_rect, Color::from_rgb(0x955233)); @@ -457,13 +457,13 @@ Rect GTextEditor::cursor_content_rect() const return { }; ASSERT(!m_lines.is_empty()); ASSERT(m_cursor.column() <= (current_line().length() + 1)); - return { m_cursor.column() * glyph_width(), m_cursor.line() * line_height(), 1, line_height() }; + return { m_horizontal_content_padding + m_cursor.column() * glyph_width(), m_cursor.line() * line_height(), 1, line_height() }; } Rect GTextEditor::line_widget_rect(int line_index) const { auto rect = line_content_rect(line_index); - rect.move_by(-(horizontal_scrollbar().value() - padding().width()), -(vertical_scrollbar().value() - padding().height())); + rect.move_by(-(horizontal_scrollbar().value() - m_horizontal_content_padding), -(vertical_scrollbar().value())); rect.set_width(rect.width() + 1); // Add 1 pixel for when the cursor is on the end. rect.intersect(this->rect()); // This feels rather hackish, but extend the rect to the edge of the content view: @@ -473,13 +473,18 @@ Rect GTextEditor::line_widget_rect(int line_index) const void GTextEditor::scroll_cursor_into_view() { - scroll_into_view(cursor_content_rect(), true, true); + auto rect = cursor_content_rect(); + if (m_cursor.column() == 0) + rect.set_x(0); + else if (m_cursor.column() >= m_lines[m_cursor.line()]->length()) + rect.set_x(m_lines[m_cursor.line()]->width(font()) + m_horizontal_content_padding * 2); + scroll_into_view(rect, true, true); } Rect GTextEditor::line_content_rect(int line_index) const { return { - 0, + m_horizontal_content_padding, line_index * line_height(), content_width(), line_height() diff --git a/LibGUI/GTextEditor.h b/LibGUI/GTextEditor.h index 9259737c9a..b4eb35b5d3 100644 --- a/LibGUI/GTextEditor.h +++ b/LibGUI/GTextEditor.h @@ -157,7 +157,8 @@ private: bool m_cursor_state { true }; bool m_in_drag_select { false }; bool m_ruler_visible { true }; - int m_line_spacing { 2 }; + int m_line_spacing { 4 }; int m_soft_tab_width { 4 }; + int m_horizontal_content_padding { 2 }; GTextRange m_selection; };