From f88e550998440fb2b4b130aade6c7efe2614ca13 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 19 Mar 2019 02:20:00 +0100 Subject: [PATCH] LibGUI: More work on GInputBox. - If the GInputBox has a parent and the parent is a GWindow, center the input box window within the parent window. This looks quite nice. - Stop processing events in a nested event loop immediately after it's been asked to quit. - Fix GWidget::parent_widget() behavior for non-widget parents. --- Applications/IRCClient/IRCAppWindow.cpp | 6 ++-- LibGUI/GDialog.cpp | 18 ++++++++-- LibGUI/GDialog.h | 6 +++- LibGUI/GEventLoop.cpp | 7 ++++ LibGUI/GInputBox.cpp | 46 ++++++++++++------------- LibGUI/GInputBox.h | 9 +++-- LibGUI/GObject.h | 1 + LibGUI/GWidget.h | 14 ++++++-- LibGUI/GWindow.h | 1 + 9 files changed, 74 insertions(+), 34 deletions(-) diff --git a/Applications/IRCClient/IRCAppWindow.cpp b/Applications/IRCClient/IRCAppWindow.cpp index e446a6eee7..30889f670a 100644 --- a/Applications/IRCClient/IRCAppWindow.cpp +++ b/Applications/IRCClient/IRCAppWindow.cpp @@ -50,7 +50,7 @@ void IRCAppWindow::setup_client() void IRCAppWindow::setup_actions() { m_join_action = GAction::create("Join channel", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-join.rgb", { 16, 16 }), [&] (auto&) { - GInputBox input_box("Enter nickname:", "Join channel"); + GInputBox input_box("Enter nickname:", "Join channel", this); if (input_box.exec() == GInputBox::ExecOK) m_client.handle_join_action(input_box.text_value()); }); @@ -60,13 +60,13 @@ void IRCAppWindow::setup_actions() }); m_whois_action = GAction::create("Whois user", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-whois.rgb", { 16, 16 }), [&] (auto&) { - GInputBox input_box("Enter nickname:", "IRC WHOIS lookup"); + GInputBox input_box("Enter nickname:", "IRC WHOIS lookup", this); if (input_box.exec() == GInputBox::ExecOK) m_client.handle_whois_action(input_box.text_value()); }); m_open_query_action = GAction::create("Open query", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-open-query.rgb", { 16, 16 }), [&] (auto&) { - GInputBox input_box("Enter nickname:", "Open IRC query with..."); + GInputBox input_box("Enter nickname:", "Open IRC query with...", this); if (input_box.exec() == GInputBox::ExecOK) m_client.handle_open_query_action(input_box.text_value()); }); diff --git a/LibGUI/GDialog.cpp b/LibGUI/GDialog.cpp index 97f0c103c6..d6a925bfb2 100644 --- a/LibGUI/GDialog.cpp +++ b/LibGUI/GDialog.cpp @@ -14,13 +14,25 @@ GDialog::~GDialog() int GDialog::exec() { - GEventLoop loop; + ASSERT(!m_event_loop); + m_event_loop = make(); + if (parent() && parent()->is_window()) { + auto& parent_window = *static_cast(parent()); + auto new_rect = rect(); + new_rect.center_within(parent_window.rect()); + set_rect(new_rect); + } show(); - return loop.exec(); + auto result = m_event_loop->exec(); + m_event_loop = nullptr; + dbgprintf("event loop returned with result %d\n", result); + return result; } void GDialog::done(int result) { + ASSERT(m_event_loop); m_result = result; - GEventLoop::current().quit(result); + dbgprintf("quit event loop with result %d\n", result); + m_event_loop->quit(result); } diff --git a/LibGUI/GDialog.h b/LibGUI/GDialog.h index 9dcf88a772..e6cefbce98 100644 --- a/LibGUI/GDialog.h +++ b/LibGUI/GDialog.h @@ -1,9 +1,12 @@ #pragma once #include +#include class GDialog : public GWindow { public: + enum ExecResult { ExecOK = 0, ExecCancel = 1, ExecAborted = 2 }; + virtual ~GDialog() override; int exec(); @@ -15,5 +18,6 @@ protected: explicit GDialog(GObject* parent); private: - int m_result { 0 }; + OwnPtr m_event_loop; + int m_result { ExecAborted }; }; diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index ed9aba0726..accf6fae59 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -158,6 +158,13 @@ int GEventLoop::exec() } else { receiver->event(event); } + + if (m_exit_requested) { + auto rejigged_event_queue = move(events); + rejigged_event_queue.append(move(m_queued_events)); + m_queued_events = move(rejigged_event_queue); + return m_exit_code; + } } } ASSERT_NOT_REACHED(); diff --git a/LibGUI/GInputBox.cpp b/LibGUI/GInputBox.cpp index ed37aeded5..bf315861f7 100644 --- a/LibGUI/GInputBox.cpp +++ b/LibGUI/GInputBox.cpp @@ -36,9 +36,9 @@ void GInputBox::build() label->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); label->set_preferred_size({ text_width, 16 }); - auto* text_editor = new GTextEditor(GTextEditor::SingleLine, widget); - text_editor->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); - text_editor->set_preferred_size({ 0, 16 }); + m_text_editor = new GTextEditor(GTextEditor::SingleLine, widget); + m_text_editor->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + m_text_editor->set_preferred_size({ 0, 16 }); auto* button_container_outer = new GWidget(widget); button_container_outer->set_layout(make(Orientation::Vertical)); @@ -47,30 +47,30 @@ void GInputBox::build() button_container_inner->set_layout(make(Orientation::Horizontal)); button_container_inner->layout()->set_spacing(8); - auto* cancel_button = new GButton(button_container_inner); - cancel_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); - cancel_button->set_preferred_size({ 0, 16 }); - cancel_button->set_caption("Cancel"); - cancel_button->on_click = [&] (auto&) { - fprintf(stderr, "GInputBox: Cancel button clicked\n"); - done(1); + m_cancel_button = new GButton(button_container_inner); + m_cancel_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + m_cancel_button->set_preferred_size({ 0, 16 }); + m_cancel_button->set_caption("Cancel"); + m_cancel_button->on_click = [this] (auto&) { + dbgprintf("GInputBox: Cancel button clicked\n"); + done(ExecCancel); }; - auto* ok_button = new GButton(button_container_inner); - ok_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); - ok_button->set_preferred_size({ 0, 16 }); - ok_button->set_caption("OK"); - ok_button->on_click = [&] (auto&) { - fprintf(stderr, "GInputBox: OK button clicked\n"); - m_text_value = text_editor->text(); - done(0); + m_ok_button = new GButton(button_container_inner); + m_ok_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + m_ok_button->set_preferred_size({ 0, 16 }); + m_ok_button->set_caption("OK"); + m_ok_button->on_click = [this] (auto&) { + dbgprintf("GInputBox: OK button clicked\n"); + m_text_value = m_text_editor->text(); + done(ExecOK); }; - text_editor->on_return_pressed = [&] (auto&) { - ok_button->click(); + m_text_editor->on_return_pressed = [this] (auto&) { + m_ok_button->click(); }; - text_editor->on_escape_pressed = [&] (auto&) { - cancel_button->click(); + m_text_editor->on_escape_pressed = [this] (auto&) { + m_cancel_button->click(); }; - text_editor->set_focus(true); + m_text_editor->set_focus(true); } diff --git a/LibGUI/GInputBox.h b/LibGUI/GInputBox.h index eb95d8279d..1885adaa8e 100644 --- a/LibGUI/GInputBox.h +++ b/LibGUI/GInputBox.h @@ -2,10 +2,11 @@ #include +class GButton; +class GTextEditor; + class GInputBox : public GDialog { public: - enum ExecResult { ExecOK = 0, ExecCancel = 1 }; - explicit GInputBox(const String& prompt, const String& title, GObject* parent = nullptr); virtual ~GInputBox() override; @@ -15,4 +16,8 @@ private: void build(); String m_prompt; String m_text_value; + + GButton* m_ok_button { nullptr }; + GButton* m_cancel_button { nullptr }; + GTextEditor* m_text_editor { nullptr }; }; diff --git a/LibGUI/GObject.h b/LibGUI/GObject.h index 694112dace..7c0cb4f31e 100644 --- a/LibGUI/GObject.h +++ b/LibGUI/GObject.h @@ -33,6 +33,7 @@ public: void dump_tree(int indent = 0); virtual bool is_widget() const { return false; } + virtual bool is_window() const { return false; } protected: virtual void timer_event(GTimerEvent&); diff --git a/LibGUI/GWidget.h b/LibGUI/GWidget.h index d856e66420..6a6dc8ee80 100644 --- a/LibGUI/GWidget.h +++ b/LibGUI/GWidget.h @@ -109,8 +109,18 @@ public: void set_window(GWindow*); - GWidget* parent_widget() { return static_cast(parent()); } - const GWidget* parent_widget() const { return static_cast(parent()); } + GWidget* parent_widget() + { + if (parent() && parent()->is_widget()) + return static_cast(parent()); + return nullptr; + } + const GWidget* parent_widget() const + { + if (parent() && parent()->is_widget()) + return static_cast(parent()); + return nullptr; + } void set_fill_with_background_color(bool b) { m_fill_with_background_color = b; } bool fill_with_background_color() const { return m_fill_with_background_color; } diff --git a/LibGUI/GWindow.h b/LibGUI/GWindow.h index 1331925678..1f899e1acb 100644 --- a/LibGUI/GWindow.h +++ b/LibGUI/GWindow.h @@ -82,6 +82,7 @@ public: private: virtual const char* class_name() const override { return "GWindow"; } + virtual bool is_window() const override final { return true; } Retained create_backing_bitmap(const Size&); void set_current_backing_bitmap(GraphicsBitmap&, bool flush_immediately = false);