mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:52:43 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									78039ef057
								
							
						
					
					
						commit
						ec8bffb06d
					
				
					 4 changed files with 24 additions and 30 deletions
				
			
		|  | @ -42,11 +42,11 @@ void GScrollableWidget::resize_event(GResizeEvent& event) | ||||||
| void GScrollableWidget::update_scrollbar_ranges() | void GScrollableWidget::update_scrollbar_ranges() | ||||||
| { | { | ||||||
|     int available_height = height() - m_size_occupied_by_fixed_elements.height() - height_occupied_by_horizontal_scrollbar(); |     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); |     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 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_horizontal_scrollbar->set_range(0, excess_width); | ||||||
| 
 | 
 | ||||||
|     m_vertical_scrollbar->set_big_step(visible_content_rect().height() - m_vertical_scrollbar->step()); |     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(); |     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 | int GScrollableWidget::height_occupied_by_horizontal_scrollbar() const | ||||||
| { | { | ||||||
|     return m_horizontal_scrollbar->is_visible() ? m_horizontal_scrollbar->height() : 0; |     return m_horizontal_scrollbar->is_visible() ? m_horizontal_scrollbar->height() : 0; | ||||||
|  | @ -91,8 +83,8 @@ Rect GScrollableWidget::visible_content_rect() const | ||||||
|     return { |     return { | ||||||
|         m_horizontal_scrollbar->value(), |         m_horizontal_scrollbar->value(), | ||||||
|         m_vertical_scrollbar->value(), |         m_vertical_scrollbar->value(), | ||||||
|         width() - width_occupied_by_vertical_scrollbar() - padding().width() * 2 - m_size_occupied_by_fixed_elements.width(), |         width() - width_occupied_by_vertical_scrollbar() - m_size_occupied_by_fixed_elements.width(), | ||||||
|         height() - height_occupied_by_horizontal_scrollbar() - padding().height() * 2 - m_size_occupied_by_fixed_elements.height() |         height() - height_occupied_by_horizontal_scrollbar() - m_size_occupied_by_fixed_elements.height() | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,19 +8,18 @@ class GScrollableWidget : public GWidget { | ||||||
| public: | public: | ||||||
|     virtual ~GScrollableWidget() override; |     virtual ~GScrollableWidget() override; | ||||||
| 
 | 
 | ||||||
|     virtual const char* class_name() const override { return "GScrollableWidget"; } |  | ||||||
| 
 |  | ||||||
|     Size content_size() const { return m_content_size; } |     Size content_size() const { return m_content_size; } | ||||||
|     int content_width() const { return m_content_size.width(); } |     int content_width() const { return m_content_size.width(); } | ||||||
|     int content_height() const { return m_content_size.height(); } |     int content_height() const { return m_content_size.height(); } | ||||||
| 
 | 
 | ||||||
|     Size padding() const { return m_padding; } |  | ||||||
| 
 |  | ||||||
|     Rect visible_content_rect() const; |     Rect visible_content_rect() const; | ||||||
| 
 | 
 | ||||||
|     void scroll_into_view(const Rect&, Orientation); |     void scroll_into_view(const Rect&, Orientation); | ||||||
|     void scroll_into_view(const Rect&, bool scroll_horizontally, bool scroll_vertically); |     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; } |     GScrollBar& vertical_scrollbar() { return *m_vertical_scrollbar; } | ||||||
|     const GScrollBar& vertical_scrollbar() const { return *m_vertical_scrollbar; } |     const GScrollBar& vertical_scrollbar() const { return *m_vertical_scrollbar; } | ||||||
|     GScrollBar& horizontal_scrollbar() { return *m_horizontal_scrollbar; } |     GScrollBar& horizontal_scrollbar() { return *m_horizontal_scrollbar; } | ||||||
|  | @ -28,15 +27,13 @@ public: | ||||||
|     GWidget& corner_widget() { return *m_corner_widget; } |     GWidget& corner_widget() { return *m_corner_widget; } | ||||||
|     const GWidget& corner_widget() const { return *m_corner_widget; } |     const GWidget& corner_widget() const { return *m_corner_widget; } | ||||||
| 
 | 
 | ||||||
|     void set_scrollbars_enabled(bool); |     virtual const char* class_name() const override { return "GScrollableWidget"; } | ||||||
|     bool is_scrollbars_enabled() const { return m_scrollbars_enabled; } |  | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|     explicit GScrollableWidget(GWidget* parent); |     explicit GScrollableWidget(GWidget* parent); | ||||||
|     virtual void resize_event(GResizeEvent&) override; |     virtual void resize_event(GResizeEvent&) override; | ||||||
|     void set_content_size(const Size&); |     void set_content_size(const Size&); | ||||||
|     void set_size_occupied_by_fixed_elements(const Size&); |     void set_size_occupied_by_fixed_elements(const Size&); | ||||||
|     void set_padding(const Size&); |  | ||||||
| 
 | 
 | ||||||
|     int width_occupied_by_vertical_scrollbar() const; |     int width_occupied_by_vertical_scrollbar() const; | ||||||
|     int height_occupied_by_horizontal_scrollbar() const; |     int height_occupied_by_horizontal_scrollbar() const; | ||||||
|  | @ -49,6 +46,5 @@ private: | ||||||
|     GWidget* m_corner_widget { nullptr }; |     GWidget* m_corner_widget { nullptr }; | ||||||
|     Size m_content_size; |     Size m_content_size; | ||||||
|     Size m_size_occupied_by_fixed_elements; |     Size m_size_occupied_by_fixed_elements; | ||||||
|     Size m_padding; |  | ||||||
|     bool m_scrollbars_enabled { true }; |     bool m_scrollbars_enabled { true }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -13,7 +13,6 @@ GTextEditor::GTextEditor(Type type, GWidget* parent) | ||||||
|     : GScrollableWidget(parent) |     : GScrollableWidget(parent) | ||||||
|     , m_type(type) |     , m_type(type) | ||||||
| { | { | ||||||
|     set_padding({ 3, 3 }); |  | ||||||
|     set_scrollbars_enabled(is_multi_line()); |     set_scrollbars_enabled(is_multi_line()); | ||||||
|     m_ruler_visible = is_multi_line(); |     m_ruler_visible = is_multi_line(); | ||||||
|     set_font(GFontDatabase::the().get_by_name("Csilla Thin")); |     set_font(GFontDatabase::the().get_by_name("Csilla Thin")); | ||||||
|  | @ -53,6 +52,7 @@ void GTextEditor::update_content_size() | ||||||
|     int content_width = 0; |     int content_width = 0; | ||||||
|     for (auto& line : m_lines) |     for (auto& line : m_lines) | ||||||
|         content_width = max(line->width(font()), content_width); |         content_width = max(line->width(font()), content_width); | ||||||
|  |     content_width += m_horizontal_content_padding * 2; | ||||||
|     int content_height = line_count() * line_height(); |     int content_height = line_count() * line_height(); | ||||||
|     set_content_size({ content_width, content_height }); |     set_content_size({ content_width, content_height }); | ||||||
|     set_size_occupied_by_fixed_elements({ ruler_width(), 0 }); |     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; |     auto position = a_position; | ||||||
|     position.move_by(horizontal_scrollbar().value(), vertical_scrollbar().value()); |     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 line_index = position.y() / line_height(); | ||||||
|     int column_index = position.x() / glyph_width(); |     int column_index = position.x() / glyph_width(); | ||||||
|     line_index = max(0, min(line_index, line_count() - 1)); |     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) |     if (!m_ruler_visible) | ||||||
|         return { }; |         return { }; | ||||||
|     return { |     return { | ||||||
|         0 - ruler_width() - padding().width() + horizontal_scrollbar().value(), |         0 - ruler_width() + horizontal_scrollbar().value(), | ||||||
|         line_index * line_height(), |         line_index * line_height(), | ||||||
|         ruler_width(), |         ruler_width(), | ||||||
|         line_height() |         line_height() | ||||||
|  | @ -158,7 +158,7 @@ void GTextEditor::paint_event(GPaintEvent& event) | ||||||
|     painter.save(); |     painter.save(); | ||||||
| 
 | 
 | ||||||
|     painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); |     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 exposed_width = max(content_width(), width()); | ||||||
| 
 | 
 | ||||||
|     int first_visible_line = text_position_at(event.rect().top_left()).line(); |     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) { |         if (line_has_selection) { | ||||||
|             int selection_start_column_on_line = selection.start().line() == i ? selection.start().column() : 0; |             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_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'); |             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() }; |             Rect selection_rect { selection_left, line_rect.y(), selection_right - selection_left, line_rect.height() }; | ||||||
|             painter.fill_rect(selection_rect, Color::from_rgb(0x955233)); |             painter.fill_rect(selection_rect, Color::from_rgb(0x955233)); | ||||||
|  | @ -457,13 +457,13 @@ Rect GTextEditor::cursor_content_rect() const | ||||||
|         return { }; |         return { }; | ||||||
|     ASSERT(!m_lines.is_empty()); |     ASSERT(!m_lines.is_empty()); | ||||||
|     ASSERT(m_cursor.column() <= (current_line().length() + 1)); |     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 | Rect GTextEditor::line_widget_rect(int line_index) const | ||||||
| { | { | ||||||
|     auto rect = line_content_rect(line_index); |     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.set_width(rect.width() + 1); // Add 1 pixel for when the cursor is on the end.
 | ||||||
|     rect.intersect(this->rect()); |     rect.intersect(this->rect()); | ||||||
|     // This feels rather hackish, but extend the rect to the edge of the content view:
 |     // 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() | 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 | Rect GTextEditor::line_content_rect(int line_index) const | ||||||
| { | { | ||||||
|     return { |     return { | ||||||
|         0, |         m_horizontal_content_padding, | ||||||
|         line_index * line_height(), |         line_index * line_height(), | ||||||
|         content_width(), |         content_width(), | ||||||
|         line_height() |         line_height() | ||||||
|  |  | ||||||
|  | @ -157,7 +157,8 @@ private: | ||||||
|     bool m_cursor_state { true }; |     bool m_cursor_state { true }; | ||||||
|     bool m_in_drag_select { false }; |     bool m_in_drag_select { false }; | ||||||
|     bool m_ruler_visible { true }; |     bool m_ruler_visible { true }; | ||||||
|     int m_line_spacing { 2 }; |     int m_line_spacing { 4 }; | ||||||
|     int m_soft_tab_width { 4 }; |     int m_soft_tab_width { 4 }; | ||||||
|  |     int m_horizontal_content_padding { 2 }; | ||||||
|     GTextRange m_selection; |     GTextRange m_selection; | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling