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/scrbar.hxx>
26 #include <vcl/toolkit/lstbox.hxx>
27 #include <vcl/i18nhelp.hxx>
28 #include <vcl/naturalsort.hxx>
30 #include <listbox.hxx>
31 #include <controldata.hxx>
35 #include <com/sun/star/accessibility/AccessibleRole.hpp>
37 #include <rtl/instance.hxx>
38 #include <sal/log.hxx>
39 #include <o3tl/safeint.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::SelectEntry( sal_Int32 nPos
, bool bSelect
)
86 if (0 <= nPos
&& o3tl::make_unsigned(nPos
) < maEntries
.size())
88 std::vector
<std::unique_ptr
<ImplEntryType
> >::iterator iter
= maEntries
.begin()+nPos
;
90 if ( ( (*iter
)->mbIsSelected
!= bSelect
) &&
91 ( ( (*iter
)->mnFlags
& ListBoxEntryFlags::DisableSelection
) == ListBoxEntryFlags::NONE
) )
93 (*iter
)->mbIsSelected
= bSelect
;
94 if ( mbCallSelectionChangedHdl
)
95 maSelectionChangedHdl
.Call( nPos
);
103 : public rtl::StaticWithInit
< comphelper::string::NaturalStringSorter
, theSorter
>
105 comphelper::string::NaturalStringSorter
operator () ()
107 return comphelper::string::NaturalStringSorter(
108 ::comphelper::getProcessComponentContext(),
109 Application::GetSettings().GetLanguageTag().getLocale());
116 sal_Int32
NaturalSortCompare(const OUString
&rA
, const OUString
&rB
)
118 const comphelper::string::NaturalStringSorter
&rSorter
= theSorter::get();
119 return rSorter
.compare(rA
, rB
);
123 sal_Int32
ImplEntryList::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
, bool bSort
)
126 assert(maEntries
.size() < LISTBOX_MAX_ENTRIES
);
128 if ( !!pNewEntry
->maImage
)
131 sal_Int32 insPos
= 0;
132 const sal_Int32 nEntriesSize
= static_cast<sal_Int32
>(maEntries
.size());
134 if ( !bSort
|| maEntries
.empty())
136 if (0 <= nPos
&& nPos
< nEntriesSize
)
139 maEntries
.insert( maEntries
.begin() + nPos
, std::unique_ptr
<ImplEntryType
>(pNewEntry
) );
143 insPos
= nEntriesSize
;
144 maEntries
.push_back(std::unique_ptr
<ImplEntryType
>(pNewEntry
));
149 const comphelper::string::NaturalStringSorter
&rSorter
= theSorter::get();
151 const OUString
& rStr
= pNewEntry
->maStr
;
153 ImplEntryType
* pTemp
= GetEntry( nEntriesSize
-1 );
157 sal_Int32 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
159 // fast insert for sorted data
162 insPos
= nEntriesSize
;
163 maEntries
.push_back(std::unique_ptr
<ImplEntryType
>(pNewEntry
));
167 pTemp
= GetEntry( mnMRUCount
);
169 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
173 maEntries
.insert(maEntries
.begin(), std::unique_ptr
<ImplEntryType
>(pNewEntry
));
177 sal_uLong nLow
= mnMRUCount
;
178 sal_uLong nHigh
= maEntries
.size()-1;
184 nMid
= static_cast<sal_Int32
>((nLow
+ nHigh
) / 2);
185 pTemp
= GetEntry( nMid
);
187 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
199 while ( nLow
<= nHigh
);
205 maEntries
.insert(maEntries
.begin()+nMid
, std::unique_ptr
<ImplEntryType
>(pNewEntry
));
209 catch (uno::RuntimeException
& )
211 // XXX this is arguable, if the exception occurred because pNewEntry is
212 // garbage you wouldn't insert it. If the exception occurred because the
213 // Collator implementation is garbage then give the user a chance to see
216 maEntries
.insert(maEntries
.begin(), std::unique_ptr
<ImplEntryType
>(pNewEntry
));
224 void ImplEntryList::RemoveEntry( sal_Int32 nPos
)
226 if (0 <= nPos
&& o3tl::make_unsigned(nPos
) < maEntries
.size())
228 std::vector
<std::unique_ptr
<ImplEntryType
> >::iterator iter
= maEntries
.begin()+ nPos
;
230 if ( !!(*iter
)->maImage
)
233 maEntries
.erase(iter
);
237 sal_Int32
ImplEntryList::FindEntry( const OUString
& rString
, bool bSearchMRUArea
) const
239 const sal_Int32 nEntries
= static_cast<sal_Int32
>(maEntries
.size());
240 for ( sal_Int32 n
= bSearchMRUArea
? 0 : GetMRUCount(); n
< nEntries
; n
++ )
242 OUString
aComp( vcl::I18nHelper::filterFormattingChars( maEntries
[n
]->maStr
) );
243 if ( aComp
== rString
)
246 return LISTBOX_ENTRY_NOTFOUND
;
249 sal_Int32
ImplEntryList::FindMatchingEntry( const OUString
& rStr
, sal_Int32 nStart
, bool bLazy
) const
251 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
252 sal_Int32 nEntryCount
= GetEntryCount();
254 const vcl::I18nHelper
& rI18nHelper
= mpWindow
->GetSettings().GetLocaleI18nHelper();
255 for ( sal_Int32 n
= nStart
; n
< nEntryCount
; )
257 ImplEntryType
* pImplEntry
= GetEntry( n
);
261 bMatch
= rI18nHelper
.MatchString( rStr
, pImplEntry
->maStr
);
265 bMatch
= pImplEntry
->maStr
.startsWith(rStr
);
279 tools::Long
ImplEntryList::GetAddedHeight( sal_Int32 i_nEndIndex
, sal_Int32 i_nBeginIndex
) const
281 tools::Long nHeight
= 0;
282 sal_Int32 nStart
= std::min(i_nEndIndex
, i_nBeginIndex
);
283 sal_Int32 nStop
= std::max(i_nEndIndex
, i_nBeginIndex
);
284 sal_Int32 nEntryCount
= GetEntryCount();
285 if( 0 <= nStop
&& nStop
!= LISTBOX_ENTRY_NOTFOUND
&& nEntryCount
!= 0 )
288 if( nStop
> nEntryCount
-1 )
289 nStop
= nEntryCount
-1;
292 else if( nStart
> nEntryCount
-1 )
293 nStart
= nEntryCount
-1;
295 sal_Int32 nIndex
= nStart
;
296 while( nIndex
!= LISTBOX_ENTRY_NOTFOUND
&& nIndex
< nStop
)
298 tools::Long nPosHeight
= GetEntryPtr( nIndex
)->getHeightWithMargin();
299 if (nHeight
> ::std::numeric_limits
<tools::Long
>::max() - nPosHeight
)
301 SAL_WARN( "vcl", "ImplEntryList::GetAddedHeight: truncated");
304 nHeight
+= nPosHeight
;
310 return i_nEndIndex
> i_nBeginIndex
? nHeight
: -nHeight
;
313 tools::Long
ImplEntryList::GetEntryHeight( sal_Int32 nPos
) const
315 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
316 return pImplEntry
? pImplEntry
->getHeightWithMargin() : 0;
319 OUString
ImplEntryList::GetEntryText( sal_Int32 nPos
) const
322 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
324 aEntryText
= pImplEntry
->maStr
;
328 bool ImplEntryList::HasEntryImage( sal_Int32 nPos
) const
331 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
333 bImage
= !!pImplEntry
->maImage
;
337 Image
ImplEntryList::GetEntryImage( sal_Int32 nPos
) const
340 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
342 aImage
= pImplEntry
->maImage
;
346 void ImplEntryList::SetEntryData( sal_Int32 nPos
, void* pNewData
)
348 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
350 pImplEntry
->mpUserData
= pNewData
;
353 void* ImplEntryList::GetEntryData( sal_Int32 nPos
) const
355 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
356 return pImplEntry
? pImplEntry
->mpUserData
: nullptr;
359 void ImplEntryList::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
361 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
363 pImplEntry
->mnFlags
= nFlags
;
366 sal_Int32
ImplEntryList::GetSelectedEntryCount() const
368 sal_Int32 nSelCount
= 0;
369 for ( sal_Int32 n
= GetEntryCount(); n
; )
371 ImplEntryType
* pImplEntry
= GetEntry( --n
);
372 if ( pImplEntry
->mbIsSelected
)
378 OUString
ImplEntryList::GetSelectedEntry( sal_Int32 nIndex
) const
380 return GetEntryText( GetSelectedEntryPos( nIndex
) );
383 sal_Int32
ImplEntryList::GetSelectedEntryPos( sal_Int32 nIndex
) const
385 sal_Int32 nSelEntryPos
= LISTBOX_ENTRY_NOTFOUND
;
387 sal_Int32 nEntryCount
= GetEntryCount();
389 for ( sal_Int32 n
= 0; n
< nEntryCount
; n
++ )
391 ImplEntryType
* pImplEntry
= GetEntry( n
);
392 if ( pImplEntry
->mbIsSelected
)
394 if ( nSel
== nIndex
)
406 bool ImplEntryList::IsEntryPosSelected( sal_Int32 nIndex
) const
408 ImplEntryType
* pImplEntry
= GetEntry( nIndex
);
409 return pImplEntry
&& pImplEntry
->mbIsSelected
;
412 bool ImplEntryList::IsEntrySelectable( sal_Int32 nPos
) const
414 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
415 return pImplEntry
== nullptr || ((pImplEntry
->mnFlags
& ListBoxEntryFlags::DisableSelection
) == ListBoxEntryFlags::NONE
);
418 sal_Int32
ImplEntryList::FindFirstSelectable( sal_Int32 nPos
, bool bForward
/* = true */ )
420 if( IsEntrySelectable( nPos
) )
425 for( nPos
= nPos
+ 1; nPos
< GetEntryCount(); nPos
++ )
427 if( IsEntrySelectable( nPos
) )
436 if( IsEntrySelectable( nPos
) )
441 return LISTBOX_ENTRY_NOTFOUND
;
444 ImplListBoxWindow::ImplListBoxWindow( vcl::Window
* pParent
, WinBits nWinStyle
) :
445 Control( pParent
, 0 ),
446 maQuickSelectionEngine( *this )
448 mpEntryList
.reset(new ImplEntryList( this ));
452 mnSelectModifier
= 0;
453 mnUserDrawEntry
= LISTBOX_ENTRY_NOTFOUND
;
455 mbTravelSelect
= false;
456 mbTrackingSelect
= false;
457 mbSelectionChanged
= false;
458 mbMouseMoveSelect
= false;
461 mbUserDrawEnabled
= false;
462 mbInUserDraw
= false;
464 mbHasFocusRect
= false;
465 mbRight
= ( nWinStyle
& WB_RIGHT
);
466 mbCenter
= ( nWinStyle
& WB_CENTER
);
467 mbSimpleMode
= ( nWinStyle
& WB_SIMPLEMODE
);
468 mbSort
= ( nWinStyle
& WB_SORT
);
469 mbIsDropdown
= ( nWinStyle
& WB_DROPDOWN
);
470 mbEdgeBlending
= false;
472 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
473 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
477 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
479 ApplySettings(*this);
483 ImplListBoxWindow::~ImplListBoxWindow()
488 void ImplListBoxWindow::dispose()
494 void ImplListBoxWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
496 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
498 ApplyControlFont(rRenderContext
, rStyleSettings
.GetFieldFont());
499 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetFieldTextColor());
501 if (IsControlBackground())
502 rRenderContext
.SetBackground(GetControlBackground());
504 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
507 void ImplListBoxWindow::ImplCalcMetrics()
515 mnTextHeight
= static_cast<sal_uInt16
>(GetTextHeight());
516 mnMaxTxtHeight
= mnTextHeight
+ gnBorder
;
517 mnMaxHeight
= mnMaxTxtHeight
;
519 if ( maUserItemSize
.Height() > mnMaxHeight
)
520 mnMaxHeight
= static_cast<sal_uInt16
>(maUserItemSize
.Height());
521 if ( maUserItemSize
.Width() > mnMaxWidth
)
522 mnMaxWidth
= static_cast<sal_uInt16
>(maUserItemSize
.Width());
524 for ( sal_Int32 n
= mpEntryList
->GetEntryCount(); n
; )
526 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( --n
);
527 ImplUpdateEntryMetrics( *pEntry
);
530 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
532 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryPtr( mnCurrentPos
)->getHeightWithMargin() );
533 maFocusRect
.SetSize( aSz
);
537 void ImplListBoxWindow::Clear()
539 mpEntryList
->Clear();
541 mnMaxHeight
= mnMaxTxtHeight
;
549 ImplClearLayoutData();
551 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
552 maQuickSelectionEngine
.Reset();
557 void ImplListBoxWindow::SetUserItemSize( const Size
& rSz
)
559 ImplClearLayoutData();
560 maUserItemSize
= rSz
;
566 struct ImplEntryMetrics
570 tools::Long nEntryWidth
;
571 tools::Long nEntryHeight
;
572 tools::Long nTextWidth
;
573 tools::Long nImgWidth
;
574 tools::Long nImgHeight
;
579 tools::Long
ImplEntryType::getHeightWithMargin() const
581 return mnHeight
+ ImplGetSVData()->maNWFData
.mnListBoxEntryMargin
;
584 SalLayoutGlyphs
* ImplEntryType::GetTextGlyphs(const OutputDevice
* pOutputDevice
)
586 if (maStrGlyphs
.IsValid())
587 // Use pre-calculated result.
590 std::unique_ptr
<SalLayout
> pLayout
= pOutputDevice
->ImplLayout(
591 maStr
, 0, maStr
.getLength(), Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly
);
595 const SalLayoutGlyphs
* pGlyphs
= pLayout
->GetGlyphs();
599 // Remember the calculation result.
600 maStrGlyphs
= *pGlyphs
;
605 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType
& rEntry
)
607 ImplEntryMetrics aMetrics
;
608 aMetrics
.bText
= !rEntry
.maStr
.isEmpty();
609 aMetrics
.bImage
= !!rEntry
.maImage
;
610 aMetrics
.nEntryWidth
= 0;
611 aMetrics
.nEntryHeight
= 0;
612 aMetrics
.nTextWidth
= 0;
613 aMetrics
.nImgWidth
= 0;
614 aMetrics
.nImgHeight
= 0;
616 if ( aMetrics
.bText
)
618 if( rEntry
.mnFlags
& ListBoxEntryFlags::MultiLine
)
621 Size
aCurSize( PixelToLogic( GetSizePixel() ) );
622 // set the current size to a large number
623 // GetTextRect should shrink it to the actual size
624 aCurSize
.setHeight( 0x7fffff );
625 tools::Rectangle
aTextRect( Point( 0, 0 ), aCurSize
);
626 aTextRect
= GetTextRect( aTextRect
, rEntry
.maStr
, DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
);
627 aMetrics
.nTextWidth
= aTextRect
.GetWidth();
628 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
629 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
630 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
631 aMetrics
.nEntryHeight
= aTextRect
.GetHeight() + gnBorder
;
635 // normal single line case
636 const SalLayoutGlyphs
* pGlyphs
= rEntry
.GetTextGlyphs(this);
638 = static_cast<sal_uInt16
>(GetTextWidth(rEntry
.maStr
, 0, -1, nullptr, pGlyphs
));
639 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
640 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
641 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
642 aMetrics
.nEntryHeight
= mnTextHeight
+ gnBorder
;
645 if ( aMetrics
.bImage
)
647 Size aImgSz
= rEntry
.maImage
.GetSizePixel();
648 aMetrics
.nImgWidth
= static_cast<sal_uInt16
>(CalcZoom( aImgSz
.Width() ));
649 aMetrics
.nImgHeight
= static_cast<sal_uInt16
>(CalcZoom( aImgSz
.Height() ));
651 if( aMetrics
.nImgWidth
> mnMaxImgWidth
)
652 mnMaxImgWidth
= aMetrics
.nImgWidth
;
653 if( aMetrics
.nImgHeight
> mnMaxImgHeight
)
654 mnMaxImgHeight
= aMetrics
.nImgHeight
;
656 mnMaxImgTxtWidth
= std::max( mnMaxImgTxtWidth
, aMetrics
.nTextWidth
);
657 aMetrics
.nEntryHeight
= std::max( aMetrics
.nImgHeight
, aMetrics
.nEntryHeight
);
661 bool bIsUserDrawEnabled
= IsUserDrawEnabled();
662 if (bIsUserDrawEnabled
|| aMetrics
.bImage
)
664 aMetrics
.nEntryWidth
= std::max( aMetrics
.nImgWidth
, maUserItemSize
.Width() );
665 if (!bIsUserDrawEnabled
&& aMetrics
.bText
)
666 aMetrics
.nEntryWidth
+= aMetrics
.nTextWidth
+ IMG_TXT_DISTANCE
;
667 aMetrics
.nEntryHeight
= std::max( std::max( mnMaxImgHeight
, maUserItemSize
.Height() ) + 2,
668 aMetrics
.nEntryHeight
);
671 if (!aMetrics
.bText
&& !aMetrics
.bImage
&& !bIsUserDrawEnabled
)
673 // entries which have no (aka an empty) text, and no image,
674 // and are not user-drawn, should be shown nonetheless
675 aMetrics
.nEntryHeight
= mnTextHeight
+ gnBorder
;
678 if ( aMetrics
.nEntryWidth
> mnMaxWidth
)
679 mnMaxWidth
= aMetrics
.nEntryWidth
;
680 if ( aMetrics
.nEntryHeight
> mnMaxHeight
)
681 mnMaxHeight
= aMetrics
.nEntryHeight
;
683 rEntry
.mnHeight
= aMetrics
.nEntryHeight
;
686 void ImplListBoxWindow::ImplCallSelect()
688 if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
690 // Insert the selected entry as MRU, if not already first MRU
691 sal_Int32 nSelected
= GetEntryList()->GetSelectedEntryPos( 0 );
692 sal_Int32 nMRUCount
= GetEntryList()->GetMRUCount();
693 OUString aSelected
= GetEntryList()->GetEntryText( nSelected
);
694 sal_Int32 nFirstMatchingEntryPos
= GetEntryList()->FindEntry( aSelected
, true );
695 if ( nFirstMatchingEntryPos
|| !nMRUCount
)
697 bool bSelectNewEntry
= false;
698 if ( nFirstMatchingEntryPos
< nMRUCount
)
700 RemoveEntry( nFirstMatchingEntryPos
);
702 if ( nFirstMatchingEntryPos
== nSelected
)
703 bSelectNewEntry
= true;
705 else if ( nMRUCount
== GetEntryList()->GetMaxMRUCount() )
707 RemoveEntry( nMRUCount
- 1 );
711 ImplClearLayoutData();
713 ImplEntryType
* pNewEntry
= new ImplEntryType( aSelected
);
714 pNewEntry
->mbIsSelected
= bSelectNewEntry
;
715 GetEntryList()->InsertEntry( 0, pNewEntry
, false );
716 ImplUpdateEntryMetrics( *pNewEntry
);
717 GetEntryList()->SetMRUCount( ++nMRUCount
);
718 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
719 maMRUChangedHdl
.Call( nullptr );
723 maSelectHdl
.Call( nullptr );
724 mbSelectionChanged
= false;
727 sal_Int32
ImplListBoxWindow::InsertEntry(sal_Int32 nPos
, ImplEntryType
* pNewEntry
, bool bSort
)
730 assert(mpEntryList
->GetEntryCount() < LISTBOX_MAX_ENTRIES
);
732 ImplClearLayoutData();
733 sal_Int32 nNewPos
= mpEntryList
->InsertEntry( nPos
, pNewEntry
, bSort
);
735 if( GetStyle() & WB_WORDBREAK
)
736 pNewEntry
->mnFlags
|= ListBoxEntryFlags::MultiLine
;
738 ImplUpdateEntryMetrics( *pNewEntry
);
742 sal_Int32
ImplListBoxWindow::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
)
744 return InsertEntry(nPos
, pNewEntry
, mbSort
);
747 void ImplListBoxWindow::RemoveEntry( sal_Int32 nPos
)
749 ImplClearLayoutData();
750 mpEntryList
->RemoveEntry( nPos
);
751 if( mnCurrentPos
>= mpEntryList
->GetEntryCount() )
752 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
756 void ImplListBoxWindow::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
758 mpEntryList
->SetEntryFlags( nPos
, nFlags
);
759 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( nPos
);
761 ImplUpdateEntryMetrics( *pEntry
);
764 void ImplListBoxWindow::ImplShowFocusRect()
766 if ( mbHasFocusRect
)
768 ShowFocus( maFocusRect
);
769 mbHasFocusRect
= true;
772 void ImplListBoxWindow::ImplHideFocusRect()
774 if ( mbHasFocusRect
)
777 mbHasFocusRect
= false;
781 sal_Int32
ImplListBoxWindow::GetEntryPosForPoint( const Point
& rPoint
) const
783 tools::Long nY
= gnBorder
;
785 sal_Int32 nSelect
= mnTop
;
786 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nSelect
);
789 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
790 if (rPoint
.Y() <= nEntryHeight
+ nY
)
793 pEntry
= mpEntryList
->GetEntryPtr( ++nSelect
);
795 if( pEntry
== nullptr )
796 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
801 bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry
) const
805 if( i_nEntry
>= mnTop
)
807 if( mpEntryList
->GetAddedHeight( i_nEntry
, mnTop
) <
808 PixelToLogic( GetSizePixel() ).Height() )
817 tools::Long
ImplListBoxWindow::GetEntryHeightWithMargin() const
819 tools::Long nMargin
= ImplGetSVData()->maNWFData
.mnListBoxEntryMargin
;
820 return mnMaxHeight
+ nMargin
;
823 sal_Int32
ImplListBoxWindow::GetLastVisibleEntry() const
825 sal_Int32 nPos
= mnTop
;
826 tools::Long nWindowHeight
= GetSizePixel().Height();
827 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
829 for( nDiff
= 0; nDiff
< nWindowHeight
&& nPos
< nCount
; nDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
) )
832 if( nDiff
> nWindowHeight
&& nPos
> mnTop
)
841 void ImplListBoxWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
843 mbMouseMoveSelect
= false; // only till the first MouseButtonDown
844 maQuickSelectionEngine
.Reset();
848 if( rMEvt
.GetClicks() == 1 )
850 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
851 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
853 if ( !mbMulti
&& GetEntryList()->GetSelectedEntryCount() )
854 mnTrackingSaveSelection
= GetEntryList()->GetSelectedEntryPos( 0 );
856 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
858 mnCurrentPos
= nSelect
;
859 mbTrackingSelect
= true;
860 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
861 (void)SelectEntries( nSelect
, LET_MBDOWN
, rMEvt
.IsShift(), rMEvt
.IsMod1() ,bCurPosChange
);
862 mbTrackingSelect
= false;
866 StartTracking( StartTrackingFlags::ScrollRepeat
);
869 if( rMEvt
.GetClicks() == 2 )
871 maDoubleClickHdl
.Call( this );
874 else // if ( mbGrabFocus )
880 void ImplListBoxWindow::MouseMove( const MouseEvent
& rMEvt
)
882 if (rMEvt
.IsLeaveWindow() || mbMulti
|| !IsMouseMoveSelect() || !mpEntryList
->GetEntryCount())
885 tools::Rectangle
aRect( Point(), GetOutputSizePixel() );
886 if( !aRect
.IsInside( rMEvt
.GetPosPixel() ) )
889 if ( IsMouseMoveSelect() )
891 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
892 if( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
893 nSelect
= mpEntryList
->GetEntryCount() - 1;
894 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
895 nSelect
= std::min( nSelect
, static_cast<sal_Int32
>( mpEntryList
->GetEntryCount() - 1 ) );
896 // Select only visible Entries with MouseMove, otherwise Tracking...
897 if ( IsVisible( nSelect
) &&
898 mpEntryList
->IsEntrySelectable( nSelect
) &&
899 ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectedEntryCount() || ( nSelect
!= GetEntryList()->GetSelectedEntryPos( 0 ) ) ) )
901 mbTrackingSelect
= true;
902 if ( SelectEntries( nSelect
, LET_TRACKING
) )
904 // When list box selection change by mouse move, notify
905 // VclEventId::ListboxSelect vcl event.
906 maListItemSelectHdl
.Call(nullptr);
908 mbTrackingSelect
= false;
912 // if the DD button was pressed and someone moved into the ListBox
913 // with the mouse button pressed...
914 if ( rMEvt
.IsLeft() && !rMEvt
.IsSynthetic() )
916 if ( !mbMulti
&& GetEntryList()->GetSelectedEntryCount() )
917 mnTrackingSaveSelection
= GetEntryList()->GetSelectedEntryPos( 0 );
919 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
921 StartTracking( StartTrackingFlags::ScrollRepeat
);
925 void ImplListBoxWindow::DeselectAll()
927 while ( GetEntryList()->GetSelectedEntryCount() )
929 sal_Int32 nS
= GetEntryList()->GetSelectedEntryPos( 0 );
930 SelectEntry( nS
, false );
934 void ImplListBoxWindow::SelectEntry( sal_Int32 nPos
, bool bSelect
)
936 if( (mpEntryList
->IsEntryPosSelected( nPos
) == bSelect
) || !mpEntryList
->IsEntrySelectable( nPos
) )
944 // deselect the selected entry
945 sal_Int32 nDeselect
= GetEntryList()->GetSelectedEntryPos( 0 );
946 if( nDeselect
!= LISTBOX_ENTRY_NOTFOUND
)
948 //SelectEntryPos( nDeselect, false );
949 GetEntryList()->SelectEntry( nDeselect
, false );
950 if (IsUpdateMode() && IsReallyVisible())
954 mpEntryList
->SelectEntry( nPos
, true );
956 if ( ( nPos
!= LISTBOX_ENTRY_NOTFOUND
) && IsUpdateMode() )
959 if ( !IsVisible( nPos
) )
961 ImplClearLayoutData();
962 sal_Int32 nVisibleEntries
= GetLastVisibleEntry()-mnTop
;
963 if ( !nVisibleEntries
|| !IsReallyVisible() || ( nPos
< GetTopEntry() ) )
966 ShowProminentEntry( nPos
);
970 ShowProminentEntry( nPos
);
977 mpEntryList
->SelectEntry( nPos
, false );
980 mbSelectionChanged
= true;
983 bool ImplListBoxWindow::SelectEntries( sal_Int32 nSelect
, LB_EVENT_TYPE eLET
, bool bShift
, bool bCtrl
, bool bSelectPosChange
/*=FALSE*/ )
985 bool bSelectionChanged
= false;
987 if( IsEnabled() && mpEntryList
->IsEntrySelectable( nSelect
) )
989 bool bFocusChanged
= false;
991 // here (Single-ListBox) only one entry can be deselected
994 sal_Int32 nDeselect
= mpEntryList
->GetSelectedEntryPos( 0 );
995 if( nSelect
!= nDeselect
)
997 SelectEntry( nSelect
, true );
998 mpEntryList
->SetLastSelected( nSelect
);
999 bFocusChanged
= true;
1000 bSelectionChanged
= true;
1003 // MultiListBox without Modifier
1004 else if( mbSimpleMode
&& !bCtrl
&& !bShift
)
1006 sal_Int32 nEntryCount
= mpEntryList
->GetEntryCount();
1007 for ( sal_Int32 nPos
= 0; nPos
< nEntryCount
; nPos
++ )
1009 bool bSelect
= nPos
== nSelect
;
1010 if ( mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
)
1012 SelectEntry( nPos
, bSelect
);
1013 bFocusChanged
= true;
1014 bSelectionChanged
= true;
1017 mpEntryList
->SetLastSelected( nSelect
);
1018 mpEntryList
->SetSelectionAnchor( nSelect
);
1020 // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1021 else if( ( !mbSimpleMode
/* && !bShift */ ) || ( mbSimpleMode
&& ( bCtrl
|| bShift
) ) )
1023 // Space for selection change
1024 if( !bShift
&& ( ( eLET
== LET_KEYSPACE
) || ( eLET
== LET_MBDOWN
) ) )
1026 bool bSelect
= !mpEntryList
->IsEntryPosSelected( nSelect
);
1027 SelectEntry( nSelect
, bSelect
);
1028 mpEntryList
->SetLastSelected( nSelect
);
1029 mpEntryList
->SetSelectionAnchor( nSelect
);
1030 if ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1031 mpEntryList
->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND
);
1032 bFocusChanged
= true;
1033 bSelectionChanged
= true;
1035 else if( ( ( eLET
== LET_TRACKING
) && ( nSelect
!= mnCurrentPos
) ) ||
1036 ( bShift
&& ( ( eLET
== LET_KEYMOVE
) || ( eLET
== LET_MBDOWN
) ) ) )
1038 mnCurrentPos
= nSelect
;
1039 bFocusChanged
= true;
1041 sal_Int32 nAnchor
= mpEntryList
->GetSelectionAnchor();
1042 if( ( nAnchor
== LISTBOX_ENTRY_NOTFOUND
) && mpEntryList
->GetSelectedEntryCount() )
1044 nAnchor
= mpEntryList
->GetSelectedEntryPos( mpEntryList
->GetSelectedEntryCount() - 1 );
1046 if( nAnchor
!= LISTBOX_ENTRY_NOTFOUND
)
1048 // All entries from Anchor to nSelect have to be selected
1049 sal_Int32 nStart
= std::min( nSelect
, nAnchor
);
1050 sal_Int32 nEnd
= std::max( nSelect
, nAnchor
);
1051 for ( sal_Int32 n
= nStart
; n
<= nEnd
; n
++ )
1053 if ( !mpEntryList
->IsEntryPosSelected( n
) )
1055 SelectEntry( n
, true );
1056 bSelectionChanged
= true;
1060 // if appropriate some more has to be deselected...
1061 sal_Int32 nLast
= mpEntryList
->GetLastSelected();
1062 if ( nLast
!= LISTBOX_ENTRY_NOTFOUND
)
1064 if ( ( nLast
> nSelect
) && ( nLast
> nAnchor
) )
1066 for ( sal_Int32 n
= nSelect
+1; n
<= nLast
; n
++ )
1068 if ( mpEntryList
->IsEntryPosSelected( n
) )
1070 SelectEntry( n
, false );
1071 bSelectionChanged
= true;
1075 else if ( ( nLast
< nSelect
) && ( nLast
< nAnchor
) )
1077 for ( sal_Int32 n
= nLast
; n
< nSelect
; n
++ )
1079 if ( mpEntryList
->IsEntryPosSelected( n
) )
1081 SelectEntry( n
, false );
1082 bSelectionChanged
= true;
1087 mpEntryList
->SetLastSelected( nSelect
);
1090 else if( eLET
!= LET_TRACKING
)
1092 ImplHideFocusRect();
1094 bFocusChanged
= true;
1099 bFocusChanged
= true;
1102 if( bSelectionChanged
)
1103 mbSelectionChanged
= true;
1107 tools::Long nHeightDiff
= mpEntryList
->GetAddedHeight( nSelect
, mnTop
);
1108 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1109 Size
aSz( maFocusRect
.GetWidth(),
1110 mpEntryList
->GetEntryHeight( nSelect
) );
1111 maFocusRect
.SetSize( aSz
);
1113 ImplShowFocusRect();
1114 if (bSelectPosChange
)
1116 maFocusHdl
.Call(nSelect
);
1119 ImplClearLayoutData();
1121 return bSelectionChanged
;
1124 void ImplListBoxWindow::Tracking( const TrackingEvent
& rTEvt
)
1126 tools::Rectangle
aRect( Point(), GetOutputSizePixel() );
1127 bool bInside
= aRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() );
1129 if( rTEvt
.IsTrackingCanceled() || rTEvt
.IsTrackingEnded() ) // MouseButtonUp
1131 if ( bInside
&& !rTEvt
.IsTrackingCanceled() )
1133 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1138 maCancelHdl
.Call( nullptr );
1141 mbTrackingSelect
= true;
1142 SelectEntry( mnTrackingSaveSelection
, true );
1143 mbTrackingSelect
= false;
1144 if ( mnTrackingSaveSelection
!= LISTBOX_ENTRY_NOTFOUND
)
1146 tools::Long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
);
1147 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1148 Size
aSz( maFocusRect
.GetWidth(),
1149 mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1150 maFocusRect
.SetSize( aSz
);
1151 ImplShowFocusRect();
1160 bool bTrackOrQuickClick
= mbTrack
;
1168 // this case only happens, if the mouse button is pressed very briefly
1169 if( rTEvt
.IsTrackingEnded() && mbTrack
)
1171 bTrackOrQuickClick
= true;
1176 if( bTrackOrQuickClick
)
1178 MouseEvent aMEvt
= rTEvt
.GetMouseEvent();
1179 Point
aPt( aMEvt
.GetPosPixel() );
1180 bool bShift
= aMEvt
.IsShift();
1181 bool bCtrl
= aMEvt
.IsMod1();
1183 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1186 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1188 nSelect
= mnCurrentPos
? ( mnCurrentPos
- 1 ) : 0;
1189 if( nSelect
< mnTop
)
1190 SetTopEntry( mnTop
-1 );
1193 else if( aPt
.Y() > GetOutputSizePixel().Height() )
1195 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1197 nSelect
= std::min( static_cast<sal_Int32
>(mnCurrentPos
+1), static_cast<sal_Int32
>(mpEntryList
->GetEntryCount()-1) );
1198 if( nSelect
>= GetLastVisibleEntry() )
1199 SetTopEntry( mnTop
+1 );
1204 nSelect
= static_cast<sal_Int32
>( ( aPt
.Y() + gnBorder
) / mnMaxHeight
) + mnTop
;
1205 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
1206 nSelect
= std::min( nSelect
, static_cast<sal_Int32
>( mpEntryList
->GetEntryCount() - 1 ) );
1211 if ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectedEntryCount() )
1213 mbTrackingSelect
= true;
1214 SelectEntries(nSelect
, LET_TRACKING
, bShift
, bCtrl
);
1215 mbTrackingSelect
= false;
1220 if ( !mbMulti
&& GetEntryList()->GetSelectedEntryCount() )
1222 mbTrackingSelect
= true;
1223 SelectEntry( GetEntryList()->GetSelectedEntryPos( 0 ), false );
1224 mbTrackingSelect
= false;
1227 mnCurrentPos
= nSelect
;
1228 if ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1230 ImplHideFocusRect();
1234 tools::Long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
);
1235 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1236 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1237 maFocusRect
.SetSize( aSz
);
1238 ImplShowFocusRect();
1244 void ImplListBoxWindow::KeyInput( const KeyEvent
& rKEvt
)
1246 if( !ProcessKeyInput( rKEvt
) )
1247 Control::KeyInput( rKEvt
);
1250 bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent
& rKEvt
)
1252 // entry to be selected
1253 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1254 LB_EVENT_TYPE eLET
= LET_KEYMOVE
;
1256 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1258 bool bShift
= aKeyCode
.IsShift();
1259 bool bCtrl
= aKeyCode
.IsMod1() || aKeyCode
.IsMod3();
1260 bool bMod2
= aKeyCode
.IsMod2();
1262 bool bHandleKey
= false;
1264 switch( aKeyCode
.GetCode() )
1270 if ( GetTopEntry() )
1271 SetTopEntry( GetTopEntry()-1 );
1275 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1277 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1279 else if ( mnCurrentPos
)
1281 // search first selectable above the current position
1282 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
- 1, false );
1285 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
< mnTop
) )
1286 SetTopEntry( mnTop
-1 );
1290 maQuickSelectionEngine
.Reset();
1298 SetTopEntry( GetTopEntry()+1 );
1302 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1304 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1306 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1308 // search first selectable below the current position
1309 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
+ 1 );
1312 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
>= GetLastVisibleEntry() ) )
1313 SetTopEntry( mnTop
+1 );
1317 maQuickSelectionEngine
.Reset();
1325 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1326 SetTopEntry( ( mnTop
> nCurVis
) ?
1327 (mnTop
-nCurVis
) : 0 );
1329 else if ( !bCtrl
&& !bMod2
)
1331 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1333 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1335 else if ( mnCurrentPos
)
1337 if( mnCurrentPos
== mnTop
)
1339 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1340 SetTopEntry( ( mnTop
> nCurVis
) ? ( mnTop
-nCurVis
+1 ) : 0 );
1343 // find first selectable starting from mnTop looking forward
1344 nSelect
= mpEntryList
->FindFirstSelectable( mnTop
);
1348 maQuickSelectionEngine
.Reset();
1356 SetTopEntry( GetLastVisibleEntry() );
1358 else if ( !bCtrl
&& !bMod2
)
1360 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1362 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1364 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1366 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1367 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
;
1368 sal_Int32 nTmp
= std::min( nCurVis
, nCount
);
1370 if( mnCurrentPos
== nTmp
&& mnCurrentPos
!= nCount
- 1 )
1372 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) );
1373 nTmp2
= std::max( tools::Long(0) , nTmp2
);
1374 nTmp
= static_cast<sal_Int32
>(nTmp2
+(nCurVis
-1) );
1375 SetTopEntry( static_cast<sal_Int32
>(nTmp2
) );
1377 // find first selectable starting from nTmp looking backwards
1378 nSelect
= mpEntryList
->FindFirstSelectable( nTmp
, false );
1382 maQuickSelectionEngine
.Reset();
1392 else if ( !bCtrl
&& !bMod2
&& mnCurrentPos
)
1394 nSelect
= mpEntryList
->FindFirstSelectable( mpEntryList
->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND
);
1400 maQuickSelectionEngine
.Reset();
1408 SetTopEntry( 0xFFFF );
1410 else if ( !bCtrl
&& !bMod2
)
1412 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1414 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1416 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1418 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1419 nSelect
= mpEntryList
->FindFirstSelectable( nCount
- 1, false );
1420 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+ 1;
1421 if( nCount
> nCurVis
)
1422 SetTopEntry( nCount
- nCurVis
);
1426 maQuickSelectionEngine
.Reset();
1432 if ( !bCtrl
&& !bMod2
)
1434 ScrollHorz( -HORZ_SCROLL
);
1437 maQuickSelectionEngine
.Reset();
1443 if ( !bCtrl
&& !bMod2
)
1445 ScrollHorz( HORZ_SCROLL
);
1448 maQuickSelectionEngine
.Reset();
1454 if ( !bMod2
&& !IsReadOnly() )
1456 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1458 bDone
= false; // do not catch RETURN
1460 maQuickSelectionEngine
.Reset();
1466 if ( !bMod2
&& !IsReadOnly() )
1468 if( mbMulti
&& ( !mbSimpleMode
|| ( mbSimpleMode
&& bCtrl
&& !bShift
) ) )
1470 nSelect
= mnCurrentPos
;
1471 eLET
= LET_KEYSPACE
;
1481 if( bCtrl
&& mbMulti
)
1484 bool bUpdates
= IsUpdateMode();
1485 SetUpdateMode( false );
1487 sal_Int32 nEntryCount
= mpEntryList
->GetEntryCount();
1488 for( sal_Int32 i
= 0; i
< nEntryCount
; i
++ )
1489 SelectEntry( i
, true );
1491 // restore update mode
1492 SetUpdateMode( bUpdates
);
1495 maQuickSelectionEngine
.Reset();
1510 if (bHandleKey
&& !IsReadOnly())
1512 bDone
= maQuickSelectionEngine
.HandleKeyEvent( rKEvt
);
1515 if ( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
1516 && ( ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1517 || ( eLET
== LET_KEYSPACE
)
1521 SAL_WARN_IF( mpEntryList
->IsEntryPosSelected( nSelect
) && !mbMulti
, "vcl", "ImplListBox: Selecting same Entry" );
1522 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1523 if (nSelect
>= nCount
)
1524 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1525 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
1526 mnCurrentPos
= nSelect
;
1527 if(SelectEntries( nSelect
, eLET
, bShift
, bCtrl
, bCurPosChange
))
1529 // tdf#129043 Correctly deliver events when changing values with arrow keys in combobox
1530 if (mbIsDropdown
&& IsReallyVisible())
1531 mbTravelSelect
= true;
1532 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1534 mbTravelSelect
= false;
1543 vcl::StringEntryIdentifier
lcl_getEntry( const ImplEntryList
& _rList
, sal_Int32 _nPos
, OUString
& _out_entryText
)
1545 OSL_PRECOND( ( _nPos
!= LISTBOX_ENTRY_NOTFOUND
), "lcl_getEntry: invalid position!" );
1546 sal_Int32
nEntryCount( _rList
.GetEntryCount() );
1547 if ( _nPos
>= nEntryCount
)
1549 _out_entryText
= _rList
.GetEntryText( _nPos
);
1551 // vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1553 return reinterpret_cast< vcl::StringEntryIdentifier
>( _nPos
+ 1 );
1556 sal_Int32
lcl_getEntryPos( vcl::StringEntryIdentifier _entry
)
1558 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1559 return static_cast< sal_Int32
>( reinterpret_cast< sal_Int64
>( _entry
) ) - 1;
1563 vcl::StringEntryIdentifier
ImplListBoxWindow::CurrentEntry( OUString
& _out_entryText
) const
1565 return lcl_getEntry( *GetEntryList(), ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
) ? 0 : mnCurrentPos
, _out_entryText
);
1568 vcl::StringEntryIdentifier
ImplListBoxWindow::NextEntry( vcl::StringEntryIdentifier _currentEntry
, OUString
& _out_entryText
) const
1570 sal_Int32 nNextPos
= lcl_getEntryPos( _currentEntry
) + 1;
1571 return lcl_getEntry( *GetEntryList(), nNextPos
, _out_entryText
);
1574 void ImplListBoxWindow::SelectEntry( vcl::StringEntryIdentifier _entry
)
1576 sal_Int32 nSelect
= lcl_getEntryPos( _entry
);
1577 if ( mpEntryList
->IsEntryPosSelected( nSelect
) )
1579 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1580 // to select the given entry by typing its starting letters. No need to act.
1585 OSL_ENSURE( nSelect
< mpEntryList
->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1586 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1587 if (nSelect
>= nCount
)
1588 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1591 ShowProminentEntry( nSelect
);
1594 mnCurrentPos
= nSelect
;
1595 if ( SelectEntries( nSelect
, LET_KEYMOVE
) )
1597 mbTravelSelect
= true;
1598 mnSelectModifier
= 0;
1600 mbTravelSelect
= false;
1604 void ImplListBoxWindow::ImplPaint(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
)
1606 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1608 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nPos
);
1612 tools::Long nWidth
= GetOutputSizePixel().Width();
1613 tools::Long nY
= mpEntryList
->GetAddedHeight(nPos
, mnTop
);
1614 tools::Rectangle
aRect(Point(0, nY
), Size(nWidth
, pEntry
->getHeightWithMargin()));
1616 bool bSelected
= mpEntryList
->IsEntryPosSelected(nPos
);
1619 rRenderContext
.SetTextColor(!IsEnabled() ? rStyleSettings
.GetDisableColor() : rStyleSettings
.GetHighlightTextColor());
1620 rRenderContext
.SetFillColor(rStyleSettings
.GetHighlightColor());
1621 rRenderContext
.SetLineColor();
1622 rRenderContext
.DrawRect(aRect
);
1626 ApplySettings(rRenderContext
);
1628 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
1630 rRenderContext
.SetTextFillColor();
1632 if (IsUserDrawEnabled())
1634 mbInUserDraw
= true;
1635 mnUserDrawEntry
= nPos
;
1636 aRect
.AdjustLeft( -mnLeft
);
1637 if (nPos
< GetEntryList()->GetMRUCount())
1638 nPos
= GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nPos
));
1639 nPos
= nPos
- GetEntryList()->GetMRUCount();
1641 UserDrawEvent
aUDEvt(this, &rRenderContext
, aRect
, nPos
, bSelected
);
1642 maUserDrawHdl
.Call( &aUDEvt
);
1643 mbInUserDraw
= false;
1647 DrawEntry(rRenderContext
, nPos
, true, true);
1651 void ImplListBoxWindow::DrawEntry(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
, bool bDrawImage
, bool bDrawText
)
1653 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr(nPos
);
1657 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
1659 // when changing this function don't forget to adjust ImplWin::DrawEntry()
1662 nPos
= mnUserDrawEntry
; // real entry, not the matching entry from MRU
1664 tools::Long nY
= mpEntryList
->GetAddedHeight(nPos
, mnTop
);
1666 if (bDrawImage
&& mpEntryList
->HasImages())
1668 Image aImage
= mpEntryList
->GetEntryImage(nPos
);
1671 Size aImgSz
= aImage
.GetSizePixel();
1672 Point
aPtImg(gnBorder
- mnLeft
, nY
+ ((nEntryHeight
- aImgSz
.Height()) / 2));
1676 rRenderContext
.DrawImage(aPtImg
, aImage
);
1680 aImgSz
.setWidth( CalcZoom(aImgSz
.Width()) );
1681 aImgSz
.setHeight( CalcZoom(aImgSz
.Height()) );
1682 rRenderContext
.DrawImage(aPtImg
, aImgSz
, aImage
);
1685 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1686 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
1688 if (nEdgeBlendingPercent
&& aImgSz
.Width() && aImgSz
.Height())
1690 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
1691 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
1692 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
1693 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
1695 if (!aBlendFrame
.IsEmpty())
1697 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
1705 OUString
aStr(mpEntryList
->GetEntryText(nPos
));
1706 if (!aStr
.isEmpty())
1708 tools::Long nMaxWidth
= std::max(mnMaxWidth
, GetOutputSizePixel().Width() - 2 * gnBorder
);
1709 // a multiline entry should only be as wide as the window
1710 if (pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
)
1711 nMaxWidth
= GetOutputSizePixel().Width() - 2 * gnBorder
;
1713 tools::Rectangle
aTextRect(Point(gnBorder
- mnLeft
, nY
),
1714 Size(nMaxWidth
, nEntryHeight
));
1716 if (mpEntryList
->HasEntryImage(nPos
) || IsUserDrawEnabled())
1718 tools::Long nImageWidth
= std::max(mnMaxImgWidth
, maUserItemSize
.Width());
1719 aTextRect
.AdjustLeft(nImageWidth
+ IMG_TXT_DISTANCE
);
1722 DrawTextFlags nDrawStyle
= ImplGetTextStyle();
1723 if (pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
)
1724 nDrawStyle
|= MULTILINE_ENTRY_DRAW_FLAGS
;
1725 if (pEntry
->mnFlags
& ListBoxEntryFlags::DrawDisabled
)
1726 nDrawStyle
|= DrawTextFlags::Disable
;
1728 rRenderContext
.DrawText(aTextRect
, aStr
, nDrawStyle
);
1732 if ( !maSeparators
.empty() && ( isSeparator(nPos
) || isSeparator(nPos
-1) ) )
1734 Color
aOldLineColor(rRenderContext
.GetLineColor());
1735 rRenderContext
.SetLineColor((GetBackground() != COL_LIGHTGRAY
) ? COL_LIGHTGRAY
: COL_GRAY
);
1736 Point
aStartPos(0, nY
);
1737 if (isSeparator(nPos
))
1738 aStartPos
.AdjustY(pEntry
->getHeightWithMargin() - 1 );
1739 Point
aEndPos(aStartPos
);
1740 aEndPos
.setX( GetOutputSizePixel().Width() );
1741 rRenderContext
.DrawLine(aStartPos
, aEndPos
);
1742 rRenderContext
.SetLineColor(aOldLineColor
);
1746 void ImplListBoxWindow::FillLayoutData() const
1748 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
1749 const_cast<ImplListBoxWindow
*>(this)->Invalidate(tools::Rectangle(Point(0, 0), GetOutputSize()));
1752 void ImplListBoxWindow::ImplDoPaint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
1754 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1756 bool bShowFocusRect
= mbHasFocusRect
;
1758 ImplHideFocusRect();
1760 tools::Long nY
= 0; // + gnBorder;
1761 tools::Long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1763 for (sal_Int32 i
= mnTop
; i
< nCount
&& nY
< nHeight
+ mnMaxHeight
; i
++)
1765 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr(i
);
1766 tools::Long nEntryHeight
= pEntry
->getHeightWithMargin();
1767 if (nY
+ nEntryHeight
>= rRect
.Top() &&
1768 nY
<= rRect
.Bottom() + mnMaxHeight
)
1770 ImplPaint(rRenderContext
, i
);
1775 tools::Long nHeightDiff
= mpEntryList
->GetAddedHeight(mnCurrentPos
, mnTop
);
1776 maFocusRect
.SetPos(Point(0, nHeightDiff
));
1777 Size
aSz(maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight(mnCurrentPos
));
1778 maFocusRect
.SetSize(aSz
);
1779 if (HasFocus() && bShowFocusRect
)
1780 ImplShowFocusRect();
1783 void ImplListBoxWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
1785 if (SupportsDoubleBuffering())
1787 // This widget is explicitly double-buffered, so avoid partial paints.
1788 tools::Rectangle
aRect(Point(0, 0), GetOutputSizePixel());
1789 ImplDoPaint(rRenderContext
, aRect
);
1792 ImplDoPaint(rRenderContext
, rRect
);
1795 sal_uInt16
ImplListBoxWindow::GetDisplayLineCount() const
1797 // FIXME: ListBoxEntryFlags::MultiLine
1799 const sal_Int32 nCount
= mpEntryList
->GetEntryCount()-mnTop
;
1800 tools::Long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1801 sal_uInt16 nEntries
= static_cast< sal_uInt16
>( ( nHeight
+ mnMaxHeight
- 1 ) / mnMaxHeight
);
1802 if( nEntries
> nCount
)
1803 nEntries
= static_cast<sal_uInt16
>(nCount
);
1808 void ImplListBoxWindow::Resize()
1812 bool bShowFocusRect
= mbHasFocusRect
;
1813 if ( bShowFocusRect
)
1814 ImplHideFocusRect();
1816 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1818 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1819 maFocusRect
.SetSize( aSz
);
1822 if ( bShowFocusRect
)
1823 ImplShowFocusRect();
1825 ImplClearLayoutData();
1828 void ImplListBoxWindow::GetFocus()
1830 sal_Int32 nPos
= mnCurrentPos
;
1831 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
1833 tools::Long nHeightDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
);
1834 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1835 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( nPos
) );
1836 maFocusRect
.SetSize( aSz
);
1837 ImplShowFocusRect();
1838 Control::GetFocus();
1841 void ImplListBoxWindow::LoseFocus()
1843 ImplHideFocusRect();
1844 Control::LoseFocus();
1847 void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop
)
1849 if( mpEntryList
->GetEntryCount() == 0 )
1852 tools::Long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1854 sal_Int32 nLastEntry
= mpEntryList
->GetEntryCount()-1;
1855 if( nTop
> nLastEntry
)
1857 const ImplEntryType
* pLast
= mpEntryList
->GetEntryPtr( nLastEntry
);
1858 while( nTop
> 0 && mpEntryList
->GetAddedHeight( nLastEntry
, nTop
-1 ) + pLast
->getHeightWithMargin() <= nWHeight
)
1861 if ( nTop
== mnTop
)
1864 ImplClearLayoutData();
1865 tools::Long nDiff
= mpEntryList
->GetAddedHeight( mnTop
, nTop
);
1867 ImplHideFocusRect();
1872 ImplShowFocusRect();
1873 maScrollHdl
.Call( this );
1876 void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos
)
1878 SetTopEntry( nEntryPos
);
1881 void ImplListBoxWindow::SetLeftIndent( tools::Long n
)
1883 ScrollHorz( n
- mnLeft
);
1886 void ImplListBoxWindow::ScrollHorz( tools::Long n
)
1888 tools::Long nDiff
= 0;
1891 tools::Long nWidth
= GetOutputSizePixel().Width();
1892 if( ( mnMaxWidth
- mnLeft
+ n
) > nWidth
)
1899 tools::Long nAbs
= -n
;
1900 nDiff
= - std::min( mnLeft
, nAbs
);
1906 ImplClearLayoutData();
1907 mnLeft
= sal::static_int_cast
<sal_uInt16
>(mnLeft
+ nDiff
);
1909 ImplHideFocusRect();
1910 Scroll( -nDiff
, 0 );
1913 ImplShowFocusRect();
1914 maScrollHdl
.Call( this );
1918 void ImplListBoxWindow::SetSeparatorPos( sal_Int32 n
)
1920 maSeparators
.clear();
1922 if ( n
!= LISTBOX_ENTRY_NOTFOUND
)
1924 maSeparators
.insert( n
);
1928 sal_Int32
ImplListBoxWindow::GetSeparatorPos() const
1930 if (!maSeparators
.empty())
1931 return *(maSeparators
.begin());
1933 return LISTBOX_ENTRY_NOTFOUND
;
1936 bool ImplListBoxWindow::isSeparator( const sal_Int32
&n
) const
1938 return maSeparators
.find(n
) != maSeparators
.end();
1941 Size
ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines
) const
1943 // FIXME: ListBoxEntryFlags::MultiLine
1946 aSz
.setHeight(nMaxLines
* GetEntryHeightWithMargin());
1947 aSz
.setWidth( mnMaxWidth
+ 2*gnBorder
);
1951 tools::Rectangle
ImplListBoxWindow::GetBoundingRectangle( sal_Int32 nItem
) const
1953 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nItem
);
1954 Size
aSz( GetSizePixel().Width(), pEntry
? pEntry
->getHeightWithMargin() : GetEntryHeightWithMargin() );
1955 tools::Long nY
= mpEntryList
->GetAddedHeight( nItem
, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeightWithMargin();
1956 tools::Rectangle
aRect( Point( 0, nY
), aSz
);
1960 void ImplListBoxWindow::StateChanged( StateChangedType nType
)
1962 Control::StateChanged( nType
);
1964 if ( nType
== StateChangedType::Zoom
)
1966 ApplySettings(*this);
1970 else if ( nType
== StateChangedType::UpdateMode
)
1972 if ( IsUpdateMode() && IsReallyVisible() )
1975 else if ( nType
== StateChangedType::ControlFont
)
1977 ApplySettings(*this);
1981 else if ( nType
== StateChangedType::ControlForeground
)
1983 ApplySettings(*this);
1986 else if ( nType
== StateChangedType::ControlBackground
)
1988 ApplySettings(*this);
1991 else if( nType
== StateChangedType::Enable
)
1996 ImplClearLayoutData();
1999 void ImplListBoxWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
2001 Control::DataChanged( rDCEvt
);
2003 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2004 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2005 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2006 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2008 ImplClearLayoutData();
2009 ApplySettings(*this);
2015 DrawTextFlags
ImplListBoxWindow::ImplGetTextStyle() const
2017 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2019 if (mpEntryList
->HasImages())
2020 nTextStyle
|= DrawTextFlags::Left
;
2022 nTextStyle
|= DrawTextFlags::Center
;
2024 nTextStyle
|= DrawTextFlags::Right
;
2026 nTextStyle
|= DrawTextFlags::Left
;
2031 ImplListBox::ImplListBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
2032 Control( pParent
, nWinStyle
),
2033 maLBWindow(VclPtr
<ImplListBoxWindow
>::Create( this, nWinStyle
&(~WB_BORDER
) ))
2035 // for native widget rendering we must be able to detect this window type
2036 SetType( WindowType::LISTBOXWINDOW
);
2038 mpVScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_VSCROLL
| WB_DRAG
);
2039 mpHScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_HSCROLL
| WB_DRAG
);
2040 mpScrollBarBox
= VclPtr
<ScrollBarBox
>::Create( this );
2042 Link
<ScrollBar
*,void> aLink( LINK( this, ImplListBox
, ScrollBarHdl
) );
2043 mpVScrollBar
->SetScrollHdl( aLink
);
2044 mpHScrollBar
->SetScrollHdl( aLink
);
2048 mbAutoHScroll
= ( nWinStyle
& WB_AUTOHSCROLL
);
2049 mbEdgeBlending
= false;
2051 maLBWindow
->SetScrollHdl( LINK( this, ImplListBox
, LBWindowScrolled
) );
2052 maLBWindow
->SetMRUChangedHdl( LINK( this, ImplListBox
, MRUChanged
) );
2053 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2057 ImplListBox::~ImplListBox()
2062 void ImplListBox::dispose()
2064 mpHScrollBar
.disposeAndClear();
2065 mpVScrollBar
.disposeAndClear();
2066 mpScrollBarBox
.disposeAndClear();
2067 maLBWindow
.disposeAndClear();
2071 void ImplListBox::Clear()
2073 maLBWindow
->Clear();
2074 if ( GetEntryList()->GetMRUCount() )
2076 maLBWindow
->GetEntryList()->SetMRUCount( 0 );
2077 maLBWindow
->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND
);
2079 mpVScrollBar
->SetThumbPos( 0 );
2080 mpHScrollBar
->SetThumbPos( 0 );
2081 CompatStateChanged( StateChangedType::Data
);
2084 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
)
2086 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
);
2087 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2088 CompatStateChanged( StateChangedType::Data
);
2092 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
, const Image
& rImage
)
2094 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
, rImage
);
2095 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2096 CompatStateChanged( StateChangedType::Data
);
2100 void ImplListBox::RemoveEntry( sal_Int32 nPos
)
2102 maLBWindow
->RemoveEntry( nPos
);
2103 CompatStateChanged( StateChangedType::Data
);
2106 void ImplListBox::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
2108 maLBWindow
->SetEntryFlags( nPos
, nFlags
);
2111 void ImplListBox::SelectEntry( sal_Int32 nPos
, bool bSelect
)
2113 maLBWindow
->SelectEntry( nPos
, bSelect
);
2116 void ImplListBox::SetNoSelection()
2118 maLBWindow
->DeselectAll();
2121 void ImplListBox::GetFocus()
2124 maLBWindow
->GrabFocus();
2126 Control::GetFocus();
2129 void ImplListBox::Resize()
2132 ImplResizeControls();
2133 ImplCheckScrollBars();
2136 IMPL_LINK_NOARG(ImplListBox
, MRUChanged
, LinkParamNone
*, void)
2138 CompatStateChanged( StateChangedType::Data
);
2141 IMPL_LINK_NOARG(ImplListBox
, LBWindowScrolled
, ImplListBoxWindow
*, void)
2143 tools::Long nSet
= GetTopEntry();
2144 if( nSet
> mpVScrollBar
->GetRangeMax() )
2145 mpVScrollBar
->SetRangeMax( GetEntryList()->GetEntryCount() );
2146 mpVScrollBar
->SetThumbPos( GetTopEntry() );
2148 mpHScrollBar
->SetThumbPos( GetLeftIndent() );
2150 maScrollHdl
.Call( this );
2153 IMPL_LINK( ImplListBox
, ScrollBarHdl
, ScrollBar
*, pSB
, void )
2155 sal_uInt16 nPos
= static_cast<sal_uInt16
>(pSB
->GetThumbPos());
2156 if( pSB
== mpVScrollBar
)
2157 SetTopEntry( nPos
);
2158 else if( pSB
== mpHScrollBar
)
2159 SetLeftIndent( nPos
);
2161 GetParent()->Invalidate( InvalidateFlags::Update
);
2164 void ImplListBox::ImplCheckScrollBars()
2166 bool bArrange
= false;
2168 Size aOutSz
= GetOutputSizePixel();
2169 sal_Int32 nEntries
= GetEntryList()->GetEntryCount();
2170 sal_uInt16 nMaxVisEntries
= static_cast<sal_uInt16
>(aOutSz
.Height() / GetEntryHeightWithMargin());
2172 // vertical ScrollBar
2173 if( nEntries
> nMaxVisEntries
)
2179 // check of the scrolled-out region
2180 if( GetEntryList()->GetSelectedEntryCount() == 1 &&
2181 GetEntryList()->GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2182 ShowProminentEntry( GetEntryList()->GetSelectedEntryPos( 0 ) );
2184 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2194 // horizontal ScrollBar
2197 tools::Long nWidth
= static_cast<sal_uInt16
>(aOutSz
.Width());
2199 nWidth
-= mpVScrollBar
->GetSizePixel().Width();
2201 tools::Long nMaxWidth
= GetMaxEntryWidth();
2202 if( nWidth
< nMaxWidth
)
2208 if ( !mbVScroll
) // maybe we do need one now
2210 nMaxVisEntries
= static_cast<sal_uInt16
>( ( aOutSz
.Height() - mpHScrollBar
->GetSizePixel().Height() ) / GetEntryHeightWithMargin() );
2211 if( nEntries
> nMaxVisEntries
)
2216 // check of the scrolled-out region
2217 if( GetEntryList()->GetSelectedEntryCount() == 1 &&
2218 GetEntryList()->GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2219 ShowProminentEntry( GetEntryList()->GetSelectedEntryPos( 0 ) );
2221 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2225 // check of the scrolled-out region
2226 sal_uInt16 nMaxLI
= static_cast<sal_uInt16
>(nMaxWidth
- nWidth
);
2227 if ( nMaxLI
< GetLeftIndent() )
2228 SetLeftIndent( nMaxLI
);
2240 ImplResizeControls();
2242 ImplInitScrollBars();
2245 void ImplListBox::ImplInitScrollBars()
2247 Size aOutSz
= maLBWindow
->GetOutputSizePixel();
2251 sal_Int32 nEntries
= GetEntryList()->GetEntryCount();
2252 sal_uInt16 nVisEntries
= static_cast<sal_uInt16
>(aOutSz
.Height() / GetEntryHeightWithMargin());
2253 mpVScrollBar
->SetRangeMax( nEntries
);
2254 mpVScrollBar
->SetVisibleSize( nVisEntries
);
2255 mpVScrollBar
->SetPageSize( nVisEntries
- 1 );
2260 mpHScrollBar
->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL
);
2261 mpHScrollBar
->SetVisibleSize( static_cast<sal_uInt16
>(aOutSz
.Width()) );
2262 mpHScrollBar
->SetLineSize( HORZ_SCROLL
);
2263 mpHScrollBar
->SetPageSize( aOutSz
.Width() - HORZ_SCROLL
);
2267 void ImplListBox::ImplResizeControls()
2269 // Here we only position the Controls; if the Scrollbars are to be
2270 // visible is already determined in ImplCheckScrollBars
2272 Size aOutSz
= GetOutputSizePixel();
2273 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2274 nSBWidth
= CalcZoom( nSBWidth
);
2276 Size
aInnerSz( aOutSz
);
2278 aInnerSz
.AdjustWidth( -nSBWidth
);
2280 aInnerSz
.AdjustHeight( -nSBWidth
);
2282 Point
aWinPos( 0, 0 );
2283 maLBWindow
->SetPosSizePixel( aWinPos
, aInnerSz
);
2286 if( mbVScroll
&& mbHScroll
)
2288 Point
aBoxPos( aInnerSz
.Width(), aInnerSz
.Height() );
2289 mpScrollBarBox
->SetPosSizePixel( aBoxPos
, Size( nSBWidth
, nSBWidth
) );
2290 mpScrollBarBox
->Show();
2294 mpScrollBarBox
->Hide();
2297 // vertical ScrollBar
2300 // Scrollbar on left or right side?
2301 Point
aVPos( aOutSz
.Width() - nSBWidth
, 0 );
2302 mpVScrollBar
->SetPosSizePixel( aVPos
, Size( nSBWidth
, aInnerSz
.Height() ) );
2303 mpVScrollBar
->Show();
2307 mpVScrollBar
->Hide();
2308 // #107254# Don't reset top entry after resize, but check for max top entry
2309 SetTopEntry( GetTopEntry() );
2312 // horizontal ScrollBar
2315 Point
aHPos( 0, aOutSz
.Height() - nSBWidth
);
2316 mpHScrollBar
->SetPosSizePixel( aHPos
, Size( aInnerSz
.Width(), nSBWidth
) );
2317 mpHScrollBar
->Show();
2321 mpHScrollBar
->Hide();
2326 void ImplListBox::StateChanged( StateChangedType nType
)
2328 if ( nType
== StateChangedType::InitShow
)
2330 ImplCheckScrollBars();
2332 else if ( ( nType
== StateChangedType::UpdateMode
) || ( nType
== StateChangedType::Data
) )
2334 bool bUpdate
= IsUpdateMode();
2335 maLBWindow
->SetUpdateMode( bUpdate
);
2336 if ( bUpdate
&& IsReallyVisible() )
2337 ImplCheckScrollBars();
2339 else if( nType
== StateChangedType::Enable
)
2341 mpHScrollBar
->Enable( IsEnabled() );
2342 mpVScrollBar
->Enable( IsEnabled() );
2343 mpScrollBarBox
->Enable( IsEnabled() );
2344 maLBWindow
->Enable( IsEnabled() );
2348 else if ( nType
== StateChangedType::Zoom
)
2350 maLBWindow
->SetZoom( GetZoom() );
2353 else if ( nType
== StateChangedType::ControlFont
)
2355 maLBWindow
->SetControlFont( GetControlFont() );
2357 else if ( nType
== StateChangedType::ControlForeground
)
2359 maLBWindow
->SetControlForeground( GetControlForeground() );
2361 else if ( nType
== StateChangedType::ControlBackground
)
2363 maLBWindow
->SetControlBackground( GetControlBackground() );
2365 else if( nType
== StateChangedType::Mirroring
)
2367 maLBWindow
->EnableRTL( IsRTLEnabled() );
2368 mpHScrollBar
->EnableRTL( IsRTLEnabled() );
2369 mpVScrollBar
->EnableRTL( IsRTLEnabled() );
2370 ImplResizeControls();
2373 Control::StateChanged( nType
);
2376 bool ImplListBox::EventNotify( NotifyEvent
& rNEvt
)
2379 if ( rNEvt
.GetType() == MouseNotifyEvent::COMMAND
)
2381 const CommandEvent
& rCEvt
= *rNEvt
.GetCommandEvent();
2382 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2384 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2385 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2387 bDone
= HandleScrollCommand( rCEvt
, mpHScrollBar
, mpVScrollBar
);
2390 else if (rCEvt
.GetCommand() == CommandEventId::Gesture
)
2392 bDone
= HandleScrollCommand(rCEvt
, mpHScrollBar
, mpVScrollBar
);
2396 return bDone
|| Window::EventNotify( rNEvt
);
2399 const Wallpaper
& ImplListBox::GetDisplayBackground() const
2401 return maLBWindow
->GetDisplayBackground();
2404 bool ImplListBox::HandleWheelAsCursorTravel(const CommandEvent
& rCEvt
, Control
& rControl
)
2407 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2409 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2410 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2412 if (!rControl
.HasChildPathFocus())
2413 rControl
.GrabFocus();
2414 sal_uInt16 nKey
= ( pData
->GetDelta() < 0 ) ? KEY_DOWN
: KEY_UP
;
2415 KeyEvent
aKeyEvent( 0, vcl::KeyCode( nKey
) );
2416 bDone
= ProcessKeyInput( aKeyEvent
);
2422 void ImplListBox::SetMRUEntries( const OUString
& rEntries
, sal_Unicode cSep
)
2424 bool bChanges
= GetEntryList()->GetMRUCount() != 0;
2426 // Remove old MRU entries
2427 for ( sal_Int32 n
= GetEntryList()->GetMRUCount();n
; )
2428 maLBWindow
->RemoveEntry( --n
);
2430 sal_Int32 nMRUCount
= 0;
2431 sal_Int32 nIndex
= 0;
2434 OUString aEntry
= rEntries
.getToken( 0, cSep
, nIndex
);
2435 // Accept only existing entries
2436 if ( GetEntryList()->FindEntry( aEntry
) != LISTBOX_ENTRY_NOTFOUND
)
2438 ImplEntryType
* pNewEntry
= new ImplEntryType( aEntry
);
2439 maLBWindow
->InsertEntry(nMRUCount
++, pNewEntry
, false);
2443 while ( nIndex
>= 0 );
2447 maLBWindow
->GetEntryList()->SetMRUCount( nMRUCount
);
2448 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
2449 CompatStateChanged( StateChangedType::Data
);
2453 OUString
ImplListBox::GetMRUEntries( sal_Unicode cSep
) const
2455 OUStringBuffer aEntries
;
2456 for ( sal_Int32 n
= 0; n
< GetEntryList()->GetMRUCount(); n
++ )
2458 aEntries
.append(GetEntryList()->GetEntryText( n
));
2459 if( n
< ( GetEntryList()->GetMRUCount() - 1 ) )
2460 aEntries
.append(cSep
);
2462 return aEntries
.makeStringAndClear();
2465 void ImplListBox::SetEdgeBlending(bool bNew
)
2467 if(mbEdgeBlending
!= bNew
)
2469 mbEdgeBlending
= bNew
;
2470 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2474 ImplWin::ImplWin( vcl::Window
* pParent
, WinBits nWinStyle
) :
2475 Control ( pParent
, nWinStyle
)
2477 if ( IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2478 && ! IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
2481 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2483 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
2485 mbEdgeBlending
= false;
2486 mnItemPos
= LISTBOX_ENTRY_NOTFOUND
;
2489 void ImplWin::MouseButtonDown( const MouseEvent
& )
2493 maMBDownHdl
.Call(this);
2497 void ImplWin::FillLayoutData() const
2499 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
2500 ImplWin
* pThis
= const_cast<ImplWin
*>(this);
2501 pThis
->ImplDraw(*pThis
, true);
2504 bool ImplWin::PreNotify( NotifyEvent
& rNEvt
)
2506 if( rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
)
2508 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
2509 if( pMouseEvt
&& (pMouseEvt
->IsEnterWindow() || pMouseEvt
->IsLeaveWindow()) )
2511 // trigger redraw as mouse over state has changed
2512 if ( IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2513 && ! IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
2515 GetParent()->GetWindow( GetWindowType::Border
)->Invalidate( InvalidateFlags::NoErase
);
2520 return Control::PreNotify(rNEvt
);
2523 void ImplWin::ImplDraw(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2525 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2529 bool bNativeOK
= false;
2530 bool bHasFocus
= HasFocus();
2531 bool bIsEnabled
= IsEnabled();
2533 ControlState nState
= ControlState::ENABLED
;
2534 if (rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2535 && rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::HasBackgroundTexture
) )
2537 // Repaint the (focused) area similarly to
2538 // ImplSmallBorderWindowView::DrawWindow() in
2539 // vcl/source/window/brdwin.cxx
2540 vcl::Window
*pWin
= GetParent();
2542 ImplControlValue aControlValue
;
2543 bIsEnabled
&= pWin
->IsEnabled();
2545 nState
&= ~ControlState::ENABLED
;
2546 bHasFocus
|= pWin
->HasFocus();
2548 nState
|= ControlState::FOCUSED
;
2550 // The listbox is painted over the entire control including the
2551 // border, but ImplWin does not contain the border => correction
2553 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2554 pWin
->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2555 Point
aPoint( -nLeft
, -nTop
);
2556 tools::Rectangle
aCtrlRegion( aPoint
- GetPosPixel(), pWin
->GetSizePixel() );
2558 bool bMouseOver
= false;
2559 vcl::Window
*pChild
= pWin
->GetWindow( GetWindowType::FirstChild
);
2562 bMouseOver
= pChild
->IsMouseOver();
2565 pChild
= pChild
->GetWindow( GetWindowType::Next
);
2568 nState
|= ControlState::ROLLOVER
;
2570 // if parent has no border, then nobody has drawn the background
2571 // since no border window exists. so draw it here.
2572 WinBits nParentStyle
= pWin
->GetStyle();
2573 if( ! (nParentStyle
& WB_BORDER
) || (nParentStyle
& WB_NOBORDER
) )
2575 tools::Rectangle
aParentRect( Point( 0, 0 ), pWin
->GetSizePixel() );
2576 pWin
->DrawNativeControl( ControlType::Listbox
, ControlPart::Entire
, aParentRect
,
2577 nState
, aControlValue
, OUString() );
2580 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Listbox
, ControlPart::Entire
, aCtrlRegion
,
2581 nState
, aControlValue
, OUString());
2586 if (bHasFocus
&& !ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2588 if ( !ImplGetSVData()->maNWFData
.mbNoFocusRects
)
2590 rRenderContext
.SetFillColor( rStyleSettings
.GetHighlightColor() );
2591 rRenderContext
.SetTextColor( rStyleSettings
.GetHighlightTextColor() );
2595 rRenderContext
.SetLineColor();
2596 rRenderContext
.SetFillColor();
2597 rRenderContext
.SetTextColor( rStyleSettings
.GetFieldTextColor() );
2599 rRenderContext
.DrawRect( maFocusRect
);
2604 if (IsControlForeground())
2605 aColor
= GetControlForeground();
2606 else if (ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2608 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2609 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
2611 aColor
= rStyleSettings
.GetButtonTextColor();
2615 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2616 aColor
= rStyleSettings
.GetFieldRolloverTextColor();
2618 aColor
= rStyleSettings
.GetFieldTextColor();
2620 rRenderContext
.SetTextColor(aColor
);
2622 rRenderContext
.Erase(maFocusRect
);
2627 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
2629 rRenderContext
.Erase(maFocusRect
);
2633 DrawEntry(rRenderContext
, bLayout
);
2636 void ImplWin::ApplySettings(vcl::RenderContext
& rRenderContext
)
2638 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2640 ApplyControlFont(rRenderContext
, rStyleSettings
.GetFieldFont());
2641 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetFieldTextColor());
2643 if (IsControlBackground())
2644 rRenderContext
.SetBackground(GetControlBackground());
2646 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
2649 void ImplWin::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
2651 ImplDraw(rRenderContext
);
2654 void ImplWin::DrawEntry(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2656 tools::Long nBorder
= 1;
2657 Size
aOutSz(GetOutputSizePixel());
2659 bool bImage
= !!maImage
;
2660 if (bImage
&& !bLayout
)
2662 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
2663 Size aImgSz
= maImage
.GetSizePixel();
2664 Point
aPtImg( nBorder
, ( ( aOutSz
.Height() - aImgSz
.Height() ) / 2 ) );
2665 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2667 // check for HC mode
2668 Image
*pImage
= &maImage
;
2672 rRenderContext
.DrawImage( aPtImg
, *pImage
, nStyle
);
2676 aImgSz
.setWidth( CalcZoom( aImgSz
.Width() ) );
2677 aImgSz
.setHeight( CalcZoom( aImgSz
.Height() ) );
2678 rRenderContext
.DrawImage( aPtImg
, aImgSz
, *pImage
, nStyle
);
2681 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
2683 if(nEdgeBlendingPercent
)
2685 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
2686 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
2687 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
2688 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
2690 if(!aBlendFrame
.IsEmpty())
2692 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
2697 if( !maString
.isEmpty() )
2699 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2701 if ( bImage
&& !bLayout
)
2702 nTextStyle
|= DrawTextFlags::Left
;
2703 else if ( GetStyle() & WB_CENTER
)
2704 nTextStyle
|= DrawTextFlags::Center
;
2705 else if ( GetStyle() & WB_RIGHT
)
2706 nTextStyle
|= DrawTextFlags::Right
;
2708 nTextStyle
|= DrawTextFlags::Left
;
2710 tools::Rectangle
aTextRect( Point( nBorder
, 0 ), Size( aOutSz
.Width()-2*nBorder
, aOutSz
.Height() ) );
2714 aTextRect
.AdjustLeft(maImage
.GetSizePixel().Width() + IMG_TXT_DISTANCE
);
2717 MetricVector
* pVector
= bLayout
? &mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
: nullptr;
2718 OUString
* pDisplayText
= bLayout
? &mpControlData
->mpLayoutData
->m_aDisplayText
: nullptr;
2719 rRenderContext
.DrawText( aTextRect
, maString
, nTextStyle
, pVector
, pDisplayText
);
2722 if( HasFocus() && !bLayout
)
2723 ShowFocus( maFocusRect
);
2726 void ImplWin::Resize()
2729 maFocusRect
.SetSize( GetOutputSizePixel() );
2733 void ImplWin::GetFocus()
2735 ShowFocus( maFocusRect
);
2736 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2737 IsNativeWidgetEnabled() &&
2738 IsNativeControlSupported( ControlType::Listbox
, ControlPart::Entire
) )
2740 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2747 Control::GetFocus();
2750 void ImplWin::LoseFocus()
2753 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2754 IsNativeWidgetEnabled() &&
2755 IsNativeControlSupported( ControlType::Listbox
, ControlPart::Entire
) )
2757 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2764 Control::LoseFocus();
2767 void ImplWin::ShowFocus(const tools::Rectangle
& rRect
)
2769 if (IsNativeControlSupported(ControlType::Listbox
, ControlPart::Focus
))
2771 ImplControlValue aControlValue
;
2773 vcl::Window
*pWin
= GetParent();
2774 tools::Rectangle
aParentRect(Point(0, 0), pWin
->GetSizePixel());
2775 pWin
->DrawNativeControl(ControlType::Listbox
, ControlPart::Focus
, aParentRect
,
2776 ControlState::FOCUSED
, aControlValue
, OUString());
2778 Control::ShowFocus(rRect
);
2781 ImplBtn::ImplBtn( vcl::Window
* pParent
, WinBits nWinStyle
) :
2782 PushButton( pParent
, nWinStyle
)
2786 void ImplBtn::MouseButtonDown( const MouseEvent
& )
2789 maMBDownHdl
.Call(this);
2792 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( vcl::Window
* pParent
) :
2793 FloatingWindow( pParent
, WB_BORDER
| WB_SYSTEMWINDOW
| WB_NOSHADOW
) // no drop shadow for list boxes
2797 mbAutoWidth
= false;
2799 mnPopupModeStartSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
2801 vcl::Window
* pBorderWindow
= ImplGetBorderWindow();
2804 SetAccessibleRole(accessibility::AccessibleRole::PANEL
);
2805 pBorderWindow
->SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2809 SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2814 ImplListBoxFloatingWindow::~ImplListBoxFloatingWindow()
2819 void ImplListBoxFloatingWindow::dispose()
2822 FloatingWindow::dispose();
2826 bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent
& rNEvt
)
2828 if( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2830 if( !GetParent()->HasChildPathFocus( true ) )
2834 return FloatingWindow::PreNotify( rNEvt
);
2837 void ImplListBoxFloatingWindow::setPosSizePixel( tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
, PosSizeFlags nFlags
)
2839 FloatingWindow::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
2841 // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2842 // after a call to Resize(), we adjust its position if necessary
2843 if ( IsReallyVisible() && ( nFlags
& PosSizeFlags::Height
) )
2845 Point aPos
= GetParent()->GetPosPixel();
2846 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2848 if ( nFlags
& PosSizeFlags::X
)
2851 if ( nFlags
& PosSizeFlags::Y
)
2855 SetPosPixel( ImplCalcPos( this, tools::Rectangle( aPos
, GetParent()->GetSizePixel() ), FloatWinPopupFlags::Down
, nIndex
) );
2858 // if( !IsReallyVisible() )
2860 // The ImplListBox does not get a Resize() as not visible.
2861 // But the windows must get a Resize(), so that the number of
2862 // visible entries is correct for PgUp/PgDown.
2863 // The number also cannot be calculated by List/Combobox, as for
2864 // this the presence of the vertical Scrollbar has to be known.
2865 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
2866 static_cast<vcl::Window
*>(mpImplLB
)->Resize();
2867 static_cast<vcl::Window
*>(mpImplLB
->GetMainWindow())->Resize();
2871 void ImplListBoxFloatingWindow::Resize()
2873 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
2874 FloatingWindow::Resize();
2877 Size
ImplListBoxFloatingWindow::CalcFloatSize()
2879 Size
aFloatSz( maPrefSz
);
2881 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2882 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2884 sal_Int32 nLines
= mpImplLB
->GetEntryList()->GetEntryCount();
2885 if ( mnDDLineCount
&& ( nLines
> mnDDLineCount
) )
2886 nLines
= mnDDLineCount
;
2888 Size aSz
= mpImplLB
->CalcSize( nLines
);
2889 tools::Long nMaxHeight
= aSz
.Height() + nTop
+ nBottom
;
2891 if ( mnDDLineCount
)
2892 aFloatSz
.setHeight( nMaxHeight
);
2896 // AutoSize first only for width...
2898 aFloatSz
.setWidth( aSz
.Width() + nLeft
+ nRight
);
2899 aFloatSz
.AdjustWidth(nRight
); // adding some space looks better...
2901 if ( ( aFloatSz
.Height() < nMaxHeight
) || ( mnDDLineCount
&& ( mnDDLineCount
< mpImplLB
->GetEntryList()->GetEntryCount() ) ) )
2903 // then we also need the vertical Scrollbar
2904 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2905 aFloatSz
.AdjustWidth(nSBWidth
);
2908 tools::Long nDesktopWidth
= GetDesktopRectPixel().getWidth();
2909 if (aFloatSz
.Width() > nDesktopWidth
)
2910 // Don't exceed the desktop width.
2911 aFloatSz
.setWidth( nDesktopWidth
);
2914 if ( aFloatSz
.Height() > nMaxHeight
)
2915 aFloatSz
.setHeight( nMaxHeight
);
2917 // Minimal height, in case height is not set to Float height.
2918 // The parent of FloatWin must be DropDown-Combo/Listbox.
2919 Size aParentSz
= GetParent()->GetSizePixel();
2920 if( (!mnDDLineCount
|| !nLines
) && ( aFloatSz
.Height() < aParentSz
.Height() ) )
2921 aFloatSz
.setHeight( aParentSz
.Height() );
2923 // do not get narrower than the parent...
2924 if( aFloatSz
.Width() < aParentSz
.Width() )
2925 aFloatSz
.setWidth( aParentSz
.Width() );
2927 // align height to entries...
2928 tools::Long nInnerHeight
= aFloatSz
.Height() - nTop
- nBottom
;
2929 tools::Long nEntryHeight
= mpImplLB
->GetEntryHeightWithMargin();
2930 if ( nInnerHeight
% nEntryHeight
)
2932 nInnerHeight
/= nEntryHeight
;
2934 nInnerHeight
*= nEntryHeight
;
2935 aFloatSz
.setHeight( nInnerHeight
+ nTop
+ nBottom
);
2938 if (aFloatSz
.Width() < aSz
.Width())
2940 // The max width of list box entries exceeds the window width.
2941 // Account for the scroll bar height.
2942 tools::Long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2943 aFloatSz
.AdjustHeight(nSBWidth
);
2949 void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking
)
2951 if( IsInPopupMode() )
2954 Size aFloatSz
= CalcFloatSize();
2956 SetSizePixel( aFloatSz
);
2957 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
2959 sal_Int32 nPos
= mpImplLB
->GetEntryList()->GetSelectedEntryPos( 0 );
2960 mnPopupModeStartSaveSelection
= nPos
;
2962 Size aSz
= GetParent()->GetSizePixel();
2963 Point aPos
= GetParent()->GetPosPixel();
2964 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2965 // FIXME: this ugly hack is for Mac/Aqua
2966 // should be replaced by a real mechanism to place the float rectangle
2967 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2968 GetParent()->IsNativeWidgetEnabled() )
2970 const sal_Int32 nLeft
= 4, nTop
= 4, nRight
= 4, nBottom
= 4;
2971 aPos
.AdjustX(nLeft
);
2972 aPos
.AdjustY(nTop
);
2973 aSz
.AdjustWidth( -(nLeft
+ nRight
) );
2974 aSz
.AdjustHeight( -(nTop
+ nBottom
) );
2976 tools::Rectangle
aRect( aPos
, aSz
);
2978 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
2979 // where the document is unmirrored
2980 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
2981 vcl::Window
*pGrandparent
= GetParent()->GetParent();
2982 const OutputDevice
*pGrandparentOutDev
= pGrandparent
->GetOutDev();
2984 if( pGrandparent
->ImplIsAntiparallel() )
2985 pGrandparentOutDev
->ReMirror( aRect
);
2987 // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795
2988 StartPopupMode( aRect
, FloatWinPopupFlags::Down
| FloatWinPopupFlags::NoHorzPlacement
| FloatWinPopupFlags::AllMouseButtonClose
);
2990 if( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
2991 mpImplLB
->ShowProminentEntry( nPos
);
2993 if( bStartTracking
)
2994 mpImplLB
->GetMainWindow()->EnableMouseMoveSelect( true );
2996 if ( mpImplLB
->GetMainWindow()->IsGrabFocusAllowed() )
2997 mpImplLB
->GetMainWindow()->GrabFocus();
2999 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
3003 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */