瀏覽代碼

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().
thankyouverycool 5 年之前
父節點
當前提交
b2783a234a

+ 1 - 1
Applications/Browser/Tab.cpp

@@ -261,7 +261,7 @@ Tab::Tab(Type type)
                 auto window = GUI::Window::construct();
                 auto window = GUI::Window::construct();
                 auto& editor = window->set_main_widget<GUI::TextEditor>();
                 auto& editor = window->set_main_widget<GUI::TextEditor>();
                 editor.set_text(source);
                 editor.set_text(source);
-                editor.set_readonly(true);
+                editor.set_mode(GUI::TextEditor::ReadOnly);
                 editor.set_ruler_visible(true);
                 editor.set_ruler_visible(true);
                 window->set_rect(150, 150, 640, 480);
                 window->set_rect(150, 150, 640, 480);
                 window->set_title(url);
                 window->set_title(url);

+ 1 - 1
Applications/SystemMonitor/ProcessStacksWidget.cpp

@@ -35,7 +35,7 @@ ProcessStacksWidget::ProcessStacksWidget()
     set_layout<GUI::VerticalBoxLayout>();
     set_layout<GUI::VerticalBoxLayout>();
     layout()->set_margins({ 4, 4, 4, 4 });
     layout()->set_margins({ 4, 4, 4, 4 });
     m_stacks_editor = add<GUI::TextEditor>();
     m_stacks_editor = add<GUI::TextEditor>();
-    m_stacks_editor->set_readonly(true);
+    m_stacks_editor->set_mode(GUI::TextEditor::ReadOnly);
 
 
     m_timer = add<Core::Timer>(1000, [this] { refresh(); });
     m_timer = add<Core::Timer>(1000, [this] { refresh(); });
 }
 }

+ 2 - 2
DevTools/HackStudio/main.cpp

@@ -734,11 +734,11 @@ void open_file(const String& filename)
     auto project_file = g_project->get_file(filename);
     auto project_file = g_project->get_file(filename);
     if (project_file) {
     if (project_file) {
         current_editor().set_document(const_cast<GUI::TextDocument&>(project_file->document()));
         current_editor().set_document(const_cast<GUI::TextDocument&>(project_file->document()));
-        current_editor().set_readonly(false);
+        current_editor().set_mode(GUI::TextEditor::Editable);
     } else {
     } else {
         auto external_file = ProjectFile::construct_with_name(filename);
         auto external_file = ProjectFile::construct_with_name(filename);
         current_editor().set_document(const_cast<GUI::TextDocument&>(external_file->document()));
         current_editor().set_document(const_cast<GUI::TextDocument&>(external_file->document()));
-        current_editor().set_readonly(true);
+        current_editor().set_mode(GUI::TextEditor::ReadOnly);
     }
     }
 
 
     if (filename.ends_with(".cpp") || filename.ends_with(".h"))
     if (filename.ends_with(".cpp") || filename.ends_with(".h"))

+ 1 - 1
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)
     if (m_only_allow_values_from_model == b)
         return;
         return;
     m_only_allow_values_from_model = b;
     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()
 Model* ComboBox::model()

+ 63 - 8
Libraries/LibGUI/TextEditor.cpp

@@ -201,6 +201,9 @@ void TextEditor::doubleclick_event(MouseEvent& event)
     if (event.button() != MouseButton::Left)
     if (event.button() != MouseButton::Left)
         return;
         return;
 
 
+    if (is_displayonly())
+        return;
+
     // NOTE: This ensures that spans are updated before we look at them.
     // NOTE: This ensures that spans are updated before we look at them.
     flush_pending_change_notification_if_needed();
     flush_pending_change_notification_if_needed();
 
 
@@ -236,6 +239,12 @@ void TextEditor::mousedown_event(MouseEvent& event)
         return;
         return;
     }
     }
 
 
+    if (on_mousedown)
+        on_mousedown();
+
+    if (is_displayonly())
+        return;
+
     if (m_triple_click_timer.is_valid() && m_triple_click_timer.elapsed() < 250) {
     if (m_triple_click_timer.is_valid() && m_triple_click_timer.elapsed() < 250) {
         m_triple_click_timer = Core::ElapsedTimer();
         m_triple_click_timer = Core::ElapsedTimer();
 
 
@@ -364,6 +373,19 @@ void TextEditor::paint_event(PaintEvent& event)
     painter.add_clip_rect(event.rect());
     painter.add_clip_rect(event.rect());
     painter.fill_rect(event.rect(), widget_background_color);
     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());
     painter.translate(frame_thickness(), frame_thickness());
 
 
     auto ruler_rect = ruler_rect_in_inner_coordinates();
     auto ruler_rect = ruler_rect_in_inner_coordinates();
@@ -438,6 +460,8 @@ void TextEditor::paint_event(PaintEvent& event)
             if (!document().has_spans()) {
             if (!document().has_spans()) {
                 // Fast-path for plain text
                 // Fast-path for plain text
                 auto color = palette().color(is_enabled() ? foreground_role() : Gfx::ColorRole::DisabledText);
                 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);
                 painter.draw_text(visual_line_rect, visual_line_text, m_text_alignment, color);
             } else {
             } else {
                 Gfx::IntRect character_rect = { visual_line_rect.location(), { 0, line_height() } };
                 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());
         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());
         painter.fill_rect(cursor_content_rect(), palette().text_cursor());
 }
 }
 
 
@@ -1269,7 +1293,8 @@ void TextEditor::undefer_reflow()
 void TextEditor::enter_event(Core::Event&)
 void TextEditor::enter_event(Core::Event&)
 {
 {
     ASSERT(window());
     ASSERT(window());
-    window()->set_override_cursor(StandardCursor::IBeam);
+    if (!is_displayonly())
+        window()->set_override_cursor(StandardCursor::IBeam);
 
 
     m_automatic_selection_scroll_timer->stop();
     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;
         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()
 void TextEditor::did_update_selection()
@@ -1327,6 +1379,9 @@ void TextEditor::did_update_selection()
 
 
 void TextEditor::context_menu_event(ContextMenuEvent& event)
 void TextEditor::context_menu_event(ContextMenuEvent& event)
 {
 {
+    if (is_displayonly())
+        return;
+
     if (!m_context_menu) {
     if (!m_context_menu) {
         m_context_menu = Menu::construct();
         m_context_menu = Menu::construct();
         m_context_menu->add_action(undo_action());
         m_context_menu->add_action(undo_action());

+ 23 - 4
Libraries/LibGUI/TextEditor.h

@@ -46,6 +46,13 @@ public:
         MultiLine,
         MultiLine,
         SingleLine
         SingleLine
     };
     };
+
+    enum Mode {
+        Editable,
+        ReadOnly,
+        DisplayOnly
+    };
+
     virtual ~TextEditor() override;
     virtual ~TextEditor() override;
 
 
     const TextDocument& document() const { return *m_document; }
     const TextDocument& document() const { return *m_document; }
@@ -53,8 +60,10 @@ public:
 
 
     void set_document(TextDocument&);
     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; }
     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; }
     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_single_line() const { return m_type == SingleLine; }
     bool is_multi_line() const { return m_type == MultiLine; }
     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; }
     bool is_ruler_visible() const { return m_ruler_visible; }
     void set_ruler_visible(bool b) { m_ruler_visible = b; }
     void set_ruler_visible(bool b) { m_ruler_visible = b; }
 
 
@@ -153,7 +168,7 @@ protected:
     virtual void context_menu_event(ContextMenuEvent&) override;
     virtual void context_menu_event(ContextMenuEvent&) override;
     virtual void resize_event(ResizeEvent&) override;
     virtual void resize_event(ResizeEvent&) override;
     virtual void theme_change_event(ThemeChangeEvent&) 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;
     Gfx::IntRect ruler_content_rect(size_t line) const;
 
 
     TextPosition text_position_at(const Gfx::IntPoint&) const;
     TextPosition text_position_at(const Gfx::IntPoint&) const;
@@ -182,6 +197,7 @@ private:
 
 
     int icon_size() const { return 16; }
     int icon_size() const { return 16; }
     int icon_padding() const { return 2; }
     int icon_padding() const { return 2; }
+    int button_padding() const { return m_has_open_button ? 17 : 2; }
 
 
     class ReflowDeferrer {
     class ReflowDeferrer {
     public:
     public:
@@ -194,6 +210,7 @@ private:
         {
         {
             m_editor.undefer_reflow();
             m_editor.undefer_reflow();
         }
         }
+
     private:
     private:
         TextEditor& m_editor;
         TextEditor& m_editor;
     };
     };
@@ -238,6 +255,7 @@ private:
     }
     }
 
 
     Type m_type { MultiLine };
     Type m_type { MultiLine };
+    Mode m_mode { Editable };
 
 
     TextPosition m_cursor;
     TextPosition m_cursor;
     Gfx::TextAlignment m_text_alignment { Gfx::TextAlignment::CenterLeft };
     Gfx::TextAlignment m_text_alignment { Gfx::TextAlignment::CenterLeft };
@@ -247,7 +265,8 @@ private:
     bool m_has_pending_change_notification { false };
     bool m_has_pending_change_notification { false };
     bool m_automatic_indentation_enabled { false };
     bool m_automatic_indentation_enabled { false };
     bool m_line_wrapping_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 };
     int m_line_spacing { 4 };
     size_t m_soft_tab_width { 4 };
     size_t m_soft_tab_width { 4 };
     int m_horizontal_content_padding { 3 };
     int m_horizontal_content_padding { 3 };