1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <vcl/svapp.hxx>
23 #include <vcl/settings.hxx>
24 #include <vcl/event.hxx>
25 #include <vcl/i18nhelp.hxx>
26 #include <vcl/naturalsort.hxx>
27 #include <vcl/vcllayout.hxx>
28 #include <vcl/toolkit/lstbox.hxx>
29 #include <vcl/toolkit/scrbar.hxx>
31 #include <listbox.hxx>
35 #include <com/sun/star/accessibility/AccessibleRole.hpp>
37 #include <sal/log.hxx>
38 #include <o3tl/safeint.hxx>
39 #include <o3tl/string_view.hxx>
40 #include <osl/diagnose.h>
41 #include <comphelper/string.hxx>
42 #include <comphelper/processfactory.hxx>
46 #define MULTILINE_ENTRY_DRAW_FLAGS ( DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags::VCenter )
48 using namespace ::com::sun::star
;
50 constexpr tools::Long gnBorder
= 1;
52 void ImplInitDropDownButton( PushButton
* pButton
)
54 pButton
->SetSymbol( SymbolType::SPIN_DOWN
);
56 if ( pButton
->IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
57 && ! pButton
->IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
58 pButton
->SetBackground();
61 ImplEntryList::ImplEntryList( vcl::Window
* pWindow
)
64 mnLastSelected
= LISTBOX_ENTRY_NOTFOUND
;
65 mnSelectionAnchor
= LISTBOX_ENTRY_NOTFOUND
;
67 mbCallSelectionChangedHdl
= true;
73 ImplEntryList::~ImplEntryList()
78 void ImplEntryList::Clear()
84 void ImplEntryList::dispose()
90 void ImplEntryList::SelectEntry( sal_Int32 nPos
, bool bSelect
)
92 if (0 <= nPos
&& o3tl::make_unsigned(nPos
) < maEntries
.size())
94 std::vector
<std::unique_ptr
<ImplEntryType
> >::iterator iter
= maEntries
.begin()+nPos
;
96 if ( ( (*iter
)->mbIsSelected
!= bSelect
) &&
97 ( ( (*iter
)->mnFlags
& ListBoxEntryFlags::DisableSelection
) == ListBoxEntryFlags::NONE
) )
99 (*iter
)->mbIsSelected
= bSelect
;
100 if ( mbCallSelectionChangedHdl
)
101 maSelectionChangedHdl
.Call( nPos
);
108 comphelper::string::NaturalStringSorter
& GetSorter()
110 static comphelper::string::NaturalStringSorter
gSorter(
111 ::comphelper::getProcessComponentContext(),
112 Application::GetSettings().GetLanguageTag().getLocale());
119 sal_Int32
NaturalSortCompare(const OUString
&rA
, const OUString
&rB
)
121 const comphelper::string::NaturalStringSorter
&rSorter
= GetSorter();
122 return rSorter
.compare(rA
, rB
);
126 sal_Int32
ImplEntryList::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
, bool bSort
)
129 assert(maEntries
.size() < LISTBOX_MAX_ENTRIES
);
131 if ( !!pNewEntry
->maImage
)
134 sal_Int32 insPos
= 0;
135 const sal_Int32 nEntriesSize
= static_cast<sal_Int32
>(maEntries
.size());
137 if ( !bSort
|| maEntries
.empty())
139 if (0 <= nPos
&& nPos
< nEntriesSize
)
142 maEntries
.insert( maEntries
.begin() + nPos
, std::unique_ptr
<ImplEntryType
>(pNewEntry
) );
146 insPos
= nEntriesSize
;
147 maEntries
.push_back(std::unique_ptr
<ImplEntryType
>(pNewEntry
));
152 const comphelper::string::NaturalStringSorter
&rSorter
= GetSorter();
154 const OUString
& rStr
= pNewEntry
->maStr
;
156 ImplEntryType
* pTemp
= GetEntry( nEntriesSize
-1 );
160 sal_Int32 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
162 // fast insert for sorted data
165 insPos
= nEntriesSize
;
166 maEntries
.push_back(std::unique_ptr
<ImplEntryType
>(pNewEntry
));
170 pTemp
= GetEntry( mnMRUCount
);
172 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
176 maEntries
.insert(maEntries
.begin(), std::unique_ptr
<ImplEntryType
>(pNewEntry
));
180 sal_uLong nLow
= mnMRUCount
;
181 sal_uLong nHigh
= maEntries
.size()-1;
187 nMid
= static_cast<sal_Int32
>((nLow
+ nHigh
) / 2);
188 pTemp
= GetEntry( nMid
);
190 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
202 while ( nLow
<= nHigh
);
208 maEntries
.insert(maEntries
.begin()+nMid
, std::unique_ptr
<ImplEntryType
>(pNewEntry
));
212 catch (uno::RuntimeException
& )
214 // XXX this is arguable, if the exception occurred because pNewEntry is
215 // garbage you wouldn't insert it. If the exception occurred because the
216 // Collator implementation is garbage then give the user a chance to see
219 maEntries
.insert(maEntries
.begin(), std::unique_ptr
<ImplEntryType
>(pNewEntry
));
227 void ImplEntryList::RemoveEntry( sal_Int32 nPos
)
229 if (0 <= nPos
&& o3tl::make_unsigned(nPos
) < maEntries
.size())
231 std::vector
<std::unique_ptr
<ImplEntryType
> >::iterator iter
= maEntries
.begin()+ nPos
;
233 if ( !!(*iter
)->maImage
)
236 maEntries
.erase(iter
);
240 sal_Int32
ImplEntryList::FindEntry( std::u16string_view rString
, bool bSearchMRUArea
) const
242 const sal_Int32 nEntries
= static_cast<sal_Int32
>(maEntries
.size());
243 for ( sal_Int32 n
= bSearchMRUArea
? 0 : GetMRUCount(); n
< nEntries
; n
++ )
245 OUString
aComp( vcl::I18nHelper::filterFormattingChars( maEntries
[n
]->maStr
) );
246 if ( aComp
== rString
)
249 return LISTBOX_ENTRY_NOTFOUND
;
252 sal_Int32
ImplEntryList::FindMatchingEntry( const OUString
& rStr
, sal_Int32 nStart
, bool bLazy
) const
254 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
255 sal_Int32 nEntryCount
= GetEntryCount();
257 const vcl::I18nHelper
& rI18nHelper
= mpWindow
->GetSettings().GetLocaleI18nHelper();
258 for ( sal_Int32 n
= nStart
; n
< nEntryCount
; )
260 ImplEntryType
* pImplEntry
= GetEntry( n
);
264 bMatch
= rI18nHelper
.MatchString( rStr
, pImplEntry
->maStr
);
268 bMatch
= pImplEntry
->maStr
.startsWith(rStr
);
282 tools::Long
ImplEntryList::GetAddedHeight( sal_Int32 i_nEndIndex
, sal_Int32 i_nBeginIndex
) const
284 tools::Long nHeight
= 0;
285 sal_Int32 nStart
= std::min(i_nEndIndex
, i_nBeginIndex
);
286 sal_Int32 nStop
= std::max(i_nEndIndex
, i_nBeginIndex
);
287 sal_Int32 nEntryCount
= GetEntryCount();
288 if( 0 <= nStop
&& nStop
!= LISTBOX_ENTRY_NOTFOUND
&& nEntryCount
!= 0 )
291 if( nStop
> nEntryCount
-1 )
292 nStop
= nEntryCount
-1;
295 else if( nStart
> nEntryCount
-1 )
296 nStart
= nEntryCount
-1;
298 sal_Int32 nIndex
= nStart
;
299 while( nIndex
!= LISTBOX_ENTRY_NOTFOUND
&& nIndex
< nStop
)
301 tools::Long nPosHeight
= GetEntryPtr( nIndex
)->getHeightWithMargin();
302 if (nHeight
> ::std::numeric_limits
<tools::Long
>::max() - nPosHeight
)
304 SAL_WARN( "vcl", "ImplEntryList::GetAddedHeight: truncated");
307 nHeight
+= nPosHeight
;
313 return i_nEndIndex
> i_nBeginIndex
? nHeight
: -nHeight
;
316 tools::Long
ImplEntryList::GetEntryHeight( sal_Int32 nPos
) const
318 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
319 return pImplEntry
? pImplEntry
->getHeightWithMargin() : 0;
322 OUString
ImplEntryList::GetEntryText( sal_Int32 nPos
) const
325 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
327 aEntryText
= pImplEntry
->maStr
;
331 bool ImplEntryList::HasEntryImage( sal_Int32 nPos
) const
334 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
336 bImage
= !!pImplEntry
->maImage
;
340 Image
ImplEntryList::GetEntryImage( sal_Int32 nPos
) const
343 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
345 aImage
= pImplEntry
->maImage
;
349 void ImplEntryList::SetEntryData( sal_Int32 nPos
, void* pNewData
)
351 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
353 pImplEntry
->mpUserData
= pNewData
;
356 void* ImplEntryList::GetEntryData( sal_Int32 nPos
) const
358 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
359 return pImplEntry
? pImplEntry
->mpUserData
: nullptr;
362 void ImplEntryList::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
364 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
366 pImplEntry
->mnFlags
= nFlags
;
369 sal_Int32
ImplEntryList::GetSelectedEntryCount() const
371 sal_Int32 nSelCount
= 0;
372 for ( sal_Int32 n
= GetEntryCount(); n
; )
374 ImplEntryType
* pImplEntry
= GetEntry( --n
);
375 if ( pImplEntry
->mbIsSelected
)
381 OUString
ImplEntryList::GetSelectedEntry( sal_Int32 nIndex
) const
383 return GetEntryText( GetSelectedEntryPos( nIndex
) );
386 sal_Int32
ImplEntryList::GetSelectedEntryPos( sal_Int32 nIndex
) const
388 sal_Int32 nSelEntryPos
= LISTBOX_ENTRY_NOTFOUND
;
390 sal_Int32 nEntryCount
= GetEntryCount();
392 for ( sal_Int32 n
= 0; n
< nEntryCount
; n
++ )
394 ImplEntryType
* pImplEntry
= GetEntry( n
);
395 if ( pImplEntry
->mbIsSelected
)
397 if ( nSel
== nIndex
)
409 bool ImplEntryList::IsEntryPosSelected( sal_Int32 nIndex
) const
411 ImplEntryType
* pImplEntry
= GetEntry( nIndex
);
412 return pImplEntry
&& pImplEntry
->mbIsSelected
;
415 bool ImplEntryList::IsEntrySelectable( sal_Int32 nPos
) const
417 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
418 return pImplEntry
== nullptr || ((pImplEntry
->mnFlags
& ListBoxEntryFlags::DisableSelection
) == ListBoxEntryFlags::NONE
);
421 sal_Int32
ImplEntryList::FindFirstSelectable( sal_Int32 nPos
, bool bForward
/* = true */ ) const
423 if( IsEntrySelectable( nPos
) )
428 for( nPos
= nPos
+ 1; nPos
< GetEntryCount(); nPos
++ )
430 if( IsEntrySelectable( nPos
) )
439 if( IsEntrySelectable( nPos
) )
444 return LISTBOX_ENTRY_NOTFOUND
;
447 ImplListBoxWindow::ImplListBoxWindow( vcl::Window
* pParent
, WinBits nWinStyle
) :
448 Control( pParent
, 0 ),
450 maQuickSelectionEngine( *this )
455 mnSelectModifier
= 0;
456 mnUserDrawEntry
= LISTBOX_ENTRY_NOTFOUND
;
458 mbTravelSelect
= false;
459 mbTrackingSelect
= false;
460 mbSelectionChanged
= false;
461 mbMouseMoveSelect
= false;
464 mbUserDrawEnabled
= false;
465 mbInUserDraw
= false;
467 mbHasFocusRect
= false;
468 mbRight
= ( nWinStyle
& WB_RIGHT
);
469 mbCenter
= ( nWinStyle
& WB_CENTER
);
470 mbSimpleMode
= ( nWinStyle
& WB_SIMPLEMODE
);
471 mbSort
= ( nWinStyle
& WB_SORT
);
472 mbIsDropdown
= ( nWinStyle
& WB_DROPDOWN
);
473 mbEdgeBlending
= false;
475 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
476 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
478 GetOutDev()->SetLineColor();
480 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
482 ApplySettings(*GetOutDev());
486 ImplListBoxWindow::~ImplListBoxWindow()
491 void ImplListBoxWindow::dispose()
493 maEntryList
.dispose();
497 void ImplListBoxWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
499 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
501 ApplyControlFont(rRenderContext
, rStyleSettings
.GetFieldFont());
502 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetListBoxWindowTextColor());
504 if (IsControlBackground())
505 rRenderContext
.SetBackground(GetControlBackground());
507 rRenderContext
.SetBackground(rStyleSettings
.GetListBoxWindowBackgroundColor());
510 void ImplListBoxWindow::ImplCalcMetrics()
518 mnTextHeight
= static_cast<sal_uInt16
>(GetTextHeight());
519 mnMaxTxtHeight
= mnTextHeight
+ gnBorder
;
520 mnMaxHeight
= mnMaxTxtHeight
;
522 if ( maUserItemSize
.Height() > mnMaxHeight
)
523 mnMaxHeight
= static_cast<sal_uInt16
>(maUserItemSize
.Height());
524 if ( maUserItemSize
.Width() > mnMaxWidth
)
525 mnMaxWidth
= static_cast<sal_uInt16
>(maUserItemSize
.Width());
527 for ( sal_Int32 n
= maEntryList
.GetEntryCount(); n
; )
529 ImplEntryType
* pEntry
= maEntryList
.GetMutableEntryPtr( --n
);
530 ImplUpdateEntryMetrics( *pEntry
);
533 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
535 Size
aSz( GetOutputSizePixel().Width(), maEntryList
.GetEntryPtr( mnCurrentPos
)->getHeightWithMargin() );
536 maFocusRect
.SetSize( aSz
);
540 void ImplListBoxWindow::Clear()
544 mnMaxHeight
= mnMaxTxtHeight
;
552 ImplClearLayoutData();
554 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
555 maQuickSelectionEngine
.Reset();
560 void ImplListBoxWindow::SetUserItemSize( const Size
& rSz
)
562 ImplClearLayoutData();
563 maUserItemSize
= rSz
;
569 struct ImplEntryMetrics
573 tools::Long nEntryWidth
;
574 tools::Long nEntryHeight
;
575 tools::Long nTextWidth
;
576 tools::Long nImgWidth
;
577 tools::Long nImgHeight
;
582 tools::Long
ImplEntryType::getHeightWithMargin() const
584 return mnHeight
+ ImplGetSVData()->maNWFData
.mnListBoxEntryMargin
;
587 SalLayoutGlyphs
* ImplEntryType::GetTextGlyphs(const OutputDevice
* pOutputDevice
)
589 if (maStrGlyphs
.IsValid())
590 // Use pre-calculated result.
593 std::unique_ptr
<SalLayout
> pLayout
= pOutputDevice
->ImplLayout(
594 maStr
, 0, maStr
.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly
);
598 // Remember the calculation result.
599 maStrGlyphs
= pLayout
->GetGlyphs();
604 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType
& rEntry
)
606 ImplEntryMetrics aMetrics
;
607 aMetrics
.bText
= !rEntry
.maStr
.isEmpty();
608 aMetrics
.bImage
= !!rEntry
.maImage
;
609 aMetrics
.nEntryWidth
= 0;
610 aMetrics
.nEntryHeight
= 0;
611 aMetrics
.nTextWidth
= 0;
612 aMetrics
.nImgWidth
= 0;
613 aMetrics
.nImgHeight
= 0;
615 if ( aMetrics
.bText
)
617 if( rEntry
.mnFlags
& ListBoxEntryFlags::MultiLine
)
620 Size
aCurSize( PixelToLogic( GetSizePixel() ) );
621 // set the current size to a large number
622 // GetTextRect should shrink it to the actual size
623 aCurSize
.setHeight( 0x7fffff );
624 tools::Rectangle
aTextRect( Point( 0, 0 ), aCurSize
);
625 aTextRect
= GetTextRect( aTextRect
, rEntry
.maStr
, DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
);
626 aMetrics
.nTextWidth
= aTextRect
.GetWidth();
627 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
628 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
629 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
630 aMetrics
.nEntryHeight
= aTextRect
.GetHeight() + gnBorder
;
634 // normal single line case
635 const SalLayoutGlyphs
* pGlyphs
= rEntry
.GetTextGlyphs(GetOutDev());
637 = static_cast<sal_uInt16
>(GetTextWidth(rEntry
.maStr
, 0, -1, nullptr, pGlyphs
));
638 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
639 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
640 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
641 aMetrics
.nEntryHeight
= mnTextHeight
+ gnBorder
;
644 if ( aMetrics
.bImage
)
646 Size aImgSz
= rEntry
.maImage
.GetSizePixel();
647 aMetrics
.nImgWidth
= static_cast<sal_uInt16
>(CalcZoom( aImgSz
.Width() ));
648 aMetrics
.nImgHeight
= static_cast<sal_uInt16
>(CalcZoom( aImgSz
.Height() ));
650 if( aMetrics
.nImgWidth
> mnMaxImgWidth
)
651 mnMaxImgWidth
= aMetrics
.nImgWidth
;
652 if( aMetrics
.nImgHeight
> mnMaxImgHeight
)
653 mnMaxImgHeight
= aMetrics
.nImgHeight
;
655 mnMaxImgTxtWidth
= std::max( mnMaxImgTxtWidth
, aMetrics
.nTextWidth
);
656 aMetrics
.nEntryHeight
= std::max( aMetrics
.nImgHeight
, aMetrics
.nEntryHeight
);
660 bool bIsUserDrawEnabled
= IsUserDrawEnabled();
661 if (bIsUserDrawEnabled
|| aMetrics
.bImage
)
663 aMetrics
.nEntryWidth
= std::max( aMetrics
.nImgWidth
, maUserItemSize
.Width() );
664 if (!bIsUserDrawEnabled
&& aMetrics
.bText
)
665 aMetrics
.nEntryWidth
+= aMetrics
.nTextWidth
+ IMG_TXT_DISTANCE
;
666 aMetrics
.nEntryHeight
= std::max( std::max( mnMaxImgHeight
, maUserItemSize
.Height() ) + 2,
667 aMetrics
.nEntryHeight
);
670 if (!aMetrics
.bText
&& !aMetrics
.bImage
&& !bIsUserDrawEnabled
)
672 // entries which have no (aka an empty) text, and no image,
673 // and are not user-drawn, should be shown nonetheless
674 aMetrics
.nEntryHeight
= mnTextHeight
+ gnBorder
;
677 if ( aMetrics
.nEntryWidth
> mnMaxWidth
)
678 mnMaxWidth
= aMetrics
.nEntryWidth
;
679 if ( aMetrics
.nEntryHeight
> mnMaxHeight
)
680 mnMaxHeight
= aMetrics
.nEntryHeight
;
682 rEntry
.mnHeight
= aMetrics
.nEntryHeight
;
685 void ImplListBoxWindow::ImplCallSelect()
687 if ( !IsTravelSelect() && GetEntryList().GetMaxMRUCount() )
689 // Insert the selected entry as MRU, if not already first MRU
690 sal_Int32 nSelected
= GetEntryList().GetSelectedEntryPos( 0 );
691 sal_Int32 nMRUCount
= GetEntryList().GetMRUCount();
692 OUString aSelected
= GetEntryList().GetEntryText( nSelected
);
693 sal_Int32 nFirstMatchingEntryPos
= GetEntryList().FindEntry( aSelected
, true );
694 if ( nFirstMatchingEntryPos
|| !nMRUCount
)
696 bool bSelectNewEntry
= false;
697 if ( nFirstMatchingEntryPos
< nMRUCount
)
699 RemoveEntry( nFirstMatchingEntryPos
);
701 if ( nFirstMatchingEntryPos
== nSelected
)
702 bSelectNewEntry
= true;
704 else if ( nMRUCount
== GetEntryList().GetMaxMRUCount() )
706 RemoveEntry( nMRUCount
- 1 );
710 ImplClearLayoutData();
712 ImplEntryType
* pNewEntry
= new ImplEntryType( aSelected
);
713 pNewEntry
->mbIsSelected
= bSelectNewEntry
;
714 GetEntryList().InsertEntry( 0, pNewEntry
, false );
715 ImplUpdateEntryMetrics( *pNewEntry
);
716 GetEntryList().SetMRUCount( ++nMRUCount
);
717 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
718 maMRUChangedHdl
.Call( nullptr );
722 maSelectHdl
.Call( nullptr );
723 mbSelectionChanged
= false;
726 sal_Int32
ImplListBoxWindow::InsertEntry(sal_Int32 nPos
, ImplEntryType
* pNewEntry
, bool bSort
)
729 assert(maEntryList
.GetEntryCount() < LISTBOX_MAX_ENTRIES
);
731 ImplClearLayoutData();
732 sal_Int32 nNewPos
= maEntryList
.InsertEntry( nPos
, pNewEntry
, bSort
);
734 if( GetStyle() & WB_WORDBREAK
)
735 pNewEntry
->mnFlags
|= ListBoxEntryFlags::MultiLine
;
737 ImplUpdateEntryMetrics( *pNewEntry
);
741 sal_Int32
ImplListBoxWindow::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
)
743 return InsertEntry(nPos
, pNewEntry
, mbSort
);
746 void ImplListBoxWindow::RemoveEntry( sal_Int32 nPos
)
748 ImplClearLayoutData();
749 maEntryList
.RemoveEntry( nPos
);
750 if( mnCurrentPos
>= maEntryList
.GetEntryCount() )
751 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
755 void ImplListBoxWindow::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
757 maEntryList
.SetEntryFlags( nPos
, nFlags
);
758 ImplEntryType
* pEntry
= maEntryList
.GetMutableEntryPtr( nPos
);
760 ImplUpdateEntryMetrics( *pEntry
);
763 void ImplListBoxWindow::ImplShowFocusRect()
765 if ( mbHasFocusRect
)
767 ShowFocus( maFocusRect
);
768 mbHasFocusRect
= true;
771 void ImplListBoxWindow::ImplHideFocusRect()
773 if ( mbHasFocusRect
)
776 mbHasFocusRect
= false;
780 sal_Int32
ImplListBoxWindow::GetEntryPosForPoint( const Point
& rPoint
) const
782 tools::Long nY
= gnBorder
;
784 sal_Int32 nSelect
= mnTop
;
785 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr( nSelect
);
788 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
789 if (rPoint
.Y() <= nEntryHeight
+ nY
)
792 pEntry
= maEntryList
.GetEntryPtr( ++nSelect
);
794 if( pEntry
== nullptr )
795 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
800 bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry
) const
804 if( i_nEntry
>= mnTop
)
806 if( maEntryList
.GetAddedHeight( i_nEntry
, mnTop
) <
807 PixelToLogic( GetSizePixel() ).Height() )
816 tools::Long
ImplListBoxWindow::GetEntryHeightWithMargin() const
818 tools::Long nMargin
= ImplGetSVData()->maNWFData
.mnListBoxEntryMargin
;
819 return mnMaxHeight
+ nMargin
;
822 sal_Int32
ImplListBoxWindow::GetLastVisibleEntry() const
824 sal_Int32 nPos
= mnTop
;
825 tools::Long nWindowHeight
= GetSizePixel().Height();
826 sal_Int32 nCount
= maEntryList
.GetEntryCount();
828 for( nDiff
= 0; nDiff
< nWindowHeight
&& nPos
< nCount
; nDiff
= maEntryList
.GetAddedHeight( nPos
, mnTop
) )
831 if( nDiff
> nWindowHeight
&& nPos
> mnTop
)
840 void ImplListBoxWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
842 mbMouseMoveSelect
= false; // only till the first MouseButtonDown
843 maQuickSelectionEngine
.Reset();
847 if( rMEvt
.GetClicks() == 1 )
849 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
850 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
852 if ( !mbMulti
&& GetEntryList().GetSelectedEntryCount() )
853 mnTrackingSaveSelection
= GetEntryList().GetSelectedEntryPos( 0 );
855 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
857 mnCurrentPos
= nSelect
;
858 mbTrackingSelect
= true;
859 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
860 (void)SelectEntries( nSelect
, LET_MBDOWN
, rMEvt
.IsShift(), rMEvt
.IsMod1() ,bCurPosChange
);
861 mbTrackingSelect
= false;
865 StartTracking( StartTrackingFlags::ScrollRepeat
);
868 if( rMEvt
.GetClicks() == 2 )
870 maDoubleClickHdl
.Call( this );
873 else // if ( mbGrabFocus )
879 void ImplListBoxWindow::MouseMove( const MouseEvent
& rMEvt
)
881 if (rMEvt
.IsLeaveWindow() || mbMulti
|| !IsMouseMoveSelect() || !maEntryList
.GetEntryCount())
884 tools::Rectangle
aRect( Point(), GetOutputSizePixel() );
885 if( !aRect
.Contains( rMEvt
.GetPosPixel() ) )
888 if ( IsMouseMoveSelect() )
890 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
891 if( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
892 nSelect
= maEntryList
.GetEntryCount() - 1;
893 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
894 nSelect
= std::min( nSelect
, static_cast<sal_Int32
>( maEntryList
.GetEntryCount() - 1 ) );
895 // Select only visible Entries with MouseMove, otherwise Tracking...
896 if ( IsVisible( nSelect
) &&
897 maEntryList
.IsEntrySelectable( nSelect
) &&
898 ( ( nSelect
!= mnCurrentPos
) || !GetEntryList().GetSelectedEntryCount() || ( nSelect
!= GetEntryList().GetSelectedEntryPos( 0 ) ) ) )
900 mbTrackingSelect
= true;
901 if ( SelectEntries( nSelect
, LET_TRACKING
) )
903 // When list box selection change by mouse move, notify
904 // VclEventId::ListboxSelect vcl event.
905 maListItemSelectHdl
.Call(nullptr);
907 mbTrackingSelect
= false;
911 // if the DD button was pressed and someone moved into the ListBox
912 // with the mouse button pressed...
913 if ( rMEvt
.IsLeft() && !rMEvt
.IsSynthetic() )
915 if ( !mbMulti
&& GetEntryList().GetSelectedEntryCount() )
916 mnTrackingSaveSelection
= GetEntryList().GetSelectedEntryPos( 0 );
918 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
920 StartTracking( StartTrackingFlags::ScrollRepeat
);
924 void ImplListBoxWindow::DeselectAll()
926 while ( GetEntryList().GetSelectedEntryCount() )
928 sal_Int32 nS
= GetEntryList().GetSelectedEntryPos( 0 );
929 SelectEntry( nS
, false );
933 void ImplListBoxWindow::SelectEntry( sal_Int32 nPos
, bool bSelect
)
935 if( (maEntryList
.IsEntryPosSelected( nPos
) == bSelect
) || !maEntryList
.IsEntrySelectable( nPos
) )
943 // deselect the selected entry
944 sal_Int32 nDeselect
= GetEntryList().GetSelectedEntryPos( 0 );
945 if( nDeselect
!= LISTBOX_ENTRY_NOTFOUND
)
947 //SelectEntryPos( nDeselect, false );
948 GetEntryList().SelectEntry( nDeselect
, false );
949 if (IsUpdateMode() && IsReallyVisible())
953 maEntryList
.SelectEntry( nPos
, true );
955 if ( ( nPos
!= LISTBOX_ENTRY_NOTFOUND
) && IsUpdateMode() )
958 if ( !IsVisible( nPos
) )
960 ImplClearLayoutData();
961 sal_Int32 nVisibleEntries
= GetLastVisibleEntry()-mnTop
;
962 if ( !nVisibleEntries
|| !IsReallyVisible() || ( nPos
< GetTopEntry() ) )
965 ShowProminentEntry( nPos
);
969 ShowProminentEntry( nPos
);
976 maEntryList
.SelectEntry( nPos
, false );
979 mbSelectionChanged
= true;
982 bool ImplListBoxWindow::SelectEntries( sal_Int32 nSelect
, LB_EVENT_TYPE eLET
, bool bShift
, bool bCtrl
, bool bSelectPosChange
/*=FALSE*/ )
984 bool bSelectionChanged
= false;
986 if( IsEnabled() && maEntryList
.IsEntrySelectable( nSelect
) )
988 bool bFocusChanged
= false;
990 // here (Single-ListBox) only one entry can be deselected
993 sal_Int32 nDeselect
= maEntryList
.GetSelectedEntryPos( 0 );
994 if( nSelect
!= nDeselect
)
996 SelectEntry( nSelect
, true );
997 maEntryList
.SetLastSelected( nSelect
);
998 bFocusChanged
= true;
999 bSelectionChanged
= true;
1002 // MultiListBox without Modifier
1003 else if( mbSimpleMode
&& !bCtrl
&& !bShift
)
1005 sal_Int32 nEntryCount
= maEntryList
.GetEntryCount();
1006 for ( sal_Int32 nPos
= 0; nPos
< nEntryCount
; nPos
++ )
1008 bool bSelect
= nPos
== nSelect
;
1009 if ( maEntryList
.IsEntryPosSelected( nPos
) != bSelect
)
1011 SelectEntry( nPos
, bSelect
);
1012 bFocusChanged
= true;
1013 bSelectionChanged
= true;
1016 maEntryList
.SetLastSelected( nSelect
);
1017 maEntryList
.SetSelectionAnchor( nSelect
);
1019 // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1020 else if( ( !mbSimpleMode
/* && !bShift */ ) || ( mbSimpleMode
&& ( bCtrl
|| bShift
) ) )
1022 // Space for selection change
1023 if( !bShift
&& ( ( eLET
== LET_KEYSPACE
) || ( eLET
== LET_MBDOWN
) ) )
1025 bool bSelect
= !maEntryList
.IsEntryPosSelected( nSelect
);
1026 SelectEntry( nSelect
, bSelect
);
1027 maEntryList
.SetLastSelected( nSelect
);
1028 maEntryList
.SetSelectionAnchor( nSelect
);
1029 if ( !maEntryList
.IsEntryPosSelected( nSelect
) )
1030 maEntryList
.SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND
);
1031 bFocusChanged
= true;
1032 bSelectionChanged
= true;
1034 else if( ( ( eLET
== LET_TRACKING
) && ( nSelect
!= mnCurrentPos
) ) ||
1035 ( bShift
&& ( ( eLET
== LET_KEYMOVE
) || ( eLET
== LET_MBDOWN
) ) ) )
1037 mnCurrentPos
= nSelect
;
1038 bFocusChanged
= true;
1040 sal_Int32 nAnchor
= maEntryList
.GetSelectionAnchor();
1041 if( ( nAnchor
== LISTBOX_ENTRY_NOTFOUND
) && maEntryList
.GetSelectedEntryCount() )
1043 nAnchor
= maEntryList
.GetSelectedEntryPos( maEntryList
.GetSelectedEntryCount() - 1 );
1045 if( nAnchor
!= LISTBOX_ENTRY_NOTFOUND
)
1047 // All entries from Anchor to nSelect have to be selected
1048 sal_Int32 nStart
= std::min( nSelect
, nAnchor
);
1049 sal_Int32 nEnd
= std::max( nSelect
, nAnchor
);
1050 for ( sal_Int32 n
= nStart
; n
<= nEnd
; n
++ )
1052 if ( !maEntryList
.IsEntryPosSelected( n
) )
1054 SelectEntry( n
, true );
1055 bSelectionChanged
= true;
1059 // if appropriate some more has to be deselected...
1060 sal_Int32 nLast
= maEntryList
.GetLastSelected();
1061 if ( nLast
!= LISTBOX_ENTRY_NOTFOUND
)
1063 if ( ( nLast
> nSelect
) && ( nLast
> nAnchor
) )
1065 for ( sal_Int32 n
= nSelect
+1; n
<= nLast
; n
++ )
1067 if ( maEntryList
.IsEntryPosSelected( n
) )
1069 SelectEntry( n
, false );
1070 bSelectionChanged
= true;
1074 else if ( ( nLast
< nSelect
) && ( nLast
< nAnchor
) )
1076 for ( sal_Int32 n
= nLast
; n
< nSelect
; n
++ )
1078 if ( maEntryList
.IsEntryPosSelected( n
) )
1080 SelectEntry( n
, false );
1081 bSelectionChanged
= true;
1086 maEntryList
.SetLastSelected( nSelect
);
1089 else if( eLET
!= LET_TRACKING
)
1091 ImplHideFocusRect();
1093 bFocusChanged
= true;
1098 bFocusChanged
= true;
1101 if( bSelectionChanged
)
1102 mbSelectionChanged
= true;
1106 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight( nSelect
, mnTop
);
1107 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1108 Size
aSz( maFocusRect
.GetWidth(),
1109 maEntryList
.GetEntryHeight( nSelect
) );
1110 maFocusRect
.SetSize( aSz
);
1112 ImplShowFocusRect();
1113 if (bSelectPosChange
)
1115 maFocusHdl
.Call(nSelect
);
1118 ImplClearLayoutData();
1120 return bSelectionChanged
;
1123 void ImplListBoxWindow::Tracking( const TrackingEvent
& rTEvt
)
1125 tools::Rectangle
aRect( Point(), GetOutputSizePixel() );
1126 bool bInside
= aRect
.Contains( rTEvt
.GetMouseEvent().GetPosPixel() );
1128 if( rTEvt
.IsTrackingCanceled() || rTEvt
.IsTrackingEnded() ) // MouseButtonUp
1130 if ( bInside
&& !rTEvt
.IsTrackingCanceled() )
1132 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1137 maCancelHdl
.Call( nullptr );
1140 mbTrackingSelect
= true;
1141 SelectEntry( mnTrackingSaveSelection
, true );
1142 mbTrackingSelect
= false;
1143 if ( mnTrackingSaveSelection
!= LISTBOX_ENTRY_NOTFOUND
)
1145 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight( mnCurrentPos
, mnTop
);
1146 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1147 Size
aSz( maFocusRect
.GetWidth(),
1148 maEntryList
.GetEntryHeight( mnCurrentPos
) );
1149 maFocusRect
.SetSize( aSz
);
1150 ImplShowFocusRect();
1159 bool bTrackOrQuickClick
= mbTrack
;
1167 // this case only happens, if the mouse button is pressed very briefly
1168 if( rTEvt
.IsTrackingEnded() && mbTrack
)
1170 bTrackOrQuickClick
= true;
1175 if( bTrackOrQuickClick
)
1177 MouseEvent aMEvt
= rTEvt
.GetMouseEvent();
1178 Point
aPt( aMEvt
.GetPosPixel() );
1179 bool bShift
= aMEvt
.IsShift();
1180 bool bCtrl
= aMEvt
.IsMod1();
1182 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1185 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1187 nSelect
= mnCurrentPos
? ( mnCurrentPos
- 1 ) : 0;
1188 if( nSelect
< mnTop
)
1189 SetTopEntry( mnTop
-1 );
1192 else if( aPt
.Y() > GetOutputSizePixel().Height() )
1194 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1196 nSelect
= std::min( static_cast<sal_Int32
>(mnCurrentPos
+1), static_cast<sal_Int32
>(maEntryList
.GetEntryCount()-1) );
1197 if( nSelect
>= GetLastVisibleEntry() )
1198 SetTopEntry( mnTop
+1 );
1203 nSelect
= static_cast<sal_Int32
>( ( aPt
.Y() + gnBorder
) / mnMaxHeight
) + mnTop
;
1204 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
1205 nSelect
= std::min( nSelect
, static_cast<sal_Int32
>( maEntryList
.GetEntryCount() - 1 ) );
1210 if ( ( nSelect
!= mnCurrentPos
) || !GetEntryList().GetSelectedEntryCount() )
1212 mbTrackingSelect
= true;
1213 SelectEntries(nSelect
, LET_TRACKING
, bShift
, bCtrl
);
1214 mbTrackingSelect
= false;
1219 if ( !mbMulti
&& GetEntryList().GetSelectedEntryCount() )
1221 mbTrackingSelect
= true;
1222 SelectEntry( GetEntryList().GetSelectedEntryPos( 0 ), false );
1223 mbTrackingSelect
= false;
1226 mnCurrentPos
= nSelect
;
1227 if ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1229 ImplHideFocusRect();
1233 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight( mnCurrentPos
, mnTop
);
1234 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1235 Size
aSz( maFocusRect
.GetWidth(), maEntryList
.GetEntryHeight( mnCurrentPos
) );
1236 maFocusRect
.SetSize( aSz
);
1237 ImplShowFocusRect();
1243 void ImplListBoxWindow::KeyInput( const KeyEvent
& rKEvt
)
1245 if( !ProcessKeyInput( rKEvt
) )
1246 Control::KeyInput( rKEvt
);
1249 bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent
& rKEvt
)
1251 // entry to be selected
1252 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1253 LB_EVENT_TYPE eLET
= LET_KEYMOVE
;
1255 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1257 bool bShift
= aKeyCode
.IsShift();
1258 bool bCtrl
= aKeyCode
.IsMod1() || aKeyCode
.IsMod3();
1259 bool bMod2
= aKeyCode
.IsMod2();
1261 bool bHandleKey
= false;
1263 switch( aKeyCode
.GetCode() )
1269 if ( GetTopEntry() )
1270 SetTopEntry( GetTopEntry()-1 );
1274 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1276 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1278 else if ( mnCurrentPos
)
1280 // search first selectable above the current position
1281 nSelect
= maEntryList
.FindFirstSelectable( mnCurrentPos
- 1, false );
1284 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
< mnTop
) )
1285 SetTopEntry( mnTop
-1 );
1289 maQuickSelectionEngine
.Reset();
1297 SetTopEntry( GetTopEntry()+1 );
1301 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1303 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1305 else if ( (mnCurrentPos
+1) < maEntryList
.GetEntryCount() )
1307 // search first selectable below the current position
1308 nSelect
= maEntryList
.FindFirstSelectable( mnCurrentPos
+ 1 );
1311 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
>= GetLastVisibleEntry() ) )
1312 SetTopEntry( mnTop
+1 );
1316 maQuickSelectionEngine
.Reset();
1324 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1325 SetTopEntry( ( mnTop
> nCurVis
) ?
1326 (mnTop
-nCurVis
) : 0 );
1328 else if ( !bCtrl
&& !bMod2
)
1330 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1332 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1334 else if ( mnCurrentPos
)
1336 if( mnCurrentPos
== mnTop
)
1338 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1339 SetTopEntry( ( mnTop
> nCurVis
) ? ( mnTop
-nCurVis
+1 ) : 0 );
1342 // find first selectable starting from mnTop looking forward
1343 nSelect
= maEntryList
.FindFirstSelectable( mnTop
);
1347 maQuickSelectionEngine
.Reset();
1355 SetTopEntry( GetLastVisibleEntry() );
1357 else if ( !bCtrl
&& !bMod2
)
1359 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1361 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1363 else if ( (mnCurrentPos
+1) < maEntryList
.GetEntryCount() )
1365 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1366 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
;
1367 sal_Int32 nTmp
= std::min( nCurVis
, nCount
);
1369 if( mnCurrentPos
== nTmp
&& mnCurrentPos
!= nCount
- 1 )
1371 tools::Long nTmp2
= std::min( static_cast<tools::Long
>(nCount
-nCurVis
), static_cast<tools::Long
>(static_cast<tools::Long
>(mnTop
)+static_cast<tools::Long
>(nCurVis
)-1) );
1372 nTmp2
= std::max( tools::Long(0) , nTmp2
);
1373 nTmp
= static_cast<sal_Int32
>(nTmp2
+(nCurVis
-1) );
1374 SetTopEntry( static_cast<sal_Int32
>(nTmp2
) );
1376 // find first selectable starting from nTmp looking backwards
1377 nSelect
= maEntryList
.FindFirstSelectable( nTmp
, false );
1381 maQuickSelectionEngine
.Reset();
1391 else if ( !bCtrl
&& !bMod2
&& mnCurrentPos
)
1393 nSelect
= maEntryList
.FindFirstSelectable( maEntryList
.GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND
);
1399 maQuickSelectionEngine
.Reset();
1407 SetTopEntry( 0xFFFF );
1409 else if ( !bCtrl
&& !bMod2
)
1411 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1413 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1415 else if ( (mnCurrentPos
+1) < maEntryList
.GetEntryCount() )
1417 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1418 nSelect
= maEntryList
.FindFirstSelectable( nCount
- 1, false );
1419 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+ 1;
1420 if( nCount
> nCurVis
)
1421 SetTopEntry( nCount
- nCurVis
);
1425 maQuickSelectionEngine
.Reset();
1431 if ( !bCtrl
&& !bMod2
)
1433 ScrollHorz( -HORZ_SCROLL
);
1436 maQuickSelectionEngine
.Reset();
1442 if ( !bCtrl
&& !bMod2
)
1444 ScrollHorz( HORZ_SCROLL
);
1447 maQuickSelectionEngine
.Reset();
1453 if ( !bMod2
&& !IsReadOnly() )
1455 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1457 bDone
= false; // do not catch RETURN
1459 maQuickSelectionEngine
.Reset();
1465 if ( !bMod2
&& !IsReadOnly() )
1467 if( mbMulti
&& ( !mbSimpleMode
|| ( mbSimpleMode
&& bCtrl
&& !bShift
) ) )
1469 nSelect
= mnCurrentPos
;
1470 eLET
= LET_KEYSPACE
;
1480 if( bCtrl
&& mbMulti
)
1483 bool bUpdates
= IsUpdateMode();
1484 SetUpdateMode( false );
1486 sal_Int32 nEntryCount
= maEntryList
.GetEntryCount();
1487 for( sal_Int32 i
= 0; i
< nEntryCount
; i
++ )
1488 SelectEntry( i
, true );
1490 // tdf#97066 - Update selected items
1493 // restore update mode
1494 SetUpdateMode( bUpdates
);
1497 maQuickSelectionEngine
.Reset();
1512 if (bHandleKey
&& !IsReadOnly())
1514 bDone
= maQuickSelectionEngine
.HandleKeyEvent( rKEvt
);
1517 if ( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
1518 && ( ( !maEntryList
.IsEntryPosSelected( nSelect
) )
1519 || ( eLET
== LET_KEYSPACE
)
1523 SAL_WARN_IF( maEntryList
.IsEntryPosSelected( nSelect
) && !mbMulti
, "vcl", "ImplListBox: Selecting same Entry" );
1524 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1525 if (nSelect
>= nCount
)
1526 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1527 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
1528 mnCurrentPos
= nSelect
;
1529 if(SelectEntries( nSelect
, eLET
, bShift
, bCtrl
, bCurPosChange
))
1531 // tdf#129043 Correctly deliver events when changing values with arrow keys in combobox
1532 if (mbIsDropdown
&& IsReallyVisible())
1533 mbTravelSelect
= true;
1534 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1536 mbTravelSelect
= false;
1545 vcl::StringEntryIdentifier
lcl_getEntry( const ImplEntryList
& _rList
, sal_Int32 _nPos
, OUString
& _out_entryText
)
1547 OSL_PRECOND( ( _nPos
!= LISTBOX_ENTRY_NOTFOUND
), "lcl_getEntry: invalid position!" );
1548 sal_Int32
nEntryCount( _rList
.GetEntryCount() );
1549 if ( _nPos
>= nEntryCount
)
1551 _out_entryText
= _rList
.GetEntryText( _nPos
);
1553 // vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1555 return reinterpret_cast< vcl::StringEntryIdentifier
>( _nPos
+ sal_IntPtr(1) );
1558 sal_Int32
lcl_getEntryPos( vcl::StringEntryIdentifier _entry
)
1560 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1561 return static_cast< sal_Int32
>( reinterpret_cast< sal_Int64
>( _entry
) ) - 1;
1565 vcl::StringEntryIdentifier
ImplListBoxWindow::CurrentEntry( OUString
& _out_entryText
) const
1567 return lcl_getEntry( GetEntryList(), ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
) ? 0 : mnCurrentPos
, _out_entryText
);
1570 vcl::StringEntryIdentifier
ImplListBoxWindow::NextEntry( vcl::StringEntryIdentifier _currentEntry
, OUString
& _out_entryText
) const
1572 sal_Int32 nNextPos
= lcl_getEntryPos( _currentEntry
) + 1;
1573 return lcl_getEntry( GetEntryList(), nNextPos
, _out_entryText
);
1576 void ImplListBoxWindow::SelectEntry( vcl::StringEntryIdentifier _entry
)
1578 sal_Int32 nSelect
= lcl_getEntryPos( _entry
);
1579 if ( maEntryList
.IsEntryPosSelected( nSelect
) )
1581 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1582 // to select the given entry by typing its starting letters. No need to act.
1587 OSL_ENSURE( nSelect
< maEntryList
.GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1588 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1589 if (nSelect
>= nCount
)
1590 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1593 ShowProminentEntry( nSelect
);
1596 mnCurrentPos
= nSelect
;
1597 if ( SelectEntries( nSelect
, LET_KEYMOVE
) )
1599 mbTravelSelect
= true;
1600 mnSelectModifier
= 0;
1602 mbTravelSelect
= false;
1606 void ImplListBoxWindow::ImplPaint(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
)
1608 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1610 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr( nPos
);
1614 tools::Long nWidth
= GetOutputSizePixel().Width();
1615 tools::Long nY
= maEntryList
.GetAddedHeight(nPos
, mnTop
);
1616 tools::Rectangle
aRect(Point(0, nY
), Size(nWidth
, pEntry
->getHeightWithMargin()));
1618 bool bSelected
= maEntryList
.IsEntryPosSelected(nPos
);
1621 rRenderContext
.SetTextColor(!IsEnabled() ? rStyleSettings
.GetDisableColor() : rStyleSettings
.GetListBoxWindowHighlightTextColor());
1622 rRenderContext
.SetFillColor(rStyleSettings
.GetListBoxWindowHighlightColor());
1623 rRenderContext
.SetLineColor();
1624 rRenderContext
.DrawRect(aRect
);
1628 ApplySettings(rRenderContext
);
1630 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
1632 rRenderContext
.SetTextFillColor();
1634 if (IsUserDrawEnabled())
1636 mbInUserDraw
= true;
1637 mnUserDrawEntry
= nPos
;
1638 aRect
.AdjustLeft( -mnLeft
);
1639 if (nPos
< GetEntryList().GetMRUCount())
1640 nPos
= GetEntryList().FindEntry(GetEntryList().GetEntryText(nPos
));
1641 nPos
= nPos
- GetEntryList().GetMRUCount();
1643 UserDrawEvent
aUDEvt(&rRenderContext
, aRect
, nPos
, bSelected
);
1644 maUserDrawHdl
.Call( &aUDEvt
);
1645 mbInUserDraw
= false;
1649 DrawEntry(rRenderContext
, nPos
, true, true);
1653 void ImplListBoxWindow::DrawEntry(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
, bool bDrawImage
, bool bDrawText
)
1655 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr(nPos
);
1659 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
1661 // when changing this function don't forget to adjust ImplWin::DrawEntry()
1664 nPos
= mnUserDrawEntry
; // real entry, not the matching entry from MRU
1666 tools::Long nY
= maEntryList
.GetAddedHeight(nPos
, mnTop
);
1668 if (bDrawImage
&& maEntryList
.HasImages())
1670 Image aImage
= maEntryList
.GetEntryImage(nPos
);
1673 Size aImgSz
= aImage
.GetSizePixel();
1674 Point
aPtImg(gnBorder
- mnLeft
, nY
+ ((nEntryHeight
- aImgSz
.Height()) / 2));
1678 rRenderContext
.DrawImage(aPtImg
, aImage
);
1682 aImgSz
.setWidth( CalcZoom(aImgSz
.Width()) );
1683 aImgSz
.setHeight( CalcZoom(aImgSz
.Height()) );
1684 rRenderContext
.DrawImage(aPtImg
, aImgSz
, aImage
);
1687 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1688 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
1690 if (nEdgeBlendingPercent
&& aImgSz
.Width() && aImgSz
.Height())
1692 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
1693 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
1694 const sal_uInt8
nAlpha(255 - ((nEdgeBlendingPercent
* 255) / 100));
1695 const BitmapEx
aBlendFrame(createAlphaBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
1697 if (!aBlendFrame
.IsEmpty())
1699 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
1707 OUString
aStr(maEntryList
.GetEntryText(nPos
));
1708 if (!aStr
.isEmpty())
1710 tools::Long nMaxWidth
= std::max(mnMaxWidth
, GetOutputSizePixel().Width() - 2 * gnBorder
);
1711 // a multiline entry should only be as wide as the window
1712 if (pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
)
1713 nMaxWidth
= GetOutputSizePixel().Width() - 2 * gnBorder
;
1715 tools::Rectangle
aTextRect(Point(gnBorder
- mnLeft
, nY
),
1716 Size(nMaxWidth
, nEntryHeight
));
1718 if (maEntryList
.HasEntryImage(nPos
) || IsUserDrawEnabled())
1720 tools::Long nImageWidth
= std::max(mnMaxImgWidth
, maUserItemSize
.Width());
1721 aTextRect
.AdjustLeft(nImageWidth
+ IMG_TXT_DISTANCE
);
1724 DrawTextFlags nDrawStyle
= ImplGetTextStyle();
1725 if (pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
)
1726 nDrawStyle
|= MULTILINE_ENTRY_DRAW_FLAGS
;
1727 if (pEntry
->mnFlags
& ListBoxEntryFlags::DrawDisabled
)
1728 nDrawStyle
|= DrawTextFlags::Disable
;
1730 rRenderContext
.DrawText(aTextRect
, aStr
, nDrawStyle
);
1734 if ( !maSeparators
.empty() && ( isSeparator(nPos
) || isSeparator(nPos
-1) ) )
1736 Color
aOldLineColor(rRenderContext
.GetLineColor());
1737 rRenderContext
.SetLineColor((GetBackground() != COL_LIGHTGRAY
) ? COL_LIGHTGRAY
: COL_GRAY
);
1738 Point
aStartPos(0, nY
);
1739 if (isSeparator(nPos
))
1740 aStartPos
.AdjustY(pEntry
->getHeightWithMargin() - 1 );
1741 Point
aEndPos(aStartPos
);
1742 aEndPos
.setX( GetOutputSizePixel().Width() );
1743 rRenderContext
.DrawLine(aStartPos
, aEndPos
);
1744 rRenderContext
.SetLineColor(aOldLineColor
);
1748 void ImplListBoxWindow::FillLayoutData() const
1750 mxLayoutData
.emplace();
1751 const_cast<ImplListBoxWindow
*>(this)->Invalidate(tools::Rectangle(Point(0, 0), GetOutDev()->GetOutputSize()));
1754 void ImplListBoxWindow::ImplDoPaint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
1756 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1758 bool bShowFocusRect
= mbHasFocusRect
;
1760 ImplHideFocusRect();
1762 tools::Long nY
= 0; // + gnBorder;
1763 tools::Long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1765 for (sal_Int32 i
= mnTop
; i
< nCount
&& nY
< nHeight
+ mnMaxHeight
; i
++)
1767 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr(i
);
1768 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
1769 if (nY
+ nEntryHeight
>= rRect
.Top() &&
1770 nY
<= rRect
.Bottom() + mnMaxHeight
)
1772 ImplPaint(rRenderContext
, i
);
1777 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight(mnCurrentPos
, mnTop
);
1778 maFocusRect
.SetPos(Point(0, nHeightDiff
));
1779 Size
aSz(maFocusRect
.GetWidth(), maEntryList
.GetEntryHeight(mnCurrentPos
));
1780 maFocusRect
.SetSize(aSz
);
1781 if (HasFocus() && bShowFocusRect
)
1782 ImplShowFocusRect();
1785 void ImplListBoxWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
1787 if (SupportsDoubleBuffering())
1789 // This widget is explicitly double-buffered, so avoid partial paints.
1790 tools::Rectangle
aRect(Point(0, 0), GetOutputSizePixel());
1791 ImplDoPaint(rRenderContext
, aRect
);
1794 ImplDoPaint(rRenderContext
, rRect
);
1797 sal_uInt16
ImplListBoxWindow::GetDisplayLineCount() const
1799 // FIXME: ListBoxEntryFlags::MultiLine
1801 const sal_Int32 nCount
= maEntryList
.GetEntryCount()-mnTop
;
1802 tools::Long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1803 sal_uInt16 nEntries
= static_cast< sal_uInt16
>( ( nHeight
+ mnMaxHeight
- 1 ) / mnMaxHeight
);
1804 if( nEntries
> nCount
)
1805 nEntries
= static_cast<sal_uInt16
>(nCount
);
1810 void ImplListBoxWindow::Resize()
1814 bool bShowFocusRect
= mbHasFocusRect
;
1815 if ( bShowFocusRect
)
1816 ImplHideFocusRect();
1818 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1820 Size
aSz( GetOutputSizePixel().Width(), maEntryList
.GetEntryHeight( mnCurrentPos
) );
1821 maFocusRect
.SetSize( aSz
);
1824 if ( bShowFocusRect
)
1825 ImplShowFocusRect();
1827 ImplClearLayoutData();
1830 void ImplListBoxWindow::GetFocus()
1832 sal_Int32 nPos
= mnCurrentPos
;
1833 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
1835 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight( nPos
, mnTop
);
1836 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1837 Size
aSz( maFocusRect
.GetWidth(), maEntryList
.GetEntryHeight( nPos
) );
1838 maFocusRect
.SetSize( aSz
);
1839 ImplShowFocusRect();
1840 Control::GetFocus();
1843 void ImplListBoxWindow::LoseFocus()
1845 ImplHideFocusRect();
1846 Control::LoseFocus();
1849 void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop
)
1851 if( maEntryList
.GetEntryCount() == 0 )
1854 tools::Long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1856 sal_Int32 nLastEntry
= maEntryList
.GetEntryCount()-1;
1857 if( nTop
> nLastEntry
)
1859 const ImplEntryType
* pLast
= maEntryList
.GetEntryPtr( nLastEntry
);
1860 while( nTop
> 0 && maEntryList
.GetAddedHeight( nLastEntry
, nTop
-1 ) + pLast
->getHeightWithMargin() <= nWHeight
)
1863 if ( nTop
== mnTop
)
1866 ImplClearLayoutData();
1867 tools::Long nDiff
= maEntryList
.GetAddedHeight( mnTop
, nTop
);
1869 ImplHideFocusRect();
1874 ImplShowFocusRect();
1875 maScrollHdl
.Call( this );
1878 void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos
)
1880 sal_Int32 nPos
= nEntryPos
;
1881 auto nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1882 while( nEntryPos
> 0 && maEntryList
.GetAddedHeight( nPos
+1, nEntryPos
) < nWHeight
/2 )
1885 SetTopEntry( nEntryPos
);
1888 void ImplListBoxWindow::SetLeftIndent( tools::Long n
)
1890 ScrollHorz( n
- mnLeft
);
1893 void ImplListBoxWindow::ScrollHorz( tools::Long n
)
1895 tools::Long nDiff
= 0;
1898 tools::Long nWidth
= GetOutputSizePixel().Width();
1899 if( ( mnMaxWidth
- mnLeft
+ n
) > nWidth
)
1906 tools::Long nAbs
= -n
;
1907 nDiff
= - std::min( mnLeft
, nAbs
);
1913 ImplClearLayoutData();
1914 mnLeft
= sal::static_int_cast
<sal_uInt16
>(mnLeft
+ nDiff
);
1916 ImplHideFocusRect();
1917 Scroll( -nDiff
, 0 );
1920 ImplShowFocusRect();
1921 maScrollHdl
.Call( this );
1925 void ImplListBoxWindow::SetSeparatorPos( sal_Int32 n
)
1927 maSeparators
.clear();
1929 if ( n
!= LISTBOX_ENTRY_NOTFOUND
)
1931 maSeparators
.insert( n
);
1935 sal_Int32
ImplListBoxWindow::GetSeparatorPos() const
1937 if (!maSeparators
.empty())
1938 return *(maSeparators
.begin());
1940 return LISTBOX_ENTRY_NOTFOUND
;
1943 bool ImplListBoxWindow::isSeparator( const sal_Int32
&n
) const
1945 return maSeparators
.find(n
) != maSeparators
.end();
1948 Size
ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines
) const
1950 // FIXME: ListBoxEntryFlags::MultiLine
1953 aSz
.setHeight(nMaxLines
* GetEntryHeightWithMargin());
1954 aSz
.setWidth( mnMaxWidth
+ 2*gnBorder
);
1958 tools::Rectangle
ImplListBoxWindow::GetBoundingRectangle( sal_Int32 nItem
) const
1960 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr( nItem
);
1961 Size
aSz( GetSizePixel().Width(), pEntry
? pEntry
->getHeightWithMargin() : GetEntryHeightWithMargin() );
1962 tools::Long nY
= maEntryList
.GetAddedHeight( nItem
, GetTopEntry() ) + GetEntryList().GetMRUCount()*GetEntryHeightWithMargin();
1963 tools::Rectangle
aRect( Point( 0, nY
), aSz
);
1967 void ImplListBoxWindow::StateChanged( StateChangedType nType
)
1969 Control::StateChanged( nType
);
1971 if ( nType
== StateChangedType::Zoom
)
1973 ApplySettings(*GetOutDev());
1977 else if ( nType
== StateChangedType::UpdateMode
)
1979 if ( IsUpdateMode() && IsReallyVisible() )
1982 else if ( nType
== StateChangedType::ControlFont
)
1984 ApplySettings(*GetOutDev());
1988 else if ( nType
== StateChangedType::ControlForeground
)
1990 ApplySettings(*GetOutDev());
1993 else if ( nType
== StateChangedType::ControlBackground
)
1995 ApplySettings(*GetOutDev());
1998 else if( nType
== StateChangedType::Enable
)
2003 ImplClearLayoutData();
2006 void ImplListBoxWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
2008 Control::DataChanged( rDCEvt
);
2010 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2011 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2012 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2013 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2015 ImplClearLayoutData();
2016 ApplySettings(*GetOutDev());
2022 DrawTextFlags
ImplListBoxWindow::ImplGetTextStyle() const
2024 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2026 if (maEntryList
.HasImages())
2027 nTextStyle
|= DrawTextFlags::Left
;
2029 nTextStyle
|= DrawTextFlags::Center
;
2031 nTextStyle
|= DrawTextFlags::Right
;
2033 nTextStyle
|= DrawTextFlags::Left
;
2038 ImplListBox::ImplListBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
2039 Control( pParent
, nWinStyle
),
2040 maLBWindow(VclPtr
<ImplListBoxWindow
>::Create( this, nWinStyle
&(~WB_BORDER
) ))
2042 // for native widget rendering we must be able to detect this window type
2043 SetType( WindowType::LISTBOXWINDOW
);
2045 mpVScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_VSCROLL
| WB_DRAG
);
2046 mpHScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_HSCROLL
| WB_DRAG
);
2047 mpScrollBarBox
= VclPtr
<ScrollBarBox
>::Create( this );
2049 Link
<ScrollBar
*,void> aLink( LINK( this, ImplListBox
, ScrollBarHdl
) );
2050 mpVScrollBar
->SetScrollHdl( aLink
);
2051 mpHScrollBar
->SetScrollHdl( aLink
);
2055 mbAutoHScroll
= ( nWinStyle
& WB_AUTOHSCROLL
);
2056 mbEdgeBlending
= false;
2058 maLBWindow
->SetScrollHdl( LINK( this, ImplListBox
, LBWindowScrolled
) );
2059 maLBWindow
->SetMRUChangedHdl( LINK( this, ImplListBox
, MRUChanged
) );
2060 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2064 ImplListBox::~ImplListBox()
2069 void ImplListBox::dispose()
2071 mpHScrollBar
.disposeAndClear();
2072 mpVScrollBar
.disposeAndClear();
2073 mpScrollBarBox
.disposeAndClear();
2074 maLBWindow
.disposeAndClear();
2078 void ImplListBox::Clear()
2080 maLBWindow
->Clear();
2081 if ( GetEntryList().GetMRUCount() )
2083 maLBWindow
->GetEntryList().SetMRUCount( 0 );
2084 maLBWindow
->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND
);
2086 mpVScrollBar
->SetThumbPos( 0 );
2087 mpHScrollBar
->SetThumbPos( 0 );
2088 CompatStateChanged( StateChangedType::Data
);
2091 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
)
2093 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
);
2094 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2095 CompatStateChanged( StateChangedType::Data
);
2099 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
, const Image
& rImage
)
2101 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
, rImage
);
2102 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2103 CompatStateChanged( StateChangedType::Data
);
2107 void ImplListBox::RemoveEntry( sal_Int32 nPos
)
2109 maLBWindow
->RemoveEntry( nPos
);
2110 CompatStateChanged( StateChangedType::Data
);
2113 void ImplListBox::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
2115 maLBWindow
->SetEntryFlags( nPos
, nFlags
);
2118 void ImplListBox::SelectEntry( sal_Int32 nPos
, bool bSelect
)
2120 maLBWindow
->SelectEntry( nPos
, bSelect
);
2123 void ImplListBox::SetNoSelection()
2125 maLBWindow
->DeselectAll();
2128 void ImplListBox::GetFocus()
2131 maLBWindow
->GrabFocus();
2133 Control::GetFocus();
2136 void ImplListBox::Resize()
2139 ImplResizeControls();
2140 ImplCheckScrollBars();
2143 IMPL_LINK_NOARG(ImplListBox
, MRUChanged
, LinkParamNone
*, void)
2145 CompatStateChanged( StateChangedType::Data
);
2148 IMPL_LINK_NOARG(ImplListBox
, LBWindowScrolled
, ImplListBoxWindow
*, void)
2150 tools::Long nSet
= GetTopEntry();
2151 if( nSet
> mpVScrollBar
->GetRangeMax() )
2152 mpVScrollBar
->SetRangeMax( GetEntryList().GetEntryCount() );
2153 mpVScrollBar
->SetThumbPos( GetTopEntry() );
2155 mpHScrollBar
->SetThumbPos( GetLeftIndent() );
2157 maScrollHdl
.Call( this );
2160 IMPL_LINK( ImplListBox
, ScrollBarHdl
, ScrollBar
*, pSB
, void )
2162 sal_uInt16 nPos
= static_cast<sal_uInt16
>(pSB
->GetThumbPos());
2163 if( pSB
== mpVScrollBar
)
2164 SetTopEntry( nPos
);
2165 else if( pSB
== mpHScrollBar
)
2166 SetLeftIndent( nPos
);
2168 GetParent()->Invalidate( InvalidateFlags::Update
);
2171 void ImplListBox::ImplCheckScrollBars()
2173 bool bArrange
= false;
2175 Size aOutSz
= GetOutputSizePixel();
2176 sal_Int32 nEntries
= GetEntryList().GetEntryCount();
2177 sal_uInt16 nMaxVisEntries
= static_cast<sal_uInt16
>(aOutSz
.Height() / GetEntryHeightWithMargin());
2179 // vertical ScrollBar
2180 if( nEntries
> nMaxVisEntries
)
2186 // check of the scrolled-out region
2187 if( GetEntryList().GetSelectedEntryCount() == 1 &&
2188 GetEntryList().GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2189 ShowProminentEntry( GetEntryList().GetSelectedEntryPos( 0 ) );
2191 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2201 // horizontal ScrollBar
2204 tools::Long nWidth
= static_cast<sal_uInt16
>(aOutSz
.Width());
2206 nWidth
-= mpVScrollBar
->GetSizePixel().Width();
2208 tools::Long nMaxWidth
= GetMaxEntryWidth();
2209 if( nWidth
< nMaxWidth
)
2215 if ( !mbVScroll
) // maybe we do need one now
2217 nMaxVisEntries
= static_cast<sal_uInt16
>( ( aOutSz
.Height() - mpHScrollBar
->GetSizePixel().Height() ) / GetEntryHeightWithMargin() );
2218 if( nEntries
> nMaxVisEntries
)
2223 // check of the scrolled-out region
2224 if( GetEntryList().GetSelectedEntryCount() == 1 &&
2225 GetEntryList().GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2226 ShowProminentEntry( GetEntryList().GetSelectedEntryPos( 0 ) );
2228 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2232 // check of the scrolled-out region
2233 sal_uInt16 nMaxLI
= static_cast<sal_uInt16
>(nMaxWidth
- nWidth
);
2234 if ( nMaxLI
< GetLeftIndent() )
2235 SetLeftIndent( nMaxLI
);
2247 ImplResizeControls();
2249 ImplInitScrollBars();
2252 void ImplListBox::ImplInitScrollBars()
2254 Size aOutSz
= maLBWindow
->GetOutputSizePixel();
2258 sal_Int32 nEntries
= GetEntryList().GetEntryCount();
2259 sal_uInt16 nVisEntries
= static_cast<sal_uInt16
>(aOutSz
.Height() / GetEntryHeightWithMargin());
2260 mpVScrollBar
->SetRangeMax( nEntries
);
2261 mpVScrollBar
->SetVisibleSize( nVisEntries
);
2262 mpVScrollBar
->SetPageSize( nVisEntries
- 1 );
2267 mpHScrollBar
->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL
);
2268 mpHScrollBar
->SetVisibleSize( static_cast<sal_uInt16
>(aOutSz
.Width()) );
2269 mpHScrollBar
->SetLineSize( HORZ_SCROLL
);
2270 mpHScrollBar
->SetPageSize( aOutSz
.Width() - HORZ_SCROLL
);
2274 void ImplListBox::ImplResizeControls()
2276 // Here we only position the Controls; if the Scrollbars are to be
2277 // visible is already determined in ImplCheckScrollBars
2279 Size aOutSz
= GetOutputSizePixel();
2280 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2281 nSBWidth
= CalcZoom( nSBWidth
);
2283 Size
aInnerSz( aOutSz
);
2285 aInnerSz
.AdjustWidth( -nSBWidth
);
2287 aInnerSz
.AdjustHeight( -nSBWidth
);
2289 Point
aWinPos( 0, 0 );
2290 maLBWindow
->SetPosSizePixel( aWinPos
, aInnerSz
);
2293 if( mbVScroll
&& mbHScroll
)
2295 Point
aBoxPos( aInnerSz
.Width(), aInnerSz
.Height() );
2296 mpScrollBarBox
->SetPosSizePixel( aBoxPos
, Size( nSBWidth
, nSBWidth
) );
2297 mpScrollBarBox
->Show();
2301 mpScrollBarBox
->Hide();
2304 // vertical ScrollBar
2307 // Scrollbar on left or right side?
2308 Point
aVPos( aOutSz
.Width() - nSBWidth
, 0 );
2309 mpVScrollBar
->SetPosSizePixel( aVPos
, Size( nSBWidth
, aInnerSz
.Height() ) );
2310 mpVScrollBar
->Show();
2314 mpVScrollBar
->Hide();
2315 // #107254# Don't reset top entry after resize, but check for max top entry
2316 SetTopEntry( GetTopEntry() );
2319 // horizontal ScrollBar
2322 Point
aHPos( 0, aOutSz
.Height() - nSBWidth
);
2323 mpHScrollBar
->SetPosSizePixel( aHPos
, Size( aInnerSz
.Width(), nSBWidth
) );
2324 mpHScrollBar
->Show();
2328 mpHScrollBar
->Hide();
2333 void ImplListBox::StateChanged( StateChangedType nType
)
2335 if ( nType
== StateChangedType::InitShow
)
2337 ImplCheckScrollBars();
2339 else if ( ( nType
== StateChangedType::UpdateMode
) || ( nType
== StateChangedType::Data
) )
2341 bool bUpdate
= IsUpdateMode();
2342 maLBWindow
->SetUpdateMode( bUpdate
);
2343 if ( bUpdate
&& IsReallyVisible() )
2344 ImplCheckScrollBars();
2346 else if( nType
== StateChangedType::Enable
)
2348 mpHScrollBar
->Enable( IsEnabled() );
2349 mpVScrollBar
->Enable( IsEnabled() );
2350 mpScrollBarBox
->Enable( IsEnabled() );
2351 maLBWindow
->Enable( IsEnabled() );
2355 else if ( nType
== StateChangedType::Zoom
)
2357 maLBWindow
->SetZoom( GetZoom() );
2360 else if ( nType
== StateChangedType::ControlFont
)
2362 maLBWindow
->SetControlFont( GetControlFont() );
2364 else if ( nType
== StateChangedType::ControlForeground
)
2366 maLBWindow
->SetControlForeground( GetControlForeground() );
2368 else if ( nType
== StateChangedType::ControlBackground
)
2370 maLBWindow
->SetControlBackground( GetControlBackground() );
2372 else if( nType
== StateChangedType::Mirroring
)
2374 maLBWindow
->EnableRTL( IsRTLEnabled() );
2375 mpHScrollBar
->EnableRTL( IsRTLEnabled() );
2376 mpVScrollBar
->EnableRTL( IsRTLEnabled() );
2377 ImplResizeControls();
2380 Control::StateChanged( nType
);
2383 bool ImplListBox::EventNotify( NotifyEvent
& rNEvt
)
2386 if ( rNEvt
.GetType() == NotifyEventType::COMMAND
)
2388 const CommandEvent
& rCEvt
= *rNEvt
.GetCommandEvent();
2389 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2391 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2392 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2394 bDone
= HandleScrollCommand( rCEvt
, mpHScrollBar
, mpVScrollBar
);
2397 else if (rCEvt
.GetCommand() == CommandEventId::GesturePan
)
2399 bDone
= HandleScrollCommand(rCEvt
, mpHScrollBar
, mpVScrollBar
);
2403 return bDone
|| Window::EventNotify( rNEvt
);
2406 const Wallpaper
& ImplListBox::GetDisplayBackground() const
2408 return maLBWindow
->GetDisplayBackground();
2411 bool ImplListBox::HandleWheelAsCursorTravel(const CommandEvent
& rCEvt
, Control
& rControl
)
2414 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2416 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2417 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2419 if (!rControl
.HasChildPathFocus())
2420 rControl
.GrabFocus();
2421 sal_uInt16 nKey
= ( pData
->GetDelta() < 0 ) ? KEY_DOWN
: KEY_UP
;
2422 KeyEvent
aKeyEvent( 0, vcl::KeyCode( nKey
) );
2423 bDone
= ProcessKeyInput( aKeyEvent
);
2429 void ImplListBox::SetMRUEntries( std::u16string_view rEntries
, sal_Unicode cSep
)
2431 bool bChanges
= GetEntryList().GetMRUCount() != 0;
2433 // Remove old MRU entries
2434 for ( sal_Int32 n
= GetEntryList().GetMRUCount();n
; )
2435 maLBWindow
->RemoveEntry( --n
);
2437 sal_Int32 nMRUCount
= 0;
2438 sal_Int32 nIndex
= 0;
2441 OUString
aEntry( o3tl::getToken(rEntries
, 0, cSep
, nIndex
) );
2442 // Accept only existing entries
2443 if ( GetEntryList().FindEntry( aEntry
) != LISTBOX_ENTRY_NOTFOUND
)
2445 ImplEntryType
* pNewEntry
= new ImplEntryType( aEntry
);
2446 maLBWindow
->InsertEntry(nMRUCount
++, pNewEntry
, false);
2450 while ( nIndex
>= 0 );
2454 maLBWindow
->GetEntryList().SetMRUCount( nMRUCount
);
2455 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
2456 CompatStateChanged( StateChangedType::Data
);
2460 OUString
ImplListBox::GetMRUEntries( sal_Unicode cSep
) const
2462 OUStringBuffer aEntries
;
2463 for ( sal_Int32 n
= 0; n
< GetEntryList().GetMRUCount(); n
++ )
2465 aEntries
.append(GetEntryList().GetEntryText( n
));
2466 if( n
< ( GetEntryList().GetMRUCount() - 1 ) )
2467 aEntries
.append(cSep
);
2469 return aEntries
.makeStringAndClear();
2472 void ImplListBox::SetEdgeBlending(bool bNew
)
2474 if(mbEdgeBlending
!= bNew
)
2476 mbEdgeBlending
= bNew
;
2477 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2481 void ImplListBox::SetHighlightColor(const Color
& rColor
)
2483 AllSettings
aSettings(GetSettings());
2484 StyleSettings
aStyle(aSettings
.GetStyleSettings());
2485 aStyle
.SetHighlightColor(rColor
);
2486 aSettings
.SetStyleSettings(aStyle
);
2487 SetSettings(aSettings
);
2489 AllSettings
aSettingsLB(maLBWindow
->GetSettings());
2490 StyleSettings
aStyleLB(aSettingsLB
.GetStyleSettings());
2491 aStyleLB
.SetListBoxWindowHighlightColor(rColor
);
2492 aSettingsLB
.SetStyleSettings(aStyleLB
);
2493 maLBWindow
->SetSettings(aSettingsLB
);
2496 void ImplListBox::SetHighlightTextColor(const Color
& rColor
)
2498 AllSettings
aSettings(GetSettings());
2499 StyleSettings
aStyle(aSettings
.GetStyleSettings());
2500 aStyle
.SetHighlightTextColor(rColor
);
2501 aSettings
.SetStyleSettings(aStyle
);
2502 SetSettings(aSettings
);
2504 AllSettings
aSettingsLB(maLBWindow
->GetSettings());
2505 StyleSettings
aStyleLB(aSettingsLB
.GetStyleSettings());
2506 aStyleLB
.SetListBoxWindowHighlightTextColor(rColor
);
2507 aSettingsLB
.SetStyleSettings(aStyleLB
);
2508 maLBWindow
->SetSettings(aSettingsLB
);
2511 ImplWin::ImplWin( vcl::Window
* pParent
, WinBits nWinStyle
) :
2512 Control ( pParent
, nWinStyle
)
2514 if ( IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2515 && ! IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
2518 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2520 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
2522 mbEdgeBlending
= false;
2523 mnItemPos
= LISTBOX_ENTRY_NOTFOUND
;
2526 void ImplWin::MouseButtonDown( const MouseEvent
& )
2530 maMBDownHdl
.Call(this);
2534 void ImplWin::FillLayoutData() const
2536 mxLayoutData
.emplace();
2537 ImplWin
* pThis
= const_cast<ImplWin
*>(this);
2538 pThis
->ImplDraw(*pThis
->GetOutDev(), true);
2541 void ImplWin::ImplDraw(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2543 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2547 bool bNativeOK
= false;
2548 bool bHasFocus
= HasFocus();
2549 bool bIsEnabled
= IsEnabled();
2551 ControlState nState
= ControlState::ENABLED
;
2552 if (rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2553 && rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::HasBackgroundTexture
) )
2555 // Repaint the (focused) area similarly to
2556 // ImplSmallBorderWindowView::DrawWindow() in
2557 // vcl/source/window/brdwin.cxx
2558 vcl::Window
*pWin
= GetParent();
2560 ImplControlValue aControlValue
;
2561 bIsEnabled
&= pWin
->IsEnabled();
2563 nState
&= ~ControlState::ENABLED
;
2564 bHasFocus
|= pWin
->HasFocus();
2566 nState
|= ControlState::FOCUSED
;
2568 // The listbox is painted over the entire control including the
2569 // border, but ImplWin does not contain the border => correction
2571 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2572 pWin
->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2573 Point
aPoint( -nLeft
, -nTop
);
2574 tools::Rectangle
aCtrlRegion( aPoint
- GetPosPixel(), pWin
->GetSizePixel() );
2576 bool bMouseOver
= pWin
->IsMouseOver();
2579 vcl::Window
*pChild
= pWin
->GetWindow( GetWindowType::FirstChild
);
2582 bMouseOver
= pChild
->IsMouseOver();
2585 pChild
= pChild
->GetWindow( GetWindowType::Next
);
2589 nState
|= ControlState::ROLLOVER
;
2591 Color aBackgroundColor
= COL_AUTO
;
2592 if (IsControlBackground())
2593 aBackgroundColor
= GetControlBackground();
2595 // if parent has no border, then nobody has drawn the background
2596 // since no border window exists. so draw it here.
2597 WinBits nParentStyle
= pWin
->GetStyle();
2598 if( ! (nParentStyle
& WB_BORDER
) || (nParentStyle
& WB_NOBORDER
) )
2600 tools::Rectangle
aParentRect( Point( 0, 0 ), pWin
->GetSizePixel() );
2601 pWin
->GetOutDev()->DrawNativeControl( ControlType::Listbox
, ControlPart::Entire
, aParentRect
,
2602 nState
, aControlValue
, OUString(), aBackgroundColor
);
2605 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Listbox
, ControlPart::Entire
, aCtrlRegion
,
2606 nState
, aControlValue
, OUString(), aBackgroundColor
);
2611 if (bHasFocus
&& !ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2613 if ( !ImplGetSVData()->maNWFData
.mbNoFocusRects
)
2615 rRenderContext
.SetFillColor( rStyleSettings
.GetHighlightColor() );
2616 rRenderContext
.SetTextColor( rStyleSettings
.GetHighlightTextColor() );
2620 rRenderContext
.SetLineColor();
2621 rRenderContext
.SetFillColor();
2622 rRenderContext
.SetTextColor( rStyleSettings
.GetFieldTextColor() );
2624 rRenderContext
.DrawRect( maFocusRect
);
2629 if (IsControlForeground())
2630 aColor
= GetControlForeground();
2631 else if (ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2633 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2634 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
2636 aColor
= rStyleSettings
.GetButtonTextColor();
2640 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2641 aColor
= rStyleSettings
.GetFieldRolloverTextColor();
2643 aColor
= rStyleSettings
.GetFieldTextColor();
2645 rRenderContext
.SetTextColor(aColor
);
2647 rRenderContext
.Erase(maFocusRect
);
2652 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
2654 rRenderContext
.Erase(maFocusRect
);
2658 DrawEntry(rRenderContext
, bLayout
);
2661 void ImplWin::ApplySettings(vcl::RenderContext
& rRenderContext
)
2663 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2665 ApplyControlFont(rRenderContext
, rStyleSettings
.GetFieldFont());
2666 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetFieldTextColor());
2668 if (IsControlBackground())
2669 rRenderContext
.SetBackground(GetControlBackground());
2671 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
2674 void ImplWin::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
2676 ImplDraw(rRenderContext
);
2679 void ImplWin::DrawEntry(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2681 tools::Long nBorder
= 1;
2682 Size
aOutSz(GetOutputSizePixel());
2684 bool bImage
= !!maImage
;
2685 if (bImage
&& !bLayout
)
2687 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
2688 Size aImgSz
= maImage
.GetSizePixel();
2689 Point
aPtImg( nBorder
, ( ( aOutSz
.Height() - aImgSz
.Height() ) / 2 ) );
2690 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2692 // check for HC mode
2693 Image
*pImage
= &maImage
;
2697 rRenderContext
.DrawImage( aPtImg
, *pImage
, nStyle
);
2701 aImgSz
.setWidth( CalcZoom( aImgSz
.Width() ) );
2702 aImgSz
.setHeight( CalcZoom( aImgSz
.Height() ) );
2703 rRenderContext
.DrawImage( aPtImg
, aImgSz
, *pImage
, nStyle
);
2706 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
2708 if(nEdgeBlendingPercent
)
2710 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
2711 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
2712 const sal_uInt8
nAlpha(255 - ((nEdgeBlendingPercent
* 255) / 100));
2713 const BitmapEx
aBlendFrame(createAlphaBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
2715 if(!aBlendFrame
.IsEmpty())
2717 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
2722 if( !maString
.isEmpty() )
2724 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2726 if ( bImage
&& !bLayout
)
2727 nTextStyle
|= DrawTextFlags::Left
;
2728 else if ( GetStyle() & WB_CENTER
)
2729 nTextStyle
|= DrawTextFlags::Center
;
2730 else if ( GetStyle() & WB_RIGHT
)
2731 nTextStyle
|= DrawTextFlags::Right
;
2733 nTextStyle
|= DrawTextFlags::Left
;
2735 tools::Rectangle
aTextRect( Point( nBorder
, 0 ), Size( aOutSz
.Width()-2*nBorder
, aOutSz
.Height() ) );
2739 aTextRect
.AdjustLeft(maImage
.GetSizePixel().Width() + IMG_TXT_DISTANCE
);
2742 std::vector
< tools::Rectangle
>* pVector
= bLayout
? &mxLayoutData
->m_aUnicodeBoundRects
: nullptr;
2743 OUString
* pDisplayText
= bLayout
? &mxLayoutData
->m_aDisplayText
: nullptr;
2744 rRenderContext
.DrawText( aTextRect
, maString
, nTextStyle
, pVector
, pDisplayText
);
2747 if( HasFocus() && !bLayout
)
2748 ShowFocus( maFocusRect
);
2751 void ImplWin::Resize()
2754 maFocusRect
.SetSize( GetOutputSizePixel() );
2758 void ImplWin::GetFocus()
2760 ShowFocus( maFocusRect
);
2761 if (IsNativeWidgetEnabled() &&
2762 IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
))
2764 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2771 Control::GetFocus();
2774 void ImplWin::LoseFocus()
2777 if (IsNativeWidgetEnabled() &&
2778 IsNativeControlSupported( ControlType::Listbox
, ControlPart::Entire
))
2780 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2787 Control::LoseFocus();
2790 void ImplWin::ShowFocus(const tools::Rectangle
& rRect
)
2792 if (IsNativeControlSupported(ControlType::Listbox
, ControlPart::Focus
))
2794 ImplControlValue aControlValue
;
2796 vcl::Window
*pWin
= GetParent();
2797 tools::Rectangle
aParentRect(Point(0, 0), pWin
->GetSizePixel());
2798 pWin
->GetOutDev()->DrawNativeControl(ControlType::Listbox
, ControlPart::Focus
, aParentRect
,
2799 ControlState::FOCUSED
, aControlValue
, OUString());
2801 Control::ShowFocus(rRect
);
2804 ImplBtn::ImplBtn( vcl::Window
* pParent
, WinBits nWinStyle
) :
2805 PushButton( pParent
, nWinStyle
)
2809 void ImplBtn::MouseButtonDown( const MouseEvent
& )
2812 maMBDownHdl
.Call(this);
2815 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( vcl::Window
* pParent
) :
2816 FloatingWindow( pParent
, WB_BORDER
| WB_SYSTEMWINDOW
| WB_NOSHADOW
) // no drop shadow for list boxes
2818 // for native widget rendering we must be able to detect this window type
2819 SetType( WindowType::LISTBOXWINDOW
);
2823 mbAutoWidth
= false;
2825 mnPopupModeStartSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
2827 vcl::Window
* pBorderWindow
= ImplGetBorderWindow();
2830 SetAccessibleRole(accessibility::AccessibleRole::PANEL
);
2831 pBorderWindow
->SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2835 SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2840 ImplListBoxFloatingWindow::~ImplListBoxFloatingWindow()
2845 void ImplListBoxFloatingWindow::dispose()
2848 FloatingWindow::dispose();
2852 bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent
& rNEvt
)
2854 if( rNEvt
.GetType() == NotifyEventType::LOSEFOCUS
)
2856 if( !GetParent()->HasChildPathFocus( true ) )
2860 return FloatingWindow::PreNotify( rNEvt
);
2863 void ImplListBoxFloatingWindow::setPosSizePixel( tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
, PosSizeFlags nFlags
)
2865 FloatingWindow::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
2867 // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2868 // after a call to Resize(), we adjust its position if necessary
2869 if ( IsReallyVisible() && ( nFlags
& PosSizeFlags::Height
) )
2871 Point aPos
= GetParent()->GetPosPixel();
2872 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2874 if ( nFlags
& PosSizeFlags::X
)
2877 if ( nFlags
& PosSizeFlags::Y
)
2881 SetPosPixel( ImplCalcPos( this, tools::Rectangle( aPos
, GetParent()->GetSizePixel() ), FloatWinPopupFlags::Down
, nIndex
) );
2884 // if( !IsReallyVisible() )
2886 // The ImplListBox does not get a Resize() as not visible.
2887 // But the windows must get a Resize(), so that the number of
2888 // visible entries is correct for PgUp/PgDown.
2889 // The number also cannot be calculated by List/Combobox, as for
2890 // this the presence of the vertical Scrollbar has to be known.
2891 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
2892 static_cast<vcl::Window
*>(mpImplLB
)->Resize();
2893 static_cast<vcl::Window
*>(mpImplLB
->GetMainWindow())->Resize();
2897 void ImplListBoxFloatingWindow::Resize()
2899 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
2900 FloatingWindow::Resize();
2903 Size
ImplListBoxFloatingWindow::CalcFloatSize() const
2905 Size
aFloatSz( maPrefSz
);
2907 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2908 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2910 sal_Int32 nLines
= mpImplLB
->GetEntryList().GetEntryCount();
2911 if ( mnDDLineCount
&& ( nLines
> mnDDLineCount
) )
2912 nLines
= mnDDLineCount
;
2914 Size aSz
= mpImplLB
->CalcSize( nLines
);
2915 tools::Long nMaxHeight
= aSz
.Height() + nTop
+ nBottom
;
2917 if ( mnDDLineCount
)
2918 aFloatSz
.setHeight( nMaxHeight
);
2922 // AutoSize first only for width...
2924 aFloatSz
.setWidth( aSz
.Width() + nLeft
+ nRight
);
2925 aFloatSz
.AdjustWidth(nRight
); // adding some space looks better...
2927 if ( ( aFloatSz
.Height() < nMaxHeight
) || ( mnDDLineCount
&& ( mnDDLineCount
< mpImplLB
->GetEntryList().GetEntryCount() ) ) )
2929 // then we also need the vertical Scrollbar
2930 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2931 aFloatSz
.AdjustWidth(nSBWidth
);
2934 tools::Long nDesktopWidth
= GetDesktopRectPixel().getOpenWidth();
2935 if (aFloatSz
.Width() > nDesktopWidth
)
2936 // Don't exceed the desktop width.
2937 aFloatSz
.setWidth( nDesktopWidth
);
2940 if ( aFloatSz
.Height() > nMaxHeight
)
2941 aFloatSz
.setHeight( nMaxHeight
);
2943 // Minimal height, in case height is not set to Float height.
2944 // The parent of FloatWin must be DropDown-Combo/Listbox.
2945 Size aParentSz
= GetParent()->GetSizePixel();
2946 if( (!mnDDLineCount
|| !nLines
) && ( aFloatSz
.Height() < aParentSz
.Height() ) )
2947 aFloatSz
.setHeight( aParentSz
.Height() );
2949 // do not get narrower than the parent...
2950 if( aFloatSz
.Width() < aParentSz
.Width() )
2951 aFloatSz
.setWidth( aParentSz
.Width() );
2953 // align height to entries...
2954 tools::Long nInnerHeight
= aFloatSz
.Height() - nTop
- nBottom
;
2955 tools::Long nEntryHeight
= mpImplLB
->GetEntryHeightWithMargin();
2956 if ( nInnerHeight
% nEntryHeight
)
2958 nInnerHeight
/= nEntryHeight
;
2960 nInnerHeight
*= nEntryHeight
;
2961 aFloatSz
.setHeight( nInnerHeight
+ nTop
+ nBottom
);
2964 if (aFloatSz
.Width() < aSz
.Width())
2966 // The max width of list box entries exceeds the window width.
2967 // Account for the scroll bar height.
2968 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2969 aFloatSz
.AdjustHeight(nSBWidth
);
2975 void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking
)
2977 if( IsInPopupMode() )
2980 Size aFloatSz
= CalcFloatSize();
2982 SetSizePixel( aFloatSz
);
2983 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
2985 sal_Int32 nPos
= mpImplLB
->GetEntryList().GetSelectedEntryPos( 0 );
2986 mnPopupModeStartSaveSelection
= nPos
;
2988 Size aSz
= GetParent()->GetSizePixel();
2989 Point aPos
= GetParent()->GetPosPixel();
2990 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2991 // FIXME: this ugly hack is for Mac/Aqua
2992 // should be replaced by a real mechanism to place the float rectangle
2993 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2994 GetParent()->IsNativeWidgetEnabled() )
2996 const sal_Int32 nLeft
= 4, nTop
= 4, nRight
= 4, nBottom
= 4;
2997 aPos
.AdjustX(nLeft
);
2998 aPos
.AdjustY(nTop
);
2999 aSz
.AdjustWidth( -(nLeft
+ nRight
) );
3000 aSz
.AdjustHeight( -(nTop
+ nBottom
) );
3002 tools::Rectangle
aRect( aPos
, aSz
);
3004 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3005 // where the document is unmirrored
3006 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3007 vcl::Window
*pGrandparent
= GetParent()->GetParent();
3008 const OutputDevice
*pGrandparentOutDev
= pGrandparent
->GetOutDev();
3010 if( pGrandparent
->GetOutDev()->ImplIsAntiparallel() )
3011 pGrandparentOutDev
->ReMirror( aRect
);
3013 // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795
3014 StartPopupMode( aRect
, LISTBOX_FLOATWINPOPUPFLAGS
);
3016 if( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
3017 mpImplLB
->ShowProminentEntry( nPos
);
3019 if( bStartTracking
)
3020 mpImplLB
->GetMainWindow()->EnableMouseMoveSelect( true );
3022 if ( mpImplLB
->GetMainWindow()->IsGrabFocusAllowed() )
3023 mpImplLB
->GetMainWindow()->GrabFocus();
3025 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
3029 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */