mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 09:42:45 +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() | ||||
| { | ||||
|     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() | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 }; | ||||
| }; | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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; | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling