vcl/inc/listbox.hxx | 3 + vcl/source/control/combobox.cxx | 2 - vcl/source/control/imp_listbox.cxx | 60 +++++++++++++++++++++++++++---------- vcl/source/control/listbox.cxx | 2 - 4 files changed, 48 insertions(+), 19 deletions(-)
New commits: commit 794946c9a7bd876468c02fc6b254f4a2536b6a93 Author: Caolán McNamara <caolan.mcnam...@collabora.com> AuthorDate: Fri Jun 27 11:06:53 2025 +0100 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Fri Jun 27 14:53:49 2025 +0200 Resolves: tdf#136943 limit combobox popups to max available below/above height If the popup won't fit either above/below then force the menu to scroll if it won't fit Change-Id: I03c051606ce29e2eba7046248e05c25fbdbded1a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187096 Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Tested-by: Jenkins diff --git a/vcl/inc/listbox.hxx b/vcl/inc/listbox.hxx index 725e0d3c7c49..b05cee40fa97 100644 --- a/vcl/inc/listbox.hxx +++ b/vcl/inc/listbox.hxx @@ -522,7 +522,8 @@ public: void SetAutoWidth( bool b ) { mbAutoWidth = b; } - Size CalcFloatSize() const; + tools::Rectangle GetParentRect() const; + Size CalcFloatSize(const tools::Rectangle& rParentRect) const; void StartFloat( bool bStartTracking ); virtual void setPosSizePixel( tools::Long nX, tools::Long nY, diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx index 7b1b2ab59b1e..a565e4028e16 100644 --- a/vcl/source/control/combobox.cxx +++ b/vcl/source/control/combobox.cxx @@ -587,7 +587,7 @@ void ComboBox::Resize() // adjust the size of the FloatingWindow even when invisible // as KEY_PGUP/DOWN is being processed... if (m_pFloatWin) - m_pFloatWin->SetSizePixel(m_pFloatWin->CalcFloatSize()); + m_pFloatWin->SetSizePixel(m_pFloatWin->CalcFloatSize(m_pFloatWin->GetParentRect())); } bool ComboBox::IsDropDownBox() const { return m_pFloatWin != nullptr; } diff --git a/vcl/source/control/imp_listbox.cxx b/vcl/source/control/imp_listbox.cxx index ab4c7d614685..73284a54de2c 100644 --- a/vcl/source/control/imp_listbox.cxx +++ b/vcl/source/control/imp_listbox.cxx @@ -2910,7 +2910,7 @@ void ImplListBoxFloatingWindow::Resize() FloatingWindow::Resize(); } -Size ImplListBoxFloatingWindow::CalcFloatSize() const +Size ImplListBoxFloatingWindow::CalcFloatSize(const tools::Rectangle& rParentRect) const { Size aFloatSz( maPrefSz ); @@ -2927,6 +2927,8 @@ Size ImplListBoxFloatingWindow::CalcFloatSize() const if ( mnDDLineCount ) aFloatSz.setHeight( nMaxHeight ); + AbsoluteScreenPixelRectangle aDesktopRect(GetDesktopRectPixel()); + if( mbAutoWidth ) { // AutoSize first only for width... @@ -2941,13 +2943,32 @@ Size ImplListBoxFloatingWindow::CalcFloatSize() const aFloatSz.AdjustWidth(nSBWidth ); } - tools::Long nDesktopWidth = GetDesktopRectPixel().getOpenWidth(); + tools::Long nDesktopWidth = aDesktopRect.getOpenWidth(); if (aFloatSz.Width() > nDesktopWidth) // Don't exceed the desktop width. aFloatSz.setWidth( nDesktopWidth ); } - tools::Long nDesktopHeight = GetDesktopRectPixel().getOpenHeight(); + tools::Long nDesktopHeight = aDesktopRect.getOpenHeight(); + + //tdf#136943. If the popup won't fit either above/below then force the menu + //to scroll if it won't fit + { + const vcl::Window* pRef = this; + if ( pRef->GetParent() ) + pRef = pRef->GetParent(); + + tools::Rectangle normRect( rParentRect ); // rRect is already relative to top-level window + normRect.SetPos( pRef->ScreenToOutputPixel( normRect.TopLeft() ) ); + + AbsoluteScreenPixelRectangle devRect(pRef->OutputToAbsoluteScreenPixel(normRect.TopLeft()), + pRef->OutputToAbsoluteScreenPixel(normRect.BottomRight())); + + tools::Long nHeightAbove = devRect.Top() - aDesktopRect.Top(); + tools::Long nHeightBelow = aDesktopRect.Bottom() - devRect.Bottom(); + nDesktopHeight = std::min(nDesktopHeight, std::max(nHeightAbove, nHeightBelow)); + } + if (aFloatSz.Height() > nDesktopHeight) aFloatSz.setHeight(nDesktopHeight); @@ -2967,7 +2988,6 @@ Size ImplListBoxFloatingWindow::CalcFloatSize() const if ( nInnerHeight % nEntryHeight ) { nInnerHeight /= nEntryHeight; - nInnerHeight++; nInnerHeight *= nEntryHeight; aFloatSz.setHeight( nInnerHeight + nTop + nBottom ); } @@ -2983,19 +3003,9 @@ Size ImplListBoxFloatingWindow::CalcFloatSize() const return aFloatSz; } -void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking ) +tools::Rectangle ImplListBoxFloatingWindow::GetParentRect() const { - if( IsInPopupMode() ) - return; - - Size aFloatSz = CalcFloatSize(); - - SetSizePixel( aFloatSz ); - mpImplLB->SetSizePixel( GetOutputSizePixel() ); - - sal_Int32 nPos = mpImplLB->GetEntryList().GetSelectedEntryPos( 0 ); - mnPopupModeStartSaveSelection = nPos; - + // Get Rectangle at which popup will appear Size aSz = GetParent()->GetSizePixel(); Point aPos = GetParent()->GetPosPixel(); aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos ); @@ -3021,6 +3031,24 @@ void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking ) if( pGrandparent->GetOutDev()->ImplIsAntiparallel() ) pGrandparentOutDev->ReMirror( aRect ); + return aRect; +} + +void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking ) +{ + if( IsInPopupMode() ) + return; + + tools::Rectangle aRect = GetParentRect(); + + Size aFloatSz = CalcFloatSize(aRect); + + SetSizePixel( aFloatSz ); + mpImplLB->SetSizePixel( GetOutputSizePixel() ); + + sal_Int32 nPos = mpImplLB->GetEntryList().GetSelectedEntryPos( 0 ); + mnPopupModeStartSaveSelection = nPos; + mpImplLB->GetMainWindow()->ResetLastPosPixel(); // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795 StartPopupMode( aRect, LISTBOX_FLOATWINPOPUPFLAGS ); diff --git a/vcl/source/control/listbox.cxx b/vcl/source/control/listbox.cxx index 6c00d62f3a93..bd209e3d9c00 100644 --- a/vcl/source/control/listbox.cxx +++ b/vcl/source/control/listbox.cxx @@ -636,7 +636,7 @@ void ListBox::Resize() // Retain FloatingWindow size even when it's invisible, as we still process KEY_PGUP/DOWN ... if ( mpFloatWin ) - mpFloatWin->SetSizePixel( mpFloatWin->CalcFloatSize() ); + mpFloatWin->SetSizePixel( mpFloatWin->CalcFloatSize(mpFloatWin->GetParentRect()) ); Control::Resize(); }