瀏覽代碼

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.
Andreas Kling 6 年之前
父節點
當前提交
f88e550998
共有 9 個文件被更改,包括 74 次插入34 次删除
  1. 3 3
      Applications/IRCClient/IRCAppWindow.cpp
  2. 15 3
      LibGUI/GDialog.cpp
  3. 5 1
      LibGUI/GDialog.h
  4. 7 0
      LibGUI/GEventLoop.cpp
  5. 23 23
      LibGUI/GInputBox.cpp
  6. 7 2
      LibGUI/GInputBox.h
  7. 1 0
      LibGUI/GObject.h
  8. 12 2
      LibGUI/GWidget.h
  9. 1 0
      LibGUI/GWindow.h

+ 3 - 3
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());
     });

+ 15 - 3
LibGUI/GDialog.cpp

@@ -14,13 +14,25 @@ GDialog::~GDialog()
 
 int GDialog::exec()
 {
-    GEventLoop loop;
+    ASSERT(!m_event_loop);
+    m_event_loop = make<GEventLoop>();
+    if (parent() && parent()->is_window()) {
+        auto& parent_window = *static_cast<GWindow*>(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);
 }

+ 5 - 1
LibGUI/GDialog.h

@@ -1,9 +1,12 @@
 #pragma once
 
 #include <LibGUI/GWindow.h>
+#include <LibGUI/GEventLoop.h>
 
 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<GEventLoop> m_event_loop;
+    int m_result { ExecAborted };
 };

+ 7 - 0
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();

+ 23 - 23
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<GBoxLayout>(Orientation::Vertical));
@@ -47,30 +47,30 @@ void GInputBox::build()
     button_container_inner->set_layout(make<GBoxLayout>(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);
 }

+ 7 - 2
LibGUI/GInputBox.h

@@ -2,10 +2,11 @@
 
 #include <LibGUI/GDialog.h>
 
+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 };
 };

+ 1 - 0
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&);

+ 12 - 2
LibGUI/GWidget.h

@@ -109,8 +109,18 @@ public:
 
     void set_window(GWindow*);
 
-    GWidget* parent_widget() { return static_cast<GWidget*>(parent()); }
-    const GWidget* parent_widget() const { return static_cast<const GWidget*>(parent()); }
+    GWidget* parent_widget()
+    {
+        if (parent() && parent()->is_widget())
+            return static_cast<GWidget*>(parent());
+        return nullptr;
+    }
+    const GWidget* parent_widget() const
+    {
+        if (parent() && parent()->is_widget())
+            return static_cast<const GWidget*>(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; }

+ 1 - 0
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<GraphicsBitmap> create_backing_bitmap(const Size&);
     void set_current_backing_bitmap(GraphicsBitmap&, bool flush_immediately = false);