xref: /AOO41X/main/vcl/source/control/ilstbox.cxx (revision 5443dcac4da55ae8863c5c80e8907938642a7f1b)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <tools/debug.hxx>
28 
29 #include <vcl/svapp.hxx>
30 #include <vcl/settings.hxx>
31 #include <vcl/event.hxx>
32 #include <vcl/scrbar.hxx>
33 #include <vcl/help.hxx>
34 #include <vcl/lstbox.h>
35 #include <vcl/unohelp.hxx>
36 #include <vcl/i18nhelp.hxx>
37 
38 #include <ilstbox.hxx>
39 #include <controldata.hxx>
40 #include <svdata.hxx>
41 
42 #include <com/sun/star/i18n/XCollator.hpp>
43 #include <com/sun/star/accessibility/XAccessible.hpp>
44 #include <com/sun/star/accessibility/AccessibleRole.hpp>
45 
46 #define MULTILINE_ENTRY_DRAW_FLAGS ( TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_VCENTER )
47 
48 using namespace ::com::sun::star;
49 
50 // =======================================================================
51 
52 void ImplInitFieldSettings( Window* pWin, sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
53 {
54     const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
55 
56     if ( bFont )
57     {
58         Font aFont = rStyleSettings.GetFieldFont();
59         if ( pWin->IsControlFont() )
60             aFont.Merge( pWin->GetControlFont() );
61         pWin->SetZoomedPointFont( aFont );
62     }
63 
64     if ( bFont || bForeground )
65     {
66         Color aTextColor = rStyleSettings.GetFieldTextColor();
67         if ( pWin->IsControlForeground() )
68             aTextColor = pWin->GetControlForeground();
69         pWin->SetTextColor( aTextColor );
70     }
71 
72     if ( bBackground )
73     {
74         if( pWin->IsControlBackground() )
75             pWin->SetBackground( pWin->GetControlBackground() );
76         else
77             pWin->SetBackground( rStyleSettings.GetFieldColor() );
78     }
79 }
80 
81 // -----------------------------------------------------------------------
82 
83 void ImplInitDropDownButton( PushButton* pButton )
84 {
85     if ( pButton->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
86         pButton->SetSymbol( SYMBOL_SPIN_UPDOWN );
87     else
88         pButton->SetSymbol( SYMBOL_SPIN_DOWN );
89 
90     if ( pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
91             && ! pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
92         pButton->SetBackground();
93 }
94 
95 // =======================================================================
96 
97 ImplEntryList::ImplEntryList( Window* pWindow )
98 {
99     mpWindow = pWindow;
100     mnLastSelected = LISTBOX_ENTRY_NOTFOUND;
101     mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND;
102     mnImages = 0;
103     mbCallSelectionChangedHdl = sal_True;
104 
105     mnMRUCount = 0;
106     mnMaxMRUCount = 0;
107 }
108 
109 // -----------------------------------------------------------------------
110 
111 ImplEntryList::~ImplEntryList()
112 {
113     Clear();
114 }
115 
116 // -----------------------------------------------------------------------
117 
118 void ImplEntryList::Clear()
119 {
120     mnImages = 0;
121     for ( sal_uInt16 n = GetEntryCount(); n; )
122     {
123         ImplEntryType* pImplEntry = GetEntry( --n );
124         delete pImplEntry;
125     }
126     List::Clear();
127 }
128 
129 // -----------------------------------------------------------------------
130 
131 void ImplEntryList::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
132 {
133     ImplEntryType* pImplEntry = GetEntry( nPos );
134     if ( pImplEntry &&
135        ( pImplEntry->mbIsSelected != bSelect ) &&
136        ( (pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0  ) )
137     {
138         pImplEntry->mbIsSelected = bSelect;
139         if ( mbCallSelectionChangedHdl )
140             maSelectionChangedHdl.Call( (void*)sal_IntPtr(nPos) );
141     }
142 }
143 
144 // -----------------------------------------------------------------------
145 
146 uno::Reference< i18n::XCollator > ImplGetCollator (lang::Locale &rLocale)
147 {
148     static uno::Reference< i18n::XCollator > xCollator;
149     if ( !xCollator.is() )
150         xCollator = vcl::unohelper::CreateCollator();
151     if( xCollator.is() )
152         xCollator->loadDefaultCollator (rLocale, 0);
153 
154     return xCollator;
155 }
156 
157 sal_uInt16 ImplEntryList::InsertEntry( sal_uInt16 nPos, ImplEntryType* pNewEntry, sal_Bool bSort )
158 {
159     if ( !!pNewEntry->maImage )
160         mnImages++;
161 
162     if ( !bSort || !Count() )
163     {
164         Insert( pNewEntry, nPos );
165     }
166     else
167     {
168         lang::Locale aLocale = Application::GetSettings().GetLocale();
169         uno::Reference< i18n::XCollator > xCollator = ImplGetCollator(aLocale);
170 
171         const XubString& rStr = pNewEntry->maStr;
172         sal_uLong nLow, nHigh, nMid;
173 
174         nHigh = Count();
175 
176         ImplEntryType* pTemp = GetEntry( (sal_uInt16)(nHigh-1) );
177 
178         try
179         {
180             // XXX even though XCollator::compareString returns a sal_Int32 the only
181             // defined values are {-1, 0, 1} which is compatible with StringCompare
182             StringCompare eComp = xCollator.is() ?
183                 (StringCompare)xCollator->compareString (rStr, pTemp->maStr)
184                 : COMPARE_EQUAL;
185 
186             // Schnelles Einfuegen bei sortierten Daten
187             if ( eComp != COMPARE_LESS )
188             {
189                 Insert( pNewEntry, LIST_APPEND );
190             }
191             else
192             {
193                 nLow  = mnMRUCount;
194                 pTemp = (ImplEntryType*)GetEntry( (sal_uInt16)nLow );
195 
196                 eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
197                 if ( eComp != COMPARE_GREATER )
198                 {
199                     Insert( pNewEntry, (sal_uLong)0 );
200                 }
201                 else
202                 {
203                     // Binaeres Suchen
204                     nHigh--;
205                     do
206                     {
207                         nMid = (nLow + nHigh) / 2;
208                         pTemp = (ImplEntryType*)GetObject( nMid );
209 
210                         eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
211 
212                         if ( eComp == COMPARE_LESS )
213                             nHigh = nMid-1;
214                         else
215                         {
216                             if ( eComp == COMPARE_GREATER )
217                                 nLow = nMid + 1;
218                             else
219                                 break;
220                         }
221                     }
222                     while ( nLow <= nHigh );
223 
224                     if ( eComp != COMPARE_LESS )
225                         nMid++;
226 
227                     Insert( pNewEntry, nMid );
228                 }
229             }
230         }
231         catch (uno::RuntimeException& )
232         {
233             // XXX this is arguable, if the exception occured because pNewEntry is
234             // garbage you wouldn't insert it. If the exception occured because the
235             // Collator implementation is garbage then give the user a chance to see
236             // his stuff
237             Insert( pNewEntry, (sal_uLong)0 );
238         }
239 
240     }
241 
242     return (sal_uInt16)GetPos( pNewEntry );
243 }
244 
245 // -----------------------------------------------------------------------
246 
247 void ImplEntryList::RemoveEntry( sal_uInt16 nPos )
248 {
249     ImplEntryType* pImplEntry = (ImplEntryType*)List::Remove( nPos );
250     if ( pImplEntry )
251     {
252         if ( !!pImplEntry->maImage )
253             mnImages--;
254 
255         delete pImplEntry;
256     }
257 }
258 
259 // -----------------------------------------------------------------------
260 
261 sal_uInt16 ImplEntryList::FindEntry( const XubString& rString, sal_Bool bSearchMRUArea ) const
262 {
263     sal_uInt16 nEntries = GetEntryCount();
264     for ( sal_uInt16 n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
265     {
266         ImplEntryType* pImplEntry = GetEntry( n );
267         String aComp( vcl::I18nHelper::filterFormattingChars( pImplEntry->maStr ) );
268         if ( aComp == rString )
269             return n;
270     }
271     return LISTBOX_ENTRY_NOTFOUND;
272 }
273 
274     // -----------------------------------------------------------------------
275 
276 sal_uInt16 ImplEntryList::FindMatchingEntry( const XubString& rStr, sal_uInt16 nStart, sal_Bool bForward, sal_Bool bLazy ) const
277 {
278     sal_uInt16  nPos = LISTBOX_ENTRY_NOTFOUND;
279     sal_uInt16  nEntryCount = GetEntryCount();
280     if ( !bForward )
281         nStart++;   // wird sofort dekrementiert
282 
283     const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
284     for ( sal_uInt16 n = nStart; bForward ? ( n < nEntryCount ) : n; )
285     {
286         if ( !bForward )
287             n--;
288 
289         ImplEntryType* pImplEntry = GetEntry( n );
290         sal_Bool bMatch = bLazy ? rI18nHelper.MatchString( rStr, pImplEntry->maStr ) != 0 : ( rStr.Match( pImplEntry->maStr ) == STRING_MATCH );
291         if ( bMatch )
292         {
293             nPos = n;
294             break;
295         }
296 
297         if ( bForward )
298             n++;
299     }
300 
301     return nPos;
302 }
303 
304 // -----------------------------------------------------------------------
305 
306 sal_uInt16 ImplEntryList::FindEntry( const void* pData ) const
307 {
308     sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;
309     for ( sal_uInt16 n = GetEntryCount(); n; )
310     {
311         ImplEntryType* pImplEntry = GetEntry( --n );
312         if ( pImplEntry->mpUserData == pData )
313         {
314             nPos = n;
315             break;
316         }
317     }
318     return nPos;
319 }
320 
321 // -----------------------------------------------------------------------
322 
323 long ImplEntryList::GetAddedHeight( sal_uInt16 i_nEndIndex, sal_uInt16 i_nBeginIndex, long i_nBeginHeight ) const
324 {
325     long nHeight = i_nBeginHeight;
326     sal_uInt16 nStart = i_nEndIndex > i_nBeginIndex ? i_nBeginIndex : i_nEndIndex;
327     sal_uInt16 nStop  = i_nEndIndex > i_nBeginIndex ? i_nEndIndex : i_nBeginIndex;
328     sal_uInt16 nEntryCount = GetEntryCount();
329     if( nStop != LISTBOX_ENTRY_NOTFOUND && nEntryCount != 0 )
330     {
331         // sanity check
332         if( nStop > nEntryCount-1 )
333             nStop = nEntryCount-1;
334         if( nStart > nEntryCount-1 )
335             nStart = nEntryCount-1;
336 
337         sal_uInt16 nIndex = nStart;
338         while( nIndex != LISTBOX_ENTRY_NOTFOUND && nIndex < nStop )
339         {
340             nHeight += GetEntryPtr( nIndex )-> mnHeight;
341             nIndex++;
342         }
343     }
344     else
345         nHeight = 0;
346     return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
347 }
348 
349 // -----------------------------------------------------------------------
350 
351 long ImplEntryList::GetEntryHeight( sal_uInt16 nPos ) const
352 {
353     ImplEntryType* pImplEntry = GetEntry( nPos );
354     return pImplEntry ? pImplEntry->mnHeight : 0;
355 }
356 
357 // -----------------------------------------------------------------------
358 
359 XubString ImplEntryList::GetEntryText( sal_uInt16 nPos ) const
360 {
361     XubString aEntryText;
362     ImplEntryType* pImplEntry = GetEntry( nPos );
363     if ( pImplEntry )
364         aEntryText = pImplEntry->maStr;
365     return aEntryText;
366 }
367 
368 // -----------------------------------------------------------------------
369 
370 sal_Bool ImplEntryList::HasEntryImage( sal_uInt16 nPos ) const
371 {
372     sal_Bool bImage = sal_False;
373     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
374     if ( pImplEntry )
375         bImage = !!pImplEntry->maImage;
376     return bImage;
377 }
378 
379 // -----------------------------------------------------------------------
380 
381 Image ImplEntryList::GetEntryImage( sal_uInt16 nPos ) const
382 {
383     Image aImage;
384     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
385     if ( pImplEntry )
386         aImage = pImplEntry->maImage;
387     return aImage;
388 }
389 
390 // -----------------------------------------------------------------------
391 
392 void ImplEntryList::SetEntryData( sal_uInt16 nPos, void* pNewData )
393 {
394     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
395     if ( pImplEntry )
396         pImplEntry->mpUserData = pNewData;
397 }
398 
399 // -----------------------------------------------------------------------
400 
401 void* ImplEntryList::GetEntryData( sal_uInt16 nPos ) const
402 {
403     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
404     return pImplEntry ? pImplEntry->mpUserData : NULL;
405 }
406 
407 // -----------------------------------------------------------------------
408 
409 void ImplEntryList::SetEntryFlags( sal_uInt16 nPos, long nFlags )
410 {
411     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
412     if ( pImplEntry )
413         pImplEntry->mnFlags = nFlags;
414 }
415 
416 // -----------------------------------------------------------------------
417 
418 long ImplEntryList::GetEntryFlags( sal_uInt16 nPos ) const
419 {
420     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
421     return pImplEntry ? pImplEntry->mnFlags : 0;
422 }
423 
424 // -----------------------------------------------------------------------
425 
426 sal_uInt16 ImplEntryList::GetSelectEntryCount() const
427 {
428     sal_uInt16 nSelCount = 0;
429     for ( sal_uInt16 n = GetEntryCount(); n; )
430     {
431         ImplEntryType* pImplEntry = GetEntry( --n );
432         if ( pImplEntry->mbIsSelected )
433             nSelCount++;
434     }
435     return nSelCount;
436 }
437 
438 // -----------------------------------------------------------------------
439 
440 XubString ImplEntryList::GetSelectEntry( sal_uInt16 nIndex ) const
441 {
442     return GetEntryText( GetSelectEntryPos( nIndex ) );
443 }
444 
445 // -----------------------------------------------------------------------
446 
447 sal_uInt16 ImplEntryList::GetSelectEntryPos( sal_uInt16 nIndex ) const
448 {
449     sal_uInt16 nSelEntryPos = LISTBOX_ENTRY_NOTFOUND;
450     sal_uInt16 nSel = 0;
451     sal_uInt16 nEntryCount = GetEntryCount();
452 
453     for ( sal_uInt16 n = 0; n < nEntryCount; n++ )
454     {
455         ImplEntryType* pImplEntry = GetEntry( n );
456         if ( pImplEntry->mbIsSelected )
457         {
458             if ( nSel == nIndex )
459             {
460                 nSelEntryPos = n;
461                 break;
462             }
463             nSel++;
464         }
465     }
466 
467     return nSelEntryPos;
468 }
469 
470 // -----------------------------------------------------------------------
471 
472 sal_Bool ImplEntryList::IsEntrySelected( const XubString& rStr ) const
473 {
474     return IsEntryPosSelected( FindEntry( rStr ) );
475 }
476 
477 // -----------------------------------------------------------------------
478 
479 sal_Bool ImplEntryList::IsEntryPosSelected( sal_uInt16 nIndex ) const
480 {
481     ImplEntryType* pImplEntry = GetEntry( nIndex );
482     return pImplEntry ? pImplEntry->mbIsSelected : sal_False;
483 }
484 
485 // -----------------------------------------------------------------------
486 
487 bool ImplEntryList::IsEntrySelectable( sal_uInt16 nPos ) const
488 {
489     ImplEntryType* pImplEntry = GetEntry( nPos );
490     return pImplEntry ? ((pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0) : true;
491 }
492 
493 // -----------------------------------------------------------------------
494 
495 sal_uInt16 ImplEntryList::FindFirstSelectable( sal_uInt16 nPos, bool bForward /* = true */ )
496 {
497     if( IsEntrySelectable( nPos ) )
498         return nPos;
499 
500     if( bForward )
501     {
502         for( nPos = nPos + 1; nPos < GetEntryCount(); nPos++ )
503         {
504             if( IsEntrySelectable( nPos ) )
505                 return nPos;
506         }
507     }
508     else
509     {
510         while( nPos )
511         {
512             nPos--;
513             if( IsEntrySelectable( nPos ) )
514                 return nPos;
515         }
516     }
517 
518     return LISTBOX_ENTRY_NOTFOUND;
519 }
520 
521 // =======================================================================
522 
523 ImplListBoxWindow::ImplListBoxWindow( Window* pParent, WinBits nWinStyle ) :
524     Control( pParent, 0 ),
525     maQuickSelectionEngine( *this )
526 {
527     mpEntryList         = new ImplEntryList( this );
528 
529     mnTop               = 0;
530     mnLeft              = 0;
531     mnBorder            = 1;
532     mnSelectModifier    = 0;
533     mnUserDrawEntry     = LISTBOX_ENTRY_NOTFOUND;
534     mbTrack             = false;
535     mbImgsDiffSz        = false;
536     mbTravelSelect      = false;
537     mbTrackingSelect    = false;
538     mbSelectionChanged  = false;
539     mbMouseMoveSelect   = false;
540     mbMulti             = false;
541     mbStackMode         = false;
542     mbGrabFocus         = false;
543     mbUserDrawEnabled   = false;
544     mbInUserDraw        = false;
545     mbReadOnly          = false;
546     mbHasFocusRect      = false;
547     mbRight             = ( nWinStyle & WB_RIGHT );
548     mbCenter            = ( nWinStyle & WB_CENTER );
549     mbSimpleMode        = ( nWinStyle & WB_SIMPLEMODE );
550     mbSort              = ( nWinStyle & WB_SORT );
551     mbEdgeBlending      = false;
552 
553     // pb: #106948# explicit mirroring for calc
554     mbMirroring         = false;
555 
556     mnCurrentPos            = LISTBOX_ENTRY_NOTFOUND;
557     mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
558     mnSeparatorPos          = LISTBOX_ENTRY_NOTFOUND;
559     meProminentType         = PROMINENT_TOP;
560 
561     SetLineColor();
562     SetTextFillColor();
563     SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
564 
565     ImplInitSettings( sal_True, sal_True, sal_True );
566     ImplCalcMetrics();
567 }
568 
569 // -----------------------------------------------------------------------
570 
571 ImplListBoxWindow::~ImplListBoxWindow()
572 {
573     delete mpEntryList;
574 }
575 
576 // -----------------------------------------------------------------------
577 
578 void ImplListBoxWindow::ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
579 {
580     ImplInitFieldSettings( this, bFont, bForeground, bBackground );
581 }
582 
583 // -----------------------------------------------------------------------
584 
585 void ImplListBoxWindow::ImplCalcMetrics()
586 {
587     mnMaxWidth      = 0;
588     mnMaxTxtWidth   = 0;
589     mnMaxImgWidth   = 0;
590     mnMaxImgTxtWidth= 0;
591     mnMaxImgHeight  = 0;
592 
593     mnTextHeight = (sal_uInt16)GetTextHeight();
594     mnMaxTxtHeight = mnTextHeight + mnBorder;
595     mnMaxHeight = mnMaxTxtHeight;
596 
597     if ( maUserItemSize.Height() > mnMaxHeight )
598         mnMaxHeight = (sal_uInt16) maUserItemSize.Height();
599     if ( maUserItemSize.Width() > mnMaxWidth )
600         mnMaxWidth= (sal_uInt16) maUserItemSize.Width();
601 
602     for ( sal_uInt16 n = mpEntryList->GetEntryCount(); n; )
603     {
604         ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
605         ImplUpdateEntryMetrics( *pEntry );
606     }
607 
608     if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
609     {
610         Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->mnHeight );
611         maFocusRect.SetSize( aSz );
612     }
613 }
614 
615 // -----------------------------------------------------------------------
616 
617 void ImplListBoxWindow::Clear()
618 {
619     mpEntryList->Clear();
620 
621     mnMaxHeight     = mnMaxTxtHeight;
622     mnMaxWidth      = 0;
623     mnMaxTxtWidth   = 0;
624     mnMaxImgTxtWidth= 0;
625     mnMaxImgWidth   = 0;
626     mnMaxImgHeight  = 0;
627     mnTop           = 0;
628     mnLeft          = 0;
629     mbImgsDiffSz    = false;
630     ImplClearLayoutData();
631 
632     mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
633     maQuickSelectionEngine.Reset();
634 
635     Invalidate();
636 }
637 
638 void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
639 {
640     ImplClearLayoutData();
641     maUserItemSize = rSz;
642     ImplCalcMetrics();
643 }
644 
645 // -----------------------------------------------------------------------
646 
647 struct ImplEntryMetrics
648 {
649     sal_Bool    bText;
650     sal_Bool    bImage;
651     long    nEntryWidth;
652     long    nEntryHeight;
653     long    nTextWidth;
654     long    nImgWidth;
655     long    nImgHeight;
656 };
657 
658 // -----------------------------------------------------------------------
659 
660 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
661 {
662     ImplEntryMetrics aMetrics;
663     aMetrics.bText = rEntry.maStr.Len() ? sal_True : sal_False;
664     aMetrics.bImage = !!rEntry.maImage;
665     aMetrics.nEntryWidth = 0;
666     aMetrics.nEntryHeight = 0;
667     aMetrics.nTextWidth = 0;
668     aMetrics.nImgWidth = 0;
669     aMetrics.nImgHeight = 0;
670 
671     if ( aMetrics.bText )
672     {
673         if( (rEntry.mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
674         {
675             // multiline case
676             Size aCurSize( PixelToLogic( GetSizePixel() ) );
677             // set the current size to a large number
678             // GetTextRect should shrink it to the actual size
679             aCurSize.Height() = 0x7fffff;
680             Rectangle aTextRect( Point( 0, 0 ), aCurSize );
681             aTextRect = GetTextRect( aTextRect, rEntry.maStr, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE );
682             aMetrics.nTextWidth = aTextRect.GetWidth();
683             if( aMetrics.nTextWidth > mnMaxTxtWidth )
684                 mnMaxTxtWidth = aMetrics.nTextWidth;
685             aMetrics.nEntryWidth = mnMaxTxtWidth;
686             aMetrics.nEntryHeight = aTextRect.GetHeight() + mnBorder;
687         }
688         else
689         {
690             // normal single line case
691             aMetrics.nTextWidth = (sal_uInt16)GetTextWidth( rEntry.maStr );
692             if( aMetrics.nTextWidth > mnMaxTxtWidth )
693                 mnMaxTxtWidth = aMetrics.nTextWidth;
694             aMetrics.nEntryWidth = mnMaxTxtWidth;
695             aMetrics.nEntryHeight = mnTextHeight + mnBorder;
696         }
697     }
698     if ( aMetrics.bImage )
699     {
700         Size aImgSz = rEntry.maImage.GetSizePixel();
701         aMetrics.nImgWidth  = (sal_uInt16) CalcZoom( aImgSz.Width() );
702         aMetrics.nImgHeight = (sal_uInt16) CalcZoom( aImgSz.Height() );
703 
704         if( mnMaxImgWidth && ( aMetrics.nImgWidth != mnMaxImgWidth ) )
705             mbImgsDiffSz = true;
706         else if ( mnMaxImgHeight && ( aMetrics.nImgHeight != mnMaxImgHeight ) )
707             mbImgsDiffSz = true;
708 
709         if( aMetrics.nImgWidth > mnMaxImgWidth )
710             mnMaxImgWidth = aMetrics.nImgWidth;
711         if( aMetrics.nImgHeight > mnMaxImgHeight )
712             mnMaxImgHeight = aMetrics.nImgHeight;
713 
714         mnMaxImgTxtWidth = Max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
715         aMetrics.nEntryHeight = Max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
716 
717     }
718     if ( IsUserDrawEnabled() || aMetrics.bImage )
719     {
720         aMetrics.nEntryWidth = Max( aMetrics.nImgWidth, maUserItemSize.Width() );
721         if ( aMetrics.bText )
722             aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE;
723         aMetrics.nEntryHeight = Max( Max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
724                                      aMetrics.nEntryHeight );
725     }
726 
727     if ( !aMetrics.bText && !aMetrics.bImage && !IsUserDrawEnabled() )
728     {
729         // entries which have no (aka an empty) text, and no image, and are not user-drawn, should be
730         // shown nonetheless
731         aMetrics.nEntryHeight = mnTextHeight + mnBorder;
732     }
733 
734     if ( aMetrics.nEntryWidth > mnMaxWidth )
735         mnMaxWidth = aMetrics.nEntryWidth;
736     if ( aMetrics.nEntryHeight > mnMaxHeight )
737         mnMaxHeight = aMetrics.nEntryHeight;
738 
739     rEntry.mnHeight = aMetrics.nEntryHeight;
740 }
741 
742 // -----------------------------------------------------------------------
743 
744 void ImplListBoxWindow::ImplCallSelect()
745 {
746     if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
747     {
748         // Insert the selected entry as MRU, if not allready first MRU
749         sal_uInt16 nSelected = GetEntryList()->GetSelectEntryPos( 0 );
750         sal_uInt16 nMRUCount = GetEntryList()->GetMRUCount();
751         String aSelected = GetEntryList()->GetEntryText( nSelected );
752         sal_uInt16 nFirstMatchingEntryPos = GetEntryList()->FindEntry( aSelected, sal_True );
753         if ( nFirstMatchingEntryPos || !nMRUCount )
754         {
755             sal_Bool bSelectNewEntry = sal_False;
756             if ( nFirstMatchingEntryPos < nMRUCount )
757             {
758                 RemoveEntry( nFirstMatchingEntryPos );
759                 nMRUCount--;
760                 if ( nFirstMatchingEntryPos == nSelected )
761                     bSelectNewEntry = sal_True;
762             }
763             else if ( nMRUCount == GetEntryList()->GetMaxMRUCount() )
764             {
765                 RemoveEntry( nMRUCount - 1 );
766                 nMRUCount--;
767             }
768 
769             ImplClearLayoutData();
770 
771             ImplEntryType* pNewEntry = new ImplEntryType( aSelected );
772             pNewEntry->mbIsSelected = bSelectNewEntry;
773             GetEntryList()->InsertEntry( 0, pNewEntry, sal_False );
774             ImplUpdateEntryMetrics( *pNewEntry );
775             GetEntryList()->SetMRUCount( ++nMRUCount );
776             SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
777             maMRUChangedHdl.Call( NULL );
778         }
779     }
780 
781     maSelectHdl.Call( NULL );
782     mbSelectionChanged = false;
783 }
784 
785 // -----------------------------------------------------------------------
786 
787 sal_uInt16 ImplListBoxWindow::InsertEntry( sal_uInt16 nPos, ImplEntryType* pNewEntry )
788 {
789     ImplClearLayoutData();
790     sal_uInt16 nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, mbSort );
791 
792     if( (GetStyle() & WB_WORDBREAK) )
793         pNewEntry->mnFlags |= LISTBOX_ENTRY_FLAG_MULTILINE;
794 
795     ImplUpdateEntryMetrics( *pNewEntry );
796     return nNewPos;
797 }
798 
799 // -----------------------------------------------------------------------
800 
801 void ImplListBoxWindow::RemoveEntry( sal_uInt16 nPos )
802 {
803     ImplClearLayoutData();
804     mpEntryList->RemoveEntry( nPos );
805     if( mnCurrentPos >= mpEntryList->GetEntryCount() )
806         mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
807     ImplCalcMetrics();
808 }
809 
810 // -----------------------------------------------------------------------
811 
812 void ImplListBoxWindow::SetEntryFlags( sal_uInt16 nPos, long nFlags )
813 {
814     mpEntryList->SetEntryFlags( nPos, nFlags );
815     ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( nPos );
816     if( pEntry )
817         ImplUpdateEntryMetrics( *pEntry );
818 }
819 
820 // -----------------------------------------------------------------------
821 
822 void ImplListBoxWindow::ImplShowFocusRect()
823 {
824     if ( mbHasFocusRect )
825         HideFocus();
826     ShowFocus( maFocusRect );
827     mbHasFocusRect = true;
828 }
829 
830 // -----------------------------------------------------------------------
831 
832 void ImplListBoxWindow::ImplHideFocusRect()
833 {
834     if ( mbHasFocusRect )
835     {
836         HideFocus();
837         mbHasFocusRect = false;
838     }
839 }
840 
841 
842 // -----------------------------------------------------------------------
843 
844 sal_uInt16 ImplListBoxWindow::GetEntryPosForPoint( const Point& rPoint ) const
845 {
846     long nY = mnBorder;
847 
848     sal_uInt16 nSelect = mnTop;
849     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nSelect );
850     while( pEntry && rPoint.Y() > pEntry->mnHeight + nY )
851     {
852         nY += pEntry->mnHeight;
853         pEntry = mpEntryList->GetEntryPtr( ++nSelect );
854     }
855     if( pEntry == NULL )
856         nSelect = LISTBOX_ENTRY_NOTFOUND;
857 
858     return nSelect;
859 }
860 
861 // -----------------------------------------------------------------------
862 
863 sal_Bool ImplListBoxWindow::IsVisible( sal_uInt16 i_nEntry ) const
864 {
865     sal_Bool bRet = sal_False;
866 
867     if( i_nEntry >= mnTop )
868     {
869         if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
870             PixelToLogic( GetSizePixel() ).Height() )
871         {
872             bRet = sal_True;
873         }
874     }
875 
876     return bRet;
877 }
878 
879 // -----------------------------------------------------------------------
880 
881 sal_uInt16 ImplListBoxWindow::GetLastVisibleEntry() const
882 {
883     sal_uInt16 nPos = mnTop;
884     long nWindowHeight = GetSizePixel().Height();
885     sal_uInt16 nCount = mpEntryList->GetEntryCount();
886     long nDiff;
887     for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
888         nPos++;
889 
890     if( nDiff > nWindowHeight && nPos > mnTop )
891         nPos--;
892 
893     if( nPos >= nCount )
894         nPos = nCount-1;
895 
896     return nPos;
897 }
898 
899 // -----------------------------------------------------------------------
900 
901 void ImplListBoxWindow::MouseButtonDown( const MouseEvent& rMEvt )
902 {
903     mbMouseMoveSelect = false;  // Nur bis zum ersten MouseButtonDown
904     maQuickSelectionEngine.Reset();
905 
906     if ( !IsReadOnly() )
907     {
908         if( rMEvt.GetClicks() == 1 )
909         {
910             sal_uInt16 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
911             if( nSelect != LISTBOX_ENTRY_NOTFOUND )
912             {
913                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
914                     mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
915                 else
916                     mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
917 
918                 mnCurrentPos = nSelect;
919                 mbTrackingSelect = true;
920                 SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() );
921                 mbTrackingSelect = false;
922                 if ( mbGrabFocus )
923                     GrabFocus();
924 
925                 StartTracking( STARTTRACK_SCROLLREPEAT );
926             }
927         }
928         if( rMEvt.GetClicks() == 2 )
929         {
930             maDoubleClickHdl.Call( this );
931         }
932     }
933     else // if ( mbGrabFocus )
934     {
935         GrabFocus();
936     }
937 }
938 
939 // -----------------------------------------------------------------------
940 
941 void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
942 {
943     if ( rMEvt.IsLeaveWindow() )
944     {
945         if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
946         {
947             if ( rMEvt.GetPosPixel().Y() < 0 )
948             {
949                 DeselectAll();
950                 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
951                 SetTopEntry( 0 );
952                 if ( mbStackMode ) // #87072#, #92323#
953                 {
954                     mbTravelSelect = true;
955                     mnSelectModifier = rMEvt.GetModifier();
956                     ImplCallSelect();
957                     mbTravelSelect = false;
958                 }
959 
960             }
961         }
962     }
963     else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
964     {
965         Point aPoint;
966         Rectangle aRect( aPoint, GetOutputSizePixel() );
967         if( aRect.IsInside( rMEvt.GetPosPixel() ) )
968         {
969             if ( IsMouseMoveSelect() )
970             {
971                 sal_uInt16 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
972                 if( nSelect == LISTBOX_ENTRY_NOTFOUND )
973                     nSelect = mpEntryList->GetEntryCount() - 1;
974                 nSelect = Min( nSelect, GetLastVisibleEntry() );
975                 nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
976                 // Select only visible Entries with MouseMove, otherwise Tracking...
977                 if ( IsVisible( nSelect ) &&
978                     mpEntryList->IsEntrySelectable( nSelect ) &&
979                     ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
980                 {
981                     mbTrackingSelect = true;
982                     if ( SelectEntries( nSelect, LET_TRACKING, sal_False, sal_False ) )
983                     {
984                         if ( mbStackMode ) // #87072#
985                         {
986                             mbTravelSelect = true;
987                             mnSelectModifier = rMEvt.GetModifier();
988                             ImplCallSelect();
989                             mbTravelSelect = false;
990                         }
991                     }
992                     mbTrackingSelect = false;
993                 }
994             }
995 
996             // Falls der DD-Button gedrueckt wurde und jemand mit gedrueckter
997             // Maustaste in die ListBox faehrt...
998             if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
999             {
1000                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1001                     mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
1002                 else
1003                     mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
1004 
1005                 if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
1006                     mpEntryList->SetSelectionAnchor( 0 );
1007 
1008                 StartTracking( STARTTRACK_SCROLLREPEAT );
1009             }
1010         }
1011     }
1012 }
1013 
1014 // -----------------------------------------------------------------------
1015 
1016 void ImplListBoxWindow::DeselectAll()
1017 {
1018     while ( GetEntryList()->GetSelectEntryCount() )
1019     {
1020         sal_uInt16 nS = GetEntryList()->GetSelectEntryPos( 0 );
1021         SelectEntry( nS, sal_False );
1022     }
1023 }
1024 
1025 // -----------------------------------------------------------------------
1026 
1027 void ImplListBoxWindow::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
1028 {
1029     if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
1030     {
1031         ImplHideFocusRect();
1032         if( bSelect )
1033         {
1034             if( !mbMulti )
1035             {
1036                 // Selektierten Eintrag deselektieren
1037                 sal_uInt16 nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
1038                 if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
1039                 {
1040                     //SelectEntryPos( nDeselect, sal_False );
1041                     GetEntryList()->SelectEntry( nDeselect, sal_False );
1042                     if ( IsUpdateMode() && IsReallyVisible() )
1043                         ImplPaint( nDeselect, sal_True );
1044                 }
1045             }
1046             mpEntryList->SelectEntry( nPos, sal_True );
1047             mnCurrentPos = nPos;
1048             if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
1049             {
1050                 ImplPaint( nPos );
1051                 if ( !IsVisible( nPos ) )
1052                 {
1053                     ImplClearLayoutData();
1054                     sal_uInt16 nVisibleEntries = GetLastVisibleEntry()-mnTop;
1055                     if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
1056                     {
1057                         Resize();
1058                         ShowProminentEntry( nPos );
1059                     }
1060                     else
1061                     {
1062                         ShowProminentEntry( nPos );
1063                     }
1064                 }
1065             }
1066         }
1067         else
1068         {
1069             mpEntryList->SelectEntry( nPos, sal_False );
1070             ImplPaint( nPos, sal_True );
1071         }
1072         mbSelectionChanged = true;
1073     }
1074 }
1075 
1076 // -----------------------------------------------------------------------
1077 
1078 sal_Bool ImplListBoxWindow::SelectEntries( sal_uInt16 nSelect, LB_EVENT_TYPE eLET, sal_Bool bShift, sal_Bool bCtrl )
1079 {
1080     sal_Bool bFocusChanged = sal_False;
1081     sal_Bool bSelectionChanged = sal_False;
1082 
1083     if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
1084     {
1085         // Hier (Single-ListBox) kann nur ein Eintrag deselektiert werden
1086         if( !mbMulti )
1087         {
1088             sal_uInt16 nDeselect = mpEntryList->GetSelectEntryPos( 0 );
1089             if( nSelect != nDeselect )
1090             {
1091                 SelectEntry( nSelect, sal_True );
1092                 mpEntryList->SetLastSelected( nSelect );
1093                 bFocusChanged = sal_True;
1094                 bSelectionChanged = sal_True;
1095             }
1096         }
1097         // MultiListBox ohne Modifier
1098         else if( mbSimpleMode && !bCtrl && !bShift )
1099         {
1100             sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
1101             for ( sal_uInt16 nPos = 0; nPos < nEntryCount; nPos++ )
1102             {
1103                 sal_Bool bSelect = nPos == nSelect;
1104                 if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
1105                 {
1106                     SelectEntry( nPos, bSelect );
1107                     bFocusChanged = sal_True;
1108                     bSelectionChanged = sal_True;
1109                 }
1110             }
1111             mpEntryList->SetLastSelected( nSelect );
1112             mpEntryList->SetSelectionAnchor( nSelect );
1113         }
1114         // MultiListBox nur mit CTRL/SHIFT oder nicht im SimpleMode
1115         else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
1116         {
1117             // Space fuer Selektionswechsel
1118             if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
1119             {
1120                 sal_Bool bSelect = ( mbStackMode && IsMouseMoveSelect() ) ? sal_True : !mpEntryList->IsEntryPosSelected( nSelect );
1121                 if ( mbStackMode )
1122                 {
1123                     sal_uInt16 n;
1124                     if ( bSelect )
1125                     {
1126                         // All entries before nSelect must be selected...
1127                         for ( n = 0; n < nSelect; n++ )
1128                             SelectEntry( n, sal_True );
1129                     }
1130                     if ( !bSelect )
1131                     {
1132                         for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
1133                             SelectEntry( n, sal_False );
1134                     }
1135                 }
1136                 SelectEntry( nSelect, bSelect );
1137                 mpEntryList->SetLastSelected( nSelect );
1138                 mpEntryList->SetSelectionAnchor( mbStackMode ? 0 : nSelect );
1139                 if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1140                     mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND );
1141                 bFocusChanged = sal_True;
1142                 bSelectionChanged = sal_True;
1143             }
1144             else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
1145                      ( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
1146             {
1147                 mnCurrentPos = nSelect;
1148                 bFocusChanged = sal_True;
1149 
1150                 sal_uInt16 nAnchor = mpEntryList->GetSelectionAnchor();
1151                 if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
1152                 {
1153                     nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
1154                 }
1155                 if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
1156                 {
1157                     // Alle Eintraege vom Anchor bis nSelect muessen selektiert sein
1158                     sal_uInt16 nStart = Min( nSelect, nAnchor );
1159                     sal_uInt16 nEnd = Max( nSelect, nAnchor );
1160                     for ( sal_uInt16 n = nStart; n <= nEnd; n++ )
1161                     {
1162                         if ( !mpEntryList->IsEntryPosSelected( n ) )
1163                         {
1164                             SelectEntry( n, sal_True );
1165                             bSelectionChanged = sal_True;
1166                         }
1167                     }
1168 
1169                     // Ggf. muss noch was deselektiert werden...
1170                     sal_uInt16 nLast = mpEntryList->GetLastSelected();
1171                     if ( nLast != LISTBOX_ENTRY_NOTFOUND )
1172                     {
1173                         if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
1174                         {
1175                             for ( sal_uInt16 n = nSelect+1; n <= nLast; n++ )
1176                             {
1177                                 if ( mpEntryList->IsEntryPosSelected( n ) )
1178                                 {
1179                                     SelectEntry( n, sal_False );
1180                                     bSelectionChanged = sal_True;
1181                                 }
1182                             }
1183                         }
1184                         else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
1185                         {
1186                             for ( sal_uInt16 n = nLast; n < nSelect; n++ )
1187                             {
1188                                 if ( mpEntryList->IsEntryPosSelected( n ) )
1189                                 {
1190                                     SelectEntry( n, sal_False );
1191                                     bSelectionChanged = sal_True;
1192                                 }
1193                             }
1194                         }
1195                     }
1196                     mpEntryList->SetLastSelected( nSelect );
1197                 }
1198             }
1199             else if( eLET != LET_TRACKING )
1200             {
1201                 ImplHideFocusRect();
1202                 ImplPaint( nSelect, sal_True );
1203                 bFocusChanged = sal_True;
1204             }
1205         }
1206         else if( bShift )
1207         {
1208             bFocusChanged = sal_True;
1209         }
1210 
1211         if( bSelectionChanged )
1212             mbSelectionChanged = true;
1213 
1214         if( bFocusChanged )
1215         {
1216             long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop, 0 );
1217             maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1218             Size aSz( maFocusRect.GetWidth(),
1219                       mpEntryList->GetEntryHeight( nSelect ) );
1220             maFocusRect.SetSize( aSz );
1221             if( HasFocus() )
1222                 ImplShowFocusRect();
1223         }
1224         ImplClearLayoutData();
1225     }
1226     return bSelectionChanged;
1227 }
1228 
1229 // -----------------------------------------------------------------------
1230 
1231 void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
1232 {
1233     Point aPoint;
1234     Rectangle aRect( aPoint, GetOutputSizePixel() );
1235     sal_Bool bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
1236 
1237     if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
1238     {
1239         if ( bInside && !rTEvt.IsTrackingCanceled() )
1240         {
1241             mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1242             ImplCallSelect();
1243         }
1244         else
1245         {
1246             maCancelHdl.Call( NULL );
1247             if ( !mbMulti )
1248             {
1249                 mbTrackingSelect = true;
1250                 SelectEntry( mnTrackingSaveSelection, sal_True );
1251                 mbTrackingSelect = false;
1252                 if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
1253                 {
1254                     long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1255                     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1256                     Size aSz( maFocusRect.GetWidth(),
1257                               mpEntryList->GetEntryHeight( mnCurrentPos ) );
1258                     maFocusRect.SetSize( aSz );
1259                     ImplShowFocusRect();
1260                 }
1261             }
1262         }
1263 
1264         mbTrack = false;
1265     }
1266     else
1267     {
1268         sal_Bool bTrackOrQuickClick = mbTrack;
1269         if( !mbTrack )
1270         {
1271             if ( bInside )
1272             {
1273                 mbTrack = true;
1274             }
1275 
1276             // Folgender Fall tritt nur auf, wenn man ganz kurz die Maustaste drueckt
1277             if( rTEvt.IsTrackingEnded() && mbTrack )
1278             {
1279                 bTrackOrQuickClick = sal_True;
1280                 mbTrack = false;
1281             }
1282         }
1283 
1284         if( bTrackOrQuickClick )
1285         {
1286             MouseEvent aMEvt = rTEvt.GetMouseEvent();
1287             Point aPt( aMEvt.GetPosPixel() );
1288             sal_Bool bShift = aMEvt.IsShift();
1289             sal_Bool bCtrl  = aMEvt.IsMod1();
1290 
1291             sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
1292             if( aPt.Y() < 0 )
1293             {
1294                 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1295                 {
1296                     nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
1297                     if( nSelect < mnTop )
1298                         SetTopEntry( mnTop-1 );
1299                 }
1300             }
1301             else if( aPt.Y() > GetOutputSizePixel().Height() )
1302             {
1303                 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1304                 {
1305                     nSelect = Min(  (sal_uInt16)(mnCurrentPos+1), (sal_uInt16)(mpEntryList->GetEntryCount()-1) );
1306                     if( nSelect >= GetLastVisibleEntry() )
1307                         SetTopEntry( mnTop+1 );
1308                 }
1309             }
1310             else
1311             {
1312                 nSelect = (sal_uInt16) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (sal_uInt16) mnTop;
1313                 nSelect = Min( nSelect, GetLastVisibleEntry() );
1314                 nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
1315             }
1316 
1317             if ( bInside )
1318             {
1319                 if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
1320                 {
1321                     mbTrackingSelect = true;
1322                     if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
1323                     {
1324                         if ( mbStackMode ) // #87734# (#87072#)
1325                         {
1326                             mbTravelSelect = true;
1327                             mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1328                             ImplCallSelect();
1329                             mbTravelSelect = false;
1330                         }
1331                     }
1332                     mbTrackingSelect = false;
1333                 }
1334             }
1335             else
1336             {
1337                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1338                 {
1339                     mbTrackingSelect = true;
1340                     SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), sal_False );
1341                     mbTrackingSelect = false;
1342                 }
1343                 else if ( mbStackMode )
1344                 {
1345                     if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 )  && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
1346                     {
1347                         if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1348                         {
1349                             sal_Bool bSelectionChanged = sal_False;
1350                             if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
1351                                    && !mnCurrentPos )
1352                             {
1353                                 if ( mpEntryList->IsEntryPosSelected( 0 ) )
1354                                 {
1355                                     SelectEntry( 0, sal_False );
1356                                     bSelectionChanged = sal_True;
1357                                     nSelect = LISTBOX_ENTRY_NOTFOUND;
1358 
1359                                 }
1360                             }
1361                             else
1362                             {
1363                                 mbTrackingSelect = true;
1364                                 bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
1365                                 mbTrackingSelect = false;
1366                             }
1367 
1368                             if ( bSelectionChanged )
1369                             {
1370                                 mbSelectionChanged = true;
1371                                 mbTravelSelect = true;
1372                                 mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1373                                 ImplCallSelect();
1374                                 mbTravelSelect = false;
1375                             }
1376                         }
1377                     }
1378                 }
1379             }
1380             mnCurrentPos = nSelect;
1381             if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1382             {
1383                 ImplHideFocusRect();
1384             }
1385             else
1386             {
1387                 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1388                 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1389                 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1390                 maFocusRect.SetSize( aSz );
1391                 ImplShowFocusRect();
1392             }
1393         }
1394     }
1395 }
1396 
1397 
1398 // -----------------------------------------------------------------------
1399 
1400 void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
1401 {
1402     if( !ProcessKeyInput( rKEvt ) )
1403         Control::KeyInput( rKEvt );
1404 }
1405 
1406 // -----------------------------------------------------------------------
1407 
1408 #define IMPL_SELECT_NODIRECTION 0
1409 #define IMPL_SELECT_UP          1
1410 #define IMPL_SELECT_DOWN        2
1411 
1412 sal_Bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
1413 {
1414     // zu selektierender Eintrag
1415     sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
1416     LB_EVENT_TYPE eLET = LET_KEYMOVE;
1417 
1418     KeyCode aKeyCode = rKEvt.GetKeyCode();
1419 
1420     sal_Bool bShift = aKeyCode.IsShift();
1421     sal_Bool bCtrl  = aKeyCode.IsMod1() || aKeyCode.IsMod3();
1422     sal_Bool bMod2 = aKeyCode.IsMod2();
1423     sal_Bool bDone = sal_False;
1424 
1425     switch( aKeyCode.GetCode() )
1426     {
1427         case KEY_UP:
1428         {
1429             if ( IsReadOnly() )
1430             {
1431                 if ( GetTopEntry() )
1432                     SetTopEntry( GetTopEntry()-1 );
1433             }
1434             else if ( !bMod2 )
1435             {
1436                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1437                 {
1438                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1439                 }
1440                 else if ( mnCurrentPos )
1441                 {
1442                     // search first selectable above the current position
1443                     nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
1444                 }
1445 
1446                 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
1447                     SetTopEntry( mnTop-1 );
1448 
1449                 bDone = sal_True;
1450             }
1451             maQuickSelectionEngine.Reset();
1452         }
1453         break;
1454 
1455         case KEY_DOWN:
1456         {
1457             if ( IsReadOnly() )
1458             {
1459                 SetTopEntry( GetTopEntry()+1 );
1460             }
1461             else if ( !bMod2 )
1462             {
1463                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1464                 {
1465                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1466                 }
1467                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1468                 {
1469                     // search first selectable below the current position
1470                     nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
1471                 }
1472 
1473                 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
1474                     SetTopEntry( mnTop+1 );
1475 
1476                 bDone = sal_True;
1477             }
1478             maQuickSelectionEngine.Reset();
1479         }
1480         break;
1481 
1482         case KEY_PAGEUP:
1483         {
1484             if ( IsReadOnly() )
1485             {
1486                 sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
1487                 SetTopEntry( ( mnTop > nCurVis ) ?
1488                                 (mnTop-nCurVis) : 0 );
1489             }
1490             else if ( !bCtrl && !bMod2 )
1491             {
1492                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1493                 {
1494                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1495                 }
1496                 else if ( mnCurrentPos )
1497                 {
1498                     if( mnCurrentPos == mnTop )
1499                     {
1500                         sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
1501                         SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
1502                     }
1503 
1504                     // find first selectable starting from mnTop looking foreward
1505                     nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
1506                 }
1507                 bDone = sal_True;
1508             }
1509             maQuickSelectionEngine.Reset();
1510         }
1511         break;
1512 
1513         case KEY_PAGEDOWN:
1514         {
1515             if ( IsReadOnly() )
1516             {
1517                 SetTopEntry( GetLastVisibleEntry() );
1518             }
1519             else if ( !bCtrl && !bMod2 )
1520             {
1521                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1522                 {
1523                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1524                 }
1525                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1526                 {
1527                     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1528                     sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop;
1529                     sal_uInt16 nTmp = Min( nCurVis, nCount );
1530                     nTmp += mnTop - 1;
1531                     if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
1532                     {
1533                         long nTmp2 = Min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
1534                         nTmp2 = Max( (long)0 , nTmp2 );
1535                         nTmp = (sal_uInt16)(nTmp2+(nCurVis-1) );
1536                         SetTopEntry( (sal_uInt16)nTmp2 );
1537                     }
1538                     // find first selectable starting from nTmp looking backwards
1539                     nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
1540                 }
1541                 bDone = sal_True;
1542             }
1543             maQuickSelectionEngine.Reset();
1544         }
1545         break;
1546 
1547         case KEY_HOME:
1548         {
1549             if ( IsReadOnly() )
1550             {
1551                 SetTopEntry( 0 );
1552             }
1553             else if ( !bCtrl && !bMod2 )
1554             {
1555                 if ( mnCurrentPos )
1556                 {
1557                     nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
1558                     if( mnTop != 0 )
1559                         SetTopEntry( 0 );
1560 
1561                     bDone = sal_True;
1562                 }
1563             }
1564             maQuickSelectionEngine.Reset();
1565         }
1566         break;
1567 
1568         case KEY_END:
1569         {
1570             if ( IsReadOnly() )
1571             {
1572                 SetTopEntry( 0xFFFF );
1573             }
1574             else if ( !bCtrl && !bMod2 )
1575             {
1576                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1577                 {
1578                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1579                 }
1580                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1581                 {
1582                     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1583                     nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
1584                     sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop + 1;
1585                     if( nCount > nCurVis )
1586                         SetTopEntry( nCount - nCurVis );
1587                 }
1588                 bDone = sal_True;
1589             }
1590             maQuickSelectionEngine.Reset();
1591         }
1592         break;
1593 
1594         case KEY_LEFT:
1595         {
1596             if ( !bCtrl && !bMod2 )
1597             {
1598                 ScrollHorz( -HORZ_SCROLL );
1599                 bDone = sal_True;
1600             }
1601             maQuickSelectionEngine.Reset();
1602         }
1603         break;
1604 
1605         case KEY_RIGHT:
1606         {
1607             if ( !bCtrl && !bMod2 )
1608             {
1609                 ScrollHorz( HORZ_SCROLL );
1610                 bDone = sal_True;
1611             }
1612             maQuickSelectionEngine.Reset();
1613         }
1614         break;
1615 
1616         case KEY_RETURN:
1617         {
1618             if ( !bMod2 && !IsReadOnly() )
1619             {
1620                 mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1621                 ImplCallSelect();
1622                 bDone = sal_False;  // RETURN nicht abfangen.
1623             }
1624             maQuickSelectionEngine.Reset();
1625         }
1626         break;
1627 
1628         case KEY_SPACE:
1629         {
1630             if ( !bMod2 && !IsReadOnly() )
1631             {
1632                 if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
1633                 {
1634                     nSelect = mnCurrentPos;
1635                     eLET = LET_KEYSPACE;
1636                 }
1637                 bDone = sal_True;
1638             }
1639             maQuickSelectionEngine.Reset();
1640         }
1641         break;
1642 
1643         case KEY_A:
1644         {
1645             if( bCtrl && mbMulti )
1646             {
1647                 // paint only once
1648                 sal_Bool bUpdates = IsUpdateMode();
1649                 SetUpdateMode( sal_False );
1650 
1651                 sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
1652                 for( sal_uInt16 i = 0; i < nEntryCount; i++ )
1653                     SelectEntry( i, sal_True );
1654 
1655                 // restore update mode
1656                 SetUpdateMode( bUpdates );
1657                 Invalidate();
1658 
1659                 maQuickSelectionEngine.Reset();
1660 
1661                 bDone = sal_True;
1662                 break;
1663             }
1664         }
1665         // fall through intentional
1666         default:
1667         {
1668             if ( !IsReadOnly() )
1669             {
1670                 bDone = maQuickSelectionEngine.HandleKeyEvent( rKEvt );
1671             }
1672         }
1673         break;
1674     }
1675 
1676     if  (   ( nSelect != LISTBOX_ENTRY_NOTFOUND )
1677         &&  (   ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1678             ||  ( eLET == LET_KEYSPACE )
1679             )
1680         )
1681     {
1682         DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
1683         if( nSelect >= mpEntryList->GetEntryCount() )
1684             nSelect = mpEntryList->GetEntryCount()-1;
1685         mnCurrentPos = nSelect;
1686         if ( SelectEntries( nSelect, eLET, bShift, bCtrl ) )
1687         {
1688             mbTravelSelect = true;
1689             mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1690             ImplCallSelect();
1691             mbTravelSelect = false;
1692         }
1693     }
1694 
1695     return bDone;
1696 }
1697 
1698 // -----------------------------------------------------------------------
1699 namespace
1700 {
1701     static ::vcl::StringEntryIdentifier lcl_getEntry( const ImplEntryList& _rList, sal_uInt16 _nPos, String& _out_entryText )
1702     {
1703         OSL_PRECOND( ( _nPos != LISTBOX_ENTRY_NOTFOUND ), "lcl_getEntry: invalid position!" );
1704         sal_uInt16 nEntryCount( _rList.GetEntryCount() );
1705         if ( _nPos >= nEntryCount )
1706             _nPos = 0;
1707         _out_entryText = _rList.GetEntryText( _nPos );
1708 
1709         // ::vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1710         // => normalize
1711         return reinterpret_cast< ::vcl::StringEntryIdentifier >( _nPos + 1 );
1712     }
1713 
1714     static sal_uInt16 lcl_getEntryPos( ::vcl::StringEntryIdentifier _entry )
1715     {
1716         // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1717         return static_cast< sal_uInt16 >( reinterpret_cast< sal_Int64 >( _entry ) ) - 1;
1718     }
1719 }
1720 
1721 // -----------------------------------------------------------------------
1722 ::vcl::StringEntryIdentifier ImplListBoxWindow::CurrentEntry( String& _out_entryText ) const
1723 {
1724     return lcl_getEntry( *GetEntryList(), ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND ) ? 0 : mnCurrentPos + 1, _out_entryText );
1725 }
1726 
1727 // -----------------------------------------------------------------------
1728 ::vcl::StringEntryIdentifier ImplListBoxWindow::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, String& _out_entryText ) const
1729 {
1730     sal_uInt16 nNextPos = lcl_getEntryPos( _currentEntry ) + 1;
1731     return lcl_getEntry( *GetEntryList(), nNextPos, _out_entryText );
1732 }
1733 
1734 // -----------------------------------------------------------------------
1735 void ImplListBoxWindow::SelectEntry( ::vcl::StringEntryIdentifier _entry )
1736 {
1737     sal_uInt16 nSelect = lcl_getEntryPos( _entry );
1738     if ( mpEntryList->IsEntryPosSelected( nSelect ) )
1739     {
1740         // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1741         // to select the given entry by typing its starting letters. No need to act.
1742         return;
1743     }
1744 
1745     // normalize
1746     OSL_ENSURE( nSelect < mpEntryList->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1747     if( nSelect >= mpEntryList->GetEntryCount() )
1748         nSelect = mpEntryList->GetEntryCount()-1;
1749 
1750     // make visible
1751     ShowProminentEntry( nSelect );
1752 
1753     // actually select
1754     mnCurrentPos = nSelect;
1755     if ( SelectEntries( nSelect, LET_KEYMOVE, sal_False, sal_False ) )
1756     {
1757         mbTravelSelect = true;
1758         mnSelectModifier = 0;
1759         ImplCallSelect();
1760         mbTravelSelect = false;
1761     }
1762 }
1763 
1764 // -----------------------------------------------------------------------
1765 
1766 void ImplListBoxWindow::ImplPaint( sal_uInt16 nPos, sal_Bool bErase, bool bLayout )
1767 {
1768     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1769 
1770     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1771     if( ! pEntry )
1772         return;
1773 
1774     long nWidth  = GetOutputSizePixel().Width();
1775     long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1776     Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
1777 
1778     if( ! bLayout )
1779     {
1780         if( mpEntryList->IsEntryPosSelected( nPos ) )
1781         {
1782             SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
1783             SetFillColor( rStyleSettings.GetHighlightColor() );
1784             SetTextFillColor( rStyleSettings.GetHighlightColor() );
1785             DrawRect( aRect );
1786         }
1787         else
1788         {
1789             ImplInitSettings( sal_False, sal_True, sal_False );
1790             if( !IsEnabled() )
1791                 SetTextColor( rStyleSettings.GetDisableColor() );
1792             SetTextFillColor();
1793             if( bErase )
1794                 Erase( aRect );
1795         }
1796     }
1797 
1798     if ( IsUserDrawEnabled() )
1799     {
1800         mbInUserDraw = true;
1801         mnUserDrawEntry = nPos;
1802         aRect.Left() -= mnLeft;
1803         if ( nPos < GetEntryList()->GetMRUCount() )
1804             nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
1805         nPos = sal::static_int_cast<sal_uInt16>(nPos - GetEntryList()->GetMRUCount());
1806         UserDrawEvent aUDEvt( this, aRect, nPos, 0 );
1807         maUserDrawHdl.Call( &aUDEvt );
1808         mbInUserDraw = false;
1809     }
1810     else
1811     {
1812         DrawEntry( nPos, sal_True, sal_True, sal_False, bLayout );
1813     }
1814 }
1815 
1816 // -----------------------------------------------------------------------
1817 
1818 void ImplListBoxWindow::DrawEntry( sal_uInt16 nPos, sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
1819 {
1820     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1821     if( ! pEntry )
1822         return;
1823 
1824     // Bei Aenderungen in dieser Methode ggf. auch ImplWin::DrawEntry() anpassen.
1825 
1826     if ( mbInUserDraw )
1827         nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
1828 
1829     long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1830     Size aImgSz;
1831 
1832     if( bDrawImage && mpEntryList->HasImages() && !bLayout )
1833     {
1834         Image aImage = mpEntryList->GetEntryImage( nPos );
1835         if( !!aImage )
1836         {
1837             aImgSz = aImage.GetSizePixel();
1838             Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
1839 
1840             // pb: #106948# explicit mirroring for calc
1841             if ( mbMirroring )
1842                 // right aligned
1843                 aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
1844 
1845             if ( !IsZoom() )
1846             {
1847                 DrawImage( aPtImg, aImage );
1848             }
1849             else
1850             {
1851                 aImgSz.Width() = CalcZoom( aImgSz.Width() );
1852                 aImgSz.Height() = CalcZoom( aImgSz.Height() );
1853                 DrawImage( aPtImg, aImgSz, aImage );
1854             }
1855 
1856             const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1857             const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
1858 
1859             if(nEdgeBlendingPercent)
1860             {
1861                 const Rectangle aRect(aPtImg, aImgSz);
1862                 Bitmap aBitmap(GetBitmap(aRect.TopLeft(), aRect.GetSize()));
1863 
1864                 if(!aBitmap.IsEmpty())
1865                 {
1866                     const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
1867                     const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
1868                     const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
1869 
1870                     aBitmap.DrawBlendFrame(nAlpha, rTopLeft, rBottomRight);
1871                     DrawBitmap(aRect.TopLeft(), aBitmap);
1872                 }
1873             }
1874         }
1875     }
1876 
1877     if( bDrawText )
1878     {
1879         MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
1880         String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
1881         XubString aStr( mpEntryList->GetEntryText( nPos ) );
1882         if ( aStr.Len() )
1883         {
1884             long nMaxWidth = Max( static_cast< long >( mnMaxWidth ),
1885                                   GetOutputSizePixel().Width() - 2*mnBorder );
1886             // a multiline entry should only be as wide a the window
1887             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1888                 nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
1889 
1890             Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
1891                                  Size( nMaxWidth, pEntry->mnHeight ) );
1892 
1893             if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
1894             {
1895                 long nImageWidth = Max( mnMaxImgWidth, maUserItemSize.Width() );
1896                 aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
1897             }
1898 
1899             if( bLayout )
1900                 mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
1901 
1902             // pb: #106948# explicit mirroring for calc
1903             if ( mbMirroring )
1904             {
1905                 // right aligned
1906                 aTextRect.Left() = nMaxWidth + mnBorder - GetTextWidth( aStr ) - mnLeft;
1907                 if ( aImgSz.Width() > 0 )
1908                     aTextRect.Left() -= ( aImgSz.Width() + IMG_TXT_DISTANCE );
1909             }
1910 
1911             sal_uInt16 nDrawStyle = ImplGetTextStyle();
1912             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1913                 nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
1914             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) )
1915                 nDrawStyle |= TEXT_DRAW_DISABLE;
1916 
1917             DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
1918         }
1919     }
1920 
1921     if( !bLayout )
1922     {
1923         if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
1924              ( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
1925         {
1926             Color aOldLineColor( GetLineColor() );
1927             SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
1928             Point aStartPos( 0, nY );
1929             if ( nPos == mnSeparatorPos )
1930                 aStartPos.Y() += pEntry->mnHeight-1;
1931             Point aEndPos( aStartPos );
1932             aEndPos.X() = GetOutputSizePixel().Width();
1933             DrawLine( aStartPos, aEndPos );
1934             SetLineColor( aOldLineColor );
1935         }
1936     }
1937 }
1938 
1939 // -----------------------------------------------------------------------
1940 
1941 void ImplListBoxWindow::FillLayoutData() const
1942 {
1943     mpControlData->mpLayoutData = new vcl::ControlLayoutData();
1944     const_cast<ImplListBoxWindow*>(this)->
1945         ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
1946 }
1947 
1948 // -----------------------------------------------------------------------
1949 
1950 void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
1951 {
1952     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1953 
1954     sal_Bool bShowFocusRect = mbHasFocusRect;
1955     if ( mbHasFocusRect && ! bLayout )
1956         ImplHideFocusRect();
1957 
1958     long nY = 0; // + mnBorder;
1959     long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1960 
1961     for( sal_uInt16 i = (sal_uInt16)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
1962     {
1963         const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
1964         if( nY + pEntry->mnHeight >= rRect.Top() &&
1965             nY <= rRect.Bottom() + mnMaxHeight )
1966         {
1967             ImplPaint( i, sal_False, bLayout );
1968         }
1969         nY += pEntry->mnHeight;
1970     }
1971 
1972     long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1973     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1974     Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1975     maFocusRect.SetSize( aSz );
1976     if( HasFocus() && bShowFocusRect && !bLayout )
1977         ImplShowFocusRect();
1978 }
1979 
1980 // -----------------------------------------------------------------------
1981 
1982 void ImplListBoxWindow::Paint( const Rectangle& rRect )
1983 {
1984     ImplDoPaint( rRect );
1985 }
1986 
1987 // -----------------------------------------------------------------------
1988 
1989 sal_uInt16 ImplListBoxWindow::GetDisplayLineCount() const
1990 {
1991     // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
1992 
1993     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1994     long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1995     sal_uInt16 nEntries = static_cast< sal_uInt16 >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
1996     if( nEntries > nCount-mnTop )
1997         nEntries = nCount-mnTop;
1998 
1999     return nEntries;
2000 }
2001 
2002 // -----------------------------------------------------------------------
2003 
2004 void ImplListBoxWindow::Resize()
2005 {
2006     Control::Resize();
2007 
2008     sal_Bool bShowFocusRect = mbHasFocusRect;
2009     if ( bShowFocusRect )
2010         ImplHideFocusRect();
2011 
2012     if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
2013     {
2014         Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
2015         maFocusRect.SetSize( aSz );
2016     }
2017 
2018     if ( bShowFocusRect )
2019         ImplShowFocusRect();
2020 
2021     ImplClearLayoutData();
2022 }
2023 
2024 // -----------------------------------------------------------------------
2025 
2026 void ImplListBoxWindow::GetFocus()
2027 {
2028     sal_uInt16 nPos = mnCurrentPos;
2029     if ( nPos == LISTBOX_ENTRY_NOTFOUND )
2030         nPos = 0;
2031     long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
2032     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
2033     Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
2034     maFocusRect.SetSize( aSz );
2035     ImplShowFocusRect();
2036     Control::GetFocus();
2037 }
2038 
2039 // -----------------------------------------------------------------------
2040 
2041 void ImplListBoxWindow::LoseFocus()
2042 {
2043     ImplHideFocusRect();
2044     Control::LoseFocus();
2045 }
2046 
2047 // -----------------------------------------------------------------------
2048 
2049 /*
2050 void ImplListBoxWindow::RequestHelp( const HelpEvent& rHEvt )
2051 {
2052     if ( rHEvt.GetMode() & HELPMODE_BALLOON )
2053         Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), String() );
2054 
2055     Window::RequestHelp( rHEvt );
2056 }
2057 */
2058 
2059 // -----------------------------------------------------------------------
2060 
2061 void ImplListBoxWindow::SetTopEntry( sal_uInt16 nTop )
2062 {
2063     if( mpEntryList->GetEntryCount() == 0 )
2064         return;
2065 
2066     long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2067 
2068     sal_uInt16 nLastEntry = mpEntryList->GetEntryCount()-1;
2069     if( nTop > nLastEntry )
2070         nTop = nLastEntry;
2071     const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
2072     while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
2073         nTop--;
2074 
2075     if ( nTop != mnTop )
2076     {
2077         ImplClearLayoutData();
2078         long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
2079         Update();
2080         ImplHideFocusRect();
2081         mnTop = nTop;
2082         Scroll( 0, nDiff );
2083         Update();
2084         if( HasFocus() )
2085             ImplShowFocusRect();
2086         maScrollHdl.Call( this );
2087     }
2088 }
2089 
2090 // -----------------------------------------------------------------------
2091 
2092 void ImplListBoxWindow::ShowProminentEntry( sal_uInt16 nEntryPos )
2093 {
2094     if( meProminentType == PROMINENT_MIDDLE )
2095     {
2096         sal_uInt16 nPos = nEntryPos;
2097         long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2098         while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
2099             nEntryPos--;
2100     }
2101     SetTopEntry( nEntryPos );
2102 }
2103 
2104 // -----------------------------------------------------------------------
2105 
2106 void ImplListBoxWindow::SetLeftIndent( long n )
2107 {
2108     ScrollHorz( n - mnLeft );
2109 }
2110 
2111 // -----------------------------------------------------------------------
2112 
2113 void ImplListBoxWindow::ScrollHorz( long n )
2114 {
2115     long nDiff = 0;
2116     if ( n > 0 )
2117     {
2118         long nWidth = GetOutputSizePixel().Width();
2119         if( ( mnMaxWidth - mnLeft + n ) > nWidth )
2120             nDiff = n;
2121     }
2122     else if ( n < 0 )
2123     {
2124         if( mnLeft )
2125         {
2126             long nAbs = -n;
2127             nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
2128         }
2129     }
2130 
2131     if ( nDiff )
2132     {
2133         ImplClearLayoutData();
2134         mnLeft = sal::static_int_cast<sal_uInt16>(mnLeft + nDiff);
2135         Update();
2136         ImplHideFocusRect();
2137         Scroll( -nDiff, 0 );
2138         Update();
2139         if( HasFocus() )
2140             ImplShowFocusRect();
2141         maScrollHdl.Call( this );
2142     }
2143 }
2144 
2145 // -----------------------------------------------------------------------
2146 
2147 Size ImplListBoxWindow::CalcSize( sal_uInt16 nMaxLines ) const
2148 {
2149     // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2150 
2151     Size aSz;
2152 //  sal_uInt16 nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
2153     aSz.Height() =  nMaxLines * mnMaxHeight;
2154     aSz.Width() = mnMaxWidth + 2*mnBorder;
2155     return aSz;
2156 }
2157 
2158 // -----------------------------------------------------------------------
2159 
2160 Rectangle ImplListBoxWindow::GetBoundingRectangle( sal_uInt16 nItem ) const
2161 {
2162     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
2163     Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
2164     long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) - mpEntryList->GetAddedHeight( GetTopEntry() );
2165     Rectangle aRect( Point( 0, nY ), aSz );
2166     return aRect;
2167 }
2168 
2169 
2170 // -----------------------------------------------------------------------
2171 
2172 void ImplListBoxWindow::StateChanged( StateChangedType nType )
2173 {
2174     Control::StateChanged( nType );
2175 
2176     if ( nType == STATE_CHANGE_ZOOM )
2177     {
2178         ImplInitSettings( sal_True, sal_False, sal_False );
2179         ImplCalcMetrics();
2180         Invalidate();
2181     }
2182     else if ( nType == STATE_CHANGE_UPDATEMODE )
2183     {
2184         if ( IsUpdateMode() && IsReallyVisible() )
2185             Invalidate();
2186     }
2187     else if ( nType == STATE_CHANGE_CONTROLFONT )
2188     {
2189         ImplInitSettings( sal_True, sal_False, sal_False );
2190         ImplCalcMetrics();
2191         Invalidate();
2192     }
2193     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2194     {
2195         ImplInitSettings( sal_False, sal_True, sal_False );
2196         Invalidate();
2197     }
2198     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2199     {
2200         ImplInitSettings( sal_False, sal_False, sal_True );
2201         Invalidate();
2202     }
2203     ImplClearLayoutData();
2204 }
2205 
2206 // -----------------------------------------------------------------------
2207 
2208 void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
2209 {
2210     Control::DataChanged( rDCEvt );
2211 
2212     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2213          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2214          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2215           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2216     {
2217         ImplClearLayoutData();
2218         ImplInitSettings( sal_True, sal_True, sal_True );
2219         ImplCalcMetrics();
2220         Invalidate();
2221     }
2222 }
2223 
2224 // -----------------------------------------------------------------------
2225 
2226 sal_uInt16 ImplListBoxWindow::ImplGetTextStyle() const
2227 {
2228     sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
2229 
2230     if ( mpEntryList->HasImages() )
2231         nTextStyle |= TEXT_DRAW_LEFT;
2232     else if ( mbCenter )
2233         nTextStyle |= TEXT_DRAW_CENTER;
2234     else if ( mbRight )
2235         nTextStyle |= TEXT_DRAW_RIGHT;
2236     else
2237         nTextStyle |= TEXT_DRAW_LEFT;
2238 
2239     return nTextStyle;
2240 }
2241 
2242 // =======================================================================
2243 
2244 ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
2245     Control( pParent, nWinStyle ),
2246     maLBWindow( this, nWinStyle&(~WB_BORDER) )
2247 {
2248     // for native widget rendering we must be able to detect this window type
2249     SetType( WINDOW_LISTBOXWINDOW );
2250 
2251     mpVScrollBar    = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
2252     mpHScrollBar    = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
2253     mpScrollBarBox  = new ScrollBarBox( this );
2254 
2255     Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
2256     mpVScrollBar->SetScrollHdl( aLink );
2257     mpHScrollBar->SetScrollHdl( aLink );
2258 
2259     mbVScroll       = false;
2260     mbHScroll       = false;
2261     mbAutoHScroll   = ( nWinStyle & WB_AUTOHSCROLL );
2262     mbEdgeBlending  = false;
2263 
2264     maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
2265     maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
2266     maLBWindow.SetEdgeBlending(GetEdgeBlending());
2267     maLBWindow.Show();
2268 }
2269 
2270 // -----------------------------------------------------------------------
2271 
2272 ImplListBox::~ImplListBox()
2273 {
2274     delete mpHScrollBar;
2275     delete mpVScrollBar;
2276     delete mpScrollBarBox;
2277 }
2278 
2279 // -----------------------------------------------------------------------
2280 
2281 void ImplListBox::Clear()
2282 {
2283     maLBWindow.Clear();
2284     if ( GetEntryList()->GetMRUCount() )
2285     {
2286         maLBWindow.GetEntryList()->SetMRUCount( 0 );
2287         maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
2288     }
2289     mpVScrollBar->SetThumbPos( 0 );
2290     mpHScrollBar->SetThumbPos( 0 );
2291     StateChanged( STATE_CHANGE_DATA );
2292 }
2293 
2294 // -----------------------------------------------------------------------
2295 
2296 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr )
2297 {
2298     ImplEntryType* pNewEntry = new ImplEntryType( rStr );
2299     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2300     StateChanged( STATE_CHANGE_DATA );
2301     return nNewPos;
2302 }
2303 
2304 // -----------------------------------------------------------------------
2305 
2306 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const Image& rImage )
2307 {
2308     ImplEntryType* pNewEntry = new ImplEntryType( rImage );
2309     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2310     StateChanged( STATE_CHANGE_DATA );
2311     return nNewPos;
2312 }
2313 
2314 // -----------------------------------------------------------------------
2315 
2316 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr, const Image& rImage )
2317 {
2318     ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
2319     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2320     StateChanged( STATE_CHANGE_DATA );
2321     return nNewPos;
2322 }
2323 
2324 // -----------------------------------------------------------------------
2325 
2326 void ImplListBox::RemoveEntry( sal_uInt16 nPos )
2327 {
2328     maLBWindow.RemoveEntry( nPos );
2329     StateChanged( STATE_CHANGE_DATA );
2330 }
2331 
2332 // -----------------------------------------------------------------------
2333 
2334 void ImplListBox::SetEntryFlags( sal_uInt16 nPos, long nFlags )
2335 {
2336     maLBWindow.SetEntryFlags( nPos, nFlags );
2337 }
2338 
2339 // -----------------------------------------------------------------------
2340 
2341 long ImplListBox::GetEntryFlags( sal_uInt16 nPos ) const
2342 {
2343     return maLBWindow.GetEntryList()->GetEntryFlags( nPos );
2344 }
2345 
2346 // -----------------------------------------------------------------------
2347 
2348 void ImplListBox::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
2349 {
2350     maLBWindow.SelectEntry( nPos, bSelect );
2351 }
2352 
2353 // -----------------------------------------------------------------------
2354 
2355 void ImplListBox::SetNoSelection()
2356 {
2357     maLBWindow.DeselectAll();
2358 }
2359 
2360 // -----------------------------------------------------------------------
2361 
2362 void ImplListBox::GetFocus()
2363 {
2364     maLBWindow.GrabFocus();
2365 }
2366 
2367 // -----------------------------------------------------------------------
2368 
2369 Window* ImplListBox::GetPreferredKeyInputWindow()
2370 {
2371     return &maLBWindow;
2372 }
2373 
2374 // -----------------------------------------------------------------------
2375 
2376 void ImplListBox::Resize()
2377 {
2378     Control::Resize();
2379     ImplResizeControls();
2380     ImplCheckScrollBars();
2381 }
2382 
2383 
2384 // -----------------------------------------------------------------------
2385 
2386 IMPL_LINK( ImplListBox, MRUChanged, void*, EMPTYARG )
2387 {
2388     StateChanged( STATE_CHANGE_DATA );
2389     return 1;
2390 }
2391 
2392 // -----------------------------------------------------------------------
2393 
2394 IMPL_LINK( ImplListBox, LBWindowScrolled, void*, EMPTYARG )
2395 {
2396     long nSet = GetTopEntry();
2397     if( nSet > mpVScrollBar->GetRangeMax() )
2398         mpVScrollBar->SetRangeMax( GetEntryList()->GetEntryCount() );
2399     mpVScrollBar->SetThumbPos( GetTopEntry() );
2400 
2401     mpHScrollBar->SetThumbPos( GetLeftIndent() );
2402 
2403     maScrollHdl.Call( this );
2404 
2405     return 1;
2406 }
2407 
2408 // -----------------------------------------------------------------------
2409 
2410 IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
2411 {
2412     sal_uInt16 nPos = (sal_uInt16) pSB->GetThumbPos();
2413     if( pSB == mpVScrollBar )
2414         SetTopEntry( nPos );
2415     else if( pSB == mpHScrollBar )
2416         SetLeftIndent( nPos );
2417 
2418     return 1;
2419 }
2420 
2421 // -----------------------------------------------------------------------
2422 
2423 void ImplListBox::ImplCheckScrollBars()
2424 {
2425     sal_Bool bArrange = sal_False;
2426 
2427     Size aOutSz = GetOutputSizePixel();
2428     sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
2429     sal_uInt16 nMaxVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2430 
2431     // vert. ScrollBar
2432     if( nEntries > nMaxVisEntries )
2433     {
2434         if( !mbVScroll )
2435             bArrange = sal_True;
2436         mbVScroll = true;
2437 
2438         // Ueberpruefung des rausgescrollten Bereichs
2439         if( GetEntryList()->GetSelectEntryCount() == 1 &&
2440             GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2441             ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2442         else
2443             SetTopEntry( GetTopEntry() );   // MaxTop wird geprueft...
2444     }
2445     else
2446     {
2447         if( mbVScroll )
2448             bArrange = sal_True;
2449         mbVScroll = false;
2450         SetTopEntry( 0 );
2451     }
2452 
2453     // horz. ScrollBar
2454     if( mbAutoHScroll )
2455     {
2456         long nWidth = (sal_uInt16) aOutSz.Width();
2457         if ( mbVScroll )
2458             nWidth -= mpVScrollBar->GetSizePixel().Width();
2459 
2460         long nMaxWidth = GetMaxEntryWidth();
2461         if( nWidth < nMaxWidth )
2462         {
2463             if( !mbHScroll )
2464                 bArrange = sal_True;
2465             mbHScroll = true;
2466 
2467             if ( !mbVScroll )   // ggf. brauchen wir jetzt doch einen
2468             {
2469                 nMaxVisEntries = (sal_uInt16) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
2470                 if( nEntries > nMaxVisEntries )
2471                 {
2472                     bArrange = sal_True;
2473                     mbVScroll = true;
2474 
2475                     // Ueberpruefung des rausgescrollten Bereichs
2476                     if( GetEntryList()->GetSelectEntryCount() == 1 &&
2477                         GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2478                         ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2479                     else
2480                         SetTopEntry( GetTopEntry() );   // MaxTop wird geprueft...
2481                 }
2482             }
2483 
2484             // Ueberpruefung des rausgescrollten Bereichs
2485             sal_uInt16 nMaxLI = (sal_uInt16) (nMaxWidth - nWidth);
2486             if ( nMaxLI < GetLeftIndent() )
2487                 SetLeftIndent( nMaxLI );
2488         }
2489         else
2490         {
2491             if( mbHScroll )
2492                 bArrange = sal_True;
2493             mbHScroll = false;
2494             SetLeftIndent( 0 );
2495         }
2496     }
2497 
2498     if( bArrange )
2499         ImplResizeControls();
2500 
2501     ImplInitScrollBars();
2502 }
2503 
2504 // -----------------------------------------------------------------------
2505 
2506 void ImplListBox::ImplInitScrollBars()
2507 {
2508     Size aOutSz = maLBWindow.GetOutputSizePixel();
2509 
2510     if ( mbVScroll )
2511     {
2512         sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
2513         sal_uInt16 nVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2514         mpVScrollBar->SetRangeMax( nEntries );
2515         mpVScrollBar->SetVisibleSize( nVisEntries );
2516         mpVScrollBar->SetPageSize( nVisEntries - 1 );
2517     }
2518 
2519     if ( mbHScroll )
2520     {
2521         mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
2522         mpHScrollBar->SetVisibleSize( (sal_uInt16)aOutSz.Width() );
2523         mpHScrollBar->SetLineSize( HORZ_SCROLL );
2524         mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
2525     }
2526 }
2527 
2528 // -----------------------------------------------------------------------
2529 
2530 void ImplListBox::ImplResizeControls()
2531 {
2532     // Hier werden die Controls nur angeordnet, ob die Scrollbars
2533     // sichtbar sein sollen wird bereits in ImplCheckScrollBars ermittelt.
2534 
2535     Size aOutSz = GetOutputSizePixel();
2536     long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2537     nSBWidth = CalcZoom( nSBWidth );
2538 
2539     Size aInnerSz( aOutSz );
2540     if ( mbVScroll )
2541         aInnerSz.Width() -= nSBWidth;
2542     if ( mbHScroll )
2543         aInnerSz.Height() -= nSBWidth;
2544 
2545     // pb: #106948# explicit mirroring for calc
2546     // Scrollbar on left or right side?
2547     sal_Bool bMirroring = maLBWindow.IsMirroring();
2548     Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
2549     maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
2550 
2551     // ScrollBarBox
2552     if( mbVScroll && mbHScroll )
2553     {
2554         Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
2555         mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
2556         mpScrollBarBox->Show();
2557     }
2558     else
2559     {
2560         mpScrollBarBox->Hide();
2561     }
2562 
2563     // vert. ScrollBar
2564     if( mbVScroll )
2565     {
2566         // Scrollbar on left or right side?
2567         Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
2568         mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
2569         mpVScrollBar->Show();
2570     }
2571     else
2572     {
2573         mpVScrollBar->Hide();
2574         // #107254# Don't reset top entry after resize, but check for max top entry
2575         SetTopEntry( GetTopEntry() );
2576     }
2577 
2578     // horz. ScrollBar
2579     if( mbHScroll )
2580     {
2581         Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
2582         mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
2583         mpHScrollBar->Show();
2584     }
2585     else
2586     {
2587         mpHScrollBar->Hide();
2588         SetLeftIndent( 0 );
2589     }
2590 }
2591 
2592 // -----------------------------------------------------------------------
2593 
2594 void ImplListBox::StateChanged( StateChangedType nType )
2595 {
2596     if ( nType == STATE_CHANGE_INITSHOW )
2597     {
2598         ImplCheckScrollBars();
2599     }
2600     else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
2601     {
2602         sal_Bool bUpdate = IsUpdateMode();
2603         maLBWindow.SetUpdateMode( bUpdate );
2604 //      mpHScrollBar->SetUpdateMode( bUpdate );
2605 //      mpVScrollBar->SetUpdateMode( bUpdate );
2606         if ( bUpdate && IsReallyVisible() )
2607             ImplCheckScrollBars();
2608     }
2609     else if( nType == STATE_CHANGE_ENABLE )
2610     {
2611         mpHScrollBar->Enable( IsEnabled() );
2612         mpVScrollBar->Enable( IsEnabled() );
2613         mpScrollBarBox->Enable( IsEnabled() );
2614         Invalidate();
2615     }
2616     else if ( nType == STATE_CHANGE_ZOOM )
2617     {
2618         maLBWindow.SetZoom( GetZoom() );
2619         Resize();
2620     }
2621     else if ( nType == STATE_CHANGE_CONTROLFONT )
2622     {
2623         maLBWindow.SetControlFont( GetControlFont() );
2624     }
2625     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2626     {
2627         maLBWindow.SetControlForeground( GetControlForeground() );
2628     }
2629     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2630     {
2631         maLBWindow.SetControlBackground( GetControlBackground() );
2632     }
2633     else if( nType == STATE_CHANGE_MIRRORING )
2634     {
2635         maLBWindow.EnableRTL( IsRTLEnabled() );
2636         mpHScrollBar->EnableRTL( IsRTLEnabled() );
2637         mpVScrollBar->EnableRTL( IsRTLEnabled() );
2638         ImplResizeControls();
2639     }
2640 
2641     Control::StateChanged( nType );
2642 }
2643 
2644 // -----------------------------------------------------------------------
2645 
2646 void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
2647 {
2648 //  if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2649 //       (rDCEvt.GetFlags() & SETTINGS_STYLE) )
2650 //  {
2651 //      maLBWindow.SetSettings( GetSettings() );
2652 //      Resize();
2653 //  }
2654 //  else
2655         Control::DataChanged( rDCEvt );
2656 }
2657 
2658 // -----------------------------------------------------------------------
2659 
2660 long ImplListBox::Notify( NotifyEvent& rNEvt )
2661 {
2662     long nDone = 0;
2663     if ( rNEvt.GetType() == EVENT_COMMAND )
2664     {
2665         const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2666         if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2667         {
2668             const CommandWheelData* pData = rCEvt.GetWheelData();
2669             if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2670             {
2671                 nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
2672             }
2673         }
2674     }
2675 
2676     return nDone ? nDone : Window::Notify( rNEvt );
2677 }
2678 
2679 // -----------------------------------------------------------------------
2680 
2681 const Wallpaper& ImplListBox::GetDisplayBackground() const
2682 {
2683     return maLBWindow.GetDisplayBackground();
2684 }
2685 
2686 // -----------------------------------------------------------------------
2687 
2688 sal_Bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
2689 {
2690     sal_Bool bDone = sal_False;
2691     if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2692     {
2693         const CommandWheelData* pData = rCEvt.GetWheelData();
2694         if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2695         {
2696             sal_uInt16 nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
2697             KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
2698             bDone = ProcessKeyInput( aKeyEvent );
2699         }
2700     }
2701     return bDone;
2702 }
2703 
2704 // -----------------------------------------------------------------------
2705 
2706 void ImplListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
2707 {
2708     sal_Bool bChanges = GetEntryList()->GetMRUCount() ? sal_True : sal_False;
2709 
2710     // Remove old MRU entries
2711     for ( sal_uInt16 n = GetEntryList()->GetMRUCount();n; )
2712         maLBWindow.RemoveEntry( --n );
2713 
2714     sal_uInt16 nMRUCount = 0;
2715     sal_uInt16 nEntries = rEntries.GetTokenCount( cSep );
2716     for ( sal_uInt16 nEntry = 0; nEntry < nEntries; nEntry++ )
2717     {
2718         XubString aEntry = rEntries.GetToken( nEntry, cSep );
2719         // Accept only existing entries
2720         if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
2721         {
2722             ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
2723             maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, sal_False );
2724             bChanges = sal_True;
2725         }
2726     }
2727 
2728     if ( bChanges )
2729     {
2730         maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
2731         SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
2732         StateChanged( STATE_CHANGE_DATA );
2733     }
2734 }
2735 
2736 // -----------------------------------------------------------------------
2737 
2738 XubString ImplListBox::GetMRUEntries( xub_Unicode cSep ) const
2739 {
2740     String aEntries;
2741     for ( sal_uInt16 n = 0; n < GetEntryList()->GetMRUCount(); n++ )
2742     {
2743         aEntries += GetEntryList()->GetEntryText( n );
2744         if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
2745             aEntries += cSep;
2746     }
2747     return aEntries;
2748 }
2749 
2750 // -----------------------------------------------------------------------
2751 
2752 void ImplListBox::SetEdgeBlending(bool bNew)
2753 {
2754     if(mbEdgeBlending != bNew)
2755     {
2756         mbEdgeBlending = bNew;
2757         maLBWindow.SetEdgeBlending(GetEdgeBlending());
2758     }
2759 }
2760 
2761 // =======================================================================
2762 
2763 ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
2764     Control ( pParent, nWinStyle )
2765 {
2766     if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2767             && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2768         SetBackground();
2769     else
2770         SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2771 
2772     mbInUserDraw = false;
2773     mbUserDrawEnabled = false;
2774     mbEdgeBlending = false;
2775     mnItemPos = LISTBOX_ENTRY_NOTFOUND;
2776 }
2777 
2778 // -----------------------------------------------------------------------
2779 
2780 sal_Bool ImplWin::SetModeImage( const Image& rImage, BmpColorMode eMode )
2781 {
2782     if( eMode == BMP_COLOR_NORMAL )
2783         SetImage( rImage );
2784     else if( eMode == BMP_COLOR_HIGHCONTRAST )
2785         maImageHC = rImage;
2786     else
2787         return sal_False;
2788     return sal_True;
2789 }
2790 
2791 // -----------------------------------------------------------------------
2792 
2793 const Image& ImplWin::GetModeImage( BmpColorMode eMode ) const
2794 {
2795     if( eMode == BMP_COLOR_HIGHCONTRAST )
2796         return maImageHC;
2797     else
2798         return maImage;
2799 }
2800 
2801 // -----------------------------------------------------------------------
2802 
2803 void ImplWin::MBDown()
2804 {
2805     if( IsEnabled() )
2806         maMBDownHdl.Call( this );
2807 }
2808 
2809 // -----------------------------------------------------------------------
2810 
2811 void ImplWin::MouseButtonDown( const MouseEvent& )
2812 {
2813     if( IsEnabled() )
2814     {
2815 //      Control::MouseButtonDown( rMEvt );
2816         MBDown();
2817     }
2818 }
2819 
2820 // -----------------------------------------------------------------------
2821 
2822 void ImplWin::FillLayoutData() const
2823 {
2824     mpControlData->mpLayoutData = new vcl::ControlLayoutData();
2825     const_cast<ImplWin*>(this)->ImplDraw( true );
2826 }
2827 
2828 // -----------------------------------------------------------------------
2829 
2830 long ImplWin::PreNotify( NotifyEvent& rNEvt )
2831 {
2832     long nDone = 0;
2833     const MouseEvent* pMouseEvt = NULL;
2834 
2835     if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
2836     {
2837         if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
2838         {
2839             // trigger redraw as mouse over state has changed
2840             if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2841             && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2842             {
2843                 GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
2844                 GetParent()->GetWindow( WINDOW_BORDER )->Update();
2845             }
2846         }
2847     }
2848 
2849     return nDone ? nDone : Control::PreNotify(rNEvt);
2850 }
2851 
2852 // -----------------------------------------------------------------------
2853 
2854 void ImplWin::ImplDraw( bool bLayout )
2855 {
2856     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2857 
2858     sal_Bool bNativeOK = sal_False;
2859 
2860     if( ! bLayout )
2861     {
2862         ControlState nState = CTRL_STATE_ENABLED;
2863         if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2864             && IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
2865         {
2866             // Repaint the (focused) area similarly to
2867             // ImplSmallBorderWindowView::DrawWindow() in
2868             // vcl/source/window/brdwin.cxx
2869             Window *pWin = GetParent();
2870 
2871             ImplControlValue aControlValue;
2872             if ( !pWin->IsEnabled() )
2873             nState &= ~CTRL_STATE_ENABLED;
2874             if ( pWin->HasFocus() )
2875             nState |= CTRL_STATE_FOCUSED;
2876 
2877             // The listbox is painted over the entire control including the
2878             // border, but ImplWin does not contain the border => correction
2879             // needed.
2880             sal_Int32 nLeft, nTop, nRight, nBottom;
2881             pWin->GetBorder( nLeft, nTop, nRight, nBottom );
2882             Point aPoint( -nLeft, -nTop );
2883             Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
2884 
2885             sal_Bool bMouseOver = sal_False;
2886             if( GetParent() )
2887             {
2888                 Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
2889                 while( pChild && (bMouseOver = pChild->IsMouseOver()) == sal_False )
2890                     pChild = pChild->GetWindow( WINDOW_NEXT );
2891             }
2892 
2893             if( bMouseOver )
2894                 nState |= CTRL_STATE_ROLLOVER;
2895 
2896             // if parent has no border, then nobody has drawn the background
2897             // since no border window exists. so draw it here.
2898             WinBits nParentStyle = pWin->GetStyle();
2899             if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
2900             {
2901                 Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
2902                 pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentRect,
2903                                          nState, aControlValue, rtl::OUString() );
2904             }
2905 
2906             bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
2907                 aControlValue, rtl::OUString() );
2908         }
2909 
2910         if( IsEnabled() )
2911         {
2912             if( HasFocus() )
2913             {
2914                 SetTextColor( rStyleSettings.GetHighlightTextColor() );
2915                 SetFillColor( rStyleSettings.GetHighlightColor() );
2916                 DrawRect( maFocusRect );
2917             }
2918             else
2919             {
2920                 Color aColor;
2921                 if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
2922                     aColor = rStyleSettings.GetFieldRolloverTextColor();
2923                 else
2924                     aColor = rStyleSettings.GetFieldTextColor();
2925                 if( IsControlForeground() )
2926                     aColor = GetControlForeground();
2927                 SetTextColor( aColor );
2928                 if ( !bNativeOK )
2929                     Erase( maFocusRect );
2930             }
2931         }
2932         else // Disabled
2933         {
2934             SetTextColor( rStyleSettings.GetDisableColor() );
2935             if ( !bNativeOK )
2936                 Erase( maFocusRect );
2937         }
2938     }
2939 
2940     if ( IsUserDrawEnabled() )
2941     {
2942         mbInUserDraw = true;
2943         UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
2944         maUserDrawHdl.Call( &aUDEvt );
2945         mbInUserDraw = false;
2946     }
2947     else
2948     {
2949         DrawEntry( sal_True, sal_True, sal_False, bLayout );
2950     }
2951 }
2952 
2953 // -----------------------------------------------------------------------
2954 
2955 void ImplWin::Paint( const Rectangle& )
2956 {
2957     ImplDraw();
2958 }
2959 
2960 // -----------------------------------------------------------------------
2961 
2962 void ImplWin::DrawEntry( sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
2963 {
2964     long nBorder = 1;
2965     Size aOutSz = GetOutputSizePixel();
2966 
2967     sal_Bool bImage = !!maImage;
2968     if( bDrawImage && bImage && !bLayout )
2969     {
2970         sal_uInt16 nStyle = 0;
2971         Size aImgSz = maImage.GetSizePixel();
2972         Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
2973         const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2974 
2975         // check for HC mode
2976         Image *pImage = &maImage;
2977 
2978         if( !!maImageHC )
2979         {
2980             if( rStyleSettings.GetHighContrastMode() )
2981                 pImage = &maImageHC;
2982         }
2983 
2984         if ( !IsZoom() )
2985         {
2986             DrawImage( aPtImg, *pImage, nStyle );
2987         }
2988         else
2989         {
2990             aImgSz.Width() = CalcZoom( aImgSz.Width() );
2991             aImgSz.Height() = CalcZoom( aImgSz.Height() );
2992             DrawImage( aPtImg, aImgSz, *pImage, nStyle );
2993         }
2994 
2995         const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
2996 
2997         if(nEdgeBlendingPercent)
2998         {
2999             const Rectangle aRect(aPtImg, aImgSz);
3000             Bitmap aBitmap(GetBitmap(aRect.TopLeft(), aRect.GetSize()));
3001 
3002             if(!aBitmap.IsEmpty())
3003             {
3004                 const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
3005                 const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
3006                 const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
3007 
3008                 aBitmap.DrawBlendFrame(nAlpha, rTopLeft, rBottomRight);
3009                 DrawBitmap(aRect.TopLeft(), aBitmap);
3010             }
3011         }
3012     }
3013 
3014     if( bDrawText && maString.Len() )
3015     {
3016         sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
3017 
3018         if ( bDrawImage && bImage && !bLayout )
3019             nTextStyle |= TEXT_DRAW_LEFT;
3020         else if ( GetStyle() & WB_CENTER )
3021             nTextStyle |= TEXT_DRAW_CENTER;
3022         else if ( GetStyle() & WB_RIGHT )
3023             nTextStyle |= TEXT_DRAW_RIGHT;
3024         else
3025             nTextStyle |= TEXT_DRAW_LEFT;
3026 
3027         Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
3028 
3029         if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
3030         {
3031             long nMaxWidth = Max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
3032             aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
3033         }
3034 
3035         MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
3036         String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
3037         DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
3038     }
3039 
3040     if( HasFocus() && !bLayout )
3041         ShowFocus( maFocusRect );
3042 }
3043 
3044 // -----------------------------------------------------------------------
3045 
3046 void ImplWin::Resize()
3047 {
3048     Control::Resize();
3049     maFocusRect.SetSize( GetOutputSizePixel() );
3050     Invalidate();
3051 }
3052 
3053 // -----------------------------------------------------------------------
3054 
3055 void ImplWin::GetFocus()
3056 {
3057     ShowFocus( maFocusRect );
3058     if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3059         IsNativeWidgetEnabled() &&
3060         IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
3061     {
3062         Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
3063         if( ! pWin )
3064             pWin = GetParent();
3065         pWin->Invalidate();
3066     }
3067     else
3068         Invalidate();
3069     Control::GetFocus();
3070 }
3071 
3072 // -----------------------------------------------------------------------
3073 
3074 void ImplWin::LoseFocus()
3075 {
3076     HideFocus();
3077     if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3078         IsNativeWidgetEnabled() &&
3079         IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
3080     {
3081         Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
3082         if( ! pWin )
3083             pWin = GetParent();
3084         pWin->Invalidate();
3085     }
3086     else
3087         Invalidate();
3088     Control::LoseFocus();
3089 }
3090 
3091 // =======================================================================
3092 
3093 ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
3094     PushButton(  pParent, nWinStyle ),
3095     mbDown  ( sal_False )
3096 {
3097 }
3098 
3099 // -----------------------------------------------------------------------
3100 
3101 void ImplBtn::MBDown()
3102 {
3103     if( IsEnabled() )
3104        maMBDownHdl.Call( this );
3105 }
3106 
3107 // -----------------------------------------------------------------------
3108 
3109 void ImplBtn::MouseButtonDown( const MouseEvent& )
3110 {
3111     //PushButton::MouseButtonDown( rMEvt );
3112     if( IsEnabled() )
3113     {
3114         MBDown();
3115         mbDown = sal_True;
3116     }
3117 }
3118 
3119 // =======================================================================
3120 
3121 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
3122     FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW )    // no drop shadow for list boxes
3123 {
3124     mpImplLB = NULL;
3125     mnDDLineCount = 0;
3126     mbAutoWidth = sal_False;
3127 
3128     mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
3129 
3130     EnableSaveBackground();
3131 
3132     Window * pBorderWindow = ImplGetBorderWindow();
3133     if( pBorderWindow )
3134     {
3135         SetAccessibleRole(accessibility::AccessibleRole::PANEL);
3136         pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3137     }
3138     else
3139     {
3140         SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3141     }
3142 
3143 }
3144 
3145 // -----------------------------------------------------------------------
3146 
3147 long ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
3148 {
3149     if( rNEvt.GetType() == EVENT_LOSEFOCUS )
3150     {
3151         if( !GetParent()->HasChildPathFocus( sal_True ) )
3152             EndPopupMode();
3153     }
3154 
3155     return FloatingWindow::PreNotify( rNEvt );
3156 }
3157 
3158 // -----------------------------------------------------------------------
3159 
3160 void ImplListBoxFloatingWindow::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
3161 {
3162     FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
3163 
3164     // Fix #60890# ( MBA ): um auch im aufgeklappten Zustand der Listbox die Gr"o\se einfach zu einen
3165     // Aufruf von Resize() "andern zu k"onnen, wird die Position hier ggf. angepa\t
3166     if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
3167     {
3168         Point aPos = GetParent()->GetPosPixel();
3169         aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3170 
3171         if ( nFlags & WINDOW_POSSIZE_X )
3172             aPos.X() = nX;
3173 
3174         if ( nFlags & WINDOW_POSSIZE_Y )
3175             aPos.Y() = nY;
3176 
3177         sal_uInt16 nIndex;
3178         SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
3179     }
3180 
3181 //  if( !IsReallyVisible() )
3182     {
3183         // Die ImplListBox erhaelt kein Resize, weil nicht sichtbar.
3184         // Die Fenster muessen aber ein Resize() erhalten, damit die
3185         // Anzahl der sichtbaren Eintraege fuer PgUp/PgDown stimmt.
3186         // Die Anzahl kann auch nicht von List/Combobox berechnet werden,
3187         // weil hierfuer auch die ggf. vorhandene vertikale Scrollbar
3188         // beruecksichtigt werden muss.
3189         mpImplLB->SetSizePixel( GetOutputSizePixel() );
3190         ((Window*)mpImplLB)->Resize();
3191         ((Window*)mpImplLB->GetMainWindow())->Resize();
3192     }
3193 }
3194 
3195 // -----------------------------------------------------------------------
3196 
3197 void ImplListBoxFloatingWindow::Resize()
3198 {
3199     mpImplLB->GetMainWindow()->ImplClearLayoutData();
3200     FloatingWindow::Resize();
3201 }
3202 
3203 // -----------------------------------------------------------------------
3204 
3205 Size ImplListBoxFloatingWindow::CalcFloatSize()
3206 {
3207     Size aFloatSz( maPrefSz );
3208 
3209     sal_Int32 nLeft, nTop, nRight, nBottom;
3210     GetBorder( nLeft, nTop, nRight, nBottom );
3211 
3212     sal_uInt16 nLines = mpImplLB->GetEntryList()->GetEntryCount();
3213     if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
3214         nLines = mnDDLineCount;
3215 
3216     Size aSz = mpImplLB->CalcSize( nLines );
3217     long nMaxHeight = aSz.Height() + nTop + nBottom;
3218 
3219     if ( mnDDLineCount )
3220         aFloatSz.Height() = nMaxHeight;
3221 
3222     if( mbAutoWidth )
3223     {
3224         // AutoSize erstmal nur fuer die Breite...
3225 
3226         aFloatSz.Width() = aSz.Width() + nLeft + nRight;
3227         aFloatSz.Width() += nRight; // etwas mehr Platz sieht besser aus...
3228 
3229         if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
3230         {
3231             // dann wird noch der vertikale Scrollbar benoetigt
3232             long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
3233             aFloatSz.Width() += nSBWidth;
3234         }
3235     }
3236 
3237     if ( aFloatSz.Height() > nMaxHeight )
3238         aFloatSz.Height() = nMaxHeight;
3239 
3240     // Minimale Hoehe, falls Hoehe nicht auf Float-Hoehe eingestellt wurde.
3241     // Der Parent vom FloatWin muss die DropDown-Combo/Listbox sein.
3242     Size aParentSz = GetParent()->GetSizePixel();
3243     if( !mnDDLineCount && ( aFloatSz.Height() < aParentSz.Height() ) )
3244         aFloatSz.Height() = aParentSz.Height();
3245 
3246     // Nicht schmaler als der Parent werden...
3247     if( aFloatSz.Width() < aParentSz.Width() )
3248         aFloatSz.Width() = aParentSz.Width();
3249 
3250     // Hoehe auf Entries alignen...
3251     long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
3252     long nEntryHeight = mpImplLB->GetEntryHeight();
3253     if ( nInnerHeight % nEntryHeight )
3254     {
3255         nInnerHeight /= nEntryHeight;
3256         nInnerHeight++;
3257         nInnerHeight *= nEntryHeight;
3258         aFloatSz.Height() = nInnerHeight + nTop + nBottom;
3259     }
3260 
3261     return aFloatSz;
3262 }
3263 
3264 // -----------------------------------------------------------------------
3265 
3266 void ImplListBoxFloatingWindow::StartFloat( sal_Bool bStartTracking )
3267 {
3268     if( !IsInPopupMode() )
3269     {
3270         Size aFloatSz = CalcFloatSize();
3271 
3272         SetSizePixel( aFloatSz );
3273         mpImplLB->SetSizePixel( GetOutputSizePixel() );
3274 
3275         sal_uInt16 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
3276         mnPopupModeStartSaveSelection = nPos;
3277 
3278         Size aSz = GetParent()->GetSizePixel();
3279         Point aPos = GetParent()->GetPosPixel();
3280         aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3281         // FIXME: this ugly hack is for Mac/Aqua
3282         // should be replaced by a real mechanism to place the float rectangle
3283         if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3284             GetParent()->IsNativeWidgetEnabled() )
3285         {
3286             sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
3287             aPos.X() += nLeft;
3288             aPos.Y() += nTop;
3289             aSz.Width() -= nLeft + nRight;
3290             aSz.Height() -= nTop + nBottom;
3291         }
3292         Rectangle aRect( aPos, aSz );
3293 
3294         // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3295         // where the document is unmirrored
3296         // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3297         if( GetParent()->GetParent()->ImplIsAntiparallel() )
3298             GetParent()->GetParent()->ImplReMirror( aRect );
3299 
3300         StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
3301 
3302         if( nPos != LISTBOX_ENTRY_NOTFOUND )
3303             mpImplLB->ShowProminentEntry( nPos );
3304 
3305         if( bStartTracking )
3306             mpImplLB->GetMainWindow()->EnableMouseMoveSelect( sal_True );
3307 
3308         if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
3309             mpImplLB->GetMainWindow()->GrabFocus();
3310 
3311         mpImplLB->GetMainWindow()->ImplClearLayoutData();
3312     }
3313 }
3314