From 313ac5183280953979fb55b03286940c0cdd8134 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 10 Apr 2019 03:08:29 +0200 Subject: LibGUI: Turn GTextBox into a wrapper around a single-line GTextEditor. --- Applications/FileManager/main.cpp | 4 +- Applications/FontEditor/FontEditor.cpp | 4 +- Applications/IRCClient/IRCWindow.cpp | 8 +- Applications/TextEditor/Makefile | 2 +- Applications/TextEditor/main.cpp | 4 +- LibGUI/GInputBox.cpp | 4 +- LibGUI/GTextBox.cpp | 213 +-------------------------------- LibGUI/GTextBox.h | 30 +---- LibGUI/GTextEditor.cpp | 6 +- LibGUI/GTextEditor.h | 6 +- Userland/guitest2.cpp | 4 +- 11 files changed, 25 insertions(+), 260 deletions(-) diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp index fd52be97f1..c893375dff 100644 --- a/Applications/FileManager/main.cpp +++ b/Applications/FileManager/main.cpp @@ -69,8 +69,8 @@ int main(int argc, char** argv) progressbar->set_frame_shadow(GFrame::Shadow::Sunken); progressbar->set_frame_thickness(1); - location_textbox->on_return_pressed = [directory_view] (auto& editor) { - directory_view->open(editor.text()); + location_textbox->on_return_pressed = [directory_view, location_textbox] { + directory_view->open(location_textbox->text()); }; file_system_model->on_selection_changed = [&] (auto& index) { diff --git a/Applications/FontEditor/FontEditor.cpp b/Applications/FontEditor/FontEditor.cpp index 86f39c5c31..63f9afed08 100644 --- a/Applications/FontEditor/FontEditor.cpp +++ b/Applications/FontEditor/FontEditor.cpp @@ -33,14 +33,14 @@ FontEditorWidget::FontEditorWidget(const String& path, RetainPtr&& edited_ m_name_textbox = new GTextBox(this); m_name_textbox->set_relative_rect({ 5, 220, 300, 20 }); m_name_textbox->set_text(m_edited_font->name()); - m_name_textbox->on_change = [this] (GTextBox&) { + m_name_textbox->on_change = [this] { m_edited_font->set_name(m_name_textbox->text()); }; m_path_textbox = new GTextBox(this); m_path_textbox->set_relative_rect({ 5, 245, 300, 20 }); m_path_textbox->set_text(m_path); - m_path_textbox->on_change = [this] (GTextBox&) { + m_path_textbox->on_change = [this] { m_path = m_path_textbox->text(); }; diff --git a/Applications/IRCClient/IRCWindow.cpp b/Applications/IRCClient/IRCWindow.cpp index 8f10815fb2..ea00c7801d 100644 --- a/Applications/IRCClient/IRCWindow.cpp +++ b/Applications/IRCClient/IRCWindow.cpp @@ -42,13 +42,13 @@ IRCWindow::IRCWindow(IRCClient& client, void* owner, Type type, const String& na m_text_editor = new GTextEditor(GTextEditor::SingleLine, this); m_text_editor->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); m_text_editor->set_preferred_size({ 0, 19 }); - m_text_editor->on_return_pressed = [this] (GTextEditor& editor) { + m_text_editor->on_return_pressed = [this] { if (m_type == Channel) - m_client.handle_user_input_in_channel(m_name, editor.text()); + m_client.handle_user_input_in_channel(m_name, m_text_editor->text()); else if (m_type == Query) - m_client.handle_user_input_in_query(m_name, editor.text()); + m_client.handle_user_input_in_query(m_name, m_text_editor->text()); else if (m_type == Server) - m_client.handle_user_input_in_server(editor.text()); + m_client.handle_user_input_in_server(m_text_editor->text()); m_text_editor->clear(); }; diff --git a/Applications/TextEditor/Makefile b/Applications/TextEditor/Makefile index 48c77b8a68..4944eef8e2 100644 --- a/Applications/TextEditor/Makefile +++ b/Applications/TextEditor/Makefile @@ -3,7 +3,7 @@ OBJS = \ APP = TextEditor -STANDARD_FLAGS = -std=c++17 +STANDARD_FLAGS = -std=c++17 -Wno-sized-deallocation WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough FLAVOR_FLAGS = -fno-exceptions -fno-rtti OPTIMIZATION_FLAGS = -Os diff --git a/Applications/TextEditor/main.cpp b/Applications/TextEditor/main.cpp index 3e26083e7a..42dc167551 100644 --- a/Applications/TextEditor/main.cpp +++ b/Applications/TextEditor/main.cpp @@ -26,9 +26,9 @@ int main(int argc, char** argv) auto* text_editor = new GTextEditor(GTextEditor::MultiLine, widget); auto* statusbar = new GStatusBar(widget); - text_editor->on_cursor_change = [statusbar] (GTextEditor& editor) { + text_editor->on_cursor_change = [statusbar, text_editor] { StringBuilder builder; - builder.appendf("Line: %d, Column: %d", editor.cursor().line(), editor.cursor().column()); + builder.appendf("Line: %d, Column: %d", text_editor->cursor().line(), text_editor->cursor().column()); statusbar->set_text(builder.to_string()); }; diff --git a/LibGUI/GInputBox.cpp b/LibGUI/GInputBox.cpp index 80dd0e3256..3950f7abb8 100644 --- a/LibGUI/GInputBox.cpp +++ b/LibGUI/GInputBox.cpp @@ -68,10 +68,10 @@ void GInputBox::build() done(ExecOK); }; - m_text_editor->on_return_pressed = [this] (auto&) { + m_text_editor->on_return_pressed = [this] { m_ok_button->click(); }; - m_text_editor->on_escape_pressed = [this] (auto&) { + m_text_editor->on_escape_pressed = [this] { m_cancel_button->click(); }; m_text_editor->set_focus(true); diff --git a/LibGUI/GTextBox.cpp b/LibGUI/GTextBox.cpp index 3f2a48ab31..cd9e1cf495 100644 --- a/LibGUI/GTextBox.cpp +++ b/LibGUI/GTextBox.cpp @@ -1,219 +1,10 @@ -#include "GTextBox.h" -#include -#include -#include -#include -#include +#include GTextBox::GTextBox(GWidget* parent) - : GWidget(parent) + : GTextEditor(GTextEditor::SingleLine, parent) { - set_background_color(Color::White); } GTextBox::~GTextBox() { } - -void GTextBox::set_text(const String& text) -{ - if (m_text == text) - return; - m_text = text; - m_cursor_position = m_text.length(); - scroll_cursor_into_view(HorizontalDirection::Right); - update(); -} - -void GTextBox::scroll_cursor_into_view(HorizontalDirection direction) -{ - if (visible_content_rect().contains(cursor_content_position())) - return; - int total_text_width = font().width(m_text); - dbgprintf("total_text_width = %d, visible_content width = %d\n", total_text_width, visible_content_rect().width()); - if (total_text_width < visible_content_rect().width()) { - m_scroll_offset = 0; - return; - } - if (direction == HorizontalDirection::Left) { - dbgprintf("Left, orig offset = %d\n", m_scroll_offset); - m_scroll_offset = cursor_content_position().x(); - int offset_into_visible = m_scroll_offset - visible_content_rect().x(); - if (offset_into_visible < font().glyph_width(' ')) - m_scroll_offset -= width() / 2; - } else { - m_scroll_offset = cursor_content_position().x() - visible_content_rect().width(); - dbgprintf("Right, orig offset = %d\n", m_scroll_offset); - int offset_into_visible = m_scroll_offset - visible_content_rect().x(); - if (offset_into_visible > width() / 4) { - dbgprintf("Right, adjust offset = %d\n", m_scroll_offset); - m_scroll_offset += width() / 2; - } - } - if (m_scroll_offset < 0) - m_scroll_offset = 0; - if (m_scroll_offset > total_text_width)dbgprintf("Right, adjust offset = %d\n", m_scroll_offset); - m_scroll_offset = total_text_width - width(); -} - -Rect GTextBox::visible_content_rect() const -{ - if (rect().is_empty()) - return { }; - return { m_scroll_offset, 0, rect().shrunken(6, 6).width(), rect().shrunken(6, 6).height() }; -} - -Point GTextBox::cursor_content_position() const -{ - int x = 0; - for (int i = 0; i < m_cursor_position; ++i) - x += font().glyph_width(m_text[i]) + font().glyph_spacing(); - return { x, 0 }; -} - -void GTextBox::paint_event(GPaintEvent& event) -{ - GPainter painter(*this); - painter.add_clip_rect(event.rect()); - - painter.fill_rect(rect().shrunken(2, 2), background_color()); - painter.draw_rect(rect(), foreground_color()); - - if (is_focused()) - painter.draw_focus_rect(rect()); - - Rect inner_rect = rect(); - inner_rect.shrink(6, 6); - - painter.add_clip_rect(inner_rect); - painter.translate(-m_scroll_offset, 0); - - int space_width = font().glyph_width(' ') + font().glyph_spacing(); - int x = inner_rect.x(); - int y = inner_rect.center().y() - font().glyph_height() / 2; - - for (int i = 0; i < m_text.length(); ++i) { - char ch = m_text[i]; - if (ch == ' ') { - x += space_width; - continue; - } - painter.draw_glyph({x, y}, ch, Color::Black); - x += font().glyph_width(ch) + font().glyph_spacing(); - } - - if (is_focused() && m_cursor_blink_state) { - Rect cursor_rect { - inner_rect.x() + cursor_content_position().x(), - inner_rect.y(), - 1, - inner_rect.height() - }; - painter.fill_rect(cursor_rect, foreground_color()); - } -} - -void GTextBox::mousedown_event(GMouseEvent&) -{ -} - -void GTextBox::handle_backspace() -{ - if (m_cursor_position == 0) - return; - - if (m_text.length() == 1) { - m_text = String::empty(); - m_cursor_position = 0; - m_scroll_offset = 0; - if (on_change) - on_change(*this); - update(); - return; - } - - char* buffer; - auto new_text = StringImpl::create_uninitialized(m_text.length() - 1, buffer); - - memcpy(buffer, m_text.characters(), m_cursor_position - 1); - memcpy(buffer + m_cursor_position - 1, m_text.characters() + m_cursor_position, m_text.length() - (m_cursor_position - 1)); - - m_text = move(new_text); - --m_cursor_position; - scroll_cursor_into_view(HorizontalDirection::Left); - if (on_change) - on_change(*this); - update(); -} - -void GTextBox::keydown_event(GKeyEvent& event) -{ - switch (event.key()) { - case KeyCode::Key_Left: - if (m_cursor_position) { - --m_cursor_position; - scroll_cursor_into_view(HorizontalDirection::Left); - } - m_cursor_blink_state = true; - update(); - return; - case KeyCode::Key_Right: - if (m_cursor_position < m_text.length()) { - ++m_cursor_position; - scroll_cursor_into_view(HorizontalDirection::Right); - } - m_cursor_blink_state = true; - update(); - return; - case KeyCode::Key_Backspace: - return handle_backspace(); - case KeyCode::Key_Return: - if (on_return_pressed) - on_return_pressed(*this); - return; - } - - if (!event.text().is_empty()) { - ASSERT(event.text().length() == 1); - - char* buffer; - auto new_text = StringImpl::create_uninitialized(m_text.length() + 1, buffer); - - memcpy(buffer, m_text.characters(), m_cursor_position); - buffer[m_cursor_position] = event.text()[0]; - memcpy(buffer + m_cursor_position + 1, m_text.characters() + m_cursor_position, m_text.length() - m_cursor_position); - - m_text = move(new_text); - ++m_cursor_position; - scroll_cursor_into_view(HorizontalDirection::Right); - if (on_change) - on_change(*this); - update(); - return; - } -} - -void GTextBox::timer_event(GTimerEvent&) -{ - // FIXME: Disable the timer when not focused. - if (!is_focused()) - return; - - m_cursor_blink_state = !m_cursor_blink_state; - update(); -} - -void GTextBox::focusin_event(GEvent&) -{ - start_timer(500); -} - -void GTextBox::focusout_event(GEvent&) -{ - stop_timer(); -} - -void GTextBox::resize_event(GResizeEvent&) -{ - scroll_cursor_into_view(HorizontalDirection::Right); -} diff --git a/LibGUI/GTextBox.h b/LibGUI/GTextBox.h index 7988eb3964..fd05d885b2 100644 --- a/LibGUI/GTextBox.h +++ b/LibGUI/GTextBox.h @@ -1,39 +1,13 @@ #pragma once -#include "GWidget.h" +#include #include -class GTextBox final : public GWidget { +class GTextBox final : public GTextEditor { public: explicit GTextBox(GWidget* parent); virtual ~GTextBox() override; - String text() const { return m_text; } - void set_text(const String&); - - Function on_return_pressed; - Function on_change; - virtual const char* class_name() const override { return "GTextBox"; } - -private: - virtual void paint_event(GPaintEvent&) override; - virtual void mousedown_event(GMouseEvent&) override; - virtual void keydown_event(GKeyEvent&) override; - virtual void timer_event(GTimerEvent&) override; - virtual void focusin_event(GEvent&) override; - virtual void focusout_event(GEvent&) override; - virtual void resize_event(GResizeEvent&) override; - virtual bool accepts_focus() const override { return true; } - - Point cursor_content_position() const; - Rect visible_content_rect() const; - void handle_backspace(); - void scroll_cursor_into_view(HorizontalDirection); - - String m_text; - int m_cursor_position { 0 }; - int m_scroll_offset { 0 }; - bool m_cursor_blink_state { false }; }; diff --git a/LibGUI/GTextEditor.cpp b/LibGUI/GTextEditor.cpp index 1c17d14b0b..25b58eac93 100644 --- a/LibGUI/GTextEditor.cpp +++ b/LibGUI/GTextEditor.cpp @@ -234,7 +234,7 @@ void GTextEditor::keydown_event(GKeyEvent& event) { if (event.key() == KeyCode::Key_Escape) { if (on_escape_pressed) - on_escape_pressed(*this); + on_escape_pressed(); return; } if (event.key() == KeyCode::Key_Up) { @@ -447,7 +447,7 @@ void GTextEditor::insert_at_cursor(char ch) if (ch == '\n') { if (is_single_line()) { if (on_return_pressed) - on_return_pressed(*this); + on_return_pressed(); return; } if (at_tail || at_head) { @@ -561,7 +561,7 @@ void GTextEditor::set_cursor(const GTextPosition& position) update_cursor(); } if (on_cursor_change) - on_cursor_change(*this); + on_cursor_change(); } void GTextEditor::focusin_event(GEvent&) diff --git a/LibGUI/GTextEditor.h b/LibGUI/GTextEditor.h index 42a5df16e7..89e438eb67 100644 --- a/LibGUI/GTextEditor.h +++ b/LibGUI/GTextEditor.h @@ -71,7 +71,7 @@ public: bool is_single_line() const { return m_type == SingleLine; } bool is_multi_line() const { return m_type == MultiLine; } - Function on_cursor_change; + Function on_cursor_change; void set_text(const String&); void scroll_cursor_into_view(); @@ -97,8 +97,8 @@ public: void delete_current_line(); Function on_change; - Function on_return_pressed; - Function on_escape_pressed; + Function on_return_pressed; + Function on_escape_pressed; virtual const char* class_name() const override { return "GTextEditor"; } diff --git a/Userland/guitest2.cpp b/Userland/guitest2.cpp index cb133b4a76..00bd8a34fd 100644 --- a/Userland/guitest2.cpp +++ b/Userland/guitest2.cpp @@ -103,8 +103,8 @@ GWindow* make_launcher_window() auto* textbox = new GTextBox(widget); textbox->set_relative_rect({ 5, 110, 90, 20 }); - textbox->on_return_pressed = [window] (GTextBox& textbox) { - window->set_title(textbox.text()); + textbox->on_return_pressed = [window, textbox] { + window->set_title(textbox->text()); }; auto* other_textbox = new GTextBox(widget); -- cgit v1.2.3