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/lstbox.hxx>
27 #include <vcl/i18nhelp.hxx>
29 #include <listbox.hxx>
30 #include <controldata.hxx>
34 #include <com/sun/star/accessibility/AccessibleRole.hpp>
36 #include <rtl/instance.hxx>
37 #include <sal/log.hxx>
38 #include <osl/diagnose.h>
39 #include <comphelper/string.hxx>
40 #include <comphelper/processfactory.hxx>
44 #define MULTILINE_ENTRY_DRAW_FLAGS ( DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags::VCenter )
46 using namespace ::com::sun::star
;
48 static constexpr long gnBorder
= 1;
50 void ImplInitDropDownButton( PushButton
* pButton
)
52 pButton
->SetSymbol( SymbolType::SPIN_DOWN
);
54 if ( pButton
->IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
55 && ! pButton
->IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
56 pButton
->SetBackground();
59 ImplEntryList::ImplEntryList( vcl::Window
* pWindow
)
62 mnLastSelected
= LISTBOX_ENTRY_NOTFOUND
;
63 mnSelectionAnchor
= LISTBOX_ENTRY_NOTFOUND
;
65 mbCallSelectionChangedHdl
= true;
71 ImplEntryList::~ImplEntryList()
76 void ImplEntryList::Clear()
82 void ImplEntryList::SelectEntry( sal_Int32 nPos
, bool bSelect
)
84 if (0 <= nPos
&& static_cast<size_t>(nPos
) < maEntries
.size())
86 std::vector
<std::unique_ptr
<ImplEntryType
> >::iterator iter
= maEntries
.begin()+nPos
;
88 if ( ( (*iter
)->mbIsSelected
!= bSelect
) &&
89 ( ( (*iter
)->mnFlags
& ListBoxEntryFlags::DisableSelection
) == ListBoxEntryFlags::NONE
) )
91 (*iter
)->mbIsSelected
= bSelect
;
92 if ( mbCallSelectionChangedHdl
)
93 maSelectionChangedHdl
.Call( nPos
);
101 : public rtl::StaticWithInit
< comphelper::string::NaturalStringSorter
, theSorter
>
103 comphelper::string::NaturalStringSorter
operator () ()
105 return comphelper::string::NaturalStringSorter(
106 ::comphelper::getProcessComponentContext(),
107 Application::GetSettings().GetLanguageTag().getLocale());
112 sal_Int32
ListBox::NaturalSortCompare(const OUString
&rA
, const OUString
&rB
)
114 const comphelper::string::NaturalStringSorter
&rSorter
= theSorter::get();
115 return rSorter
.compare(rA
, rB
);
118 sal_Int32
ImplEntryList::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
, bool bSort
)
121 assert(maEntries
.size() < LISTBOX_MAX_ENTRIES
);
123 if ( !!pNewEntry
->maImage
)
126 sal_Int32 insPos
= 0;
127 const sal_Int32 nEntriesSize
= static_cast<sal_Int32
>(maEntries
.size());
129 if ( !bSort
|| maEntries
.empty())
131 if (0 <= nPos
&& nPos
< nEntriesSize
)
134 maEntries
.insert( maEntries
.begin() + nPos
, std::unique_ptr
<ImplEntryType
>(pNewEntry
) );
138 insPos
= nEntriesSize
;
139 maEntries
.push_back(std::unique_ptr
<ImplEntryType
>(pNewEntry
));
144 const comphelper::string::NaturalStringSorter
&rSorter
= theSorter::get();
146 const OUString
& rStr
= pNewEntry
->maStr
;
148 ImplEntryType
* pTemp
= GetEntry( nEntriesSize
-1 );
152 sal_Int32 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
154 // fast insert for sorted data
157 insPos
= nEntriesSize
;
158 maEntries
.push_back(std::unique_ptr
<ImplEntryType
>(pNewEntry
));
162 pTemp
= GetEntry( mnMRUCount
);
164 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
168 maEntries
.insert(maEntries
.begin(), std::unique_ptr
<ImplEntryType
>(pNewEntry
));
172 sal_uLong nLow
= mnMRUCount
;
173 sal_uLong nHigh
= maEntries
.size()-1;
179 nMid
= static_cast<sal_Int32
>((nLow
+ nHigh
) / 2);
180 pTemp
= GetEntry( nMid
);
182 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
194 while ( nLow
<= nHigh
);
200 maEntries
.insert(maEntries
.begin()+nMid
, std::unique_ptr
<ImplEntryType
>(pNewEntry
));
204 catch (uno::RuntimeException
& )
206 // XXX this is arguable, if the exception occurred because pNewEntry is
207 // garbage you wouldn't insert it. If the exception occurred because the
208 // Collator implementation is garbage then give the user a chance to see
211 maEntries
.insert(maEntries
.begin(), std::unique_ptr
<ImplEntryType
>(pNewEntry
));
219 void ImplEntryList::RemoveEntry( sal_Int32 nPos
)
221 if (0 <= nPos
&& static_cast<size_t>(nPos
) < maEntries
.size())
223 std::vector
<std::unique_ptr
<ImplEntryType
> >::iterator iter
= maEntries
.begin()+ nPos
;
225 if ( !!(*iter
)->maImage
)
228 maEntries
.erase(iter
);
232 sal_Int32
ImplEntryList::FindEntry( const OUString
& rString
, bool bSearchMRUArea
) const
234 const sal_Int32 nEntries
= static_cast<sal_Int32
>(maEntries
.size());
235 for ( sal_Int32 n
= bSearchMRUArea
? 0 : GetMRUCount(); n
< nEntries
; n
++ )
237 OUString
aComp( vcl::I18nHelper::filterFormattingChars( maEntries
[n
]->maStr
) );
238 if ( aComp
== rString
)
241 return LISTBOX_ENTRY_NOTFOUND
;
244 sal_Int32
ImplEntryList::FindMatchingEntry( const OUString
& rStr
, sal_Int32 nStart
, bool bLazy
) const
246 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
247 sal_Int32 nEntryCount
= GetEntryCount();
249 const vcl::I18nHelper
& rI18nHelper
= mpWindow
->GetSettings().GetLocaleI18nHelper();
250 for ( sal_Int32 n
= nStart
; n
< nEntryCount
; )
252 ImplEntryType
* pImplEntry
= GetEntry( n
);
256 bMatch
= rI18nHelper
.MatchString( rStr
, pImplEntry
->maStr
);
260 bMatch
= pImplEntry
->maStr
.startsWith(rStr
);
274 sal_Int32
ImplEntryList::FindEntry( const void* pData
) const
276 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
277 for ( sal_Int32 n
= GetEntryCount(); n
; )
279 ImplEntryType
* pImplEntry
= GetEntry( --n
);
280 if ( pImplEntry
->mpUserData
== pData
)
289 long ImplEntryList::GetAddedHeight( sal_Int32 i_nEndIndex
, sal_Int32 i_nBeginIndex
) const
292 sal_Int32 nStart
= std::min(i_nEndIndex
, i_nBeginIndex
);
293 sal_Int32 nStop
= std::max(i_nEndIndex
, i_nBeginIndex
);
294 sal_Int32 nEntryCount
= GetEntryCount();
295 if( 0 <= nStop
&& nStop
!= LISTBOX_ENTRY_NOTFOUND
&& nEntryCount
!= 0 )
298 if( nStop
> nEntryCount
-1 )
299 nStop
= nEntryCount
-1;
302 else if( nStart
> nEntryCount
-1 )
303 nStart
= nEntryCount
-1;
305 sal_Int32 nIndex
= nStart
;
306 while( nIndex
!= LISTBOX_ENTRY_NOTFOUND
&& nIndex
< nStop
)
308 long nPosHeight
= GetEntryPtr( nIndex
)->getHeightWithMargin();
309 if (nHeight
> ::std::numeric_limits
<long>::max() - nPosHeight
)
311 SAL_WARN( "vcl", "ImplEntryList::GetAddedHeight: truncated");
314 nHeight
+= nPosHeight
;
320 return i_nEndIndex
> i_nBeginIndex
? nHeight
: -nHeight
;
323 long ImplEntryList::GetEntryHeight( sal_Int32 nPos
) const
325 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
326 return pImplEntry
? pImplEntry
->getHeightWithMargin() : 0;
329 OUString
ImplEntryList::GetEntryText( sal_Int32 nPos
) const
332 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
334 aEntryText
= pImplEntry
->maStr
;
338 bool ImplEntryList::HasEntryImage( sal_Int32 nPos
) const
341 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
343 bImage
= !!pImplEntry
->maImage
;
347 Image
ImplEntryList::GetEntryImage( sal_Int32 nPos
) const
350 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
352 aImage
= pImplEntry
->maImage
;
356 void ImplEntryList::SetEntryData( sal_Int32 nPos
, void* pNewData
)
358 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
360 pImplEntry
->mpUserData
= pNewData
;
363 void* ImplEntryList::GetEntryData( sal_Int32 nPos
) const
365 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
366 return pImplEntry
? pImplEntry
->mpUserData
: nullptr;
369 void ImplEntryList::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
371 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
373 pImplEntry
->mnFlags
= nFlags
;
376 ListBoxEntryFlags
ImplEntryList::GetEntryFlags( sal_Int32 nPos
) const
378 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
379 return pImplEntry
? pImplEntry
->mnFlags
: ListBoxEntryFlags::NONE
;
382 sal_Int32
ImplEntryList::GetSelectedEntryCount() const
384 sal_Int32 nSelCount
= 0;
385 for ( sal_Int32 n
= GetEntryCount(); n
; )
387 ImplEntryType
* pImplEntry
= GetEntry( --n
);
388 if ( pImplEntry
->mbIsSelected
)
394 OUString
ImplEntryList::GetSelectedEntry( sal_Int32 nIndex
) const
396 return GetEntryText( GetSelectedEntryPos( nIndex
) );
399 sal_Int32
ImplEntryList::GetSelectedEntryPos( sal_Int32 nIndex
) const
401 sal_Int32 nSelEntryPos
= LISTBOX_ENTRY_NOTFOUND
;
403 sal_Int32 nEntryCount
= GetEntryCount();
405 for ( sal_Int32 n
= 0; n
< nEntryCount
; n
++ )
407 ImplEntryType
* pImplEntry
= GetEntry( n
);
408 if ( pImplEntry
->mbIsSelected
)
410 if ( nSel
== nIndex
)
422 bool ImplEntryList::IsEntryPosSelected( sal_Int32 nIndex
) const
424 ImplEntryType
* pImplEntry
= GetEntry( nIndex
);
425 return pImplEntry
&& pImplEntry
->mbIsSelected
;
428 bool ImplEntryList::IsEntrySelectable( sal_Int32 nPos
) const
430 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
431 return pImplEntry
== nullptr || ((pImplEntry
->mnFlags
& ListBoxEntryFlags::DisableSelection
) == ListBoxEntryFlags::NONE
);
434 sal_Int32
ImplEntryList::FindFirstSelectable( sal_Int32 nPos
, bool bForward
/* = true */ )
436 if( IsEntrySelectable( nPos
) )
441 for( nPos
= nPos
+ 1; nPos
< GetEntryCount(); nPos
++ )
443 if( IsEntrySelectable( nPos
) )
452 if( IsEntrySelectable( nPos
) )
457 return LISTBOX_ENTRY_NOTFOUND
;
460 ImplListBoxWindow::ImplListBoxWindow( vcl::Window
* pParent
, WinBits nWinStyle
) :
461 Control( pParent
, 0 ),
462 maQuickSelectionEngine( *this )
464 mpEntryList
.reset(new ImplEntryList( this ));
468 mnSelectModifier
= 0;
469 mnUserDrawEntry
= LISTBOX_ENTRY_NOTFOUND
;
471 mbTravelSelect
= false;
472 mbTrackingSelect
= false;
473 mbSelectionChanged
= false;
474 mbMouseMoveSelect
= false;
478 mbUserDrawEnabled
= false;
479 mbInUserDraw
= false;
481 mbHasFocusRect
= false;
482 mbRight
= ( nWinStyle
& WB_RIGHT
);
483 mbCenter
= ( nWinStyle
& WB_CENTER
);
484 mbSimpleMode
= ( nWinStyle
& WB_SIMPLEMODE
);
485 mbSort
= ( nWinStyle
& WB_SORT
);
486 mbIsComboboxDropdown
= ( nWinStyle
& WB_DROPDOWN
);
487 mbEdgeBlending
= false;
489 // pb: #106948# explicit mirroring for calc
492 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
493 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
494 meProminentType
= ProminentEntry::TOP
;
498 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
500 ApplySettings(*this);
504 ImplListBoxWindow::~ImplListBoxWindow()
509 void ImplListBoxWindow::dispose()
515 void ImplListBoxWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
517 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
519 ApplyControlFont(rRenderContext
, rStyleSettings
.GetFieldFont());
520 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetFieldTextColor());
522 if (IsControlBackground())
523 rRenderContext
.SetBackground(GetControlBackground());
525 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
528 void ImplListBoxWindow::ImplCalcMetrics()
536 mnTextHeight
= static_cast<sal_uInt16
>(GetTextHeight());
537 mnMaxTxtHeight
= mnTextHeight
+ gnBorder
;
538 mnMaxHeight
= mnMaxTxtHeight
;
540 if ( maUserItemSize
.Height() > mnMaxHeight
)
541 mnMaxHeight
= static_cast<sal_uInt16
>(maUserItemSize
.Height());
542 if ( maUserItemSize
.Width() > mnMaxWidth
)
543 mnMaxWidth
= static_cast<sal_uInt16
>(maUserItemSize
.Width());
545 for ( sal_Int32 n
= mpEntryList
->GetEntryCount(); n
; )
547 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( --n
);
548 ImplUpdateEntryMetrics( *pEntry
);
551 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
553 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryPtr( mnCurrentPos
)->getHeightWithMargin() );
554 maFocusRect
.SetSize( aSz
);
558 void ImplListBoxWindow::Clear()
560 mpEntryList
->Clear();
562 mnMaxHeight
= mnMaxTxtHeight
;
570 ImplClearLayoutData();
572 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
573 maQuickSelectionEngine
.Reset();
578 void ImplListBoxWindow::SetUserItemSize( const Size
& rSz
)
580 ImplClearLayoutData();
581 maUserItemSize
= rSz
;
585 struct ImplEntryMetrics
596 long ImplEntryType::getHeightWithMargin() const
598 return mnHeight
+ ImplGetSVData()->maNWFData
.mnListBoxEntryMargin
;
601 SalLayoutGlyphs
* ImplEntryType::GetTextGlyphs(const OutputDevice
* pOutputDevice
)
603 if (maStrGlyphs
.IsValid())
604 // Use pre-calculated result.
607 std::unique_ptr
<SalLayout
> pLayout
= pOutputDevice
->ImplLayout(
608 maStr
, 0, maStr
.getLength(), Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly
);
612 const SalLayoutGlyphs
* pGlyphs
= pLayout
->GetGlyphs();
616 // Remember the calculation result.
617 maStrGlyphs
= *pGlyphs
;
622 void ImplListBoxWindow::EnableQuickSelection( bool b
)
624 maQuickSelectionEngine
.SetEnabled( b
);
627 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType
& rEntry
)
629 ImplEntryMetrics aMetrics
;
630 aMetrics
.bText
= !rEntry
.maStr
.isEmpty();
631 aMetrics
.bImage
= !!rEntry
.maImage
;
632 aMetrics
.nEntryWidth
= 0;
633 aMetrics
.nEntryHeight
= 0;
634 aMetrics
.nTextWidth
= 0;
635 aMetrics
.nImgWidth
= 0;
636 aMetrics
.nImgHeight
= 0;
638 if ( aMetrics
.bText
)
640 if( rEntry
.mnFlags
& ListBoxEntryFlags::MultiLine
)
643 Size
aCurSize( PixelToLogic( GetSizePixel() ) );
644 // set the current size to a large number
645 // GetTextRect should shrink it to the actual size
646 aCurSize
.setHeight( 0x7fffff );
647 tools::Rectangle
aTextRect( Point( 0, 0 ), aCurSize
);
648 aTextRect
= GetTextRect( aTextRect
, rEntry
.maStr
, DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
);
649 aMetrics
.nTextWidth
= aTextRect
.GetWidth();
650 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
651 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
652 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
653 aMetrics
.nEntryHeight
= aTextRect
.GetHeight() + gnBorder
;
657 // normal single line case
658 const SalLayoutGlyphs
* pGlyphs
= rEntry
.GetTextGlyphs(this);
660 = static_cast<sal_uInt16
>(GetTextWidth(rEntry
.maStr
, 0, -1, nullptr, pGlyphs
));
661 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
662 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
663 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
664 aMetrics
.nEntryHeight
= mnTextHeight
+ gnBorder
;
667 if ( aMetrics
.bImage
)
669 Size aImgSz
= rEntry
.maImage
.GetSizePixel();
670 aMetrics
.nImgWidth
= static_cast<sal_uInt16
>(CalcZoom( aImgSz
.Width() ));
671 aMetrics
.nImgHeight
= static_cast<sal_uInt16
>(CalcZoom( aImgSz
.Height() ));
673 if( aMetrics
.nImgWidth
> mnMaxImgWidth
)
674 mnMaxImgWidth
= aMetrics
.nImgWidth
;
675 if( aMetrics
.nImgHeight
> mnMaxImgHeight
)
676 mnMaxImgHeight
= aMetrics
.nImgHeight
;
678 mnMaxImgTxtWidth
= std::max( mnMaxImgTxtWidth
, aMetrics
.nTextWidth
);
679 aMetrics
.nEntryHeight
= std::max( aMetrics
.nImgHeight
, aMetrics
.nEntryHeight
);
682 if ( IsUserDrawEnabled() || aMetrics
.bImage
)
684 aMetrics
.nEntryWidth
= std::max( aMetrics
.nImgWidth
, maUserItemSize
.Width() );
685 if ( aMetrics
.bText
)
686 aMetrics
.nEntryWidth
+= aMetrics
.nTextWidth
+ IMG_TXT_DISTANCE
;
687 aMetrics
.nEntryHeight
= std::max( std::max( mnMaxImgHeight
, maUserItemSize
.Height() ) + 2,
688 aMetrics
.nEntryHeight
);
691 if ( !aMetrics
.bText
&& !aMetrics
.bImage
&& !IsUserDrawEnabled() )
693 // entries which have no (aka an empty) text, and no image,
694 // and are not user-drawn, should be shown nonetheless
695 aMetrics
.nEntryHeight
= mnTextHeight
+ gnBorder
;
698 if ( aMetrics
.nEntryWidth
> mnMaxWidth
)
699 mnMaxWidth
= aMetrics
.nEntryWidth
;
700 if ( aMetrics
.nEntryHeight
> mnMaxHeight
)
701 mnMaxHeight
= aMetrics
.nEntryHeight
;
703 rEntry
.mnHeight
= aMetrics
.nEntryHeight
;
706 void ImplListBoxWindow::ImplCallSelect()
708 if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
710 // Insert the selected entry as MRU, if not already first MRU
711 sal_Int32 nSelected
= GetEntryList()->GetSelectedEntryPos( 0 );
712 sal_Int32 nMRUCount
= GetEntryList()->GetMRUCount();
713 OUString aSelected
= GetEntryList()->GetEntryText( nSelected
);
714 sal_Int32 nFirstMatchingEntryPos
= GetEntryList()->FindEntry( aSelected
, true );
715 if ( nFirstMatchingEntryPos
|| !nMRUCount
)
717 bool bSelectNewEntry
= false;
718 if ( nFirstMatchingEntryPos
< nMRUCount
)
720 RemoveEntry( nFirstMatchingEntryPos
);
722 if ( nFirstMatchingEntryPos
== nSelected
)
723 bSelectNewEntry
= true;
725 else if ( nMRUCount
== GetEntryList()->GetMaxMRUCount() )
727 RemoveEntry( nMRUCount
- 1 );
731 ImplClearLayoutData();
733 ImplEntryType
* pNewEntry
= new ImplEntryType( aSelected
);
734 pNewEntry
->mbIsSelected
= bSelectNewEntry
;
735 GetEntryList()->InsertEntry( 0, pNewEntry
, false );
736 ImplUpdateEntryMetrics( *pNewEntry
);
737 GetEntryList()->SetMRUCount( ++nMRUCount
);
738 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
739 maMRUChangedHdl
.Call( nullptr );
743 maSelectHdl
.Call( nullptr );
744 mbSelectionChanged
= false;
747 sal_Int32
ImplListBoxWindow::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
)
750 assert(mpEntryList
->GetEntryCount() < LISTBOX_MAX_ENTRIES
);
752 ImplClearLayoutData();
753 sal_Int32 nNewPos
= mpEntryList
->InsertEntry( nPos
, pNewEntry
, mbSort
);
755 if( GetStyle() & WB_WORDBREAK
)
756 pNewEntry
->mnFlags
|= ListBoxEntryFlags::MultiLine
;
758 ImplUpdateEntryMetrics( *pNewEntry
);
762 void ImplListBoxWindow::RemoveEntry( sal_Int32 nPos
)
764 ImplClearLayoutData();
765 mpEntryList
->RemoveEntry( nPos
);
766 if( mnCurrentPos
>= mpEntryList
->GetEntryCount() )
767 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
771 void ImplListBoxWindow::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
773 mpEntryList
->SetEntryFlags( nPos
, nFlags
);
774 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( nPos
);
776 ImplUpdateEntryMetrics( *pEntry
);
779 void ImplListBoxWindow::ImplShowFocusRect()
781 if ( mbHasFocusRect
)
783 ShowFocus( maFocusRect
);
784 mbHasFocusRect
= true;
787 void ImplListBoxWindow::ImplHideFocusRect()
789 if ( mbHasFocusRect
)
792 mbHasFocusRect
= false;
796 sal_Int32
ImplListBoxWindow::GetEntryPosForPoint( const Point
& rPoint
) const
800 sal_Int32 nSelect
= mnTop
;
801 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nSelect
);
804 long nEntryHeight
= pEntry
->getHeightWithMargin();
805 if (rPoint
.Y() <= nEntryHeight
+ nY
)
808 pEntry
= mpEntryList
->GetEntryPtr( ++nSelect
);
810 if( pEntry
== nullptr )
811 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
816 bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry
) const
820 if( i_nEntry
>= mnTop
)
822 if( mpEntryList
->GetAddedHeight( i_nEntry
, mnTop
) <
823 PixelToLogic( GetSizePixel() ).Height() )
832 long ImplListBoxWindow::GetEntryHeightWithMargin() const
834 long nMargin
= ImplGetSVData()->maNWFData
.mnListBoxEntryMargin
;
835 return mnMaxHeight
+ nMargin
;
838 sal_Int32
ImplListBoxWindow::GetLastVisibleEntry() const
840 sal_Int32 nPos
= mnTop
;
841 long nWindowHeight
= GetSizePixel().Height();
842 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
844 for( nDiff
= 0; nDiff
< nWindowHeight
&& nPos
< nCount
; nDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
) )
847 if( nDiff
> nWindowHeight
&& nPos
> mnTop
)
856 void ImplListBoxWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
858 mbMouseMoveSelect
= false; // only till the first MouseButtonDown
859 maQuickSelectionEngine
.Reset();
863 if( rMEvt
.GetClicks() == 1 )
865 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
866 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
868 if ( !mbMulti
&& GetEntryList()->GetSelectedEntryCount() )
869 mnTrackingSaveSelection
= GetEntryList()->GetSelectedEntryPos( 0 );
871 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
873 mnCurrentPos
= nSelect
;
874 mbTrackingSelect
= true;
875 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
876 (void)SelectEntries( nSelect
, LET_MBDOWN
, rMEvt
.IsShift(), rMEvt
.IsMod1() ,bCurPosChange
);
877 mbTrackingSelect
= false;
881 StartTracking( StartTrackingFlags::ScrollRepeat
);
884 if( rMEvt
.GetClicks() == 2 )
886 maDoubleClickHdl
.Call( this );
889 else // if ( mbGrabFocus )
895 void ImplListBoxWindow::MouseMove( const MouseEvent
& rMEvt
)
897 if ( rMEvt
.IsLeaveWindow() )
899 if ( mbStackMode
&& IsMouseMoveSelect() && IsReallyVisible() )
901 if ( rMEvt
.GetPosPixel().Y() < 0 )
904 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
908 mbTravelSelect
= true;
909 mnSelectModifier
= rMEvt
.GetModifier();
911 mbTravelSelect
= false;
917 else if ( ( ( !mbMulti
&& IsMouseMoveSelect() ) || mbStackMode
) && mpEntryList
->GetEntryCount() )
919 tools::Rectangle
aRect( Point(), GetOutputSizePixel() );
920 if( aRect
.IsInside( rMEvt
.GetPosPixel() ) )
922 if ( IsMouseMoveSelect() )
924 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
925 if( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
926 nSelect
= mpEntryList
->GetEntryCount() - 1;
927 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
928 nSelect
= std::min( nSelect
, static_cast<sal_Int32
>( mpEntryList
->GetEntryCount() - 1 ) );
929 // Select only visible Entries with MouseMove, otherwise Tracking...
930 if ( IsVisible( nSelect
) &&
931 mpEntryList
->IsEntrySelectable( nSelect
) &&
932 ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectedEntryCount() || ( nSelect
!= GetEntryList()->GetSelectedEntryPos( 0 ) ) ) )
934 mbTrackingSelect
= true;
935 if ( SelectEntries( nSelect
, LET_TRACKING
) )
939 mbTravelSelect
= true;
940 mnSelectModifier
= rMEvt
.GetModifier();
942 mbTravelSelect
= false;
944 // When list box selection change by mouse move, notify
945 // VclEventId::ListboxSelect vcl event.
948 maListItemSelectHdl
.Call(nullptr);
951 mbTrackingSelect
= false;
955 // if the DD button was pressed and someone moved into the ListBox
956 // with the mouse button pressed...
957 if ( rMEvt
.IsLeft() && !rMEvt
.IsSynthetic() )
959 if ( !mbMulti
&& GetEntryList()->GetSelectedEntryCount() )
960 mnTrackingSaveSelection
= GetEntryList()->GetSelectedEntryPos( 0 );
962 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
964 if ( mbStackMode
&& ( mpEntryList
->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND
) )
965 mpEntryList
->SetSelectionAnchor( 0 );
967 StartTracking( StartTrackingFlags::ScrollRepeat
);
973 void ImplListBoxWindow::DeselectAll()
975 while ( GetEntryList()->GetSelectedEntryCount() )
977 sal_Int32 nS
= GetEntryList()->GetSelectedEntryPos( 0 );
978 SelectEntry( nS
, false );
982 void ImplListBoxWindow::SelectEntry( sal_Int32 nPos
, bool bSelect
)
984 if( (mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
) && mpEntryList
->IsEntrySelectable( nPos
) )
991 // deselect the selected entry
992 sal_Int32 nDeselect
= GetEntryList()->GetSelectedEntryPos( 0 );
993 if( nDeselect
!= LISTBOX_ENTRY_NOTFOUND
)
995 //SelectEntryPos( nDeselect, false );
996 GetEntryList()->SelectEntry( nDeselect
, false );
997 if (IsUpdateMode() && IsReallyVisible())
1001 mpEntryList
->SelectEntry( nPos
, true );
1002 mnCurrentPos
= nPos
;
1003 if ( ( nPos
!= LISTBOX_ENTRY_NOTFOUND
) && IsUpdateMode() )
1006 if ( !IsVisible( nPos
) )
1008 ImplClearLayoutData();
1009 sal_Int32 nVisibleEntries
= GetLastVisibleEntry()-mnTop
;
1010 if ( !nVisibleEntries
|| !IsReallyVisible() || ( nPos
< GetTopEntry() ) )
1013 ShowProminentEntry( nPos
);
1017 ShowProminentEntry( nPos
);
1024 mpEntryList
->SelectEntry( nPos
, false );
1027 mbSelectionChanged
= true;
1031 bool ImplListBoxWindow::SelectEntries( sal_Int32 nSelect
, LB_EVENT_TYPE eLET
, bool bShift
, bool bCtrl
, bool bSelectPosChange
/*=FALSE*/ )
1033 bool bSelectionChanged
= false;
1035 if( IsEnabled() && mpEntryList
->IsEntrySelectable( nSelect
) )
1037 bool bFocusChanged
= false;
1039 // here (Single-ListBox) only one entry can be deselected
1042 sal_Int32 nDeselect
= mpEntryList
->GetSelectedEntryPos( 0 );
1043 if( nSelect
!= nDeselect
)
1045 SelectEntry( nSelect
, true );
1046 mpEntryList
->SetLastSelected( nSelect
);
1047 bFocusChanged
= true;
1048 bSelectionChanged
= true;
1051 // MultiListBox without Modifier
1052 else if( mbSimpleMode
&& !bCtrl
&& !bShift
)
1054 sal_Int32 nEntryCount
= mpEntryList
->GetEntryCount();
1055 for ( sal_Int32 nPos
= 0; nPos
< nEntryCount
; nPos
++ )
1057 bool bSelect
= nPos
== nSelect
;
1058 if ( mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
)
1060 SelectEntry( nPos
, bSelect
);
1061 bFocusChanged
= true;
1062 bSelectionChanged
= true;
1065 mpEntryList
->SetLastSelected( nSelect
);
1066 mpEntryList
->SetSelectionAnchor( nSelect
);
1068 // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1069 else if( ( !mbSimpleMode
/* && !bShift */ ) || ( (mbSimpleMode
&& ( bCtrl
|| bShift
)) || mbStackMode
) )
1071 // Space for selection change
1072 if( !bShift
&& ( ( eLET
== LET_KEYSPACE
) || ( eLET
== LET_MBDOWN
) ) )
1074 bool bSelect
= ( mbStackMode
&& IsMouseMoveSelect() ) || !mpEntryList
->IsEntryPosSelected( nSelect
);
1080 // All entries before nSelect must be selected...
1081 for ( n
= 0; n
< nSelect
; n
++ )
1082 SelectEntry( n
, true );
1086 for ( n
= nSelect
+1; n
< mpEntryList
->GetEntryCount(); n
++ )
1087 SelectEntry( n
, false );
1090 SelectEntry( nSelect
, bSelect
);
1091 mpEntryList
->SetLastSelected( nSelect
);
1092 mpEntryList
->SetSelectionAnchor( mbStackMode
? 0 : nSelect
);
1093 if ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1094 mpEntryList
->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND
);
1095 bFocusChanged
= true;
1096 bSelectionChanged
= true;
1098 else if( ( ( eLET
== LET_TRACKING
) && ( nSelect
!= mnCurrentPos
) ) ||
1099 ( (bShift
||mbStackMode
) && ( ( eLET
== LET_KEYMOVE
) || ( eLET
== LET_MBDOWN
) ) ) )
1101 mnCurrentPos
= nSelect
;
1102 bFocusChanged
= true;
1104 sal_Int32 nAnchor
= mpEntryList
->GetSelectionAnchor();
1105 if( ( nAnchor
== LISTBOX_ENTRY_NOTFOUND
) && ( mpEntryList
->GetSelectedEntryCount() || mbStackMode
) )
1107 nAnchor
= mbStackMode
? 0 : mpEntryList
->GetSelectedEntryPos( mpEntryList
->GetSelectedEntryCount() - 1 );
1109 if( nAnchor
!= LISTBOX_ENTRY_NOTFOUND
)
1111 // All entries from Anchor to nSelect have to be selected
1112 sal_Int32 nStart
= std::min( nSelect
, nAnchor
);
1113 sal_Int32 nEnd
= std::max( nSelect
, nAnchor
);
1114 for ( sal_Int32 n
= nStart
; n
<= nEnd
; n
++ )
1116 if ( !mpEntryList
->IsEntryPosSelected( n
) )
1118 SelectEntry( n
, true );
1119 bSelectionChanged
= true;
1123 // if appropriate some more has to be deselected...
1124 sal_Int32 nLast
= mpEntryList
->GetLastSelected();
1125 if ( nLast
!= LISTBOX_ENTRY_NOTFOUND
)
1127 if ( ( nLast
> nSelect
) && ( nLast
> nAnchor
) )
1129 for ( sal_Int32 n
= nSelect
+1; n
<= nLast
; n
++ )
1131 if ( mpEntryList
->IsEntryPosSelected( n
) )
1133 SelectEntry( n
, false );
1134 bSelectionChanged
= true;
1138 else if ( ( nLast
< nSelect
) && ( nLast
< nAnchor
) )
1140 for ( sal_Int32 n
= nLast
; n
< nSelect
; n
++ )
1142 if ( mpEntryList
->IsEntryPosSelected( n
) )
1144 SelectEntry( n
, false );
1145 bSelectionChanged
= true;
1150 mpEntryList
->SetLastSelected( nSelect
);
1153 else if( eLET
!= LET_TRACKING
)
1155 ImplHideFocusRect();
1157 bFocusChanged
= true;
1162 bFocusChanged
= true;
1165 if( bSelectionChanged
)
1166 mbSelectionChanged
= true;
1170 long nHeightDiff
= mpEntryList
->GetAddedHeight( nSelect
, mnTop
);
1171 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1172 Size
aSz( maFocusRect
.GetWidth(),
1173 mpEntryList
->GetEntryHeight( nSelect
) );
1174 maFocusRect
.SetSize( aSz
);
1176 ImplShowFocusRect();
1177 if (bSelectPosChange
)
1179 maFocusHdl
.Call(nSelect
);
1182 ImplClearLayoutData();
1184 return bSelectionChanged
;
1187 void ImplListBoxWindow::Tracking( const TrackingEvent
& rTEvt
)
1189 tools::Rectangle
aRect( Point(), GetOutputSizePixel() );
1190 bool bInside
= aRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() );
1192 if( rTEvt
.IsTrackingCanceled() || rTEvt
.IsTrackingEnded() ) // MouseButtonUp
1194 if ( bInside
&& !rTEvt
.IsTrackingCanceled() )
1196 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1201 maCancelHdl
.Call( nullptr );
1204 mbTrackingSelect
= true;
1205 SelectEntry( mnTrackingSaveSelection
, true );
1206 mbTrackingSelect
= false;
1207 if ( mnTrackingSaveSelection
!= LISTBOX_ENTRY_NOTFOUND
)
1209 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
);
1210 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1211 Size
aSz( maFocusRect
.GetWidth(),
1212 mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1213 maFocusRect
.SetSize( aSz
);
1214 ImplShowFocusRect();
1223 bool bTrackOrQuickClick
= mbTrack
;
1231 // this case only happens, if the mouse button is pressed very briefly
1232 if( rTEvt
.IsTrackingEnded() && mbTrack
)
1234 bTrackOrQuickClick
= true;
1239 if( bTrackOrQuickClick
)
1241 MouseEvent aMEvt
= rTEvt
.GetMouseEvent();
1242 Point
aPt( aMEvt
.GetPosPixel() );
1243 bool bShift
= aMEvt
.IsShift();
1244 bool bCtrl
= aMEvt
.IsMod1();
1246 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1249 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1251 nSelect
= mnCurrentPos
? ( mnCurrentPos
- 1 ) : 0;
1252 if( nSelect
< mnTop
)
1253 SetTopEntry( mnTop
-1 );
1256 else if( aPt
.Y() > GetOutputSizePixel().Height() )
1258 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1260 nSelect
= std::min( static_cast<sal_Int32
>(mnCurrentPos
+1), static_cast<sal_Int32
>(mpEntryList
->GetEntryCount()-1) );
1261 if( nSelect
>= GetLastVisibleEntry() )
1262 SetTopEntry( mnTop
+1 );
1267 nSelect
= static_cast<sal_Int32
>( ( aPt
.Y() + gnBorder
) / mnMaxHeight
) + mnTop
;
1268 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
1269 nSelect
= std::min( nSelect
, static_cast<sal_Int32
>( mpEntryList
->GetEntryCount() - 1 ) );
1274 if ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectedEntryCount() )
1276 mbTrackingSelect
= true;
1277 if ( SelectEntries( nSelect
, LET_TRACKING
, bShift
, bCtrl
) )
1281 mbTravelSelect
= true;
1282 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1284 mbTravelSelect
= false;
1287 mbTrackingSelect
= false;
1292 if ( !mbMulti
&& GetEntryList()->GetSelectedEntryCount() )
1294 mbTrackingSelect
= true;
1295 SelectEntry( GetEntryList()->GetSelectedEntryPos( 0 ), false );
1296 mbTrackingSelect
= false;
1298 else if ( mbStackMode
)
1300 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt
.GetMouseEvent().GetPosPixel().X() < aRect
.Right() ) )
1302 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt
.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1304 bool bSelectionChanged
= false;
1305 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().Y() < 0 )
1308 if ( mpEntryList
->IsEntryPosSelected( 0 ) )
1310 SelectEntry( 0, false );
1311 bSelectionChanged
= true;
1312 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1318 mbTrackingSelect
= true;
1319 bSelectionChanged
= SelectEntries( nSelect
, LET_TRACKING
, bShift
, bCtrl
);
1320 mbTrackingSelect
= false;
1323 if ( bSelectionChanged
)
1325 mbSelectionChanged
= true;
1326 mbTravelSelect
= true;
1327 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1329 mbTravelSelect
= false;
1335 mnCurrentPos
= nSelect
;
1336 if ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1338 ImplHideFocusRect();
1342 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
);
1343 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1344 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1345 maFocusRect
.SetSize( aSz
);
1346 ImplShowFocusRect();
1352 void ImplListBoxWindow::KeyInput( const KeyEvent
& rKEvt
)
1354 if( !ProcessKeyInput( rKEvt
) )
1355 Control::KeyInput( rKEvt
);
1358 bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent
& rKEvt
)
1360 // entry to be selected
1361 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1362 LB_EVENT_TYPE eLET
= LET_KEYMOVE
;
1364 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1366 bool bShift
= aKeyCode
.IsShift();
1367 bool bCtrl
= aKeyCode
.IsMod1() || aKeyCode
.IsMod3();
1368 bool bMod2
= aKeyCode
.IsMod2();
1370 bool bHandleKey
= false;
1372 switch( aKeyCode
.GetCode() )
1378 if ( GetTopEntry() )
1379 SetTopEntry( GetTopEntry()-1 );
1383 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1385 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1387 else if ( mnCurrentPos
)
1389 // search first selectable above the current position
1390 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
- 1, false );
1393 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
< mnTop
) )
1394 SetTopEntry( mnTop
-1 );
1398 maQuickSelectionEngine
.Reset();
1406 SetTopEntry( GetTopEntry()+1 );
1410 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1412 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1414 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1416 // search first selectable below the current position
1417 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
+ 1 );
1420 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
>= GetLastVisibleEntry() ) )
1421 SetTopEntry( mnTop
+1 );
1425 maQuickSelectionEngine
.Reset();
1433 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1434 SetTopEntry( ( mnTop
> nCurVis
) ?
1435 (mnTop
-nCurVis
) : 0 );
1437 else if ( !bCtrl
&& !bMod2
)
1439 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1441 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1443 else if ( mnCurrentPos
)
1445 if( mnCurrentPos
== mnTop
)
1447 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1448 SetTopEntry( ( mnTop
> nCurVis
) ? ( mnTop
-nCurVis
+1 ) : 0 );
1451 // find first selectable starting from mnTop looking forward
1452 nSelect
= mpEntryList
->FindFirstSelectable( mnTop
);
1456 maQuickSelectionEngine
.Reset();
1464 SetTopEntry( GetLastVisibleEntry() );
1466 else if ( !bCtrl
&& !bMod2
)
1468 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1470 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1472 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1474 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1475 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
;
1476 sal_Int32 nTmp
= std::min( nCurVis
, nCount
);
1478 if( mnCurrentPos
== nTmp
&& mnCurrentPos
!= nCount
- 1 )
1480 long nTmp2
= std::min( static_cast<long>(nCount
-nCurVis
), static_cast<long>(static_cast<long>(mnTop
)+static_cast<long>(nCurVis
)-1) );
1481 nTmp2
= std::max( long(0) , nTmp2
);
1482 nTmp
= static_cast<sal_Int32
>(nTmp2
+(nCurVis
-1) );
1483 SetTopEntry( static_cast<sal_Int32
>(nTmp2
) );
1485 // find first selectable starting from nTmp looking backwards
1486 nSelect
= mpEntryList
->FindFirstSelectable( nTmp
, false );
1490 maQuickSelectionEngine
.Reset();
1500 else if ( !bCtrl
&& !bMod2
&& mnCurrentPos
)
1502 nSelect
= mpEntryList
->FindFirstSelectable( mpEntryList
->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND
);
1508 maQuickSelectionEngine
.Reset();
1516 SetTopEntry( 0xFFFF );
1518 else if ( !bCtrl
&& !bMod2
)
1520 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1522 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1524 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1526 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1527 nSelect
= mpEntryList
->FindFirstSelectable( nCount
- 1, false );
1528 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+ 1;
1529 if( nCount
> nCurVis
)
1530 SetTopEntry( nCount
- nCurVis
);
1534 maQuickSelectionEngine
.Reset();
1540 if ( !bCtrl
&& !bMod2
)
1542 ScrollHorz( -HORZ_SCROLL
);
1545 maQuickSelectionEngine
.Reset();
1551 if ( !bCtrl
&& !bMod2
)
1553 ScrollHorz( HORZ_SCROLL
);
1556 maQuickSelectionEngine
.Reset();
1562 if ( !bMod2
&& !IsReadOnly() )
1564 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1566 bDone
= false; // do not catch RETURN
1568 maQuickSelectionEngine
.Reset();
1574 if ( !bMod2
&& !IsReadOnly() )
1576 if( mbMulti
&& ( !mbSimpleMode
|| ( mbSimpleMode
&& bCtrl
&& !bShift
) || mbStackMode
) )
1578 nSelect
= mnCurrentPos
;
1579 eLET
= LET_KEYSPACE
;
1589 if( bCtrl
&& mbMulti
)
1592 bool bUpdates
= IsUpdateMode();
1593 SetUpdateMode( false );
1595 sal_Int32 nEntryCount
= mpEntryList
->GetEntryCount();
1596 for( sal_Int32 i
= 0; i
< nEntryCount
; i
++ )
1597 SelectEntry( i
, true );
1599 // restore update mode
1600 SetUpdateMode( bUpdates
);
1603 maQuickSelectionEngine
.Reset();
1618 if (bHandleKey
&& !IsReadOnly())
1620 bDone
= maQuickSelectionEngine
.HandleKeyEvent( rKEvt
);
1623 if ( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
1624 && ( ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1625 || ( eLET
== LET_KEYSPACE
)
1629 SAL_WARN_IF( mpEntryList
->IsEntryPosSelected( nSelect
) && !mbMulti
, "vcl", "ImplListBox: Selecting same Entry" );
1630 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1631 if (nSelect
>= nCount
)
1632 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1633 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
1634 mnCurrentPos
= nSelect
;
1635 if(SelectEntries( nSelect
, eLET
, bShift
, bCtrl
, bCurPosChange
))
1637 // tdf#129043 Correctly deliver events when changing values with arrow keys in combobox
1638 if (mbIsComboboxDropdown
&& IsReallyVisible())
1639 mbTravelSelect
= true;
1640 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1642 mbTravelSelect
= false;
1651 vcl::StringEntryIdentifier
lcl_getEntry( const ImplEntryList
& _rList
, sal_Int32 _nPos
, OUString
& _out_entryText
)
1653 OSL_PRECOND( ( _nPos
!= LISTBOX_ENTRY_NOTFOUND
), "lcl_getEntry: invalid position!" );
1654 sal_Int32
nEntryCount( _rList
.GetEntryCount() );
1655 if ( _nPos
>= nEntryCount
)
1657 _out_entryText
= _rList
.GetEntryText( _nPos
);
1659 // vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1661 return reinterpret_cast< vcl::StringEntryIdentifier
>( _nPos
+ 1 );
1664 sal_Int32
lcl_getEntryPos( vcl::StringEntryIdentifier _entry
)
1666 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1667 return static_cast< sal_Int32
>( reinterpret_cast< sal_Int64
>( _entry
) ) - 1;
1671 vcl::StringEntryIdentifier
ImplListBoxWindow::CurrentEntry( OUString
& _out_entryText
) const
1673 return lcl_getEntry( *GetEntryList(), ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
) ? 0 : mnCurrentPos
, _out_entryText
);
1676 vcl::StringEntryIdentifier
ImplListBoxWindow::NextEntry( vcl::StringEntryIdentifier _currentEntry
, OUString
& _out_entryText
) const
1678 sal_Int32 nNextPos
= lcl_getEntryPos( _currentEntry
) + 1;
1679 return lcl_getEntry( *GetEntryList(), nNextPos
, _out_entryText
);
1682 void ImplListBoxWindow::SelectEntry( vcl::StringEntryIdentifier _entry
)
1684 sal_Int32 nSelect
= lcl_getEntryPos( _entry
);
1685 if ( mpEntryList
->IsEntryPosSelected( nSelect
) )
1687 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1688 // to select the given entry by typing its starting letters. No need to act.
1693 OSL_ENSURE( nSelect
< mpEntryList
->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1694 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1695 if (nSelect
>= nCount
)
1696 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1699 ShowProminentEntry( nSelect
);
1702 mnCurrentPos
= nSelect
;
1703 if ( SelectEntries( nSelect
, LET_KEYMOVE
) )
1705 mbTravelSelect
= true;
1706 mnSelectModifier
= 0;
1708 mbTravelSelect
= false;
1712 void ImplListBoxWindow::ImplPaint(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
)
1714 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1716 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nPos
);
1720 long nWidth
= GetOutputSizePixel().Width();
1721 long nY
= mpEntryList
->GetAddedHeight(nPos
, mnTop
);
1722 tools::Rectangle
aRect(Point(0, nY
), Size(nWidth
, pEntry
->getHeightWithMargin()));
1724 if (mpEntryList
->IsEntryPosSelected(nPos
))
1726 rRenderContext
.SetTextColor(!IsEnabled() ? rStyleSettings
.GetDisableColor() : rStyleSettings
.GetHighlightTextColor());
1727 rRenderContext
.SetFillColor(rStyleSettings
.GetHighlightColor());
1728 rRenderContext
.SetLineColor();
1729 rRenderContext
.DrawRect(aRect
);
1733 ApplySettings(rRenderContext
);
1735 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
1737 rRenderContext
.SetTextFillColor();
1739 if (IsUserDrawEnabled())
1741 mbInUserDraw
= true;
1742 mnUserDrawEntry
= nPos
;
1743 aRect
.AdjustLeft( -mnLeft
);
1744 if (nPos
< GetEntryList()->GetMRUCount())
1745 nPos
= GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nPos
));
1746 nPos
= nPos
- GetEntryList()->GetMRUCount();
1747 sal_Int32 nCurr
= mnCurrentPos
;
1748 if (mnCurrentPos
< GetEntryList()->GetMRUCount())
1749 nCurr
= GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nCurr
));
1750 nCurr
= sal::static_int_cast
<sal_Int32
>(nCurr
- GetEntryList()->GetMRUCount());
1752 UserDrawEvent
aUDEvt(this, &rRenderContext
, aRect
, nPos
, nCurr
);
1753 maUserDrawHdl
.Call( &aUDEvt
);
1754 mbInUserDraw
= false;
1758 DrawEntry(rRenderContext
, nPos
, true, true);
1762 void ImplListBoxWindow::DrawEntry(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
, bool bDrawImage
, bool bDrawText
, bool bDrawTextAtImagePos
)
1764 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr(nPos
);
1768 long nEntryHeight
= pEntry
->getHeightWithMargin();
1770 // when changing this function don't forget to adjust ImplWin::DrawEntry()
1773 nPos
= mnUserDrawEntry
; // real entry, not the matching entry from MRU
1775 long nY
= mpEntryList
->GetAddedHeight(nPos
, mnTop
);
1778 if (bDrawImage
&& mpEntryList
->HasImages())
1780 Image aImage
= mpEntryList
->GetEntryImage(nPos
);
1783 aImgSz
= aImage
.GetSizePixel();
1784 Point
aPtImg(gnBorder
- mnLeft
, nY
+ ((nEntryHeight
- aImgSz
.Height()) / 2));
1786 // pb: #106948# explicit mirroring for calc
1789 aPtImg
.setX( mnMaxWidth
+ gnBorder
- aImgSz
.Width() - mnLeft
);
1793 rRenderContext
.DrawImage(aPtImg
, aImage
);
1797 aImgSz
.setWidth( CalcZoom(aImgSz
.Width()) );
1798 aImgSz
.setHeight( CalcZoom(aImgSz
.Height()) );
1799 rRenderContext
.DrawImage(aPtImg
, aImgSz
, aImage
);
1802 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1803 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
1805 if (nEdgeBlendingPercent
&& aImgSz
.Width() && aImgSz
.Height())
1807 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
1808 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
1809 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
1810 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
1812 if (!aBlendFrame
.IsEmpty())
1814 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
1822 OUString
aStr(mpEntryList
->GetEntryText(nPos
));
1823 if (!aStr
.isEmpty())
1825 long nMaxWidth
= std::max(mnMaxWidth
, GetOutputSizePixel().Width() - 2 * gnBorder
);
1826 // a multiline entry should only be as wide as the window
1827 if (pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
)
1828 nMaxWidth
= GetOutputSizePixel().Width() - 2 * gnBorder
;
1830 tools::Rectangle
aTextRect(Point(gnBorder
- mnLeft
, nY
),
1831 Size(nMaxWidth
, nEntryHeight
));
1833 if (!bDrawTextAtImagePos
&& (mpEntryList
->HasEntryImage(nPos
) || IsUserDrawEnabled()))
1835 long nImageWidth
= std::max(mnMaxImgWidth
, maUserItemSize
.Width());
1836 aTextRect
.AdjustLeft(nImageWidth
+ IMG_TXT_DISTANCE
);
1839 // pb: #106948# explicit mirroring for calc
1843 aTextRect
.SetLeft( nMaxWidth
+ gnBorder
- rRenderContext
.GetTextWidth(aStr
) - mnLeft
);
1844 if (aImgSz
.Width() > 0)
1845 aTextRect
.AdjustLeft( -(aImgSz
.Width() + IMG_TXT_DISTANCE
) );
1848 DrawTextFlags nDrawStyle
= ImplGetTextStyle();
1849 if (pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
)
1850 nDrawStyle
|= MULTILINE_ENTRY_DRAW_FLAGS
;
1851 if (pEntry
->mnFlags
& ListBoxEntryFlags::DrawDisabled
)
1852 nDrawStyle
|= DrawTextFlags::Disable
;
1854 rRenderContext
.DrawText(aTextRect
, aStr
, nDrawStyle
);
1858 if ( !maSeparators
.empty() && ( isSeparator(nPos
) || isSeparator(nPos
-1) ) )
1860 Color
aOldLineColor(rRenderContext
.GetLineColor());
1861 rRenderContext
.SetLineColor((GetBackground() != COL_LIGHTGRAY
) ? COL_LIGHTGRAY
: COL_GRAY
);
1862 Point
aStartPos(0, nY
);
1863 if (isSeparator(nPos
))
1864 aStartPos
.AdjustY(pEntry
->getHeightWithMargin() - 1 );
1865 Point
aEndPos(aStartPos
);
1866 aEndPos
.setX( GetOutputSizePixel().Width() );
1867 rRenderContext
.DrawLine(aStartPos
, aEndPos
);
1868 rRenderContext
.SetLineColor(aOldLineColor
);
1872 void ImplListBoxWindow::FillLayoutData() const
1874 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
1875 const_cast<ImplListBoxWindow
*>(this)->Invalidate(tools::Rectangle(Point(0, 0), GetOutputSize()));
1878 void ImplListBoxWindow::ImplDoPaint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
1880 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1882 bool bShowFocusRect
= mbHasFocusRect
;
1884 ImplHideFocusRect();
1886 long nY
= 0; // + gnBorder;
1887 long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1889 for (sal_Int32 i
= mnTop
; i
< nCount
&& nY
< nHeight
+ mnMaxHeight
; i
++)
1891 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr(i
);
1892 long nEntryHeight
= pEntry
->getHeightWithMargin();
1893 if (nY
+ nEntryHeight
>= rRect
.Top() &&
1894 nY
<= rRect
.Bottom() + mnMaxHeight
)
1896 ImplPaint(rRenderContext
, i
);
1901 long nHeightDiff
= mpEntryList
->GetAddedHeight(mnCurrentPos
, mnTop
);
1902 maFocusRect
.SetPos(Point(0, nHeightDiff
));
1903 Size
aSz(maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight(mnCurrentPos
));
1904 maFocusRect
.SetSize(aSz
);
1905 if (HasFocus() && bShowFocusRect
)
1906 ImplShowFocusRect();
1909 void ImplListBoxWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
1911 if (SupportsDoubleBuffering())
1913 // This widget is explicitly double-buffered, so avoid partial paints.
1914 tools::Rectangle
aRect(Point(0, 0), GetOutputSizePixel());
1915 ImplDoPaint(rRenderContext
, aRect
);
1918 ImplDoPaint(rRenderContext
, rRect
);
1921 sal_uInt16
ImplListBoxWindow::GetDisplayLineCount() const
1923 // FIXME: ListBoxEntryFlags::MultiLine
1925 const sal_Int32 nCount
= mpEntryList
->GetEntryCount()-mnTop
;
1926 long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1927 sal_uInt16 nEntries
= static_cast< sal_uInt16
>( ( nHeight
+ mnMaxHeight
- 1 ) / mnMaxHeight
);
1928 if( nEntries
> nCount
)
1929 nEntries
= static_cast<sal_uInt16
>(nCount
);
1934 void ImplListBoxWindow::Resize()
1938 bool bShowFocusRect
= mbHasFocusRect
;
1939 if ( bShowFocusRect
)
1940 ImplHideFocusRect();
1942 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1944 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1945 maFocusRect
.SetSize( aSz
);
1948 if ( bShowFocusRect
)
1949 ImplShowFocusRect();
1951 ImplClearLayoutData();
1954 void ImplListBoxWindow::GetFocus()
1956 sal_Int32 nPos
= mnCurrentPos
;
1957 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
1959 long nHeightDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
);
1960 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1961 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( nPos
) );
1962 maFocusRect
.SetSize( aSz
);
1963 ImplShowFocusRect();
1964 Control::GetFocus();
1967 void ImplListBoxWindow::LoseFocus()
1969 ImplHideFocusRect();
1970 Control::LoseFocus();
1973 void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop
)
1975 if( mpEntryList
->GetEntryCount() == 0 )
1978 long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1980 sal_Int32 nLastEntry
= mpEntryList
->GetEntryCount()-1;
1981 if( nTop
> nLastEntry
)
1983 const ImplEntryType
* pLast
= mpEntryList
->GetEntryPtr( nLastEntry
);
1984 while( nTop
> 0 && mpEntryList
->GetAddedHeight( nLastEntry
, nTop
-1 ) + pLast
->getHeightWithMargin() <= nWHeight
)
1987 if ( nTop
!= mnTop
)
1989 ImplClearLayoutData();
1990 long nDiff
= mpEntryList
->GetAddedHeight( mnTop
, nTop
);
1992 ImplHideFocusRect();
1997 ImplShowFocusRect();
1998 maScrollHdl
.Call( this );
2002 void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos
)
2004 if( meProminentType
== ProminentEntry::MIDDLE
)
2006 sal_Int32 nPos
= nEntryPos
;
2007 long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
2008 while( nEntryPos
> 0 && mpEntryList
->GetAddedHeight( nPos
+1, nEntryPos
) < nWHeight
/2 )
2011 SetTopEntry( nEntryPos
);
2014 void ImplListBoxWindow::SetLeftIndent( long n
)
2016 ScrollHorz( n
- mnLeft
);
2019 void ImplListBoxWindow::ScrollHorz( long n
)
2024 long nWidth
= GetOutputSizePixel().Width();
2025 if( ( mnMaxWidth
- mnLeft
+ n
) > nWidth
)
2033 nDiff
= - std::min( mnLeft
, nAbs
);
2039 ImplClearLayoutData();
2040 mnLeft
= sal::static_int_cast
<sal_uInt16
>(mnLeft
+ nDiff
);
2042 ImplHideFocusRect();
2043 Scroll( -nDiff
, 0 );
2046 ImplShowFocusRect();
2047 maScrollHdl
.Call( this );
2051 void ImplListBoxWindow::SetSeparatorPos( sal_Int32 n
)
2053 maSeparators
.clear();
2055 if ( n
!= LISTBOX_ENTRY_NOTFOUND
)
2057 maSeparators
.insert( n
);
2061 sal_Int32
ImplListBoxWindow::GetSeparatorPos() const
2063 if (!maSeparators
.empty())
2064 return *(maSeparators
.begin());
2066 return LISTBOX_ENTRY_NOTFOUND
;
2069 bool ImplListBoxWindow::isSeparator( const sal_Int32
&n
) const
2071 return maSeparators
.find(n
) != maSeparators
.end();
2074 Size
ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines
) const
2076 // FIXME: ListBoxEntryFlags::MultiLine
2079 aSz
.setHeight(nMaxLines
* GetEntryHeightWithMargin());
2080 aSz
.setWidth( mnMaxWidth
+ 2*gnBorder
);
2084 tools::Rectangle
ImplListBoxWindow::GetBoundingRectangle( sal_Int32 nItem
) const
2086 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nItem
);
2087 Size
aSz( GetSizePixel().Width(), pEntry
? pEntry
->getHeightWithMargin() : GetEntryHeightWithMargin() );
2088 long nY
= mpEntryList
->GetAddedHeight( nItem
, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeightWithMargin();
2089 tools::Rectangle
aRect( Point( 0, nY
), aSz
);
2093 void ImplListBoxWindow::StateChanged( StateChangedType nType
)
2095 Control::StateChanged( nType
);
2097 if ( nType
== StateChangedType::Zoom
)
2099 ApplySettings(*this);
2103 else if ( nType
== StateChangedType::UpdateMode
)
2105 if ( IsUpdateMode() && IsReallyVisible() )
2108 else if ( nType
== StateChangedType::ControlFont
)
2110 ApplySettings(*this);
2114 else if ( nType
== StateChangedType::ControlForeground
)
2116 ApplySettings(*this);
2119 else if ( nType
== StateChangedType::ControlBackground
)
2121 ApplySettings(*this);
2124 else if( nType
== StateChangedType::Enable
)
2129 ImplClearLayoutData();
2132 void ImplListBoxWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
2134 Control::DataChanged( rDCEvt
);
2136 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2137 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2138 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2139 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2141 ImplClearLayoutData();
2142 ApplySettings(*this);
2148 DrawTextFlags
ImplListBoxWindow::ImplGetTextStyle() const
2150 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2152 if (mpEntryList
->HasImages())
2153 nTextStyle
|= DrawTextFlags::Left
;
2155 nTextStyle
|= DrawTextFlags::Center
;
2157 nTextStyle
|= DrawTextFlags::Right
;
2159 nTextStyle
|= DrawTextFlags::Left
;
2164 ImplListBox::ImplListBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
2165 Control( pParent
, nWinStyle
),
2166 maLBWindow(VclPtr
<ImplListBoxWindow
>::Create( this, nWinStyle
&(~WB_BORDER
) ))
2168 // for native widget rendering we must be able to detect this window type
2169 SetType( WindowType::LISTBOXWINDOW
);
2171 mpVScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_VSCROLL
| WB_DRAG
);
2172 mpHScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_HSCROLL
| WB_DRAG
);
2173 mpScrollBarBox
= VclPtr
<ScrollBarBox
>::Create( this );
2175 Link
<ScrollBar
*,void> aLink( LINK( this, ImplListBox
, ScrollBarHdl
) );
2176 mpVScrollBar
->SetScrollHdl( aLink
);
2177 mpHScrollBar
->SetScrollHdl( aLink
);
2181 mbAutoHScroll
= ( nWinStyle
& WB_AUTOHSCROLL
);
2182 mbEdgeBlending
= false;
2184 maLBWindow
->SetScrollHdl( LINK( this, ImplListBox
, LBWindowScrolled
) );
2185 maLBWindow
->SetMRUChangedHdl( LINK( this, ImplListBox
, MRUChanged
) );
2186 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2190 ImplListBox::~ImplListBox()
2195 void ImplListBox::dispose()
2197 mpHScrollBar
.disposeAndClear();
2198 mpVScrollBar
.disposeAndClear();
2199 mpScrollBarBox
.disposeAndClear();
2200 maLBWindow
.disposeAndClear();
2204 void ImplListBox::Clear()
2206 maLBWindow
->Clear();
2207 if ( GetEntryList()->GetMRUCount() )
2209 maLBWindow
->GetEntryList()->SetMRUCount( 0 );
2210 maLBWindow
->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND
);
2212 mpVScrollBar
->SetThumbPos( 0 );
2213 mpHScrollBar
->SetThumbPos( 0 );
2214 CompatStateChanged( StateChangedType::Data
);
2217 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
)
2219 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
);
2220 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2221 CompatStateChanged( StateChangedType::Data
);
2225 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
, const Image
& rImage
)
2227 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
, rImage
);
2228 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2229 CompatStateChanged( StateChangedType::Data
);
2233 void ImplListBox::RemoveEntry( sal_Int32 nPos
)
2235 maLBWindow
->RemoveEntry( nPos
);
2236 CompatStateChanged( StateChangedType::Data
);
2239 void ImplListBox::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
2241 maLBWindow
->SetEntryFlags( nPos
, nFlags
);
2244 void ImplListBox::SelectEntry( sal_Int32 nPos
, bool bSelect
)
2246 maLBWindow
->SelectEntry( nPos
, bSelect
);
2249 void ImplListBox::SetNoSelection()
2251 maLBWindow
->DeselectAll();
2254 void ImplListBox::GetFocus()
2257 maLBWindow
->GrabFocus();
2259 Control::GetFocus();
2262 void ImplListBox::Resize()
2265 ImplResizeControls();
2266 ImplCheckScrollBars();
2269 IMPL_LINK_NOARG(ImplListBox
, MRUChanged
, LinkParamNone
*, void)
2271 CompatStateChanged( StateChangedType::Data
);
2274 IMPL_LINK_NOARG(ImplListBox
, LBWindowScrolled
, ImplListBoxWindow
*, void)
2276 long nSet
= GetTopEntry();
2277 if( nSet
> mpVScrollBar
->GetRangeMax() )
2278 mpVScrollBar
->SetRangeMax( GetEntryList()->GetEntryCount() );
2279 mpVScrollBar
->SetThumbPos( GetTopEntry() );
2281 mpHScrollBar
->SetThumbPos( GetLeftIndent() );
2283 maScrollHdl
.Call( this );
2286 IMPL_LINK( ImplListBox
, ScrollBarHdl
, ScrollBar
*, pSB
, void )
2288 sal_uInt16 nPos
= static_cast<sal_uInt16
>(pSB
->GetThumbPos());
2289 if( pSB
== mpVScrollBar
)
2290 SetTopEntry( nPos
);
2291 else if( pSB
== mpHScrollBar
)
2292 SetLeftIndent( nPos
);
2294 GetParent()->Invalidate( InvalidateFlags::Update
);
2297 void ImplListBox::ImplCheckScrollBars()
2299 bool bArrange
= false;
2301 Size aOutSz
= GetOutputSizePixel();
2302 sal_Int32 nEntries
= GetEntryList()->GetEntryCount();
2303 sal_uInt16 nMaxVisEntries
= static_cast<sal_uInt16
>(aOutSz
.Height() / GetEntryHeightWithMargin());
2305 // vertical ScrollBar
2306 if( nEntries
> nMaxVisEntries
)
2312 // check of the scrolled-out region
2313 if( GetEntryList()->GetSelectedEntryCount() == 1 &&
2314 GetEntryList()->GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2315 ShowProminentEntry( GetEntryList()->GetSelectedEntryPos( 0 ) );
2317 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2327 // horizontal ScrollBar
2330 long nWidth
= static_cast<sal_uInt16
>(aOutSz
.Width());
2332 nWidth
-= mpVScrollBar
->GetSizePixel().Width();
2334 long nMaxWidth
= GetMaxEntryWidth();
2335 if( nWidth
< nMaxWidth
)
2341 if ( !mbVScroll
) // maybe we do need one now
2343 nMaxVisEntries
= static_cast<sal_uInt16
>( ( aOutSz
.Height() - mpHScrollBar
->GetSizePixel().Height() ) / GetEntryHeightWithMargin() );
2344 if( nEntries
> nMaxVisEntries
)
2349 // check of the scrolled-out region
2350 if( GetEntryList()->GetSelectedEntryCount() == 1 &&
2351 GetEntryList()->GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2352 ShowProminentEntry( GetEntryList()->GetSelectedEntryPos( 0 ) );
2354 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2358 // check of the scrolled-out region
2359 sal_uInt16 nMaxLI
= static_cast<sal_uInt16
>(nMaxWidth
- nWidth
);
2360 if ( nMaxLI
< GetLeftIndent() )
2361 SetLeftIndent( nMaxLI
);
2373 ImplResizeControls();
2375 ImplInitScrollBars();
2378 void ImplListBox::ImplInitScrollBars()
2380 Size aOutSz
= maLBWindow
->GetOutputSizePixel();
2384 sal_Int32 nEntries
= GetEntryList()->GetEntryCount();
2385 sal_uInt16 nVisEntries
= static_cast<sal_uInt16
>(aOutSz
.Height() / GetEntryHeightWithMargin());
2386 mpVScrollBar
->SetRangeMax( nEntries
);
2387 mpVScrollBar
->SetVisibleSize( nVisEntries
);
2388 mpVScrollBar
->SetPageSize( nVisEntries
- 1 );
2393 mpHScrollBar
->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL
);
2394 mpHScrollBar
->SetVisibleSize( static_cast<sal_uInt16
>(aOutSz
.Width()) );
2395 mpHScrollBar
->SetLineSize( HORZ_SCROLL
);
2396 mpHScrollBar
->SetPageSize( aOutSz
.Width() - HORZ_SCROLL
);
2400 void ImplListBox::ImplResizeControls()
2402 // Here we only position the Controls; if the Scrollbars are to be
2403 // visible is already determined in ImplCheckScrollBars
2405 Size aOutSz
= GetOutputSizePixel();
2406 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2407 nSBWidth
= CalcZoom( nSBWidth
);
2409 Size
aInnerSz( aOutSz
);
2411 aInnerSz
.AdjustWidth( -nSBWidth
);
2413 aInnerSz
.AdjustHeight( -nSBWidth
);
2415 // pb: #106948# explicit mirroring for calc
2416 // Scrollbar on left or right side?
2417 bool bMirroring
= maLBWindow
->IsMirroring();
2418 Point
aWinPos( bMirroring
&& mbVScroll
? nSBWidth
: 0, 0 );
2419 maLBWindow
->SetPosSizePixel( aWinPos
, aInnerSz
);
2422 if( mbVScroll
&& mbHScroll
)
2424 Point
aBoxPos( bMirroring
? 0 : aInnerSz
.Width(), aInnerSz
.Height() );
2425 mpScrollBarBox
->SetPosSizePixel( aBoxPos
, Size( nSBWidth
, nSBWidth
) );
2426 mpScrollBarBox
->Show();
2430 mpScrollBarBox
->Hide();
2433 // vertical ScrollBar
2436 // Scrollbar on left or right side?
2437 Point
aVPos( bMirroring
? 0 : aOutSz
.Width() - nSBWidth
, 0 );
2438 mpVScrollBar
->SetPosSizePixel( aVPos
, Size( nSBWidth
, aInnerSz
.Height() ) );
2439 mpVScrollBar
->Show();
2443 mpVScrollBar
->Hide();
2444 // #107254# Don't reset top entry after resize, but check for max top entry
2445 SetTopEntry( GetTopEntry() );
2448 // horizontal ScrollBar
2451 Point
aHPos( ( bMirroring
&& mbVScroll
) ? nSBWidth
: 0, aOutSz
.Height() - nSBWidth
);
2452 mpHScrollBar
->SetPosSizePixel( aHPos
, Size( aInnerSz
.Width(), nSBWidth
) );
2453 mpHScrollBar
->Show();
2457 mpHScrollBar
->Hide();
2462 void ImplListBox::StateChanged( StateChangedType nType
)
2464 if ( nType
== StateChangedType::InitShow
)
2466 ImplCheckScrollBars();
2468 else if ( ( nType
== StateChangedType::UpdateMode
) || ( nType
== StateChangedType::Data
) )
2470 bool bUpdate
= IsUpdateMode();
2471 maLBWindow
->SetUpdateMode( bUpdate
);
2472 if ( bUpdate
&& IsReallyVisible() )
2473 ImplCheckScrollBars();
2475 else if( nType
== StateChangedType::Enable
)
2477 mpHScrollBar
->Enable( IsEnabled() );
2478 mpVScrollBar
->Enable( IsEnabled() );
2479 mpScrollBarBox
->Enable( IsEnabled() );
2480 maLBWindow
->Enable( IsEnabled() );
2484 else if ( nType
== StateChangedType::Zoom
)
2486 maLBWindow
->SetZoom( GetZoom() );
2489 else if ( nType
== StateChangedType::ControlFont
)
2491 maLBWindow
->SetControlFont( GetControlFont() );
2493 else if ( nType
== StateChangedType::ControlForeground
)
2495 maLBWindow
->SetControlForeground( GetControlForeground() );
2497 else if ( nType
== StateChangedType::ControlBackground
)
2499 maLBWindow
->SetControlBackground( GetControlBackground() );
2501 else if( nType
== StateChangedType::Mirroring
)
2503 maLBWindow
->EnableRTL( IsRTLEnabled() );
2504 mpHScrollBar
->EnableRTL( IsRTLEnabled() );
2505 mpVScrollBar
->EnableRTL( IsRTLEnabled() );
2506 ImplResizeControls();
2509 Control::StateChanged( nType
);
2512 bool ImplListBox::EventNotify( NotifyEvent
& rNEvt
)
2515 if ( rNEvt
.GetType() == MouseNotifyEvent::COMMAND
)
2517 const CommandEvent
& rCEvt
= *rNEvt
.GetCommandEvent();
2518 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2520 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2521 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2523 bDone
= HandleScrollCommand( rCEvt
, mpHScrollBar
, mpVScrollBar
);
2526 else if (rCEvt
.GetCommand() == CommandEventId::Gesture
)
2528 bDone
= HandleScrollCommand(rCEvt
, mpHScrollBar
, mpVScrollBar
);
2532 return bDone
|| Window::EventNotify( rNEvt
);
2535 const Wallpaper
& ImplListBox::GetDisplayBackground() const
2537 return maLBWindow
->GetDisplayBackground();
2540 bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent
& rCEvt
)
2543 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2545 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2546 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2548 sal_uInt16 nKey
= ( pData
->GetDelta() < 0 ) ? KEY_DOWN
: KEY_UP
;
2549 KeyEvent
aKeyEvent( 0, vcl::KeyCode( nKey
) );
2550 bDone
= ProcessKeyInput( aKeyEvent
);
2556 void ImplListBox::SetMRUEntries( const OUString
& rEntries
, sal_Unicode cSep
)
2558 bool bChanges
= GetEntryList()->GetMRUCount() != 0;
2560 // Remove old MRU entries
2561 for ( sal_Int32 n
= GetEntryList()->GetMRUCount();n
; )
2562 maLBWindow
->RemoveEntry( --n
);
2564 sal_Int32 nMRUCount
= 0;
2565 sal_Int32 nIndex
= 0;
2568 OUString aEntry
= rEntries
.getToken( 0, cSep
, nIndex
);
2569 // Accept only existing entries
2570 if ( GetEntryList()->FindEntry( aEntry
) != LISTBOX_ENTRY_NOTFOUND
)
2572 ImplEntryType
* pNewEntry
= new ImplEntryType( aEntry
);
2573 maLBWindow
->GetEntryList()->InsertEntry( nMRUCount
++, pNewEntry
, false );
2577 while ( nIndex
>= 0 );
2581 maLBWindow
->GetEntryList()->SetMRUCount( nMRUCount
);
2582 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
2583 CompatStateChanged( StateChangedType::Data
);
2587 OUString
ImplListBox::GetMRUEntries( sal_Unicode cSep
) const
2589 OUStringBuffer aEntries
;
2590 for ( sal_Int32 n
= 0; n
< GetEntryList()->GetMRUCount(); n
++ )
2592 aEntries
.append(GetEntryList()->GetEntryText( n
));
2593 if( n
< ( GetEntryList()->GetMRUCount() - 1 ) )
2594 aEntries
.append(cSep
);
2596 return aEntries
.makeStringAndClear();
2599 void ImplListBox::SetEdgeBlending(bool bNew
)
2601 if(mbEdgeBlending
!= bNew
)
2603 mbEdgeBlending
= bNew
;
2604 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2608 ImplWin::ImplWin( vcl::Window
* pParent
, WinBits nWinStyle
) :
2609 Control ( pParent
, nWinStyle
)
2611 if ( IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2612 && ! IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
2615 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2617 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
2619 mbUserDrawEnabled
= false;
2620 mbEdgeBlending
= false;
2621 mnItemPos
= LISTBOX_ENTRY_NOTFOUND
;
2624 void ImplWin::MouseButtonDown( const MouseEvent
& )
2628 maMBDownHdl
.Call(this);
2632 void ImplWin::FillLayoutData() const
2634 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
2635 ImplWin
* pThis
= const_cast<ImplWin
*>(this);
2636 pThis
->ImplDraw(*pThis
, true);
2639 bool ImplWin::PreNotify( NotifyEvent
& rNEvt
)
2641 const MouseEvent
* pMouseEvt
= nullptr;
2643 if( (rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
) && (pMouseEvt
= rNEvt
.GetMouseEvent()) != nullptr )
2645 if( pMouseEvt
->IsEnterWindow() || pMouseEvt
->IsLeaveWindow() )
2647 // trigger redraw as mouse over state has changed
2648 if ( IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2649 && ! IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
2651 GetParent()->GetWindow( GetWindowType::Border
)->Invalidate( InvalidateFlags::NoErase
);
2652 GetParent()->GetWindow( GetWindowType::Border
)->Update();
2657 return Control::PreNotify(rNEvt
);
2660 void ImplWin::ImplDraw(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2662 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2666 bool bNativeOK
= false;
2667 bool bHasFocus
= HasFocus();
2668 bool bIsEnabled
= IsEnabled();
2670 ControlState nState
= ControlState::ENABLED
;
2671 if (rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2672 && rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::HasBackgroundTexture
) )
2674 // Repaint the (focused) area similarly to
2675 // ImplSmallBorderWindowView::DrawWindow() in
2676 // vcl/source/window/brdwin.cxx
2677 vcl::Window
*pWin
= GetParent();
2679 ImplControlValue aControlValue
;
2680 bIsEnabled
&= pWin
->IsEnabled();
2682 nState
&= ~ControlState::ENABLED
;
2683 bHasFocus
|= pWin
->HasFocus();
2685 nState
|= ControlState::FOCUSED
;
2687 // The listbox is painted over the entire control including the
2688 // border, but ImplWin does not contain the border => correction
2690 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2691 pWin
->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2692 Point
aPoint( -nLeft
, -nTop
);
2693 tools::Rectangle
aCtrlRegion( aPoint
- GetPosPixel(), pWin
->GetSizePixel() );
2695 bool bMouseOver
= false;
2696 vcl::Window
*pChild
= pWin
->GetWindow( GetWindowType::FirstChild
);
2697 while( pChild
&& !(bMouseOver
= pChild
->IsMouseOver()) )
2698 pChild
= pChild
->GetWindow( GetWindowType::Next
);
2700 nState
|= ControlState::ROLLOVER
;
2702 // if parent has no border, then nobody has drawn the background
2703 // since no border window exists. so draw it here.
2704 WinBits nParentStyle
= pWin
->GetStyle();
2705 if( ! (nParentStyle
& WB_BORDER
) || (nParentStyle
& WB_NOBORDER
) )
2707 tools::Rectangle
aParentRect( Point( 0, 0 ), pWin
->GetSizePixel() );
2708 pWin
->DrawNativeControl( ControlType::Listbox
, ControlPart::Entire
, aParentRect
,
2709 nState
, aControlValue
, OUString() );
2712 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Listbox
, ControlPart::Entire
, aCtrlRegion
,
2713 nState
, aControlValue
, OUString());
2718 if (bHasFocus
&& !ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2720 if ( !ImplGetSVData()->maNWFData
.mbNoFocusRects
)
2722 rRenderContext
.SetFillColor( rStyleSettings
.GetHighlightColor() );
2723 rRenderContext
.SetTextColor( rStyleSettings
.GetHighlightTextColor() );
2727 rRenderContext
.SetLineColor();
2728 rRenderContext
.SetFillColor();
2729 rRenderContext
.SetTextColor( rStyleSettings
.GetFieldTextColor() );
2731 rRenderContext
.DrawRect( maFocusRect
);
2736 if (IsControlForeground())
2737 aColor
= GetControlForeground();
2738 else if (ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2740 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2741 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
2743 aColor
= rStyleSettings
.GetButtonTextColor();
2747 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2748 aColor
= rStyleSettings
.GetFieldRolloverTextColor();
2750 aColor
= rStyleSettings
.GetFieldTextColor();
2752 rRenderContext
.SetTextColor(aColor
);
2754 rRenderContext
.Erase(maFocusRect
);
2759 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
2761 rRenderContext
.Erase(maFocusRect
);
2765 if ( IsUserDrawEnabled() )
2767 UserDrawEvent
aUDEvt(this, &rRenderContext
, maFocusRect
, mnItemPos
, 0);
2768 maUserDrawHdl
.Call( &aUDEvt
);
2772 DrawEntry(rRenderContext
, bLayout
);
2776 void ImplWin::ApplySettings(vcl::RenderContext
& rRenderContext
)
2778 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2780 ApplyControlFont(rRenderContext
, rStyleSettings
.GetFieldFont());
2781 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetFieldTextColor());
2783 if (IsControlBackground())
2784 rRenderContext
.SetBackground(GetControlBackground());
2786 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
2789 void ImplWin::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
2791 ImplDraw(rRenderContext
);
2794 void ImplWin::DrawEntry(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2797 Size
aOutSz(GetOutputSizePixel());
2799 bool bImage
= !!maImage
;
2800 if (bImage
&& !bLayout
)
2802 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
2803 Size aImgSz
= maImage
.GetSizePixel();
2804 Point
aPtImg( nBorder
, ( ( aOutSz
.Height() - aImgSz
.Height() ) / 2 ) );
2805 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2807 // check for HC mode
2808 Image
*pImage
= &maImage
;
2812 rRenderContext
.DrawImage( aPtImg
, *pImage
, nStyle
);
2816 aImgSz
.setWidth( CalcZoom( aImgSz
.Width() ) );
2817 aImgSz
.setHeight( CalcZoom( aImgSz
.Height() ) );
2818 rRenderContext
.DrawImage( aPtImg
, aImgSz
, *pImage
, nStyle
);
2821 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
2823 if(nEdgeBlendingPercent
)
2825 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
2826 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
2827 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
2828 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
2830 if(!aBlendFrame
.IsEmpty())
2832 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
2837 if( !maString
.isEmpty() )
2839 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2841 if ( bImage
&& !bLayout
)
2842 nTextStyle
|= DrawTextFlags::Left
;
2843 else if ( GetStyle() & WB_CENTER
)
2844 nTextStyle
|= DrawTextFlags::Center
;
2845 else if ( GetStyle() & WB_RIGHT
)
2846 nTextStyle
|= DrawTextFlags::Right
;
2848 nTextStyle
|= DrawTextFlags::Left
;
2850 tools::Rectangle
aTextRect( Point( nBorder
, 0 ), Size( aOutSz
.Width()-2*nBorder
, aOutSz
.Height() ) );
2852 if ( bImage
|| IsUserDrawEnabled() )
2854 aTextRect
.AdjustLeft(maImage
.GetSizePixel().Width() + IMG_TXT_DISTANCE
);
2857 MetricVector
* pVector
= bLayout
? &mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
: nullptr;
2858 OUString
* pDisplayText
= bLayout
? &mpControlData
->mpLayoutData
->m_aDisplayText
: nullptr;
2859 rRenderContext
.DrawText( aTextRect
, maString
, nTextStyle
, pVector
, pDisplayText
);
2862 if( HasFocus() && !bLayout
)
2863 ShowFocus( maFocusRect
);
2866 void ImplWin::Resize()
2869 maFocusRect
.SetSize( GetOutputSizePixel() );
2873 void ImplWin::GetFocus()
2875 ShowFocus( maFocusRect
);
2876 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2877 IsNativeWidgetEnabled() &&
2878 IsNativeControlSupported( ControlType::Listbox
, ControlPart::Entire
) )
2880 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2887 Control::GetFocus();
2890 void ImplWin::LoseFocus()
2893 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2894 IsNativeWidgetEnabled() &&
2895 IsNativeControlSupported( ControlType::Listbox
, ControlPart::Entire
) )
2897 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2904 Control::LoseFocus();
2907 void ImplWin::ShowFocus(const tools::Rectangle
& rRect
)
2909 if (IsNativeControlSupported(ControlType::Listbox
, ControlPart::Focus
))
2911 ImplControlValue aControlValue
;
2913 vcl::Window
*pWin
= GetParent();
2914 tools::Rectangle
aParentRect(Point(0, 0), pWin
->GetSizePixel());
2915 pWin
->DrawNativeControl(ControlType::Listbox
, ControlPart::Focus
, aParentRect
,
2916 ControlState::FOCUSED
, aControlValue
, OUString());
2918 Control::ShowFocus(rRect
);
2921 ImplBtn::ImplBtn( vcl::Window
* pParent
, WinBits nWinStyle
) :
2922 PushButton( pParent
, nWinStyle
)
2926 void ImplBtn::MouseButtonDown( const MouseEvent
& )
2929 maMBDownHdl
.Call(this);
2932 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( vcl::Window
* pParent
) :
2933 FloatingWindow( pParent
, WB_BORDER
| WB_SYSTEMWINDOW
| WB_NOSHADOW
) // no drop shadow for list boxes
2937 mbAutoWidth
= false;
2939 mnPopupModeStartSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
2941 vcl::Window
* pBorderWindow
= ImplGetBorderWindow();
2944 SetAccessibleRole(accessibility::AccessibleRole::PANEL
);
2945 pBorderWindow
->SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2949 SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2954 ImplListBoxFloatingWindow::~ImplListBoxFloatingWindow()
2959 void ImplListBoxFloatingWindow::dispose()
2962 FloatingWindow::dispose();
2966 bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent
& rNEvt
)
2968 if( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2970 if( !GetParent()->HasChildPathFocus( true ) )
2974 return FloatingWindow::PreNotify( rNEvt
);
2977 void ImplListBoxFloatingWindow::setPosSizePixel( long nX
, long nY
, long nWidth
, long nHeight
, PosSizeFlags nFlags
)
2979 FloatingWindow::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
2981 // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2982 // after a call to Resize(), we adjust its position if necessary
2983 if ( IsReallyVisible() && ( nFlags
& PosSizeFlags::Height
) )
2985 Point aPos
= GetParent()->GetPosPixel();
2986 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2988 if ( nFlags
& PosSizeFlags::X
)
2991 if ( nFlags
& PosSizeFlags::Y
)
2995 SetPosPixel( ImplCalcPos( this, tools::Rectangle( aPos
, GetParent()->GetSizePixel() ), FloatWinPopupFlags::Down
, nIndex
) );
2998 // if( !IsReallyVisible() )
3000 // The ImplListBox does not get a Resize() as not visible.
3001 // But the windows must get a Resize(), so that the number of
3002 // visible entries is correct for PgUp/PgDown.
3003 // The number also cannot be calculated by List/Combobox, as for
3004 // this the presence of the vertical Scrollbar has to be known.
3005 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
3006 static_cast<vcl::Window
*>(mpImplLB
)->Resize();
3007 static_cast<vcl::Window
*>(mpImplLB
->GetMainWindow())->Resize();
3011 void ImplListBoxFloatingWindow::Resize()
3013 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
3014 FloatingWindow::Resize();
3017 Size
ImplListBoxFloatingWindow::CalcFloatSize()
3019 Size
aFloatSz( maPrefSz
);
3021 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
3022 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
3024 sal_Int32 nLines
= mpImplLB
->GetEntryList()->GetEntryCount();
3025 if ( mnDDLineCount
&& ( nLines
> mnDDLineCount
) )
3026 nLines
= mnDDLineCount
;
3028 Size aSz
= mpImplLB
->CalcSize( nLines
);
3029 long nMaxHeight
= aSz
.Height() + nTop
+ nBottom
;
3031 if ( mnDDLineCount
)
3032 aFloatSz
.setHeight( nMaxHeight
);
3036 // AutoSize first only for width...
3038 aFloatSz
.setWidth( aSz
.Width() + nLeft
+ nRight
);
3039 aFloatSz
.AdjustWidth(nRight
); // adding some space looks better...
3041 if ( ( aFloatSz
.Height() < nMaxHeight
) || ( mnDDLineCount
&& ( mnDDLineCount
< mpImplLB
->GetEntryList()->GetEntryCount() ) ) )
3043 // then we also need the vertical Scrollbar
3044 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
3045 aFloatSz
.AdjustWidth(nSBWidth
);
3048 long nDesktopWidth
= GetDesktopRectPixel().getWidth();
3049 if (aFloatSz
.Width() > nDesktopWidth
)
3050 // Don't exceed the desktop width.
3051 aFloatSz
.setWidth( nDesktopWidth
);
3054 if ( aFloatSz
.Height() > nMaxHeight
)
3055 aFloatSz
.setHeight( nMaxHeight
);
3057 // Minimal height, in case height is not set to Float height.
3058 // The parent of FloatWin must be DropDown-Combo/Listbox.
3059 Size aParentSz
= GetParent()->GetSizePixel();
3060 if( (!mnDDLineCount
|| !nLines
) && ( aFloatSz
.Height() < aParentSz
.Height() ) )
3061 aFloatSz
.setHeight( aParentSz
.Height() );
3063 // do not get narrower than the parent...
3064 if( aFloatSz
.Width() < aParentSz
.Width() )
3065 aFloatSz
.setWidth( aParentSz
.Width() );
3067 // align height to entries...
3068 long nInnerHeight
= aFloatSz
.Height() - nTop
- nBottom
;
3069 long nEntryHeight
= mpImplLB
->GetEntryHeightWithMargin();
3070 if ( nInnerHeight
% nEntryHeight
)
3072 nInnerHeight
/= nEntryHeight
;
3074 nInnerHeight
*= nEntryHeight
;
3075 aFloatSz
.setHeight( nInnerHeight
+ nTop
+ nBottom
);
3078 if (aFloatSz
.Width() < aSz
.Width())
3080 // The max width of list box entries exceeds the window width.
3081 // Account for the scroll bar height.
3082 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
3083 aFloatSz
.AdjustHeight(nSBWidth
);
3089 void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking
)
3091 if( IsInPopupMode() )
3094 Size aFloatSz
= CalcFloatSize();
3096 SetSizePixel( aFloatSz
);
3097 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
3099 sal_Int32 nPos
= mpImplLB
->GetEntryList()->GetSelectedEntryPos( 0 );
3100 mnPopupModeStartSaveSelection
= nPos
;
3102 Size aSz
= GetParent()->GetSizePixel();
3103 Point aPos
= GetParent()->GetPosPixel();
3104 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
3105 // FIXME: this ugly hack is for Mac/Aqua
3106 // should be replaced by a real mechanism to place the float rectangle
3107 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
3108 GetParent()->IsNativeWidgetEnabled() )
3110 const sal_Int32 nLeft
= 4, nTop
= 4, nRight
= 4, nBottom
= 4;
3111 aPos
.AdjustX(nLeft
);
3112 aPos
.AdjustY(nTop
);
3113 aSz
.AdjustWidth( -(nLeft
+ nRight
) );
3114 aSz
.AdjustHeight( -(nTop
+ nBottom
) );
3116 tools::Rectangle
aRect( aPos
, aSz
);
3118 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3119 // where the document is unmirrored
3120 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3121 vcl::Window
*pGrandparent
= GetParent()->GetParent();
3122 const OutputDevice
*pGrandparentOutDev
= pGrandparent
->GetOutDev();
3124 if( pGrandparent
->ImplIsAntiparallel() )
3125 pGrandparentOutDev
->ReMirror( aRect
);
3127 // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795
3128 StartPopupMode( aRect
, FloatWinPopupFlags::Down
| FloatWinPopupFlags::AllMouseButtonClose
);
3130 if( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
3131 mpImplLB
->ShowProminentEntry( nPos
);
3133 if( bStartTracking
)
3134 mpImplLB
->GetMainWindow()->EnableMouseMoveSelect( true );
3136 if ( mpImplLB
->GetMainWindow()->IsGrabFocusAllowed() )
3137 mpImplLB
->GetMainWindow()->GrabFocus();
3139 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
3143 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */