Przeglądaj źródła

LibGUI: Allow to specify position on screen for Dialog window

This change allows us to specify where on screen we'd like the Dialog
window to be drawn. By default it's set to CenterWithinParent which
may fall back to Center if parent window is unset or not visible on
screen.
LuK1337 4 lat temu
rodzic
commit
84ee95c346

+ 59 - 9
Userland/Libraries/LibGUI/Dialog.cpp

@@ -5,13 +5,15 @@
  */
 
 #include <LibCore/EventLoop.h>
+#include <LibGUI/Desktop.h>
 #include <LibGUI/Dialog.h>
 #include <LibGUI/Event.h>
 
 namespace GUI {
 
-Dialog::Dialog(Window* parent_window)
+Dialog::Dialog(Window* parent_window, ScreenPosition screen_position)
     : Window(parent_window)
+    , m_screen_position(screen_position)
 {
     set_modal(true);
     set_minimizable(false);
@@ -25,16 +27,64 @@ int Dialog::exec()
 {
     VERIFY(!m_event_loop);
     m_event_loop = make<Core::EventLoop>();
-    if (parent() && is<Window>(parent())) {
-        auto& parent_window = *static_cast<Window*>(parent());
-        if (parent_window.is_visible()) {
-            center_within(parent_window);
-        } else {
-            center_on_screen();
+
+    auto desktop_rect = Desktop::the().rect();
+    auto window_rect = rect();
+
+    auto top_align = [](Gfx::Rect<int>& rect) { rect.set_y(32); };
+    auto bottom_align = [this, desktop_rect](Gfx::Rect<int>& rect) { rect.set_y(desktop_rect.height() - Desktop::the().taskbar_height() - height() - 12); };
+
+    auto left_align = [](Gfx::Rect<int>& rect) { rect.set_x(12); };
+    auto right_align = [this, desktop_rect](Gfx::Rect<int>& rect) { rect.set_x(desktop_rect.width() - width() - 12); };
+
+    switch (m_screen_position) {
+    case CenterWithinParent:
+        if (parent() && is<Window>(parent())) {
+            auto& parent_window = *static_cast<Window*>(parent());
+            if (parent_window.is_visible()) {
+                window_rect.center_within(parent_window.rect());
+                break;
+            }
         }
-    } else {
-        center_on_screen();
+        [[fallthrough]]; // Fall back to `Center` if parent window is invalid or not visible
+    case Center:
+        window_rect.center_within(desktop_rect);
+        break;
+    case CenterLeft:
+        left_align(window_rect);
+        window_rect.center_vertically_within(desktop_rect);
+        break;
+    case CenterRight:
+        right_align(window_rect);
+        window_rect.center_vertically_within(desktop_rect);
+        break;
+    case TopLeft:
+        left_align(window_rect);
+        top_align(window_rect);
+        break;
+    case TopCenter:
+        window_rect.center_horizontally_within(desktop_rect);
+        top_align(window_rect);
+        break;
+    case TopRight:
+        right_align(window_rect);
+        top_align(window_rect);
+        break;
+    case BottomLeft:
+        left_align(window_rect);
+        bottom_align(window_rect);
+        break;
+    case BottomCenter:
+        window_rect.center_horizontally_within(desktop_rect);
+        bottom_align(window_rect);
+        break;
+    case BottomRight:
+        right_align(window_rect);
+        bottom_align(window_rect);
+        break;
     }
+
+    set_rect(window_rect);
     show();
     auto result = m_event_loop->exec();
     m_event_loop = nullptr;

+ 17 - 1
Userland/Libraries/LibGUI/Dialog.h

@@ -20,6 +20,21 @@ public:
         ExecYes = 3,
         ExecNo = 4,
     };
+    enum ScreenPosition {
+        CenterWithinParent = 0,
+
+        Center = 1,
+        CenterLeft = 2,
+        CenterRight = 3,
+
+        TopLeft = 4,
+        TopCenter = 5,
+        TopRight = 6,
+
+        BottomLeft = 7,
+        BottomCenter = 8,
+        BottomRight = 9,
+    };
 
     virtual ~Dialog() override;
 
@@ -33,11 +48,12 @@ public:
     virtual void close() override;
 
 protected:
-    explicit Dialog(Window* parent_window);
+    explicit Dialog(Window* parent_window, ScreenPosition screen_position = CenterWithinParent);
 
 private:
     OwnPtr<Core::EventLoop> m_event_loop;
     int m_result { ExecAborted };
+    int m_screen_position { CenterWithinParent };
 };
 
 }