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/toolkit/lstbox.hxx>
28 #include <vcl/toolkit/scrbar.hxx>
30 #include <listbox.hxx>
34 #include <com/sun/star/accessibility/AccessibleRole.hpp>
36 #include <sal/log.hxx>
37 #include <o3tl/safeint.hxx>
38 #include <o3tl/string_view.hxx>
39 #include <osl/diagnose.h>
40 #include <comphelper/string.hxx>
41 #include <comphelper/processfactory.hxx>
45 #define MULTILINE_ENTRY_DRAW_FLAGS ( DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags::VCenter )
47 using namespace ::com::sun::star
;
49 constexpr tools::Long gnBorder
= 1;
51 void ImplInitDropDownButton( PushButton
* pButton
)
53 pButton
->SetSymbol( SymbolType::SPIN_DOWN
);
55 if ( pButton
->IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
56 && ! pButton
->IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
57 pButton
->SetBackground();
60 ImplEntryList::ImplEntryList( vcl::Window
* pWindow
)
63 mnLastSelected
= LISTBOX_ENTRY_NOTFOUND
;
64 mnSelectionAnchor
= LISTBOX_ENTRY_NOTFOUND
;
66 mbCallSelectionChangedHdl
= true;
72 ImplEntryList::~ImplEntryList()
77 void ImplEntryList::Clear()
83 void ImplEntryList::dispose()
89 void ImplEntryList::SelectEntry( sal_Int32 nPos
, bool bSelect
)
91 if (0 <= nPos
&& o3tl::make_unsigned(nPos
) < maEntries
.size())
93 std::vector
<std::unique_ptr
<ImplEntryType
> >::iterator iter
= maEntries
.begin()+nPos
;
95 if ( ( (*iter
)->mbIsSelected
!= bSelect
) &&
96 ( ( (*iter
)->mnFlags
& ListBoxEntryFlags::DisableSelection
) == ListBoxEntryFlags::NONE
) )
98 (*iter
)->mbIsSelected
= bSelect
;
99 if ( mbCallSelectionChangedHdl
)
100 maSelectionChangedHdl
.Call( nPos
);
107 comphelper::string::NaturalStringSorter
& GetSorter()
109 static comphelper::string::NaturalStringSorter
gSorter(
110 ::comphelper::getProcessComponentContext(),
111 Application::GetSettings().GetLanguageTag().getLocale());
118 sal_Int32
NaturalSortCompare(const OUString
&rA
, const OUString
&rB
)
120 const comphelper::string::NaturalStringSorter
&rSorter
= GetSorter();
121 return rSorter
.compare(rA
, rB
);
125 sal_Int32
ImplEntryList::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
, bool bSort
)
128 assert(maEntries
.size() < LISTBOX_MAX_ENTRIES
);
130 if ( !!pNewEntry
->maImage
)
133 sal_Int32 insPos
= 0;
134 const sal_Int32 nEntriesSize
= static_cast<sal_Int32
>(maEntries
.size());
136 if ( !bSort
|| maEntries
.empty())
138 if (0 <= nPos
&& nPos
< nEntriesSize
)
141 maEntries
.insert( maEntries
.begin() + nPos
, std::unique_ptr
<ImplEntryType
>(pNewEntry
) );
145 insPos
= nEntriesSize
;
146 maEntries
.push_back(std::unique_ptr
<ImplEntryType
>(pNewEntry
));
151 const comphelper::string::NaturalStringSorter
&rSorter
= GetSorter();
153 const OUString
& rStr
= pNewEntry
->maStr
;
155 ImplEntryType
* pTemp
= GetEntry( nEntriesSize
-1 );
159 sal_Int32 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
161 // fast insert for sorted data
164 insPos
= nEntriesSize
;
165 maEntries
.push_back(std::unique_ptr
<ImplEntryType
>(pNewEntry
));
169 pTemp
= GetEntry( mnMRUCount
);
171 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
175 maEntries
.insert(maEntries
.begin(), std::unique_ptr
<ImplEntryType
>(pNewEntry
));
179 sal_uLong nLow
= mnMRUCount
;
180 sal_uLong nHigh
= maEntries
.size()-1;
186 nMid
= static_cast<sal_Int32
>((nLow
+ nHigh
) / 2);
187 pTemp
= GetEntry( nMid
);
189 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
201 while ( nLow
<= nHigh
);
207 maEntries
.insert(maEntries
.begin()+nMid
, std::unique_ptr
<ImplEntryType
>(pNewEntry
));
211 catch (uno::RuntimeException
& )
213 // XXX this is arguable, if the exception occurred because pNewEntry is
214 // garbage you wouldn't insert it. If the exception occurred because the
215 // Collator implementation is garbage then give the user a chance to see
218 maEntries
.insert(maEntries
.begin(), std::unique_ptr
<ImplEntryType
>(pNewEntry
));
226 void ImplEntryList::RemoveEntry( sal_Int32 nPos
)
228 if (0 <= nPos
&& o3tl::make_unsigned(nPos
) < maEntries
.size())
230 std::vector
<std::unique_ptr
<ImplEntryType
> >::iterator iter
= maEntries
.begin()+ nPos
;
232 if ( !!(*iter
)->maImage
)
235 maEntries
.erase(iter
);
239 sal_Int32
ImplEntryList::FindEntry( std::u16string_view rString
, bool bSearchMRUArea
) const
241 const sal_Int32 nEntries
= static_cast<sal_Int32
>(maEntries
.size());
242 for ( sal_Int32 n
= bSearchMRUArea
? 0 : GetMRUCount(); n
< nEntries
; n
++ )
244 OUString
aComp( vcl::I18nHelper::filterFormattingChars( maEntries
[n
]->maStr
) );
245 if ( aComp
== rString
)
248 return LISTBOX_ENTRY_NOTFOUND
;
251 sal_Int32
ImplEntryList::FindMatchingEntry( const OUString
& rStr
, sal_Int32 nStart
, bool bLazy
) const
253 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
254 sal_Int32 nEntryCount
= GetEntryCount();
256 const vcl::I18nHelper
& rI18nHelper
= mpWindow
->GetSettings().GetLocaleI18nHelper();
257 for ( sal_Int32 n
= nStart
; n
< nEntryCount
; )
259 ImplEntryType
* pImplEntry
= GetEntry( n
);
263 bMatch
= rI18nHelper
.MatchString( rStr
, pImplEntry
->maStr
);
267 bMatch
= pImplEntry
->maStr
.startsWith(rStr
);
281 tools::Long
ImplEntryList::GetAddedHeight( sal_Int32 i_nEndIndex
, sal_Int32 i_nBeginIndex
) const
283 tools::Long nHeight
= 0;
284 sal_Int32 nStart
= std::min(i_nEndIndex
, i_nBeginIndex
);
285 sal_Int32 nStop
= std::max(i_nEndIndex
, i_nBeginIndex
);
286 sal_Int32 nEntryCount
= GetEntryCount();
287 if( 0 <= nStop
&& nStop
!= LISTBOX_ENTRY_NOTFOUND
&& nEntryCount
!= 0 )
290 if( nStop
> nEntryCount
-1 )
291 nStop
= nEntryCount
-1;
294 else if( nStart
> nEntryCount
-1 )
295 nStart
= nEntryCount
-1;
297 sal_Int32 nIndex
= nStart
;
298 while( nIndex
!= LISTBOX_ENTRY_NOTFOUND
&& nIndex
< nStop
)
300 tools::Long nPosHeight
= GetEntryPtr( nIndex
)->getHeightWithMargin();
301 if (nHeight
> ::std::numeric_limits
<tools::Long
>::max() - nPosHeight
)
303 SAL_WARN( "vcl", "ImplEntryList::GetAddedHeight: truncated");
306 nHeight
+= nPosHeight
;
312 return i_nEndIndex
> i_nBeginIndex
? nHeight
: -nHeight
;
315 tools::Long
ImplEntryList::GetEntryHeight( sal_Int32 nPos
) const
317 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
318 return pImplEntry
? pImplEntry
->getHeightWithMargin() : 0;
321 OUString
ImplEntryList::GetEntryText( sal_Int32 nPos
) const
324 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
326 aEntryText
= pImplEntry
->maStr
;
330 bool ImplEntryList::HasEntryImage( sal_Int32 nPos
) const
333 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
335 bImage
= !!pImplEntry
->maImage
;
339 Image
ImplEntryList::GetEntryImage( sal_Int32 nPos
) const
342 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
344 aImage
= pImplEntry
->maImage
;
348 void ImplEntryList::SetEntryData( sal_Int32 nPos
, void* pNewData
)
350 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
352 pImplEntry
->mpUserData
= pNewData
;
355 void* ImplEntryList::GetEntryData( sal_Int32 nPos
) const
357 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
358 return pImplEntry
? pImplEntry
->mpUserData
: nullptr;
361 void ImplEntryList::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
363 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
365 pImplEntry
->mnFlags
= nFlags
;
368 sal_Int32
ImplEntryList::GetSelectedEntryCount() const
370 sal_Int32 nSelCount
= 0;
371 for ( sal_Int32 n
= GetEntryCount(); n
; )
373 ImplEntryType
* pImplEntry
= GetEntry( --n
);
374 if ( pImplEntry
->mbIsSelected
)
380 OUString
ImplEntryList::GetSelectedEntry( sal_Int32 nIndex
) const
382 return GetEntryText( GetSelectedEntryPos( nIndex
) );
385 sal_Int32
ImplEntryList::GetSelectedEntryPos( sal_Int32 nIndex
) const
387 sal_Int32 nSelEntryPos
= LISTBOX_ENTRY_NOTFOUND
;
389 sal_Int32 nEntryCount
= GetEntryCount();
391 for ( sal_Int32 n
= 0; n
< nEntryCount
; n
++ )
393 ImplEntryType
* pImplEntry
= GetEntry( n
);
394 if ( pImplEntry
->mbIsSelected
)
396 if ( nSel
== nIndex
)
408 bool ImplEntryList::IsEntryPosSelected( sal_Int32 nIndex
) const
410 ImplEntryType
* pImplEntry
= GetEntry( nIndex
);
411 return pImplEntry
&& pImplEntry
->mbIsSelected
;
414 bool ImplEntryList::IsEntrySelectable( sal_Int32 nPos
) const
416 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
417 return pImplEntry
== nullptr || ((pImplEntry
->mnFlags
& ListBoxEntryFlags::DisableSelection
) == ListBoxEntryFlags::NONE
);
420 sal_Int32
ImplEntryList::FindFirstSelectable( sal_Int32 nPos
, bool bForward
/* = true */ ) const
422 if( IsEntrySelectable( nPos
) )
427 for( nPos
= nPos
+ 1; nPos
< GetEntryCount(); nPos
++ )
429 if( IsEntrySelectable( nPos
) )
438 if( IsEntrySelectable( nPos
) )
443 return LISTBOX_ENTRY_NOTFOUND
;
446 ImplListBoxWindow::ImplListBoxWindow( vcl::Window
* pParent
, WinBits nWinStyle
) :
447 Control( pParent
, 0 ),
449 maQuickSelectionEngine( *this )
454 mnSelectModifier
= 0;
455 mnUserDrawEntry
= LISTBOX_ENTRY_NOTFOUND
;
457 mbTravelSelect
= false;
458 mbTrackingSelect
= false;
459 mbSelectionChanged
= false;
460 mbMouseMoveSelect
= false;
463 mbUserDrawEnabled
= false;
464 mbInUserDraw
= false;
466 mbHasFocusRect
= false;
467 mbRight
= ( nWinStyle
& WB_RIGHT
);
468 mbCenter
= ( nWinStyle
& WB_CENTER
);
469 mbSimpleMode
= ( nWinStyle
& WB_SIMPLEMODE
);
470 mbSort
= ( nWinStyle
& WB_SORT
);
471 mbIsDropdown
= ( nWinStyle
& WB_DROPDOWN
);
472 mbEdgeBlending
= false;
474 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
475 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
477 GetOutDev()->SetLineColor();
479 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
481 ApplySettings(*GetOutDev());
485 ImplListBoxWindow::~ImplListBoxWindow()
490 void ImplListBoxWindow::dispose()
492 maEntryList
.dispose();
496 void ImplListBoxWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
498 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
500 ApplyControlFont(rRenderContext
, rStyleSettings
.GetFieldFont());
501 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetListBoxWindowTextColor());
503 if (IsControlBackground())
504 rRenderContext
.SetBackground(GetControlBackground());
506 rRenderContext
.SetBackground(rStyleSettings
.GetListBoxWindowBackgroundColor());
509 void ImplListBoxWindow::ImplCalcMetrics()
517 mnTextHeight
= static_cast<sal_uInt16
>(GetTextHeight());
518 mnMaxTxtHeight
= mnTextHeight
+ gnBorder
;
519 mnMaxHeight
= mnMaxTxtHeight
;
521 if ( maUserItemSize
.Height() > mnMaxHeight
)
522 mnMaxHeight
= static_cast<sal_uInt16
>(maUserItemSize
.Height());
523 if ( maUserItemSize
.Width() > mnMaxWidth
)
524 mnMaxWidth
= static_cast<sal_uInt16
>(maUserItemSize
.Width());
526 for ( sal_Int32 n
= maEntryList
.GetEntryCount(); n
; )
528 ImplEntryType
* pEntry
= maEntryList
.GetMutableEntryPtr( --n
);
529 ImplUpdateEntryMetrics( *pEntry
);
532 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
534 Size
aSz( GetOutputSizePixel().Width(), maEntryList
.GetEntryPtr( mnCurrentPos
)->getHeightWithMargin() );
535 maFocusRect
.SetSize( aSz
);
539 void ImplListBoxWindow::Clear()
543 mnMaxHeight
= mnMaxTxtHeight
;
551 ImplClearLayoutData();
553 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
554 maQuickSelectionEngine
.Reset();
559 void ImplListBoxWindow::SetUserItemSize( const Size
& rSz
)
561 ImplClearLayoutData();
562 maUserItemSize
= rSz
;
568 struct ImplEntryMetrics
572 tools::Long nEntryWidth
;
573 tools::Long nEntryHeight
;
574 tools::Long nTextWidth
;
575 tools::Long nImgWidth
;
576 tools::Long nImgHeight
;
581 tools::Long
ImplEntryType::getHeightWithMargin() const
583 return mnHeight
+ ImplGetSVData()->maNWFData
.mnListBoxEntryMargin
;
586 SalLayoutGlyphs
* ImplEntryType::GetTextGlyphs(const OutputDevice
* pOutputDevice
)
588 if (maStrGlyphs
.IsValid())
589 // Use pre-calculated result.
592 std::unique_ptr
<SalLayout
> pLayout
= pOutputDevice
->ImplLayout(
593 maStr
, 0, maStr
.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly
);
597 // Remember the calculation result.
598 maStrGlyphs
= pLayout
->GetGlyphs();
603 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType
& rEntry
)
605 ImplEntryMetrics aMetrics
;
606 aMetrics
.bText
= !rEntry
.maStr
.isEmpty();
607 aMetrics
.bImage
= !!rEntry
.maImage
;
608 aMetrics
.nEntryWidth
= 0;
609 aMetrics
.nEntryHeight
= 0;
610 aMetrics
.nTextWidth
= 0;
611 aMetrics
.nImgWidth
= 0;
612 aMetrics
.nImgHeight
= 0;
614 if ( aMetrics
.bText
)
616 if( rEntry
.mnFlags
& ListBoxEntryFlags::MultiLine
)
619 Size
aCurSize( PixelToLogic( GetSizePixel() ) );
620 // set the current size to a large number
621 // GetTextRect should shrink it to the actual size
622 aCurSize
.setHeight( 0x7fffff );
623 tools::Rectangle
aTextRect( Point( 0, 0 ), aCurSize
);
624 aTextRect
= GetTextRect( aTextRect
, rEntry
.maStr
, DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
);
625 aMetrics
.nTextWidth
= aTextRect
.GetWidth();
626 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
627 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
628 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
629 aMetrics
.nEntryHeight
= aTextRect
.GetHeight() + gnBorder
;
633 // normal single line case
634 const SalLayoutGlyphs
* pGlyphs
= rEntry
.GetTextGlyphs(GetOutDev());
636 = static_cast<sal_uInt16
>(GetTextWidth(rEntry
.maStr
, 0, -1, nullptr, pGlyphs
));
637 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
638 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
639 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
640 aMetrics
.nEntryHeight
= mnTextHeight
+ gnBorder
;
643 if ( aMetrics
.bImage
)
645 Size aImgSz
= rEntry
.maImage
.GetSizePixel();
646 aMetrics
.nImgWidth
= static_cast<sal_uInt16
>(CalcZoom( aImgSz
.Width() ));
647 aMetrics
.nImgHeight
= static_cast<sal_uInt16
>(CalcZoom( aImgSz
.Height() ));
649 if( aMetrics
.nImgWidth
> mnMaxImgWidth
)
650 mnMaxImgWidth
= aMetrics
.nImgWidth
;
651 if( aMetrics
.nImgHeight
> mnMaxImgHeight
)
652 mnMaxImgHeight
= aMetrics
.nImgHeight
;
654 mnMaxImgTxtWidth
= std::max( mnMaxImgTxtWidth
, aMetrics
.nTextWidth
);
655 aMetrics
.nEntryHeight
= std::max( aMetrics
.nImgHeight
, aMetrics
.nEntryHeight
);
659 bool bIsUserDrawEnabled
= IsUserDrawEnabled();
660 if (bIsUserDrawEnabled
|| aMetrics
.bImage
)
662 aMetrics
.nEntryWidth
= std::max( aMetrics
.nImgWidth
, maUserItemSize
.Width() );
663 if (!bIsUserDrawEnabled
&& aMetrics
.bText
)
664 aMetrics
.nEntryWidth
+= aMetrics
.nTextWidth
+ IMG_TXT_DISTANCE
;
665 aMetrics
.nEntryHeight
= std::max( std::max( mnMaxImgHeight
, maUserItemSize
.Height() ) + 2,
666 aMetrics
.nEntryHeight
);
669 if (!aMetrics
.bText
&& !aMetrics
.bImage
&& !bIsUserDrawEnabled
)
671 // entries which have no (aka an empty) text, and no image,
672 // and are not user-drawn, should be shown nonetheless
673 aMetrics
.nEntryHeight
= mnTextHeight
+ gnBorder
;
676 if ( aMetrics
.nEntryWidth
> mnMaxWidth
)
677 mnMaxWidth
= aMetrics
.nEntryWidth
;
678 if ( aMetrics
.nEntryHeight
> mnMaxHeight
)
679 mnMaxHeight
= aMetrics
.nEntryHeight
;
681 rEntry
.mnHeight
= aMetrics
.nEntryHeight
;
684 void ImplListBoxWindow::ImplCallSelect()
686 if ( !IsTravelSelect() && GetEntryList().GetMaxMRUCount() )
688 // Insert the selected entry as MRU, if not already first MRU
689 sal_Int32 nSelected
= GetEntryList().GetSelectedEntryPos( 0 );
690 sal_Int32 nMRUCount
= GetEntryList().GetMRUCount();
691 OUString aSelected
= GetEntryList().GetEntryText( nSelected
);
692 sal_Int32 nFirstMatchingEntryPos
= GetEntryList().FindEntry( aSelected
, true );
693 if ( nFirstMatchingEntryPos
|| !nMRUCount
)
695 bool bSelectNewEntry
= false;
696 if ( nFirstMatchingEntryPos
< nMRUCount
)
698 RemoveEntry( nFirstMatchingEntryPos
);
700 if ( nFirstMatchingEntryPos
== nSelected
)
701 bSelectNewEntry
= true;
703 else if ( nMRUCount
== GetEntryList().GetMaxMRUCount() )
705 RemoveEntry( nMRUCount
- 1 );
709 ImplClearLayoutData();
711 ImplEntryType
* pNewEntry
= new ImplEntryType( aSelected
);
712 pNewEntry
->mbIsSelected
= bSelectNewEntry
;
713 GetEntryList().InsertEntry( 0, pNewEntry
, false );
714 ImplUpdateEntryMetrics( *pNewEntry
);
715 GetEntryList().SetMRUCount( ++nMRUCount
);
716 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
717 maMRUChangedHdl
.Call( nullptr );
721 maSelectHdl
.Call( nullptr );
722 mbSelectionChanged
= false;
725 sal_Int32
ImplListBoxWindow::InsertEntry(sal_Int32 nPos
, ImplEntryType
* pNewEntry
, bool bSort
)
728 assert(maEntryList
.GetEntryCount() < LISTBOX_MAX_ENTRIES
);
730 ImplClearLayoutData();
731 sal_Int32 nNewPos
= maEntryList
.InsertEntry( nPos
, pNewEntry
, bSort
);
733 if( GetStyle() & WB_WORDBREAK
)
734 pNewEntry
->mnFlags
|= ListBoxEntryFlags::MultiLine
;
736 ImplUpdateEntryMetrics( *pNewEntry
);
740 sal_Int32
ImplListBoxWindow::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
)
742 return InsertEntry(nPos
, pNewEntry
, mbSort
);
745 void ImplListBoxWindow::RemoveEntry( sal_Int32 nPos
)
747 ImplClearLayoutData();
748 maEntryList
.RemoveEntry( nPos
);
749 if( mnCurrentPos
>= maEntryList
.GetEntryCount() )
750 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
754 void ImplListBoxWindow::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
756 maEntryList
.SetEntryFlags( nPos
, nFlags
);
757 ImplEntryType
* pEntry
= maEntryList
.GetMutableEntryPtr( nPos
);
759 ImplUpdateEntryMetrics( *pEntry
);
762 void ImplListBoxWindow::ImplShowFocusRect()
764 if ( mbHasFocusRect
)
766 ShowFocus( maFocusRect
);
767 mbHasFocusRect
= true;
770 void ImplListBoxWindow::ImplHideFocusRect()
772 if ( mbHasFocusRect
)
775 mbHasFocusRect
= false;
779 sal_Int32
ImplListBoxWindow::GetEntryPosForPoint( const Point
& rPoint
) const
781 tools::Long nY
= gnBorder
;
783 sal_Int32 nSelect
= mnTop
;
784 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr( nSelect
);
787 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
788 if (rPoint
.Y() <= nEntryHeight
+ nY
)
791 pEntry
= maEntryList
.GetEntryPtr( ++nSelect
);
793 if( pEntry
== nullptr )
794 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
799 bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry
) const
803 if( i_nEntry
>= mnTop
)
805 if( maEntryList
.GetAddedHeight( i_nEntry
, mnTop
) <
806 PixelToLogic( GetSizePixel() ).Height() )
815 tools::Long
ImplListBoxWindow::GetEntryHeightWithMargin() const
817 tools::Long nMargin
= ImplGetSVData()->maNWFData
.mnListBoxEntryMargin
;
818 return mnMaxHeight
+ nMargin
;
821 sal_Int32
ImplListBoxWindow::GetLastVisibleEntry() const
823 sal_Int32 nPos
= mnTop
;
824 tools::Long nWindowHeight
= GetSizePixel().Height();
825 sal_Int32 nCount
= maEntryList
.GetEntryCount();
827 for( nDiff
= 0; nDiff
< nWindowHeight
&& nPos
< nCount
; nDiff
= maEntryList
.GetAddedHeight( nPos
, mnTop
) )
830 if( nDiff
> nWindowHeight
&& nPos
> mnTop
)
839 void ImplListBoxWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
841 mbMouseMoveSelect
= false; // only till the first MouseButtonDown
842 maQuickSelectionEngine
.Reset();
846 if( rMEvt
.GetClicks() == 1 )
848 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
849 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
851 if ( !mbMulti
&& GetEntryList().GetSelectedEntryCount() )
852 mnTrackingSaveSelection
= GetEntryList().GetSelectedEntryPos( 0 );
854 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
856 mnCurrentPos
= nSelect
;
857 mbTrackingSelect
= true;
858 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
859 (void)SelectEntries( nSelect
, LET_MBDOWN
, rMEvt
.IsShift(), rMEvt
.IsMod1() ,bCurPosChange
);
860 mbTrackingSelect
= false;
864 StartTracking( StartTrackingFlags::ScrollRepeat
);
867 if( rMEvt
.GetClicks() == 2 )
869 maDoubleClickHdl
.Call( this );
872 else // if ( mbGrabFocus )
878 void ImplListBoxWindow::MouseMove( const MouseEvent
& rMEvt
)
880 if (rMEvt
.IsLeaveWindow() || mbMulti
|| !IsMouseMoveSelect() || !maEntryList
.GetEntryCount())
883 tools::Rectangle
aRect( Point(), GetOutputSizePixel() );
884 if( !aRect
.Contains( rMEvt
.GetPosPixel() ) )
887 if ( IsMouseMoveSelect() )
889 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
890 if( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
891 nSelect
= maEntryList
.GetEntryCount() - 1;
892 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
893 nSelect
= std::min( nSelect
, static_cast<sal_Int32
>( maEntryList
.GetEntryCount() - 1 ) );
894 // Select only visible Entries with MouseMove, otherwise Tracking...
895 if ( IsVisible( nSelect
) &&
896 maEntryList
.IsEntrySelectable( nSelect
) &&
897 ( ( nSelect
!= mnCurrentPos
) || !GetEntryList().GetSelectedEntryCount() || ( nSelect
!= GetEntryList().GetSelectedEntryPos( 0 ) ) ) )
899 mbTrackingSelect
= true;
900 if ( SelectEntries( nSelect
, LET_TRACKING
) )
902 // When list box selection change by mouse move, notify
903 // VclEventId::ListboxSelect vcl event.
904 maListItemSelectHdl
.Call(nullptr);
906 mbTrackingSelect
= false;
910 // if the DD button was pressed and someone moved into the ListBox
911 // with the mouse button pressed...
912 if ( rMEvt
.IsLeft() && !rMEvt
.IsSynthetic() )
914 if ( !mbMulti
&& GetEntryList().GetSelectedEntryCount() )
915 mnTrackingSaveSelection
= GetEntryList().GetSelectedEntryPos( 0 );
917 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
919 StartTracking( StartTrackingFlags::ScrollRepeat
);
923 void ImplListBoxWindow::DeselectAll()
925 while ( GetEntryList().GetSelectedEntryCount() )
927 sal_Int32 nS
= GetEntryList().GetSelectedEntryPos( 0 );
928 SelectEntry( nS
, false );
932 void ImplListBoxWindow::SelectEntry( sal_Int32 nPos
, bool bSelect
)
934 if( (maEntryList
.IsEntryPosSelected( nPos
) == bSelect
) || !maEntryList
.IsEntrySelectable( nPos
) )
942 // deselect the selected entry
943 sal_Int32 nDeselect
= GetEntryList().GetSelectedEntryPos( 0 );
944 if( nDeselect
!= LISTBOX_ENTRY_NOTFOUND
)
946 //SelectEntryPos( nDeselect, false );
947 GetEntryList().SelectEntry( nDeselect
, false );
948 if (IsUpdateMode() && IsReallyVisible())
952 maEntryList
.SelectEntry( nPos
, true );
954 if ( ( nPos
!= LISTBOX_ENTRY_NOTFOUND
) && IsUpdateMode() )
957 if ( !IsVisible( nPos
) )
959 ImplClearLayoutData();
960 sal_Int32 nVisibleEntries
= GetLastVisibleEntry()-mnTop
;
961 if ( !nVisibleEntries
|| !IsReallyVisible() || ( nPos
< GetTopEntry() ) )
964 ShowProminentEntry( nPos
);
968 ShowProminentEntry( nPos
);
975 maEntryList
.SelectEntry( nPos
, false );
978 mbSelectionChanged
= true;
981 bool ImplListBoxWindow::SelectEntries( sal_Int32 nSelect
, LB_EVENT_TYPE eLET
, bool bShift
, bool bCtrl
, bool bSelectPosChange
/*=FALSE*/ )
983 bool bSelectionChanged
= false;
985 if( IsEnabled() && maEntryList
.IsEntrySelectable( nSelect
) )
987 bool bFocusChanged
= false;
989 // here (Single-ListBox) only one entry can be deselected
992 sal_Int32 nDeselect
= maEntryList
.GetSelectedEntryPos( 0 );
993 if( nSelect
!= nDeselect
)
995 SelectEntry( nSelect
, true );
996 maEntryList
.SetLastSelected( nSelect
);
997 bFocusChanged
= true;
998 bSelectionChanged
= true;
1001 // MultiListBox without Modifier
1002 else if( mbSimpleMode
&& !bCtrl
&& !bShift
)
1004 sal_Int32 nEntryCount
= maEntryList
.GetEntryCount();
1005 for ( sal_Int32 nPos
= 0; nPos
< nEntryCount
; nPos
++ )
1007 bool bSelect
= nPos
== nSelect
;
1008 if ( maEntryList
.IsEntryPosSelected( nPos
) != bSelect
)
1010 SelectEntry( nPos
, bSelect
);
1011 bFocusChanged
= true;
1012 bSelectionChanged
= true;
1015 maEntryList
.SetLastSelected( nSelect
);
1016 maEntryList
.SetSelectionAnchor( nSelect
);
1018 // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1019 else if( ( !mbSimpleMode
/* && !bShift */ ) || ( mbSimpleMode
&& ( bCtrl
|| bShift
) ) )
1021 // Space for selection change
1022 if( !bShift
&& ( ( eLET
== LET_KEYSPACE
) || ( eLET
== LET_MBDOWN
) ) )
1024 bool bSelect
= !maEntryList
.IsEntryPosSelected( nSelect
);
1025 SelectEntry( nSelect
, bSelect
);
1026 maEntryList
.SetLastSelected( nSelect
);
1027 maEntryList
.SetSelectionAnchor( nSelect
);
1028 if ( !maEntryList
.IsEntryPosSelected( nSelect
) )
1029 maEntryList
.SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND
);
1030 bFocusChanged
= true;
1031 bSelectionChanged
= true;
1033 else if( ( ( eLET
== LET_TRACKING
) && ( nSelect
!= mnCurrentPos
) ) ||
1034 ( bShift
&& ( ( eLET
== LET_KEYMOVE
) || ( eLET
== LET_MBDOWN
) ) ) )
1036 mnCurrentPos
= nSelect
;
1037 bFocusChanged
= true;
1039 sal_Int32 nAnchor
= maEntryList
.GetSelectionAnchor();
1040 if( ( nAnchor
== LISTBOX_ENTRY_NOTFOUND
) && maEntryList
.GetSelectedEntryCount() )
1042 nAnchor
= maEntryList
.GetSelectedEntryPos( maEntryList
.GetSelectedEntryCount() - 1 );
1044 if( nAnchor
!= LISTBOX_ENTRY_NOTFOUND
)
1046 // All entries from Anchor to nSelect have to be selected
1047 sal_Int32 nStart
= std::min( nSelect
, nAnchor
);
1048 sal_Int32 nEnd
= std::max( nSelect
, nAnchor
);
1049 for ( sal_Int32 n
= nStart
; n
<= nEnd
; n
++ )
1051 if ( !maEntryList
.IsEntryPosSelected( n
) )
1053 SelectEntry( n
, true );
1054 bSelectionChanged
= true;
1058 // if appropriate some more has to be deselected...
1059 sal_Int32 nLast
= maEntryList
.GetLastSelected();
1060 if ( nLast
!= LISTBOX_ENTRY_NOTFOUND
)
1062 if ( ( nLast
> nSelect
) && ( nLast
> nAnchor
) )
1064 for ( sal_Int32 n
= nSelect
+1; n
<= nLast
; n
++ )
1066 if ( maEntryList
.IsEntryPosSelected( n
) )
1068 SelectEntry( n
, false );
1069 bSelectionChanged
= true;
1073 else if ( ( nLast
< nSelect
) && ( nLast
< nAnchor
) )
1075 for ( sal_Int32 n
= nLast
; n
< nSelect
; n
++ )
1077 if ( maEntryList
.IsEntryPosSelected( n
) )
1079 SelectEntry( n
, false );
1080 bSelectionChanged
= true;
1085 maEntryList
.SetLastSelected( nSelect
);
1088 else if( eLET
!= LET_TRACKING
)
1090 ImplHideFocusRect();
1092 bFocusChanged
= true;
1097 bFocusChanged
= true;
1100 if( bSelectionChanged
)
1101 mbSelectionChanged
= true;
1105 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight( nSelect
, mnTop
);
1106 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1107 Size
aSz( maFocusRect
.GetWidth(),
1108 maEntryList
.GetEntryHeight( nSelect
) );
1109 maFocusRect
.SetSize( aSz
);
1111 ImplShowFocusRect();
1112 if (bSelectPosChange
)
1114 maFocusHdl
.Call(nSelect
);
1117 ImplClearLayoutData();
1119 return bSelectionChanged
;
1122 void ImplListBoxWindow::Tracking( const TrackingEvent
& rTEvt
)
1124 tools::Rectangle
aRect( Point(), GetOutputSizePixel() );
1125 bool bInside
= aRect
.Contains( rTEvt
.GetMouseEvent().GetPosPixel() );
1127 if( rTEvt
.IsTrackingCanceled() || rTEvt
.IsTrackingEnded() ) // MouseButtonUp
1129 if ( bInside
&& !rTEvt
.IsTrackingCanceled() )
1131 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1136 maCancelHdl
.Call( nullptr );
1139 mbTrackingSelect
= true;
1140 SelectEntry( mnTrackingSaveSelection
, true );
1141 mbTrackingSelect
= false;
1142 if ( mnTrackingSaveSelection
!= LISTBOX_ENTRY_NOTFOUND
)
1144 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight( mnCurrentPos
, mnTop
);
1145 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1146 Size
aSz( maFocusRect
.GetWidth(),
1147 maEntryList
.GetEntryHeight( mnCurrentPos
) );
1148 maFocusRect
.SetSize( aSz
);
1149 ImplShowFocusRect();
1158 bool bTrackOrQuickClick
= mbTrack
;
1166 // this case only happens, if the mouse button is pressed very briefly
1167 if( rTEvt
.IsTrackingEnded() && mbTrack
)
1169 bTrackOrQuickClick
= true;
1174 if( bTrackOrQuickClick
)
1176 MouseEvent aMEvt
= rTEvt
.GetMouseEvent();
1177 Point
aPt( aMEvt
.GetPosPixel() );
1178 bool bShift
= aMEvt
.IsShift();
1179 bool bCtrl
= aMEvt
.IsMod1();
1181 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1184 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1186 nSelect
= mnCurrentPos
? ( mnCurrentPos
- 1 ) : 0;
1187 if( nSelect
< mnTop
)
1188 SetTopEntry( mnTop
-1 );
1191 else if( aPt
.Y() > GetOutputSizePixel().Height() )
1193 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1195 nSelect
= std::min( static_cast<sal_Int32
>(mnCurrentPos
+1), static_cast<sal_Int32
>(maEntryList
.GetEntryCount()-1) );
1196 if( nSelect
>= GetLastVisibleEntry() )
1197 SetTopEntry( mnTop
+1 );
1202 nSelect
= static_cast<sal_Int32
>( ( aPt
.Y() + gnBorder
) / mnMaxHeight
) + mnTop
;
1203 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
1204 nSelect
= std::min( nSelect
, static_cast<sal_Int32
>( maEntryList
.GetEntryCount() - 1 ) );
1209 if ( ( nSelect
!= mnCurrentPos
) || !GetEntryList().GetSelectedEntryCount() )
1211 mbTrackingSelect
= true;
1212 SelectEntries(nSelect
, LET_TRACKING
, bShift
, bCtrl
);
1213 mbTrackingSelect
= false;
1218 if ( !mbMulti
&& GetEntryList().GetSelectedEntryCount() )
1220 mbTrackingSelect
= true;
1221 SelectEntry( GetEntryList().GetSelectedEntryPos( 0 ), false );
1222 mbTrackingSelect
= false;
1225 mnCurrentPos
= nSelect
;
1226 if ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1228 ImplHideFocusRect();
1232 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight( mnCurrentPos
, mnTop
);
1233 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1234 Size
aSz( maFocusRect
.GetWidth(), maEntryList
.GetEntryHeight( mnCurrentPos
) );
1235 maFocusRect
.SetSize( aSz
);
1236 ImplShowFocusRect();
1242 void ImplListBoxWindow::KeyInput( const KeyEvent
& rKEvt
)
1244 if( !ProcessKeyInput( rKEvt
) )
1245 Control::KeyInput( rKEvt
);
1248 bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent
& rKEvt
)
1250 // entry to be selected
1251 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1252 LB_EVENT_TYPE eLET
= LET_KEYMOVE
;
1254 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1256 bool bShift
= aKeyCode
.IsShift();
1257 bool bCtrl
= aKeyCode
.IsMod1() || aKeyCode
.IsMod3();
1258 bool bMod2
= aKeyCode
.IsMod2();
1260 bool bHandleKey
= false;
1262 switch( aKeyCode
.GetCode() )
1268 if ( GetTopEntry() )
1269 SetTopEntry( GetTopEntry()-1 );
1273 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1275 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1277 else if ( mnCurrentPos
)
1279 // search first selectable above the current position
1280 nSelect
= maEntryList
.FindFirstSelectable( mnCurrentPos
- 1, false );
1283 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
< mnTop
) )
1284 SetTopEntry( mnTop
-1 );
1288 maQuickSelectionEngine
.Reset();
1296 SetTopEntry( GetTopEntry()+1 );
1300 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1302 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1304 else if ( (mnCurrentPos
+1) < maEntryList
.GetEntryCount() )
1306 // search first selectable below the current position
1307 nSelect
= maEntryList
.FindFirstSelectable( mnCurrentPos
+ 1 );
1310 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
>= GetLastVisibleEntry() ) )
1311 SetTopEntry( mnTop
+1 );
1315 maQuickSelectionEngine
.Reset();
1323 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1324 SetTopEntry( ( mnTop
> nCurVis
) ?
1325 (mnTop
-nCurVis
) : 0 );
1327 else if ( !bCtrl
&& !bMod2
)
1329 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1331 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1333 else if ( mnCurrentPos
)
1335 if( mnCurrentPos
== mnTop
)
1337 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1338 SetTopEntry( ( mnTop
> nCurVis
) ? ( mnTop
-nCurVis
+1 ) : 0 );
1341 // find first selectable starting from mnTop looking forward
1342 nSelect
= maEntryList
.FindFirstSelectable( mnTop
);
1346 maQuickSelectionEngine
.Reset();
1354 SetTopEntry( GetLastVisibleEntry() );
1356 else if ( !bCtrl
&& !bMod2
)
1358 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1360 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1362 else if ( (mnCurrentPos
+1) < maEntryList
.GetEntryCount() )
1364 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1365 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
;
1366 sal_Int32 nTmp
= std::min( nCurVis
, nCount
);
1368 if( mnCurrentPos
== nTmp
&& mnCurrentPos
!= nCount
- 1 )
1370 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) );
1371 nTmp2
= std::max( tools::Long(0) , nTmp2
);
1372 nTmp
= static_cast<sal_Int32
>(nTmp2
+(nCurVis
-1) );
1373 SetTopEntry( static_cast<sal_Int32
>(nTmp2
) );
1375 // find first selectable starting from nTmp looking backwards
1376 nSelect
= maEntryList
.FindFirstSelectable( nTmp
, false );
1380 maQuickSelectionEngine
.Reset();
1390 else if ( !bCtrl
&& !bMod2
&& mnCurrentPos
)
1392 nSelect
= maEntryList
.FindFirstSelectable( maEntryList
.GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND
);
1398 maQuickSelectionEngine
.Reset();
1406 SetTopEntry( 0xFFFF );
1408 else if ( !bCtrl
&& !bMod2
)
1410 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1412 nSelect
= maEntryList
.FindFirstSelectable( 0 );
1414 else if ( (mnCurrentPos
+1) < maEntryList
.GetEntryCount() )
1416 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1417 nSelect
= maEntryList
.FindFirstSelectable( nCount
- 1, false );
1418 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+ 1;
1419 if( nCount
> nCurVis
)
1420 SetTopEntry( nCount
- nCurVis
);
1424 maQuickSelectionEngine
.Reset();
1430 if ( !bCtrl
&& !bMod2
)
1432 ScrollHorz( -HORZ_SCROLL
);
1435 maQuickSelectionEngine
.Reset();
1441 if ( !bCtrl
&& !bMod2
)
1443 ScrollHorz( HORZ_SCROLL
);
1446 maQuickSelectionEngine
.Reset();
1452 if ( !bMod2
&& !IsReadOnly() )
1454 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1456 bDone
= false; // do not catch RETURN
1458 maQuickSelectionEngine
.Reset();
1464 if ( !bMod2
&& !IsReadOnly() )
1466 if( mbMulti
&& ( !mbSimpleMode
|| ( mbSimpleMode
&& bCtrl
&& !bShift
) ) )
1468 nSelect
= mnCurrentPos
;
1469 eLET
= LET_KEYSPACE
;
1479 if( bCtrl
&& mbMulti
)
1482 bool bUpdates
= IsUpdateMode();
1483 SetUpdateMode( false );
1485 sal_Int32 nEntryCount
= maEntryList
.GetEntryCount();
1486 for( sal_Int32 i
= 0; i
< nEntryCount
; i
++ )
1487 SelectEntry( i
, true );
1489 // tdf#97066 - Update selected items
1492 // restore update mode
1493 SetUpdateMode( bUpdates
);
1496 maQuickSelectionEngine
.Reset();
1511 if (bHandleKey
&& !IsReadOnly())
1513 bDone
= maQuickSelectionEngine
.HandleKeyEvent( rKEvt
);
1516 if ( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
1517 && ( ( !maEntryList
.IsEntryPosSelected( nSelect
) )
1518 || ( eLET
== LET_KEYSPACE
)
1522 SAL_WARN_IF( maEntryList
.IsEntryPosSelected( nSelect
) && !mbMulti
, "vcl", "ImplListBox: Selecting same Entry" );
1523 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1524 if (nSelect
>= nCount
)
1525 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1526 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
1527 mnCurrentPos
= nSelect
;
1528 if(SelectEntries( nSelect
, eLET
, bShift
, bCtrl
, bCurPosChange
))
1530 // tdf#129043 Correctly deliver events when changing values with arrow keys in combobox
1531 if (mbIsDropdown
&& IsReallyVisible())
1532 mbTravelSelect
= true;
1533 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1535 mbTravelSelect
= false;
1544 vcl::StringEntryIdentifier
lcl_getEntry( const ImplEntryList
& _rList
, sal_Int32 _nPos
, OUString
& _out_entryText
)
1546 OSL_PRECOND( ( _nPos
!= LISTBOX_ENTRY_NOTFOUND
), "lcl_getEntry: invalid position!" );
1547 sal_Int32
nEntryCount( _rList
.GetEntryCount() );
1548 if ( _nPos
>= nEntryCount
)
1550 _out_entryText
= _rList
.GetEntryText( _nPos
);
1552 // vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1554 return reinterpret_cast< vcl::StringEntryIdentifier
>( _nPos
+ 1 );
1557 sal_Int32
lcl_getEntryPos( vcl::StringEntryIdentifier _entry
)
1559 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1560 return static_cast< sal_Int32
>( reinterpret_cast< sal_Int64
>( _entry
) ) - 1;
1564 vcl::StringEntryIdentifier
ImplListBoxWindow::CurrentEntry( OUString
& _out_entryText
) const
1566 return lcl_getEntry( GetEntryList(), ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
) ? 0 : mnCurrentPos
, _out_entryText
);
1569 vcl::StringEntryIdentifier
ImplListBoxWindow::NextEntry( vcl::StringEntryIdentifier _currentEntry
, OUString
& _out_entryText
) const
1571 sal_Int32 nNextPos
= lcl_getEntryPos( _currentEntry
) + 1;
1572 return lcl_getEntry( GetEntryList(), nNextPos
, _out_entryText
);
1575 void ImplListBoxWindow::SelectEntry( vcl::StringEntryIdentifier _entry
)
1577 sal_Int32 nSelect
= lcl_getEntryPos( _entry
);
1578 if ( maEntryList
.IsEntryPosSelected( nSelect
) )
1580 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1581 // to select the given entry by typing its starting letters. No need to act.
1586 OSL_ENSURE( nSelect
< maEntryList
.GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1587 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1588 if (nSelect
>= nCount
)
1589 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1592 ShowProminentEntry( nSelect
);
1595 mnCurrentPos
= nSelect
;
1596 if ( SelectEntries( nSelect
, LET_KEYMOVE
) )
1598 mbTravelSelect
= true;
1599 mnSelectModifier
= 0;
1601 mbTravelSelect
= false;
1605 void ImplListBoxWindow::ImplPaint(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
)
1607 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1609 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr( nPos
);
1613 tools::Long nWidth
= GetOutputSizePixel().Width();
1614 tools::Long nY
= maEntryList
.GetAddedHeight(nPos
, mnTop
);
1615 tools::Rectangle
aRect(Point(0, nY
), Size(nWidth
, pEntry
->getHeightWithMargin()));
1617 bool bSelected
= maEntryList
.IsEntryPosSelected(nPos
);
1620 rRenderContext
.SetTextColor(!IsEnabled() ? rStyleSettings
.GetDisableColor() : rStyleSettings
.GetListBoxWindowHighlightTextColor());
1621 rRenderContext
.SetFillColor(rStyleSettings
.GetListBoxWindowHighlightColor());
1622 rRenderContext
.SetLineColor();
1623 rRenderContext
.DrawRect(aRect
);
1627 ApplySettings(rRenderContext
);
1629 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
1631 rRenderContext
.SetTextFillColor();
1633 if (IsUserDrawEnabled())
1635 mbInUserDraw
= true;
1636 mnUserDrawEntry
= nPos
;
1637 aRect
.AdjustLeft( -mnLeft
);
1638 if (nPos
< GetEntryList().GetMRUCount())
1639 nPos
= GetEntryList().FindEntry(GetEntryList().GetEntryText(nPos
));
1640 nPos
= nPos
- GetEntryList().GetMRUCount();
1642 UserDrawEvent
aUDEvt(&rRenderContext
, aRect
, nPos
, bSelected
);
1643 maUserDrawHdl
.Call( &aUDEvt
);
1644 mbInUserDraw
= false;
1648 DrawEntry(rRenderContext
, nPos
, true, true);
1652 void ImplListBoxWindow::DrawEntry(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
, bool bDrawImage
, bool bDrawText
)
1654 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr(nPos
);
1658 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
1660 // when changing this function don't forget to adjust ImplWin::DrawEntry()
1663 nPos
= mnUserDrawEntry
; // real entry, not the matching entry from MRU
1665 tools::Long nY
= maEntryList
.GetAddedHeight(nPos
, mnTop
);
1667 if (bDrawImage
&& maEntryList
.HasImages())
1669 Image aImage
= maEntryList
.GetEntryImage(nPos
);
1672 Size aImgSz
= aImage
.GetSizePixel();
1673 Point
aPtImg(gnBorder
- mnLeft
, nY
+ ((nEntryHeight
- aImgSz
.Height()) / 2));
1677 rRenderContext
.DrawImage(aPtImg
, aImage
);
1681 aImgSz
.setWidth( CalcZoom(aImgSz
.Width()) );
1682 aImgSz
.setHeight( CalcZoom(aImgSz
.Height()) );
1683 rRenderContext
.DrawImage(aPtImg
, aImgSz
, aImage
);
1686 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1687 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
1689 if (nEdgeBlendingPercent
&& aImgSz
.Width() && aImgSz
.Height())
1691 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
1692 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
1693 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
1694 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
1696 if (!aBlendFrame
.IsEmpty())
1698 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
1706 OUString
aStr(maEntryList
.GetEntryText(nPos
));
1707 if (!aStr
.isEmpty())
1709 tools::Long nMaxWidth
= std::max(mnMaxWidth
, GetOutputSizePixel().Width() - 2 * gnBorder
);
1710 // a multiline entry should only be as wide as the window
1711 if (pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
)
1712 nMaxWidth
= GetOutputSizePixel().Width() - 2 * gnBorder
;
1714 tools::Rectangle
aTextRect(Point(gnBorder
- mnLeft
, nY
),
1715 Size(nMaxWidth
, nEntryHeight
));
1717 if (maEntryList
.HasEntryImage(nPos
) || IsUserDrawEnabled())
1719 tools::Long nImageWidth
= std::max(mnMaxImgWidth
, maUserItemSize
.Width());
1720 aTextRect
.AdjustLeft(nImageWidth
+ IMG_TXT_DISTANCE
);
1723 DrawTextFlags nDrawStyle
= ImplGetTextStyle();
1724 if (pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
)
1725 nDrawStyle
|= MULTILINE_ENTRY_DRAW_FLAGS
;
1726 if (pEntry
->mnFlags
& ListBoxEntryFlags::DrawDisabled
)
1727 nDrawStyle
|= DrawTextFlags::Disable
;
1729 rRenderContext
.DrawText(aTextRect
, aStr
, nDrawStyle
);
1733 if ( !maSeparators
.empty() && ( isSeparator(nPos
) || isSeparator(nPos
-1) ) )
1735 Color
aOldLineColor(rRenderContext
.GetLineColor());
1736 rRenderContext
.SetLineColor((GetBackground() != COL_LIGHTGRAY
) ? COL_LIGHTGRAY
: COL_GRAY
);
1737 Point
aStartPos(0, nY
);
1738 if (isSeparator(nPos
))
1739 aStartPos
.AdjustY(pEntry
->getHeightWithMargin() - 1 );
1740 Point
aEndPos(aStartPos
);
1741 aEndPos
.setX( GetOutputSizePixel().Width() );
1742 rRenderContext
.DrawLine(aStartPos
, aEndPos
);
1743 rRenderContext
.SetLineColor(aOldLineColor
);
1747 void ImplListBoxWindow::FillLayoutData() const
1749 mxLayoutData
.emplace();
1750 const_cast<ImplListBoxWindow
*>(this)->Invalidate(tools::Rectangle(Point(0, 0), GetOutDev()->GetOutputSize()));
1753 void ImplListBoxWindow::ImplDoPaint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
1755 sal_Int32 nCount
= maEntryList
.GetEntryCount();
1757 bool bShowFocusRect
= mbHasFocusRect
;
1759 ImplHideFocusRect();
1761 tools::Long nY
= 0; // + gnBorder;
1762 tools::Long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1764 for (sal_Int32 i
= mnTop
; i
< nCount
&& nY
< nHeight
+ mnMaxHeight
; i
++)
1766 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr(i
);
1767 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
1768 if (nY
+ nEntryHeight
>= rRect
.Top() &&
1769 nY
<= rRect
.Bottom() + mnMaxHeight
)
1771 ImplPaint(rRenderContext
, i
);
1776 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight(mnCurrentPos
, mnTop
);
1777 maFocusRect
.SetPos(Point(0, nHeightDiff
));
1778 Size
aSz(maFocusRect
.GetWidth(), maEntryList
.GetEntryHeight(mnCurrentPos
));
1779 maFocusRect
.SetSize(aSz
);
1780 if (HasFocus() && bShowFocusRect
)
1781 ImplShowFocusRect();
1784 void ImplListBoxWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
1786 if (SupportsDoubleBuffering())
1788 // This widget is explicitly double-buffered, so avoid partial paints.
1789 tools::Rectangle
aRect(Point(0, 0), GetOutputSizePixel());
1790 ImplDoPaint(rRenderContext
, aRect
);
1793 ImplDoPaint(rRenderContext
, rRect
);
1796 sal_uInt16
ImplListBoxWindow::GetDisplayLineCount() const
1798 // FIXME: ListBoxEntryFlags::MultiLine
1800 const sal_Int32 nCount
= maEntryList
.GetEntryCount()-mnTop
;
1801 tools::Long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1802 sal_uInt16 nEntries
= static_cast< sal_uInt16
>( ( nHeight
+ mnMaxHeight
- 1 ) / mnMaxHeight
);
1803 if( nEntries
> nCount
)
1804 nEntries
= static_cast<sal_uInt16
>(nCount
);
1809 void ImplListBoxWindow::Resize()
1813 bool bShowFocusRect
= mbHasFocusRect
;
1814 if ( bShowFocusRect
)
1815 ImplHideFocusRect();
1817 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1819 Size
aSz( GetOutputSizePixel().Width(), maEntryList
.GetEntryHeight( mnCurrentPos
) );
1820 maFocusRect
.SetSize( aSz
);
1823 if ( bShowFocusRect
)
1824 ImplShowFocusRect();
1826 ImplClearLayoutData();
1829 void ImplListBoxWindow::GetFocus()
1831 sal_Int32 nPos
= mnCurrentPos
;
1832 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
1834 tools::Long nHeightDiff
= maEntryList
.GetAddedHeight( nPos
, mnTop
);
1835 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1836 Size
aSz( maFocusRect
.GetWidth(), maEntryList
.GetEntryHeight( nPos
) );
1837 maFocusRect
.SetSize( aSz
);
1838 ImplShowFocusRect();
1839 Control::GetFocus();
1842 void ImplListBoxWindow::LoseFocus()
1844 ImplHideFocusRect();
1845 Control::LoseFocus();
1848 void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop
)
1850 if( maEntryList
.GetEntryCount() == 0 )
1853 tools::Long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1855 sal_Int32 nLastEntry
= maEntryList
.GetEntryCount()-1;
1856 if( nTop
> nLastEntry
)
1858 const ImplEntryType
* pLast
= maEntryList
.GetEntryPtr( nLastEntry
);
1859 while( nTop
> 0 && maEntryList
.GetAddedHeight( nLastEntry
, nTop
-1 ) + pLast
->getHeightWithMargin() <= nWHeight
)
1862 if ( nTop
== mnTop
)
1865 ImplClearLayoutData();
1866 tools::Long nDiff
= maEntryList
.GetAddedHeight( mnTop
, nTop
);
1868 ImplHideFocusRect();
1873 ImplShowFocusRect();
1874 maScrollHdl
.Call( this );
1877 void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos
)
1879 sal_Int32 nPos
= nEntryPos
;
1880 auto nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1881 while( nEntryPos
> 0 && maEntryList
.GetAddedHeight( nPos
+1, nEntryPos
) < nWHeight
/2 )
1884 SetTopEntry( nEntryPos
);
1887 void ImplListBoxWindow::SetLeftIndent( tools::Long n
)
1889 ScrollHorz( n
- mnLeft
);
1892 void ImplListBoxWindow::ScrollHorz( tools::Long n
)
1894 tools::Long nDiff
= 0;
1897 tools::Long nWidth
= GetOutputSizePixel().Width();
1898 if( ( mnMaxWidth
- mnLeft
+ n
) > nWidth
)
1905 tools::Long nAbs
= -n
;
1906 nDiff
= - std::min( mnLeft
, nAbs
);
1912 ImplClearLayoutData();
1913 mnLeft
= sal::static_int_cast
<sal_uInt16
>(mnLeft
+ nDiff
);
1915 ImplHideFocusRect();
1916 Scroll( -nDiff
, 0 );
1919 ImplShowFocusRect();
1920 maScrollHdl
.Call( this );
1924 void ImplListBoxWindow::SetSeparatorPos( sal_Int32 n
)
1926 maSeparators
.clear();
1928 if ( n
!= LISTBOX_ENTRY_NOTFOUND
)
1930 maSeparators
.insert( n
);
1934 sal_Int32
ImplListBoxWindow::GetSeparatorPos() const
1936 if (!maSeparators
.empty())
1937 return *(maSeparators
.begin());
1939 return LISTBOX_ENTRY_NOTFOUND
;
1942 bool ImplListBoxWindow::isSeparator( const sal_Int32
&n
) const
1944 return maSeparators
.find(n
) != maSeparators
.end();
1947 Size
ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines
) const
1949 // FIXME: ListBoxEntryFlags::MultiLine
1952 aSz
.setHeight(nMaxLines
* GetEntryHeightWithMargin());
1953 aSz
.setWidth( mnMaxWidth
+ 2*gnBorder
);
1957 tools::Rectangle
ImplListBoxWindow::GetBoundingRectangle( sal_Int32 nItem
) const
1959 const ImplEntryType
* pEntry
= maEntryList
.GetEntryPtr( nItem
);
1960 Size
aSz( GetSizePixel().Width(), pEntry
? pEntry
->getHeightWithMargin() : GetEntryHeightWithMargin() );
1961 tools::Long nY
= maEntryList
.GetAddedHeight( nItem
, GetTopEntry() ) + GetEntryList().GetMRUCount()*GetEntryHeightWithMargin();
1962 tools::Rectangle
aRect( Point( 0, nY
), aSz
);
1966 void ImplListBoxWindow::StateChanged( StateChangedType nType
)
1968 Control::StateChanged( nType
);
1970 if ( nType
== StateChangedType::Zoom
)
1972 ApplySettings(*GetOutDev());
1976 else if ( nType
== StateChangedType::UpdateMode
)
1978 if ( IsUpdateMode() && IsReallyVisible() )
1981 else if ( nType
== StateChangedType::ControlFont
)
1983 ApplySettings(*GetOutDev());
1987 else if ( nType
== StateChangedType::ControlForeground
)
1989 ApplySettings(*GetOutDev());
1992 else if ( nType
== StateChangedType::ControlBackground
)
1994 ApplySettings(*GetOutDev());
1997 else if( nType
== StateChangedType::Enable
)
2002 ImplClearLayoutData();
2005 void ImplListBoxWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
2007 Control::DataChanged( rDCEvt
);
2009 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2010 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2011 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2012 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2014 ImplClearLayoutData();
2015 ApplySettings(*GetOutDev());
2021 DrawTextFlags
ImplListBoxWindow::ImplGetTextStyle() const
2023 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2025 if (maEntryList
.HasImages())
2026 nTextStyle
|= DrawTextFlags::Left
;
2028 nTextStyle
|= DrawTextFlags::Center
;
2030 nTextStyle
|= DrawTextFlags::Right
;
2032 nTextStyle
|= DrawTextFlags::Left
;
2037 ImplListBox::ImplListBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
2038 Control( pParent
, nWinStyle
),
2039 maLBWindow(VclPtr
<ImplListBoxWindow
>::Create( this, nWinStyle
&(~WB_BORDER
) ))
2041 // for native widget rendering we must be able to detect this window type
2042 SetType( WindowType::LISTBOXWINDOW
);
2044 mpVScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_VSCROLL
| WB_DRAG
);
2045 mpHScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_HSCROLL
| WB_DRAG
);
2046 mpScrollBarBox
= VclPtr
<ScrollBarBox
>::Create( this );
2048 Link
<ScrollBar
*,void> aLink( LINK( this, ImplListBox
, ScrollBarHdl
) );
2049 mpVScrollBar
->SetScrollHdl( aLink
);
2050 mpHScrollBar
->SetScrollHdl( aLink
);
2054 mbAutoHScroll
= ( nWinStyle
& WB_AUTOHSCROLL
);
2055 mbEdgeBlending
= false;
2057 maLBWindow
->SetScrollHdl( LINK( this, ImplListBox
, LBWindowScrolled
) );
2058 maLBWindow
->SetMRUChangedHdl( LINK( this, ImplListBox
, MRUChanged
) );
2059 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2063 ImplListBox::~ImplListBox()
2068 void ImplListBox::dispose()
2070 mpHScrollBar
.disposeAndClear();
2071 mpVScrollBar
.disposeAndClear();
2072 mpScrollBarBox
.disposeAndClear();
2073 maLBWindow
.disposeAndClear();
2077 void ImplListBox::Clear()
2079 maLBWindow
->Clear();
2080 if ( GetEntryList().GetMRUCount() )
2082 maLBWindow
->GetEntryList().SetMRUCount( 0 );
2083 maLBWindow
->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND
);
2085 mpVScrollBar
->SetThumbPos( 0 );
2086 mpHScrollBar
->SetThumbPos( 0 );
2087 CompatStateChanged( StateChangedType::Data
);
2090 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
)
2092 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
);
2093 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2094 CompatStateChanged( StateChangedType::Data
);
2098 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
, const Image
& rImage
)
2100 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
, rImage
);
2101 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2102 CompatStateChanged( StateChangedType::Data
);
2106 void ImplListBox::RemoveEntry( sal_Int32 nPos
)
2108 maLBWindow
->RemoveEntry( nPos
);
2109 CompatStateChanged( StateChangedType::Data
);
2112 void ImplListBox::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
2114 maLBWindow
->SetEntryFlags( nPos
, nFlags
);
2117 void ImplListBox::SelectEntry( sal_Int32 nPos
, bool bSelect
)
2119 maLBWindow
->SelectEntry( nPos
, bSelect
);
2122 void ImplListBox::SetNoSelection()
2124 maLBWindow
->DeselectAll();
2127 void ImplListBox::GetFocus()
2130 maLBWindow
->GrabFocus();
2132 Control::GetFocus();
2135 void ImplListBox::Resize()
2138 ImplResizeControls();
2139 ImplCheckScrollBars();
2142 IMPL_LINK_NOARG(ImplListBox
, MRUChanged
, LinkParamNone
*, void)
2144 CompatStateChanged( StateChangedType::Data
);
2147 IMPL_LINK_NOARG(ImplListBox
, LBWindowScrolled
, ImplListBoxWindow
*, void)
2149 tools::Long nSet
= GetTopEntry();
2150 if( nSet
> mpVScrollBar
->GetRangeMax() )
2151 mpVScrollBar
->SetRangeMax( GetEntryList().GetEntryCount() );
2152 mpVScrollBar
->SetThumbPos( GetTopEntry() );
2154 mpHScrollBar
->SetThumbPos( GetLeftIndent() );
2156 maScrollHdl
.Call( this );
2159 IMPL_LINK( ImplListBox
, ScrollBarHdl
, ScrollBar
*, pSB
, void )
2161 sal_uInt16 nPos
= static_cast<sal_uInt16
>(pSB
->GetThumbPos());
2162 if( pSB
== mpVScrollBar
)
2163 SetTopEntry( nPos
);
2164 else if( pSB
== mpHScrollBar
)
2165 SetLeftIndent( nPos
);
2167 GetParent()->Invalidate( InvalidateFlags::Update
);
2170 void ImplListBox::ImplCheckScrollBars()
2172 bool bArrange
= false;
2174 Size aOutSz
= GetOutputSizePixel();
2175 sal_Int32 nEntries
= GetEntryList().GetEntryCount();
2176 sal_uInt16 nMaxVisEntries
= static_cast<sal_uInt16
>(aOutSz
.Height() / GetEntryHeightWithMargin());
2178 // vertical ScrollBar
2179 if( nEntries
> nMaxVisEntries
)
2185 // check of the scrolled-out region
2186 if( GetEntryList().GetSelectedEntryCount() == 1 &&
2187 GetEntryList().GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2188 ShowProminentEntry( GetEntryList().GetSelectedEntryPos( 0 ) );
2190 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2200 // horizontal ScrollBar
2203 tools::Long nWidth
= static_cast<sal_uInt16
>(aOutSz
.Width());
2205 nWidth
-= mpVScrollBar
->GetSizePixel().Width();
2207 tools::Long nMaxWidth
= GetMaxEntryWidth();
2208 if( nWidth
< nMaxWidth
)
2214 if ( !mbVScroll
) // maybe we do need one now
2216 nMaxVisEntries
= static_cast<sal_uInt16
>( ( aOutSz
.Height() - mpHScrollBar
->GetSizePixel().Height() ) / GetEntryHeightWithMargin() );
2217 if( nEntries
> nMaxVisEntries
)
2222 // check of the scrolled-out region
2223 if( GetEntryList().GetSelectedEntryCount() == 1 &&
2224 GetEntryList().GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2225 ShowProminentEntry( GetEntryList().GetSelectedEntryPos( 0 ) );
2227 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2231 // check of the scrolled-out region
2232 sal_uInt16 nMaxLI
= static_cast<sal_uInt16
>(nMaxWidth
- nWidth
);
2233 if ( nMaxLI
< GetLeftIndent() )
2234 SetLeftIndent( nMaxLI
);
2246 ImplResizeControls();
2248 ImplInitScrollBars();
2251 void ImplListBox::ImplInitScrollBars()
2253 Size aOutSz
= maLBWindow
->GetOutputSizePixel();
2257 sal_Int32 nEntries
= GetEntryList().GetEntryCount();
2258 sal_uInt16 nVisEntries
= static_cast<sal_uInt16
>(aOutSz
.Height() / GetEntryHeightWithMargin());
2259 mpVScrollBar
->SetRangeMax( nEntries
);
2260 mpVScrollBar
->SetVisibleSize( nVisEntries
);
2261 mpVScrollBar
->SetPageSize( nVisEntries
- 1 );
2266 mpHScrollBar
->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL
);
2267 mpHScrollBar
->SetVisibleSize( static_cast<sal_uInt16
>(aOutSz
.Width()) );
2268 mpHScrollBar
->SetLineSize( HORZ_SCROLL
);
2269 mpHScrollBar
->SetPageSize( aOutSz
.Width() - HORZ_SCROLL
);
2273 void ImplListBox::ImplResizeControls()
2275 // Here we only position the Controls; if the Scrollbars are to be
2276 // visible is already determined in ImplCheckScrollBars
2278 Size aOutSz
= GetOutputSizePixel();
2279 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2280 nSBWidth
= CalcZoom( nSBWidth
);
2282 Size
aInnerSz( aOutSz
);
2284 aInnerSz
.AdjustWidth( -nSBWidth
);
2286 aInnerSz
.AdjustHeight( -nSBWidth
);
2288 Point
aWinPos( 0, 0 );
2289 maLBWindow
->SetPosSizePixel( aWinPos
, aInnerSz
);
2292 if( mbVScroll
&& mbHScroll
)
2294 Point
aBoxPos( aInnerSz
.Width(), aInnerSz
.Height() );
2295 mpScrollBarBox
->SetPosSizePixel( aBoxPos
, Size( nSBWidth
, nSBWidth
) );
2296 mpScrollBarBox
->Show();
2300 mpScrollBarBox
->Hide();
2303 // vertical ScrollBar
2306 // Scrollbar on left or right side?
2307 Point
aVPos( aOutSz
.Width() - nSBWidth
, 0 );
2308 mpVScrollBar
->SetPosSizePixel( aVPos
, Size( nSBWidth
, aInnerSz
.Height() ) );
2309 mpVScrollBar
->Show();
2313 mpVScrollBar
->Hide();
2314 // #107254# Don't reset top entry after resize, but check for max top entry
2315 SetTopEntry( GetTopEntry() );
2318 // horizontal ScrollBar
2321 Point
aHPos( 0, aOutSz
.Height() - nSBWidth
);
2322 mpHScrollBar
->SetPosSizePixel( aHPos
, Size( aInnerSz
.Width(), nSBWidth
) );
2323 mpHScrollBar
->Show();
2327 mpHScrollBar
->Hide();
2332 void ImplListBox::StateChanged( StateChangedType nType
)
2334 if ( nType
== StateChangedType::InitShow
)
2336 ImplCheckScrollBars();
2338 else if ( ( nType
== StateChangedType::UpdateMode
) || ( nType
== StateChangedType::Data
) )
2340 bool bUpdate
= IsUpdateMode();
2341 maLBWindow
->SetUpdateMode( bUpdate
);
2342 if ( bUpdate
&& IsReallyVisible() )
2343 ImplCheckScrollBars();
2345 else if( nType
== StateChangedType::Enable
)
2347 mpHScrollBar
->Enable( IsEnabled() );
2348 mpVScrollBar
->Enable( IsEnabled() );
2349 mpScrollBarBox
->Enable( IsEnabled() );
2350 maLBWindow
->Enable( IsEnabled() );
2354 else if ( nType
== StateChangedType::Zoom
)
2356 maLBWindow
->SetZoom( GetZoom() );
2359 else if ( nType
== StateChangedType::ControlFont
)
2361 maLBWindow
->SetControlFont( GetControlFont() );
2363 else if ( nType
== StateChangedType::ControlForeground
)
2365 maLBWindow
->SetControlForeground( GetControlForeground() );
2367 else if ( nType
== StateChangedType::ControlBackground
)
2369 maLBWindow
->SetControlBackground( GetControlBackground() );
2371 else if( nType
== StateChangedType::Mirroring
)
2373 maLBWindow
->EnableRTL( IsRTLEnabled() );
2374 mpHScrollBar
->EnableRTL( IsRTLEnabled() );
2375 mpVScrollBar
->EnableRTL( IsRTLEnabled() );
2376 ImplResizeControls();
2379 Control::StateChanged( nType
);
2382 bool ImplListBox::EventNotify( NotifyEvent
& rNEvt
)
2385 if ( rNEvt
.GetType() == NotifyEventType::COMMAND
)
2387 const CommandEvent
& rCEvt
= *rNEvt
.GetCommandEvent();
2388 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2390 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2391 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2393 bDone
= HandleScrollCommand( rCEvt
, mpHScrollBar
, mpVScrollBar
);
2396 else if (rCEvt
.GetCommand() == CommandEventId::GesturePan
)
2398 bDone
= HandleScrollCommand(rCEvt
, mpHScrollBar
, mpVScrollBar
);
2402 return bDone
|| Window::EventNotify( rNEvt
);
2405 const Wallpaper
& ImplListBox::GetDisplayBackground() const
2407 return maLBWindow
->GetDisplayBackground();
2410 bool ImplListBox::HandleWheelAsCursorTravel(const CommandEvent
& rCEvt
, Control
& rControl
)
2413 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2415 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2416 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2418 if (!rControl
.HasChildPathFocus())
2419 rControl
.GrabFocus();
2420 sal_uInt16 nKey
= ( pData
->GetDelta() < 0 ) ? KEY_DOWN
: KEY_UP
;
2421 KeyEvent
aKeyEvent( 0, vcl::KeyCode( nKey
) );
2422 bDone
= ProcessKeyInput( aKeyEvent
);
2428 void ImplListBox::SetMRUEntries( std::u16string_view rEntries
, sal_Unicode cSep
)
2430 bool bChanges
= GetEntryList().GetMRUCount() != 0;
2432 // Remove old MRU entries
2433 for ( sal_Int32 n
= GetEntryList().GetMRUCount();n
; )
2434 maLBWindow
->RemoveEntry( --n
);
2436 sal_Int32 nMRUCount
= 0;
2437 sal_Int32 nIndex
= 0;
2440 OUString
aEntry( o3tl::getToken(rEntries
, 0, cSep
, nIndex
) );
2441 // Accept only existing entries
2442 if ( GetEntryList().FindEntry( aEntry
) != LISTBOX_ENTRY_NOTFOUND
)
2444 ImplEntryType
* pNewEntry
= new ImplEntryType( aEntry
);
2445 maLBWindow
->InsertEntry(nMRUCount
++, pNewEntry
, false);
2449 while ( nIndex
>= 0 );
2453 maLBWindow
->GetEntryList().SetMRUCount( nMRUCount
);
2454 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
2455 CompatStateChanged( StateChangedType::Data
);
2459 OUString
ImplListBox::GetMRUEntries( sal_Unicode cSep
) const
2461 OUStringBuffer aEntries
;
2462 for ( sal_Int32 n
= 0; n
< GetEntryList().GetMRUCount(); n
++ )
2464 aEntries
.append(GetEntryList().GetEntryText( n
));
2465 if( n
< ( GetEntryList().GetMRUCount() - 1 ) )
2466 aEntries
.append(cSep
);
2468 return aEntries
.makeStringAndClear();
2471 void ImplListBox::SetEdgeBlending(bool bNew
)
2473 if(mbEdgeBlending
!= bNew
)
2475 mbEdgeBlending
= bNew
;
2476 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2480 void ImplListBox::SetHighlightColor(const Color
& rColor
)
2482 AllSettings
aSettings(GetSettings());
2483 StyleSettings
aStyle(aSettings
.GetStyleSettings());
2484 aStyle
.SetHighlightColor(rColor
);
2485 aSettings
.SetStyleSettings(aStyle
);
2486 SetSettings(aSettings
);
2488 AllSettings
aSettingsLB(maLBWindow
->GetSettings());
2489 StyleSettings
aStyleLB(aSettingsLB
.GetStyleSettings());
2490 aStyleLB
.SetListBoxWindowHighlightColor(rColor
);
2491 aSettingsLB
.SetStyleSettings(aStyleLB
);
2492 maLBWindow
->SetSettings(aSettingsLB
);
2495 void ImplListBox::SetHighlightTextColor(const Color
& rColor
)
2497 AllSettings
aSettings(GetSettings());
2498 StyleSettings
aStyle(aSettings
.GetStyleSettings());
2499 aStyle
.SetHighlightTextColor(rColor
);
2500 aSettings
.SetStyleSettings(aStyle
);
2501 SetSettings(aSettings
);
2503 AllSettings
aSettingsLB(maLBWindow
->GetSettings());
2504 StyleSettings
aStyleLB(aSettingsLB
.GetStyleSettings());
2505 aStyleLB
.SetListBoxWindowHighlightTextColor(rColor
);
2506 aSettingsLB
.SetStyleSettings(aStyleLB
);
2507 maLBWindow
->SetSettings(aSettingsLB
);
2510 ImplWin::ImplWin( vcl::Window
* pParent
, WinBits nWinStyle
) :
2511 Control ( pParent
, nWinStyle
)
2513 if ( IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2514 && ! IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
2517 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2519 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
2521 mbEdgeBlending
= false;
2522 mnItemPos
= LISTBOX_ENTRY_NOTFOUND
;
2525 void ImplWin::MouseButtonDown( const MouseEvent
& )
2529 maMBDownHdl
.Call(this);
2533 void ImplWin::FillLayoutData() const
2535 mxLayoutData
.emplace();
2536 ImplWin
* pThis
= const_cast<ImplWin
*>(this);
2537 pThis
->ImplDraw(*pThis
->GetOutDev(), true);
2540 void ImplWin::ImplDraw(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2542 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2546 bool bNativeOK
= false;
2547 bool bHasFocus
= HasFocus();
2548 bool bIsEnabled
= IsEnabled();
2550 ControlState nState
= ControlState::ENABLED
;
2551 if (rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2552 && rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::HasBackgroundTexture
) )
2554 // Repaint the (focused) area similarly to
2555 // ImplSmallBorderWindowView::DrawWindow() in
2556 // vcl/source/window/brdwin.cxx
2557 vcl::Window
*pWin
= GetParent();
2559 ImplControlValue aControlValue
;
2560 bIsEnabled
&= pWin
->IsEnabled();
2562 nState
&= ~ControlState::ENABLED
;
2563 bHasFocus
|= pWin
->HasFocus();
2565 nState
|= ControlState::FOCUSED
;
2567 // The listbox is painted over the entire control including the
2568 // border, but ImplWin does not contain the border => correction
2570 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2571 pWin
->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2572 Point
aPoint( -nLeft
, -nTop
);
2573 tools::Rectangle
aCtrlRegion( aPoint
- GetPosPixel(), pWin
->GetSizePixel() );
2575 bool bMouseOver
= pWin
->IsMouseOver();
2578 vcl::Window
*pChild
= pWin
->GetWindow( GetWindowType::FirstChild
);
2581 bMouseOver
= pChild
->IsMouseOver();
2584 pChild
= pChild
->GetWindow( GetWindowType::Next
);
2588 nState
|= ControlState::ROLLOVER
;
2590 Color aBackgroundColor
= COL_AUTO
;
2591 if (IsControlBackground())
2592 aBackgroundColor
= GetControlBackground();
2594 // if parent has no border, then nobody has drawn the background
2595 // since no border window exists. so draw it here.
2596 WinBits nParentStyle
= pWin
->GetStyle();
2597 if( ! (nParentStyle
& WB_BORDER
) || (nParentStyle
& WB_NOBORDER
) )
2599 tools::Rectangle
aParentRect( Point( 0, 0 ), pWin
->GetSizePixel() );
2600 pWin
->GetOutDev()->DrawNativeControl( ControlType::Listbox
, ControlPart::Entire
, aParentRect
,
2601 nState
, aControlValue
, OUString(), aBackgroundColor
);
2604 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Listbox
, ControlPart::Entire
, aCtrlRegion
,
2605 nState
, aControlValue
, OUString(), aBackgroundColor
);
2610 if (bHasFocus
&& !ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2612 if ( !ImplGetSVData()->maNWFData
.mbNoFocusRects
)
2614 rRenderContext
.SetFillColor( rStyleSettings
.GetHighlightColor() );
2615 rRenderContext
.SetTextColor( rStyleSettings
.GetHighlightTextColor() );
2619 rRenderContext
.SetLineColor();
2620 rRenderContext
.SetFillColor();
2621 rRenderContext
.SetTextColor( rStyleSettings
.GetFieldTextColor() );
2623 rRenderContext
.DrawRect( maFocusRect
);
2628 if (IsControlForeground())
2629 aColor
= GetControlForeground();
2630 else if (ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2632 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2633 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
2635 aColor
= rStyleSettings
.GetButtonTextColor();
2639 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2640 aColor
= rStyleSettings
.GetFieldRolloverTextColor();
2642 aColor
= rStyleSettings
.GetFieldTextColor();
2644 rRenderContext
.SetTextColor(aColor
);
2646 rRenderContext
.Erase(maFocusRect
);
2651 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
2653 rRenderContext
.Erase(maFocusRect
);
2657 DrawEntry(rRenderContext
, bLayout
);
2660 void ImplWin::ApplySettings(vcl::RenderContext
& rRenderContext
)
2662 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2664 ApplyControlFont(rRenderContext
, rStyleSettings
.GetFieldFont());
2665 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetFieldTextColor());
2667 if (IsControlBackground())
2668 rRenderContext
.SetBackground(GetControlBackground());
2670 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
2673 void ImplWin::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
2675 ImplDraw(rRenderContext
);
2678 void ImplWin::DrawEntry(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2680 tools::Long nBorder
= 1;
2681 Size
aOutSz(GetOutputSizePixel());
2683 bool bImage
= !!maImage
;
2684 if (bImage
&& !bLayout
)
2686 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
2687 Size aImgSz
= maImage
.GetSizePixel();
2688 Point
aPtImg( nBorder
, ( ( aOutSz
.Height() - aImgSz
.Height() ) / 2 ) );
2689 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2691 // check for HC mode
2692 Image
*pImage
= &maImage
;
2696 rRenderContext
.DrawImage( aPtImg
, *pImage
, nStyle
);
2700 aImgSz
.setWidth( CalcZoom( aImgSz
.Width() ) );
2701 aImgSz
.setHeight( CalcZoom( aImgSz
.Height() ) );
2702 rRenderContext
.DrawImage( aPtImg
, aImgSz
, *pImage
, nStyle
);
2705 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
2707 if(nEdgeBlendingPercent
)
2709 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
2710 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
2711 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
2712 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
2714 if(!aBlendFrame
.IsEmpty())
2716 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
2721 if( !maString
.isEmpty() )
2723 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2725 if ( bImage
&& !bLayout
)
2726 nTextStyle
|= DrawTextFlags::Left
;
2727 else if ( GetStyle() & WB_CENTER
)
2728 nTextStyle
|= DrawTextFlags::Center
;
2729 else if ( GetStyle() & WB_RIGHT
)
2730 nTextStyle
|= DrawTextFlags::Right
;
2732 nTextStyle
|= DrawTextFlags::Left
;
2734 tools::Rectangle
aTextRect( Point( nBorder
, 0 ), Size( aOutSz
.Width()-2*nBorder
, aOutSz
.Height() ) );
2738 aTextRect
.AdjustLeft(maImage
.GetSizePixel().Width() + IMG_TXT_DISTANCE
);
2741 std::vector
< tools::Rectangle
>* pVector
= bLayout
? &mxLayoutData
->m_aUnicodeBoundRects
: nullptr;
2742 OUString
* pDisplayText
= bLayout
? &mxLayoutData
->m_aDisplayText
: nullptr;
2743 rRenderContext
.DrawText( aTextRect
, maString
, nTextStyle
, pVector
, pDisplayText
);
2746 if( HasFocus() && !bLayout
)
2747 ShowFocus( maFocusRect
);
2750 void ImplWin::Resize()
2753 maFocusRect
.SetSize( GetOutputSizePixel() );
2757 void ImplWin::GetFocus()
2759 ShowFocus( maFocusRect
);
2760 if (IsNativeWidgetEnabled() &&
2761 IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
))
2763 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2770 Control::GetFocus();
2773 void ImplWin::LoseFocus()
2776 if (IsNativeWidgetEnabled() &&
2777 IsNativeControlSupported( ControlType::Listbox
, ControlPart::Entire
))
2779 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2786 Control::LoseFocus();
2789 void ImplWin::ShowFocus(const tools::Rectangle
& rRect
)
2791 if (IsNativeControlSupported(ControlType::Listbox
, ControlPart::Focus
))
2793 ImplControlValue aControlValue
;
2795 vcl::Window
*pWin
= GetParent();
2796 tools::Rectangle
aParentRect(Point(0, 0), pWin
->GetSizePixel());
2797 pWin
->GetOutDev()->DrawNativeControl(ControlType::Listbox
, ControlPart::Focus
, aParentRect
,
2798 ControlState::FOCUSED
, aControlValue
, OUString());
2800 Control::ShowFocus(rRect
);
2803 ImplBtn::ImplBtn( vcl::Window
* pParent
, WinBits nWinStyle
) :
2804 PushButton( pParent
, nWinStyle
)
2808 void ImplBtn::MouseButtonDown( const MouseEvent
& )
2811 maMBDownHdl
.Call(this);
2814 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( vcl::Window
* pParent
) :
2815 FloatingWindow( pParent
, WB_BORDER
| WB_SYSTEMWINDOW
| WB_NOSHADOW
) // no drop shadow for list boxes
2817 // for native widget rendering we must be able to detect this window type
2818 SetType( WindowType::LISTBOXWINDOW
);
2822 mbAutoWidth
= false;
2824 mnPopupModeStartSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
2826 vcl::Window
* pBorderWindow
= ImplGetBorderWindow();
2829 SetAccessibleRole(accessibility::AccessibleRole::PANEL
);
2830 pBorderWindow
->SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2834 SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2839 ImplListBoxFloatingWindow::~ImplListBoxFloatingWindow()
2844 void ImplListBoxFloatingWindow::dispose()
2847 FloatingWindow::dispose();
2851 bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent
& rNEvt
)
2853 if( rNEvt
.GetType() == NotifyEventType::LOSEFOCUS
)
2855 if( !GetParent()->HasChildPathFocus( true ) )
2859 return FloatingWindow::PreNotify( rNEvt
);
2862 void ImplListBoxFloatingWindow::setPosSizePixel( tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
, PosSizeFlags nFlags
)
2864 FloatingWindow::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
2866 // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2867 // after a call to Resize(), we adjust its position if necessary
2868 if ( IsReallyVisible() && ( nFlags
& PosSizeFlags::Height
) )
2870 Point aPos
= GetParent()->GetPosPixel();
2871 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2873 if ( nFlags
& PosSizeFlags::X
)
2876 if ( nFlags
& PosSizeFlags::Y
)
2880 SetPosPixel( ImplCalcPos( this, tools::Rectangle( aPos
, GetParent()->GetSizePixel() ), FloatWinPopupFlags::Down
, nIndex
) );
2883 // if( !IsReallyVisible() )
2885 // The ImplListBox does not get a Resize() as not visible.
2886 // But the windows must get a Resize(), so that the number of
2887 // visible entries is correct for PgUp/PgDown.
2888 // The number also cannot be calculated by List/Combobox, as for
2889 // this the presence of the vertical Scrollbar has to be known.
2890 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
2891 static_cast<vcl::Window
*>(mpImplLB
)->Resize();
2892 static_cast<vcl::Window
*>(mpImplLB
->GetMainWindow())->Resize();
2896 void ImplListBoxFloatingWindow::Resize()
2898 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
2899 FloatingWindow::Resize();
2902 Size
ImplListBoxFloatingWindow::CalcFloatSize() const
2904 Size
aFloatSz( maPrefSz
);
2906 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2907 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2909 sal_Int32 nLines
= mpImplLB
->GetEntryList().GetEntryCount();
2910 if ( mnDDLineCount
&& ( nLines
> mnDDLineCount
) )
2911 nLines
= mnDDLineCount
;
2913 Size aSz
= mpImplLB
->CalcSize( nLines
);
2914 tools::Long nMaxHeight
= aSz
.Height() + nTop
+ nBottom
;
2916 if ( mnDDLineCount
)
2917 aFloatSz
.setHeight( nMaxHeight
);
2921 // AutoSize first only for width...
2923 aFloatSz
.setWidth( aSz
.Width() + nLeft
+ nRight
);
2924 aFloatSz
.AdjustWidth(nRight
); // adding some space looks better...
2926 if ( ( aFloatSz
.Height() < nMaxHeight
) || ( mnDDLineCount
&& ( mnDDLineCount
< mpImplLB
->GetEntryList().GetEntryCount() ) ) )
2928 // then we also need the vertical Scrollbar
2929 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2930 aFloatSz
.AdjustWidth(nSBWidth
);
2933 tools::Long nDesktopWidth
= GetDesktopRectPixel().getOpenWidth();
2934 if (aFloatSz
.Width() > nDesktopWidth
)
2935 // Don't exceed the desktop width.
2936 aFloatSz
.setWidth( nDesktopWidth
);
2939 if ( aFloatSz
.Height() > nMaxHeight
)
2940 aFloatSz
.setHeight( nMaxHeight
);
2942 // Minimal height, in case height is not set to Float height.
2943 // The parent of FloatWin must be DropDown-Combo/Listbox.
2944 Size aParentSz
= GetParent()->GetSizePixel();
2945 if( (!mnDDLineCount
|| !nLines
) && ( aFloatSz
.Height() < aParentSz
.Height() ) )
2946 aFloatSz
.setHeight( aParentSz
.Height() );
2948 // do not get narrower than the parent...
2949 if( aFloatSz
.Width() < aParentSz
.Width() )
2950 aFloatSz
.setWidth( aParentSz
.Width() );
2952 // align height to entries...
2953 tools::Long nInnerHeight
= aFloatSz
.Height() - nTop
- nBottom
;
2954 tools::Long nEntryHeight
= mpImplLB
->GetEntryHeightWithMargin();
2955 if ( nInnerHeight
% nEntryHeight
)
2957 nInnerHeight
/= nEntryHeight
;
2959 nInnerHeight
*= nEntryHeight
;
2960 aFloatSz
.setHeight( nInnerHeight
+ nTop
+ nBottom
);
2963 if (aFloatSz
.Width() < aSz
.Width())
2965 // The max width of list box entries exceeds the window width.
2966 // Account for the scroll bar height.
2967 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2968 aFloatSz
.AdjustHeight(nSBWidth
);
2974 void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking
)
2976 if( IsInPopupMode() )
2979 Size aFloatSz
= CalcFloatSize();
2981 SetSizePixel( aFloatSz
);
2982 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
2984 sal_Int32 nPos
= mpImplLB
->GetEntryList().GetSelectedEntryPos( 0 );
2985 mnPopupModeStartSaveSelection
= nPos
;
2987 Size aSz
= GetParent()->GetSizePixel();
2988 Point aPos
= GetParent()->GetPosPixel();
2989 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2990 // FIXME: this ugly hack is for Mac/Aqua
2991 // should be replaced by a real mechanism to place the float rectangle
2992 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2993 GetParent()->IsNativeWidgetEnabled() )
2995 const sal_Int32 nLeft
= 4, nTop
= 4, nRight
= 4, nBottom
= 4;
2996 aPos
.AdjustX(nLeft
);
2997 aPos
.AdjustY(nTop
);
2998 aSz
.AdjustWidth( -(nLeft
+ nRight
) );
2999 aSz
.AdjustHeight( -(nTop
+ nBottom
) );
3001 tools::Rectangle
aRect( aPos
, aSz
);
3003 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3004 // where the document is unmirrored
3005 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3006 vcl::Window
*pGrandparent
= GetParent()->GetParent();
3007 const OutputDevice
*pGrandparentOutDev
= pGrandparent
->GetOutDev();
3009 if( pGrandparent
->GetOutDev()->ImplIsAntiparallel() )
3010 pGrandparentOutDev
->ReMirror( aRect
);
3012 // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795
3013 StartPopupMode( aRect
, FloatWinPopupFlags::Down
| FloatWinPopupFlags::NoHorzPlacement
| FloatWinPopupFlags::AllMouseButtonClose
);
3015 if( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
3016 mpImplLB
->ShowProminentEntry( nPos
);
3018 if( bStartTracking
)
3019 mpImplLB
->GetMainWindow()->EnableMouseMoveSelect( true );
3021 if ( mpImplLB
->GetMainWindow()->IsGrabFocusAllowed() )
3022 mpImplLB
->GetMainWindow()->GrabFocus();
3024 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
3028 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */