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 .
21 #include <tools/debug.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/event.hxx>
26 #include <vcl/scrbar.hxx>
27 #include <vcl/help.hxx>
28 #include <vcl/lstbox.h>
29 #include <vcl/unohelp.hxx>
30 #include <vcl/i18nhelp.hxx>
32 #include <ilstbox.hxx>
33 #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>
44 #define MULTILINE_ENTRY_DRAW_FLAGS ( TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_VCENTER )
46 using namespace ::com::sun::star
;
48 // =======================================================================
50 void ImplInitFieldSettings( Window
* pWin
, sal_Bool bFont
, sal_Bool bForeground
, sal_Bool bBackground
)
52 const StyleSettings
& rStyleSettings
= pWin
->GetSettings().GetStyleSettings();
56 Font aFont
= rStyleSettings
.GetFieldFont();
57 if ( pWin
->IsControlFont() )
58 aFont
.Merge( pWin
->GetControlFont() );
59 pWin
->SetZoomedPointFont( aFont
);
62 if ( bFont
|| bForeground
)
64 Color aTextColor
= rStyleSettings
.GetFieldTextColor();
65 if ( pWin
->IsControlForeground() )
66 aTextColor
= pWin
->GetControlForeground();
67 pWin
->SetTextColor( aTextColor
);
72 if( pWin
->IsControlBackground() )
73 pWin
->SetBackground( pWin
->GetControlBackground() );
75 pWin
->SetBackground( rStyleSettings
.GetFieldColor() );
79 // -----------------------------------------------------------------------
81 void ImplInitDropDownButton( PushButton
* pButton
)
83 if ( pButton
->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN
)
84 pButton
->SetSymbol( SYMBOL_SPIN_UPDOWN
);
86 pButton
->SetSymbol( SYMBOL_SPIN_DOWN
);
88 if ( pButton
->IsNativeControlSupported(CTRL_LISTBOX
, PART_ENTIRE_CONTROL
)
89 && ! pButton
->IsNativeControlSupported(CTRL_LISTBOX
, PART_BUTTON_DOWN
) )
90 pButton
->SetBackground();
93 // =======================================================================
95 ImplEntryList::ImplEntryList( Window
* pWindow
)
98 mnLastSelected
= LISTBOX_ENTRY_NOTFOUND
;
99 mnSelectionAnchor
= LISTBOX_ENTRY_NOTFOUND
;
101 mbCallSelectionChangedHdl
= sal_True
;
107 // -----------------------------------------------------------------------
109 ImplEntryList::~ImplEntryList()
114 // -----------------------------------------------------------------------
116 void ImplEntryList::Clear()
122 // -----------------------------------------------------------------------
124 void ImplEntryList::SelectEntry( sal_uInt16 nPos
, sal_Bool bSelect
)
126 if (nPos
< maEntries
.size())
128 boost::ptr_vector
<ImplEntryType
>::iterator iter
= maEntries
.begin()+nPos
;
130 if ( ( iter
->mbIsSelected
!= bSelect
) &&
131 ( (iter
->mnFlags
& LISTBOX_ENTRY_FLAG_DISABLE_SELECTION
) == 0 ) )
133 iter
->mbIsSelected
= bSelect
;
134 if ( mbCallSelectionChangedHdl
)
135 maSelectionChangedHdl
.Call( (void*)sal_IntPtr(nPos
) );
143 : public rtl::StaticWithInit
< comphelper::string::NaturalStringSorter
, theSorter
>
145 comphelper::string::NaturalStringSorter
operator () ()
147 return comphelper::string::NaturalStringSorter(
148 ::comphelper::getProcessComponentContext(),
149 Application::GetSettings().GetLanguageTag().getLocale());
158 const comphelper::string::NaturalStringSorter
& getNaturalStringSorterForAppLocale()
160 return theSorter::get();
165 sal_uInt16
ImplEntryList::InsertEntry( sal_uInt16 nPos
, ImplEntryType
* pNewEntry
, sal_Bool bSort
)
167 if ( !!pNewEntry
->maImage
)
170 sal_uInt16 insPos
= 0;
172 if ( !bSort
|| maEntries
.empty())
174 if (nPos
< maEntries
.size())
177 maEntries
.insert( maEntries
.begin() + nPos
, pNewEntry
);
181 insPos
= maEntries
.size();
182 maEntries
.push_back(pNewEntry
);
187 const comphelper::string::NaturalStringSorter
&rSorter
= theSorter::get();
189 const XubString
& rStr
= pNewEntry
->maStr
;
190 sal_uLong nLow
, nHigh
, nMid
;
192 nHigh
= maEntries
.size();
194 ImplEntryType
* pTemp
= GetEntry( (sal_uInt16
)(nHigh
-1) );
198 // XXX even though XCollator::compareString returns a sal_Int32 the only
199 // defined values are {-1, 0, 1} which is compatible with StringCompare
200 StringCompare eComp
= (StringCompare
)rSorter
.compare(rStr
, pTemp
->maStr
);
202 // fast insert for sorted data
203 if ( eComp
!= COMPARE_LESS
)
205 insPos
= maEntries
.size();
206 maEntries
.push_back(pNewEntry
);
211 pTemp
= (ImplEntryType
*)GetEntry( (sal_uInt16
)nLow
);
213 eComp
= (StringCompare
)rSorter
.compare(rStr
, pTemp
->maStr
);
214 if ( eComp
!= COMPARE_GREATER
)
217 maEntries
.insert(maEntries
.begin(),pNewEntry
);
225 nMid
= (nLow
+ nHigh
) / 2;
226 pTemp
= (ImplEntryType
*)GetEntry( nMid
);
228 eComp
= (StringCompare
)rSorter
.compare(rStr
, pTemp
->maStr
);
230 if ( eComp
== COMPARE_LESS
)
234 if ( eComp
== COMPARE_GREATER
)
240 while ( nLow
<= nHigh
);
242 if ( eComp
!= COMPARE_LESS
)
246 maEntries
.insert(maEntries
.begin()+nMid
,pNewEntry
);
250 catch (uno::RuntimeException
& )
252 // XXX this is arguable, if the exception occurred because pNewEntry is
253 // garbage you wouldn't insert it. If the exception occurred because the
254 // Collator implementation is garbage then give the user a chance to see
257 maEntries
.insert(maEntries
.begin(),pNewEntry
);
265 // -----------------------------------------------------------------------
267 void ImplEntryList::RemoveEntry( sal_uInt16 nPos
)
269 if (nPos
< maEntries
.size())
271 boost::ptr_vector
<ImplEntryType
>::iterator iter
= maEntries
.begin()+ nPos
;
273 if ( !!iter
->maImage
)
276 maEntries
.erase(iter
);
280 // -----------------------------------------------------------------------
282 sal_uInt16
ImplEntryList::FindEntry( const XubString
& rString
, sal_Bool bSearchMRUArea
) const
284 sal_uInt16 nEntries
= maEntries
.size();
285 for ( sal_uInt16 n
= bSearchMRUArea
? 0 : GetMRUCount(); n
< nEntries
; n
++ )
287 String
aComp( vcl::I18nHelper::filterFormattingChars( maEntries
[n
].maStr
) );
288 if ( aComp
== rString
)
291 return LISTBOX_ENTRY_NOTFOUND
;
294 // -----------------------------------------------------------------------
296 sal_uInt16
ImplEntryList::FindMatchingEntry( const XubString
& rStr
, sal_uInt16 nStart
, sal_Bool bForward
, sal_Bool bLazy
) const
298 sal_uInt16 nPos
= LISTBOX_ENTRY_NOTFOUND
;
299 sal_uInt16 nEntryCount
= GetEntryCount();
301 nStart
++; // decrements right away
303 const vcl::I18nHelper
& rI18nHelper
= mpWindow
->GetSettings().GetLocaleI18nHelper();
304 for ( sal_uInt16 n
= nStart
; bForward
? ( n
< nEntryCount
) : n
; )
309 ImplEntryType
* pImplEntry
= GetEntry( n
);
310 bool bMatch
= bLazy
? rI18nHelper
.MatchString( rStr
, pImplEntry
->maStr
) != 0 : ( rStr
.Match( pImplEntry
->maStr
) == STRING_MATCH
);
324 // -----------------------------------------------------------------------
326 sal_uInt16
ImplEntryList::FindEntry( const void* pData
) const
328 sal_uInt16 nPos
= LISTBOX_ENTRY_NOTFOUND
;
329 for ( sal_uInt16 n
= GetEntryCount(); n
; )
331 ImplEntryType
* pImplEntry
= GetEntry( --n
);
332 if ( pImplEntry
->mpUserData
== pData
)
341 // -----------------------------------------------------------------------
343 long ImplEntryList::GetAddedHeight( sal_uInt16 i_nEndIndex
, sal_uInt16 i_nBeginIndex
, long i_nBeginHeight
) const
345 long nHeight
= i_nBeginHeight
;
346 sal_uInt16 nStart
= i_nEndIndex
> i_nBeginIndex
? i_nBeginIndex
: i_nEndIndex
;
347 sal_uInt16 nStop
= i_nEndIndex
> i_nBeginIndex
? i_nEndIndex
: i_nBeginIndex
;
348 sal_uInt16 nEntryCount
= GetEntryCount();
349 if( nStop
!= LISTBOX_ENTRY_NOTFOUND
&& nEntryCount
!= 0 )
352 if( nStop
> nEntryCount
-1 )
353 nStop
= nEntryCount
-1;
354 if( nStart
> nEntryCount
-1 )
355 nStart
= nEntryCount
-1;
357 sal_uInt16 nIndex
= nStart
;
358 while( nIndex
!= LISTBOX_ENTRY_NOTFOUND
&& nIndex
< nStop
)
360 nHeight
+= GetEntryPtr( nIndex
)-> mnHeight
;
366 return i_nEndIndex
> i_nBeginIndex
? nHeight
: -nHeight
;
369 // -----------------------------------------------------------------------
371 long ImplEntryList::GetEntryHeight( sal_uInt16 nPos
) const
373 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
374 return pImplEntry
? pImplEntry
->mnHeight
: 0;
377 // -----------------------------------------------------------------------
379 OUString
ImplEntryList::GetEntryText( sal_uInt16 nPos
) const
382 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
384 aEntryText
= pImplEntry
->maStr
;
388 // -----------------------------------------------------------------------
390 sal_Bool
ImplEntryList::HasEntryImage( sal_uInt16 nPos
) const
392 sal_Bool bImage
= sal_False
;
393 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
395 bImage
= !!pImplEntry
->maImage
;
399 // -----------------------------------------------------------------------
401 Image
ImplEntryList::GetEntryImage( sal_uInt16 nPos
) const
404 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
406 aImage
= pImplEntry
->maImage
;
410 // -----------------------------------------------------------------------
412 void ImplEntryList::SetEntryData( sal_uInt16 nPos
, void* pNewData
)
414 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
416 pImplEntry
->mpUserData
= pNewData
;
419 // -----------------------------------------------------------------------
421 void* ImplEntryList::GetEntryData( sal_uInt16 nPos
) const
423 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
424 return pImplEntry
? pImplEntry
->mpUserData
: NULL
;
427 // -----------------------------------------------------------------------
429 void ImplEntryList::SetEntryFlags( sal_uInt16 nPos
, long nFlags
)
431 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
433 pImplEntry
->mnFlags
= nFlags
;
436 // -----------------------------------------------------------------------
438 long ImplEntryList::GetEntryFlags( sal_uInt16 nPos
) const
440 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
441 return pImplEntry
? pImplEntry
->mnFlags
: 0;
444 // -----------------------------------------------------------------------
446 sal_uInt16
ImplEntryList::GetSelectEntryCount() const
448 sal_uInt16 nSelCount
= 0;
449 for ( sal_uInt16 n
= GetEntryCount(); n
; )
451 ImplEntryType
* pImplEntry
= GetEntry( --n
);
452 if ( pImplEntry
->mbIsSelected
)
458 // -----------------------------------------------------------------------
460 OUString
ImplEntryList::GetSelectEntry( sal_uInt16 nIndex
) const
462 return GetEntryText( GetSelectEntryPos( nIndex
) );
465 // -----------------------------------------------------------------------
467 sal_uInt16
ImplEntryList::GetSelectEntryPos( sal_uInt16 nIndex
) const
469 sal_uInt16 nSelEntryPos
= LISTBOX_ENTRY_NOTFOUND
;
471 sal_uInt16 nEntryCount
= GetEntryCount();
473 for ( sal_uInt16 n
= 0; n
< nEntryCount
; n
++ )
475 ImplEntryType
* pImplEntry
= GetEntry( n
);
476 if ( pImplEntry
->mbIsSelected
)
478 if ( nSel
== nIndex
)
490 // -----------------------------------------------------------------------
492 sal_Bool
ImplEntryList::IsEntryPosSelected( sal_uInt16 nIndex
) const
494 ImplEntryType
* pImplEntry
= GetEntry( nIndex
);
495 return pImplEntry
? pImplEntry
->mbIsSelected
: sal_False
;
498 // -----------------------------------------------------------------------
500 bool ImplEntryList::IsEntrySelectable( sal_uInt16 nPos
) const
502 ImplEntryType
* pImplEntry
= GetEntry( nPos
);
503 return pImplEntry
? ((pImplEntry
->mnFlags
& LISTBOX_ENTRY_FLAG_DISABLE_SELECTION
) == 0) : true;
506 // -----------------------------------------------------------------------
508 sal_uInt16
ImplEntryList::FindFirstSelectable( sal_uInt16 nPos
, bool bForward
/* = true */ )
510 if( IsEntrySelectable( nPos
) )
515 for( nPos
= nPos
+ 1; nPos
< GetEntryCount(); nPos
++ )
517 if( IsEntrySelectable( nPos
) )
526 if( IsEntrySelectable( nPos
) )
531 return LISTBOX_ENTRY_NOTFOUND
;
534 // =======================================================================
536 ImplListBoxWindow::ImplListBoxWindow( Window
* pParent
, WinBits nWinStyle
) :
537 Control( pParent
, 0 ),
538 maQuickSelectionEngine( *this )
540 mpEntryList
= new ImplEntryList( this );
545 mnSelectModifier
= 0;
546 mnUserDrawEntry
= LISTBOX_ENTRY_NOTFOUND
;
548 mbImgsDiffSz
= false;
549 mbTravelSelect
= false;
550 mbTrackingSelect
= false;
551 mbSelectionChanged
= false;
552 mbMouseMoveSelect
= false;
556 mbUserDrawEnabled
= false;
557 mbInUserDraw
= false;
559 mbHasFocusRect
= false;
560 mbRight
= ( nWinStyle
& WB_RIGHT
);
561 mbCenter
= ( nWinStyle
& WB_CENTER
);
562 mbSimpleMode
= ( nWinStyle
& WB_SIMPLEMODE
);
563 mbSort
= ( nWinStyle
& WB_SORT
);
564 mbEdgeBlending
= false;
566 // pb: #106948# explicit mirroring for calc
569 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
570 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
571 mnSeparatorPos
= LISTBOX_ENTRY_NOTFOUND
;
572 meProminentType
= PROMINENT_TOP
;
576 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
578 ImplInitSettings( sal_True
, sal_True
, sal_True
);
582 // -----------------------------------------------------------------------
584 ImplListBoxWindow::~ImplListBoxWindow()
589 // -----------------------------------------------------------------------
591 void ImplListBoxWindow::ImplInitSettings( sal_Bool bFont
, sal_Bool bForeground
, sal_Bool bBackground
)
593 ImplInitFieldSettings( this, bFont
, bForeground
, bBackground
);
596 // -----------------------------------------------------------------------
598 void ImplListBoxWindow::ImplCalcMetrics()
606 mnTextHeight
= (sal_uInt16
)GetTextHeight();
607 mnMaxTxtHeight
= mnTextHeight
+ mnBorder
;
608 mnMaxHeight
= mnMaxTxtHeight
;
610 if ( maUserItemSize
.Height() > mnMaxHeight
)
611 mnMaxHeight
= (sal_uInt16
) maUserItemSize
.Height();
612 if ( maUserItemSize
.Width() > mnMaxWidth
)
613 mnMaxWidth
= (sal_uInt16
) maUserItemSize
.Width();
615 for ( sal_uInt16 n
= mpEntryList
->GetEntryCount(); n
; )
617 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( --n
);
618 ImplUpdateEntryMetrics( *pEntry
);
621 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
623 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryPtr( mnCurrentPos
)->mnHeight
);
624 maFocusRect
.SetSize( aSz
);
628 // -----------------------------------------------------------------------
630 void ImplListBoxWindow::Clear()
632 mpEntryList
->Clear();
634 mnMaxHeight
= mnMaxTxtHeight
;
642 mbImgsDiffSz
= false;
643 ImplClearLayoutData();
645 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
646 maQuickSelectionEngine
.Reset();
651 void ImplListBoxWindow::SetUserItemSize( const Size
& rSz
)
653 ImplClearLayoutData();
654 maUserItemSize
= rSz
;
658 // -----------------------------------------------------------------------
660 struct ImplEntryMetrics
671 // -----------------------------------------------------------------------
673 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType
& rEntry
)
675 ImplEntryMetrics aMetrics
;
676 aMetrics
.bText
= !rEntry
.maStr
.isEmpty();
677 aMetrics
.bImage
= !!rEntry
.maImage
;
678 aMetrics
.nEntryWidth
= 0;
679 aMetrics
.nEntryHeight
= 0;
680 aMetrics
.nTextWidth
= 0;
681 aMetrics
.nImgWidth
= 0;
682 aMetrics
.nImgHeight
= 0;
684 if ( aMetrics
.bText
)
686 if( (rEntry
.mnFlags
& LISTBOX_ENTRY_FLAG_MULTILINE
) )
689 Size
aCurSize( PixelToLogic( GetSizePixel() ) );
690 // set the current size to a large number
691 // GetTextRect should shrink it to the actual size
692 aCurSize
.Height() = 0x7fffff;
693 Rectangle
aTextRect( Point( 0, 0 ), aCurSize
);
694 aTextRect
= GetTextRect( aTextRect
, rEntry
.maStr
, TEXT_DRAW_WORDBREAK
| TEXT_DRAW_MULTILINE
);
695 aMetrics
.nTextWidth
= aTextRect
.GetWidth();
696 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
697 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
698 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
699 aMetrics
.nEntryHeight
= aTextRect
.GetHeight() + mnBorder
;
703 // normal single line case
704 aMetrics
.nTextWidth
= (sal_uInt16
)GetTextWidth( rEntry
.maStr
);
705 if( aMetrics
.nTextWidth
> mnMaxTxtWidth
)
706 mnMaxTxtWidth
= aMetrics
.nTextWidth
;
707 aMetrics
.nEntryWidth
= mnMaxTxtWidth
;
708 aMetrics
.nEntryHeight
= mnTextHeight
+ mnBorder
;
711 if ( aMetrics
.bImage
)
713 Size aImgSz
= rEntry
.maImage
.GetSizePixel();
714 aMetrics
.nImgWidth
= (sal_uInt16
) CalcZoom( aImgSz
.Width() );
715 aMetrics
.nImgHeight
= (sal_uInt16
) CalcZoom( aImgSz
.Height() );
717 if( mnMaxImgWidth
&& ( aMetrics
.nImgWidth
!= mnMaxImgWidth
) )
719 else if ( mnMaxImgHeight
&& ( aMetrics
.nImgHeight
!= mnMaxImgHeight
) )
722 if( aMetrics
.nImgWidth
> mnMaxImgWidth
)
723 mnMaxImgWidth
= aMetrics
.nImgWidth
;
724 if( aMetrics
.nImgHeight
> mnMaxImgHeight
)
725 mnMaxImgHeight
= aMetrics
.nImgHeight
;
727 mnMaxImgTxtWidth
= std::max( mnMaxImgTxtWidth
, aMetrics
.nTextWidth
);
728 aMetrics
.nEntryHeight
= std::max( aMetrics
.nImgHeight
, aMetrics
.nEntryHeight
);
731 if ( IsUserDrawEnabled() || aMetrics
.bImage
)
733 aMetrics
.nEntryWidth
= std::max( aMetrics
.nImgWidth
, maUserItemSize
.Width() );
734 if ( aMetrics
.bText
)
735 aMetrics
.nEntryWidth
+= aMetrics
.nTextWidth
+ IMG_TXT_DISTANCE
;
736 aMetrics
.nEntryHeight
= std::max( std::max( mnMaxImgHeight
, maUserItemSize
.Height() ) + 2,
737 aMetrics
.nEntryHeight
);
740 if ( !aMetrics
.bText
&& !aMetrics
.bImage
&& !IsUserDrawEnabled() )
742 // entries which have no (aka an empty) text, and no image,
743 // and are not user-drawn, should be shown nonetheless
744 aMetrics
.nEntryHeight
= mnTextHeight
+ mnBorder
;
747 if ( aMetrics
.nEntryWidth
> mnMaxWidth
)
748 mnMaxWidth
= aMetrics
.nEntryWidth
;
749 if ( aMetrics
.nEntryHeight
> mnMaxHeight
)
750 mnMaxHeight
= aMetrics
.nEntryHeight
;
752 rEntry
.mnHeight
= aMetrics
.nEntryHeight
;
755 // -----------------------------------------------------------------------
757 void ImplListBoxWindow::ImplCallSelect()
759 if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
761 // Insert the selected entry as MRU, if not already first MRU
762 sal_uInt16 nSelected
= GetEntryList()->GetSelectEntryPos( 0 );
763 sal_uInt16 nMRUCount
= GetEntryList()->GetMRUCount();
764 String aSelected
= GetEntryList()->GetEntryText( nSelected
);
765 sal_uInt16 nFirstMatchingEntryPos
= GetEntryList()->FindEntry( aSelected
, sal_True
);
766 if ( nFirstMatchingEntryPos
|| !nMRUCount
)
768 sal_Bool bSelectNewEntry
= sal_False
;
769 if ( nFirstMatchingEntryPos
< nMRUCount
)
771 RemoveEntry( nFirstMatchingEntryPos
);
773 if ( nFirstMatchingEntryPos
== nSelected
)
774 bSelectNewEntry
= sal_True
;
776 else if ( nMRUCount
== GetEntryList()->GetMaxMRUCount() )
778 RemoveEntry( nMRUCount
- 1 );
782 ImplClearLayoutData();
784 ImplEntryType
* pNewEntry
= new ImplEntryType( aSelected
);
785 pNewEntry
->mbIsSelected
= bSelectNewEntry
;
786 GetEntryList()->InsertEntry( 0, pNewEntry
, sal_False
);
787 ImplUpdateEntryMetrics( *pNewEntry
);
788 GetEntryList()->SetMRUCount( ++nMRUCount
);
789 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
790 maMRUChangedHdl
.Call( NULL
);
794 maSelectHdl
.Call( NULL
);
795 mbSelectionChanged
= false;
798 // -----------------------------------------------------------------------
800 sal_uInt16
ImplListBoxWindow::InsertEntry( sal_uInt16 nPos
, ImplEntryType
* pNewEntry
)
802 ImplClearLayoutData();
803 sal_uInt16 nNewPos
= mpEntryList
->InsertEntry( nPos
, pNewEntry
, mbSort
);
805 if( (GetStyle() & WB_WORDBREAK
) )
806 pNewEntry
->mnFlags
|= LISTBOX_ENTRY_FLAG_MULTILINE
;
808 ImplUpdateEntryMetrics( *pNewEntry
);
812 // -----------------------------------------------------------------------
814 void ImplListBoxWindow::RemoveEntry( sal_uInt16 nPos
)
816 ImplClearLayoutData();
817 mpEntryList
->RemoveEntry( nPos
);
818 if( mnCurrentPos
>= mpEntryList
->GetEntryCount() )
819 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
823 // -----------------------------------------------------------------------
825 void ImplListBoxWindow::SetEntryFlags( sal_uInt16 nPos
, long nFlags
)
827 mpEntryList
->SetEntryFlags( nPos
, nFlags
);
828 ImplEntryType
* pEntry
= mpEntryList
->GetMutableEntryPtr( nPos
);
830 ImplUpdateEntryMetrics( *pEntry
);
833 // -----------------------------------------------------------------------
835 void ImplListBoxWindow::ImplShowFocusRect()
837 if ( mbHasFocusRect
)
839 ShowFocus( maFocusRect
);
840 mbHasFocusRect
= true;
843 // -----------------------------------------------------------------------
845 void ImplListBoxWindow::ImplHideFocusRect()
847 if ( mbHasFocusRect
)
850 mbHasFocusRect
= false;
855 // -----------------------------------------------------------------------
857 sal_uInt16
ImplListBoxWindow::GetEntryPosForPoint( const Point
& rPoint
) const
861 sal_uInt16 nSelect
= mnTop
;
862 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nSelect
);
863 while( pEntry
&& rPoint
.Y() > pEntry
->mnHeight
+ nY
)
865 nY
+= pEntry
->mnHeight
;
866 pEntry
= mpEntryList
->GetEntryPtr( ++nSelect
);
869 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
874 // -----------------------------------------------------------------------
876 sal_Bool
ImplListBoxWindow::IsVisible( sal_uInt16 i_nEntry
) const
878 sal_Bool bRet
= sal_False
;
880 if( i_nEntry
>= mnTop
)
882 if( mpEntryList
->GetAddedHeight( i_nEntry
, mnTop
) <
883 PixelToLogic( GetSizePixel() ).Height() )
892 // -----------------------------------------------------------------------
894 sal_uInt16
ImplListBoxWindow::GetLastVisibleEntry() const
896 sal_uInt16 nPos
= mnTop
;
897 long nWindowHeight
= GetSizePixel().Height();
898 sal_uInt16 nCount
= mpEntryList
->GetEntryCount();
900 for( nDiff
= 0; nDiff
< nWindowHeight
&& nPos
< nCount
; nDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
) )
903 if( nDiff
> nWindowHeight
&& nPos
> mnTop
)
912 // -----------------------------------------------------------------------
914 void ImplListBoxWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
916 mbMouseMoveSelect
= false; // only till the first MouseButtonDown
917 maQuickSelectionEngine
.Reset();
921 if( rMEvt
.GetClicks() == 1 )
923 sal_uInt16 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
924 if( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
926 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
927 mnTrackingSaveSelection
= GetEntryList()->GetSelectEntryPos( 0 );
929 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
931 mnCurrentPos
= nSelect
;
932 mbTrackingSelect
= true;
933 SelectEntries( nSelect
, LET_MBDOWN
, rMEvt
.IsShift(), rMEvt
.IsMod1() );
934 mbTrackingSelect
= false;
938 StartTracking( STARTTRACK_SCROLLREPEAT
);
941 if( rMEvt
.GetClicks() == 2 )
943 maDoubleClickHdl
.Call( this );
946 else // if ( mbGrabFocus )
952 // -----------------------------------------------------------------------
954 void ImplListBoxWindow::MouseMove( const MouseEvent
& rMEvt
)
956 if ( rMEvt
.IsLeaveWindow() )
958 if ( mbStackMode
&& IsMouseMoveSelect() && IsReallyVisible() )
960 if ( rMEvt
.GetPosPixel().Y() < 0 )
963 mnCurrentPos
= LISTBOX_ENTRY_NOTFOUND
;
965 if ( mbStackMode
) // #87072#, #92323#
967 mbTravelSelect
= true;
968 mnSelectModifier
= rMEvt
.GetModifier();
970 mbTravelSelect
= false;
976 else if ( ( ( !mbMulti
&& IsMouseMoveSelect() ) || mbStackMode
) && mpEntryList
->GetEntryCount() )
979 Rectangle
aRect( aPoint
, GetOutputSizePixel() );
980 if( aRect
.IsInside( rMEvt
.GetPosPixel() ) )
982 if ( IsMouseMoveSelect() )
984 sal_uInt16 nSelect
= GetEntryPosForPoint( rMEvt
.GetPosPixel() );
985 if( nSelect
== LISTBOX_ENTRY_NOTFOUND
)
986 nSelect
= mpEntryList
->GetEntryCount() - 1;
987 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
988 nSelect
= std::min( nSelect
, (sal_uInt16
) ( mpEntryList
->GetEntryCount() - 1 ) );
989 // Select only visible Entries with MouseMove, otherwise Tracking...
990 if ( IsVisible( nSelect
) &&
991 mpEntryList
->IsEntrySelectable( nSelect
) &&
992 ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectEntryCount() || ( nSelect
!= GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
994 mbTrackingSelect
= true;
995 if ( SelectEntries( nSelect
, LET_TRACKING
, sal_False
, sal_False
) )
997 if ( mbStackMode
) // #87072#
999 mbTravelSelect
= true;
1000 mnSelectModifier
= rMEvt
.GetModifier();
1002 mbTravelSelect
= false;
1005 mbTrackingSelect
= false;
1009 // if the DD button was pressed and someone moved into the ListBox
1010 // with the mouse button pressed...
1011 if ( rMEvt
.IsLeft() && !rMEvt
.IsSynthetic() )
1013 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
1014 mnTrackingSaveSelection
= GetEntryList()->GetSelectEntryPos( 0 );
1016 mnTrackingSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
1018 if ( mbStackMode
&& ( mpEntryList
->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND
) )
1019 mpEntryList
->SetSelectionAnchor( 0 );
1021 StartTracking( STARTTRACK_SCROLLREPEAT
);
1027 // -----------------------------------------------------------------------
1029 void ImplListBoxWindow::DeselectAll()
1031 while ( GetEntryList()->GetSelectEntryCount() )
1033 sal_uInt16 nS
= GetEntryList()->GetSelectEntryPos( 0 );
1034 SelectEntry( nS
, sal_False
);
1038 // -----------------------------------------------------------------------
1040 void ImplListBoxWindow::SelectEntry( sal_uInt16 nPos
, sal_Bool bSelect
)
1042 if( (mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
) && mpEntryList
->IsEntrySelectable( nPos
) )
1044 ImplHideFocusRect();
1049 // deselect the selected entry
1050 sal_uInt16 nDeselect
= GetEntryList()->GetSelectEntryPos( 0 );
1051 if( nDeselect
!= LISTBOX_ENTRY_NOTFOUND
)
1053 //SelectEntryPos( nDeselect, sal_False );
1054 GetEntryList()->SelectEntry( nDeselect
, sal_False
);
1055 if ( IsUpdateMode() && IsReallyVisible() )
1056 ImplPaint( nDeselect
, sal_True
);
1059 mpEntryList
->SelectEntry( nPos
, sal_True
);
1060 mnCurrentPos
= nPos
;
1061 if ( ( nPos
!= LISTBOX_ENTRY_NOTFOUND
) && IsUpdateMode() )
1064 if ( !IsVisible( nPos
) )
1066 ImplClearLayoutData();
1067 sal_uInt16 nVisibleEntries
= GetLastVisibleEntry()-mnTop
;
1068 if ( !nVisibleEntries
|| !IsReallyVisible() || ( nPos
< GetTopEntry() ) )
1071 ShowProminentEntry( nPos
);
1075 ShowProminentEntry( nPos
);
1082 mpEntryList
->SelectEntry( nPos
, sal_False
);
1083 ImplPaint( nPos
, sal_True
);
1085 mbSelectionChanged
= true;
1089 // -----------------------------------------------------------------------
1091 sal_Bool
ImplListBoxWindow::SelectEntries( sal_uInt16 nSelect
, LB_EVENT_TYPE eLET
, sal_Bool bShift
, sal_Bool bCtrl
)
1093 bool bFocusChanged
= false;
1094 sal_Bool bSelectionChanged
= sal_False
;
1096 if( IsEnabled() && mpEntryList
->IsEntrySelectable( nSelect
) )
1098 // here (Single-ListBox) only one entry can be deselected
1101 sal_uInt16 nDeselect
= mpEntryList
->GetSelectEntryPos( 0 );
1102 if( nSelect
!= nDeselect
)
1104 SelectEntry( nSelect
, sal_True
);
1105 mpEntryList
->SetLastSelected( nSelect
);
1106 bFocusChanged
= true;
1107 bSelectionChanged
= sal_True
;
1110 // MultiListBox without Modifier
1111 else if( mbSimpleMode
&& !bCtrl
&& !bShift
)
1113 sal_uInt16 nEntryCount
= mpEntryList
->GetEntryCount();
1114 for ( sal_uInt16 nPos
= 0; nPos
< nEntryCount
; nPos
++ )
1116 sal_Bool bSelect
= nPos
== nSelect
;
1117 if ( mpEntryList
->IsEntryPosSelected( nPos
) != bSelect
)
1119 SelectEntry( nPos
, bSelect
);
1120 bFocusChanged
= true;
1121 bSelectionChanged
= sal_True
;
1124 mpEntryList
->SetLastSelected( nSelect
);
1125 mpEntryList
->SetSelectionAnchor( nSelect
);
1127 // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1128 else if( ( !mbSimpleMode
/* && !bShift */ ) || ( (mbSimpleMode
&& ( bCtrl
|| bShift
)) || mbStackMode
) )
1130 // Space for selection change
1131 if( !bShift
&& ( ( eLET
== LET_KEYSPACE
) || ( eLET
== LET_MBDOWN
) ) )
1133 sal_Bool bSelect
= ( mbStackMode
&& IsMouseMoveSelect() ) ? sal_True
: !mpEntryList
->IsEntryPosSelected( nSelect
);
1139 // All entries before nSelect must be selected...
1140 for ( n
= 0; n
< nSelect
; n
++ )
1141 SelectEntry( n
, sal_True
);
1145 for ( n
= nSelect
+1; n
< mpEntryList
->GetEntryCount(); n
++ )
1146 SelectEntry( n
, sal_False
);
1149 SelectEntry( nSelect
, bSelect
);
1150 mpEntryList
->SetLastSelected( nSelect
);
1151 mpEntryList
->SetSelectionAnchor( mbStackMode
? 0 : nSelect
);
1152 if ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1153 mpEntryList
->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND
);
1154 bFocusChanged
= true;
1155 bSelectionChanged
= sal_True
;
1157 else if( ( ( eLET
== LET_TRACKING
) && ( nSelect
!= mnCurrentPos
) ) ||
1158 ( (bShift
||mbStackMode
) && ( ( eLET
== LET_KEYMOVE
) || ( eLET
== LET_MBDOWN
) ) ) )
1160 mnCurrentPos
= nSelect
;
1161 bFocusChanged
= true;
1163 sal_uInt16 nAnchor
= mpEntryList
->GetSelectionAnchor();
1164 if( ( nAnchor
== LISTBOX_ENTRY_NOTFOUND
) && ( mpEntryList
->GetSelectEntryCount() || mbStackMode
) )
1166 nAnchor
= mbStackMode
? 0 : mpEntryList
->GetSelectEntryPos( mpEntryList
->GetSelectEntryCount() - 1 );
1168 if( nAnchor
!= LISTBOX_ENTRY_NOTFOUND
)
1170 // All entries from achor to nSelect have to be selected
1171 sal_uInt16 nStart
= std::min( nSelect
, nAnchor
);
1172 sal_uInt16 nEnd
= std::max( nSelect
, nAnchor
);
1173 for ( sal_uInt16 n
= nStart
; n
<= nEnd
; n
++ )
1175 if ( !mpEntryList
->IsEntryPosSelected( n
) )
1177 SelectEntry( n
, sal_True
);
1178 bSelectionChanged
= sal_True
;
1182 // if appropriate some more has to be deselected...
1183 sal_uInt16 nLast
= mpEntryList
->GetLastSelected();
1184 if ( nLast
!= LISTBOX_ENTRY_NOTFOUND
)
1186 if ( ( nLast
> nSelect
) && ( nLast
> nAnchor
) )
1188 for ( sal_uInt16 n
= nSelect
+1; n
<= nLast
; n
++ )
1190 if ( mpEntryList
->IsEntryPosSelected( n
) )
1192 SelectEntry( n
, sal_False
);
1193 bSelectionChanged
= sal_True
;
1197 else if ( ( nLast
< nSelect
) && ( nLast
< nAnchor
) )
1199 for ( sal_uInt16 n
= nLast
; n
< nSelect
; n
++ )
1201 if ( mpEntryList
->IsEntryPosSelected( n
) )
1203 SelectEntry( n
, sal_False
);
1204 bSelectionChanged
= sal_True
;
1209 mpEntryList
->SetLastSelected( nSelect
);
1212 else if( eLET
!= LET_TRACKING
)
1214 ImplHideFocusRect();
1215 ImplPaint( nSelect
, sal_True
);
1216 bFocusChanged
= true;
1221 bFocusChanged
= true;
1224 if( bSelectionChanged
)
1225 mbSelectionChanged
= true;
1229 long nHeightDiff
= mpEntryList
->GetAddedHeight( nSelect
, mnTop
, 0 );
1230 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1231 Size
aSz( maFocusRect
.GetWidth(),
1232 mpEntryList
->GetEntryHeight( nSelect
) );
1233 maFocusRect
.SetSize( aSz
);
1235 ImplShowFocusRect();
1237 ImplClearLayoutData();
1239 return bSelectionChanged
;
1242 // -----------------------------------------------------------------------
1244 void ImplListBoxWindow::Tracking( const TrackingEvent
& rTEvt
)
1247 Rectangle
aRect( aPoint
, GetOutputSizePixel() );
1248 sal_Bool bInside
= aRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() );
1250 if( rTEvt
.IsTrackingCanceled() || rTEvt
.IsTrackingEnded() ) // MouseButtonUp
1252 if ( bInside
&& !rTEvt
.IsTrackingCanceled() )
1254 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1259 maCancelHdl
.Call( NULL
);
1262 mbTrackingSelect
= true;
1263 SelectEntry( mnTrackingSaveSelection
, sal_True
);
1264 mbTrackingSelect
= false;
1265 if ( mnTrackingSaveSelection
!= LISTBOX_ENTRY_NOTFOUND
)
1267 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
, 0 );
1268 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1269 Size
aSz( maFocusRect
.GetWidth(),
1270 mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1271 maFocusRect
.SetSize( aSz
);
1272 ImplShowFocusRect();
1281 sal_Bool bTrackOrQuickClick
= mbTrack
;
1289 // this case only happens, if the mouse button is pressed very briefly
1290 if( rTEvt
.IsTrackingEnded() && mbTrack
)
1292 bTrackOrQuickClick
= sal_True
;
1297 if( bTrackOrQuickClick
)
1299 MouseEvent aMEvt
= rTEvt
.GetMouseEvent();
1300 Point
aPt( aMEvt
.GetPosPixel() );
1301 sal_Bool bShift
= aMEvt
.IsShift();
1302 sal_Bool bCtrl
= aMEvt
.IsMod1();
1304 sal_uInt16 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1307 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1309 nSelect
= mnCurrentPos
? ( mnCurrentPos
- 1 ) : 0;
1310 if( nSelect
< mnTop
)
1311 SetTopEntry( mnTop
-1 );
1314 else if( aPt
.Y() > GetOutputSizePixel().Height() )
1316 if ( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
1318 nSelect
= std::min( (sal_uInt16
)(mnCurrentPos
+1), (sal_uInt16
)(mpEntryList
->GetEntryCount()-1) );
1319 if( nSelect
>= GetLastVisibleEntry() )
1320 SetTopEntry( mnTop
+1 );
1325 nSelect
= (sal_uInt16
) ( ( aPt
.Y() + mnBorder
) / mnMaxHeight
) + (sal_uInt16
) mnTop
;
1326 nSelect
= std::min( nSelect
, GetLastVisibleEntry() );
1327 nSelect
= std::min( nSelect
, (sal_uInt16
) ( mpEntryList
->GetEntryCount() - 1 ) );
1332 if ( ( nSelect
!= mnCurrentPos
) || !GetEntryList()->GetSelectEntryCount() )
1334 mbTrackingSelect
= true;
1335 if ( SelectEntries( nSelect
, LET_TRACKING
, bShift
, bCtrl
) )
1337 if ( mbStackMode
) // #87734# (#87072#)
1339 mbTravelSelect
= true;
1340 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1342 mbTravelSelect
= false;
1345 mbTrackingSelect
= false;
1350 if ( !mbMulti
&& GetEntryList()->GetSelectEntryCount() )
1352 mbTrackingSelect
= true;
1353 SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), sal_False
);
1354 mbTrackingSelect
= false;
1356 else if ( mbStackMode
)
1358 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt
.GetMouseEvent().GetPosPixel().X() < aRect
.Right() ) )
1360 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt
.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1362 sal_Bool bSelectionChanged
= sal_False
;
1363 if ( ( rTEvt
.GetMouseEvent().GetPosPixel().Y() < 0 )
1366 if ( mpEntryList
->IsEntryPosSelected( 0 ) )
1368 SelectEntry( 0, sal_False
);
1369 bSelectionChanged
= sal_True
;
1370 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1376 mbTrackingSelect
= true;
1377 bSelectionChanged
= SelectEntries( nSelect
, LET_TRACKING
, bShift
, bCtrl
);
1378 mbTrackingSelect
= false;
1381 if ( bSelectionChanged
)
1383 mbSelectionChanged
= true;
1384 mbTravelSelect
= true;
1385 mnSelectModifier
= rTEvt
.GetMouseEvent().GetModifier();
1387 mbTravelSelect
= false;
1393 mnCurrentPos
= nSelect
;
1394 if ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1396 ImplHideFocusRect();
1400 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
, 0 );
1401 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1402 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1403 maFocusRect
.SetSize( aSz
);
1404 ImplShowFocusRect();
1411 // -----------------------------------------------------------------------
1413 void ImplListBoxWindow::KeyInput( const KeyEvent
& rKEvt
)
1415 if( !ProcessKeyInput( rKEvt
) )
1416 Control::KeyInput( rKEvt
);
1419 // -----------------------------------------------------------------------
1421 sal_Bool
ImplListBoxWindow::ProcessKeyInput( const KeyEvent
& rKEvt
)
1423 // entry to be selected
1424 sal_uInt16 nSelect
= LISTBOX_ENTRY_NOTFOUND
;
1425 LB_EVENT_TYPE eLET
= LET_KEYMOVE
;
1427 KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1429 sal_Bool bShift
= aKeyCode
.IsShift();
1430 sal_Bool bCtrl
= aKeyCode
.IsMod1() || aKeyCode
.IsMod3();
1431 sal_Bool bMod2
= aKeyCode
.IsMod2();
1432 sal_Bool bDone
= sal_False
;
1434 switch( aKeyCode
.GetCode() )
1440 if ( GetTopEntry() )
1441 SetTopEntry( GetTopEntry()-1 );
1445 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1447 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1449 else if ( mnCurrentPos
)
1451 // search first selectable above the current position
1452 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
- 1, false );
1455 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
< mnTop
) )
1456 SetTopEntry( mnTop
-1 );
1460 maQuickSelectionEngine
.Reset();
1468 SetTopEntry( GetTopEntry()+1 );
1472 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1474 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1476 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1478 // search first selectable below the current position
1479 nSelect
= mpEntryList
->FindFirstSelectable( mnCurrentPos
+ 1, true );
1482 if( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
) && ( nSelect
>= GetLastVisibleEntry() ) )
1483 SetTopEntry( mnTop
+1 );
1487 maQuickSelectionEngine
.Reset();
1495 sal_uInt16 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1496 SetTopEntry( ( mnTop
> nCurVis
) ?
1497 (mnTop
-nCurVis
) : 0 );
1499 else if ( !bCtrl
&& !bMod2
)
1501 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1503 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1505 else if ( mnCurrentPos
)
1507 if( mnCurrentPos
== mnTop
)
1509 sal_uInt16 nCurVis
= GetLastVisibleEntry() - mnTop
+1;
1510 SetTopEntry( ( mnTop
> nCurVis
) ? ( mnTop
-nCurVis
+1 ) : 0 );
1513 // find first selectable starting from mnTop looking foreward
1514 nSelect
= mpEntryList
->FindFirstSelectable( mnTop
, true );
1518 maQuickSelectionEngine
.Reset();
1526 SetTopEntry( GetLastVisibleEntry() );
1528 else if ( !bCtrl
&& !bMod2
)
1530 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1532 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1534 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1536 sal_uInt16 nCount
= mpEntryList
->GetEntryCount();
1537 sal_uInt16 nCurVis
= GetLastVisibleEntry() - mnTop
;
1538 sal_uInt16 nTmp
= std::min( nCurVis
, nCount
);
1540 if( mnCurrentPos
== nTmp
&& mnCurrentPos
!= nCount
- 1 )
1542 long nTmp2
= std::min( (long)(nCount
-nCurVis
), (long)((long)mnTop
+(long)nCurVis
-1) );
1543 nTmp2
= std::max( (long)0 , nTmp2
);
1544 nTmp
= (sal_uInt16
)(nTmp2
+(nCurVis
-1) );
1545 SetTopEntry( (sal_uInt16
)nTmp2
);
1547 // find first selectable starting from nTmp looking backwards
1548 nSelect
= mpEntryList
->FindFirstSelectable( nTmp
, false );
1552 maQuickSelectionEngine
.Reset();
1562 else if ( !bCtrl
&& !bMod2
)
1566 nSelect
= mpEntryList
->FindFirstSelectable( mpEntryList
->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND
, true );
1573 maQuickSelectionEngine
.Reset();
1581 SetTopEntry( 0xFFFF );
1583 else if ( !bCtrl
&& !bMod2
)
1585 if( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
)
1587 nSelect
= mpEntryList
->FindFirstSelectable( 0, true );
1589 else if ( (mnCurrentPos
+1) < mpEntryList
->GetEntryCount() )
1591 sal_uInt16 nCount
= mpEntryList
->GetEntryCount();
1592 nSelect
= mpEntryList
->FindFirstSelectable( nCount
- 1, false );
1593 sal_uInt16 nCurVis
= GetLastVisibleEntry() - mnTop
+ 1;
1594 if( nCount
> nCurVis
)
1595 SetTopEntry( nCount
- nCurVis
);
1599 maQuickSelectionEngine
.Reset();
1605 if ( !bCtrl
&& !bMod2
)
1607 ScrollHorz( -HORZ_SCROLL
);
1610 maQuickSelectionEngine
.Reset();
1616 if ( !bCtrl
&& !bMod2
)
1618 ScrollHorz( HORZ_SCROLL
);
1621 maQuickSelectionEngine
.Reset();
1627 if ( !bMod2
&& !IsReadOnly() )
1629 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1631 bDone
= sal_False
; // do not catch RETURN
1633 maQuickSelectionEngine
.Reset();
1639 if ( !bMod2
&& !IsReadOnly() )
1641 if( mbMulti
&& ( !mbSimpleMode
|| ( mbSimpleMode
&& bCtrl
&& !bShift
) || mbStackMode
) )
1643 nSelect
= mnCurrentPos
;
1644 eLET
= LET_KEYSPACE
;
1648 maQuickSelectionEngine
.Reset();
1654 if( bCtrl
&& mbMulti
)
1657 sal_Bool bUpdates
= IsUpdateMode();
1658 SetUpdateMode( sal_False
);
1660 sal_uInt16 nEntryCount
= mpEntryList
->GetEntryCount();
1661 for( sal_uInt16 i
= 0; i
< nEntryCount
; i
++ )
1662 SelectEntry( i
, sal_True
);
1664 // restore update mode
1665 SetUpdateMode( bUpdates
);
1668 maQuickSelectionEngine
.Reset();
1674 // fall through intentional
1677 if ( !IsReadOnly() )
1679 bDone
= maQuickSelectionEngine
.HandleKeyEvent( rKEvt
);
1685 if ( ( nSelect
!= LISTBOX_ENTRY_NOTFOUND
)
1686 && ( ( !mpEntryList
->IsEntryPosSelected( nSelect
) )
1687 || ( eLET
== LET_KEYSPACE
)
1691 DBG_ASSERT( !mpEntryList
->IsEntryPosSelected( nSelect
) || mbMulti
, "ImplListBox: Selecting same Entry" );
1692 if( nSelect
>= mpEntryList
->GetEntryCount() )
1693 nSelect
= mpEntryList
->GetEntryCount()-1;
1694 mnCurrentPos
= nSelect
;
1695 if ( SelectEntries( nSelect
, eLET
, bShift
, bCtrl
) )
1697 mbTravelSelect
= true;
1698 mnSelectModifier
= rKEvt
.GetKeyCode().GetModifier();
1700 mbTravelSelect
= false;
1707 // -----------------------------------------------------------------------
1710 static ::vcl::StringEntryIdentifier
lcl_getEntry( const ImplEntryList
& _rList
, sal_uInt16 _nPos
, String
& _out_entryText
)
1712 OSL_PRECOND( ( _nPos
!= LISTBOX_ENTRY_NOTFOUND
), "lcl_getEntry: invalid position!" );
1713 sal_uInt16
nEntryCount( _rList
.GetEntryCount() );
1714 if ( _nPos
>= nEntryCount
)
1716 _out_entryText
= _rList
.GetEntryText( _nPos
);
1718 // ::vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1720 return reinterpret_cast< ::vcl::StringEntryIdentifier
>( _nPos
+ 1 );
1723 static sal_uInt16
lcl_getEntryPos( ::vcl::StringEntryIdentifier _entry
)
1725 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1726 return static_cast< sal_uInt16
>( reinterpret_cast< sal_Int64
>( _entry
) ) - 1;
1730 // -----------------------------------------------------------------------
1731 ::vcl::StringEntryIdentifier
ImplListBoxWindow::CurrentEntry( String
& _out_entryText
) const
1733 return lcl_getEntry( *GetEntryList(), ( mnCurrentPos
== LISTBOX_ENTRY_NOTFOUND
) ? 0 : mnCurrentPos
+ 1, _out_entryText
);
1736 // -----------------------------------------------------------------------
1737 ::vcl::StringEntryIdentifier
ImplListBoxWindow::NextEntry( ::vcl::StringEntryIdentifier _currentEntry
, String
& _out_entryText
) const
1739 sal_uInt16 nNextPos
= lcl_getEntryPos( _currentEntry
) + 1;
1740 return lcl_getEntry( *GetEntryList(), nNextPos
, _out_entryText
);
1743 // -----------------------------------------------------------------------
1744 void ImplListBoxWindow::SelectEntry( ::vcl::StringEntryIdentifier _entry
)
1746 sal_uInt16 nSelect
= lcl_getEntryPos( _entry
);
1747 if ( mpEntryList
->IsEntryPosSelected( nSelect
) )
1749 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1750 // to select the given entry by typing its starting letters. No need to act.
1755 OSL_ENSURE( nSelect
< mpEntryList
->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1756 if( nSelect
>= mpEntryList
->GetEntryCount() )
1757 nSelect
= mpEntryList
->GetEntryCount()-1;
1760 ShowProminentEntry( nSelect
);
1763 mnCurrentPos
= nSelect
;
1764 if ( SelectEntries( nSelect
, LET_KEYMOVE
, sal_False
, sal_False
) )
1766 mbTravelSelect
= true;
1767 mnSelectModifier
= 0;
1769 mbTravelSelect
= false;
1773 // -----------------------------------------------------------------------
1775 void ImplListBoxWindow::ImplPaint( sal_uInt16 nPos
, sal_Bool bErase
, bool bLayout
)
1777 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
1779 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nPos
);
1783 long nWidth
= GetOutputSizePixel().Width();
1784 long nY
= mpEntryList
->GetAddedHeight( nPos
, mnTop
);
1785 Rectangle
aRect( Point( 0, nY
), Size( nWidth
, pEntry
->mnHeight
) );
1789 if( mpEntryList
->IsEntryPosSelected( nPos
) )
1791 SetTextColor( !IsEnabled() ? rStyleSettings
.GetDisableColor() : rStyleSettings
.GetHighlightTextColor() );
1792 SetFillColor( rStyleSettings
.GetHighlightColor() );
1793 SetTextFillColor( rStyleSettings
.GetHighlightColor() );
1798 ImplInitSettings( sal_False
, sal_True
, sal_False
);
1800 SetTextColor( rStyleSettings
.GetDisableColor() );
1807 if ( IsUserDrawEnabled() )
1809 mbInUserDraw
= true;
1810 mnUserDrawEntry
= nPos
;
1811 aRect
.Left() -= mnLeft
;
1812 if ( nPos
< GetEntryList()->GetMRUCount() )
1813 nPos
= GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos
) );
1814 nPos
= sal::static_int_cast
<sal_uInt16
>(nPos
- GetEntryList()->GetMRUCount());
1815 sal_uInt16 nCurr
= mnCurrentPos
;
1816 if ( mnCurrentPos
< GetEntryList()->GetMRUCount() )
1817 nCurr
= GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nCurr
) );
1818 nCurr
= sal::static_int_cast
<sal_uInt16
>( nCurr
- GetEntryList()->GetMRUCount());
1820 UserDrawEvent
aUDEvt( this, aRect
, nPos
, nCurr
);
1821 maUserDrawHdl
.Call( &aUDEvt
);
1822 mbInUserDraw
= false;
1826 DrawEntry( nPos
, sal_True
, sal_True
, sal_False
, bLayout
);
1830 // -----------------------------------------------------------------------
1832 void ImplListBoxWindow::DrawEntry( sal_uInt16 nPos
, sal_Bool bDrawImage
, sal_Bool bDrawText
, sal_Bool bDrawTextAtImagePos
, bool bLayout
)
1834 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nPos
);
1838 // when changing this function don't forget to adjust ImplWin::DrawEntry()
1841 nPos
= mnUserDrawEntry
; // real entry, not the matching entry from MRU
1843 long nY
= mpEntryList
->GetAddedHeight( nPos
, mnTop
);
1846 if( bDrawImage
&& mpEntryList
->HasImages() && !bLayout
)
1848 Image aImage
= mpEntryList
->GetEntryImage( nPos
);
1851 aImgSz
= aImage
.GetSizePixel();
1852 Point
aPtImg( mnBorder
- mnLeft
, nY
+ ( ( pEntry
->mnHeight
- aImgSz
.Height() ) / 2 ) );
1854 // pb: #106948# explicit mirroring for calc
1857 aPtImg
.X() = mnMaxWidth
+ mnBorder
- aImgSz
.Width() - mnLeft
;
1861 DrawImage( aPtImg
, aImage
);
1865 aImgSz
.Width() = CalcZoom( aImgSz
.Width() );
1866 aImgSz
.Height() = CalcZoom( aImgSz
.Height() );
1867 DrawImage( aPtImg
, aImgSz
, aImage
);
1870 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1871 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
1873 if(nEdgeBlendingPercent
&& aImgSz
.Width() && aImgSz
.Height())
1875 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
1876 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
1877 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
1878 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
1880 if(!aBlendFrame
.IsEmpty())
1882 DrawBitmapEx(aPtImg
, aBlendFrame
);
1890 MetricVector
* pVector
= bLayout
? &mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
: NULL
;
1891 OUString
* pDisplayText
= bLayout
? &mpControlData
->mpLayoutData
->m_aDisplayText
: NULL
;
1892 XubString
aStr( mpEntryList
->GetEntryText( nPos
) );
1895 long nMaxWidth
= std::max( static_cast< long >( mnMaxWidth
),
1896 GetOutputSizePixel().Width() - 2*mnBorder
);
1897 // a multiline entry should only be as wide a the window
1898 if( (pEntry
->mnFlags
& LISTBOX_ENTRY_FLAG_MULTILINE
) )
1899 nMaxWidth
= GetOutputSizePixel().Width() - 2*mnBorder
;
1901 Rectangle
aTextRect( Point( mnBorder
- mnLeft
, nY
),
1902 Size( nMaxWidth
, pEntry
->mnHeight
) );
1904 if( !bDrawTextAtImagePos
&& ( mpEntryList
->HasEntryImage(nPos
) || IsUserDrawEnabled() ) )
1906 long nImageWidth
= std::max( mnMaxImgWidth
, maUserItemSize
.Width() );
1907 aTextRect
.Left() += nImageWidth
+ IMG_TXT_DISTANCE
;
1911 mpControlData
->mpLayoutData
->m_aLineIndices
.push_back( mpControlData
->mpLayoutData
->m_aDisplayText
.getLength() );
1913 // pb: #106948# explicit mirroring for calc
1917 aTextRect
.Left() = nMaxWidth
+ mnBorder
- GetTextWidth( aStr
) - mnLeft
;
1918 if ( aImgSz
.Width() > 0 )
1919 aTextRect
.Left() -= ( aImgSz
.Width() + IMG_TXT_DISTANCE
);
1922 sal_uInt16 nDrawStyle
= ImplGetTextStyle();
1923 if( (pEntry
->mnFlags
& LISTBOX_ENTRY_FLAG_MULTILINE
) )
1924 nDrawStyle
|= MULTILINE_ENTRY_DRAW_FLAGS
;
1925 if( (pEntry
->mnFlags
& LISTBOX_ENTRY_FLAG_DRAW_DISABLED
) )
1926 nDrawStyle
|= TEXT_DRAW_DISABLE
;
1928 DrawText( aTextRect
, aStr
, nDrawStyle
, pVector
, pDisplayText
);
1934 if ( ( mnSeparatorPos
!= LISTBOX_ENTRY_NOTFOUND
) &&
1935 ( ( nPos
== mnSeparatorPos
) || ( nPos
== mnSeparatorPos
+1 ) ) )
1937 Color
aOldLineColor( GetLineColor() );
1938 SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY
) ? COL_LIGHTGRAY
: COL_GRAY
);
1939 Point
aStartPos( 0, nY
);
1940 if ( nPos
== mnSeparatorPos
)
1941 aStartPos
.Y() += pEntry
->mnHeight
-1;
1942 Point
aEndPos( aStartPos
);
1943 aEndPos
.X() = GetOutputSizePixel().Width();
1944 DrawLine( aStartPos
, aEndPos
);
1945 SetLineColor( aOldLineColor
);
1950 // -----------------------------------------------------------------------
1952 void ImplListBoxWindow::FillLayoutData() const
1954 mpControlData
->mpLayoutData
= new vcl::ControlLayoutData();
1955 const_cast<ImplListBoxWindow
*>(this)->
1956 ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
1959 // -----------------------------------------------------------------------
1961 void ImplListBoxWindow::ImplDoPaint( const Rectangle
& rRect
, bool bLayout
)
1963 sal_uInt16 nCount
= mpEntryList
->GetEntryCount();
1965 sal_Bool bShowFocusRect
= mbHasFocusRect
;
1966 if ( mbHasFocusRect
&& ! bLayout
)
1967 ImplHideFocusRect();
1969 long nY
= 0; // + mnBorder;
1970 long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1972 for( sal_uInt16 i
= (sal_uInt16
)mnTop
; i
< nCount
&& nY
< nHeight
+ mnMaxHeight
; i
++ )
1974 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( i
);
1975 if( nY
+ pEntry
->mnHeight
>= rRect
.Top() &&
1976 nY
<= rRect
.Bottom() + mnMaxHeight
)
1978 ImplPaint( i
, sal_False
, bLayout
);
1980 nY
+= pEntry
->mnHeight
;
1983 long nHeightDiff
= mpEntryList
->GetAddedHeight( mnCurrentPos
, mnTop
, 0 );
1984 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
1985 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
1986 maFocusRect
.SetSize( aSz
);
1987 if( HasFocus() && bShowFocusRect
&& !bLayout
)
1988 ImplShowFocusRect();
1991 // -----------------------------------------------------------------------
1993 void ImplListBoxWindow::Paint( const Rectangle
& rRect
)
1995 ImplDoPaint( rRect
);
1998 // -----------------------------------------------------------------------
2000 sal_uInt16
ImplListBoxWindow::GetDisplayLineCount() const
2002 // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2004 sal_uInt16 nCount
= mpEntryList
->GetEntryCount();
2005 long nHeight
= GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
2006 sal_uInt16 nEntries
= static_cast< sal_uInt16
>( ( nHeight
+ mnMaxHeight
- 1 ) / mnMaxHeight
);
2007 if( nEntries
> nCount
-mnTop
)
2008 nEntries
= nCount
-mnTop
;
2013 // -----------------------------------------------------------------------
2015 void ImplListBoxWindow::Resize()
2019 sal_Bool bShowFocusRect
= mbHasFocusRect
;
2020 if ( bShowFocusRect
)
2021 ImplHideFocusRect();
2023 if( mnCurrentPos
!= LISTBOX_ENTRY_NOTFOUND
)
2025 Size
aSz( GetOutputSizePixel().Width(), mpEntryList
->GetEntryHeight( mnCurrentPos
) );
2026 maFocusRect
.SetSize( aSz
);
2029 if ( bShowFocusRect
)
2030 ImplShowFocusRect();
2032 ImplClearLayoutData();
2035 // -----------------------------------------------------------------------
2037 void ImplListBoxWindow::GetFocus()
2039 sal_uInt16 nPos
= mnCurrentPos
;
2040 if ( nPos
== LISTBOX_ENTRY_NOTFOUND
)
2042 long nHeightDiff
= mpEntryList
->GetAddedHeight( nPos
, mnTop
, 0 );
2043 maFocusRect
.SetPos( Point( 0, nHeightDiff
) );
2044 Size
aSz( maFocusRect
.GetWidth(), mpEntryList
->GetEntryHeight( nPos
) );
2045 maFocusRect
.SetSize( aSz
);
2046 ImplShowFocusRect();
2047 Control::GetFocus();
2050 // -----------------------------------------------------------------------
2052 void ImplListBoxWindow::LoseFocus()
2054 ImplHideFocusRect();
2055 Control::LoseFocus();
2058 // -----------------------------------------------------------------------
2060 void ImplListBoxWindow::SetTopEntry( sal_uInt16 nTop
)
2062 if( mpEntryList
->GetEntryCount() == 0 )
2065 long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
2067 sal_uInt16 nLastEntry
= mpEntryList
->GetEntryCount()-1;
2068 if( nTop
> nLastEntry
)
2070 const ImplEntryType
* pLast
= mpEntryList
->GetEntryPtr( nLastEntry
);
2071 while( nTop
> 0 && mpEntryList
->GetAddedHeight( nLastEntry
, nTop
-1 ) + pLast
->mnHeight
<= nWHeight
)
2074 if ( nTop
!= mnTop
)
2076 ImplClearLayoutData();
2077 long nDiff
= mpEntryList
->GetAddedHeight( mnTop
, nTop
, 0 );
2079 ImplHideFocusRect();
2084 ImplShowFocusRect();
2085 maScrollHdl
.Call( this );
2089 // -----------------------------------------------------------------------
2091 void ImplListBoxWindow::ShowProminentEntry( sal_uInt16 nEntryPos
)
2093 if( meProminentType
== PROMINENT_MIDDLE
)
2095 sal_uInt16 nPos
= nEntryPos
;
2096 long nWHeight
= PixelToLogic( GetSizePixel() ).Height();
2097 while( nEntryPos
> 0 && mpEntryList
->GetAddedHeight( nPos
+1, nEntryPos
) < nWHeight
/2 )
2100 SetTopEntry( nEntryPos
);
2103 // -----------------------------------------------------------------------
2105 void ImplListBoxWindow::SetLeftIndent( long n
)
2107 ScrollHorz( n
- mnLeft
);
2110 // -----------------------------------------------------------------------
2112 void ImplListBoxWindow::ScrollHorz( long n
)
2117 long nWidth
= GetOutputSizePixel().Width();
2118 if( ( mnMaxWidth
- mnLeft
+ n
) > nWidth
)
2126 nDiff
= - ( ( mnLeft
> nAbs
) ? nAbs
: mnLeft
);
2132 ImplClearLayoutData();
2133 mnLeft
= sal::static_int_cast
<sal_uInt16
>(mnLeft
+ nDiff
);
2135 ImplHideFocusRect();
2136 Scroll( -nDiff
, 0 );
2139 ImplShowFocusRect();
2140 maScrollHdl
.Call( this );
2144 // -----------------------------------------------------------------------
2146 Size
ImplListBoxWindow::CalcSize( sal_uInt16 nMaxLines
) const
2148 // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2151 // sal_uInt16 nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
2152 aSz
.Height() = nMaxLines
* mnMaxHeight
;
2153 aSz
.Width() = mnMaxWidth
+ 2*mnBorder
;
2157 // -----------------------------------------------------------------------
2159 Rectangle
ImplListBoxWindow::GetBoundingRectangle( sal_uInt16 nItem
) const
2161 const ImplEntryType
* pEntry
= mpEntryList
->GetEntryPtr( nItem
);
2162 Size
aSz( GetSizePixel().Width(), pEntry
? pEntry
->mnHeight
: GetEntryHeight() );
2163 long nY
= mpEntryList
->GetAddedHeight( nItem
, GetTopEntry() ) - mpEntryList
->GetAddedHeight( GetTopEntry() );
2164 Rectangle
aRect( Point( 0, nY
), aSz
);
2169 // -----------------------------------------------------------------------
2171 void ImplListBoxWindow::StateChanged( StateChangedType nType
)
2173 Control::StateChanged( nType
);
2175 if ( nType
== STATE_CHANGE_ZOOM
)
2177 ImplInitSettings( sal_True
, sal_False
, sal_False
);
2181 else if ( nType
== STATE_CHANGE_UPDATEMODE
)
2183 if ( IsUpdateMode() && IsReallyVisible() )
2186 else if ( nType
== STATE_CHANGE_CONTROLFONT
)
2188 ImplInitSettings( sal_True
, sal_False
, sal_False
);
2192 else if ( nType
== STATE_CHANGE_CONTROLFOREGROUND
)
2194 ImplInitSettings( sal_False
, sal_True
, sal_False
);
2197 else if ( nType
== STATE_CHANGE_CONTROLBACKGROUND
)
2199 ImplInitSettings( sal_False
, sal_False
, sal_True
);
2202 ImplClearLayoutData();
2205 // -----------------------------------------------------------------------
2207 void ImplListBoxWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
2209 Control::DataChanged( rDCEvt
);
2211 if ( (rDCEvt
.GetType() == DATACHANGED_FONTS
) ||
2212 (rDCEvt
.GetType() == DATACHANGED_FONTSUBSTITUTION
) ||
2213 ((rDCEvt
.GetType() == DATACHANGED_SETTINGS
) &&
2214 (rDCEvt
.GetFlags() & SETTINGS_STYLE
)) )
2216 ImplClearLayoutData();
2217 ImplInitSettings( sal_True
, sal_True
, sal_True
);
2223 // -----------------------------------------------------------------------
2225 sal_uInt16
ImplListBoxWindow::ImplGetTextStyle() const
2227 sal_uInt16 nTextStyle
= TEXT_DRAW_VCENTER
;
2229 if ( mpEntryList
->HasImages() )
2230 nTextStyle
|= TEXT_DRAW_LEFT
;
2231 else if ( mbCenter
)
2232 nTextStyle
|= TEXT_DRAW_CENTER
;
2234 nTextStyle
|= TEXT_DRAW_RIGHT
;
2236 nTextStyle
|= TEXT_DRAW_LEFT
;
2241 // =======================================================================
2243 ImplListBox::ImplListBox( Window
* pParent
, WinBits nWinStyle
) :
2244 Control( pParent
, nWinStyle
),
2245 maLBWindow( this, nWinStyle
&(~WB_BORDER
) )
2247 // for native widget rendering we must be able to detect this window type
2248 SetType( WINDOW_LISTBOXWINDOW
);
2250 mpVScrollBar
= new ScrollBar( this, WB_VSCROLL
| WB_DRAG
);
2251 mpHScrollBar
= new ScrollBar( this, WB_HSCROLL
| WB_DRAG
);
2252 mpScrollBarBox
= new ScrollBarBox( this );
2254 Link
aLink( LINK( this, ImplListBox
, ScrollBarHdl
) );
2255 mpVScrollBar
->SetScrollHdl( aLink
);
2256 mpHScrollBar
->SetScrollHdl( aLink
);
2260 mbAutoHScroll
= ( nWinStyle
& WB_AUTOHSCROLL
);
2261 mbEdgeBlending
= false;
2263 maLBWindow
.SetScrollHdl( LINK( this, ImplListBox
, LBWindowScrolled
) );
2264 maLBWindow
.SetMRUChangedHdl( LINK( this, ImplListBox
, MRUChanged
) );
2265 maLBWindow
.SetEdgeBlending(GetEdgeBlending());
2269 // -----------------------------------------------------------------------
2271 ImplListBox::~ImplListBox()
2273 delete mpHScrollBar
;
2274 delete mpVScrollBar
;
2275 delete mpScrollBarBox
;
2278 // -----------------------------------------------------------------------
2280 void ImplListBox::Clear()
2283 if ( GetEntryList()->GetMRUCount() )
2285 maLBWindow
.GetEntryList()->SetMRUCount( 0 );
2286 maLBWindow
.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND
);
2288 mpVScrollBar
->SetThumbPos( 0 );
2289 mpHScrollBar
->SetThumbPos( 0 );
2290 StateChanged( STATE_CHANGE_DATA
);
2293 // -----------------------------------------------------------------------
2295 sal_uInt16
ImplListBox::InsertEntry( sal_uInt16 nPos
, const OUString
& rStr
)
2297 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
);
2298 sal_uInt16 nNewPos
= maLBWindow
.InsertEntry( nPos
, pNewEntry
);
2299 StateChanged( STATE_CHANGE_DATA
);
2303 // -----------------------------------------------------------------------
2305 sal_uInt16
ImplListBox::InsertEntry( sal_uInt16 nPos
, const Image
& rImage
)
2307 ImplEntryType
* pNewEntry
= new ImplEntryType( rImage
);
2308 sal_uInt16 nNewPos
= maLBWindow
.InsertEntry( nPos
, pNewEntry
);
2309 StateChanged( STATE_CHANGE_DATA
);
2313 // -----------------------------------------------------------------------
2315 sal_uInt16
ImplListBox::InsertEntry( sal_uInt16 nPos
, const OUString
& rStr
, const Image
& rImage
)
2317 ImplEntryType
* pNewEntry
= new ImplEntryType( rStr
, rImage
);
2318 sal_uInt16 nNewPos
= maLBWindow
.InsertEntry( nPos
, pNewEntry
);
2319 StateChanged( STATE_CHANGE_DATA
);
2323 // -----------------------------------------------------------------------
2325 void ImplListBox::RemoveEntry( sal_uInt16 nPos
)
2327 maLBWindow
.RemoveEntry( nPos
);
2328 StateChanged( STATE_CHANGE_DATA
);
2331 // -----------------------------------------------------------------------
2333 void ImplListBox::SetEntryFlags( sal_uInt16 nPos
, long nFlags
)
2335 maLBWindow
.SetEntryFlags( nPos
, nFlags
);
2338 // -----------------------------------------------------------------------
2340 void ImplListBox::SelectEntry( sal_uInt16 nPos
, sal_Bool bSelect
)
2342 maLBWindow
.SelectEntry( nPos
, bSelect
);
2345 // -----------------------------------------------------------------------
2347 void ImplListBox::SetNoSelection()
2349 maLBWindow
.DeselectAll();
2352 // -----------------------------------------------------------------------
2354 void ImplListBox::GetFocus()
2356 maLBWindow
.GrabFocus();
2359 // -----------------------------------------------------------------------
2361 Window
* ImplListBox::GetPreferredKeyInputWindow()
2366 // -----------------------------------------------------------------------
2368 void ImplListBox::Resize()
2371 ImplResizeControls();
2372 ImplCheckScrollBars();
2376 // -----------------------------------------------------------------------
2378 IMPL_LINK_NOARG(ImplListBox
, MRUChanged
)
2380 StateChanged( STATE_CHANGE_DATA
);
2384 // -----------------------------------------------------------------------
2386 IMPL_LINK_NOARG(ImplListBox
, LBWindowScrolled
)
2388 long nSet
= GetTopEntry();
2389 if( nSet
> mpVScrollBar
->GetRangeMax() )
2390 mpVScrollBar
->SetRangeMax( GetEntryList()->GetEntryCount() );
2391 mpVScrollBar
->SetThumbPos( GetTopEntry() );
2393 mpHScrollBar
->SetThumbPos( GetLeftIndent() );
2395 maScrollHdl
.Call( this );
2400 // -----------------------------------------------------------------------
2402 IMPL_LINK( ImplListBox
, ScrollBarHdl
, ScrollBar
*, pSB
)
2404 sal_uInt16 nPos
= (sal_uInt16
) pSB
->GetThumbPos();
2405 if( pSB
== mpVScrollBar
)
2406 SetTopEntry( nPos
);
2407 else if( pSB
== mpHScrollBar
)
2408 SetLeftIndent( nPos
);
2413 // -----------------------------------------------------------------------
2415 void ImplListBox::ImplCheckScrollBars()
2417 bool bArrange
= false;
2419 Size aOutSz
= GetOutputSizePixel();
2420 sal_uInt16 nEntries
= GetEntryList()->GetEntryCount();
2421 sal_uInt16 nMaxVisEntries
= (sal_uInt16
) (aOutSz
.Height() / GetEntryHeight());
2423 // vertical ScrollBar
2424 if( nEntries
> nMaxVisEntries
)
2430 // check of the scrolled-out region
2431 if( GetEntryList()->GetSelectEntryCount() == 1 &&
2432 GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2433 ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2435 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2445 // horizontal ScrollBar
2448 long nWidth
= (sal_uInt16
) aOutSz
.Width();
2450 nWidth
-= mpVScrollBar
->GetSizePixel().Width();
2452 long nMaxWidth
= GetMaxEntryWidth();
2453 if( nWidth
< nMaxWidth
)
2459 if ( !mbVScroll
) // maybe we do need one now
2461 nMaxVisEntries
= (sal_uInt16
) ( ( aOutSz
.Height() - mpHScrollBar
->GetSizePixel().Height() ) / GetEntryHeight() );
2462 if( nEntries
> nMaxVisEntries
)
2467 // check of the scrolled-out region
2468 if( GetEntryList()->GetSelectEntryCount() == 1 &&
2469 GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND
)
2470 ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2472 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2476 // check of the scrolled-out region
2477 sal_uInt16 nMaxLI
= (sal_uInt16
) (nMaxWidth
- nWidth
);
2478 if ( nMaxLI
< GetLeftIndent() )
2479 SetLeftIndent( nMaxLI
);
2491 ImplResizeControls();
2493 ImplInitScrollBars();
2496 // -----------------------------------------------------------------------
2498 void ImplListBox::ImplInitScrollBars()
2500 Size aOutSz
= maLBWindow
.GetOutputSizePixel();
2504 sal_uInt16 nEntries
= GetEntryList()->GetEntryCount();
2505 sal_uInt16 nVisEntries
= (sal_uInt16
) (aOutSz
.Height() / GetEntryHeight());
2506 mpVScrollBar
->SetRangeMax( nEntries
);
2507 mpVScrollBar
->SetVisibleSize( nVisEntries
);
2508 mpVScrollBar
->SetPageSize( nVisEntries
- 1 );
2513 mpHScrollBar
->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL
);
2514 mpHScrollBar
->SetVisibleSize( (sal_uInt16
)aOutSz
.Width() );
2515 mpHScrollBar
->SetLineSize( HORZ_SCROLL
);
2516 mpHScrollBar
->SetPageSize( aOutSz
.Width() - HORZ_SCROLL
);
2520 // -----------------------------------------------------------------------
2522 void ImplListBox::ImplResizeControls()
2524 // Here we only position the Controls; if the Scrollbars are to be
2525 // visible is already determined in ImplCheckScrollBars
2527 Size aOutSz
= GetOutputSizePixel();
2528 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
2529 nSBWidth
= CalcZoom( nSBWidth
);
2531 Size
aInnerSz( aOutSz
);
2533 aInnerSz
.Width() -= nSBWidth
;
2535 aInnerSz
.Height() -= nSBWidth
;
2537 // pb: #106948# explicit mirroring for calc
2538 // Scrollbar on left or right side?
2539 sal_Bool bMirroring
= maLBWindow
.IsMirroring();
2540 Point
aWinPos( bMirroring
&& mbVScroll
? nSBWidth
: 0, 0 );
2541 maLBWindow
.SetPosSizePixel( aWinPos
, aInnerSz
);
2544 if( mbVScroll
&& mbHScroll
)
2546 Point
aBoxPos( bMirroring
? 0 : aInnerSz
.Width(), aInnerSz
.Height() );
2547 mpScrollBarBox
->SetPosSizePixel( aBoxPos
, Size( nSBWidth
, nSBWidth
) );
2548 mpScrollBarBox
->Show();
2552 mpScrollBarBox
->Hide();
2555 // vertical ScrollBar
2558 // Scrollbar on left or right side?
2559 Point
aVPos( bMirroring
? 0 : aOutSz
.Width() - nSBWidth
, 0 );
2560 mpVScrollBar
->SetPosSizePixel( aVPos
, Size( nSBWidth
, aInnerSz
.Height() ) );
2561 mpVScrollBar
->Show();
2565 mpVScrollBar
->Hide();
2566 // #107254# Don't reset top entry after resize, but check for max top entry
2567 SetTopEntry( GetTopEntry() );
2570 // horizontal ScrollBar
2573 Point
aHPos( ( bMirroring
&& mbVScroll
) ? nSBWidth
: 0, aOutSz
.Height() - nSBWidth
);
2574 mpHScrollBar
->SetPosSizePixel( aHPos
, Size( aInnerSz
.Width(), nSBWidth
) );
2575 mpHScrollBar
->Show();
2579 mpHScrollBar
->Hide();
2584 // -----------------------------------------------------------------------
2586 void ImplListBox::StateChanged( StateChangedType nType
)
2588 if ( nType
== STATE_CHANGE_INITSHOW
)
2590 ImplCheckScrollBars();
2592 else if ( ( nType
== STATE_CHANGE_UPDATEMODE
) || ( nType
== STATE_CHANGE_DATA
) )
2594 sal_Bool bUpdate
= IsUpdateMode();
2595 maLBWindow
.SetUpdateMode( bUpdate
);
2596 if ( bUpdate
&& IsReallyVisible() )
2597 ImplCheckScrollBars();
2599 else if( nType
== STATE_CHANGE_ENABLE
)
2601 mpHScrollBar
->Enable( IsEnabled() );
2602 mpVScrollBar
->Enable( IsEnabled() );
2603 mpScrollBarBox
->Enable( IsEnabled() );
2606 else if ( nType
== STATE_CHANGE_ZOOM
)
2608 maLBWindow
.SetZoom( GetZoom() );
2611 else if ( nType
== STATE_CHANGE_CONTROLFONT
)
2613 maLBWindow
.SetControlFont( GetControlFont() );
2615 else if ( nType
== STATE_CHANGE_CONTROLFOREGROUND
)
2617 maLBWindow
.SetControlForeground( GetControlForeground() );
2619 else if ( nType
== STATE_CHANGE_CONTROLBACKGROUND
)
2621 maLBWindow
.SetControlBackground( GetControlBackground() );
2623 else if( nType
== STATE_CHANGE_MIRRORING
)
2625 maLBWindow
.EnableRTL( IsRTLEnabled() );
2626 mpHScrollBar
->EnableRTL( IsRTLEnabled() );
2627 mpVScrollBar
->EnableRTL( IsRTLEnabled() );
2628 ImplResizeControls();
2631 Control::StateChanged( nType
);
2634 // -----------------------------------------------------------------------
2636 void ImplListBox::DataChanged( const DataChangedEvent
& rDCEvt
)
2638 Control::DataChanged( rDCEvt
);
2641 // -----------------------------------------------------------------------
2643 long ImplListBox::Notify( NotifyEvent
& rNEvt
)
2646 if ( rNEvt
.GetType() == EVENT_COMMAND
)
2648 const CommandEvent
& rCEvt
= *rNEvt
.GetCommandEvent();
2649 if ( rCEvt
.GetCommand() == COMMAND_WHEEL
)
2651 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2652 if( !pData
->GetModifier() && ( pData
->GetMode() == COMMAND_WHEEL_SCROLL
) )
2654 nDone
= HandleScrollCommand( rCEvt
, mpHScrollBar
, mpVScrollBar
);
2659 return nDone
? nDone
: Window::Notify( rNEvt
);
2662 // -----------------------------------------------------------------------
2664 const Wallpaper
& ImplListBox::GetDisplayBackground() const
2666 return maLBWindow
.GetDisplayBackground();
2669 // -----------------------------------------------------------------------
2671 sal_Bool
ImplListBox::HandleWheelAsCursorTravel( const CommandEvent
& rCEvt
)
2673 sal_Bool bDone
= sal_False
;
2674 if ( rCEvt
.GetCommand() == COMMAND_WHEEL
)
2676 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
2677 if( !pData
->GetModifier() && ( pData
->GetMode() == COMMAND_WHEEL_SCROLL
) )
2679 sal_uInt16 nKey
= ( pData
->GetDelta() < 0 ) ? KEY_DOWN
: KEY_UP
;
2680 KeyEvent
aKeyEvent( 0, KeyCode( nKey
) );
2681 bDone
= ProcessKeyInput( aKeyEvent
);
2687 // -----------------------------------------------------------------------
2689 void ImplListBox::SetMRUEntries( const OUString
& rEntries
, sal_Unicode cSep
)
2691 bool bChanges
= GetEntryList()->GetMRUCount() ? true : false;
2693 // Remove old MRU entries
2694 for ( sal_uInt16 n
= GetEntryList()->GetMRUCount();n
; )
2695 maLBWindow
.RemoveEntry( --n
);
2697 sal_uInt16 nMRUCount
= 0;
2698 sal_Int32 nIndex
= 0;
2701 XubString aEntry
= rEntries
.getToken( 0, cSep
, nIndex
);
2702 // Accept only existing entries
2703 if ( GetEntryList()->FindEntry( aEntry
) != LISTBOX_ENTRY_NOTFOUND
)
2705 ImplEntryType
* pNewEntry
= new ImplEntryType( aEntry
);
2706 maLBWindow
.GetEntryList()->InsertEntry( nMRUCount
++, pNewEntry
, sal_False
);
2710 while ( nIndex
>= 0 );
2714 maLBWindow
.GetEntryList()->SetMRUCount( nMRUCount
);
2715 SetSeparatorPos( nMRUCount
? nMRUCount
-1 : 0 );
2716 StateChanged( STATE_CHANGE_DATA
);
2720 // -----------------------------------------------------------------------
2722 OUString
ImplListBox::GetMRUEntries( sal_Unicode cSep
) const
2724 OUStringBuffer aEntries
;
2725 for ( sal_uInt16 n
= 0; n
< GetEntryList()->GetMRUCount(); n
++ )
2727 aEntries
.append(GetEntryList()->GetEntryText( n
));
2728 if( n
< ( GetEntryList()->GetMRUCount() - 1 ) )
2729 aEntries
.append(cSep
);
2731 return aEntries
.makeStringAndClear();
2734 // -----------------------------------------------------------------------
2736 void ImplListBox::SetEdgeBlending(bool bNew
)
2738 if(mbEdgeBlending
!= bNew
)
2740 mbEdgeBlending
= bNew
;
2741 maLBWindow
.SetEdgeBlending(GetEdgeBlending());
2745 // =======================================================================
2747 ImplWin::ImplWin( Window
* pParent
, WinBits nWinStyle
) :
2748 Control ( pParent
, nWinStyle
)
2750 if ( IsNativeControlSupported(CTRL_LISTBOX
, PART_ENTIRE_CONTROL
)
2751 && ! IsNativeControlSupported(CTRL_LISTBOX
, PART_BUTTON_DOWN
) )
2754 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2756 mbInUserDraw
= false;
2757 mbUserDrawEnabled
= false;
2758 mbEdgeBlending
= false;
2759 mnItemPos
= LISTBOX_ENTRY_NOTFOUND
;
2762 // -----------------------------------------------------------------------
2764 void ImplWin::MBDown()
2767 maMBDownHdl
.Call( this );
2770 // -----------------------------------------------------------------------
2772 void ImplWin::MouseButtonDown( const MouseEvent
& )
2780 // -----------------------------------------------------------------------
2782 void ImplWin::FillLayoutData() const
2784 mpControlData
->mpLayoutData
= new vcl::ControlLayoutData();
2785 const_cast<ImplWin
*>(this)->ImplDraw( true );
2788 // -----------------------------------------------------------------------
2790 long ImplWin::PreNotify( NotifyEvent
& rNEvt
)
2793 const MouseEvent
* pMouseEvt
= NULL
;
2795 if( (rNEvt
.GetType() == EVENT_MOUSEMOVE
) && (pMouseEvt
= rNEvt
.GetMouseEvent()) != NULL
)
2797 if( pMouseEvt
->IsEnterWindow() || pMouseEvt
->IsLeaveWindow() )
2799 // trigger redraw as mouse over state has changed
2800 if ( IsNativeControlSupported(CTRL_LISTBOX
, PART_ENTIRE_CONTROL
)
2801 && ! IsNativeControlSupported(CTRL_LISTBOX
, PART_BUTTON_DOWN
) )
2803 GetParent()->GetWindow( WINDOW_BORDER
)->Invalidate( INVALIDATE_NOERASE
);
2804 GetParent()->GetWindow( WINDOW_BORDER
)->Update();
2809 return nDone
? nDone
: Control::PreNotify(rNEvt
);
2812 // -----------------------------------------------------------------------
2814 void ImplWin::ImplDraw( bool bLayout
)
2816 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
2818 sal_Bool bNativeOK
= sal_False
;
2822 ControlState nState
= CTRL_STATE_ENABLED
;
2823 if ( IsNativeControlSupported(CTRL_LISTBOX
, PART_ENTIRE_CONTROL
)
2824 && IsNativeControlSupported(CTRL_LISTBOX
, HAS_BACKGROUND_TEXTURE
) )
2826 // Repaint the (focused) area similarly to
2827 // ImplSmallBorderWindowView::DrawWindow() in
2828 // vcl/source/window/brdwin.cxx
2829 Window
*pWin
= GetParent();
2831 ImplControlValue aControlValue
;
2832 if ( !pWin
->IsEnabled() )
2833 nState
&= ~CTRL_STATE_ENABLED
;
2834 if ( pWin
->HasFocus() )
2835 nState
|= CTRL_STATE_FOCUSED
;
2837 // The listbox is painted over the entire control including the
2838 // border, but ImplWin does not contain the border => correction
2840 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
2841 pWin
->GetBorder( nLeft
, nTop
, nRight
, nBottom
);
2842 Point
aPoint( -nLeft
, -nTop
);
2843 Rectangle
aCtrlRegion( aPoint
- GetPosPixel(), pWin
->GetSizePixel() );
2845 sal_Bool bMouseOver
= sal_False
;
2848 Window
*pChild
= GetParent()->GetWindow( WINDOW_FIRSTCHILD
);
2849 while( pChild
&& (bMouseOver
= pChild
->IsMouseOver()) == sal_False
)
2850 pChild
= pChild
->GetWindow( WINDOW_NEXT
);
2854 nState
|= CTRL_STATE_ROLLOVER
;
2856 // if parent has no border, then nobody has drawn the background
2857 // since no border window exists. so draw it here.
2858 WinBits nParentStyle
= pWin
->GetStyle();
2859 if( ! (nParentStyle
& WB_BORDER
) || (nParentStyle
& WB_NOBORDER
) )
2861 Rectangle
aParentRect( Point( 0, 0 ), pWin
->GetSizePixel() );
2862 pWin
->DrawNativeControl( CTRL_LISTBOX
, PART_ENTIRE_CONTROL
, aParentRect
,
2863 nState
, aControlValue
, OUString() );
2866 bNativeOK
= DrawNativeControl( CTRL_LISTBOX
, PART_ENTIRE_CONTROL
, aCtrlRegion
, nState
,
2867 aControlValue
, OUString() );
2874 SetTextColor( rStyleSettings
.GetHighlightTextColor() );
2875 SetFillColor( rStyleSettings
.GetHighlightColor() );
2876 DrawRect( maFocusRect
);
2881 if( ImplGetSVData()->maNWFData
.mbDDListBoxNoTextArea
)
2883 if( bNativeOK
&& (nState
& CTRL_STATE_ROLLOVER
) )
2884 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
2886 aColor
= rStyleSettings
.GetButtonTextColor();
2890 if( bNativeOK
&& (nState
& CTRL_STATE_ROLLOVER
) )
2891 aColor
= rStyleSettings
.GetFieldRolloverTextColor();
2893 aColor
= rStyleSettings
.GetFieldTextColor();
2895 if( IsControlForeground() )
2896 aColor
= GetControlForeground();
2897 SetTextColor( aColor
);
2899 Erase( maFocusRect
);
2904 SetTextColor( rStyleSettings
.GetDisableColor() );
2906 Erase( maFocusRect
);
2910 if ( IsUserDrawEnabled() )
2912 mbInUserDraw
= true;
2913 UserDrawEvent
aUDEvt( this, maFocusRect
, mnItemPos
, 0 );
2914 maUserDrawHdl
.Call( &aUDEvt
);
2915 mbInUserDraw
= false;
2919 DrawEntry( sal_True
, sal_True
, sal_False
, bLayout
);
2923 // -----------------------------------------------------------------------
2925 void ImplWin::Paint( const Rectangle
& )
2930 // -----------------------------------------------------------------------
2932 void ImplWin::DrawEntry( sal_Bool bDrawImage
, sal_Bool bDrawText
, sal_Bool bDrawTextAtImagePos
, bool bLayout
)
2935 Size aOutSz
= GetOutputSizePixel();
2937 bool bImage
= !!maImage
;
2938 if( bDrawImage
&& bImage
&& !bLayout
)
2940 sal_uInt16 nStyle
= 0;
2941 Size aImgSz
= maImage
.GetSizePixel();
2942 Point
aPtImg( nBorder
, ( ( aOutSz
.Height() - aImgSz
.Height() ) / 2 ) );
2943 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2945 // check for HC mode
2946 Image
*pImage
= &maImage
;
2950 DrawImage( aPtImg
, *pImage
, nStyle
);
2954 aImgSz
.Width() = CalcZoom( aImgSz
.Width() );
2955 aImgSz
.Height() = CalcZoom( aImgSz
.Height() );
2956 DrawImage( aPtImg
, aImgSz
, *pImage
, nStyle
);
2959 const sal_uInt16
nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings
.GetEdgeBlending() : 0);
2961 if(nEdgeBlendingPercent
)
2963 const Color
& rTopLeft(rStyleSettings
.GetEdgeBlendingTopLeftColor());
2964 const Color
& rBottomRight(rStyleSettings
.GetEdgeBlendingBottomRightColor());
2965 const sal_uInt8
nAlpha((nEdgeBlendingPercent
* 255) / 100);
2966 const BitmapEx
aBlendFrame(createBlendFrame(aImgSz
, nAlpha
, rTopLeft
, rBottomRight
));
2968 if(!aBlendFrame
.IsEmpty())
2970 DrawBitmapEx(aPtImg
, aBlendFrame
);
2975 if( bDrawText
&& !maString
.isEmpty() )
2977 sal_uInt16 nTextStyle
= TEXT_DRAW_VCENTER
;
2979 if ( bDrawImage
&& bImage
&& !bLayout
)
2980 nTextStyle
|= TEXT_DRAW_LEFT
;
2981 else if ( GetStyle() & WB_CENTER
)
2982 nTextStyle
|= TEXT_DRAW_CENTER
;
2983 else if ( GetStyle() & WB_RIGHT
)
2984 nTextStyle
|= TEXT_DRAW_RIGHT
;
2986 nTextStyle
|= TEXT_DRAW_LEFT
;
2988 Rectangle
aTextRect( Point( nBorder
, 0 ), Size( aOutSz
.Width()-2*nBorder
, aOutSz
.Height() ) );
2990 if ( !bDrawTextAtImagePos
&& ( bImage
|| IsUserDrawEnabled() ) )
2992 long nMaxWidth
= std::max( maImage
.GetSizePixel().Width(), maUserItemSize
.Width() );
2993 aTextRect
.Left() += nMaxWidth
+ IMG_TXT_DISTANCE
;
2996 MetricVector
* pVector
= bLayout
? &mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
: NULL
;
2997 OUString
* pDisplayText
= bLayout
? &mpControlData
->mpLayoutData
->m_aDisplayText
: NULL
;
2998 DrawText( aTextRect
, maString
, nTextStyle
, pVector
, pDisplayText
);
3001 if( HasFocus() && !bLayout
)
3002 ShowFocus( maFocusRect
);
3005 // -----------------------------------------------------------------------
3007 void ImplWin::Resize()
3010 maFocusRect
.SetSize( GetOutputSizePixel() );
3014 // -----------------------------------------------------------------------
3016 void ImplWin::GetFocus()
3018 ShowFocus( maFocusRect
);
3019 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
3020 IsNativeWidgetEnabled() &&
3021 IsNativeControlSupported( CTRL_LISTBOX
, PART_ENTIRE_CONTROL
) )
3023 Window
* pWin
= GetParent()->GetWindow( WINDOW_BORDER
);
3030 Control::GetFocus();
3033 // -----------------------------------------------------------------------
3035 void ImplWin::LoseFocus()
3038 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
3039 IsNativeWidgetEnabled() &&
3040 IsNativeControlSupported( CTRL_LISTBOX
, PART_ENTIRE_CONTROL
) )
3042 Window
* pWin
= GetParent()->GetWindow( WINDOW_BORDER
);
3049 Control::LoseFocus();
3052 // =======================================================================
3054 ImplBtn::ImplBtn( Window
* pParent
, WinBits nWinStyle
) :
3055 PushButton( pParent
, nWinStyle
),
3056 mbDown ( sal_False
)
3060 // -----------------------------------------------------------------------
3062 void ImplBtn::MBDown()
3065 maMBDownHdl
.Call( this );
3068 // -----------------------------------------------------------------------
3070 void ImplBtn::MouseButtonDown( const MouseEvent
& )
3072 //PushButton::MouseButtonDown( rMEvt );
3080 // =======================================================================
3082 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window
* pParent
) :
3083 FloatingWindow( pParent
, WB_BORDER
| WB_SYSTEMWINDOW
| WB_NOSHADOW
) // no drop shadow for list boxes
3087 mbAutoWidth
= sal_False
;
3089 mnPopupModeStartSaveSelection
= LISTBOX_ENTRY_NOTFOUND
;
3091 EnableSaveBackground();
3093 Window
* pBorderWindow
= ImplGetBorderWindow();
3096 SetAccessibleRole(accessibility::AccessibleRole::PANEL
);
3097 pBorderWindow
->SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
3101 SetAccessibleRole(accessibility::AccessibleRole::WINDOW
);
3106 // -----------------------------------------------------------------------
3108 long ImplListBoxFloatingWindow::PreNotify( NotifyEvent
& rNEvt
)
3110 if( rNEvt
.GetType() == EVENT_LOSEFOCUS
)
3112 if( !GetParent()->HasChildPathFocus( sal_True
) )
3116 return FloatingWindow::PreNotify( rNEvt
);
3119 // -----------------------------------------------------------------------
3121 void ImplListBoxFloatingWindow::setPosSizePixel( long nX
, long nY
, long nWidth
, long nHeight
, sal_uInt16 nFlags
)
3123 FloatingWindow::setPosSizePixel( nX
, nY
, nWidth
, nHeight
, nFlags
);
3125 // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
3126 // after a call to Resize(), we adjust its position if necessary
3127 if ( IsReallyVisible() && ( nFlags
& WINDOW_POSSIZE_HEIGHT
) )
3129 Point aPos
= GetParent()->GetPosPixel();
3130 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
3132 if ( nFlags
& WINDOW_POSSIZE_X
)
3135 if ( nFlags
& WINDOW_POSSIZE_Y
)
3139 SetPosPixel( ImplCalcPos( this, Rectangle( aPos
, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN
, nIndex
) );
3142 // if( !IsReallyVisible() )
3144 // The ImplListBox does not get a Resize() as not visible.
3145 // But the windows must get a Resize(), so that the number of
3146 // visible entries is correct for PgUp/PgDown.
3147 // The number also cannot be calculated by List/Combobox, as for
3148 // this the presence of the vertical Scrollbar has to be known.
3149 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
3150 ((Window
*)mpImplLB
)->Resize();
3151 ((Window
*)mpImplLB
->GetMainWindow())->Resize();
3155 // -----------------------------------------------------------------------
3157 void ImplListBoxFloatingWindow::Resize()
3159 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
3160 FloatingWindow::Resize();
3163 // -----------------------------------------------------------------------
3165 Size
ImplListBoxFloatingWindow::CalcFloatSize()
3167 Size
aFloatSz( maPrefSz
);
3169 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
3170 GetBorder( nLeft
, nTop
, nRight
, nBottom
);
3172 sal_uInt16 nLines
= mpImplLB
->GetEntryList()->GetEntryCount();
3173 if ( mnDDLineCount
&& ( nLines
> mnDDLineCount
) )
3174 nLines
= mnDDLineCount
;
3176 Size aSz
= mpImplLB
->CalcSize( nLines
);
3177 long nMaxHeight
= aSz
.Height() + nTop
+ nBottom
;
3179 if ( mnDDLineCount
)
3180 aFloatSz
.Height() = nMaxHeight
;
3184 // AutoSize first only for width...
3186 aFloatSz
.Width() = aSz
.Width() + nLeft
+ nRight
;
3187 aFloatSz
.Width() += nRight
; // adding some space looks better...
3189 if ( ( aFloatSz
.Height() < nMaxHeight
) || ( mnDDLineCount
&& ( mnDDLineCount
< mpImplLB
->GetEntryList()->GetEntryCount() ) ) )
3191 // then we also need the vertical Scrollbar
3192 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
3193 aFloatSz
.Width() += nSBWidth
;
3196 long nDesktopWidth
= GetDesktopRectPixel().getWidth();
3197 if (aFloatSz
.Width() > nDesktopWidth
)
3198 // Don't exceed the desktop width.
3199 aFloatSz
.Width() = nDesktopWidth
;
3202 if ( aFloatSz
.Height() > nMaxHeight
)
3203 aFloatSz
.Height() = nMaxHeight
;
3205 // Minimal height, in case height is not set to Float height.
3206 // The parent of FloatWin must be DropDown-Combo/Listbox.
3207 Size aParentSz
= GetParent()->GetSizePixel();
3208 if( (!mnDDLineCount
|| !nLines
) && ( aFloatSz
.Height() < aParentSz
.Height() ) )
3209 aFloatSz
.Height() = aParentSz
.Height();
3211 // do not get narrower than the parent...
3212 if( aFloatSz
.Width() < aParentSz
.Width() )
3213 aFloatSz
.Width() = aParentSz
.Width();
3215 // align height to entries...
3216 long nInnerHeight
= aFloatSz
.Height() - nTop
- nBottom
;
3217 long nEntryHeight
= mpImplLB
->GetEntryHeight();
3218 if ( nInnerHeight
% nEntryHeight
)
3220 nInnerHeight
/= nEntryHeight
;
3222 nInnerHeight
*= nEntryHeight
;
3223 aFloatSz
.Height() = nInnerHeight
+ nTop
+ nBottom
;
3226 if (aFloatSz
.Width() < aSz
.Width())
3228 // The max width of list box entries exceeds the window width.
3229 // Account for the scroll bar height.
3230 long nSBWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
3231 aFloatSz
.Height() += nSBWidth
;
3237 // -----------------------------------------------------------------------
3239 void ImplListBoxFloatingWindow::StartFloat( sal_Bool bStartTracking
)
3241 if( !IsInPopupMode() )
3243 Size aFloatSz
= CalcFloatSize();
3245 SetSizePixel( aFloatSz
);
3246 mpImplLB
->SetSizePixel( GetOutputSizePixel() );
3248 sal_uInt16 nPos
= mpImplLB
->GetEntryList()->GetSelectEntryPos( 0 );
3249 mnPopupModeStartSaveSelection
= nPos
;
3251 Size aSz
= GetParent()->GetSizePixel();
3252 Point aPos
= GetParent()->GetPosPixel();
3253 aPos
= GetParent()->GetParent()->OutputToScreenPixel( aPos
);
3254 // FIXME: this ugly hack is for Mac/Aqua
3255 // should be replaced by a real mechanism to place the float rectangle
3256 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
3257 GetParent()->IsNativeWidgetEnabled() )
3259 sal_Int32 nLeft
= 4, nTop
= 4, nRight
= 4, nBottom
= 4;
3262 aSz
.Width() -= nLeft
+ nRight
;
3263 aSz
.Height() -= nTop
+ nBottom
;
3265 Rectangle
aRect( aPos
, aSz
);
3267 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3268 // where the document is unmirrored
3269 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3270 if( GetParent()->GetParent()->ImplIsAntiparallel() )
3271 GetParent()->GetParent()->ImplReMirror( aRect
);
3273 StartPopupMode( aRect
, FLOATWIN_POPUPMODE_DOWN
);
3275 if( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
3276 mpImplLB
->ShowProminentEntry( nPos
);
3278 if( bStartTracking
)
3279 mpImplLB
->GetMainWindow()->EnableMouseMoveSelect( sal_True
);
3281 if ( mpImplLB
->GetMainWindow()->IsGrabFocusAllowed() )
3282 mpImplLB
->GetMainWindow()->GrabFocus();
3284 mpImplLB
->GetMainWindow()->ImplClearLayoutData();
3288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */