Przeglądaj źródła

Browser+LibGUI+WindowServer: Open Button menus uniformly

Instead of letting buttons determine the relative position
of their menus, a workaround only used by Statusbar segments,
open them all uniformly for a nice, consistent UI.

Passing a rect to popup() now routes to open_button_menu(), an
analog to open_menubar_menu(), which adjusts the menu's popup
position in the same way. Fixes button menus obscuring the buttons
which spawn them and jutting out at odd corners depending on screen
position.
thankyouverycool 2 lat temu
rodzic
commit
35e557c657

+ 0 - 1
Userland/Applications/Browser/BookmarksBarWidget.cpp

@@ -112,7 +112,6 @@ BookmarksBarWidget::BookmarksBarWidget(String const& bookmarks_file, bool enable
     m_additional = GUI::Button::construct();
     m_additional->set_tooltip("Show hidden bookmarks");
     m_additional->set_menu(m_additional_menu);
-    m_additional->set_menu_position(GUI::Button::MenuPosition::BottomLeft);
     auto bitmap_or_error = Gfx::Bitmap::try_load_from_file("/res/icons/16x16/overflow-menu.png"sv);
     if (!bitmap_or_error.is_error())
         m_additional->set_icon(bitmap_or_error.release_value());

+ 1 - 16
Userland/Libraries/LibGUI/Button.cpp

@@ -215,22 +215,7 @@ void Button::set_menu(RefPtr<GUI::Menu> menu)
 void Button::mousedown_event(MouseEvent& event)
 {
     if (m_menu) {
-        switch (m_menu_position) {
-        case TopLeft:
-            m_menu->popup(screen_relative_rect().top_left());
-            break;
-        case TopRight:
-            m_menu->popup(screen_relative_rect().top_right());
-            break;
-        case BottomLeft:
-            m_menu->popup(screen_relative_rect().bottom_left());
-            break;
-        case BottomRight:
-            m_menu->popup(screen_relative_rect().bottom_right());
-            break;
-        default:
-            VERIFY_NOT_REACHED();
-        }
+        m_menu->popup(screen_relative_rect().bottom_left(), {}, rect());
         update();
         return;
     }

+ 0 - 4
Userland/Libraries/LibGUI/Button.h

@@ -66,9 +66,6 @@ public:
     void set_mimic_pressed(bool mimic_pressed);
     bool is_mimic_pressed() const { return m_mimic_pressed; };
 
-    MenuPosition menu_position() const { return m_menu_position; }
-    void set_menu_position(MenuPosition position) { m_menu_position = position; }
-
     virtual Optional<UISize> calculated_min_size() const override;
 
 protected:
@@ -88,7 +85,6 @@ private:
     int m_icon_spacing { 4 };
     bool m_another_button_has_focus { false };
     bool m_mimic_pressed { false };
-    MenuPosition m_menu_position { MenuPosition::TopLeft };
 };
 
 class DialogButton final : public Button {

+ 2 - 2
Userland/Libraries/LibGUI/Menu.cpp

@@ -116,10 +116,10 @@ void Menu::realize_if_needed(RefPtr<Action> const& default_action)
         realize_menu(default_action);
 }
 
-void Menu::popup(Gfx::IntPoint const& screen_position, RefPtr<Action> const& default_action)
+void Menu::popup(Gfx::IntPoint const& screen_position, RefPtr<Action> const& default_action, Gfx::IntRect const& button_rect)
 {
     realize_if_needed(default_action);
-    ConnectionToWindowServer::the().async_popup_menu(m_menu_id, screen_position);
+    ConnectionToWindowServer::the().async_popup_menu(m_menu_id, screen_position, button_rect);
 }
 
 void Menu::dismiss()

+ 1 - 1
Userland/Libraries/LibGUI/Menu.h

@@ -41,7 +41,7 @@ public:
     Menu& add_submenu(String name);
     void remove_all_actions();
 
-    void popup(Gfx::IntPoint const& screen_position, RefPtr<Action> const& default_action = nullptr);
+    void popup(Gfx::IntPoint const& screen_position, RefPtr<Action> const& default_action = nullptr, Gfx::IntRect const& button_rect = {});
     void dismiss();
 
     void visibility_did_change(Badge<ConnectionToWindowServer>, bool visible);

+ 0 - 1
Userland/Libraries/LibGUI/Statusbar.cpp

@@ -146,7 +146,6 @@ Statusbar::Segment::Segment()
     set_focus_policy(GUI::FocusPolicy::NoFocus);
     set_button_style(Gfx::ButtonStyle::Tray);
     set_text_alignment(Gfx::TextAlignment::CenterLeft);
-    set_menu_position(GUI::Button::MenuPosition::TopRight);
 }
 
 void Statusbar::Segment::paint_event(PaintEvent& event)

+ 1 - 2
Userland/Libraries/LibGUI/Toolbar.cpp

@@ -159,7 +159,7 @@ Optional<UISize> Toolbar::calculated_min_size() const
 ErrorOr<void> Toolbar::create_overflow_objects()
 {
     m_overflow_action = Action::create("Overflow Menu", { Mod_Ctrl | Mod_Shift, Key_O }, TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/overflow-menu.png"sv)), [&](auto&) {
-        m_overflow_menu->popup(m_overflow_button->screen_relative_rect().bottom_left());
+        m_overflow_menu->popup(m_overflow_button->screen_relative_rect().bottom_left(), {}, m_overflow_button->rect());
     });
     m_overflow_action->set_status_tip("Show hidden toolbar actions");
     m_overflow_action->set_enabled(false);
@@ -168,7 +168,6 @@ ErrorOr<void> Toolbar::create_overflow_objects()
 
     m_overflow_button = TRY(try_add_action(*m_overflow_action));
     m_overflow_button->set_visible(false);
-    m_overflow_button->set_menu_position(Button::MenuPosition::BottomLeft);
 
     return {};
 }

+ 5 - 2
Userland/Services/WindowServer/ConnectionFromClient.cpp

@@ -145,7 +145,7 @@ void ConnectionFromClient::add_menu_item(i32 menu_id, i32 identifier, i32 submen
     menu.add_item(move(menu_item));
 }
 
-void ConnectionFromClient::popup_menu(i32 menu_id, Gfx::IntPoint const& screen_position)
+void ConnectionFromClient::popup_menu(i32 menu_id, Gfx::IntPoint const& screen_position, Gfx::IntRect const& button_rect)
 {
     auto position = screen_position;
     auto it = m_menus.find(menu_id);
@@ -154,7 +154,10 @@ void ConnectionFromClient::popup_menu(i32 menu_id, Gfx::IntPoint const& screen_p
         return;
     }
     auto& menu = *(*it).value;
-    menu.popup(position);
+    if (!button_rect.is_null())
+        menu.open_button_menu(position, button_rect);
+    else
+        menu.popup(position);
 }
 
 void ConnectionFromClient::dismiss_menu(i32 menu_id)

+ 1 - 1
Userland/Services/WindowServer/ConnectionFromClient.h

@@ -138,7 +138,7 @@ private:
     virtual void show_screen_numbers(bool) override;
     virtual void set_window_cursor(i32, i32) override;
     virtual void set_window_custom_cursor(i32, Gfx::ShareableBitmap const&) override;
-    virtual void popup_menu(i32, Gfx::IntPoint const&) override;
+    virtual void popup_menu(i32, Gfx::IntPoint const&, Gfx::IntRect const&) override;
     virtual void dismiss_menu(i32) override;
     virtual void set_window_icon_bitmap(i32, Gfx::ShareableBitmap const&) override;
     virtual Messages::WindowServer::StartDragResponse start_drag(String const&, HashMap<String, ByteBuffer> const&, Gfx::ShareableBitmap const&) override;

+ 21 - 0
Userland/Services/WindowServer/Menu.cpp

@@ -597,6 +597,27 @@ void Menu::redraw_if_theme_changed()
         redraw();
 }
 
+void Menu::open_button_menu(Gfx::IntPoint const& position, Gfx::IntRect const& button_rect)
+{
+    if (is_empty())
+        return;
+
+    auto& screen = Screen::closest_to_location(position);
+    auto& window = ensure_menu_window(position);
+    Gfx::IntPoint adjusted_pos = position;
+
+    if (window.rect().right() > screen.width())
+        adjusted_pos = adjusted_pos.translated(-(window.rect().right() - screen.width()) - 1, 0);
+
+    if (window.rect().bottom() > screen.height())
+        adjusted_pos = adjusted_pos.translated(0, -window.rect().height() - button_rect.height() + 1);
+
+    window.set_rect(adjusted_pos.x(), adjusted_pos.y(), window.rect().width(), window.rect().height());
+    window.move_to(adjusted_pos);
+    MenuManager::the().open_menu(*this, true);
+    WindowManager::the().did_popup_a_menu({});
+}
+
 void Menu::popup(Gfx::IntPoint const& position)
 {
     do_popup(position, true);

+ 1 - 0
Userland/Services/WindowServer/Menu.h

@@ -115,6 +115,7 @@ public:
 
     void popup(Gfx::IntPoint const&);
     void do_popup(Gfx::IntPoint const&, bool make_input, bool as_submenu = false);
+    void open_button_menu(Gfx::IntPoint const& position, Gfx::IntRect const& button_rect);
 
     bool is_menu_ancestor_of(Menu const&) const;
 

+ 1 - 1
Userland/Services/WindowServer/WindowServer.ipc

@@ -100,7 +100,7 @@ endpoint WindowServer
     set_fullscreen(i32 window_id, bool fullscreen) =|
     set_frameless(i32 window_id, bool frameless) =|
     set_forced_shadow(i32 window_id, bool shadow) =|
-    popup_menu(i32 menu_id, Gfx::IntPoint screen_position) =|
+    popup_menu(i32 menu_id, Gfx::IntPoint screen_position, Gfx::IntRect button_rect) =|
     dismiss_menu(i32 menu_id) =|
 
     set_wallpaper(Gfx::ShareableBitmap wallpaper_bitmap) => (bool success)