From b2783a234aa14e5c382d9bf225b4ec54d9b98852 Mon Sep 17 00:00:00 2001 From: thankyouverycool <66646555+thankyouverycool@users.noreply.github.com> Date: Tue, 14 Jul 2020 17:02:46 -0400 Subject: LibGUI: Use enum for TextEditor modes & add new DisplayOnly mode Adds a new, more restrictive read-only state to TextEditor which forbids copying, selecting, editor cursors, and context menus. Provides a unique appearance on focus which accomodates ComboBox widgets. All TextEditor modes are now accessed by enum and set_mode() which sets the editor to Editable, ReadOnly or DisplayOnly. Updates applications still using set_readonly(). --- Libraries/LibGUI/ComboBox.cpp | 2 +- Libraries/LibGUI/TextEditor.cpp | 71 ++++++++++++++++++++++++++++++++++++----- Libraries/LibGUI/TextEditor.h | 27 +++++++++++++--- 3 files changed, 87 insertions(+), 13 deletions(-) (limited to 'Libraries') diff --git a/Libraries/LibGUI/ComboBox.cpp b/Libraries/LibGUI/ComboBox.cpp index 7516760261..42a0bdf61e 100644 --- a/Libraries/LibGUI/ComboBox.cpp +++ b/Libraries/LibGUI/ComboBox.cpp @@ -177,7 +177,7 @@ void ComboBox::set_only_allow_values_from_model(bool b) if (m_only_allow_values_from_model == b) return; m_only_allow_values_from_model = b; - m_editor->set_readonly(m_only_allow_values_from_model); + m_editor->set_mode(m_only_allow_values_from_model ? TextEditor::DisplayOnly : TextEditor::Editable); } Model* ComboBox::model() diff --git a/Libraries/LibGUI/TextEditor.cpp b/Libraries/LibGUI/TextEditor.cpp index 7eb199c732..7533f9a4e1 100644 --- a/Libraries/LibGUI/TextEditor.cpp +++ b/Libraries/LibGUI/TextEditor.cpp @@ -201,6 +201,9 @@ void TextEditor::doubleclick_event(MouseEvent& event) if (event.button() != MouseButton::Left) return; + if (is_displayonly()) + return; + // NOTE: This ensures that spans are updated before we look at them. flush_pending_change_notification_if_needed(); @@ -236,6 +239,12 @@ void TextEditor::mousedown_event(MouseEvent& event) return; } + if (on_mousedown) + on_mousedown(); + + if (is_displayonly()) + return; + if (m_triple_click_timer.is_valid() && m_triple_click_timer.elapsed() < 250) { m_triple_click_timer = Core::ElapsedTimer(); @@ -364,6 +373,19 @@ void TextEditor::paint_event(PaintEvent& event) painter.add_clip_rect(event.rect()); painter.fill_rect(event.rect(), widget_background_color); + if (is_displayonly() && (is_focused() || has_visible_list())) { + widget_background_color = palette().selection(); + Gfx::IntRect display_rect { + widget_inner_rect().x() + 1, + widget_inner_rect().y() + 1, + widget_inner_rect().width() - button_padding(), + widget_inner_rect().height() - 2 + }; + painter.add_clip_rect(display_rect); + painter.add_clip_rect(event.rect()); + painter.fill_rect(event.rect(), widget_background_color); + } + painter.translate(frame_thickness(), frame_thickness()); auto ruler_rect = ruler_rect_in_inner_coordinates(); @@ -438,6 +460,8 @@ void TextEditor::paint_event(PaintEvent& event) if (!document().has_spans()) { // Fast-path for plain text auto color = palette().color(is_enabled() ? foreground_role() : Gfx::ColorRole::DisabledText); + if (is_displayonly() && (is_focused() || has_visible_list())) + color = palette().color(is_enabled() ? Gfx::ColorRole::SelectionText : Gfx::ColorRole::DisabledText); painter.draw_text(visual_line_rect, visual_line_text, m_text_alignment, color); } else { Gfx::IntRect character_rect = { visual_line_rect.location(), { 0, line_height() } }; @@ -521,7 +545,7 @@ void TextEditor::paint_event(PaintEvent& event) painter.draw_scaled_bitmap(icon_rect, *m_icon, m_icon->rect()); } - if (is_focused() && m_cursor_state) + if (is_focused() && m_cursor_state && !is_displayonly()) painter.fill_rect(cursor_content_rect(), palette().text_cursor()); } @@ -1269,7 +1293,8 @@ void TextEditor::undefer_reflow() void TextEditor::enter_event(Core::Event&) { ASSERT(window()); - window()->set_override_cursor(StandardCursor::IBeam); + if (!is_displayonly()) + window()->set_override_cursor(StandardCursor::IBeam); m_automatic_selection_scroll_timer->stop(); } @@ -1302,15 +1327,42 @@ void TextEditor::did_change() }); } } +void TextEditor::set_mode(const Mode mode) +{ + if (m_mode == mode) + return; + m_mode = mode; + switch (mode) { + case Editable: + m_cut_action->set_enabled(true && has_selection()); + m_delete_action->set_enabled(true); + m_paste_action->set_enabled(true); + set_accepts_emoji_input(true); + break; + case ReadOnly: + case DisplayOnly: + m_cut_action->set_enabled(false && has_selection()); + m_delete_action->set_enabled(false); + m_paste_action->set_enabled(false); + set_accepts_emoji_input(false); + break; + default: + ASSERT_NOT_REACHED(); + } +} -void TextEditor::set_readonly(bool readonly) +void TextEditor::set_has_open_button(bool has_button) { - if (m_readonly == readonly) + if (m_has_open_button == has_button) return; - m_readonly = readonly; - m_cut_action->set_enabled(!is_readonly() && has_selection()); - m_delete_action->set_enabled(!is_readonly()); - m_paste_action->set_enabled(!is_readonly()); + m_has_open_button = has_button; +} + +void TextEditor::set_has_visible_list(bool visible) +{ + if (m_has_visible_list == visible) + return; + m_has_visible_list = visible; } void TextEditor::did_update_selection() @@ -1327,6 +1379,9 @@ void TextEditor::did_update_selection() void TextEditor::context_menu_event(ContextMenuEvent& event) { + if (is_displayonly()) + return; + if (!m_context_menu) { m_context_menu = Menu::construct(); m_context_menu->add_action(undo_action()); diff --git a/Libraries/LibGUI/TextEditor.h b/Libraries/LibGUI/TextEditor.h index 7d505a6b13..a3695090e5 100644 --- a/Libraries/LibGUI/TextEditor.h +++ b/Libraries/LibGUI/TextEditor.h @@ -46,6 +46,13 @@ public: MultiLine, SingleLine }; + + enum Mode { + Editable, + ReadOnly, + DisplayOnly + }; + virtual ~TextEditor() override; const TextDocument& document() const { return *m_document; } @@ -53,8 +60,10 @@ public: void set_document(TextDocument&); - bool is_readonly() const { return m_readonly; } - void set_readonly(bool); + bool has_visible_list() const { return m_has_visible_list; } + void set_has_visible_list(bool); + bool has_open_button() const { return m_has_open_button; } + void set_has_open_button(bool); virtual bool is_automatic_indentation_enabled() const final { return m_automatic_indentation_enabled; } void set_automatic_indentation_enabled(bool enabled) { m_automatic_indentation_enabled = enabled; } @@ -71,6 +80,12 @@ public: bool is_single_line() const { return m_type == SingleLine; } bool is_multi_line() const { return m_type == MultiLine; } + Mode mode() const { return m_mode; } + bool is_editable() const { return m_mode == Editable; } + bool is_readonly() const { return m_mode == ReadOnly; } + bool is_displayonly() const { return m_mode == DisplayOnly; } + void set_mode(const Mode); + bool is_ruler_visible() const { return m_ruler_visible; } void set_ruler_visible(bool b) { m_ruler_visible = b; } @@ -153,7 +168,7 @@ protected: virtual void context_menu_event(ContextMenuEvent&) override; virtual void resize_event(ResizeEvent&) override; virtual void theme_change_event(ThemeChangeEvent&) override; - virtual void cursor_did_change() {} + virtual void cursor_did_change() { } Gfx::IntRect ruler_content_rect(size_t line) const; TextPosition text_position_at(const Gfx::IntPoint&) const; @@ -182,6 +197,7 @@ private: int icon_size() const { return 16; } int icon_padding() const { return 2; } + int button_padding() const { return m_has_open_button ? 17 : 2; } class ReflowDeferrer { public: @@ -194,6 +210,7 @@ private: { m_editor.undefer_reflow(); } + private: TextEditor& m_editor; }; @@ -238,6 +255,7 @@ private: } Type m_type { MultiLine }; + Mode m_mode { Editable }; TextPosition m_cursor; Gfx::TextAlignment m_text_alignment { Gfx::TextAlignment::CenterLeft }; @@ -247,7 +265,8 @@ private: bool m_has_pending_change_notification { false }; bool m_automatic_indentation_enabled { false }; bool m_line_wrapping_enabled { false }; - bool m_readonly { false }; + bool m_has_visible_list { false }; + bool m_has_open_button { false }; int m_line_spacing { 4 }; size_t m_soft_tab_width { 4 }; int m_horizontal_content_padding { 3 }; -- cgit v1.2.3