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.h>
28 #include <vcl/unohelp.hxx>
29 #include <vcl/i18nhelp.hxx>
31 #include <ilstbox.hxx>
32 #include <controldata.hxx>
35 #include <com/sun/star/i18n/XCollator.hpp>
36 #include <com/sun/star/accessibility/XAccessible.hpp>
37 #include <com/sun/star/accessibility/AccessibleRole.hpp>
39 #include <rtl/instance.hxx>
40 #include <comphelper/string.hxx>
41 #include <comphelper/processfactory.hxx>
45 #define MULTILINE_ENTRY_DRAW_FLAGS ( TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_VCENTER )
47 using namespace ::com::sun::star
;
49 void ImplInitFieldSettings( vcl::Window
* pWin
, bool bFont
, bool bForeground
, bool bBackground
)
51 const StyleSettings
& rStyleSettings
= pWin
->GetSettings().GetStyleSettings();
55 vcl::Font aFont
= rStyleSettings
.GetFieldFont();
56 if ( pWin
->IsControlFont() )
57 aFont
.Merge( pWin
->GetControlFont() );
58 pWin
->SetZoomedPointFont( aFont
);
61 if ( bFont
|| bForeground
)
63 Color aTextColor
= rStyleSettings
.GetFieldTextColor();
64 if ( pWin
->IsControlForeground() )
65 aTextColor
= pWin
->GetControlForeground();
66 pWin
->SetTextColor( aTextColor
);
71 if( pWin
->IsControlBackground() )
72 pWin
->SetBackground( pWin
->GetControlBackground() );
74 pWin
->SetBackground( rStyleSettings
.GetFieldColor() );
78 void ImplInitDropDownButton( PushButton
* pButton
)
80 if ( pButton
->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN
)
81 pButton
->SetSymbol( SymbolType::SPIN_UPDOWN
);
83 pButton
->SetSymbol( SymbolType::SPIN_DOWN
);
85 if ( pButton
->IsNativeControlSupported(CTRL_LISTBOX
, PART_ENTIRE_CONTROL
)
86 && ! pButton
->IsNativeControlSupported(CTRL_LISTBOX
, PART_BUTTON_DOWN
) )
87 pButton
->SetBackground();
90 ImplEntryList::ImplEntryList( vcl::Window
* pWindow
)
93 mnLastSelected
= LISTBOX_ENTRY_NOTFOUND
;
94 mnSelectionAnchor
= LISTBOX_ENTRY_NOTFOUND
;
96 mbCallSelectionChangedHdl
= true;
102 ImplEntryList::~ImplEntryList()
107 void ImplEntryList::Clear()
113 void ImplEntryList::SelectEntry( sal_Int32 nPos
, bool bSelect
)
115 if (0 <= nPos
&& static_cast<size_t>(nPos
) < maEntries
.size())
117 boost::ptr_vector
<ImplEntryType
>::iterator iter
= maEntries
.begin()+nPos
;
119 if ( ( iter
->mbIsSelected
!= bSelect
) &&
120 ( (iter
->mnFlags
& LISTBOX_ENTRY_FLAG_DISABLE_SELECTION
) == 0 ) )
122 iter
->mbIsSelected
= bSelect
;
123 if ( mbCallSelectionChangedHdl
)
124 maSelectionChangedHdl
.Call( reinterpret_cast<void*>(nPos
) );
132 : public rtl::StaticWithInit
< comphelper::string::NaturalStringSorter
, theSorter
>
134 comphelper::string::NaturalStringSorter
operator () ()
136 return comphelper::string::NaturalStringSorter(
137 ::comphelper::getProcessComponentContext(),
138 Application::GetSettings().GetLanguageTag().getLocale());
143 sal_Int32
ImplEntryList::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
, bool bSort
)
145 if (nPos
< 0 || LISTBOX_MAX_ENTRIES
<= maEntries
.size())
146 return LISTBOX_ERROR
;
148 if ( !!pNewEntry
->maImage
)
151 sal_Int32 insPos
= 0;
153 if ( !bSort
|| maEntries
.empty())
155 if (0 <= nPos
&& static_cast<size_t>(nPos
) < maEntries
.size())
158 maEntries
.insert( maEntries
.begin() + nPos
, pNewEntry
);
162 insPos
= maEntries
.size();
163 maEntries
.push_back(pNewEntry
);
168 const comphelper::string::NaturalStringSorter
&rSorter
= theSorter::get();
170 const OUString
& rStr
= pNewEntry
->maStr
;
171 sal_uLong nLow
, nHigh
, nMid
;
173 nHigh
= maEntries
.size();
175 ImplEntryType
* pTemp
= GetEntry( (sal_Int32
)(nHigh
-1) );
179 sal_Int32 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
181 // fast insert for sorted data
184 insPos
= maEntries
.size();
185 maEntries
.push_back(pNewEntry
);
190 pTemp
= (ImplEntryType
*)GetEntry( (sal_Int32
)nLow
);
192 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
196 maEntries
.insert(maEntries
.begin(),pNewEntry
);
204 nMid
= (nLow
+ nHigh
) / 2;
205 pTemp
= (ImplEntryType
*)GetEntry( nMid
);
207 nComp
= rSorter
.compare(rStr
, pTemp
->maStr
);
219 while ( nLow
<= nHigh
);
225 maEntries
.insert(maEntries
.begin()+nMid
,pNewEntry
);
229 catch (uno::RuntimeException
& )
231 // XXX this is arguable, if the exception occurred because pNewEntry is
232 // garbage you wouldn't insert it. If the exception occurred because the
233 // Collator implementation is garbage then give the user a chance to see
236 maEntries
.insert(maEntries
.begin(),pNewEntry
);
244 void ImplEntryList::RemoveEntry( sal_Int32 nPos
)
246 if (0 <= nPos
&& static_cast<size_t>(nPos
) < maEntries
.size())
248 boost::ptr_vector
<ImplEntryType
>::iterator iter
= maEntries
.begin()+ nPos
;
250 if ( !!iter
->maImage
)
253 maEntries
.erase(iter
);
257 sal_Int32
ImplEntryList::FindEntry( const OUString
& rString
, bool bSearchMRUArea
) const
259 sal_Int32 nEntries
= maEntries
.size();
260 for ( sal_Int32 n
= bSearchMRUArea
? 0 : GetMRUCount(); n
< nEntries
; n
++ )
262 OUString
aComp( vcl::I18nHelper::filterFormattingChars( maEntries
[n
].maStr
) );
263 if ( aComp
== rString
)
266 return LISTBOX_ENTRY_NOTFOUND
;
269 sal_Int32
ImplEntryList::FindMatchingEntry( const OUString
& rStr
, sal_Int32 nStart
, bool bForward
, bool bLazy
) const
271 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
272 sal_Int32 nEntryCount
= GetEntryCount();
274 nStart
++; // decrements right away
276 const vcl::I18nHelper
& rI18nHelper
= mpWindow
->GetSettings().GetLocaleI18nHelper();
277 for ( sal_Int32 n
= nStart
; bForward
? n
< nEntryCount
: n
!= 0; )
282 ImplEntryType
* pImplEntry
= GetEntry( n
);
286 bMatch
= rI18nHelper
.MatchString( rStr
, pImplEntry
->maStr
);
290 bMatch
= rStr
.isEmpty() || (pImplEntry
->maStr
.startsWith(rStr
));
305 sal_Int32
ImplEntryList::FindEntry( const void* pData
) const
307 sal_Int32 nPos
= LISTBOX_ENTRY_NOTFOUND
;
308 for ( sal_Int32 n
= GetEntryCount(); n
; )
310 ImplEntryType
* pImplEntry
= GetEntry( --n
);
311 if ( pImplEntry
->mpUserData
== pData
)
320 long ImplEntryList::GetAddedHeight( sal_Int32 i_nEndIndex
, sal_Int32 i_nBeginIndex
, long i_nBeginHeight
) const
322 long nHeight
= i_nBeginHeight
;
323 sal_Int32 nStart
= i_nEndIndex
> i_nBeginIndex
? i_nBeginIndex
: i_nEndIndex
;
324 sal_Int32 nStop
= i_nEndIndex
> i_nBeginIndex
? i_nEndIndex
: i_nBeginIndex
;
325 sal_Int32 nEntryCount
= GetEntryCount();
326 if( 0 <= nStop
&& nStop
!= LISTBOX_ENTRY_NOTFOUND
&& nEntryCount
!= 0 )
329 if( nStop
> nEntryCount
-1 )
330 nStop
= nEntryCount
-1;
333 else if( nStart
> nEntryCount
-1 )
334 nStart
= nEntryCount
-1;
336 sal_Int32 nIndex
= nStart
;
337 while( nIndex
!= LISTBOX_ENTRY_NOTFOUND
&& nIndex
< nStop
)
339 long nPosHeight
= GetEntryPtr( nIndex
)->mnHeight
;
340 if (nHeight
> ::std::numeric_limits
<long>::max() - nPosHeight
)
342 SAL_WARN( "vcl", "ImplEntryList::GetAddedHeight: truncated");
345 nHeight
+= nPosHeight
;
351 return i_nEndIndex
> i_nBeginIndex
? nHeight
: -nHeight
;
354 long ImplEntryList::GetEntryHeight( sal_Int32 nPos
) const
356 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
357 return pImplEntry
? pImplEntry
->mnHeight
: 0;
360 OUString
ImplEntryList::GetEntryText( sal_Int32 nPos
) const
363 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
365 aEntryText
= pImplEntry
->maStr
;
369 bool ImplEntryList::HasEntryImage( sal_Int32 nPos
) const
372 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
374 bImage
= !!pImplEntry
->maImage
;
378 Image
ImplEntryList::GetEntryImage( sal_Int32 nPos
) const
381 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
383 aImage
= pImplEntry
->maImage
;
387 void ImplEntryList::SetEntryData( sal_Int32 nPos
, void* pNewData
)
389 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
391 pImplEntry
->mpUserData
= pNewData
;
394 void* ImplEntryList::GetEntryData( sal_Int32 nPos
) const
396 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
397 return pImplEntry
? pImplEntry
->mpUserData
: NULL
;
400 void ImplEntryList::SetEntryFlags( sal_Int32 nPos
, long nFlags
)
402 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
404 pImplEntry
->mnFlags
= nFlags
;
407 long ImplEntryList::GetEntryFlags( sal_Int32 nPos
) const
409 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
410 return pImplEntry
? pImplEntry
->mnFlags
: 0;
413 sal_Int32
ImplEntryList::GetSelectEntryCount() const
415 sal_Int32 nSelCount
= 0;
416 for ( sal_Int32 n
= GetEntryCount(); n
; )
418 ImplEntryType
* pImplEntry
= GetEntry( --n
);
419 if ( pImplEntry
->mbIsSelected
)
425 OUString
ImplEntryList::GetSelectEntry( sal_Int32 nIndex
) const
427 return GetEntryText( GetSelectEntryPos( nIndex
) );
430 sal_Int32
ImplEntryList::GetSelectEntryPos( sal_Int32 nIndex
) const
432 sal_Int32 nSelEntryPos
= LISTBOX_ENTRY_NOTFOUND
;
434 sal_Int32 nEntryCount
= GetEntryCount();
436 for ( sal_Int32 n
= 0; n
< nEntryCount
; n
++ )
438 ImplEntryType
* pImplEntry
= GetEntry( n
);
439 if ( pImplEntry
->mbIsSelected
)
441 if ( nSel
== nIndex
)
453 bool ImplEntryList::IsEntryPosSelected( sal_Int32 nIndex
) const
455 ImplEntryType
* pImplEntry
= GetEntry( nIndex
);
456 return pImplEntry
&& pImplEntry
->mbIsSelected
;
459 bool ImplEntryList::IsEntrySelectable( sal_Int32 nPos
) const
461 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
462 return pImplEntry
? ((pImplEntry
->mnFlags
& LISTBOX_ENTRY_FLAG_DISABLE_SELECTION
) == 0) : true;
465 sal_Int32
ImplEntryList::FindFirstSelectable( sal_Int32 nPos
, bool bForward
/* = true */ )
467 if( IsEntrySelectable( nPos
) )
472 for( nPos
= nPos
+ 1; nPos
< GetEntryCount(); nPos
++ )
474 if( IsEntrySelectable( nPos
) )
483 if( IsEntrySelectable( nPos
) )
488 return LISTBOX_ENTRY_NOTFOUND
;
491 ImplListBoxWindow::ImplListBoxWindow( vcl::Window
* pParent
, WinBits nWinStyle
) :
492 Control( pParent
, 0 ),
493 maQuickSelectionEngine( *this )
495 mpEntryList
= new ImplEntryList( this );
500 mnSelectModifier
= 0;
501 mnUserDrawEntry
= LISTBOX_ENTRY_NOTFOUND
;
503 mbImgsDiffSz
= false;
504 mbTravelSelect
= false;
505 mbTrackingSelect
= false;
506 mbSelectionChanged
= false;
507 mbMouseMoveSelect
= false;
511 mbUserDrawEnabled
= false;
512 mbInUserDraw
= false;
514 mbHasFocusRect
= false;
515 mbRight
= ( nWinStyle
& WB_RIGHT
);
516 mbCenter
= ( nWinStyle
& WB_CENTER
);
517 mbSimpleMode
= ( nWinStyle
& WB_SIMPLEMODE
);
518 mbSort
= ( nWinStyle
& WB_SORT
);
519 mbEdgeBlending
= false;
521 // pb: #106948# explicit mirroring for calc
524 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
525 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
526 mnSeparatorPos
= LISTBOX_ENTRY_NOTFOUND
;
527 meProminentType
= PROMINENT_TOP
;
531 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
533 ImplInitSettings( true, true, true );
537 ImplListBoxWindow::~ImplListBoxWindow()
542 void ImplListBoxWindow::ImplInitSettings( bool bFont
, bool bForeground
, bool bBackground
)
544 ImplInitFieldSettings( this, bFont
, bForeground
, bBackground
);
547 void ImplListBoxWindow::ImplCalcMetrics()
555 mnTextHeight
= (sal_uInt16
)GetTextHeight();
556 mnMaxTxtHeight
= mnTextHeight
+ mnBorder
;
557 mnMaxHeight
= mnMaxTxtHeight
;
559 if ( maUserItemSize
.Height() > mnMaxHeight
)
560 mnMaxHeight
= (sal_uInt16
) maUserItemSize
.Height();
561 if ( maUserItemSize
.Width() > mnMaxWidth
)
562 mnMaxWidth
= (sal_uInt16
) maUserItemSize
.Width();
564 for ( sal_Int32 n
= mpEntryList
->GetEntryCount(); n
; )
566 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( --n
);
567 ImplUpdateEntryMetrics( *pEntry
);
570 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
572 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryPtr( mnCurrentPos
)->mnHeight
);
573 maFocusRect
.SetSize( aSz
);
577 void ImplListBoxWindow::Clear()
579 mpEntryList
->Clear();
581 mnMaxHeight
= mnMaxTxtHeight
;
589 mbImgsDiffSz
= false;
590 ImplClearLayoutData();
592 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
593 maQuickSelectionEngine
.Reset();
598 void ImplListBoxWindow::SetUserItemSize( const Size
& rSz
)
600 ImplClearLayoutData();
601 maUserItemSize
= rSz
;
605 struct ImplEntryMetrics
616 void ImplListBoxWindow::EnableQuickSelection( const bool& b
)
618 maQuickSelectionEngine
.SetEnabled( b
);
621 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType
& rEntry
)
623 ImplEntryMetrics aMetrics
;
624 aMetrics
.bText
= !rEntry
.maStr
.isEmpty();
625 aMetrics
.bImage
= !!rEntry
.maImage
;
626 aMetrics
.nEntryWidth
= 0;
627 aMetrics
.nEntryHeight
= 0;
628 aMetrics
.nTextWidth
= 0;
629 aMetrics
.nImgWidth
= 0;
630 aMetrics
.nImgHeight
= 0;
632 if ( aMetrics
.bText
)
634 if( (rEntry
.mnFlags
& LISTBOX_ENTRY_FLAG_MULTILINE
) )
637 Size
aCurSize( PixelToLogic( GetSizePixel() ) );
638 // set the current size to a large number
639 // GetTextRect should shrink it to the actual size
640 aCurSize
.Height() = 0x7fffff;
641 Rectangle
aTextRect( Point( 0, 0 ), aCurSize
);
642 aTextRect
= GetTextRect( aTextRect
, rEntry
.maStr
, TEXT_DRAW_WORDBREAK
| TEXT_DRAW_MULTILINE
);
643 aMetrics
.nTextWidth
= aTextRect
.GetWidth();
644 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
645 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
646 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
647 aMetrics
.nEntryHeight
= aTextRect
.GetHeight() + mnBorder
;
651 // normal single line case
652 aMetrics
.nTextWidth
= (sal_uInt16
)GetTextWidth( rEntry
.maStr
);
653 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
654 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
655 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
656 aMetrics
.nEntryHeight
= mnTextHeight
+ mnBorder
;
659 if ( aMetrics
.bImage
)
661 Size aImgSz
= rEntry
.maImage
.GetSizePixel();
662 aMetrics
.nImgWidth
= (sal_uInt16
) CalcZoom( aImgSz
.Width() );
663 aMetrics
.nImgHeight
= (sal_uInt16
) CalcZoom( aImgSz
.Height() );
665 if( mnMaxImgWidth
&& ( aMetrics
.nImgWidth
!= mnMaxImgWidth
) )
667 else if ( mnMaxImgHeight
&& ( aMetrics
.nImgHeight
!= mnMaxImgHeight
) )
670 if( aMetrics
.nImgWidth
> mnMaxImgWidth
)
671 mnMaxImgWidth
= aMetrics
.nImgWidth
;
672 if( aMetrics
.nImgHeight
> mnMaxImgHeight
)
673 mnMaxImgHeight
= aMetrics
.nImgHeight
;
675 mnMaxImgTxtWidth
= std::max( mnMaxImgTxtWidth
, aMetrics
.nTextWidth
);
676 aMetrics
.nEntryHeight
= std::max( aMetrics
.nImgHeight
, aMetrics
.nEntryHeight
);
679 if ( IsUserDrawEnabled() || aMetrics
.bImage
)
681 aMetrics
.nEntryWidth
= std::max( aMetrics
.nImgWidth
, maUserItemSize
.Width() );
682 if ( aMetrics
.bText
)
683 aMetrics
.nEntryWidth
+= aMetrics
.nTextWidth
+ IMG_TXT_DISTANCE
;
684 aMetrics
.nEntryHeight
= std::max( std::max( mnMaxImgHeight
, maUserItemSize
.Height() ) + 2,
685 aMetrics
.nEntryHeight
);
688 if ( !aMetrics
.bText
&& !aMetrics
.bImage
&& !IsUserDrawEnabled() )
690 // entries which have no (aka an empty) text, and no image,
691 // and are not user-drawn, should be shown nonetheless
692 aMetrics
.nEntryHeight
= mnTextHeight
+ mnBorder
;
695 if ( aMetrics
.nEntryWidth
> mnMaxWidth
)
696 mnMaxWidth
= aMetrics
.nEntryWidth
;
697 if ( aMetrics
.nEntryHeight
> mnMaxHeight
)
698 mnMaxHeight
= aMetrics
.nEntryHeight
;
700 rEntry
.mnHeight
= aMetrics
.nEntryHeight
;
703 void ImplListBoxWindow::ImplCallSelect()
705 if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
707 // Insert the selected entry as MRU, if not already first MRU
708 sal_Int32 nSelected
= GetEntryList()->GetSelectEntryPos( 0 );
709 sal_Int32 nMRUCount
= GetEntryList()->GetMRUCount();
710 OUString aSelected
= GetEntryList()->GetEntryText( nSelected
);
711 sal_Int32 nFirstMatchingEntryPos
= GetEntryList()->FindEntry( aSelected
, true );
712 if ( nFirstMatchingEntryPos
|| !nMRUCount
)
714 bool bSelectNewEntry
= false;
715 if ( nFirstMatchingEntryPos
< nMRUCount
)
717 RemoveEntry( nFirstMatchingEntryPos
);
719 if ( nFirstMatchingEntryPos
== nSelected
)
720 bSelectNewEntry
= true;
722 else if ( nMRUCount
== GetEntryList()->GetMaxMRUCount() )
724 RemoveEntry( nMRUCount
- 1 );
728 ImplClearLayoutData();
730 ImplEntryType
* pNewEntry
= new ImplEntryType( aSelected
);
731 pNewEntry
->mbIsSelected
= bSelectNewEntry
;
732 GetEntryList()->InsertEntry( 0, pNewEntry
, false );
733 ImplUpdateEntryMetrics( *pNewEntry
);
734 GetEntryList()->SetMRUCount( ++nMRUCount
);
735 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
736 maMRUChangedHdl
.Call( NULL
);
740 maSelectHdl
.Call( NULL
);
741 mbSelectionChanged
= false;
744 sal_Int32
ImplListBoxWindow::InsertEntry( sal_Int32 nPos
, ImplEntryType
* pNewEntry
)
746 if (nPos
< 0 || LISTBOX_MAX_ENTRIES
<= mpEntryList
->GetEntryCount())
747 return LISTBOX_ERROR
;
749 ImplClearLayoutData();
750 sal_Int32 nNewPos
= mpEntryList
->InsertEntry( nPos
, pNewEntry
, mbSort
);
752 if( (GetStyle() & WB_WORDBREAK
) )
753 pNewEntry
->mnFlags
|= LISTBOX_ENTRY_FLAG_MULTILINE
;
755 ImplUpdateEntryMetrics( *pNewEntry
);
759 void ImplListBoxWindow::RemoveEntry( sal_Int32 nPos
)
761 ImplClearLayoutData();
762 mpEntryList
->RemoveEntry( nPos
);
763 if( mnCurrentPos
>= mpEntryList
->GetEntryCount() )
764 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
768 void ImplListBoxWindow::SetEntryFlags( sal_Int32 nPos
, long nFlags
)
770 mpEntryList
->SetEntryFlags( nPos
, nFlags
);
771 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( nPos
);
773 ImplUpdateEntryMetrics( *pEntry
);
776 void ImplListBoxWindow::ImplShowFocusRect()
778 if ( mbHasFocusRect
)
780 ShowFocus( maFocusRect
);
781 mbHasFocusRect
= true;
784 void ImplListBoxWindow::ImplHideFocusRect()
786 if ( mbHasFocusRect
)
789 mbHasFocusRect
= false;
793 sal_Int32
ImplListBoxWindow::GetEntryPosForPoint( const Point
& rPoint
) const
797 sal_Int32 nSelect
= mnTop
;
798 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nSelect
);
799 while( pEntry
&& rPoint
.Y() > pEntry
->mnHeight
+ nY
)
801 nY
+= pEntry
->mnHeight
;
802 pEntry
= mpEntryList
->GetEntryPtr( ++nSelect
);
805 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
810 bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry
) const
814 if( i_nEntry
>= mnTop
)
816 if( mpEntryList
->GetAddedHeight( i_nEntry
, mnTop
) <
817 PixelToLogic( GetSizePixel() ).Height() )
826 sal_Int32
ImplListBoxWindow::GetLastVisibleEntry() const
828 sal_Int32 nPos
= mnTop
;
829 long nWindowHeight
= GetSizePixel().Height();
830 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
832 for( nDiff
= 0; nDiff
< nWindowHeight
&& nPos
< nCount
; nDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
) )
835 if( nDiff
> nWindowHeight
&& nPos
> mnTop
)
844 void ImplListBoxWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
846 mbMouseMoveSelect
= false; // only till the first MouseButtonDown
847 maQuickSelectionEngine
.Reset();
851 if( rMEvt
.GetClicks() == 1 )
853 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
854 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
856 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
857 mnTrackingSaveSelection
= GetEntryList()->GetSelectEntryPos( 0 );
859 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
861 mnCurrentPos
= nSelect
;
862 mbTrackingSelect
= true;
863 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
864 (void)SelectEntries( nSelect
, LET_MBDOWN
, rMEvt
.IsShift(), rMEvt
.IsMod1() ,bCurPosChange
);
865 mbTrackingSelect
= false;
869 StartTracking( STARTTRACK_SCROLLREPEAT
);
872 if( rMEvt
.GetClicks() == 2 )
874 maDoubleClickHdl
.Call( this );
877 else // if ( mbGrabFocus )
883 void ImplListBoxWindow::MouseMove( const MouseEvent
& rMEvt
)
885 if ( rMEvt
.IsLeaveWindow() )
887 if ( mbStackMode
&& IsMouseMoveSelect() && IsReallyVisible() )
889 if ( rMEvt
.GetPosPixel().Y() < 0 )
892 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
894 if ( mbStackMode
) // #87072#, #92323#
896 mbTravelSelect
= true;
897 mnSelectModifier
= rMEvt
.GetModifier();
899 mbTravelSelect
= false;
905 else if ( ( ( !mbMulti
&& IsMouseMoveSelect() ) || mbStackMode
) && mpEntryList
->GetEntryCount() )
908 Rectangle
aRect( aPoint
, GetOutputSizePixel() );
909 if( aRect
.IsInside( rMEvt
.GetPosPixel() ) )
911 if ( IsMouseMoveSelect() )
913 sal_Int32 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
914 if( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
915 nSelect
= mpEntryList
->GetEntryCount() - 1;
916 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
917 nSelect
= std::min( nSelect
, (sal_Int32
) ( mpEntryList
->GetEntryCount() - 1 ) );
918 // Select only visible Entries with MouseMove, otherwise Tracking...
919 if ( IsVisible( nSelect
) &&
920 mpEntryList
->IsEntrySelectable( nSelect
) &&
921 ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectEntryCount() || ( nSelect
!= GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
923 mbTrackingSelect
= true;
924 if ( SelectEntries( nSelect
, LET_TRACKING
, false, false ) )
926 if ( mbStackMode
) // #87072#
928 mbTravelSelect
= true;
929 mnSelectModifier
= rMEvt
.GetModifier();
931 mbTravelSelect
= false;
933 // When list box selection change by mouse move, notity
934 // VCLEVENT_LISTBOX_SELECT vcl event.
937 maListItemSelectHdl
.Call(NULL
);
940 mbTrackingSelect
= false;
944 // if the DD button was pressed and someone moved into the ListBox
945 // with the mouse button pressed...
946 if ( rMEvt
.IsLeft() && !rMEvt
.IsSynthetic() )
948 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
949 mnTrackingSaveSelection
= GetEntryList()->GetSelectEntryPos( 0 );
951 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
953 if ( mbStackMode
&& ( mpEntryList
->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND
) )
954 mpEntryList
->SetSelectionAnchor( 0 );
956 StartTracking( STARTTRACK_SCROLLREPEAT
);
962 void ImplListBoxWindow::DeselectAll()
964 while ( GetEntryList()->GetSelectEntryCount() )
966 sal_Int32 nS
= GetEntryList()->GetSelectEntryPos( 0 );
967 SelectEntry( nS
, false );
971 void ImplListBoxWindow::SelectEntry( sal_Int32 nPos
, bool bSelect
)
973 if( (mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
) && mpEntryList
->IsEntrySelectable( nPos
) )
980 // deselect the selected entry
981 sal_Int32 nDeselect
= GetEntryList()->GetSelectEntryPos( 0 );
982 if( nDeselect
!= LISTBOX_ENTRY_NOTFOUND
)
984 //SelectEntryPos( nDeselect, false );
985 GetEntryList()->SelectEntry( nDeselect
, false );
986 if ( IsUpdateMode() && IsReallyVisible() )
987 ImplPaint( nDeselect
, true );
990 mpEntryList
->SelectEntry( nPos
, true );
992 if ( ( nPos
!= LISTBOX_ENTRY_NOTFOUND
) && IsUpdateMode() )
995 if ( !IsVisible( nPos
) )
997 ImplClearLayoutData();
998 sal_Int32 nVisibleEntries
= GetLastVisibleEntry()-mnTop
;
999 if ( !nVisibleEntries
|| !IsReallyVisible() || ( nPos
< GetTopEntry() ) )
1002 ShowProminentEntry( nPos
);
1006 ShowProminentEntry( nPos
);
1013 mpEntryList
->SelectEntry( nPos
, false );
1014 ImplPaint( nPos
, true );
1016 mbSelectionChanged
= true;
1020 bool ImplListBoxWindow::SelectEntries( sal_Int32 nSelect
, LB_EVENT_TYPE eLET
, bool bShift
, bool bCtrl
, bool bSelectPosChange
/*=FALSE*/ )
1022 bool bSelectionChanged
= false;
1024 if( IsEnabled() && mpEntryList
->IsEntrySelectable( nSelect
) )
1026 bool bFocusChanged
= false;
1028 // here (Single-ListBox) only one entry can be deselected
1031 sal_Int32 nDeselect
= mpEntryList
->GetSelectEntryPos( 0 );
1032 if( nSelect
!= nDeselect
)
1034 SelectEntry( nSelect
, true );
1035 mpEntryList
->SetLastSelected( nSelect
);
1036 bFocusChanged
= true;
1037 bSelectionChanged
= true;
1040 // MultiListBox without Modifier
1041 else if( mbSimpleMode
&& !bCtrl
&& !bShift
)
1043 sal_Int32 nEntryCount
= mpEntryList
->GetEntryCount();
1044 for ( sal_Int32 nPos
= 0; nPos
< nEntryCount
; nPos
++ )
1046 bool bSelect
= nPos
== nSelect
;
1047 if ( mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
)
1049 SelectEntry( nPos
, bSelect
);
1050 bFocusChanged
= true;
1051 bSelectionChanged
= true;
1054 mpEntryList
->SetLastSelected( nSelect
);
1055 mpEntryList
->SetSelectionAnchor( nSelect
);
1057 // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1058 else if( ( !mbSimpleMode
/* && !bShift */ ) || ( (mbSimpleMode
&& ( bCtrl
|| bShift
)) || mbStackMode
) )
1060 // Space for selection change
1061 if( !bShift
&& ( ( eLET
== LET_KEYSPACE
) || ( eLET
== LET_MBDOWN
) ) )
1063 bool bSelect
= ( mbStackMode
&& IsMouseMoveSelect() ) || !mpEntryList
->IsEntryPosSelected( nSelect
);
1069 // All entries before nSelect must be selected...
1070 for ( n
= 0; n
< nSelect
; n
++ )
1071 SelectEntry( n
, true );
1075 for ( n
= nSelect
+1; n
< mpEntryList
->GetEntryCount(); n
++ )
1076 SelectEntry( n
, false );
1079 SelectEntry( nSelect
, bSelect
);
1080 mpEntryList
->SetLastSelected( nSelect
);
1081 mpEntryList
->SetSelectionAnchor( mbStackMode
? 0 : nSelect
);
1082 if ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1083 mpEntryList
->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND
);
1084 bFocusChanged
= true;
1085 bSelectionChanged
= true;
1087 else if( ( ( eLET
== LET_TRACKING
) && ( nSelect
!= mnCurrentPos
) ) ||
1088 ( (bShift
||mbStackMode
) && ( ( eLET
== LET_KEYMOVE
) || ( eLET
== LET_MBDOWN
) ) ) )
1090 mnCurrentPos
= nSelect
;
1091 bFocusChanged
= true;
1093 sal_Int32 nAnchor
= mpEntryList
->GetSelectionAnchor();
1094 if( ( nAnchor
== LISTBOX_ENTRY_NOTFOUND
) && ( mpEntryList
->GetSelectEntryCount() || mbStackMode
) )
1096 nAnchor
= mbStackMode
? 0 : mpEntryList
->GetSelectEntryPos( mpEntryList
->GetSelectEntryCount() - 1 );
1098 if( nAnchor
!= LISTBOX_ENTRY_NOTFOUND
)
1100 // All entries from achor to nSelect have to be selected
1101 sal_Int32 nStart
= std::min( nSelect
, nAnchor
);
1102 sal_Int32 nEnd
= std::max( nSelect
, nAnchor
);
1103 for ( sal_Int32 n
= nStart
; n
<= nEnd
; n
++ )
1105 if ( !mpEntryList
->IsEntryPosSelected( n
) )
1107 SelectEntry( n
, true );
1108 bSelectionChanged
= true;
1112 // if appropriate some more has to be deselected...
1113 sal_Int32 nLast
= mpEntryList
->GetLastSelected();
1114 if ( nLast
!= LISTBOX_ENTRY_NOTFOUND
)
1116 if ( ( nLast
> nSelect
) && ( nLast
> nAnchor
) )
1118 for ( sal_Int32 n
= nSelect
+1; n
<= nLast
; n
++ )
1120 if ( mpEntryList
->IsEntryPosSelected( n
) )
1122 SelectEntry( n
, false );
1123 bSelectionChanged
= true;
1127 else if ( ( nLast
< nSelect
) && ( nLast
< nAnchor
) )
1129 for ( sal_Int32 n
= nLast
; n
< nSelect
; n
++ )
1131 if ( mpEntryList
->IsEntryPosSelected( n
) )
1133 SelectEntry( n
, false );
1134 bSelectionChanged
= true;
1139 mpEntryList
->SetLastSelected( nSelect
);
1142 else if( eLET
!= LET_TRACKING
)
1144 ImplHideFocusRect();
1145 ImplPaint( nSelect
, true );
1146 bFocusChanged
= true;
1151 bFocusChanged
= true;
1154 if( bSelectionChanged
)
1155 mbSelectionChanged
= true;
1159 long nHeightDiff
= mpEntryList
->GetAddedHeight( nSelect
, mnTop
, 0 );
1160 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1161 Size
aSz( maFocusRect
.GetWidth(),
1162 mpEntryList
->GetEntryHeight( nSelect
) );
1163 maFocusRect
.SetSize( aSz
);
1165 ImplShowFocusRect();
1166 if (bSelectPosChange
)
1168 maFocusHdl
.Call(reinterpret_cast<void*>(nSelect
));
1171 ImplClearLayoutData();
1173 return bSelectionChanged
;
1176 void ImplListBoxWindow::Tracking( const TrackingEvent
& rTEvt
)
1179 Rectangle
aRect( aPoint
, GetOutputSizePixel() );
1180 bool bInside
= aRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() );
1182 if( rTEvt
.IsTrackingCanceled() || rTEvt
.IsTrackingEnded() ) // MouseButtonUp
1184 if ( bInside
&& !rTEvt
.IsTrackingCanceled() )
1186 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1191 maCancelHdl
.Call( NULL
);
1194 mbTrackingSelect
= true;
1195 SelectEntry( mnTrackingSaveSelection
, true );
1196 mbTrackingSelect
= false;
1197 if ( mnTrackingSaveSelection
!= LISTBOX_ENTRY_NOTFOUND
)
1199 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
, 0 );
1200 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1201 Size
aSz( maFocusRect
.GetWidth(),
1202 mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1203 maFocusRect
.SetSize( aSz
);
1204 ImplShowFocusRect();
1213 bool bTrackOrQuickClick
= mbTrack
;
1221 // this case only happens, if the mouse button is pressed very briefly
1222 if( rTEvt
.IsTrackingEnded() && mbTrack
)
1224 bTrackOrQuickClick
= true;
1229 if( bTrackOrQuickClick
)
1231 MouseEvent aMEvt
= rTEvt
.GetMouseEvent();
1232 Point
aPt( aMEvt
.GetPosPixel() );
1233 bool bShift
= aMEvt
.IsShift();
1234 bool bCtrl
= aMEvt
.IsMod1();
1236 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1239 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1241 nSelect
= mnCurrentPos
? ( mnCurrentPos
- 1 ) : 0;
1242 if( nSelect
< mnTop
)
1243 SetTopEntry( mnTop
-1 );
1246 else if( aPt
.Y() > GetOutputSizePixel().Height() )
1248 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1250 nSelect
= std::min( (sal_Int32
)(mnCurrentPos
+1), (sal_Int32
)(mpEntryList
->GetEntryCount()-1) );
1251 if( nSelect
>= GetLastVisibleEntry() )
1252 SetTopEntry( mnTop
+1 );
1257 nSelect
= (sal_Int32
) ( ( aPt
.Y() + mnBorder
) / mnMaxHeight
) + (sal_Int32
) mnTop
;
1258 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
1259 nSelect
= std::min( nSelect
, (sal_Int32
) ( mpEntryList
->GetEntryCount() - 1 ) );
1264 if ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectEntryCount() )
1266 mbTrackingSelect
= true;
1267 if ( SelectEntries( nSelect
, LET_TRACKING
, bShift
, bCtrl
) )
1269 if ( mbStackMode
) // #87734# (#87072#)
1271 mbTravelSelect
= true;
1272 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1274 mbTravelSelect
= false;
1277 mbTrackingSelect
= false;
1282 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
1284 mbTrackingSelect
= true;
1285 SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), false );
1286 mbTrackingSelect
= false;
1288 else if ( mbStackMode
)
1290 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt
.GetMouseEvent().GetPosPixel().X() < aRect
.Right() ) )
1292 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt
.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1294 bool bSelectionChanged
= false;
1295 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().Y() < 0 )
1298 if ( mpEntryList
->IsEntryPosSelected( 0 ) )
1300 SelectEntry( 0, false );
1301 bSelectionChanged
= true;
1302 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1308 mbTrackingSelect
= true;
1309 bSelectionChanged
= SelectEntries( nSelect
, LET_TRACKING
, bShift
, bCtrl
);
1310 mbTrackingSelect
= false;
1313 if ( bSelectionChanged
)
1315 mbSelectionChanged
= true;
1316 mbTravelSelect
= true;
1317 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1319 mbTravelSelect
= false;
1325 mnCurrentPos
= nSelect
;
1326 if ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1328 ImplHideFocusRect();
1332 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
, 0 );
1333 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1334 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1335 maFocusRect
.SetSize( aSz
);
1336 ImplShowFocusRect();
1342 void ImplListBoxWindow::KeyInput( const KeyEvent
& rKEvt
)
1344 if( !ProcessKeyInput( rKEvt
) )
1345 Control::KeyInput( rKEvt
);
1348 bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent
& rKEvt
)
1350 // entry to be selected
1351 sal_Int32 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1352 LB_EVENT_TYPE eLET
= LET_KEYMOVE
;
1354 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1356 bool bShift
= aKeyCode
.IsShift();
1357 bool bCtrl
= aKeyCode
.IsMod1() || aKeyCode
.IsMod3();
1358 bool bMod2
= aKeyCode
.IsMod2();
1361 switch( aKeyCode
.GetCode() )
1367 if ( GetTopEntry() )
1368 SetTopEntry( GetTopEntry()-1 );
1372 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1374 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1376 else if ( mnCurrentPos
)
1378 // search first selectable above the current position
1379 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
- 1, false );
1382 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
< mnTop
) )
1383 SetTopEntry( mnTop
-1 );
1387 maQuickSelectionEngine
.Reset();
1395 SetTopEntry( GetTopEntry()+1 );
1399 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1401 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1403 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1405 // search first selectable below the current position
1406 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
+ 1, true );
1409 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
>= GetLastVisibleEntry() ) )
1410 SetTopEntry( mnTop
+1 );
1414 maQuickSelectionEngine
.Reset();
1422 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1423 SetTopEntry( ( mnTop
> nCurVis
) ?
1424 (mnTop
-nCurVis
) : 0 );
1426 else if ( !bCtrl
&& !bMod2
)
1428 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1430 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1432 else if ( mnCurrentPos
)
1434 if( mnCurrentPos
== mnTop
)
1436 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1437 SetTopEntry( ( mnTop
> nCurVis
) ? ( mnTop
-nCurVis
+1 ) : 0 );
1440 // find first selectable starting from mnTop looking forward
1441 nSelect
= mpEntryList
->FindFirstSelectable( mnTop
, true );
1445 maQuickSelectionEngine
.Reset();
1453 SetTopEntry( GetLastVisibleEntry() );
1455 else if ( !bCtrl
&& !bMod2
)
1457 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1459 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1461 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1463 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1464 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
;
1465 sal_Int32 nTmp
= std::min( nCurVis
, nCount
);
1467 if( mnCurrentPos
== nTmp
&& mnCurrentPos
!= nCount
- 1 )
1469 long nTmp2
= std::min( (long)(nCount
-nCurVis
), (long)((long)mnTop
+(long)nCurVis
-1) );
1470 nTmp2
= std::max( (long)0 , nTmp2
);
1471 nTmp
= (sal_Int32
)(nTmp2
+(nCurVis
-1) );
1472 SetTopEntry( (sal_Int32
)nTmp2
);
1474 // find first selectable starting from nTmp looking backwards
1475 nSelect
= mpEntryList
->FindFirstSelectable( nTmp
, false );
1479 maQuickSelectionEngine
.Reset();
1489 else if ( !bCtrl
&& !bMod2
)
1493 nSelect
= mpEntryList
->FindFirstSelectable( mpEntryList
->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND
, true );
1500 maQuickSelectionEngine
.Reset();
1508 SetTopEntry( 0xFFFF );
1510 else if ( !bCtrl
&& !bMod2
)
1512 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1514 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1516 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1518 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1519 nSelect
= mpEntryList
->FindFirstSelectable( nCount
- 1, false );
1520 sal_Int32 nCurVis
= GetLastVisibleEntry() - mnTop
+ 1;
1521 if( nCount
> nCurVis
)
1522 SetTopEntry( nCount
- nCurVis
);
1526 maQuickSelectionEngine
.Reset();
1532 if ( !bCtrl
&& !bMod2
)
1534 ScrollHorz( -HORZ_SCROLL
);
1537 maQuickSelectionEngine
.Reset();
1543 if ( !bCtrl
&& !bMod2
)
1545 ScrollHorz( HORZ_SCROLL
);
1548 maQuickSelectionEngine
.Reset();
1554 if ( !bMod2
&& !IsReadOnly() )
1556 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1558 bDone
= false; // do not catch RETURN
1560 maQuickSelectionEngine
.Reset();
1566 if ( !bMod2
&& !IsReadOnly() )
1568 if( mbMulti
&& ( !mbSimpleMode
|| ( mbSimpleMode
&& bCtrl
&& !bShift
) || mbStackMode
) )
1570 nSelect
= mnCurrentPos
;
1571 eLET
= LET_KEYSPACE
;
1575 maQuickSelectionEngine
.Reset();
1581 if( bCtrl
&& mbMulti
)
1584 bool bUpdates
= IsUpdateMode();
1585 SetUpdateMode( false );
1587 sal_Int32 nEntryCount
= mpEntryList
->GetEntryCount();
1588 for( sal_Int32 i
= 0; i
< nEntryCount
; i
++ )
1589 SelectEntry( i
, true );
1591 // restore update mode
1592 SetUpdateMode( bUpdates
);
1595 maQuickSelectionEngine
.Reset();
1601 // fall through intentional
1604 if ( !IsReadOnly() )
1606 bDone
= maQuickSelectionEngine
.HandleKeyEvent( rKEvt
);
1612 if ( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
1613 && ( ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1614 || ( eLET
== LET_KEYSPACE
)
1618 DBG_ASSERT( !mpEntryList
->IsEntryPosSelected( nSelect
) || mbMulti
, "ImplListBox: Selecting same Entry" );
1619 if( nSelect
>= mpEntryList
->GetEntryCount() )
1620 nSelect
= mpEntryList
->GetEntryCount()-1;
1621 bool bCurPosChange
= (mnCurrentPos
!= nSelect
);
1622 mnCurrentPos
= nSelect
;
1623 if(SelectEntries( nSelect
, eLET
, bShift
, bCtrl
, bCurPosChange
))
1625 mbTravelSelect
= true;
1626 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1628 mbTravelSelect
= false;
1637 static ::vcl::StringEntryIdentifier
lcl_getEntry( const ImplEntryList
& _rList
, sal_Int32 _nPos
, OUString
& _out_entryText
)
1639 OSL_PRECOND( ( _nPos
!= LISTBOX_ENTRY_NOTFOUND
), "lcl_getEntry: invalid position!" );
1640 sal_Int32
nEntryCount( _rList
.GetEntryCount() );
1641 if ( _nPos
>= nEntryCount
)
1643 _out_entryText
= _rList
.GetEntryText( _nPos
);
1645 // ::vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1647 return reinterpret_cast< ::vcl::StringEntryIdentifier
>( _nPos
+ 1 );
1650 static sal_Int32
lcl_getEntryPos( ::vcl::StringEntryIdentifier _entry
)
1652 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1653 return static_cast< sal_Int32
>( reinterpret_cast< sal_Int64
>( _entry
) ) - 1;
1657 ::vcl::StringEntryIdentifier
ImplListBoxWindow::CurrentEntry( OUString
& _out_entryText
) const
1659 return lcl_getEntry( *GetEntryList(), ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
) ? 0 : mnCurrentPos
, _out_entryText
);
1662 ::vcl::StringEntryIdentifier
ImplListBoxWindow::NextEntry( ::vcl::StringEntryIdentifier _currentEntry
, OUString
& _out_entryText
) const
1664 sal_Int32 nNextPos
= lcl_getEntryPos( _currentEntry
) + 1;
1665 return lcl_getEntry( *GetEntryList(), nNextPos
, _out_entryText
);
1668 void ImplListBoxWindow::SelectEntry( ::vcl::StringEntryIdentifier _entry
)
1670 sal_Int32 nSelect
= lcl_getEntryPos( _entry
);
1671 if ( mpEntryList
->IsEntryPosSelected( nSelect
) )
1673 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1674 // to select the given entry by typing its starting letters. No need to act.
1679 OSL_ENSURE( nSelect
< mpEntryList
->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1680 if( nSelect
>= mpEntryList
->GetEntryCount() )
1681 nSelect
= mpEntryList
->GetEntryCount()-1;
1684 ShowProminentEntry( nSelect
);
1687 mnCurrentPos
= nSelect
;
1688 if ( SelectEntries( nSelect
, LET_KEYMOVE
, false, false ) )
1690 mbTravelSelect
= true;
1691 mnSelectModifier
= 0;
1693 mbTravelSelect
= false;
1697 void ImplListBoxWindow::ImplPaint( sal_Int32 nPos
, bool bErase
, bool bLayout
)
1699 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
1701 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nPos
);
1705 long nWidth
= GetOutputSizePixel().Width();
1706 long nY
= mpEntryList
->GetAddedHeight( nPos
, mnTop
);
1707 Rectangle
aRect( Point( 0, nY
), Size( nWidth
, pEntry
->mnHeight
) );
1711 if( mpEntryList
->IsEntryPosSelected( nPos
) )
1713 SetTextColor( !IsEnabled() ? rStyleSettings
.GetDisableColor() : rStyleSettings
.GetHighlightTextColor() );
1714 SetFillColor( rStyleSettings
.GetHighlightColor() );
1715 SetTextFillColor( rStyleSettings
.GetHighlightColor() );
1720 ImplInitSettings( false, true, false );
1722 SetTextColor( rStyleSettings
.GetDisableColor() );
1729 if ( IsUserDrawEnabled() )
1731 mbInUserDraw
= true;
1732 mnUserDrawEntry
= nPos
;
1733 aRect
.Left() -= mnLeft
;
1734 if ( nPos
< GetEntryList()->GetMRUCount() )
1735 nPos
= GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos
) );
1736 nPos
= nPos
- GetEntryList()->GetMRUCount();
1737 sal_Int32 nCurr
= mnCurrentPos
;
1738 if ( mnCurrentPos
< GetEntryList()->GetMRUCount() )
1739 nCurr
= GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nCurr
) );
1740 nCurr
= sal::static_int_cast
<sal_Int32
>( nCurr
- GetEntryList()->GetMRUCount());
1742 UserDrawEvent
aUDEvt( this, aRect
, nPos
, nCurr
);
1743 userDrawSignal( &aUDEvt
);
1744 mbInUserDraw
= false;
1748 DrawEntry( nPos
, true, true, false, bLayout
);
1752 void ImplListBoxWindow::DrawEntry( sal_Int32 nPos
, bool bDrawImage
, bool bDrawText
, bool bDrawTextAtImagePos
, bool bLayout
)
1754 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nPos
);
1758 // when changing this function don't forget to adjust ImplWin::DrawEntry()
1761 nPos
= mnUserDrawEntry
; // real entry, not the matching entry from MRU
1763 long nY
= mpEntryList
->GetAddedHeight( nPos
, mnTop
);
1766 if( bDrawImage
&& mpEntryList
->HasImages() && !bLayout
)
1768 Image aImage
= mpEntryList
->GetEntryImage( nPos
);
1771 aImgSz
= aImage
.GetSizePixel();
1772 Point
aPtImg( mnBorder
- mnLeft
, nY
+ ( ( pEntry
->mnHeight
- aImgSz
.Height() ) / 2 ) );
1774 // pb: #106948# explicit mirroring for calc
1777 aPtImg
.X() = mnMaxWidth
+ mnBorder
- aImgSz
.Width() - mnLeft
;
1781 DrawImage( aPtImg
, aImage
);
1785 aImgSz
.Width() = CalcZoom( aImgSz
.Width() );
1786 aImgSz
.Height() = CalcZoom( aImgSz
.Height() );
1787 DrawImage( aPtImg
, aImgSz
, aImage
);
1790 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1791 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
1793 if(nEdgeBlendingPercent
&& aImgSz
.Width() && aImgSz
.Height())
1795 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
1796 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
1797 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
1798 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
1800 if(!aBlendFrame
.IsEmpty())
1802 DrawBitmapEx(aPtImg
, aBlendFrame
);
1810 MetricVector
* pVector
= bLayout
? &mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
: NULL
;
1811 OUString
* pDisplayText
= bLayout
? &mpControlData
->mpLayoutData
->m_aDisplayText
: NULL
;
1812 OUString
aStr( mpEntryList
->GetEntryText( nPos
) );
1813 if ( !aStr
.isEmpty() )
1815 long nMaxWidth
= std::max( static_cast< long >( mnMaxWidth
),
1816 GetOutputSizePixel().Width() - 2*mnBorder
);
1817 // a multiline entry should only be as wide a the window
1818 if( (pEntry
->mnFlags
& LISTBOX_ENTRY_FLAG_MULTILINE
) )
1819 nMaxWidth
= GetOutputSizePixel().Width() - 2*mnBorder
;
1821 Rectangle
aTextRect( Point( mnBorder
- mnLeft
, nY
),
1822 Size( nMaxWidth
, pEntry
->mnHeight
) );
1824 if( !bDrawTextAtImagePos
&& ( mpEntryList
->HasEntryImage(nPos
) || IsUserDrawEnabled() ) )
1826 long nImageWidth
= std::max( mnMaxImgWidth
, maUserItemSize
.Width() );
1827 aTextRect
.Left() += nImageWidth
+ IMG_TXT_DISTANCE
;
1831 mpControlData
->mpLayoutData
->m_aLineIndices
.push_back( mpControlData
->mpLayoutData
->m_aDisplayText
.getLength() );
1833 // pb: #106948# explicit mirroring for calc
1837 aTextRect
.Left() = nMaxWidth
+ mnBorder
- GetTextWidth( aStr
) - mnLeft
;
1838 if ( aImgSz
.Width() > 0 )
1839 aTextRect
.Left() -= ( aImgSz
.Width() + IMG_TXT_DISTANCE
);
1842 sal_uInt16 nDrawStyle
= ImplGetTextStyle();
1843 if( (pEntry
->mnFlags
& LISTBOX_ENTRY_FLAG_MULTILINE
) )
1844 nDrawStyle
|= MULTILINE_ENTRY_DRAW_FLAGS
;
1845 if( (pEntry
->mnFlags
& LISTBOX_ENTRY_FLAG_DRAW_DISABLED
) )
1846 nDrawStyle
|= TEXT_DRAW_DISABLE
;
1848 DrawText( aTextRect
, aStr
, nDrawStyle
, pVector
, pDisplayText
);
1854 if ( ( mnSeparatorPos
!= LISTBOX_ENTRY_NOTFOUND
) &&
1855 ( ( nPos
== mnSeparatorPos
) || ( nPos
== mnSeparatorPos
+1 ) ) )
1857 Color
aOldLineColor( GetLineColor() );
1858 SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY
) ? COL_LIGHTGRAY
: COL_GRAY
);
1859 Point
aStartPos( 0, nY
);
1860 if ( nPos
== mnSeparatorPos
)
1861 aStartPos
.Y() += pEntry
->mnHeight
-1;
1862 Point
aEndPos( aStartPos
);
1863 aEndPos
.X() = GetOutputSizePixel().Width();
1864 DrawLine( aStartPos
, aEndPos
);
1865 SetLineColor( aOldLineColor
);
1870 void ImplListBoxWindow::FillLayoutData() const
1872 mpControlData
->mpLayoutData
= new vcl::ControlLayoutData();
1873 const_cast<ImplListBoxWindow
*>(this)->
1874 ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
1877 void ImplListBoxWindow::ImplDoPaint( const Rectangle
& rRect
, bool bLayout
)
1879 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1881 bool bShowFocusRect
= mbHasFocusRect
;
1882 if ( mbHasFocusRect
&& ! bLayout
)
1883 ImplHideFocusRect();
1885 long nY
= 0; // + mnBorder;
1886 long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1888 for( sal_Int32 i
= (sal_Int32
)mnTop
; i
< nCount
&& nY
< nHeight
+ mnMaxHeight
; i
++ )
1890 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( i
);
1891 if( nY
+ pEntry
->mnHeight
>= rRect
.Top() &&
1892 nY
<= rRect
.Bottom() + mnMaxHeight
)
1894 ImplPaint( i
, false, bLayout
);
1896 nY
+= pEntry
->mnHeight
;
1899 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
, 0 );
1900 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1901 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1902 maFocusRect
.SetSize( aSz
);
1903 if( HasFocus() && bShowFocusRect
&& !bLayout
)
1904 ImplShowFocusRect();
1907 void ImplListBoxWindow::Paint( const Rectangle
& rRect
)
1909 ImplDoPaint( rRect
);
1912 sal_uInt16
ImplListBoxWindow::GetDisplayLineCount() const
1914 // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
1916 sal_Int32 nCount
= mpEntryList
->GetEntryCount();
1917 long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1918 sal_uInt16 nEntries
= static_cast< sal_uInt16
>( ( nHeight
+ mnMaxHeight
- 1 ) / mnMaxHeight
);
1919 if( nEntries
> nCount
-mnTop
)
1920 nEntries
= nCount
-mnTop
;
1925 void ImplListBoxWindow::Resize()
1929 bool bShowFocusRect
= mbHasFocusRect
;
1930 if ( bShowFocusRect
)
1931 ImplHideFocusRect();
1933 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1935 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1936 maFocusRect
.SetSize( aSz
);
1939 if ( bShowFocusRect
)
1940 ImplShowFocusRect();
1942 ImplClearLayoutData();
1945 void ImplListBoxWindow::GetFocus()
1947 sal_Int32 nPos
= mnCurrentPos
;
1948 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
1950 long nHeightDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
, 0 );
1951 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1952 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( nPos
) );
1953 maFocusRect
.SetSize( aSz
);
1954 ImplShowFocusRect();
1955 Control::GetFocus();
1958 void ImplListBoxWindow::LoseFocus()
1960 ImplHideFocusRect();
1961 Control::LoseFocus();
1964 void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop
)
1966 if( mpEntryList
->GetEntryCount() == 0 )
1969 long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1971 sal_Int32 nLastEntry
= mpEntryList
->GetEntryCount()-1;
1972 if( nTop
> nLastEntry
)
1974 const ImplEntryType
* pLast
= mpEntryList
->GetEntryPtr( nLastEntry
);
1975 while( nTop
> 0 && mpEntryList
->GetAddedHeight( nLastEntry
, nTop
-1 ) + pLast
->mnHeight
<= nWHeight
)
1978 if ( nTop
!= mnTop
)
1980 ImplClearLayoutData();
1981 long nDiff
= mpEntryList
->GetAddedHeight( mnTop
, nTop
, 0 );
1983 ImplHideFocusRect();
1988 ImplShowFocusRect();
1989 maScrollHdl
.Call( this );
1993 void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos
)
1995 if( meProminentType
== PROMINENT_MIDDLE
)
1997 sal_Int32 nPos
= nEntryPos
;
1998 long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
1999 while( nEntryPos
> 0 && mpEntryList
->GetAddedHeight( nPos
+1, nEntryPos
) < nWHeight
/2 )
2002 SetTopEntry( nEntryPos
);
2005 void ImplListBoxWindow::SetLeftIndent( long n
)
2007 ScrollHorz( n
- mnLeft
);
2010 void ImplListBoxWindow::ScrollHorz( long n
)
2015 long nWidth
= GetOutputSizePixel().Width();
2016 if( ( mnMaxWidth
- mnLeft
+ n
) > nWidth
)
2024 nDiff
= - ( ( mnLeft
> nAbs
) ? nAbs
: mnLeft
);
2030 ImplClearLayoutData();
2031 mnLeft
= sal::static_int_cast
<sal_uInt16
>(mnLeft
+ nDiff
);
2033 ImplHideFocusRect();
2034 Scroll( -nDiff
, 0 );
2037 ImplShowFocusRect();
2038 maScrollHdl
.Call( this );
2042 Size
ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines
) const
2044 // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2047 aSz
.Height() = nMaxLines
* mnMaxHeight
;
2048 aSz
.Width() = mnMaxWidth
+ 2*mnBorder
;
2052 Rectangle
ImplListBoxWindow::GetBoundingRectangle( sal_Int32 nItem
) const
2054 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nItem
);
2055 Size
aSz( GetSizePixel().Width(), pEntry
? pEntry
->mnHeight
: GetEntryHeight() );
2056 long nY
= mpEntryList
->GetAddedHeight( nItem
, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeight();
2057 Rectangle
aRect( Point( 0, nY
), aSz
);
2061 void ImplListBoxWindow::StateChanged( StateChangedType nType
)
2063 Control::StateChanged( nType
);
2065 if ( nType
== StateChangedType::ZOOM
)
2067 ImplInitSettings( true, false, false );
2071 else if ( nType
== StateChangedType::UPDATEMODE
)
2073 if ( IsUpdateMode() && IsReallyVisible() )
2076 else if ( nType
== StateChangedType::CONTROLFONT
)
2078 ImplInitSettings( true, false, false );
2082 else if ( nType
== StateChangedType::CONTROLFOREGROUND
)
2084 ImplInitSettings( false, true, false );
2087 else if ( nType
== StateChangedType::CONTROLBACKGROUND
)
2089 ImplInitSettings( false, false, true );
2092 else if( nType
== StateChangedType::ENABLE
)
2097 ImplClearLayoutData();
2100 void ImplListBoxWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
2102 Control::DataChanged( rDCEvt
);
2104 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2105 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2106 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2107 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2109 ImplClearLayoutData();
2110 ImplInitSettings( true, true, true );
2116 sal_uInt16
ImplListBoxWindow::ImplGetTextStyle() const
2118 sal_uInt16 nTextStyle
= TEXT_DRAW_VCENTER
;
2120 if ( mpEntryList
->HasImages() )
2121 nTextStyle
|= TEXT_DRAW_LEFT
;
2122 else if ( mbCenter
)
2123 nTextStyle
|= TEXT_DRAW_CENTER
;
2125 nTextStyle
|= TEXT_DRAW_RIGHT
;
2127 nTextStyle
|= TEXT_DRAW_LEFT
;
2132 ImplListBox::ImplListBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
2133 Control( pParent
, nWinStyle
),
2134 maLBWindow( this, nWinStyle
&(~WB_BORDER
) )
2136 maLBWindow
.userDrawSignal
.connect( userDrawSignal
);
2138 // for native widget rendering we must be able to detect this window type
2139 SetType( WINDOW_LISTBOXWINDOW
);
2141 mpVScrollBar
= new ScrollBar( this, WB_VSCROLL
| WB_DRAG
);
2142 mpHScrollBar
= new ScrollBar( this, WB_HSCROLL
| WB_DRAG
);
2143 mpScrollBarBox
= new ScrollBarBox( this );
2145 Link
aLink( LINK( this, ImplListBox
, ScrollBarHdl
) );
2146 mpVScrollBar
->SetScrollHdl( aLink
);
2147 mpHScrollBar
->SetScrollHdl( aLink
);
2151 mbAutoHScroll
= ( nWinStyle
& WB_AUTOHSCROLL
);
2152 mbEdgeBlending
= false;
2154 maLBWindow
.SetScrollHdl( LINK( this, ImplListBox
, LBWindowScrolled
) );
2155 maLBWindow
.SetMRUChangedHdl( LINK( this, ImplListBox
, MRUChanged
) );
2156 maLBWindow
.SetEdgeBlending(GetEdgeBlending());
2160 ImplListBox::~ImplListBox()
2162 delete mpHScrollBar
;
2163 delete mpVScrollBar
;
2164 delete mpScrollBarBox
;
2167 void ImplListBox::Clear()
2170 if ( GetEntryList()->GetMRUCount() )
2172 maLBWindow
.GetEntryList()->SetMRUCount( 0 );
2173 maLBWindow
.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND
);
2175 mpVScrollBar
->SetThumbPos( 0 );
2176 mpHScrollBar
->SetThumbPos( 0 );
2177 StateChanged( StateChangedType::DATA
);
2180 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
)
2182 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
);
2183 sal_Int32 nNewPos
= maLBWindow
.InsertEntry( nPos
, pNewEntry
);
2184 if (nNewPos
== LISTBOX_ERROR
)
2189 StateChanged( StateChangedType::DATA
);
2193 sal_Int32
ImplListBox::InsertEntry( sal_Int32 nPos
, const OUString
& rStr
, const Image
& rImage
)
2195 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
, rImage
);
2196 sal_Int32 nNewPos
= maLBWindow
.InsertEntry( nPos
, pNewEntry
);
2197 if (nNewPos
== LISTBOX_ERROR
)
2202 StateChanged( StateChangedType::DATA
);
2206 void ImplListBox::RemoveEntry( sal_Int32 nPos
)
2208 maLBWindow
.RemoveEntry( nPos
);
2209 StateChanged( StateChangedType::DATA
);
2212 void ImplListBox::SetEntryFlags( sal_Int32 nPos
, long nFlags
)
2214 maLBWindow
.SetEntryFlags( nPos
, nFlags
);
2217 void ImplListBox::SelectEntry( sal_Int32 nPos
, bool bSelect
)
2219 maLBWindow
.SelectEntry( nPos
, bSelect
);
2222 void ImplListBox::SetNoSelection()
2224 maLBWindow
.DeselectAll();
2227 void ImplListBox::GetFocus()
2229 maLBWindow
.GrabFocus();
2232 vcl::Window
* ImplListBox::GetPreferredKeyInputWindow()
2237 void ImplListBox::Resize()
2240 ImplResizeControls();
2241 ImplCheckScrollBars();
2244 IMPL_LINK_NOARG(ImplListBox
, MRUChanged
)
2246 StateChanged( StateChangedType::DATA
);
2250 IMPL_LINK_NOARG(ImplListBox
, LBWindowScrolled
)
2252 long nSet
= GetTopEntry();
2253 if( nSet
> mpVScrollBar
->GetRangeMax() )
2254 mpVScrollBar
->SetRangeMax( GetEntryList()->GetEntryCount() );
2255 mpVScrollBar
->SetThumbPos( GetTopEntry() );
2257 mpHScrollBar
->SetThumbPos( GetLeftIndent() );
2259 maScrollHdl
.Call( this );
2264 IMPL_LINK( ImplListBox
, ScrollBarHdl
, ScrollBar
*, pSB
)
2266 sal_uInt16 nPos
= (sal_uInt16
) pSB
->GetThumbPos();
2267 if( pSB
== mpVScrollBar
)
2268 SetTopEntry( nPos
);
2269 else if( pSB
== mpHScrollBar
)
2270 SetLeftIndent( nPos
);
2275 void ImplListBox::ImplCheckScrollBars()
2277 bool bArrange
= false;
2279 Size aOutSz
= GetOutputSizePixel();
2280 sal_Int32 nEntries
= GetEntryList()->GetEntryCount();
2281 sal_uInt16 nMaxVisEntries
= (sal_uInt16
) (aOutSz
.Height() / GetEntryHeight());
2283 // vertical ScrollBar
2284 if( nEntries
> nMaxVisEntries
)
2290 // check of the scrolled-out region
2291 if( GetEntryList()->GetSelectEntryCount() == 1 &&
2292 GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2293 ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2295 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2305 // horizontal ScrollBar
2308 long nWidth
= (sal_uInt16
) aOutSz
.Width();
2310 nWidth
-= mpVScrollBar
->GetSizePixel().Width();
2312 long nMaxWidth
= GetMaxEntryWidth();
2313 if( nWidth
< nMaxWidth
)
2319 if ( !mbVScroll
) // maybe we do need one now
2321 nMaxVisEntries
= (sal_uInt16
) ( ( aOutSz
.Height() - mpHScrollBar
->GetSizePixel().Height() ) / GetEntryHeight() );
2322 if( nEntries
> nMaxVisEntries
)
2327 // check of the scrolled-out region
2328 if( GetEntryList()->GetSelectEntryCount() == 1 &&
2329 GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2330 ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2332 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2336 // check of the scrolled-out region
2337 sal_uInt16 nMaxLI
= (sal_uInt16
) (nMaxWidth
- nWidth
);
2338 if ( nMaxLI
< GetLeftIndent() )
2339 SetLeftIndent( nMaxLI
);
2351 ImplResizeControls();
2353 ImplInitScrollBars();
2356 void ImplListBox::ImplInitScrollBars()
2358 Size aOutSz
= maLBWindow
.GetOutputSizePixel();
2362 sal_Int32 nEntries
= GetEntryList()->GetEntryCount();
2363 sal_uInt16 nVisEntries
= (sal_uInt16
) (aOutSz
.Height() / GetEntryHeight());
2364 mpVScrollBar
->SetRangeMax( nEntries
);
2365 mpVScrollBar
->SetVisibleSize( nVisEntries
);
2366 mpVScrollBar
->SetPageSize( nVisEntries
- 1 );
2371 mpHScrollBar
->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL
);
2372 mpHScrollBar
->SetVisibleSize( (sal_uInt16
)aOutSz
.Width() );
2373 mpHScrollBar
->SetLineSize( HORZ_SCROLL
);
2374 mpHScrollBar
->SetPageSize( aOutSz
.Width() - HORZ_SCROLL
);
2378 void ImplListBox::ImplResizeControls()
2380 // Here we only position the Controls; if the Scrollbars are to be
2381 // visible is already determined in ImplCheckScrollBars
2383 Size aOutSz
= GetOutputSizePixel();
2384 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2385 nSBWidth
= CalcZoom( nSBWidth
);
2387 Size
aInnerSz( aOutSz
);
2389 aInnerSz
.Width() -= nSBWidth
;
2391 aInnerSz
.Height() -= nSBWidth
;
2393 // pb: #106948# explicit mirroring for calc
2394 // Scrollbar on left or right side?
2395 bool bMirroring
= maLBWindow
.IsMirroring();
2396 Point
aWinPos( bMirroring
&& mbVScroll
? nSBWidth
: 0, 0 );
2397 maLBWindow
.SetPosSizePixel( aWinPos
, aInnerSz
);
2400 if( mbVScroll
&& mbHScroll
)
2402 Point
aBoxPos( bMirroring
? 0 : aInnerSz
.Width(), aInnerSz
.Height() );
2403 mpScrollBarBox
->SetPosSizePixel( aBoxPos
, Size( nSBWidth
, nSBWidth
) );
2404 mpScrollBarBox
->Show();
2408 mpScrollBarBox
->Hide();
2411 // vertical ScrollBar
2414 // Scrollbar on left or right side?
2415 Point
aVPos( bMirroring
? 0 : aOutSz
.Width() - nSBWidth
, 0 );
2416 mpVScrollBar
->SetPosSizePixel( aVPos
, Size( nSBWidth
, aInnerSz
.Height() ) );
2417 mpVScrollBar
->Show();
2421 mpVScrollBar
->Hide();
2422 // #107254# Don't reset top entry after resize, but check for max top entry
2423 SetTopEntry( GetTopEntry() );
2426 // horizontal ScrollBar
2429 Point
aHPos( ( bMirroring
&& mbVScroll
) ? nSBWidth
: 0, aOutSz
.Height() - nSBWidth
);
2430 mpHScrollBar
->SetPosSizePixel( aHPos
, Size( aInnerSz
.Width(), nSBWidth
) );
2431 mpHScrollBar
->Show();
2435 mpHScrollBar
->Hide();
2440 void ImplListBox::StateChanged( StateChangedType nType
)
2442 if ( nType
== StateChangedType::INITSHOW
)
2444 ImplCheckScrollBars();
2446 else if ( ( nType
== StateChangedType::UPDATEMODE
) || ( nType
== StateChangedType::DATA
) )
2448 bool bUpdate
= IsUpdateMode();
2449 maLBWindow
.SetUpdateMode( bUpdate
);
2450 if ( bUpdate
&& IsReallyVisible() )
2451 ImplCheckScrollBars();
2453 else if( nType
== StateChangedType::ENABLE
)
2455 mpHScrollBar
->Enable( IsEnabled() );
2456 mpVScrollBar
->Enable( IsEnabled() );
2457 mpScrollBarBox
->Enable( IsEnabled() );
2458 maLBWindow
.Enable( IsEnabled() );
2462 else if ( nType
== StateChangedType::ZOOM
)
2464 maLBWindow
.SetZoom( GetZoom() );
2467 else if ( nType
== StateChangedType::CONTROLFONT
)
2469 maLBWindow
.SetControlFont( GetControlFont() );
2471 else if ( nType
== StateChangedType::CONTROLFOREGROUND
)
2473 maLBWindow
.SetControlForeground( GetControlForeground() );
2475 else if ( nType
== StateChangedType::CONTROLBACKGROUND
)
2477 maLBWindow
.SetControlBackground( GetControlBackground() );
2479 else if( nType
== StateChangedType::MIRRORING
)
2481 maLBWindow
.EnableRTL( IsRTLEnabled() );
2482 mpHScrollBar
->EnableRTL( IsRTLEnabled() );
2483 mpVScrollBar
->EnableRTL( IsRTLEnabled() );
2484 ImplResizeControls();
2487 Control::StateChanged( nType
);
2490 void ImplListBox::DataChanged( const DataChangedEvent
& rDCEvt
)
2492 Control::DataChanged( rDCEvt
);
2495 bool ImplListBox::Notify( NotifyEvent
& rNEvt
)
2498 if ( rNEvt
.GetType() == MouseNotifyEvent::COMMAND
)
2500 const CommandEvent
& rCEvt
= *rNEvt
.GetCommandEvent();
2501 if ( rCEvt
.GetCommand() == COMMAND_WHEEL
)
2503 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2504 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2506 nDone
= HandleScrollCommand( rCEvt
, mpHScrollBar
, mpVScrollBar
);
2511 return nDone
|| Window::Notify( rNEvt
);
2514 const Wallpaper
& ImplListBox::GetDisplayBackground() const
2516 return maLBWindow
.GetDisplayBackground();
2519 bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent
& rCEvt
)
2522 if ( rCEvt
.GetCommand() == COMMAND_WHEEL
)
2524 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2525 if( !pData
->GetModifier() && ( pData
->GetMode() == CommandWheelMode::SCROLL
) )
2527 sal_uInt16 nKey
= ( pData
->GetDelta() < 0 ) ? KEY_DOWN
: KEY_UP
;
2528 KeyEvent
aKeyEvent( 0, vcl::KeyCode( nKey
) );
2529 bDone
= ProcessKeyInput( aKeyEvent
);
2535 void ImplListBox::SetMRUEntries( const OUString
& rEntries
, sal_Unicode cSep
)
2537 bool bChanges
= GetEntryList()->GetMRUCount() ? true : false;
2539 // Remove old MRU entries
2540 for ( sal_Int32 n
= GetEntryList()->GetMRUCount();n
; )
2541 maLBWindow
.RemoveEntry( --n
);
2543 sal_Int32 nMRUCount
= 0;
2544 sal_Int32 nIndex
= 0;
2547 OUString aEntry
= rEntries
.getToken( 0, cSep
, nIndex
);
2548 // Accept only existing entries
2549 if ( GetEntryList()->FindEntry( aEntry
) != LISTBOX_ENTRY_NOTFOUND
)
2551 ImplEntryType
* pNewEntry
= new ImplEntryType( aEntry
);
2552 maLBWindow
.GetEntryList()->InsertEntry( nMRUCount
++, pNewEntry
, false );
2556 while ( nIndex
>= 0 );
2560 maLBWindow
.GetEntryList()->SetMRUCount( nMRUCount
);
2561 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
2562 StateChanged( StateChangedType::DATA
);
2566 OUString
ImplListBox::GetMRUEntries( sal_Unicode cSep
) const
2568 OUStringBuffer aEntries
;
2569 for ( sal_Int32 n
= 0; n
< GetEntryList()->GetMRUCount(); n
++ )
2571 aEntries
.append(GetEntryList()->GetEntryText( n
));
2572 if( n
< ( GetEntryList()->GetMRUCount() - 1 ) )
2573 aEntries
.append(cSep
);
2575 return aEntries
.makeStringAndClear();
2578 void ImplListBox::SetEdgeBlending(bool bNew
)
2580 if(mbEdgeBlending
!= bNew
)
2582 mbEdgeBlending
= bNew
;
2583 maLBWindow
.SetEdgeBlending(GetEdgeBlending());
2587 ImplWin::ImplWin( vcl::Window
* pParent
, WinBits nWinStyle
) :
2588 Control ( pParent
, nWinStyle
)
2590 if ( IsNativeControlSupported(CTRL_LISTBOX
, PART_ENTIRE_CONTROL
)
2591 && ! IsNativeControlSupported(CTRL_LISTBOX
, PART_BUTTON_DOWN
) )
2594 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2596 mbInUserDraw
= false;
2597 mbUserDrawEnabled
= false;
2598 mbEdgeBlending
= false;
2599 mnItemPos
= LISTBOX_ENTRY_NOTFOUND
;
2602 void ImplWin::MBDown()
2605 buttonDownSignal( this );
2608 void ImplWin::MouseButtonDown( const MouseEvent
& )
2616 void ImplWin::FillLayoutData() const
2618 mpControlData
->mpLayoutData
= new vcl::ControlLayoutData();
2619 const_cast<ImplWin
*>(this)->ImplDraw( true );
2622 bool ImplWin::PreNotify( NotifyEvent
& rNEvt
)
2624 const MouseEvent
* pMouseEvt
= NULL
;
2626 if( (rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
) && (pMouseEvt
= rNEvt
.GetMouseEvent()) != NULL
)
2628 if( pMouseEvt
->IsEnterWindow() || pMouseEvt
->IsLeaveWindow() )
2630 // trigger redraw as mouse over state has changed
2631 if ( IsNativeControlSupported(CTRL_LISTBOX
, PART_ENTIRE_CONTROL
)
2632 && ! IsNativeControlSupported(CTRL_LISTBOX
, PART_BUTTON_DOWN
) )
2634 GetParent()->GetWindow( WINDOW_BORDER
)->Invalidate( INVALIDATE_NOERASE
);
2635 GetParent()->GetWindow( WINDOW_BORDER
)->Update();
2640 return Control::PreNotify(rNEvt
);
2643 void ImplWin::ImplDraw( bool bLayout
)
2645 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
2649 bool bNativeOK
= false;
2651 ControlState nState
= ControlState::ENABLED
;
2652 if ( IsNativeControlSupported(CTRL_LISTBOX
, PART_ENTIRE_CONTROL
)
2653 && IsNativeControlSupported(CTRL_LISTBOX
, HAS_BACKGROUND_TEXTURE
) )
2655 // Repaint the (focused) area similarly to
2656 // ImplSmallBorderWindowView::DrawWindow() in
2657 // vcl/source/window/brdwin.cxx
2658 vcl::Window
*pWin
= GetParent();
2660 ImplControlValue aControlValue
;
2661 if ( !pWin
->IsEnabled() )
2662 nState
&= ~ControlState::ENABLED
;
2663 if ( pWin
->HasFocus() )
2664 nState
|= ControlState::FOCUSED
;
2666 // The listbox is painted over the entire control including the
2667 // border, but ImplWin does not contain the border => correction
2669 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2670 pWin
->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2671 Point
aPoint( -nLeft
, -nTop
);
2672 Rectangle
aCtrlRegion( aPoint
- GetPosPixel(), pWin
->GetSizePixel() );
2674 bool bMouseOver
= false;
2677 vcl::Window
*pChild
= GetParent()->GetWindow( WINDOW_FIRSTCHILD
);
2678 while( pChild
&& !(bMouseOver
= pChild
->IsMouseOver()) )
2679 pChild
= pChild
->GetWindow( WINDOW_NEXT
);
2683 nState
|= ControlState::ROLLOVER
;
2685 // if parent has no border, then nobody has drawn the background
2686 // since no border window exists. so draw it here.
2687 WinBits nParentStyle
= pWin
->GetStyle();
2688 if( ! (nParentStyle
& WB_BORDER
) || (nParentStyle
& WB_NOBORDER
) )
2690 Rectangle
aParentRect( Point( 0, 0 ), pWin
->GetSizePixel() );
2691 pWin
->DrawNativeControl( CTRL_LISTBOX
, PART_ENTIRE_CONTROL
, aParentRect
,
2692 nState
, aControlValue
, OUString() );
2695 bNativeOK
= DrawNativeControl( CTRL_LISTBOX
, PART_ENTIRE_CONTROL
, aCtrlRegion
, nState
,
2696 aControlValue
, OUString() );
2703 SetTextColor( rStyleSettings
.GetHighlightTextColor() );
2704 SetFillColor( rStyleSettings
.GetHighlightColor() );
2705 DrawRect( maFocusRect
);
2710 if( ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2712 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2713 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
2715 aColor
= rStyleSettings
.GetButtonTextColor();
2719 if( bNativeOK
&& (nState
& ControlState::ROLLOVER
) )
2720 aColor
= rStyleSettings
.GetFieldRolloverTextColor();
2722 aColor
= rStyleSettings
.GetFieldTextColor();
2724 if( IsControlForeground() )
2725 aColor
= GetControlForeground();
2726 SetTextColor( aColor
);
2728 Erase( maFocusRect
);
2733 SetTextColor( rStyleSettings
.GetDisableColor() );
2735 Erase( maFocusRect
);
2739 if ( IsUserDrawEnabled() )
2741 mbInUserDraw
= true;
2742 UserDrawEvent
aUDEvt( this, maFocusRect
, mnItemPos
, 0 );
2743 userDrawSignal( &aUDEvt
);
2744 mbInUserDraw
= false;
2748 DrawEntry( true, true, false, bLayout
);
2752 void ImplWin::Paint( const Rectangle
& )
2757 void ImplWin::DrawEntry( bool bDrawImage
, bool bDrawText
, bool bDrawTextAtImagePos
, bool bLayout
)
2760 Size aOutSz
= GetOutputSizePixel();
2762 bool bImage
= !!maImage
;
2763 if( bDrawImage
&& bImage
&& !bLayout
)
2765 sal_uInt16 nStyle
= 0;
2766 Size aImgSz
= maImage
.GetSizePixel();
2767 Point
aPtImg( nBorder
, ( ( aOutSz
.Height() - aImgSz
.Height() ) / 2 ) );
2768 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2770 // check for HC mode
2771 Image
*pImage
= &maImage
;
2775 DrawImage( aPtImg
, *pImage
, nStyle
);
2779 aImgSz
.Width() = CalcZoom( aImgSz
.Width() );
2780 aImgSz
.Height() = CalcZoom( aImgSz
.Height() );
2781 DrawImage( aPtImg
, aImgSz
, *pImage
, nStyle
);
2784 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
2786 if(nEdgeBlendingPercent
)
2788 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
2789 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
2790 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
2791 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
2793 if(!aBlendFrame
.IsEmpty())
2795 DrawBitmapEx(aPtImg
, aBlendFrame
);
2800 if( bDrawText
&& !maString
.isEmpty() )
2802 sal_uInt16 nTextStyle
= TEXT_DRAW_VCENTER
;
2804 if ( bDrawImage
&& bImage
&& !bLayout
)
2805 nTextStyle
|= TEXT_DRAW_LEFT
;
2806 else if ( GetStyle() & WB_CENTER
)
2807 nTextStyle
|= TEXT_DRAW_CENTER
;
2808 else if ( GetStyle() & WB_RIGHT
)
2809 nTextStyle
|= TEXT_DRAW_RIGHT
;
2811 nTextStyle
|= TEXT_DRAW_LEFT
;
2813 Rectangle
aTextRect( Point( nBorder
, 0 ), Size( aOutSz
.Width()-2*nBorder
, aOutSz
.Height() ) );
2815 if ( !bDrawTextAtImagePos
&& ( bImage
|| IsUserDrawEnabled() ) )
2817 long nMaxWidth
= std::max( maImage
.GetSizePixel().Width(), maUserItemSize
.Width() );
2818 aTextRect
.Left() += nMaxWidth
+ IMG_TXT_DISTANCE
;
2821 MetricVector
* pVector
= bLayout
? &mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
: NULL
;
2822 OUString
* pDisplayText
= bLayout
? &mpControlData
->mpLayoutData
->m_aDisplayText
: NULL
;
2823 DrawText( aTextRect
, maString
, nTextStyle
, pVector
, pDisplayText
);
2826 if( HasFocus() && !bLayout
)
2827 ShowFocus( maFocusRect
);
2830 void ImplWin::Resize()
2833 maFocusRect
.SetSize( GetOutputSizePixel() );
2837 void ImplWin::GetFocus()
2839 ShowFocus( maFocusRect
);
2840 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2841 IsNativeWidgetEnabled() &&
2842 IsNativeControlSupported( CTRL_LISTBOX
, PART_ENTIRE_CONTROL
) )
2844 vcl::Window
* pWin
= GetParent()->GetWindow( WINDOW_BORDER
);
2851 Control::GetFocus();
2854 void ImplWin::LoseFocus()
2857 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2858 IsNativeWidgetEnabled() &&
2859 IsNativeControlSupported( CTRL_LISTBOX
, PART_ENTIRE_CONTROL
) )
2861 vcl::Window
* pWin
= GetParent()->GetWindow( WINDOW_BORDER
);
2868 Control::LoseFocus();
2871 ImplBtn::ImplBtn( vcl::Window
* pParent
, WinBits nWinStyle
) :
2872 PushButton( pParent
, nWinStyle
),
2877 void ImplBtn::MBDown()
2880 buttonDownSignal( this );
2883 void ImplBtn::MouseButtonDown( const MouseEvent
& )
2885 //PushButton::MouseButtonDown( rMEvt );
2893 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( vcl::Window
* pParent
) :
2894 FloatingWindow( pParent
, WB_BORDER
| WB_SYSTEMWINDOW
| WB_NOSHADOW
) // no drop shadow for list boxes
2898 mbAutoWidth
= false;
2900 mnPopupModeStartSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
2902 EnableSaveBackground();
2904 vcl::Window
* pBorderWindow
= ImplGetBorderWindow();
2907 SetAccessibleRole(accessibility::AccessibleRole::PANEL
);
2908 pBorderWindow
->SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2912 SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
2917 bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent
& rNEvt
)
2919 if( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2921 if( !GetParent()->HasChildPathFocus( true ) )
2925 return FloatingWindow::PreNotify( rNEvt
);
2928 void ImplListBoxFloatingWindow::setPosSizePixel( long nX
, long nY
, long nWidth
, long nHeight
, sal_uInt16 nFlags
)
2930 FloatingWindow::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
2932 // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2933 // after a call to Resize(), we adjust its position if necessary
2934 if ( IsReallyVisible() && ( nFlags
& WINDOW_POSSIZE_HEIGHT
) )
2936 Point aPos
= GetParent()->GetPosPixel();
2937 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
2939 if ( nFlags
& WINDOW_POSSIZE_X
)
2942 if ( nFlags
& WINDOW_POSSIZE_Y
)
2946 SetPosPixel( ImplCalcPos( this, Rectangle( aPos
, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN
, nIndex
) );
2949 // if( !IsReallyVisible() )
2951 // The ImplListBox does not get a Resize() as not visible.
2952 // But the windows must get a Resize(), so that the number of
2953 // visible entries is correct for PgUp/PgDown.
2954 // The number also cannot be calculated by List/Combobox, as for
2955 // this the presence of the vertical Scrollbar has to be known.
2956 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
2957 ((vcl::Window
*)mpImplLB
)->Resize();
2958 ((vcl::Window
&)mpImplLB
->GetMainWindow()).Resize();
2962 void ImplListBoxFloatingWindow::Resize()
2964 mpImplLB
->GetMainWindow().ImplClearLayoutData();
2965 FloatingWindow::Resize();
2968 Size
ImplListBoxFloatingWindow::CalcFloatSize()
2970 Size
aFloatSz( maPrefSz
);
2972 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2973 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2975 sal_Int32 nLines
= mpImplLB
->GetEntryList()->GetEntryCount();
2976 if ( mnDDLineCount
&& ( nLines
> mnDDLineCount
) )
2977 nLines
= mnDDLineCount
;
2979 Size aSz
= mpImplLB
->CalcSize( nLines
);
2980 long nMaxHeight
= aSz
.Height() + nTop
+ nBottom
;
2982 if ( mnDDLineCount
)
2983 aFloatSz
.Height() = nMaxHeight
;
2987 // AutoSize first only for width...
2989 aFloatSz
.Width() = aSz
.Width() + nLeft
+ nRight
;
2990 aFloatSz
.Width() += nRight
; // adding some space looks better...
2992 if ( ( aFloatSz
.Height() < nMaxHeight
) || ( mnDDLineCount
&& ( mnDDLineCount
< mpImplLB
->GetEntryList()->GetEntryCount() ) ) )
2994 // then we also need the vertical Scrollbar
2995 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2996 aFloatSz
.Width() += nSBWidth
;
2999 long nDesktopWidth
= GetDesktopRectPixel().getWidth();
3000 if (aFloatSz
.Width() > nDesktopWidth
)
3001 // Don't exceed the desktop width.
3002 aFloatSz
.Width() = nDesktopWidth
;
3005 if ( aFloatSz
.Height() > nMaxHeight
)
3006 aFloatSz
.Height() = nMaxHeight
;
3008 // Minimal height, in case height is not set to Float height.
3009 // The parent of FloatWin must be DropDown-Combo/Listbox.
3010 Size aParentSz
= GetParent()->GetSizePixel();
3011 if( (!mnDDLineCount
|| !nLines
) && ( aFloatSz
.Height() < aParentSz
.Height() ) )
3012 aFloatSz
.Height() = aParentSz
.Height();
3014 // do not get narrower than the parent...
3015 if( aFloatSz
.Width() < aParentSz
.Width() )
3016 aFloatSz
.Width() = aParentSz
.Width();
3018 // align height to entries...
3019 long nInnerHeight
= aFloatSz
.Height() - nTop
- nBottom
;
3020 long nEntryHeight
= mpImplLB
->GetEntryHeight();
3021 if ( nInnerHeight
% nEntryHeight
)
3023 nInnerHeight
/= nEntryHeight
;
3025 nInnerHeight
*= nEntryHeight
;
3026 aFloatSz
.Height() = nInnerHeight
+ nTop
+ nBottom
;
3029 if (aFloatSz
.Width() < aSz
.Width())
3031 // The max width of list box entries exceeds the window width.
3032 // Account for the scroll bar height.
3033 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
3034 aFloatSz
.Height() += nSBWidth
;
3040 void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking
)
3042 if( !IsInPopupMode() )
3044 Size aFloatSz
= CalcFloatSize();
3046 SetSizePixel( aFloatSz
);
3047 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
3049 sal_Int32 nPos
= mpImplLB
->GetEntryList()->GetSelectEntryPos( 0 );
3050 mnPopupModeStartSaveSelection
= nPos
;
3052 Size aSz
= GetParent()->GetSizePixel();
3053 Point aPos
= GetParent()->GetPosPixel();
3054 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
3055 // FIXME: this ugly hack is for Mac/Aqua
3056 // should be replaced by a real mechanism to place the float rectangle
3057 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
3058 GetParent()->IsNativeWidgetEnabled() )
3060 sal_Int32 nLeft
= 4, nTop
= 4, nRight
= 4, nBottom
= 4;
3063 aSz
.Width() -= nLeft
+ nRight
;
3064 aSz
.Height() -= nTop
+ nBottom
;
3066 Rectangle
aRect( aPos
, aSz
);
3068 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3069 // where the document is unmirrored
3070 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3071 vcl::Window
*pGrandparent
= GetParent()->GetParent();
3072 const OutputDevice
*pGrandparentOutDev
= pGrandparent
->GetOutDev();
3074 if( pGrandparent
->ImplIsAntiparallel() )
3075 pGrandparentOutDev
->ReMirror( aRect
);
3077 // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795
3078 const sal_uLong nFlags
= FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK
| FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE
;
3080 StartPopupMode( aRect
, FLOATWIN_POPUPMODE_DOWN
| nFlags
);
3082 if( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
3083 mpImplLB
->ShowProminentEntry( nPos
);
3085 if( bStartTracking
)
3086 mpImplLB
->GetMainWindow().EnableMouseMoveSelect( true );
3088 if ( mpImplLB
->GetMainWindow().IsGrabFocusAllowed() )
3089 mpImplLB
->GetMainWindow().GrabFocus();
3091 mpImplLB
->GetMainWindow().ImplClearLayoutData();
3095 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */