summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2021-11-19 11:45:50 +0000
committerCaolán McNamara <caolanm@redhat.com>2021-11-19 21:47:54 +0100
commit04c5aef876dc4dbeff96f772254b6a7edb6d8433 (patch)
tree10bcf57c81b2f27c1c3cf072c4dbb9d2ab0aaefb /vcl
parent2ed0c2f7ce1ac80dd0315043eb656fff41f24bfc (diff)
add placement to Popover popup_at_rect
Change-Id: Iaa12a48f62037dd985d526993a07762b10bd0cee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125474 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/salvtables.hxx3
-rw-r--r--vcl/source/app/salvtables.cxx11
-rw-r--r--vcl/unx/gtk3/gtkinst.cxx158
3 files changed, 127 insertions, 45 deletions
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index c97b39df575d..f26950fb42a6 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -1903,7 +1903,8 @@ public:
~SalInstancePopover();
- virtual void popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect) override;
+ virtual void popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect,
+ weld::Placement ePlace = weld::Placement::Under) override;
virtual void popdown() override;
};
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 987a9ffe2aeb..e8f51950b04f 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -6698,7 +6698,8 @@ SalInstancePopover::SalInstancePopover(DockingWindow* pPopover, SalInstanceBuild
SalInstancePopover::~SalInstancePopover() { signal_closed(); }
-void SalInstancePopover::popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect)
+void SalInstancePopover::popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect,
+ weld::Placement ePlace)
{
SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pParent);
assert(pVclWidget);
@@ -6712,8 +6713,12 @@ void SalInstancePopover::popup_at_rect(weld::Widget* pParent, const tools::Recta
aRect.SetRight(aPt.X());
aRect.SetBottom(aPt.Y());
- FloatWinPopupFlags nFlags = FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus
- | FloatWinPopupFlags::NoMouseUpClose;
+ FloatWinPopupFlags nFlags = FloatWinPopupFlags::GrabFocus | FloatWinPopupFlags::NoMouseUpClose;
+ if (ePlace == weld::Placement::Under)
+ nFlags = nFlags | FloatWinPopupFlags::Down;
+ else
+ nFlags = nFlags | FloatWinPopupFlags::Right;
+
m_xPopover->EnableDocking();
DockingManager* pDockingManager = vcl::Window::GetDockingManager();
pDockingManager->SetPopupModeEndHdl(m_xPopover,
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 6853ca6728f4..3acdbbd8276e 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -9639,7 +9639,7 @@ void do_ungrab(GtkWidget* pWidget)
gdk_seat_ungrab(pSeat);
}
-GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu, const GdkRectangle& rAnchor)
+GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu, const GdkRectangle& rAnchor, weld::Placement ePlace)
{
//place the toplevel just below its launcher button
GtkWidget* pToplevel = widget_get_toplevel(pMenuButton);
@@ -9652,7 +9652,11 @@ GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu, co
y += absy;
gint nButtonHeight = rAnchor.height;
- y += nButtonHeight;
+ gint nButtonWidth = rAnchor.width;
+ if (ePlace == weld::Placement::Under)
+ y += nButtonHeight;
+ else
+ x += nButtonWidth;
gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(pToplevel)), pMenu);
gtk_window_set_transient_for(pMenu, GTK_WINDOW(pToplevel));
@@ -9673,8 +9677,10 @@ GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu, co
bool bSwapForRTL = SwapForRTL(pMenuButton);
if (bSwapForRTL)
{
- gint nButtonWidth = rAnchor.width;
- x += nButtonWidth;
+ if (ePlace == weld::Placement::Under)
+ x += nButtonWidth;
+ else
+ x -= nButtonWidth;
x -= nMenuWidth;
}
@@ -9684,36 +9690,76 @@ GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu, co
// long menu to know the menu is fully on screen
aWorkArea.AdjustTop(8);
aWorkArea.AdjustBottom(-8);
- gint endx = x + nMenuWidth;
- if (endx > aWorkArea.Right())
- x -= endx - aWorkArea.Right();
- if (x < 0)
- x = 0;
+ aWorkArea.AdjustLeft(8);
+ aWorkArea.AdjustRight(-8);
- GtkPositionType ePosUsed = GTK_POS_BOTTOM;
+ GtkPositionType ePosUsed;
- gint endy = y + nMenuHeight;
- gint nMissingBelow = endy - aWorkArea.Bottom();
- if (nMissingBelow > 0)
+ if (ePlace == weld::Placement::Under)
{
- gint nNewY = y - (nButtonHeight + nMenuHeight);
- if (nNewY < aWorkArea.Top())
+ gint endx = x + nMenuWidth;
+ if (endx > aWorkArea.Right())
+ x -= endx - aWorkArea.Right();
+ if (x < 0)
+ x = 0;
+
+ ePosUsed = GTK_POS_BOTTOM;
+ gint endy = y + nMenuHeight;
+ gint nMissingBelow = endy - aWorkArea.Bottom();
+ if (nMissingBelow > 0)
{
- gint nMissingAbove = aWorkArea.Top() - nNewY;
- if (nMissingBelow <= nMissingAbove)
- nMenuHeight -= nMissingBelow;
+ gint nNewY = y - (nButtonHeight + nMenuHeight);
+ if (nNewY < aWorkArea.Top())
+ {
+ gint nMissingAbove = aWorkArea.Top() - nNewY;
+ if (nMissingBelow <= nMissingAbove)
+ nMenuHeight -= nMissingBelow;
+ else
+ {
+ nMenuHeight -= nMissingAbove;
+ y = aWorkArea.Top();
+ ePosUsed = GTK_POS_TOP;
+ }
+ gtk_widget_set_size_request(GTK_WIDGET(pMenu), nMenuWidth, nMenuHeight);
+ }
else
{
- nMenuHeight -= nMissingAbove;
- y = aWorkArea.Top();
+ y = nNewY;
ePosUsed = GTK_POS_TOP;
}
- gtk_widget_set_size_request(GTK_WIDGET(pMenu), nMenuWidth, nMenuHeight);
+ }
+ }
+ else
+ {
+ if (!bSwapForRTL)
+ {
+ ePosUsed = GTK_POS_RIGHT;
+ gint endx = x + nMenuWidth;
+ gint nMissingAfter = endx - aWorkArea.Right();
+ if (nMissingAfter > 0)
+ {
+ gint nNewX = x - (nButtonWidth + nMenuWidth);
+ if (nNewX >= aWorkArea.Left())
+ {
+ x = nNewX;
+ ePosUsed = GTK_POS_LEFT;
+ }
+ }
}
else
{
- y = nNewY;
- ePosUsed = GTK_POS_TOP;
+ ePosUsed = GTK_POS_LEFT;
+ gint startx = x;
+ gint nMissingBefore = aWorkArea.Left() - startx;
+ if (nMissingBefore > 0)
+ {
+ gint nNewX = x + (nButtonWidth + nMenuWidth);
+ if (nNewX + nMenuWidth < aWorkArea.Right())
+ {
+ x = nNewX;
+ ePosUsed = GTK_POS_RIGHT;
+ }
+ }
}
}
@@ -9722,7 +9768,7 @@ GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu, co
return ePosUsed;
}
-bool show_menu_newer_gtk(GtkWidget* pComboBox, GtkWindow* pMenu, const GdkRectangle &rAnchor)
+bool show_menu_newer_gtk(GtkWidget* pComboBox, GtkWindow* pMenu, const GdkRectangle &rAnchor, weld::Placement ePlace)
{
static auto window_move_to_rect = reinterpret_cast<void (*) (GdkWindow*, const GdkRectangle*, GdkGravity,
GdkGravity, GdkAnchorHints, gint, gint)>(
@@ -9749,20 +9795,32 @@ bool show_menu_newer_gtk(GtkWidget* pComboBox, GtkWindow* pMenu, const GdkRectan
bool bSwapForRTL = SwapForRTL(GTK_WIDGET(pComboBox));
- GdkGravity rect_anchor = !bSwapForRTL ? GDK_GRAVITY_SOUTH_WEST : GDK_GRAVITY_SOUTH_EAST;
- GdkGravity menu_anchor = !bSwapForRTL ? GDK_GRAVITY_NORTH_WEST : GDK_GRAVITY_NORTH_EAST;
+ GdkGravity rect_anchor;
+ GdkGravity menu_anchor;
+
+ if (ePlace == weld::Placement::Under)
+ {
+ rect_anchor = !bSwapForRTL ? GDK_GRAVITY_SOUTH_WEST : GDK_GRAVITY_SOUTH_EAST;
+ menu_anchor = !bSwapForRTL ? GDK_GRAVITY_NORTH_WEST : GDK_GRAVITY_NORTH_EAST;
+ }
+ else
+ {
+ rect_anchor = !bSwapForRTL ? GDK_GRAVITY_NORTH_EAST : GDK_GRAVITY_NORTH_WEST;
+ menu_anchor = !bSwapForRTL ? GDK_GRAVITY_NORTH_WEST : GDK_GRAVITY_NORTH_EAST;
+ }
+
GdkRectangle rect {x, y, rAnchor.width, rAnchor.height};
GdkSurface* toplevel = widget_get_surface(GTK_WIDGET(pMenu));
- window_move_to_rect(toplevel, &rect, rect_anchor, menu_anchor,
- static_cast<GdkAnchorHints>(GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_RESIZE_Y |
- GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_RESIZE_X),
+ window_move_to_rect(toplevel, &rect, rect_anchor, menu_anchor, static_cast<GdkAnchorHints>(0),
+ /*static_cast<GdkAnchorHints>(GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_RESIZE_Y |
+ GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_RESIZE_X),*/
0, 0);
return true;
}
-GtkPositionType show_menu(GtkWidget* pMenuButton, GtkWindow* pMenu, const GdkRectangle& rAnchor)
+GtkPositionType show_menu(GtkWidget* pMenuButton, GtkWindow* pMenu, const GdkRectangle& rAnchor, weld::Placement ePlace)
{
// we only use ePosUsed in the replacement-for-X-popover case of a
// MenuButton, so we only need it when show_menu_older_gtk is used
@@ -9783,8 +9841,8 @@ GtkPositionType show_menu(GtkWidget* pMenuButton, GtkWindow* pMenu, const GdkRec
}
// try with gdk_window_move_to_rect, but if that's not available, try without
- if (!show_menu_newer_gtk(pMenuButton, pMenu, rAnchor))
- ePosUsed = show_menu_older_gtk(pMenuButton, pMenu, rAnchor);
+ if (!show_menu_newer_gtk(pMenuButton, pMenu, rAnchor, ePlace))
+ ePosUsed = show_menu_older_gtk(pMenuButton, pMenu, rAnchor, ePlace);
gtk_widget_show_all(GTK_WIDGET(pMenu));
gtk_widget_grab_focus(GTK_WIDGET(pMenu));
do_grab(GTK_WIDGET(pMenu));
@@ -9823,7 +9881,8 @@ bool button_release_is_outside(GtkWidget* pWidget, GtkWidget* pMenuHack, GdkEven
return true;
}
-GtkPositionType MovePopoverContentsToWindow(GtkWidget* pPopover, GtkWindow* pMenuHack, GtkWidget* pAnchor, const GdkRectangle& rAnchor)
+GtkPositionType MovePopoverContentsToWindow(GtkWidget* pPopover, GtkWindow* pMenuHack, GtkWidget* pAnchor,
+ const GdkRectangle& rAnchor, weld::Placement ePlace)
{
//set border width
gtk_container_set_border_width(GTK_CONTAINER(pMenuHack), gtk_container_get_border_width(GTK_CONTAINER(pPopover)));
@@ -9835,7 +9894,7 @@ GtkPositionType MovePopoverContentsToWindow(GtkWidget* pPopover, GtkWindow* pMen
gtk_container_add(GTK_CONTAINER(pMenuHack), pChild);
g_object_unref(pChild);
- return show_menu(pAnchor, pMenuHack, rAnchor);
+ return show_menu(pAnchor, pMenuHack, rAnchor, ePlace);
}
void MoveWindowContentsToPopover(GtkWindow* pMenuHack, GtkWidget* pPopover, GtkWidget* pAnchor)
@@ -9925,7 +9984,7 @@ private:
{
GtkWidget* pAnchor = m_pMenuHackAlign ? m_pMenuHackAlign : GTK_WIDGET(m_pMenuButton);
GdkRectangle aAnchor {0, 0, gtk_widget_get_allocated_width(pAnchor), gtk_widget_get_allocated_height(pAnchor) };
- GtkPositionType ePosUsed = MovePopoverContentsToWindow(m_pPopover, m_pMenuHack, pAnchor, aAnchor);
+ GtkPositionType ePosUsed = MovePopoverContentsToWindow(m_pPopover, m_pMenuHack, pAnchor, aAnchor, weld::Placement::Under);
// tdf#132540 keep the placeholder popover on this same side as the replacement menu
gtk_popover_set_position(gtk_menu_button_get_popover(m_pMenuButton), ePosUsed);
}
@@ -10748,7 +10807,7 @@ public:
#endif
}
- virtual OString popup_at_rect(weld::Widget* pParent, const tools::Rectangle &rRect, weld::Placement ePlace) override
+ virtual OString popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect, weld::Placement ePlace) override
{
m_sActivated.clear();
@@ -10804,11 +10863,18 @@ public:
if (!pTriggerEvent)
pTriggerEvent = pKeyEvent;
+ bool bSwapForRTL = SwapForRTL(pWidget);
+
if (ePlace == weld::Placement::Under)
- gtk_menu_popup_at_rect(m_pMenu, widget_get_surface(pWidget), &aRect, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, pTriggerEvent);
+ {
+ if (bSwapForRTL)
+ gtk_menu_popup_at_rect(m_pMenu, widget_get_surface(pWidget), &aRect, GDK_GRAVITY_SOUTH_EAST, GDK_GRAVITY_NORTH_EAST, pTriggerEvent);
+ else
+ gtk_menu_popup_at_rect(m_pMenu, widget_get_surface(pWidget), &aRect, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, pTriggerEvent);
+ }
else
{
- if (SwapForRTL(pWidget))
+ if (bSwapForRTL)
gtk_menu_popup_at_rect(m_pMenu, widget_get_surface(pWidget), &aRect, GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_NORTH_EAST, pTriggerEvent);
else
gtk_menu_popup_at_rect(m_pMenu, widget_get_surface(pWidget), &aRect, GDK_GRAVITY_NORTH_EAST, GDK_GRAVITY_NORTH_WEST, pTriggerEvent);
@@ -19839,7 +19905,7 @@ private:
tree_view_set_cursor(0);
GdkRectangle aAnchor {0, 0, gtk_widget_get_allocated_width(pComboBox), gtk_widget_get_allocated_height(pComboBox) };
- show_menu(pComboBox, m_pMenuWindow, aAnchor);
+ show_menu(pComboBox, m_pMenuWindow, aAnchor, weld::Placement::Under);
}
}
@@ -21979,7 +22045,7 @@ public:
{
}
- virtual void popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect) override
+ virtual void popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect, weld::Placement ePlace) override
{
GtkInstanceWidget* pGtkWidget = dynamic_cast<GtkInstanceWidget*>(pParent);
assert(pGtkWidget);
@@ -21996,6 +22062,16 @@ public:
#endif
gtk_popover_set_pointing_to(m_pPopover, &aRect);
+ if (ePlace == weld::Placement::Under)
+ gtk_popover_set_position(m_pPopover, GTK_POS_BOTTOM);
+ else
+ {
+ if (::SwapForRTL(pWidget))
+ gtk_popover_set_position(m_pPopover, GTK_POS_LEFT);
+ else
+ gtk_popover_set_position(m_pPopover, GTK_POS_RIGHT);
+ }
+
#if !GTK_CHECK_VERSION(4, 0, 0)
#if defined(GDK_WINDOWING_X11)
//under wayland a Popover will work to "escape" the parent dialog, not
@@ -22019,7 +22095,7 @@ public:
}
}
- MovePopoverContentsToWindow(GTK_WIDGET(m_pPopover), m_pMenuHack, pWidget, aRect);
+ MovePopoverContentsToWindow(GTK_WIDGET(m_pPopover), m_pMenuHack, pWidget, aRect, ePlace);
return;
}
#endif