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 .
20 #include <tools/debug.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/settings.hxx>
24 #include <vcl/event.hxx>
25 #include <vcl/scrbar.hxx>
26 #include <vcl/help.hxx>
27 #include <vcl/lstbox.hxx>
28 #include <vcl/unohelp.hxx>
29 #include <vcl/i18nhelp.hxx>
31 #include "listbox.hxx"
32 #include <controldata.hxx>
36 #include <com/sun/star/i18n/XCollator.hpp>
37 #include <com/sun/star/accessibility/XAccessible.hpp>
38 #include <com/sun/star/accessibility/AccessibleRole.hpp>
40 #include <rtl/instance.hxx>
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 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
)
120 if (nPos
< 0 || LISTBOX_MAX_ENTRIES
<= maEntries
.size())
121 return LISTBOX_ERROR
;
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
= i_nEndIndex
> i_nBeginIndex
? i_nBeginIndex
: i_nEndIndex
;
293 sal_Int32 nStop
= i_nEndIndex
> i_nBeginIndex
? 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
)->mnHeight
;
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
->mnHeight
: 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::GetSelectEntryCount() 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::GetSelectEntry( sal_Int32 nIndex
) const
396 return GetEntryText( GetSelectEntryPos( nIndex
) );
399 sal_Int32
ImplEntryList::GetSelectEntryPos( 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
= new ImplEntryList( this );
469 mnSelectModifier
= 0;
470 mnUserDrawEntry
= LISTBOX_ENTRY_NOTFOUND
;
472 mbImgsDiffSz
= false;
473 mbTravelSelect
= false;
474 mbTrackingSelect
= false;
475 mbSelectionChanged
= false;
476 mbMouseMoveSelect
= false;
480 mbUserDrawEnabled
= false;
481 mbInUserDraw
= false;
483 mbHasFocusRect
= false;
484 mbRight
= ( nWinStyle
& WB_RIGHT
);
485 mbCenter
= ( nWinStyle
& WB_CENTER
);
486 mbSimpleMode
= ( nWinStyle
& WB_SIMPLEMODE
);
487 mbSort
= ( nWinStyle
& WB_SORT
);
488 mbEdgeBlending
= false;
490 // pb: #106948# explicit mirroring for calc
493 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
494 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
495 mnSeparatorPos
= LISTBOX_ENTRY_NOTFOUND
;
496 meProminentType
= ProminentEntry::TOP
;
500 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
502 ApplySettings(*this);
506 ImplListBoxWindow::~ImplListBoxWindow()
511 void ImplListBoxWindow::dispose()
517 void ImplListBoxWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
519 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
521 vcl::Font aFont
= rStyleSettings
.GetFieldFont();
523 aFont
.Merge(GetControlFont());
524 SetZoomedPointFont(rRenderContext
, aFont
);
526 Color aTextColor
= rStyleSettings
.GetFieldTextColor();
527 if (IsControlForeground())
528 aTextColor
= GetControlForeground();
529 rRenderContext
.SetTextColor(aTextColor
);
531 if (IsControlBackground())
532 rRenderContext
.SetBackground(GetControlBackground());
534 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
537 void ImplListBoxWindow::ImplCalcMetrics()
545 mnTextHeight
= (sal_uInt16
)GetTextHeight();
546 mnMaxTxtHeight
= mnTextHeight
+ mnBorder
;
547 mnMaxHeight
= mnMaxTxtHeight
;
549 if ( maUserItemSize
.Height() > mnMaxHeight
)
550 mnMaxHeight
= (sal_uInt16
) maUserItemSize
.Height();
551 if ( maUserItemSize
.Width() > mnMaxWidth
)
552 mnMaxWidth
= (sal_uInt16
) maUserItemSize
.Width();
554 for ( sal_Int32 n
= mpEntryList
->GetEntryCount(); n
; )
556 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( --n
);
557 ImplUpdateEntryMetrics( *pEntry
);
560 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
562 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryPtr( mnCurrentPos
)->mnHeight
);
563 maFocusRect
.SetSize( aSz
);
567 void ImplListBoxWindow::Clear()
569 mpEntryList
->Clear();
571 mnMaxHeight
= mnMaxTxtHeight
;
579 mbImgsDiffSz
= false;
580 ImplClearLayoutData();
582 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
583 maQuickSelectionEngine
.Reset();
588 void ImplListBoxWindow::SetUserItemSize( const Size
& rSz
)
590 ImplClearLayoutData();
591 maUserItemSize
= rSz
;
595 struct ImplEntryMetrics
606 void ImplListBoxWindow::EnableQuickSelection( bool b
)
608 maQuickSelectionEngine
.SetEnabled( b
);
611 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType
& rEntry
)
613 ImplEntryMetrics aMetrics
;
614 aMetrics
.bText
= !rEntry
.maStr
.isEmpty();
615 aMetrics
.bImage
= !!rEntry
.maImage
;
616 aMetrics
.nEntryWidth
= 0;
617 aMetrics
.nEntryHeight
= 0;
618 aMetrics
.nTextWidth
= 0;
619 aMetrics
.nImgWidth
= 0;
620 aMetrics
.nImgHeight
= 0;
622 if ( aMetrics
.bText
)
624 if( (rEntry
.mnFlags
& ListBoxEntryFlags::MultiLine
) )
627 Size
aCurSize( PixelToLogic( GetSizePixel() ) );
628 // set the current size to a large number
629 // GetTextRect should shrink it to the actual size
630 aCurSize
.Height() = 0x7fffff;
631 Rectangle
aTextRect( Point( 0, 0 ), aCurSize
);
632 aTextRect
= GetTextRect( aTextRect
, rEntry
.maStr
, DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
);
633 aMetrics
.nTextWidth
= aTextRect
.GetWidth();
634 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
635 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
636 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
637 aMetrics
.nEntryHeight
= aTextRect
.GetHeight() + mnBorder
;
641 // normal single line case
642 aMetrics
.nTextWidth
= (sal_uInt16
)GetTextWidth( rEntry
.maStr
);
643 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
644 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
645 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
646 aMetrics
.nEntryHeight
= mnTextHeight
+ mnBorder
;
649 if ( aMetrics
.bImage
)
651 Size aImgSz
= rEntry
.maImage
.GetSizePixel();
652 aMetrics
.nImgWidth
= (sal_uInt16
) CalcZoom( aImgSz
.Width() );
653 aMetrics
.nImgHeight
= (sal_uInt16
) CalcZoom( aImgSz
.Height() );
655 if( mnMaxImgWidth
&& ( aMetrics
.nImgWidth
!= mnMaxImgWidth
) )
657 else if ( mnMaxImgHeight
&& ( aMetrics
.nImgHeight
!= mnMaxImgHeight
) )
660 if( aMetrics
.nImgWidth
> mnMaxImgWidth
)
661 mnMaxImgWidth
= aMetrics
.nImgWidth
;
662 if( aMetrics
.nImgHeight
> mnMaxImgHeight
)
663 mnMaxImgHeight
= aMetrics
.nImgHeight
;
665 mnMaxImgTxtWidth
= std::max( mnMaxImgTxtWidth
, aMetrics
.nTextWidth
);
666 aMetrics
.nEntryHeight
= std::max( aMetrics
.nImgHeight
, aMetrics
.nEntryHeight
);
669 if ( IsUserDrawEnabled() || aMetrics
.bImage
)
671 aMetrics
.nEntryWidth
= std::max( aMetrics
.nImgWidth
, maUserItemSize
.Width() );
672 if ( aMetrics
.bText
)
673 aMetrics
.nEntryWidth
+= aMetrics
.nTextWidth
+ IMG_TXT_DISTANCE
;
674 aMetrics
.nEntryHeight
= std::max( std::max( mnMaxImgHeight
, maUserItemSize
.Height() ) + 2,
675 aMetrics
.nEntryHeight
);
678 if ( !aMetrics
.bText
&& !aMetrics
.bImage
&& !IsUserDrawEnabled() )
680 // entries which have no (aka an empty) text, and no image,
681 // and are not user-drawn, should be shown nonetheless
682 aMetrics
.nEntryHeight
= mnTextHeight
+ mnBorder
;
685 if ( aMetrics
.nEntryWidth
> mnMaxWidth
)
686 mnMaxWidth
= aMetrics
.nEntryWidth
;
687 if ( aMetrics
.nEntryHeight
> mnMaxHeight
)
688 mnMaxHeight
= aMetrics
.nEntryHeight
;
690 rEntry
.mnHeight
= aMetrics
.nEntryHeight
;
693 void ImplListBoxWindow::ImplCallSelect()
695 if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
697 // Insert the selected entry as MRU, if not already first MRU
698 sal_Int32 nSelected
= GetEntryList()->GetSelectEntryPos( 0 );
699 sal_Int32 nMRUCount
= GetEntryList()->GetMRUCount();
700 OUString aSelected
= GetEntryList()->GetEntryText( nSelected
);
701 sal_Int32 nFirstMatchingEntryPos
= GetEntryList()->FindEntry( aSelected
, true );
702 if ( nFirstMatchingEntryPos
|| !nMRUCount
)
704 bool bSelectNewEntry
= false;
705 if ( nFirstMatchingEntryPos
< nMRUCount
)
707 RemoveEntry( nFirstMatchingEntryPos
);
709 if ( nFirstMatchingEntryPos
== nSelected
)
710 bSelectNewEntry
= true;
712 else if ( nMRUCount
== GetEntryList()->GetMaxMRUCount() )
714 RemoveEntry( nMRUCount
- 1 );
718 ImplClearLayoutData();
720 ImplEntryType
* pNewEntry
= new ImplEntryType( aSelected
);
721 pNewEntry
->mbIsSelected
= bSelectNewEntry
;
722 GetEntryList()->InsertEntry( 0, pNewEntry
, false );
723 ImplUpdateEntryMetrics( *pNewEntry
);
724 GetEntryList()->SetMRUCount( ++nMRUCount
);
725 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
726 maMRUChangedHdl
.Call( nullptr );
730 maSelectHdl
.Call( nullptr );
731 mbSelectionChanged
= false;
734 sal_Int32
ImplListBoxWindow::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
)
736 if (nPos
< 0 || LISTBOX_MAX_ENTRIES
<= mpEntryList
->GetEntryCount())
737 return LISTBOX_ERROR
;
739 ImplClearLayoutData();
740 sal_Int32 nNewPos
= mpEntryList
->InsertEntry( nPos
, pNewEntry
, mbSort
);
742 if( (GetStyle() & WB_WORDBREAK
) )
743 pNewEntry
->mnFlags
|= ListBoxEntryFlags::MultiLine
;
745 ImplUpdateEntryMetrics( *pNewEntry
);
749 void ImplListBoxWindow::RemoveEntry( sal_Int32 nPos
)
751 ImplClearLayoutData();
752 mpEntryList
->RemoveEntry( nPos
);
753 if( mnCurrentPos
>= mpEntryList
->GetEntryCount() )
754 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
758 void ImplListBoxWindow::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
760 mpEntryList
->SetEntryFlags( nPos
, nFlags
);
761 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( nPos
);
763 ImplUpdateEntryMetrics( *pEntry
);
766 void ImplListBoxWindow::ImplShowFocusRect()
768 if ( mbHasFocusRect
)
770 ShowFocus( maFocusRect
);
771 mbHasFocusRect
= true;
774 void ImplListBoxWindow::ImplHideFocusRect()
776 if ( mbHasFocusRect
)
779 mbHasFocusRect
= false;
783 sal_Int32
ImplListBoxWindow::GetEntryPosForPoint( const Point
& rPoint
) const
787 sal_Int32 nSelect
= mnTop
;
788 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nSelect
);
789 while( pEntry
&& rPoint
.Y() > pEntry
->mnHeight
+ nY
)
791 nY
+= pEntry
->mnHeight
;
792 pEntry
= mpEntryList
->GetEntryPtr( ++nSelect
);
794 if( pEntry
== nullptr )
795 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
800 bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry
) const
804 if( i_nEntry
>= mnTop
)
806 if( mpEntryList
->GetAddedHeight( i_nEntry
, mnTop
) <
807 PixelToLogic( GetSizePixel() ).Height() )
816 sal_Int32
ImplListBoxWindow::GetLastVisibleEntry() const
818 sal_Int32 nPos
= mnTop
;
819 long nWindowHeight
= GetSizePixel().Height();
820 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
822 for( nDiff
= 0; nDiff
< nWindowHeight
&& nPos
< nCount
; nDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
) )
825 if( nDiff
> nWindowHeight
&& nPos
> mnTop
)
834 void ImplListBoxWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
836 mbMouseMoveSelect
= false; // only till the first MouseButtonDown
837 maQuickSelectionEngine
.Reset();
841 if( rMEvt
.GetClicks() == 1 )
843 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
844 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
846 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
847 mnTrackingSaveSelection
= GetEntryList()->GetSelectEntryPos( 0 );
849 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
851 mnCurrentPos
= nSelect
;
852 mbTrackingSelect
= true;
853 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
854 (void)SelectEntries( nSelect
, LET_MBDOWN
, rMEvt
.IsShift(), rMEvt
.IsMod1() ,bCurPosChange
);
855 mbTrackingSelect
= false;
859 StartTracking( StartTrackingFlags::ScrollRepeat
);
862 if( rMEvt
.GetClicks() == 2 )
864 maDoubleClickHdl
.Call( this );
867 else // if ( mbGrabFocus )
873 void ImplListBoxWindow::MouseMove( const MouseEvent
& rMEvt
)
875 if ( rMEvt
.IsLeaveWindow() )
877 if ( mbStackMode
&& IsMouseMoveSelect() && IsReallyVisible() )
879 if ( rMEvt
.GetPosPixel().Y() < 0 )
882 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
886 mbTravelSelect
= true;
887 mnSelectModifier
= rMEvt
.GetModifier();
889 mbTravelSelect
= false;
895 else if ( ( ( !mbMulti
&& IsMouseMoveSelect() ) || mbStackMode
) && mpEntryList
->GetEntryCount() )
898 Rectangle
aRect( aPoint
, GetOutputSizePixel() );
899 if( aRect
.IsInside( rMEvt
.GetPosPixel() ) )
901 if ( IsMouseMoveSelect() )
903 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
904 if( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
905 nSelect
= mpEntryList
->GetEntryCount() - 1;
906 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
907 nSelect
= std::min( nSelect
, (sal_Int32
) ( mpEntryList
->GetEntryCount() - 1 ) );
908 // Select only visible Entries with MouseMove, otherwise Tracking...
909 if ( IsVisible( nSelect
) &&
910 mpEntryList
->IsEntrySelectable( nSelect
) &&
911 ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectEntryCount() || ( nSelect
!= GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
913 mbTrackingSelect
= true;
914 if ( SelectEntries( nSelect
, LET_TRACKING
) )
918 mbTravelSelect
= true;
919 mnSelectModifier
= rMEvt
.GetModifier();
921 mbTravelSelect
= false;
923 // When list box selection change by mouse move, notify
924 // VCLEVENT_LISTBOX_SELECT vcl event.
927 maListItemSelectHdl
.Call(nullptr);
930 mbTrackingSelect
= false;
934 // if the DD button was pressed and someone moved into the ListBox
935 // with the mouse button pressed...
936 if ( rMEvt
.IsLeft() && !rMEvt
.IsSynthetic() )
938 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
939 mnTrackingSaveSelection
= GetEntryList()->GetSelectEntryPos( 0 );
941 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
943 if ( mbStackMode
&& ( mpEntryList
->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND
) )
944 mpEntryList
->SetSelectionAnchor( 0 );
946 StartTracking( StartTrackingFlags::ScrollRepeat
);
952 void ImplListBoxWindow::DeselectAll()
954 while ( GetEntryList()->GetSelectEntryCount() )
956 sal_Int32 nS
= GetEntryList()->GetSelectEntryPos( 0 );
957 SelectEntry( nS
, false );
961 void ImplListBoxWindow::SelectEntry( sal_Int32 nPos
, bool bSelect
)
963 if( (mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
) && mpEntryList
->IsEntrySelectable( nPos
) )
970 // deselect the selected entry
971 sal_Int32 nDeselect
= GetEntryList()->GetSelectEntryPos( 0 );
972 if( nDeselect
!= LISTBOX_ENTRY_NOTFOUND
)
974 //SelectEntryPos( nDeselect, false );
975 GetEntryList()->SelectEntry( nDeselect
, false );
976 if (IsUpdateMode() && IsReallyVisible())
980 mpEntryList
->SelectEntry( nPos
, true );
982 if ( ( nPos
!= LISTBOX_ENTRY_NOTFOUND
) && IsUpdateMode() )
985 if ( !IsVisible( nPos
) )
987 ImplClearLayoutData();
988 sal_Int32 nVisibleEntries
= GetLastVisibleEntry()-mnTop
;
989 if ( !nVisibleEntries
|| !IsReallyVisible() || ( nPos
< GetTopEntry() ) )
992 ShowProminentEntry( nPos
);
996 ShowProminentEntry( nPos
);
1003 mpEntryList
->SelectEntry( nPos
, false );
1006 mbSelectionChanged
= true;
1010 bool ImplListBoxWindow::SelectEntries( sal_Int32 nSelect
, LB_EVENT_TYPE eLET
, bool bShift
, bool bCtrl
, bool bSelectPosChange
/*=FALSE*/ )
1012 bool bSelectionChanged
= false;
1014 if( IsEnabled() && mpEntryList
->IsEntrySelectable( nSelect
) )
1016 bool bFocusChanged
= false;
1018 // here (Single-ListBox) only one entry can be deselected
1021 sal_Int32 nDeselect
= mpEntryList
->GetSelectEntryPos( 0 );
1022 if( nSelect
!= nDeselect
)
1024 SelectEntry( nSelect
, true );
1025 mpEntryList
->SetLastSelected( nSelect
);
1026 bFocusChanged
= true;
1027 bSelectionChanged
= true;
1030 // MultiListBox without Modifier
1031 else if( mbSimpleMode
&& !bCtrl
&& !bShift
)
1033 sal_Int32 nEntryCount
= mpEntryList
->GetEntryCount();
1034 for ( sal_Int32 nPos
= 0; nPos
< nEntryCount
; nPos
++ )
1036 bool bSelect
= nPos
== nSelect
;
1037 if ( mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
)
1039 SelectEntry( nPos
, bSelect
);
1040 bFocusChanged
= true;
1041 bSelectionChanged
= true;
1044 mpEntryList
->SetLastSelected( nSelect
);
1045 mpEntryList
->SetSelectionAnchor( nSelect
);
1047 // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1048 else if( ( !mbSimpleMode
/* && !bShift */ ) || ( (mbSimpleMode
&& ( bCtrl
|| bShift
)) || mbStackMode
) )
1050 // Space for selection change
1051 if( !bShift
&& ( ( eLET
== LET_KEYSPACE
) || ( eLET
== LET_MBDOWN
) ) )
1053 bool bSelect
= ( mbStackMode
&& IsMouseMoveSelect() ) || !mpEntryList
->IsEntryPosSelected( nSelect
);
1059 // All entries before nSelect must be selected...
1060 for ( n
= 0; n
< nSelect
; n
++ )
1061 SelectEntry( n
, true );
1065 for ( n
= nSelect
+1; n
< mpEntryList
->GetEntryCount(); n
++ )
1066 SelectEntry( n
, false );
1069 SelectEntry( nSelect
, bSelect
);
1070 mpEntryList
->SetLastSelected( nSelect
);
1071 mpEntryList
->SetSelectionAnchor( mbStackMode
? 0 : nSelect
);
1072 if ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1073 mpEntryList
->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND
);
1074 bFocusChanged
= true;
1075 bSelectionChanged
= true;
1077 else if( ( ( eLET
== LET_TRACKING
) && ( nSelect
!= mnCurrentPos
) ) ||
1078 ( (bShift
||mbStackMode
) && ( ( eLET
== LET_KEYMOVE
) || ( eLET
== LET_MBDOWN
) ) ) )
1080 mnCurrentPos
= nSelect
;
1081 bFocusChanged
= true;
1083 sal_Int32 nAnchor
= mpEntryList
->GetSelectionAnchor();
1084 if( ( nAnchor
== LISTBOX_ENTRY_NOTFOUND
) && ( mpEntryList
->GetSelectEntryCount() || mbStackMode
) )
1086 nAnchor
= mbStackMode
? 0 : mpEntryList
->GetSelectEntryPos( mpEntryList
->GetSelectEntryCount() - 1 );
1088 if( nAnchor
!= LISTBOX_ENTRY_NOTFOUND
)
1090 // All entries from Anchor to nSelect have to be selected
1091 sal_Int32 nStart
= std::min( nSelect
, nAnchor
);
1092 sal_Int32 nEnd
= std::max( nSelect
, nAnchor
);
1093 for ( sal_Int32 n
= nStart
; n
<= nEnd
; n
++ )
1095 if ( !mpEntryList
->IsEntryPosSelected( n
) )
1097 SelectEntry( n
, true );
1098 bSelectionChanged
= true;
1102 // if appropriate some more has to be deselected...
1103 sal_Int32 nLast
= mpEntryList
->GetLastSelected();
1104 if ( nLast
!= LISTBOX_ENTRY_NOTFOUND
)
1106 if ( ( nLast
> nSelect
) && ( nLast
> nAnchor
) )
1108 for ( sal_Int32 n
= nSelect
+1; n
<= nLast
; n
++ )
1110 if ( mpEntryList
->IsEntryPosSelected( n
) )
1112 SelectEntry( n
, false );
1113 bSelectionChanged
= true;
1117 else if ( ( nLast
< nSelect
) && ( nLast
< nAnchor
) )
1119 for ( sal_Int32 n
= nLast
; n
< nSelect
; n
++ )
1121 if ( mpEntryList
->IsEntryPosSelected( n
) )
1123 SelectEntry( n
, false );
1124 bSelectionChanged
= true;
1129 mpEntryList
->SetLastSelected( nSelect
);
1132 else if( eLET
!= LET_TRACKING
)
1134 ImplHideFocusRect();
1136 bFocusChanged
= true;
1141 bFocusChanged
= true;
1144 if( bSelectionChanged
)
1145 mbSelectionChanged
= true;
1149 long nHeightDiff
= mpEntryList
->GetAddedHeight( nSelect
, mnTop
);
1150 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1151 Size
aSz( maFocusRect
.GetWidth(),
1152 mpEntryList
->GetEntryHeight( nSelect
) );
1153 maFocusRect
.SetSize( aSz
);
1155 ImplShowFocusRect();
1156 if (bSelectPosChange
)
1158 maFocusHdl
.Call(nSelect
);
1161 ImplClearLayoutData();
1163 return bSelectionChanged
;
1166 void ImplListBoxWindow::Tracking( const TrackingEvent
& rTEvt
)
1169 Rectangle
aRect( aPoint
, GetOutputSizePixel() );
1170 bool bInside
= aRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() );
1172 if( rTEvt
.IsTrackingCanceled() || rTEvt
.IsTrackingEnded() ) // MouseButtonUp
1174 if ( bInside
&& !rTEvt
.IsTrackingCanceled() )
1176 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1181 maCancelHdl
.Call( nullptr );
1184 mbTrackingSelect
= true;
1185 SelectEntry( mnTrackingSaveSelection
, true );
1186 mbTrackingSelect
= false;
1187 if ( mnTrackingSaveSelection
!= LISTBOX_ENTRY_NOTFOUND
)
1189 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
);
1190 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1191 Size
aSz( maFocusRect
.GetWidth(),
1192 mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1193 maFocusRect
.SetSize( aSz
);
1194 ImplShowFocusRect();
1203 bool bTrackOrQuickClick
= mbTrack
;
1211 // this case only happens, if the mouse button is pressed very briefly
1212 if( rTEvt
.IsTrackingEnded() && mbTrack
)
1214 bTrackOrQuickClick
= true;
1219 if( bTrackOrQuickClick
)
1221 MouseEvent aMEvt
= rTEvt
.GetMouseEvent();
1222 Point
aPt( aMEvt
.GetPosPixel() );
1223 bool bShift
= aMEvt
.IsShift();
1224 bool bCtrl
= aMEvt
.IsMod1();
1226 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1229 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1231 nSelect
= mnCurrentPos
? ( mnCurrentPos
- 1 ) : 0;
1232 if( nSelect
< mnTop
)
1233 SetTopEntry( mnTop
-1 );
1236 else if( aPt
.Y() > GetOutputSizePixel().Height() )
1238 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1240 nSelect
= std::min( (sal_Int32
)(mnCurrentPos
+1), (sal_Int32
)(mpEntryList
->GetEntryCount()-1) );
1241 if( nSelect
>= GetLastVisibleEntry() )
1242 SetTopEntry( mnTop
+1 );
1247 nSelect
= (sal_Int32
) ( ( aPt
.Y() + mnBorder
) / mnMaxHeight
) + (sal_Int32
) mnTop
;
1248 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
1249 nSelect
= std::min( nSelect
, (sal_Int32
) ( mpEntryList
->GetEntryCount() - 1 ) );
1254 if ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectEntryCount() )
1256 mbTrackingSelect
= true;
1257 if ( SelectEntries( nSelect
, LET_TRACKING
, bShift
, bCtrl
) )
1261 mbTravelSelect
= true;
1262 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1264 mbTravelSelect
= false;
1267 mbTrackingSelect
= false;
1272 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
1274 mbTrackingSelect
= true;
1275 SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), false );
1276 mbTrackingSelect
= false;
1278 else if ( mbStackMode
)
1280 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt
.GetMouseEvent().GetPosPixel().X() < aRect
.Right() ) )
1282 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt
.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1284 bool bSelectionChanged
= false;
1285 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().Y() < 0 )
1288 if ( mpEntryList
->IsEntryPosSelected( 0 ) )
1290 SelectEntry( 0, false );
1291 bSelectionChanged
= true;
1292 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1298 mbTrackingSelect
= true;
1299 bSelectionChanged
= SelectEntries( nSelect
, LET_TRACKING
, bShift
, bCtrl
);
1300 mbTrackingSelect
= false;
1303 if ( bSelectionChanged
)
1305 mbSelectionChanged
= true;
1306 mbTravelSelect
= true;
1307 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1309 mbTravelSelect
= false;
1315 mnCurrentPos
= nSelect
;
1316 if ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1318 ImplHideFocusRect();
1322 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
);
1323 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1324 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1325 maFocusRect
.SetSize( aSz
);
1326 ImplShowFocusRect();
1332 void ImplListBoxWindow::KeyInput( const KeyEvent
& rKEvt
)
1334 if( !ProcessKeyInput( rKEvt
) )
1335 Control::KeyInput( rKEvt
);
1338 bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent
& rKEvt
)
1340 // entry to be selected
1341 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1342 LB_EVENT_TYPE eLET
= LET_KEYMOVE
;
1344 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1346 bool bShift
= aKeyCode
.IsShift();
1347 bool bCtrl
= aKeyCode
.IsMod1() || aKeyCode
.IsMod3();
1348 bool bMod2
= aKeyCode
.IsMod2();
1350 bool bHandleKey
= false;
1352 switch( aKeyCode
.GetCode() )
1358 if ( GetTopEntry() )
1359 SetTopEntry( GetTopEntry()-1 );
1363 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1365 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1367 else if ( mnCurrentPos
)
1369 // search first selectable above the current position
1370 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
- 1, false );
1373 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
< mnTop
) )
1374 SetTopEntry( mnTop
-1 );
1378 maQuickSelectionEngine
.Reset();
1386 SetTopEntry( GetTopEntry()+1 );
1390 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1392 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1394 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1396 // search first selectable below the current position
1397 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
+ 1 );
1400 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
>= GetLastVisibleEntry() ) )
1401 SetTopEntry( mnTop
+1 );
1405 maQuickSelectionEngine
.Reset();
1413 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1414 SetTopEntry( ( mnTop
> nCurVis
) ?
1415 (mnTop
-nCurVis
) : 0 );
1417 else if ( !bCtrl
&& !bMod2
)
1419 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1421 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1423 else if ( mnCurrentPos
)
1425 if( mnCurrentPos
== mnTop
)
1427 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1428 SetTopEntry( ( mnTop
> nCurVis
) ? ( mnTop
-nCurVis
+1 ) : 0 );
1431 // find first selectable starting from mnTop looking forward
1432 nSelect
= mpEntryList
->FindFirstSelectable( mnTop
);
1436 maQuickSelectionEngine
.Reset();
1444 SetTopEntry( GetLastVisibleEntry() );
1446 else if ( !bCtrl
&& !bMod2
)
1448 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1450 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1452 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1454 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1455 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
;
1456 sal_Int32 nTmp
= std::min( nCurVis
, nCount
);
1458 if( mnCurrentPos
== nTmp
&& mnCurrentPos
!= nCount
- 1 )
1460 long nTmp2
= std::min( (long)(nCount
-nCurVis
), (long)((long)mnTop
+(long)nCurVis
-1) );
1461 nTmp2
= std::max( (long)0 , nTmp2
);
1462 nTmp
= (sal_Int32
)(nTmp2
+(nCurVis
-1) );
1463 SetTopEntry( (sal_Int32
)nTmp2
);
1465 // find first selectable starting from nTmp looking backwards
1466 nSelect
= mpEntryList
->FindFirstSelectable( nTmp
, false );
1470 maQuickSelectionEngine
.Reset();
1480 else if ( !bCtrl
&& !bMod2
)
1484 nSelect
= mpEntryList
->FindFirstSelectable( mpEntryList
->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND
);
1491 maQuickSelectionEngine
.Reset();
1499 SetTopEntry( 0xFFFF );
1501 else if ( !bCtrl
&& !bMod2
)
1503 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1505 nSelect
= mpEntryList
->FindFirstSelectable( 0 );
1507 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1509 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1510 nSelect
= mpEntryList
->FindFirstSelectable( nCount
- 1, false );
1511 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+ 1;
1512 if( nCount
> nCurVis
)
1513 SetTopEntry( nCount
- nCurVis
);
1517 maQuickSelectionEngine
.Reset();
1523 if ( !bCtrl
&& !bMod2
)
1525 ScrollHorz( -HORZ_SCROLL
);
1528 maQuickSelectionEngine
.Reset();
1534 if ( !bCtrl
&& !bMod2
)
1536 ScrollHorz( HORZ_SCROLL
);
1539 maQuickSelectionEngine
.Reset();
1545 if ( !bMod2
&& !IsReadOnly() )
1547 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1549 bDone
= false; // do not catch RETURN
1551 maQuickSelectionEngine
.Reset();
1557 if ( !bMod2
&& !IsReadOnly() )
1559 if( mbMulti
&& ( !mbSimpleMode
|| ( mbSimpleMode
&& bCtrl
&& !bShift
) || mbStackMode
) )
1561 nSelect
= mnCurrentPos
;
1562 eLET
= LET_KEYSPACE
;
1572 if( bCtrl
&& mbMulti
)
1575 bool bUpdates
= IsUpdateMode();
1576 SetUpdateMode( false );
1578 sal_Int32 nEntryCount
= mpEntryList
->GetEntryCount();
1579 for( sal_Int32 i
= 0; i
< nEntryCount
; i
++ )
1580 SelectEntry( i
, true );
1582 // restore update mode
1583 SetUpdateMode( bUpdates
);
1586 maQuickSelectionEngine
.Reset();
1601 if (bHandleKey
&& !IsReadOnly())
1603 bDone
= maQuickSelectionEngine
.HandleKeyEvent( rKEvt
);
1606 if ( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
1607 && ( ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1608 || ( eLET
== LET_KEYSPACE
)
1612 SAL_WARN_IF( mpEntryList
->IsEntryPosSelected( nSelect
) && !mbMulti
, "vcl", "ImplListBox: Selecting same Entry" );
1613 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1614 if (nSelect
>= nCount
)
1615 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1616 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
1617 mnCurrentPos
= nSelect
;
1618 if(SelectEntries( nSelect
, eLET
, bShift
, bCtrl
, bCurPosChange
))
1620 mbTravelSelect
= true;
1621 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1623 mbTravelSelect
= false;
1632 vcl::StringEntryIdentifier
lcl_getEntry( const ImplEntryList
& _rList
, sal_Int32 _nPos
, OUString
& _out_entryText
)
1634 OSL_PRECOND( ( _nPos
!= LISTBOX_ENTRY_NOTFOUND
), "lcl_getEntry: invalid position!" );
1635 sal_Int32
nEntryCount( _rList
.GetEntryCount() );
1636 if ( _nPos
>= nEntryCount
)
1638 _out_entryText
= _rList
.GetEntryText( _nPos
);
1640 // vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1642 return reinterpret_cast< vcl::StringEntryIdentifier
>( _nPos
+ 1 );
1645 sal_Int32
lcl_getEntryPos( vcl::StringEntryIdentifier _entry
)
1647 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1648 return static_cast< sal_Int32
>( reinterpret_cast< sal_Int64
>( _entry
) ) - 1;
1652 vcl::StringEntryIdentifier
ImplListBoxWindow::CurrentEntry( OUString
& _out_entryText
) const
1654 return lcl_getEntry( *GetEntryList(), ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
) ? 0 : mnCurrentPos
, _out_entryText
);
1657 vcl::StringEntryIdentifier
ImplListBoxWindow::NextEntry( vcl::StringEntryIdentifier _currentEntry
, OUString
& _out_entryText
) const
1659 sal_Int32 nNextPos
= lcl_getEntryPos( _currentEntry
) + 1;
1660 return lcl_getEntry( *GetEntryList(), nNextPos
, _out_entryText
);
1663 void ImplListBoxWindow::SelectEntry( vcl::StringEntryIdentifier _entry
)
1665 sal_Int32 nSelect
= lcl_getEntryPos( _entry
);
1666 if ( mpEntryList
->IsEntryPosSelected( nSelect
) )
1668 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1669 // to select the given entry by typing its starting letters. No need to act.
1674 OSL_ENSURE( nSelect
< mpEntryList
->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1675 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1676 if (nSelect
>= nCount
)
1677 nSelect
= nCount
? nCount
-1 : LISTBOX_ENTRY_NOTFOUND
;
1680 ShowProminentEntry( nSelect
);
1683 mnCurrentPos
= nSelect
;
1684 if ( SelectEntries( nSelect
, LET_KEYMOVE
) )
1686 mbTravelSelect
= true;
1687 mnSelectModifier
= 0;
1689 mbTravelSelect
= false;
1693 void ImplListBoxWindow::ImplPaint(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
)
1695 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1697 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nPos
);
1701 long nWidth
= GetOutputSizePixel().Width();
1702 long nY
= mpEntryList
->GetAddedHeight(nPos
, mnTop
);
1703 Rectangle
aRect(Point(0, nY
), Size(nWidth
, pEntry
->mnHeight
));
1705 if (mpEntryList
->IsEntryPosSelected(nPos
))
1707 rRenderContext
.SetTextColor(!IsEnabled() ? rStyleSettings
.GetDisableColor() : rStyleSettings
.GetHighlightTextColor());
1708 rRenderContext
.SetFillColor(rStyleSettings
.GetHighlightColor());
1709 rRenderContext
.SetTextFillColor(rStyleSettings
.GetHighlightColor());
1710 rRenderContext
.DrawRect(aRect
);
1714 ApplySettings(rRenderContext
);
1716 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
1717 rRenderContext
.SetTextFillColor();
1720 if (IsUserDrawEnabled())
1722 mbInUserDraw
= true;
1723 mnUserDrawEntry
= nPos
;
1724 aRect
.Left() -= mnLeft
;
1725 if (nPos
< GetEntryList()->GetMRUCount())
1726 nPos
= GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nPos
));
1727 nPos
= nPos
- GetEntryList()->GetMRUCount();
1728 sal_Int32 nCurr
= mnCurrentPos
;
1729 if (mnCurrentPos
< GetEntryList()->GetMRUCount())
1730 nCurr
= GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nCurr
));
1731 nCurr
= sal::static_int_cast
<sal_Int32
>(nCurr
- GetEntryList()->GetMRUCount());
1733 UserDrawEvent
aUDEvt(this, &rRenderContext
, aRect
, nPos
, nCurr
);
1734 maUserDrawHdl
.Call( &aUDEvt
);
1735 mbInUserDraw
= false;
1739 DrawEntry(rRenderContext
, nPos
, true, true);
1743 void ImplListBoxWindow::DrawEntry(vcl::RenderContext
& rRenderContext
, sal_Int32 nPos
, bool bDrawImage
, bool bDrawText
, bool bDrawTextAtImagePos
)
1745 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr(nPos
);
1749 // when changing this function don't forget to adjust ImplWin::DrawEntry()
1752 nPos
= mnUserDrawEntry
; // real entry, not the matching entry from MRU
1754 long nY
= mpEntryList
->GetAddedHeight(nPos
, mnTop
);
1757 if (bDrawImage
&& mpEntryList
->HasImages())
1759 Image aImage
= mpEntryList
->GetEntryImage(nPos
);
1762 aImgSz
= aImage
.GetSizePixel();
1763 Point
aPtImg(mnBorder
- mnLeft
, nY
+ ((pEntry
->mnHeight
- aImgSz
.Height()) / 2));
1765 // pb: #106948# explicit mirroring for calc
1768 aPtImg
.X() = mnMaxWidth
+ mnBorder
- aImgSz
.Width() - mnLeft
;
1772 rRenderContext
.DrawImage(aPtImg
, aImage
);
1776 aImgSz
.Width() = CalcZoom(aImgSz
.Width());
1777 aImgSz
.Height() = CalcZoom(aImgSz
.Height());
1778 rRenderContext
.DrawImage(aPtImg
, aImgSz
, aImage
);
1781 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1782 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
1784 if (nEdgeBlendingPercent
&& aImgSz
.Width() && aImgSz
.Height())
1786 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
1787 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
1788 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
1789 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
1791 if (!aBlendFrame
.IsEmpty())
1793 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
1801 OUString
aStr(mpEntryList
->GetEntryText(nPos
));
1802 if (!aStr
.isEmpty())
1804 long nMaxWidth
= std::max(mnMaxWidth
, GetOutputSizePixel().Width() - 2 * mnBorder
);
1805 // a multiline entry should only be as wide a the window
1806 if ((pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
))
1807 nMaxWidth
= GetOutputSizePixel().Width() - 2 * mnBorder
;
1809 Rectangle
aTextRect(Point(mnBorder
- mnLeft
, nY
),
1810 Size(nMaxWidth
, pEntry
->mnHeight
));
1812 if (!bDrawTextAtImagePos
&& (mpEntryList
->HasEntryImage(nPos
) || IsUserDrawEnabled()))
1814 long nImageWidth
= std::max(mnMaxImgWidth
, maUserItemSize
.Width());
1815 aTextRect
.Left() += nImageWidth
+ IMG_TXT_DISTANCE
;
1818 // pb: #106948# explicit mirroring for calc
1822 aTextRect
.Left() = nMaxWidth
+ mnBorder
- rRenderContext
.GetTextWidth(aStr
) - mnLeft
;
1823 if (aImgSz
.Width() > 0)
1824 aTextRect
.Left() -= (aImgSz
.Width() + IMG_TXT_DISTANCE
);
1827 DrawTextFlags nDrawStyle
= ImplGetTextStyle();
1828 if ((pEntry
->mnFlags
& ListBoxEntryFlags::MultiLine
))
1829 nDrawStyle
|= MULTILINE_ENTRY_DRAW_FLAGS
;
1830 if ((pEntry
->mnFlags
& ListBoxEntryFlags::DrawDisabled
))
1831 nDrawStyle
|= DrawTextFlags::Disable
;
1833 rRenderContext
.DrawText(aTextRect
, aStr
, nDrawStyle
);
1837 if ((mnSeparatorPos
!= LISTBOX_ENTRY_NOTFOUND
) &&
1838 ((nPos
== mnSeparatorPos
) || (nPos
== mnSeparatorPos
+ 1)))
1840 Color
aOldLineColor(rRenderContext
.GetLineColor());
1841 rRenderContext
.SetLineColor((GetBackground().GetColor() != COL_LIGHTGRAY
) ? COL_LIGHTGRAY
: COL_GRAY
);
1842 Point
aStartPos(0, nY
);
1843 if (nPos
== mnSeparatorPos
)
1844 aStartPos
.Y() += pEntry
->mnHeight
- 1;
1845 Point
aEndPos(aStartPos
);
1846 aEndPos
.X() = GetOutputSizePixel().Width();
1847 rRenderContext
.DrawLine(aStartPos
, aEndPos
);
1848 rRenderContext
.SetLineColor(aOldLineColor
);
1852 void ImplListBoxWindow::FillLayoutData() const
1854 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
1855 const_cast<ImplListBoxWindow
*>(this)->Invalidate(Rectangle(Point(0, 0), GetOutputSize()));
1858 void ImplListBoxWindow::ImplDoPaint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
1860 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1862 bool bShowFocusRect
= mbHasFocusRect
;
1864 ImplHideFocusRect();
1866 long nY
= 0; // + mnBorder;
1867 long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1869 for (sal_Int32 i
= (sal_Int32
)mnTop
; i
< nCount
&& nY
< nHeight
+ mnMaxHeight
; i
++)
1871 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr(i
);
1872 if (nY
+ pEntry
->mnHeight
>= rRect
.Top() &&
1873 nY
<= rRect
.Bottom() + mnMaxHeight
)
1875 ImplPaint(rRenderContext
, i
);
1877 nY
+= pEntry
->mnHeight
;
1880 long nHeightDiff
= mpEntryList
->GetAddedHeight(mnCurrentPos
, mnTop
);
1881 maFocusRect
.SetPos(Point(0, nHeightDiff
));
1882 Size
aSz(maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight(mnCurrentPos
));
1883 maFocusRect
.SetSize(aSz
);
1884 if (HasFocus() && bShowFocusRect
)
1885 ImplShowFocusRect();
1888 void ImplListBoxWindow::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
1890 ImplDoPaint(rRenderContext
, rRect
);
1893 sal_uInt16
ImplListBoxWindow::GetDisplayLineCount() const
1895 // FIXME: ListBoxEntryFlags::MultiLine
1897 const sal_Int32 nCount
= mpEntryList
->GetEntryCount()-mnTop
;
1898 long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1899 sal_uInt16 nEntries
= static_cast< sal_uInt16
>( ( nHeight
+ mnMaxHeight
- 1 ) / mnMaxHeight
);
1900 if( nEntries
> nCount
)
1901 nEntries
= static_cast<sal_uInt16
>(nCount
);
1906 void ImplListBoxWindow::Resize()
1910 bool bShowFocusRect
= mbHasFocusRect
;
1911 if ( bShowFocusRect
)
1912 ImplHideFocusRect();
1914 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1916 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1917 maFocusRect
.SetSize( aSz
);
1920 if ( bShowFocusRect
)
1921 ImplShowFocusRect();
1923 ImplClearLayoutData();
1926 void ImplListBoxWindow::GetFocus()
1928 sal_Int32 nPos
= mnCurrentPos
;
1929 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
1931 long nHeightDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
);
1932 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1933 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( nPos
) );
1934 maFocusRect
.SetSize( aSz
);
1935 ImplShowFocusRect();
1936 Control::GetFocus();
1939 void ImplListBoxWindow::LoseFocus()
1941 ImplHideFocusRect();
1942 Control::LoseFocus();
1945 void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop
)
1947 if( mpEntryList
->GetEntryCount() == 0 )
1950 long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1952 sal_Int32 nLastEntry
= mpEntryList
->GetEntryCount()-1;
1953 if( nTop
> nLastEntry
)
1955 const ImplEntryType
* pLast
= mpEntryList
->GetEntryPtr( nLastEntry
);
1956 while( nTop
> 0 && mpEntryList
->GetAddedHeight( nLastEntry
, nTop
-1 ) + pLast
->mnHeight
<= nWHeight
)
1959 if ( nTop
!= mnTop
)
1961 ImplClearLayoutData();
1962 long nDiff
= mpEntryList
->GetAddedHeight( mnTop
, nTop
);
1964 ImplHideFocusRect();
1969 ImplShowFocusRect();
1970 maScrollHdl
.Call( this );
1974 void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos
)
1976 if( meProminentType
== ProminentEntry::MIDDLE
)
1978 sal_Int32 nPos
= nEntryPos
;
1979 long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1980 while( nEntryPos
> 0 && mpEntryList
->GetAddedHeight( nPos
+1, nEntryPos
) < nWHeight
/2 )
1983 SetTopEntry( nEntryPos
);
1986 void ImplListBoxWindow::SetLeftIndent( long n
)
1988 ScrollHorz( n
- mnLeft
);
1991 void ImplListBoxWindow::ScrollHorz( long n
)
1996 long nWidth
= GetOutputSizePixel().Width();
1997 if( ( mnMaxWidth
- mnLeft
+ n
) > nWidth
)
2005 nDiff
= - ( ( mnLeft
> nAbs
) ? nAbs
: mnLeft
);
2011 ImplClearLayoutData();
2012 mnLeft
= sal::static_int_cast
<sal_uInt16
>(mnLeft
+ nDiff
);
2014 ImplHideFocusRect();
2015 Scroll( -nDiff
, 0 );
2018 ImplShowFocusRect();
2019 maScrollHdl
.Call( this );
2023 Size
ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines
) const
2025 // FIXME: ListBoxEntryFlags::MultiLine
2028 aSz
.Height() = nMaxLines
* mnMaxHeight
;
2029 aSz
.Width() = mnMaxWidth
+ 2*mnBorder
;
2033 Rectangle
ImplListBoxWindow::GetBoundingRectangle( sal_Int32 nItem
) const
2035 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nItem
);
2036 Size
aSz( GetSizePixel().Width(), pEntry
? pEntry
->mnHeight
: GetEntryHeight() );
2037 long nY
= mpEntryList
->GetAddedHeight( nItem
, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeight();
2038 Rectangle
aRect( Point( 0, nY
), aSz
);
2042 void ImplListBoxWindow::StateChanged( StateChangedType nType
)
2044 Control::StateChanged( nType
);
2046 if ( nType
== StateChangedType::Zoom
)
2048 ApplySettings(*this);
2052 else if ( nType
== StateChangedType::UpdateMode
)
2054 if ( IsUpdateMode() && IsReallyVisible() )
2057 else if ( nType
== StateChangedType::ControlFont
)
2059 ApplySettings(*this);
2063 else if ( nType
== StateChangedType::ControlForeground
)
2065 ApplySettings(*this);
2068 else if ( nType
== StateChangedType::ControlBackground
)
2070 ApplySettings(*this);
2073 else if( nType
== StateChangedType::Enable
)
2078 ImplClearLayoutData();
2081 void ImplListBoxWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
2083 Control::DataChanged( rDCEvt
);
2085 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2086 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2087 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2088 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2090 ImplClearLayoutData();
2091 ApplySettings(*this);
2097 DrawTextFlags
ImplListBoxWindow::ImplGetTextStyle() const
2099 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2101 if (mpEntryList
->HasImages())
2102 nTextStyle
|= DrawTextFlags::Left
;
2104 nTextStyle
|= DrawTextFlags::Center
;
2106 nTextStyle
|= DrawTextFlags::Right
;
2108 nTextStyle
|= DrawTextFlags::Left
;
2113 ImplListBox::ImplListBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
2114 Control( pParent
, nWinStyle
),
2115 maLBWindow(VclPtr
<ImplListBoxWindow
>::Create( this, nWinStyle
&(~WB_BORDER
) ))
2117 // for native widget rendering we must be able to detect this window type
2118 SetType( WINDOW_LISTBOXWINDOW
);
2120 mpVScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_VSCROLL
| WB_DRAG
);
2121 mpHScrollBar
= VclPtr
<ScrollBar
>::Create( this, WB_HSCROLL
| WB_DRAG
);
2122 mpScrollBarBox
= VclPtr
<ScrollBarBox
>::Create( this );
2124 Link
<ScrollBar
*,void> aLink( LINK( this, ImplListBox
, ScrollBarHdl
) );
2125 mpVScrollBar
->SetScrollHdl( aLink
);
2126 mpHScrollBar
->SetScrollHdl( aLink
);
2130 mbAutoHScroll
= ( nWinStyle
& WB_AUTOHSCROLL
);
2131 mbEdgeBlending
= false;
2133 maLBWindow
->SetScrollHdl( LINK( this, ImplListBox
, LBWindowScrolled
) );
2134 maLBWindow
->SetMRUChangedHdl( LINK( this, ImplListBox
, MRUChanged
) );
2135 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2139 ImplListBox::~ImplListBox()
2144 void ImplListBox::dispose()
2146 mpHScrollBar
.disposeAndClear();
2147 mpVScrollBar
.disposeAndClear();
2148 mpScrollBarBox
.disposeAndClear();
2149 maLBWindow
.disposeAndClear();
2153 void ImplListBox::Clear()
2155 maLBWindow
->Clear();
2156 if ( GetEntryList()->GetMRUCount() )
2158 maLBWindow
->GetEntryList()->SetMRUCount( 0 );
2159 maLBWindow
->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND
);
2161 mpVScrollBar
->SetThumbPos( 0 );
2162 mpHScrollBar
->SetThumbPos( 0 );
2163 CompatStateChanged( StateChangedType::Data
);
2166 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
)
2168 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
);
2169 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2170 if (nNewPos
== LISTBOX_ERROR
)
2175 CompatStateChanged( StateChangedType::Data
);
2179 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
, const Image
& rImage
)
2181 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
, rImage
);
2182 sal_Int32 nNewPos
= maLBWindow
->InsertEntry( nPos
, pNewEntry
);
2183 if (nNewPos
== LISTBOX_ERROR
)
2188 CompatStateChanged( StateChangedType::Data
);
2192 void ImplListBox::RemoveEntry( sal_Int32 nPos
)
2194 maLBWindow
->RemoveEntry( nPos
);
2195 CompatStateChanged( StateChangedType::Data
);
2198 void ImplListBox::SetEntryFlags( sal_Int32 nPos
, ListBoxEntryFlags nFlags
)
2200 maLBWindow
->SetEntryFlags( nPos
, nFlags
);
2203 void ImplListBox::SelectEntry( sal_Int32 nPos
, bool bSelect
)
2205 maLBWindow
->SelectEntry( nPos
, bSelect
);
2208 void ImplListBox::SetNoSelection()
2210 maLBWindow
->DeselectAll();
2213 void ImplListBox::GetFocus()
2216 maLBWindow
->GrabFocus();
2218 Control::GetFocus();
2221 void ImplListBox::Resize()
2224 ImplResizeControls();
2225 ImplCheckScrollBars();
2228 IMPL_LINK_NOARG(ImplListBox
, MRUChanged
, LinkParamNone
*, void)
2230 CompatStateChanged( StateChangedType::Data
);
2233 IMPL_LINK_NOARG(ImplListBox
, LBWindowScrolled
, ImplListBoxWindow
*, void)
2235 long nSet
= GetTopEntry();
2236 if( nSet
> mpVScrollBar
->GetRangeMax() )
2237 mpVScrollBar
->SetRangeMax( GetEntryList()->GetEntryCount() );
2238 mpVScrollBar
->SetThumbPos( GetTopEntry() );
2240 mpHScrollBar
->SetThumbPos( GetLeftIndent() );
2242 maScrollHdl
.Call( this );
2245 IMPL_LINK( ImplListBox
, ScrollBarHdl
, ScrollBar
*, pSB
, void )
2247 sal_uInt16 nPos
= (sal_uInt16
) pSB
->GetThumbPos();
2248 if( pSB
== mpVScrollBar
)
2249 SetTopEntry( nPos
);
2250 else if( pSB
== mpHScrollBar
)
2251 SetLeftIndent( nPos
);
2254 void ImplListBox::ImplCheckScrollBars()
2256 bool bArrange
= false;
2258 Size aOutSz
= GetOutputSizePixel();
2259 sal_Int32 nEntries
= GetEntryList()->GetEntryCount();
2260 sal_uInt16 nMaxVisEntries
= (sal_uInt16
) (aOutSz
.Height() / GetEntryHeight());
2262 // vertical ScrollBar
2263 if( nEntries
> nMaxVisEntries
)
2269 // check of the scrolled-out region
2270 if( GetEntryList()->GetSelectEntryCount() == 1 &&
2271 GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2272 ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2274 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2284 // horizontal ScrollBar
2287 long nWidth
= (sal_uInt16
) aOutSz
.Width();
2289 nWidth
-= mpVScrollBar
->GetSizePixel().Width();
2291 long nMaxWidth
= GetMaxEntryWidth();
2292 if( nWidth
< nMaxWidth
)
2298 if ( !mbVScroll
) // maybe we do need one now
2300 nMaxVisEntries
= (sal_uInt16
) ( ( aOutSz
.Height() - mpHScrollBar
->GetSizePixel().Height() ) / GetEntryHeight() );
2301 if( nEntries
> nMaxVisEntries
)
2306 // check of the scrolled-out region
2307 if( GetEntryList()->GetSelectEntryCount() == 1 &&
2308 GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2309 ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2311 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2315 // check of the scrolled-out region
2316 sal_uInt16 nMaxLI
= (sal_uInt16
) (nMaxWidth
- nWidth
);
2317 if ( nMaxLI
< GetLeftIndent() )
2318 SetLeftIndent( nMaxLI
);
2330 ImplResizeControls();
2332 ImplInitScrollBars();
2335 void ImplListBox::ImplInitScrollBars()
2337 Size aOutSz
= maLBWindow
->GetOutputSizePixel();
2341 sal_Int32 nEntries
= GetEntryList()->GetEntryCount();
2342 sal_uInt16 nVisEntries
= (sal_uInt16
) (aOutSz
.Height() / GetEntryHeight());
2343 mpVScrollBar
->SetRangeMax( nEntries
);
2344 mpVScrollBar
->SetVisibleSize( nVisEntries
);
2345 mpVScrollBar
->SetPageSize( nVisEntries
- 1 );
2350 mpHScrollBar
->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL
);
2351 mpHScrollBar
->SetVisibleSize( (sal_uInt16
)aOutSz
.Width() );
2352 mpHScrollBar
->SetLineSize( HORZ_SCROLL
);
2353 mpHScrollBar
->SetPageSize( aOutSz
.Width() - HORZ_SCROLL
);
2357 void ImplListBox::ImplResizeControls()
2359 // Here we only position the Controls; if the Scrollbars are to be
2360 // visible is already determined in ImplCheckScrollBars
2362 Size aOutSz
= GetOutputSizePixel();
2363 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2364 nSBWidth
= CalcZoom( nSBWidth
);
2366 Size
aInnerSz( aOutSz
);
2368 aInnerSz
.Width() -= nSBWidth
;
2370 aInnerSz
.Height() -= nSBWidth
;
2372 // pb: #106948# explicit mirroring for calc
2373 // Scrollbar on left or right side?
2374 bool bMirroring
= maLBWindow
->IsMirroring();
2375 Point
aWinPos( bMirroring
&& mbVScroll
? nSBWidth
: 0, 0 );
2376 maLBWindow
->SetPosSizePixel( aWinPos
, aInnerSz
);
2379 if( mbVScroll
&& mbHScroll
)
2381 Point
aBoxPos( bMirroring
? 0 : aInnerSz
.Width(), aInnerSz
.Height() );
2382 mpScrollBarBox
->SetPosSizePixel( aBoxPos
, Size( nSBWidth
, nSBWidth
) );
2383 mpScrollBarBox
->Show();
2387 mpScrollBarBox
->Hide();
2390 // vertical ScrollBar
2393 // Scrollbar on left or right side?
2394 Point
aVPos( bMirroring
? 0 : aOutSz
.Width() - nSBWidth
, 0 );
2395 mpVScrollBar
->SetPosSizePixel( aVPos
, Size( nSBWidth
, aInnerSz
.Height() ) );
2396 mpVScrollBar
->Show();
2400 mpVScrollBar
->Hide();
2401 // #107254# Don't reset top entry after resize, but check for max top entry
2402 SetTopEntry( GetTopEntry() );
2405 // horizontal ScrollBar
2408 Point
aHPos( ( bMirroring
&& mbVScroll
) ? nSBWidth
: 0, aOutSz
.Height() - nSBWidth
);
2409 mpHScrollBar
->SetPosSizePixel( aHPos
, Size( aInnerSz
.Width(), nSBWidth
) );
2410 mpHScrollBar
->Show();
2414 mpHScrollBar
->Hide();
2419 void ImplListBox::StateChanged( StateChangedType nType
)
2421 if ( nType
== StateChangedType::InitShow
)
2423 ImplCheckScrollBars();
2425 else if ( ( nType
== StateChangedType::UpdateMode
) || ( nType
== StateChangedType::Data
) )
2427 bool bUpdate
= IsUpdateMode();
2428 maLBWindow
->SetUpdateMode( bUpdate
);
2429 if ( bUpdate
&& IsReallyVisible() )
2430 ImplCheckScrollBars();
2432 else if( nType
== StateChangedType::Enable
)
2434 mpHScrollBar
->Enable( IsEnabled() );
2435 mpVScrollBar
->Enable( IsEnabled() );
2436 mpScrollBarBox
->Enable( IsEnabled() );
2437 maLBWindow
->Enable( IsEnabled() );
2441 else if ( nType
== StateChangedType::Zoom
)
2443 maLBWindow
->SetZoom( GetZoom() );
2446 else if ( nType
== StateChangedType::ControlFont
)
2448 maLBWindow
->SetControlFont( GetControlFont() );
2450 else if ( nType
== StateChangedType::ControlForeground
)
2452 maLBWindow
->SetControlForeground( GetControlForeground() );
2454 else if ( nType
== StateChangedType::ControlBackground
)
2456 maLBWindow
->SetControlBackground( GetControlBackground() );
2458 else if( nType
== StateChangedType::Mirroring
)
2460 maLBWindow
->EnableRTL( IsRTLEnabled() );
2461 mpHScrollBar
->EnableRTL( IsRTLEnabled() );
2462 mpVScrollBar
->EnableRTL( IsRTLEnabled() );
2463 ImplResizeControls();
2466 Control::StateChanged( nType
);
2469 bool ImplListBox::EventNotify( NotifyEvent
& rNEvt
)
2472 if ( rNEvt
.GetType() == MouseNotifyEvent::COMMAND
)
2474 const CommandEvent
& rCEvt
= *rNEvt
.GetCommandEvent();
2475 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2477 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2478 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2480 bDone
= HandleScrollCommand( rCEvt
, mpHScrollBar
, mpVScrollBar
);
2485 return bDone
|| Window::EventNotify( rNEvt
);
2488 const Wallpaper
& ImplListBox::GetDisplayBackground() const
2490 return maLBWindow
->GetDisplayBackground();
2493 bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent
& rCEvt
)
2496 if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
2498 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2499 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2501 sal_uInt16 nKey
= ( pData
->GetDelta() < 0 ) ? KEY_DOWN
: KEY_UP
;
2502 KeyEvent
aKeyEvent( 0, vcl::KeyCode( nKey
) );
2503 bDone
= ProcessKeyInput( aKeyEvent
);
2509 void ImplListBox::SetMRUEntries( const OUString
& rEntries
, sal_Unicode cSep
)
2511 bool bChanges
= GetEntryList()->GetMRUCount() != 0;
2513 // Remove old MRU entries
2514 for ( sal_Int32 n
= GetEntryList()->GetMRUCount();n
; )
2515 maLBWindow
->RemoveEntry( --n
);
2517 sal_Int32 nMRUCount
= 0;
2518 sal_Int32 nIndex
= 0;
2521 OUString aEntry
= rEntries
.getToken( 0, cSep
, nIndex
);
2522 // Accept only existing entries
2523 if ( GetEntryList()->FindEntry( aEntry
) != LISTBOX_ENTRY_NOTFOUND
)
2525 ImplEntryType
* pNewEntry
= new ImplEntryType( aEntry
);
2526 maLBWindow
->GetEntryList()->InsertEntry( nMRUCount
++, pNewEntry
, false );
2530 while ( nIndex
>= 0 );
2534 maLBWindow
->GetEntryList()->SetMRUCount( nMRUCount
);
2535 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
2536 CompatStateChanged( StateChangedType::Data
);
2540 OUString
ImplListBox::GetMRUEntries( sal_Unicode cSep
) const
2542 OUStringBuffer aEntries
;
2543 for ( sal_Int32 n
= 0; n
< GetEntryList()->GetMRUCount(); n
++ )
2545 aEntries
.append(GetEntryList()->GetEntryText( n
));
2546 if( n
< ( GetEntryList()->GetMRUCount() - 1 ) )
2547 aEntries
.append(cSep
);
2549 return aEntries
.makeStringAndClear();
2552 void ImplListBox::SetEdgeBlending(bool bNew
)
2554 if(mbEdgeBlending
!= bNew
)
2556 mbEdgeBlending
= bNew
;
2557 maLBWindow
->SetEdgeBlending(GetEdgeBlending());
2561 ImplWin::ImplWin( vcl::Window
* pParent
, WinBits nWinStyle
) :
2562 Control ( pParent
, nWinStyle
)
2564 if ( IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2565 && ! IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
2568 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2570 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
2572 mbInUserDraw
= false;
2573 mbUserDrawEnabled
= false;
2574 mbEdgeBlending
= false;
2575 mnItemPos
= LISTBOX_ENTRY_NOTFOUND
;
2578 void ImplWin::MouseButtonDown( const MouseEvent
& )
2582 maMBDownHdl
.Call(this);
2586 void ImplWin::FillLayoutData() const
2588 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
2589 ImplWin
* pThis
= const_cast<ImplWin
*>(this);
2590 pThis
->ImplDraw(*pThis
, true);
2593 bool ImplWin::PreNotify( NotifyEvent
& rNEvt
)
2595 const MouseEvent
* pMouseEvt
= nullptr;
2597 if( (rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
) && (pMouseEvt
= rNEvt
.GetMouseEvent()) != nullptr )
2599 if( pMouseEvt
->IsEnterWindow() || pMouseEvt
->IsLeaveWindow() )
2601 // trigger redraw as mouse over state has changed
2602 if ( IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2603 && ! IsNativeControlSupported(ControlType::Listbox
, ControlPart::ButtonDown
) )
2605 GetParent()->GetWindow( GetWindowType::Border
)->Invalidate( InvalidateFlags::NoErase
);
2606 GetParent()->GetWindow( GetWindowType::Border
)->Update();
2611 return Control::PreNotify(rNEvt
);
2614 void ImplWin::ImplDraw(vcl::RenderContext
& rRenderContext
, bool bLayout
)
2616 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2620 bool bNativeOK
= false;
2622 ControlState nState
= ControlState::ENABLED
;
2623 if (rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::Entire
)
2624 && rRenderContext
.IsNativeControlSupported(ControlType::Listbox
, ControlPart::HasBackgroundTexture
) )
2626 // Repaint the (focused) area similarly to
2627 // ImplSmallBorderWindowView::DrawWindow() in
2628 // vcl/source/window/brdwin.cxx
2629 vcl::Window
*pWin
= GetParent();
2631 ImplControlValue aControlValue
;
2632 if ( !pWin
->IsEnabled() )
2633 nState
&= ~ControlState::ENABLED
;
2634 if ( pWin
->HasFocus() )
2635 nState
|= ControlState::FOCUSED
;
2637 // The listbox is painted over the entire control including the
2638 // border, but ImplWin does not contain the border => correction
2640 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2641 pWin
->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2642 Point
aPoint( -nLeft
, -nTop
);
2643 Rectangle
aCtrlRegion( aPoint
- GetPosPixel(), pWin
->GetSizePixel() );
2645 bool bMouseOver
= false;
2648 vcl::Window
*pChild
= GetParent()->GetWindow( GetWindowType::FirstChild
);
2649 while( pChild
&& !(bMouseOver
= pChild
->IsMouseOver()) )
2650 pChild
= pChild
->GetWindow( GetWindowType::Next
);
2654 nState
|= ControlState::ROLLOVER
;
2656 // if parent has no border, then nobody has drawn the background
2657 // since no border window exists. so draw it here.
2658 WinBits nParentStyle
= pWin
->GetStyle();
2659 if( ! (nParentStyle
& WB_BORDER
) || (nParentStyle
& WB_NOBORDER
) )
2661 Rectangle
aParentRect( Point( 0, 0 ), pWin
->GetSizePixel() );
2662 pWin
->DrawNativeControl( ControlType::Listbox
, ControlPart::Entire
, aParentRect
,
2663 nState
, aControlValue
, OUString() );
2666 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Listbox
, ControlPart::Entire
, aCtrlRegion
,
2667 nState
, aControlValue
, OUString());
2672 if (HasFocus() && !ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2674 rRenderContext
.SetTextColor( rStyleSettings
.GetHighlightTextColor() );
2675 rRenderContext
.SetFillColor( rStyleSettings
.GetHighlightColor() );
2676 rRenderContext
.DrawRect( maFocusRect
);
2681 if( ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2683 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2684 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
2686 aColor
= rStyleSettings
.GetButtonTextColor();
2690 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2691 aColor
= rStyleSettings
.GetFieldRolloverTextColor();
2693 aColor
= rStyleSettings
.GetFieldTextColor();
2695 if (IsControlForeground())
2696 aColor
= GetControlForeground();
2697 rRenderContext
.SetTextColor(aColor
);
2699 rRenderContext
.Erase(maFocusRect
);
2704 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
2706 rRenderContext
.Erase(maFocusRect
);
2710 if ( IsUserDrawEnabled() )
2712 mbInUserDraw
= true;
2713 UserDrawEvent
aUDEvt(this, &rRenderContext
, maFocusRect
, mnItemPos
, 0);
2714 maUserDrawHdl
.Call( &aUDEvt
);
2715 mbInUserDraw
= false;
2719 DrawEntry(rRenderContext
, true, false, bLayout
);
2723 void ImplWin::ApplySettings(vcl::RenderContext
& rRenderContext
)
2725 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2727 vcl::Font aFont
= rStyleSettings
.GetFieldFont();
2728 if (IsControlFont())
2729 aFont
.Merge(GetControlFont());
2730 SetZoomedPointFont(rRenderContext
, aFont
);
2732 Color aTextColor
= rStyleSettings
.GetFieldTextColor();
2733 if (IsControlForeground())
2734 aTextColor
= GetControlForeground();
2735 rRenderContext
.SetTextColor(aTextColor
);
2737 if (IsControlBackground())
2738 rRenderContext
.SetBackground(GetControlBackground());
2740 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
2743 void ImplWin::Paint( vcl::RenderContext
& rRenderContext
, const Rectangle
& )
2745 ImplDraw(rRenderContext
);
2748 void ImplWin::DrawEntry(vcl::RenderContext
& rRenderContext
, bool bDrawImage
, bool bDrawTextAtImagePos
, bool bLayout
)
2751 Size
aOutSz(GetOutputSizePixel());
2753 bool bImage
= !!maImage
;
2754 if (bDrawImage
&& bImage
&& !bLayout
)
2756 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
2757 Size aImgSz
= maImage
.GetSizePixel();
2758 Point
aPtImg( nBorder
, ( ( aOutSz
.Height() - aImgSz
.Height() ) / 2 ) );
2759 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2761 // check for HC mode
2762 Image
*pImage
= &maImage
;
2766 rRenderContext
.DrawImage( aPtImg
, *pImage
, nStyle
);
2770 aImgSz
.Width() = CalcZoom( aImgSz
.Width() );
2771 aImgSz
.Height() = CalcZoom( aImgSz
.Height() );
2772 rRenderContext
.DrawImage( aPtImg
, aImgSz
, *pImage
, nStyle
);
2775 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
2777 if(nEdgeBlendingPercent
)
2779 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
2780 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
2781 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
2782 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
2784 if(!aBlendFrame
.IsEmpty())
2786 rRenderContext
.DrawBitmapEx(aPtImg
, aBlendFrame
);
2791 if( !maString
.isEmpty() )
2793 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
2795 if ( bDrawImage
&& bImage
&& !bLayout
)
2796 nTextStyle
|= DrawTextFlags::Left
;
2797 else if ( GetStyle() & WB_CENTER
)
2798 nTextStyle
|= DrawTextFlags::Center
;
2799 else if ( GetStyle() & WB_RIGHT
)
2800 nTextStyle
|= DrawTextFlags::Right
;
2802 nTextStyle
|= DrawTextFlags::Left
;
2804 Rectangle
aTextRect( Point( nBorder
, 0 ), Size( aOutSz
.Width()-2*nBorder
, aOutSz
.Height() ) );
2806 if ( !bDrawTextAtImagePos
&& ( bImage
|| IsUserDrawEnabled() ) )
2808 aTextRect
.Left() += maImage
.GetSizePixel().Width() + IMG_TXT_DISTANCE
;
2811 MetricVector
* pVector
= bLayout
? &mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
: nullptr;
2812 OUString
* pDisplayText
= bLayout
? &mpControlData
->mpLayoutData
->m_aDisplayText
: nullptr;
2813 rRenderContext
.DrawText( aTextRect
, maString
, nTextStyle
, pVector
, pDisplayText
);
2816 if( HasFocus() && !bLayout
)
2817 ShowFocus( maFocusRect
);
2820 void ImplWin::Resize()
2823 maFocusRect
.SetSize( GetOutputSizePixel() );
2827 void ImplWin::GetFocus()
2829 ShowFocus( maFocusRect
);
2830 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2831 IsNativeWidgetEnabled() &&
2832 IsNativeControlSupported( ControlType::Listbox
, ControlPart::Entire
) )
2834 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2841 Control::GetFocus();
2844 void ImplWin::LoseFocus()
2847 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2848 IsNativeWidgetEnabled() &&
2849 IsNativeControlSupported( ControlType::Listbox
, ControlPart::Entire
) )
2851 vcl::Window
* pWin
= GetParent()->GetWindow( GetWindowType::Border
);
2858 Control::LoseFocus();
2861 void ImplWin::ShowFocus(const Rectangle
& rRect
)
2863 if (IsNativeControlSupported(ControlType::Listbox
, ControlPart::Focus
))
2865 ImplControlValue aControlValue
;
2867 vcl::Window
*pWin
= GetParent();
2868 Rectangle
aParentRect(Point(0, 0), pWin
->GetSizePixel());
2869 pWin
->DrawNativeControl(ControlType::Listbox
, ControlPart::Focus
, aParentRect
,
2870 ControlState::FOCUSED
, aControlValue
, OUString());
2872 Control::ShowFocus(rRect
);
2875 ImplBtn::ImplBtn( vcl::Window
* pParent
, WinBits nWinStyle
) :
2876 PushButton( pParent
, nWinStyle
),
2881 void ImplBtn::MouseButtonDown( const MouseEvent
& )
2883 //PushButton::MouseButtonDown( rMEvt );
2886 maMBDownHdl
.Call(this);
2891 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( vcl::Window
* pParent
) :
2892 FloatingWindow( pParent
, WB_BORDER
| WB_SYSTEMWINDOW
| WB_NOSHADOW
) // no drop shadow for list boxes
2896 mbAutoWidth
= false;
2898 mnPopupModeStartSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
2900 vcl::Window
* pBorderWindow
= ImplGetBorderWindow();
2903 SetAccessibleRole(accessibility::AccessibleRole::PANEL
);
2904 pBorderWindow
->SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2908 SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2913 ImplListBoxFloatingWindow::~ImplListBoxFloatingWindow()
2918 void ImplListBoxFloatingWindow::dispose()
2921 FloatingWindow::dispose();
2925 bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent
& rNEvt
)
2927 if( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2929 if( !GetParent()->HasChildPathFocus( true ) )
2933 return FloatingWindow::PreNotify( rNEvt
);
2936 void ImplListBoxFloatingWindow::setPosSizePixel( long nX
, long nY
, long nWidth
, long nHeight
, PosSizeFlags nFlags
)
2938 FloatingWindow::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
2940 // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2941 // after a call to Resize(), we adjust its position if necessary
2942 if ( IsReallyVisible() && ( nFlags
& PosSizeFlags::Height
) )
2944 Point aPos
= GetParent()->GetPosPixel();
2945 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2947 if ( nFlags
& PosSizeFlags::X
)
2950 if ( nFlags
& PosSizeFlags::Y
)
2954 SetPosPixel( ImplCalcPos( this, Rectangle( aPos
, GetParent()->GetSizePixel() ), FloatWinPopupFlags::Down
, nIndex
) );
2957 // if( !IsReallyVisible() )
2959 // The ImplListBox does not get a Resize() as not visible.
2960 // But the windows must get a Resize(), so that the number of
2961 // visible entries is correct for PgUp/PgDown.
2962 // The number also cannot be calculated by List/Combobox, as for
2963 // this the presence of the vertical Scrollbar has to be known.
2964 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
2965 static_cast<vcl::Window
*>(mpImplLB
)->Resize();
2966 static_cast<vcl::Window
*>(mpImplLB
->GetMainWindow())->Resize();
2970 void ImplListBoxFloatingWindow::Resize()
2972 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
2973 FloatingWindow::Resize();
2976 Size
ImplListBoxFloatingWindow::CalcFloatSize()
2978 Size
aFloatSz( maPrefSz
);
2980 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2981 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2983 sal_Int32 nLines
= mpImplLB
->GetEntryList()->GetEntryCount();
2984 if ( mnDDLineCount
&& ( nLines
> mnDDLineCount
) )
2985 nLines
= mnDDLineCount
;
2987 Size aSz
= mpImplLB
->CalcSize( nLines
);
2988 long nMaxHeight
= aSz
.Height() + nTop
+ nBottom
;
2990 if ( mnDDLineCount
)
2991 aFloatSz
.Height() = nMaxHeight
;
2995 // AutoSize first only for width...
2997 aFloatSz
.Width() = aSz
.Width() + nLeft
+ nRight
;
2998 aFloatSz
.Width() += nRight
; // adding some space looks better...
3000 if ( ( aFloatSz
.Height() < nMaxHeight
) || ( mnDDLineCount
&& ( mnDDLineCount
< mpImplLB
->GetEntryList()->GetEntryCount() ) ) )
3002 // then we also need the vertical Scrollbar
3003 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
3004 aFloatSz
.Width() += nSBWidth
;
3007 long nDesktopWidth
= GetDesktopRectPixel().getWidth();
3008 if (aFloatSz
.Width() > nDesktopWidth
)
3009 // Don't exceed the desktop width.
3010 aFloatSz
.Width() = nDesktopWidth
;
3013 if ( aFloatSz
.Height() > nMaxHeight
)
3014 aFloatSz
.Height() = nMaxHeight
;
3016 // Minimal height, in case height is not set to Float height.
3017 // The parent of FloatWin must be DropDown-Combo/Listbox.
3018 Size aParentSz
= GetParent()->GetSizePixel();
3019 if( (!mnDDLineCount
|| !nLines
) && ( aFloatSz
.Height() < aParentSz
.Height() ) )
3020 aFloatSz
.Height() = aParentSz
.Height();
3022 // do not get narrower than the parent...
3023 if( aFloatSz
.Width() < aParentSz
.Width() )
3024 aFloatSz
.Width() = aParentSz
.Width();
3026 // align height to entries...
3027 long nInnerHeight
= aFloatSz
.Height() - nTop
- nBottom
;
3028 long nEntryHeight
= mpImplLB
->GetEntryHeight();
3029 if ( nInnerHeight
% nEntryHeight
)
3031 nInnerHeight
/= nEntryHeight
;
3033 nInnerHeight
*= nEntryHeight
;
3034 aFloatSz
.Height() = nInnerHeight
+ nTop
+ nBottom
;
3037 if (aFloatSz
.Width() < aSz
.Width())
3039 // The max width of list box entries exceeds the window width.
3040 // Account for the scroll bar height.
3041 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
3042 aFloatSz
.Height() += nSBWidth
;
3048 void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking
)
3050 if( !IsInPopupMode() )
3052 Size aFloatSz
= CalcFloatSize();
3054 SetSizePixel( aFloatSz
);
3055 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
3057 sal_Int32 nPos
= mpImplLB
->GetEntryList()->GetSelectEntryPos( 0 );
3058 mnPopupModeStartSaveSelection
= nPos
;
3060 Size aSz
= GetParent()->GetSizePixel();
3061 Point aPos
= GetParent()->GetPosPixel();
3062 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
3063 // FIXME: this ugly hack is for Mac/Aqua
3064 // should be replaced by a real mechanism to place the float rectangle
3065 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
3066 GetParent()->IsNativeWidgetEnabled() )
3068 const sal_Int32 nLeft
= 4, nTop
= 4, nRight
= 4, nBottom
= 4;
3071 aSz
.Width() -= nLeft
+ nRight
;
3072 aSz
.Height() -= nTop
+ nBottom
;
3074 Rectangle
aRect( aPos
, aSz
);
3076 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3077 // where the document is unmirrored
3078 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3079 vcl::Window
*pGrandparent
= GetParent()->GetParent();
3080 const OutputDevice
*pGrandparentOutDev
= pGrandparent
->GetOutDev();
3082 if( pGrandparent
->ImplIsAntiparallel() )
3083 pGrandparentOutDev
->ReMirror( aRect
);
3085 // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795
3086 StartPopupMode( aRect
, FloatWinPopupFlags::Down
| FloatWinPopupFlags::AllMouseButtonClose
);
3088 if( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
3089 mpImplLB
->ShowProminentEntry( nPos
);
3091 if( bStartTracking
)
3092 mpImplLB
->GetMainWindow()->EnableMouseMoveSelect( true );
3094 if ( mpImplLB
->GetMainWindow()->IsGrabFocusAllowed() )
3095 mpImplLB
->GetMainWindow()->GrabFocus();
3097 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
3101 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */