xref: /trunk/main/vcl/source/control/ilstbox.cxx (revision cbe4a5e32dd06077057875dd5ecd4d8f1991662a)
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                 //IAccessibility2 Impplementaton 2009-----
921                 sal_Bool bCurPosChange = (mnCurrentPos != nSelect);
922                 //SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() );
923                 SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() ,bCurPosChange);
924                 //-----IAccessibility2 Impplementaton 2009
925                 mbTrackingSelect = false;
926                 if ( mbGrabFocus )
927                     GrabFocus();
928 
929                 StartTracking( STARTTRACK_SCROLLREPEAT );
930             }
931         }
932         if( rMEvt.GetClicks() == 2 )
933         {
934             maDoubleClickHdl.Call( this );
935         }
936     }
937     else // if ( mbGrabFocus )
938     {
939         GrabFocus();
940     }
941 }
942 
943 // -----------------------------------------------------------------------
944 
945 void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
946 {
947     if ( rMEvt.IsLeaveWindow() )
948     {
949         if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
950         {
951             if ( rMEvt.GetPosPixel().Y() < 0 )
952             {
953                 DeselectAll();
954                 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
955                 SetTopEntry( 0 );
956                 if ( mbStackMode ) // #87072#, #92323#
957                 {
958                     mbTravelSelect = true;
959                     mnSelectModifier = rMEvt.GetModifier();
960                     ImplCallSelect();
961                     mbTravelSelect = false;
962                 }
963 
964             }
965         }
966     }
967     else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
968     {
969         Point aPoint;
970         Rectangle aRect( aPoint, GetOutputSizePixel() );
971         if( aRect.IsInside( rMEvt.GetPosPixel() ) )
972         {
973             if ( IsMouseMoveSelect() )
974             {
975                 sal_uInt16 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
976                 if( nSelect == LISTBOX_ENTRY_NOTFOUND )
977                     nSelect = mpEntryList->GetEntryCount() - 1;
978                 nSelect = Min( nSelect, GetLastVisibleEntry() );
979                 nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
980                 // Select only visible Entries with MouseMove, otherwise Tracking...
981                 if ( IsVisible( nSelect ) &&
982                     mpEntryList->IsEntrySelectable( nSelect ) &&
983                     ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
984                 {
985                     mbTrackingSelect = true;
986                     if ( SelectEntries( nSelect, LET_TRACKING, sal_False, sal_False ) )
987                     {
988                         if ( mbStackMode ) // #87072#
989                         {
990                             mbTravelSelect = true;
991                             mnSelectModifier = rMEvt.GetModifier();
992                             ImplCallSelect();
993                             mbTravelSelect = false;
994                         }
995 //IAccessibility2 Implementation 2009----
996                         // When list box selection change by mouse move, notity
997                         // VCLEVENT_LISTBOX_SELECT vcl event.
998                         else
999                         {
1000                             maListItemSelectHdl.Call(NULL);
1001                         }
1002 //----IAccessibility2 Implementation 2009
1003                     }
1004                     mbTrackingSelect = false;
1005                 }
1006             }
1007 
1008             // Falls der DD-Button gedrueckt wurde und jemand mit gedrueckter
1009             // Maustaste in die ListBox faehrt...
1010             if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
1011             {
1012                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1013                     mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
1014                 else
1015                     mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
1016 
1017                 if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
1018                     mpEntryList->SetSelectionAnchor( 0 );
1019 
1020                 StartTracking( STARTTRACK_SCROLLREPEAT );
1021             }
1022         }
1023     }
1024 }
1025 
1026 // -----------------------------------------------------------------------
1027 
1028 void ImplListBoxWindow::DeselectAll()
1029 {
1030     while ( GetEntryList()->GetSelectEntryCount() )
1031     {
1032         sal_uInt16 nS = GetEntryList()->GetSelectEntryPos( 0 );
1033         SelectEntry( nS, sal_False );
1034     }
1035 }
1036 
1037 // -----------------------------------------------------------------------
1038 
1039 void ImplListBoxWindow::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
1040 {
1041     if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
1042     {
1043         ImplHideFocusRect();
1044         if( bSelect )
1045         {
1046             if( !mbMulti )
1047             {
1048                 // Selektierten Eintrag deselektieren
1049                 sal_uInt16 nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
1050                 if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
1051                 {
1052                     //SelectEntryPos( nDeselect, sal_False );
1053                     GetEntryList()->SelectEntry( nDeselect, sal_False );
1054                     if ( IsUpdateMode() && IsReallyVisible() )
1055                         ImplPaint( nDeselect, sal_True );
1056                 }
1057             }
1058             mpEntryList->SelectEntry( nPos, sal_True );
1059             mnCurrentPos = nPos;
1060             if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
1061             {
1062                 ImplPaint( nPos );
1063                 if ( !IsVisible( nPos ) )
1064                 {
1065                     ImplClearLayoutData();
1066                     sal_uInt16 nVisibleEntries = GetLastVisibleEntry()-mnTop;
1067                     if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
1068                     {
1069                         Resize();
1070                         ShowProminentEntry( nPos );
1071                     }
1072                     else
1073                     {
1074                         ShowProminentEntry( nPos );
1075                     }
1076                 }
1077             }
1078         }
1079         else
1080         {
1081             mpEntryList->SelectEntry( nPos, sal_False );
1082             ImplPaint( nPos, sal_True );
1083         }
1084         mbSelectionChanged = true;
1085     }
1086 }
1087 
1088 // -----------------------------------------------------------------------
1089 
1090 sal_Bool ImplListBoxWindow::SelectEntries( sal_uInt16 nSelect, LB_EVENT_TYPE eLET, sal_Bool bShift, sal_Bool bCtrl, sal_Bool bSelectPosChange /*=FALSE*/ )
1091 {
1092     sal_Bool bFocusChanged = sal_False;
1093     sal_Bool bSelectionChanged = sal_False;
1094 
1095     if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
1096     {
1097         // Hier (Single-ListBox) kann nur ein Eintrag deselektiert werden
1098         if( !mbMulti )
1099         {
1100             sal_uInt16 nDeselect = mpEntryList->GetSelectEntryPos( 0 );
1101             if( nSelect != nDeselect )
1102             {
1103                 SelectEntry( nSelect, sal_True );
1104                 mpEntryList->SetLastSelected( nSelect );
1105                 bFocusChanged = sal_True;
1106                 bSelectionChanged = sal_True;
1107             }
1108         }
1109         // MultiListBox ohne Modifier
1110         else if( mbSimpleMode && !bCtrl && !bShift )
1111         {
1112             sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
1113             for ( sal_uInt16 nPos = 0; nPos < nEntryCount; nPos++ )
1114             {
1115                 sal_Bool bSelect = nPos == nSelect;
1116                 if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
1117                 {
1118                     SelectEntry( nPos, bSelect );
1119                     bFocusChanged = sal_True;
1120                     bSelectionChanged = sal_True;
1121                 }
1122             }
1123             mpEntryList->SetLastSelected( nSelect );
1124             mpEntryList->SetSelectionAnchor( nSelect );
1125         }
1126         // MultiListBox nur mit CTRL/SHIFT oder nicht im SimpleMode
1127         else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
1128         {
1129             // Space fuer Selektionswechsel
1130             if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
1131             {
1132                 sal_Bool bSelect = ( mbStackMode && IsMouseMoveSelect() ) ? sal_True : !mpEntryList->IsEntryPosSelected( nSelect );
1133                 if ( mbStackMode )
1134                 {
1135                     sal_uInt16 n;
1136                     if ( bSelect )
1137                     {
1138                         // All entries before nSelect must be selected...
1139                         for ( n = 0; n < nSelect; n++ )
1140                             SelectEntry( n, sal_True );
1141                     }
1142                     if ( !bSelect )
1143                     {
1144                         for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
1145                             SelectEntry( n, sal_False );
1146                     }
1147                 }
1148                 SelectEntry( nSelect, bSelect );
1149                 mpEntryList->SetLastSelected( nSelect );
1150                 mpEntryList->SetSelectionAnchor( mbStackMode ? 0 : nSelect );
1151                 if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1152                     mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND );
1153                 bFocusChanged = sal_True;
1154                 bSelectionChanged = sal_True;
1155             }
1156             else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
1157                      ( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
1158             {
1159                 mnCurrentPos = nSelect;
1160                 bFocusChanged = sal_True;
1161 
1162                 sal_uInt16 nAnchor = mpEntryList->GetSelectionAnchor();
1163                 if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
1164                 {
1165                     nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
1166                 }
1167                 if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
1168                 {
1169                     // Alle Eintraege vom Anchor bis nSelect muessen selektiert sein
1170                     sal_uInt16 nStart = Min( nSelect, nAnchor );
1171                     sal_uInt16 nEnd = Max( nSelect, nAnchor );
1172                     for ( sal_uInt16 n = nStart; n <= nEnd; n++ )
1173                     {
1174                         if ( !mpEntryList->IsEntryPosSelected( n ) )
1175                         {
1176                             SelectEntry( n, sal_True );
1177                             bSelectionChanged = sal_True;
1178                         }
1179                     }
1180 
1181                     // Ggf. muss noch was deselektiert werden...
1182                     sal_uInt16 nLast = mpEntryList->GetLastSelected();
1183                     if ( nLast != LISTBOX_ENTRY_NOTFOUND )
1184                     {
1185                         if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
1186                         {
1187                             for ( sal_uInt16 n = nSelect+1; n <= nLast; n++ )
1188                             {
1189                                 if ( mpEntryList->IsEntryPosSelected( n ) )
1190                                 {
1191                                     SelectEntry( n, sal_False );
1192                                     bSelectionChanged = sal_True;
1193                                 }
1194                             }
1195                         }
1196                         else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
1197                         {
1198                             for ( sal_uInt16 n = nLast; n < nSelect; n++ )
1199                             {
1200                                 if ( mpEntryList->IsEntryPosSelected( n ) )
1201                                 {
1202                                     SelectEntry( n, sal_False );
1203                                     bSelectionChanged = sal_True;
1204                                 }
1205                             }
1206                         }
1207                     }
1208                     mpEntryList->SetLastSelected( nSelect );
1209                 }
1210             }
1211             else if( eLET != LET_TRACKING )
1212             {
1213                 ImplHideFocusRect();
1214                 ImplPaint( nSelect, sal_True );
1215                 bFocusChanged = sal_True;
1216             }
1217         }
1218         else if( bShift )
1219         {
1220             bFocusChanged = sal_True;
1221         }
1222 
1223         if( bSelectionChanged )
1224             mbSelectionChanged = true;
1225 
1226         if( bFocusChanged )
1227         {
1228             long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop, 0 );
1229             maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1230             Size aSz( maFocusRect.GetWidth(),
1231                       mpEntryList->GetEntryHeight( nSelect ) );
1232             maFocusRect.SetSize( aSz );
1233             if( HasFocus() )
1234                 ImplShowFocusRect();
1235 //IAccessibility2 Implementation 2009----
1236             if (bSelectPosChange)
1237             {
1238                 maFocusHdl.Call(reinterpret_cast<void*>(nSelect));
1239             }
1240 //----IAccessibility2 Implementation 2009
1241         }
1242         ImplClearLayoutData();
1243     }
1244     return bSelectionChanged;
1245 }
1246 
1247 // -----------------------------------------------------------------------
1248 
1249 void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
1250 {
1251     Point aPoint;
1252     Rectangle aRect( aPoint, GetOutputSizePixel() );
1253     sal_Bool bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
1254 
1255     if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
1256     {
1257         if ( bInside && !rTEvt.IsTrackingCanceled() )
1258         {
1259             mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1260             ImplCallSelect();
1261         }
1262         else
1263         {
1264             maCancelHdl.Call( NULL );
1265             if ( !mbMulti )
1266             {
1267                 mbTrackingSelect = true;
1268                 SelectEntry( mnTrackingSaveSelection, sal_True );
1269                 mbTrackingSelect = false;
1270                 if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
1271                 {
1272                     long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1273                     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1274                     Size aSz( maFocusRect.GetWidth(),
1275                               mpEntryList->GetEntryHeight( mnCurrentPos ) );
1276                     maFocusRect.SetSize( aSz );
1277                     ImplShowFocusRect();
1278                 }
1279             }
1280         }
1281 
1282         mbTrack = false;
1283     }
1284     else
1285     {
1286         sal_Bool bTrackOrQuickClick = mbTrack;
1287         if( !mbTrack )
1288         {
1289             if ( bInside )
1290             {
1291                 mbTrack = true;
1292             }
1293 
1294             // Folgender Fall tritt nur auf, wenn man ganz kurz die Maustaste drueckt
1295             if( rTEvt.IsTrackingEnded() && mbTrack )
1296             {
1297                 bTrackOrQuickClick = sal_True;
1298                 mbTrack = false;
1299             }
1300         }
1301 
1302         if( bTrackOrQuickClick )
1303         {
1304             MouseEvent aMEvt = rTEvt.GetMouseEvent();
1305             Point aPt( aMEvt.GetPosPixel() );
1306             sal_Bool bShift = aMEvt.IsShift();
1307             sal_Bool bCtrl  = aMEvt.IsMod1();
1308 
1309             sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
1310             if( aPt.Y() < 0 )
1311             {
1312                 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1313                 {
1314                     nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
1315                     if( nSelect < mnTop )
1316                         SetTopEntry( mnTop-1 );
1317                 }
1318             }
1319             else if( aPt.Y() > GetOutputSizePixel().Height() )
1320             {
1321                 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1322                 {
1323                     nSelect = Min(  (sal_uInt16)(mnCurrentPos+1), (sal_uInt16)(mpEntryList->GetEntryCount()-1) );
1324                     if( nSelect >= GetLastVisibleEntry() )
1325                         SetTopEntry( mnTop+1 );
1326                 }
1327             }
1328             else
1329             {
1330                 nSelect = (sal_uInt16) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (sal_uInt16) mnTop;
1331                 nSelect = Min( nSelect, GetLastVisibleEntry() );
1332                 nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
1333             }
1334 
1335             if ( bInside )
1336             {
1337                 if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
1338                 {
1339                     mbTrackingSelect = true;
1340                     if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
1341                     {
1342                         if ( mbStackMode ) // #87734# (#87072#)
1343                         {
1344                             mbTravelSelect = true;
1345                             mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1346                             ImplCallSelect();
1347                             mbTravelSelect = false;
1348                         }
1349                     }
1350                     mbTrackingSelect = false;
1351                 }
1352             }
1353             else
1354             {
1355                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1356                 {
1357                     mbTrackingSelect = true;
1358                     SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), sal_False );
1359                     mbTrackingSelect = false;
1360                 }
1361                 else if ( mbStackMode )
1362                 {
1363                     if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 )  && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
1364                     {
1365                         if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1366                         {
1367                             sal_Bool bSelectionChanged = sal_False;
1368                             if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
1369                                    && !mnCurrentPos )
1370                             {
1371                                 if ( mpEntryList->IsEntryPosSelected( 0 ) )
1372                                 {
1373                                     SelectEntry( 0, sal_False );
1374                                     bSelectionChanged = sal_True;
1375                                     nSelect = LISTBOX_ENTRY_NOTFOUND;
1376 
1377                                 }
1378                             }
1379                             else
1380                             {
1381                                 mbTrackingSelect = true;
1382                                 bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
1383                                 mbTrackingSelect = false;
1384                             }
1385 
1386                             if ( bSelectionChanged )
1387                             {
1388                                 mbSelectionChanged = true;
1389                                 mbTravelSelect = true;
1390                                 mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1391                                 ImplCallSelect();
1392                                 mbTravelSelect = false;
1393                             }
1394                         }
1395                     }
1396                 }
1397             }
1398             mnCurrentPos = nSelect;
1399             if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1400             {
1401                 ImplHideFocusRect();
1402             }
1403             else
1404             {
1405                 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1406                 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1407                 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1408                 maFocusRect.SetSize( aSz );
1409                 ImplShowFocusRect();
1410             }
1411         }
1412     }
1413 }
1414 
1415 
1416 // -----------------------------------------------------------------------
1417 
1418 void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
1419 {
1420     if( !ProcessKeyInput( rKEvt ) )
1421         Control::KeyInput( rKEvt );
1422 }
1423 
1424 // -----------------------------------------------------------------------
1425 
1426 #define IMPL_SELECT_NODIRECTION 0
1427 #define IMPL_SELECT_UP          1
1428 #define IMPL_SELECT_DOWN        2
1429 
1430 sal_Bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
1431 {
1432     // zu selektierender Eintrag
1433     sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
1434     LB_EVENT_TYPE eLET = LET_KEYMOVE;
1435 
1436     KeyCode aKeyCode = rKEvt.GetKeyCode();
1437 
1438     sal_Bool bShift = aKeyCode.IsShift();
1439     sal_Bool bCtrl  = aKeyCode.IsMod1() || aKeyCode.IsMod3();
1440     sal_Bool bMod2 = aKeyCode.IsMod2();
1441     sal_Bool bDone = sal_False;
1442 
1443     switch( aKeyCode.GetCode() )
1444     {
1445         case KEY_UP:
1446         {
1447             if ( IsReadOnly() )
1448             {
1449                 if ( GetTopEntry() )
1450                     SetTopEntry( GetTopEntry()-1 );
1451             }
1452             else if ( !bMod2 )
1453             {
1454                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1455                 {
1456                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1457                 }
1458                 else if ( mnCurrentPos )
1459                 {
1460                     // search first selectable above the current position
1461                     nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
1462                 }
1463 
1464                 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
1465                     SetTopEntry( mnTop-1 );
1466 
1467                 bDone = sal_True;
1468             }
1469             maQuickSelectionEngine.Reset();
1470         }
1471         break;
1472 
1473         case KEY_DOWN:
1474         {
1475             if ( IsReadOnly() )
1476             {
1477                 SetTopEntry( GetTopEntry()+1 );
1478             }
1479             else if ( !bMod2 )
1480             {
1481                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1482                 {
1483                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1484                 }
1485                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1486                 {
1487                     // search first selectable below the current position
1488                     nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
1489                 }
1490 
1491                 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
1492                     SetTopEntry( mnTop+1 );
1493 
1494                 bDone = sal_True;
1495             }
1496             maQuickSelectionEngine.Reset();
1497         }
1498         break;
1499 
1500         case KEY_PAGEUP:
1501         {
1502             if ( IsReadOnly() )
1503             {
1504                 sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
1505                 SetTopEntry( ( mnTop > nCurVis ) ?
1506                                 (mnTop-nCurVis) : 0 );
1507             }
1508             else if ( !bCtrl && !bMod2 )
1509             {
1510                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1511                 {
1512                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1513                 }
1514                 else if ( mnCurrentPos )
1515                 {
1516                     if( mnCurrentPos == mnTop )
1517                     {
1518                         sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
1519                         SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
1520                     }
1521 
1522                     // find first selectable starting from mnTop looking foreward
1523                     nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
1524                 }
1525                 bDone = sal_True;
1526             }
1527             maQuickSelectionEngine.Reset();
1528         }
1529         break;
1530 
1531         case KEY_PAGEDOWN:
1532         {
1533             if ( IsReadOnly() )
1534             {
1535                 SetTopEntry( GetLastVisibleEntry() );
1536             }
1537             else if ( !bCtrl && !bMod2 )
1538             {
1539                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1540                 {
1541                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1542                 }
1543                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1544                 {
1545                     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1546                     sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop;
1547                     sal_uInt16 nTmp = Min( nCurVis, nCount );
1548                     nTmp += mnTop - 1;
1549                     if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
1550                     {
1551                         long nTmp2 = Min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
1552                         nTmp2 = Max( (long)0 , nTmp2 );
1553                         nTmp = (sal_uInt16)(nTmp2+(nCurVis-1) );
1554                         SetTopEntry( (sal_uInt16)nTmp2 );
1555                     }
1556                     // find first selectable starting from nTmp looking backwards
1557                     nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
1558                 }
1559                 bDone = sal_True;
1560             }
1561             maQuickSelectionEngine.Reset();
1562         }
1563         break;
1564 
1565         case KEY_HOME:
1566         {
1567             if ( IsReadOnly() )
1568             {
1569                 SetTopEntry( 0 );
1570             }
1571             else if ( !bCtrl && !bMod2 )
1572             {
1573                 if ( mnCurrentPos )
1574                 {
1575                     nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
1576                     if( mnTop != 0 )
1577                         SetTopEntry( 0 );
1578 
1579                     bDone = sal_True;
1580                 }
1581             }
1582             maQuickSelectionEngine.Reset();
1583         }
1584         break;
1585 
1586         case KEY_END:
1587         {
1588             if ( IsReadOnly() )
1589             {
1590                 SetTopEntry( 0xFFFF );
1591             }
1592             else if ( !bCtrl && !bMod2 )
1593             {
1594                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1595                 {
1596                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1597                 }
1598                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1599                 {
1600                     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1601                     nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
1602                     sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop + 1;
1603                     if( nCount > nCurVis )
1604                         SetTopEntry( nCount - nCurVis );
1605                 }
1606                 bDone = sal_True;
1607             }
1608             maQuickSelectionEngine.Reset();
1609         }
1610         break;
1611 
1612         case KEY_LEFT:
1613         {
1614             if ( !bCtrl && !bMod2 )
1615             {
1616                 ScrollHorz( -HORZ_SCROLL );
1617                 bDone = sal_True;
1618             }
1619             maQuickSelectionEngine.Reset();
1620         }
1621         break;
1622 
1623         case KEY_RIGHT:
1624         {
1625             if ( !bCtrl && !bMod2 )
1626             {
1627                 ScrollHorz( HORZ_SCROLL );
1628                 bDone = sal_True;
1629             }
1630             maQuickSelectionEngine.Reset();
1631         }
1632         break;
1633 
1634         case KEY_RETURN:
1635         {
1636             if ( !bMod2 && !IsReadOnly() )
1637             {
1638                 mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1639                 ImplCallSelect();
1640                 bDone = sal_False;  // RETURN nicht abfangen.
1641             }
1642             maQuickSelectionEngine.Reset();
1643         }
1644         break;
1645 
1646         case KEY_SPACE:
1647         {
1648             if ( !bMod2 && !IsReadOnly() )
1649             {
1650                 if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
1651                 {
1652                     nSelect = mnCurrentPos;
1653                     eLET = LET_KEYSPACE;
1654                 }
1655                 bDone = sal_True;
1656             }
1657             maQuickSelectionEngine.Reset();
1658         }
1659         break;
1660 
1661         case KEY_A:
1662         {
1663             if( bCtrl && mbMulti )
1664             {
1665                 // paint only once
1666                 sal_Bool bUpdates = IsUpdateMode();
1667                 SetUpdateMode( sal_False );
1668 
1669                 sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
1670                 for( sal_uInt16 i = 0; i < nEntryCount; i++ )
1671                     SelectEntry( i, sal_True );
1672 
1673                 // restore update mode
1674                 SetUpdateMode( bUpdates );
1675                 Invalidate();
1676 
1677                 maQuickSelectionEngine.Reset();
1678 
1679                 bDone = sal_True;
1680                 break;
1681             }
1682         }
1683         // fall through intentional
1684         default:
1685         {
1686             if ( !IsReadOnly() )
1687             {
1688                 bDone = maQuickSelectionEngine.HandleKeyEvent( rKEvt );
1689             }
1690         }
1691         break;
1692     }
1693 
1694     if  (   ( nSelect != LISTBOX_ENTRY_NOTFOUND )
1695         &&  (   ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1696             ||  ( eLET == LET_KEYSPACE )
1697             )
1698         )
1699     {
1700         DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
1701         if( nSelect >= mpEntryList->GetEntryCount() )
1702             nSelect = mpEntryList->GetEntryCount()-1;
1703 //IAccessibility2 Implementation 2009-----
1704         sal_Bool bCurPosChange = (mnCurrentPos != nSelect);
1705         mnCurrentPos = nSelect;
1706         //if ( SelectEntries( nSelect, eLET, bShift, bCtrl ) )
1707         if(SelectEntries( nSelect, eLET, bShift, bCtrl ,bCurPosChange))
1708 //-----IAccessibility2 Implementation 2009
1709         {
1710             mbTravelSelect = true;
1711             mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1712             ImplCallSelect();
1713             mbTravelSelect = false;
1714         }
1715     }
1716 
1717     return bDone;
1718 }
1719 
1720 // -----------------------------------------------------------------------
1721 namespace
1722 {
1723     static ::vcl::StringEntryIdentifier lcl_getEntry( const ImplEntryList& _rList, sal_uInt16 _nPos, String& _out_entryText )
1724     {
1725         OSL_PRECOND( ( _nPos != LISTBOX_ENTRY_NOTFOUND ), "lcl_getEntry: invalid position!" );
1726         sal_uInt16 nEntryCount( _rList.GetEntryCount() );
1727         if ( _nPos >= nEntryCount )
1728             _nPos = 0;
1729         _out_entryText = _rList.GetEntryText( _nPos );
1730 
1731         // ::vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1732         // => normalize
1733         return reinterpret_cast< ::vcl::StringEntryIdentifier >( _nPos + 1 );
1734     }
1735 
1736     static sal_uInt16 lcl_getEntryPos( ::vcl::StringEntryIdentifier _entry )
1737     {
1738         // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1739         return static_cast< sal_uInt16 >( reinterpret_cast< sal_Int64 >( _entry ) ) - 1;
1740     }
1741 }
1742 
1743 // -----------------------------------------------------------------------
1744 ::vcl::StringEntryIdentifier ImplListBoxWindow::CurrentEntry( String& _out_entryText ) const
1745 {
1746     return lcl_getEntry( *GetEntryList(), ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND ) ? 0 : mnCurrentPos + 1, _out_entryText );
1747 }
1748 
1749 // -----------------------------------------------------------------------
1750 ::vcl::StringEntryIdentifier ImplListBoxWindow::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, String& _out_entryText ) const
1751 {
1752     sal_uInt16 nNextPos = lcl_getEntryPos( _currentEntry ) + 1;
1753     return lcl_getEntry( *GetEntryList(), nNextPos, _out_entryText );
1754 }
1755 
1756 // -----------------------------------------------------------------------
1757 void ImplListBoxWindow::SelectEntry( ::vcl::StringEntryIdentifier _entry )
1758 {
1759     sal_uInt16 nSelect = lcl_getEntryPos( _entry );
1760     if ( mpEntryList->IsEntryPosSelected( nSelect ) )
1761     {
1762         // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1763         // to select the given entry by typing its starting letters. No need to act.
1764         return;
1765     }
1766 
1767     // normalize
1768     OSL_ENSURE( nSelect < mpEntryList->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1769     if( nSelect >= mpEntryList->GetEntryCount() )
1770         nSelect = mpEntryList->GetEntryCount()-1;
1771 
1772     // make visible
1773     ShowProminentEntry( nSelect );
1774 
1775     // actually select
1776     mnCurrentPos = nSelect;
1777     if ( SelectEntries( nSelect, LET_KEYMOVE, sal_False, sal_False ) )
1778     {
1779         mbTravelSelect = true;
1780         mnSelectModifier = 0;
1781         ImplCallSelect();
1782         mbTravelSelect = false;
1783     }
1784 }
1785 
1786 // -----------------------------------------------------------------------
1787 
1788 void ImplListBoxWindow::ImplPaint( sal_uInt16 nPos, sal_Bool bErase, bool bLayout )
1789 {
1790     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1791 
1792     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1793     if( ! pEntry )
1794         return;
1795 
1796     long nWidth  = GetOutputSizePixel().Width();
1797     long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1798     Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
1799 
1800     if( ! bLayout )
1801     {
1802         if( mpEntryList->IsEntryPosSelected( nPos ) )
1803         {
1804             SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
1805             SetFillColor( rStyleSettings.GetHighlightColor() );
1806             SetTextFillColor( rStyleSettings.GetHighlightColor() );
1807             DrawRect( aRect );
1808         }
1809         else
1810         {
1811             ImplInitSettings( sal_False, sal_True, sal_False );
1812             if( !IsEnabled() )
1813                 SetTextColor( rStyleSettings.GetDisableColor() );
1814             SetTextFillColor();
1815             if( bErase )
1816                 Erase( aRect );
1817         }
1818     }
1819 
1820     if ( IsUserDrawEnabled() )
1821     {
1822         mbInUserDraw = true;
1823         mnUserDrawEntry = nPos;
1824         aRect.Left() -= mnLeft;
1825         if ( nPos < GetEntryList()->GetMRUCount() )
1826             nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
1827         nPos = sal::static_int_cast<sal_uInt16>(nPos - GetEntryList()->GetMRUCount());
1828         UserDrawEvent aUDEvt( this, aRect, nPos, 0 );
1829         maUserDrawHdl.Call( &aUDEvt );
1830         mbInUserDraw = false;
1831     }
1832     else
1833     {
1834         DrawEntry( nPos, sal_True, sal_True, sal_False, bLayout );
1835     }
1836 }
1837 
1838 // -----------------------------------------------------------------------
1839 
1840 void ImplListBoxWindow::DrawEntry( sal_uInt16 nPos, sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
1841 {
1842     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1843     if( ! pEntry )
1844         return;
1845 
1846     // Bei Aenderungen in dieser Methode ggf. auch ImplWin::DrawEntry() anpassen.
1847 
1848     if ( mbInUserDraw )
1849         nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
1850 
1851     long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1852     Size aImgSz;
1853 
1854     if( bDrawImage && mpEntryList->HasImages() && !bLayout )
1855     {
1856         Image aImage = mpEntryList->GetEntryImage( nPos );
1857         if( !!aImage )
1858         {
1859             aImgSz = aImage.GetSizePixel();
1860             Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
1861 
1862             // pb: #106948# explicit mirroring for calc
1863             if ( mbMirroring )
1864                 // right aligned
1865                 aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
1866 
1867             if ( !IsZoom() )
1868             {
1869                 DrawImage( aPtImg, aImage );
1870             }
1871             else
1872             {
1873                 aImgSz.Width() = CalcZoom( aImgSz.Width() );
1874                 aImgSz.Height() = CalcZoom( aImgSz.Height() );
1875                 DrawImage( aPtImg, aImgSz, aImage );
1876             }
1877 
1878             const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1879             const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
1880 
1881             if(nEdgeBlendingPercent)
1882             {
1883                 const Rectangle aRect(aPtImg, aImgSz);
1884                 Bitmap aBitmap(GetBitmap(aRect.TopLeft(), aRect.GetSize()));
1885 
1886                 if(!aBitmap.IsEmpty())
1887                 {
1888                     const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
1889                     const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
1890                     const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
1891 
1892                     aBitmap.DrawBlendFrame(nAlpha, rTopLeft, rBottomRight);
1893                     DrawBitmap(aRect.TopLeft(), aBitmap);
1894                 }
1895             }
1896         }
1897     }
1898 
1899     if( bDrawText )
1900     {
1901         MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
1902         String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
1903         XubString aStr( mpEntryList->GetEntryText( nPos ) );
1904         if ( aStr.Len() )
1905         {
1906             long nMaxWidth = Max( static_cast< long >( mnMaxWidth ),
1907                                   GetOutputSizePixel().Width() - 2*mnBorder );
1908             // a multiline entry should only be as wide a the window
1909             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1910                 nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
1911 
1912             Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
1913                                  Size( nMaxWidth, pEntry->mnHeight ) );
1914 
1915             if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
1916             {
1917                 long nImageWidth = Max( mnMaxImgWidth, maUserItemSize.Width() );
1918                 aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
1919             }
1920 
1921             if( bLayout )
1922                 mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
1923 
1924             // pb: #106948# explicit mirroring for calc
1925             if ( mbMirroring )
1926             {
1927                 // right aligned
1928                 aTextRect.Left() = nMaxWidth + mnBorder - GetTextWidth( aStr ) - mnLeft;
1929                 if ( aImgSz.Width() > 0 )
1930                     aTextRect.Left() -= ( aImgSz.Width() + IMG_TXT_DISTANCE );
1931             }
1932 
1933             sal_uInt16 nDrawStyle = ImplGetTextStyle();
1934             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1935                 nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
1936             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) )
1937                 nDrawStyle |= TEXT_DRAW_DISABLE;
1938 
1939             DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
1940         }
1941     }
1942 
1943     if( !bLayout )
1944     {
1945         if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
1946              ( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
1947         {
1948             Color aOldLineColor( GetLineColor() );
1949             SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
1950             Point aStartPos( 0, nY );
1951             if ( nPos == mnSeparatorPos )
1952                 aStartPos.Y() += pEntry->mnHeight-1;
1953             Point aEndPos( aStartPos );
1954             aEndPos.X() = GetOutputSizePixel().Width();
1955             DrawLine( aStartPos, aEndPos );
1956             SetLineColor( aOldLineColor );
1957         }
1958     }
1959 }
1960 
1961 // -----------------------------------------------------------------------
1962 
1963 void ImplListBoxWindow::FillLayoutData() const
1964 {
1965     mpControlData->mpLayoutData = new vcl::ControlLayoutData();
1966     const_cast<ImplListBoxWindow*>(this)->
1967         ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
1968 }
1969 
1970 // -----------------------------------------------------------------------
1971 
1972 void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
1973 {
1974     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1975 
1976     sal_Bool bShowFocusRect = mbHasFocusRect;
1977     if ( mbHasFocusRect && ! bLayout )
1978         ImplHideFocusRect();
1979 
1980     long nY = 0; // + mnBorder;
1981     long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1982 
1983     for( sal_uInt16 i = (sal_uInt16)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
1984     {
1985         const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
1986         if( nY + pEntry->mnHeight >= rRect.Top() &&
1987             nY <= rRect.Bottom() + mnMaxHeight )
1988         {
1989             ImplPaint( i, sal_False, bLayout );
1990         }
1991         nY += pEntry->mnHeight;
1992     }
1993 
1994     long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1995     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1996     Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1997     maFocusRect.SetSize( aSz );
1998     if( HasFocus() && bShowFocusRect && !bLayout )
1999         ImplShowFocusRect();
2000 }
2001 
2002 // -----------------------------------------------------------------------
2003 
2004 void ImplListBoxWindow::Paint( const Rectangle& rRect )
2005 {
2006     ImplDoPaint( rRect );
2007 }
2008 
2009 // -----------------------------------------------------------------------
2010 
2011 sal_uInt16 ImplListBoxWindow::GetDisplayLineCount() const
2012 {
2013     // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2014 
2015     sal_uInt16 nCount = mpEntryList->GetEntryCount();
2016     long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
2017     sal_uInt16 nEntries = static_cast< sal_uInt16 >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
2018     if( nEntries > nCount-mnTop )
2019         nEntries = nCount-mnTop;
2020 
2021     return nEntries;
2022 }
2023 
2024 // -----------------------------------------------------------------------
2025 
2026 void ImplListBoxWindow::Resize()
2027 {
2028     Control::Resize();
2029 
2030     sal_Bool bShowFocusRect = mbHasFocusRect;
2031     if ( bShowFocusRect )
2032         ImplHideFocusRect();
2033 
2034     if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
2035     {
2036         Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
2037         maFocusRect.SetSize( aSz );
2038     }
2039 
2040     if ( bShowFocusRect )
2041         ImplShowFocusRect();
2042 
2043     ImplClearLayoutData();
2044 }
2045 
2046 // -----------------------------------------------------------------------
2047 
2048 void ImplListBoxWindow::GetFocus()
2049 {
2050     sal_uInt16 nPos = mnCurrentPos;
2051     if ( nPos == LISTBOX_ENTRY_NOTFOUND )
2052         nPos = 0;
2053     long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
2054     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
2055     Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
2056     maFocusRect.SetSize( aSz );
2057     ImplShowFocusRect();
2058     Control::GetFocus();
2059 }
2060 
2061 // -----------------------------------------------------------------------
2062 
2063 void ImplListBoxWindow::LoseFocus()
2064 {
2065     ImplHideFocusRect();
2066     Control::LoseFocus();
2067 }
2068 
2069 // -----------------------------------------------------------------------
2070 
2071 /*
2072 void ImplListBoxWindow::RequestHelp( const HelpEvent& rHEvt )
2073 {
2074     if ( rHEvt.GetMode() & HELPMODE_BALLOON )
2075         Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), String() );
2076 
2077     Window::RequestHelp( rHEvt );
2078 }
2079 */
2080 
2081 // -----------------------------------------------------------------------
2082 
2083 void ImplListBoxWindow::SetTopEntry( sal_uInt16 nTop )
2084 {
2085     if( mpEntryList->GetEntryCount() == 0 )
2086         return;
2087 
2088     long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2089 
2090     sal_uInt16 nLastEntry = mpEntryList->GetEntryCount()-1;
2091     if( nTop > nLastEntry )
2092         nTop = nLastEntry;
2093     const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
2094     while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
2095         nTop--;
2096 
2097     if ( nTop != mnTop )
2098     {
2099         ImplClearLayoutData();
2100         long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
2101         Update();
2102         ImplHideFocusRect();
2103         mnTop = nTop;
2104         Scroll( 0, nDiff );
2105         Update();
2106         if( HasFocus() )
2107             ImplShowFocusRect();
2108         maScrollHdl.Call( this );
2109     }
2110 }
2111 
2112 // -----------------------------------------------------------------------
2113 
2114 void ImplListBoxWindow::ShowProminentEntry( sal_uInt16 nEntryPos )
2115 {
2116     if( meProminentType == PROMINENT_MIDDLE )
2117     {
2118         sal_uInt16 nPos = nEntryPos;
2119         long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2120         while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
2121             nEntryPos--;
2122     }
2123     SetTopEntry( nEntryPos );
2124 }
2125 
2126 // -----------------------------------------------------------------------
2127 
2128 void ImplListBoxWindow::SetLeftIndent( long n )
2129 {
2130     ScrollHorz( n - mnLeft );
2131 }
2132 
2133 // -----------------------------------------------------------------------
2134 
2135 void ImplListBoxWindow::ScrollHorz( long n )
2136 {
2137     long nDiff = 0;
2138     if ( n > 0 )
2139     {
2140         long nWidth = GetOutputSizePixel().Width();
2141         if( ( mnMaxWidth - mnLeft + n ) > nWidth )
2142             nDiff = n;
2143     }
2144     else if ( n < 0 )
2145     {
2146         if( mnLeft )
2147         {
2148             long nAbs = -n;
2149             nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
2150         }
2151     }
2152 
2153     if ( nDiff )
2154     {
2155         ImplClearLayoutData();
2156         mnLeft = sal::static_int_cast<sal_uInt16>(mnLeft + nDiff);
2157         Update();
2158         ImplHideFocusRect();
2159         Scroll( -nDiff, 0 );
2160         Update();
2161         if( HasFocus() )
2162             ImplShowFocusRect();
2163         maScrollHdl.Call( this );
2164     }
2165 }
2166 
2167 // -----------------------------------------------------------------------
2168 
2169 Size ImplListBoxWindow::CalcSize( sal_uInt16 nMaxLines ) const
2170 {
2171     // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2172 
2173     Size aSz;
2174 //  sal_uInt16 nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
2175     aSz.Height() =  nMaxLines * mnMaxHeight;
2176     aSz.Width() = mnMaxWidth + 2*mnBorder;
2177     return aSz;
2178 }
2179 
2180 // -----------------------------------------------------------------------
2181 
2182 Rectangle ImplListBoxWindow::GetBoundingRectangle( sal_uInt16 nItem ) const
2183 {
2184     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
2185     Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
2186     //long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) - mpEntryList->GetAddedHeight( GetTopEntry() );
2187     //IAccessibility2 Impplementaton 2009-----
2188     long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeight();
2189     //-----IAccessibility2 Impplementaton 2009
2190     Rectangle aRect( Point( 0, nY ), aSz );
2191     return aRect;
2192 }
2193 
2194 
2195 // -----------------------------------------------------------------------
2196 
2197 void ImplListBoxWindow::StateChanged( StateChangedType nType )
2198 {
2199     Control::StateChanged( nType );
2200 
2201     if ( nType == STATE_CHANGE_ZOOM )
2202     {
2203         ImplInitSettings( sal_True, sal_False, sal_False );
2204         ImplCalcMetrics();
2205         Invalidate();
2206     }
2207     else if ( nType == STATE_CHANGE_UPDATEMODE )
2208     {
2209         if ( IsUpdateMode() && IsReallyVisible() )
2210             Invalidate();
2211     }
2212     else if ( nType == STATE_CHANGE_CONTROLFONT )
2213     {
2214         ImplInitSettings( sal_True, sal_False, sal_False );
2215         ImplCalcMetrics();
2216         Invalidate();
2217     }
2218     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2219     {
2220         ImplInitSettings( sal_False, sal_True, sal_False );
2221         Invalidate();
2222     }
2223     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2224     {
2225         ImplInitSettings( sal_False, sal_False, sal_True );
2226         Invalidate();
2227     }
2228     ImplClearLayoutData();
2229 }
2230 
2231 // -----------------------------------------------------------------------
2232 
2233 void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
2234 {
2235     Control::DataChanged( rDCEvt );
2236 
2237     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2238          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2239          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2240           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2241     {
2242         ImplClearLayoutData();
2243         ImplInitSettings( sal_True, sal_True, sal_True );
2244         ImplCalcMetrics();
2245         Invalidate();
2246     }
2247 }
2248 
2249 // -----------------------------------------------------------------------
2250 
2251 sal_uInt16 ImplListBoxWindow::ImplGetTextStyle() const
2252 {
2253     sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
2254 
2255     if ( mpEntryList->HasImages() )
2256         nTextStyle |= TEXT_DRAW_LEFT;
2257     else if ( mbCenter )
2258         nTextStyle |= TEXT_DRAW_CENTER;
2259     else if ( mbRight )
2260         nTextStyle |= TEXT_DRAW_RIGHT;
2261     else
2262         nTextStyle |= TEXT_DRAW_LEFT;
2263 
2264     return nTextStyle;
2265 }
2266 
2267 // =======================================================================
2268 
2269 ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
2270     Control( pParent, nWinStyle ),
2271     maLBWindow( this, nWinStyle&(~WB_BORDER) )
2272 {
2273     // for native widget rendering we must be able to detect this window type
2274     SetType( WINDOW_LISTBOXWINDOW );
2275 
2276     mpVScrollBar    = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
2277     mpHScrollBar    = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
2278     mpScrollBarBox  = new ScrollBarBox( this );
2279 
2280     Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
2281     mpVScrollBar->SetScrollHdl( aLink );
2282     mpHScrollBar->SetScrollHdl( aLink );
2283 
2284     mbVScroll       = false;
2285     mbHScroll       = false;
2286     mbAutoHScroll   = ( nWinStyle & WB_AUTOHSCROLL );
2287     mbEdgeBlending  = false;
2288 
2289     maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
2290     maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
2291     maLBWindow.SetEdgeBlending(GetEdgeBlending());
2292     maLBWindow.Show();
2293 }
2294 
2295 // -----------------------------------------------------------------------
2296 
2297 ImplListBox::~ImplListBox()
2298 {
2299     delete mpHScrollBar;
2300     delete mpVScrollBar;
2301     delete mpScrollBarBox;
2302 }
2303 
2304 // -----------------------------------------------------------------------
2305 
2306 void ImplListBox::Clear()
2307 {
2308     maLBWindow.Clear();
2309     if ( GetEntryList()->GetMRUCount() )
2310     {
2311         maLBWindow.GetEntryList()->SetMRUCount( 0 );
2312         maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
2313     }
2314     mpVScrollBar->SetThumbPos( 0 );
2315     mpHScrollBar->SetThumbPos( 0 );
2316     StateChanged( STATE_CHANGE_DATA );
2317 }
2318 
2319 // -----------------------------------------------------------------------
2320 
2321 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr )
2322 {
2323     ImplEntryType* pNewEntry = new ImplEntryType( rStr );
2324     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2325     StateChanged( STATE_CHANGE_DATA );
2326     return nNewPos;
2327 }
2328 
2329 // -----------------------------------------------------------------------
2330 
2331 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const Image& rImage )
2332 {
2333     ImplEntryType* pNewEntry = new ImplEntryType( rImage );
2334     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2335     StateChanged( STATE_CHANGE_DATA );
2336     return nNewPos;
2337 }
2338 
2339 // -----------------------------------------------------------------------
2340 
2341 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr, const Image& rImage )
2342 {
2343     ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
2344     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2345     StateChanged( STATE_CHANGE_DATA );
2346     return nNewPos;
2347 }
2348 
2349 // -----------------------------------------------------------------------
2350 
2351 void ImplListBox::RemoveEntry( sal_uInt16 nPos )
2352 {
2353     maLBWindow.RemoveEntry( nPos );
2354     StateChanged( STATE_CHANGE_DATA );
2355 }
2356 
2357 // -----------------------------------------------------------------------
2358 
2359 void ImplListBox::SetEntryFlags( sal_uInt16 nPos, long nFlags )
2360 {
2361     maLBWindow.SetEntryFlags( nPos, nFlags );
2362 }
2363 
2364 // -----------------------------------------------------------------------
2365 
2366 long ImplListBox::GetEntryFlags( sal_uInt16 nPos ) const
2367 {
2368     return maLBWindow.GetEntryList()->GetEntryFlags( nPos );
2369 }
2370 
2371 // -----------------------------------------------------------------------
2372 
2373 void ImplListBox::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
2374 {
2375     maLBWindow.SelectEntry( nPos, bSelect );
2376 }
2377 
2378 // -----------------------------------------------------------------------
2379 
2380 void ImplListBox::SetNoSelection()
2381 {
2382     maLBWindow.DeselectAll();
2383 }
2384 
2385 // -----------------------------------------------------------------------
2386 
2387 void ImplListBox::GetFocus()
2388 {
2389     maLBWindow.GrabFocus();
2390 }
2391 
2392 // -----------------------------------------------------------------------
2393 
2394 Window* ImplListBox::GetPreferredKeyInputWindow()
2395 {
2396     return &maLBWindow;
2397 }
2398 
2399 // -----------------------------------------------------------------------
2400 
2401 void ImplListBox::Resize()
2402 {
2403     Control::Resize();
2404     ImplResizeControls();
2405     ImplCheckScrollBars();
2406 }
2407 
2408 
2409 // -----------------------------------------------------------------------
2410 
2411 IMPL_LINK( ImplListBox, MRUChanged, void*, EMPTYARG )
2412 {
2413     StateChanged( STATE_CHANGE_DATA );
2414     return 1;
2415 }
2416 
2417 // -----------------------------------------------------------------------
2418 
2419 IMPL_LINK( ImplListBox, LBWindowScrolled, void*, EMPTYARG )
2420 {
2421     long nSet = GetTopEntry();
2422     if( nSet > mpVScrollBar->GetRangeMax() )
2423         mpVScrollBar->SetRangeMax( GetEntryList()->GetEntryCount() );
2424     mpVScrollBar->SetThumbPos( GetTopEntry() );
2425 
2426     mpHScrollBar->SetThumbPos( GetLeftIndent() );
2427 
2428     maScrollHdl.Call( this );
2429 
2430     return 1;
2431 }
2432 
2433 // -----------------------------------------------------------------------
2434 
2435 IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
2436 {
2437     sal_uInt16 nPos = (sal_uInt16) pSB->GetThumbPos();
2438     if( pSB == mpVScrollBar )
2439         SetTopEntry( nPos );
2440     else if( pSB == mpHScrollBar )
2441         SetLeftIndent( nPos );
2442 
2443     return 1;
2444 }
2445 
2446 // -----------------------------------------------------------------------
2447 
2448 void ImplListBox::ImplCheckScrollBars()
2449 {
2450     sal_Bool bArrange = sal_False;
2451 
2452     Size aOutSz = GetOutputSizePixel();
2453     sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
2454     sal_uInt16 nMaxVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2455 
2456     // vert. ScrollBar
2457     if( nEntries > nMaxVisEntries )
2458     {
2459         if( !mbVScroll )
2460             bArrange = sal_True;
2461         mbVScroll = true;
2462 
2463         // Ueberpruefung des rausgescrollten Bereichs
2464         if( GetEntryList()->GetSelectEntryCount() == 1 &&
2465             GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2466             ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2467         else
2468             SetTopEntry( GetTopEntry() );   // MaxTop wird geprueft...
2469     }
2470     else
2471     {
2472         if( mbVScroll )
2473             bArrange = sal_True;
2474         mbVScroll = false;
2475         SetTopEntry( 0 );
2476     }
2477 
2478     // horz. ScrollBar
2479     if( mbAutoHScroll )
2480     {
2481         long nWidth = (sal_uInt16) aOutSz.Width();
2482         if ( mbVScroll )
2483             nWidth -= mpVScrollBar->GetSizePixel().Width();
2484 
2485         long nMaxWidth = GetMaxEntryWidth();
2486         if( nWidth < nMaxWidth )
2487         {
2488             if( !mbHScroll )
2489                 bArrange = sal_True;
2490             mbHScroll = true;
2491 
2492             if ( !mbVScroll )   // ggf. brauchen wir jetzt doch einen
2493             {
2494                 nMaxVisEntries = (sal_uInt16) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
2495                 if( nEntries > nMaxVisEntries )
2496                 {
2497                     bArrange = sal_True;
2498                     mbVScroll = true;
2499 
2500                     // Ueberpruefung des rausgescrollten Bereichs
2501                     if( GetEntryList()->GetSelectEntryCount() == 1 &&
2502                         GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2503                         ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2504                     else
2505                         SetTopEntry( GetTopEntry() );   // MaxTop wird geprueft...
2506                 }
2507             }
2508 
2509             // Ueberpruefung des rausgescrollten Bereichs
2510             sal_uInt16 nMaxLI = (sal_uInt16) (nMaxWidth - nWidth);
2511             if ( nMaxLI < GetLeftIndent() )
2512                 SetLeftIndent( nMaxLI );
2513         }
2514         else
2515         {
2516             if( mbHScroll )
2517                 bArrange = sal_True;
2518             mbHScroll = false;
2519             SetLeftIndent( 0 );
2520         }
2521     }
2522 
2523     if( bArrange )
2524         ImplResizeControls();
2525 
2526     ImplInitScrollBars();
2527 }
2528 
2529 // -----------------------------------------------------------------------
2530 
2531 void ImplListBox::ImplInitScrollBars()
2532 {
2533     Size aOutSz = maLBWindow.GetOutputSizePixel();
2534 
2535     if ( mbVScroll )
2536     {
2537         sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
2538         sal_uInt16 nVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2539         mpVScrollBar->SetRangeMax( nEntries );
2540         mpVScrollBar->SetVisibleSize( nVisEntries );
2541         mpVScrollBar->SetPageSize( nVisEntries - 1 );
2542     }
2543 
2544     if ( mbHScroll )
2545     {
2546         mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
2547         mpHScrollBar->SetVisibleSize( (sal_uInt16)aOutSz.Width() );
2548         mpHScrollBar->SetLineSize( HORZ_SCROLL );
2549         mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
2550     }
2551 }
2552 
2553 // -----------------------------------------------------------------------
2554 
2555 void ImplListBox::ImplResizeControls()
2556 {
2557     // Hier werden die Controls nur angeordnet, ob die Scrollbars
2558     // sichtbar sein sollen wird bereits in ImplCheckScrollBars ermittelt.
2559 
2560     Size aOutSz = GetOutputSizePixel();
2561     long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2562     nSBWidth = CalcZoom( nSBWidth );
2563 
2564     Size aInnerSz( aOutSz );
2565     if ( mbVScroll )
2566         aInnerSz.Width() -= nSBWidth;
2567     if ( mbHScroll )
2568         aInnerSz.Height() -= nSBWidth;
2569 
2570     // pb: #106948# explicit mirroring for calc
2571     // Scrollbar on left or right side?
2572     sal_Bool bMirroring = maLBWindow.IsMirroring();
2573     Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
2574     maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
2575 
2576     // ScrollBarBox
2577     if( mbVScroll && mbHScroll )
2578     {
2579         Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
2580         mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
2581         mpScrollBarBox->Show();
2582     }
2583     else
2584     {
2585         mpScrollBarBox->Hide();
2586     }
2587 
2588     // vert. ScrollBar
2589     if( mbVScroll )
2590     {
2591         // Scrollbar on left or right side?
2592         Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
2593         mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
2594         mpVScrollBar->Show();
2595     }
2596     else
2597     {
2598         mpVScrollBar->Hide();
2599         // #107254# Don't reset top entry after resize, but check for max top entry
2600         SetTopEntry( GetTopEntry() );
2601     }
2602 
2603     // horz. ScrollBar
2604     if( mbHScroll )
2605     {
2606         Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
2607         mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
2608         mpHScrollBar->Show();
2609     }
2610     else
2611     {
2612         mpHScrollBar->Hide();
2613         SetLeftIndent( 0 );
2614     }
2615 }
2616 
2617 // -----------------------------------------------------------------------
2618 
2619 void ImplListBox::StateChanged( StateChangedType nType )
2620 {
2621     if ( nType == STATE_CHANGE_INITSHOW )
2622     {
2623         ImplCheckScrollBars();
2624     }
2625     else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
2626     {
2627         sal_Bool bUpdate = IsUpdateMode();
2628         maLBWindow.SetUpdateMode( bUpdate );
2629 //      mpHScrollBar->SetUpdateMode( bUpdate );
2630 //      mpVScrollBar->SetUpdateMode( bUpdate );
2631         if ( bUpdate && IsReallyVisible() )
2632             ImplCheckScrollBars();
2633     }
2634     else if( nType == STATE_CHANGE_ENABLE )
2635     {
2636         mpHScrollBar->Enable( IsEnabled() );
2637         mpVScrollBar->Enable( IsEnabled() );
2638         mpScrollBarBox->Enable( IsEnabled() );
2639         Invalidate();
2640     }
2641     else if ( nType == STATE_CHANGE_ZOOM )
2642     {
2643         maLBWindow.SetZoom( GetZoom() );
2644         Resize();
2645     }
2646     else if ( nType == STATE_CHANGE_CONTROLFONT )
2647     {
2648         maLBWindow.SetControlFont( GetControlFont() );
2649     }
2650     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2651     {
2652         maLBWindow.SetControlForeground( GetControlForeground() );
2653     }
2654     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2655     {
2656         maLBWindow.SetControlBackground( GetControlBackground() );
2657     }
2658     else if( nType == STATE_CHANGE_MIRRORING )
2659     {
2660         maLBWindow.EnableRTL( IsRTLEnabled() );
2661         mpHScrollBar->EnableRTL( IsRTLEnabled() );
2662         mpVScrollBar->EnableRTL( IsRTLEnabled() );
2663         ImplResizeControls();
2664     }
2665 
2666     Control::StateChanged( nType );
2667 }
2668 
2669 // -----------------------------------------------------------------------
2670 
2671 void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
2672 {
2673 //  if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2674 //       (rDCEvt.GetFlags() & SETTINGS_STYLE) )
2675 //  {
2676 //      maLBWindow.SetSettings( GetSettings() );
2677 //      Resize();
2678 //  }
2679 //  else
2680         Control::DataChanged( rDCEvt );
2681 }
2682 
2683 // -----------------------------------------------------------------------
2684 
2685 long ImplListBox::Notify( NotifyEvent& rNEvt )
2686 {
2687     long nDone = 0;
2688     if ( rNEvt.GetType() == EVENT_COMMAND )
2689     {
2690         const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2691         if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2692         {
2693             const CommandWheelData* pData = rCEvt.GetWheelData();
2694             if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2695             {
2696                 nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
2697             }
2698         }
2699     }
2700 
2701     return nDone ? nDone : Window::Notify( rNEvt );
2702 }
2703 
2704 // -----------------------------------------------------------------------
2705 
2706 const Wallpaper& ImplListBox::GetDisplayBackground() const
2707 {
2708     return maLBWindow.GetDisplayBackground();
2709 }
2710 
2711 // -----------------------------------------------------------------------
2712 
2713 sal_Bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
2714 {
2715     sal_Bool bDone = sal_False;
2716     if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2717     {
2718         const CommandWheelData* pData = rCEvt.GetWheelData();
2719         if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2720         {
2721             sal_uInt16 nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
2722             KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
2723             bDone = ProcessKeyInput( aKeyEvent );
2724         }
2725     }
2726     return bDone;
2727 }
2728 
2729 // -----------------------------------------------------------------------
2730 
2731 void ImplListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
2732 {
2733     sal_Bool bChanges = GetEntryList()->GetMRUCount() ? sal_True : sal_False;
2734 
2735     // Remove old MRU entries
2736     for ( sal_uInt16 n = GetEntryList()->GetMRUCount();n; )
2737         maLBWindow.RemoveEntry( --n );
2738 
2739     sal_uInt16 nMRUCount = 0;
2740     sal_uInt16 nEntries = rEntries.GetTokenCount( cSep );
2741     for ( sal_uInt16 nEntry = 0; nEntry < nEntries; nEntry++ )
2742     {
2743         XubString aEntry = rEntries.GetToken( nEntry, cSep );
2744         // Accept only existing entries
2745         if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
2746         {
2747             ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
2748             maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, sal_False );
2749             bChanges = sal_True;
2750         }
2751     }
2752 
2753     if ( bChanges )
2754     {
2755         maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
2756         SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
2757         StateChanged( STATE_CHANGE_DATA );
2758     }
2759 }
2760 
2761 // -----------------------------------------------------------------------
2762 
2763 XubString ImplListBox::GetMRUEntries( xub_Unicode cSep ) const
2764 {
2765     String aEntries;
2766     for ( sal_uInt16 n = 0; n < GetEntryList()->GetMRUCount(); n++ )
2767     {
2768         aEntries += GetEntryList()->GetEntryText( n );
2769         if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
2770             aEntries += cSep;
2771     }
2772     return aEntries;
2773 }
2774 
2775 // -----------------------------------------------------------------------
2776 
2777 void ImplListBox::SetEdgeBlending(bool bNew)
2778 {
2779     if(mbEdgeBlending != bNew)
2780     {
2781         mbEdgeBlending = bNew;
2782         maLBWindow.SetEdgeBlending(GetEdgeBlending());
2783     }
2784 }
2785 
2786 // =======================================================================
2787 
2788 ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
2789     Control ( pParent, nWinStyle )
2790 {
2791     if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2792             && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2793         SetBackground();
2794     else
2795         SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2796 
2797     mbInUserDraw = false;
2798     mbUserDrawEnabled = false;
2799     mbEdgeBlending = false;
2800     mnItemPos = LISTBOX_ENTRY_NOTFOUND;
2801 }
2802 
2803 // -----------------------------------------------------------------------
2804 
2805 sal_Bool ImplWin::SetModeImage( const Image& rImage, BmpColorMode eMode )
2806 {
2807     if( eMode == BMP_COLOR_NORMAL )
2808         SetImage( rImage );
2809     else if( eMode == BMP_COLOR_HIGHCONTRAST )
2810         maImageHC = rImage;
2811     else
2812         return sal_False;
2813     return sal_True;
2814 }
2815 
2816 // -----------------------------------------------------------------------
2817 
2818 const Image& ImplWin::GetModeImage( BmpColorMode eMode ) const
2819 {
2820     if( eMode == BMP_COLOR_HIGHCONTRAST )
2821         return maImageHC;
2822     else
2823         return maImage;
2824 }
2825 
2826 // -----------------------------------------------------------------------
2827 
2828 void ImplWin::MBDown()
2829 {
2830     if( IsEnabled() )
2831         maMBDownHdl.Call( this );
2832 }
2833 
2834 // -----------------------------------------------------------------------
2835 
2836 void ImplWin::MouseButtonDown( const MouseEvent& )
2837 {
2838     if( IsEnabled() )
2839     {
2840 //      Control::MouseButtonDown( rMEvt );
2841         MBDown();
2842     }
2843 }
2844 
2845 // -----------------------------------------------------------------------
2846 
2847 void ImplWin::FillLayoutData() const
2848 {
2849     mpControlData->mpLayoutData = new vcl::ControlLayoutData();
2850     const_cast<ImplWin*>(this)->ImplDraw( true );
2851 }
2852 
2853 // -----------------------------------------------------------------------
2854 
2855 long ImplWin::PreNotify( NotifyEvent& rNEvt )
2856 {
2857     long nDone = 0;
2858     const MouseEvent* pMouseEvt = NULL;
2859 
2860     if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
2861     {
2862         if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
2863         {
2864             // trigger redraw as mouse over state has changed
2865             if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2866             && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2867             {
2868                 GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
2869                 GetParent()->GetWindow( WINDOW_BORDER )->Update();
2870             }
2871         }
2872     }
2873 
2874     return nDone ? nDone : Control::PreNotify(rNEvt);
2875 }
2876 
2877 // -----------------------------------------------------------------------
2878 
2879 void ImplWin::ImplDraw( bool bLayout )
2880 {
2881     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2882 
2883     sal_Bool bNativeOK = sal_False;
2884 
2885     if( ! bLayout )
2886     {
2887         ControlState nState = CTRL_STATE_ENABLED;
2888         if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2889             && IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
2890         {
2891             // Repaint the (focused) area similarly to
2892             // ImplSmallBorderWindowView::DrawWindow() in
2893             // vcl/source/window/brdwin.cxx
2894             Window *pWin = GetParent();
2895 
2896             ImplControlValue aControlValue;
2897             if ( !pWin->IsEnabled() )
2898             nState &= ~CTRL_STATE_ENABLED;
2899             if ( pWin->HasFocus() )
2900             nState |= CTRL_STATE_FOCUSED;
2901 
2902             // The listbox is painted over the entire control including the
2903             // border, but ImplWin does not contain the border => correction
2904             // needed.
2905             sal_Int32 nLeft, nTop, nRight, nBottom;
2906             pWin->GetBorder( nLeft, nTop, nRight, nBottom );
2907             Point aPoint( -nLeft, -nTop );
2908             Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
2909 
2910             sal_Bool bMouseOver = sal_False;
2911             if( GetParent() )
2912             {
2913                 Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
2914                 while( pChild && (bMouseOver = pChild->IsMouseOver()) == sal_False )
2915                     pChild = pChild->GetWindow( WINDOW_NEXT );
2916             }
2917 
2918             if( bMouseOver )
2919                 nState |= CTRL_STATE_ROLLOVER;
2920 
2921             // if parent has no border, then nobody has drawn the background
2922             // since no border window exists. so draw it here.
2923             WinBits nParentStyle = pWin->GetStyle();
2924             if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
2925             {
2926                 Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
2927                 pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentRect,
2928                                          nState, aControlValue, rtl::OUString() );
2929             }
2930 
2931             bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
2932                 aControlValue, rtl::OUString() );
2933         }
2934 
2935         if( IsEnabled() )
2936         {
2937             if( HasFocus() )
2938             {
2939                 SetTextColor( rStyleSettings.GetHighlightTextColor() );
2940                 SetFillColor( rStyleSettings.GetHighlightColor() );
2941                 DrawRect( maFocusRect );
2942             }
2943             else
2944             {
2945                 Color aColor;
2946                 if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
2947                     aColor = rStyleSettings.GetFieldRolloverTextColor();
2948                 else
2949                     aColor = rStyleSettings.GetFieldTextColor();
2950                 if( IsControlForeground() )
2951                     aColor = GetControlForeground();
2952                 SetTextColor( aColor );
2953                 if ( !bNativeOK )
2954                     Erase( maFocusRect );
2955             }
2956         }
2957         else // Disabled
2958         {
2959             SetTextColor( rStyleSettings.GetDisableColor() );
2960             if ( !bNativeOK )
2961                 Erase( maFocusRect );
2962         }
2963     }
2964 
2965     if ( IsUserDrawEnabled() )
2966     {
2967         mbInUserDraw = true;
2968         UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
2969         maUserDrawHdl.Call( &aUDEvt );
2970         mbInUserDraw = false;
2971     }
2972     else
2973     {
2974         DrawEntry( sal_True, sal_True, sal_False, bLayout );
2975     }
2976 }
2977 
2978 // -----------------------------------------------------------------------
2979 
2980 void ImplWin::Paint( const Rectangle& )
2981 {
2982     ImplDraw();
2983 }
2984 
2985 // -----------------------------------------------------------------------
2986 
2987 void ImplWin::DrawEntry( sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
2988 {
2989     long nBorder = 1;
2990     Size aOutSz = GetOutputSizePixel();
2991 
2992     sal_Bool bImage = !!maImage;
2993     if( bDrawImage && bImage && !bLayout )
2994     {
2995         sal_uInt16 nStyle = 0;
2996         Size aImgSz = maImage.GetSizePixel();
2997         Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
2998         const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2999 
3000         // check for HC mode
3001         Image *pImage = &maImage;
3002 
3003         if( !!maImageHC )
3004         {
3005             if( rStyleSettings.GetHighContrastMode() )
3006                 pImage = &maImageHC;
3007         }
3008 
3009         if ( !IsZoom() )
3010         {
3011             DrawImage( aPtImg, *pImage, nStyle );
3012         }
3013         else
3014         {
3015             aImgSz.Width() = CalcZoom( aImgSz.Width() );
3016             aImgSz.Height() = CalcZoom( aImgSz.Height() );
3017             DrawImage( aPtImg, aImgSz, *pImage, nStyle );
3018         }
3019 
3020         const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
3021 
3022         if(nEdgeBlendingPercent)
3023         {
3024             const Rectangle aRect(aPtImg, aImgSz);
3025             Bitmap aBitmap(GetBitmap(aRect.TopLeft(), aRect.GetSize()));
3026 
3027             if(!aBitmap.IsEmpty())
3028             {
3029                 const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
3030                 const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
3031                 const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
3032 
3033                 aBitmap.DrawBlendFrame(nAlpha, rTopLeft, rBottomRight);
3034                 DrawBitmap(aRect.TopLeft(), aBitmap);
3035             }
3036         }
3037     }
3038 
3039     if( bDrawText && maString.Len() )
3040     {
3041         sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
3042 
3043         if ( bDrawImage && bImage && !bLayout )
3044             nTextStyle |= TEXT_DRAW_LEFT;
3045         else if ( GetStyle() & WB_CENTER )
3046             nTextStyle |= TEXT_DRAW_CENTER;
3047         else if ( GetStyle() & WB_RIGHT )
3048             nTextStyle |= TEXT_DRAW_RIGHT;
3049         else
3050             nTextStyle |= TEXT_DRAW_LEFT;
3051 
3052         Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
3053 
3054         if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
3055         {
3056             long nMaxWidth = Max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
3057             aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
3058         }
3059 
3060         MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
3061         String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
3062         DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
3063     }
3064 
3065     if( HasFocus() && !bLayout )
3066         ShowFocus( maFocusRect );
3067 }
3068 
3069 // -----------------------------------------------------------------------
3070 
3071 void ImplWin::Resize()
3072 {
3073     Control::Resize();
3074     maFocusRect.SetSize( GetOutputSizePixel() );
3075     Invalidate();
3076 }
3077 
3078 // -----------------------------------------------------------------------
3079 
3080 void ImplWin::GetFocus()
3081 {
3082     ShowFocus( maFocusRect );
3083     if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3084         IsNativeWidgetEnabled() &&
3085         IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
3086     {
3087         Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
3088         if( ! pWin )
3089             pWin = GetParent();
3090         pWin->Invalidate();
3091     }
3092     else
3093         Invalidate();
3094     Control::GetFocus();
3095 }
3096 
3097 // -----------------------------------------------------------------------
3098 
3099 void ImplWin::LoseFocus()
3100 {
3101     HideFocus();
3102     if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3103         IsNativeWidgetEnabled() &&
3104         IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
3105     {
3106         Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
3107         if( ! pWin )
3108             pWin = GetParent();
3109         pWin->Invalidate();
3110     }
3111     else
3112         Invalidate();
3113     Control::LoseFocus();
3114 }
3115 
3116 // =======================================================================
3117 
3118 ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
3119     PushButton(  pParent, nWinStyle ),
3120     mbDown  ( sal_False )
3121 {
3122 }
3123 
3124 // -----------------------------------------------------------------------
3125 
3126 void ImplBtn::MBDown()
3127 {
3128     if( IsEnabled() )
3129        maMBDownHdl.Call( this );
3130 }
3131 
3132 // -----------------------------------------------------------------------
3133 
3134 void ImplBtn::MouseButtonDown( const MouseEvent& )
3135 {
3136     //PushButton::MouseButtonDown( rMEvt );
3137     if( IsEnabled() )
3138     {
3139         MBDown();
3140         mbDown = sal_True;
3141     }
3142 }
3143 
3144 // =======================================================================
3145 
3146 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
3147     FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW )    // no drop shadow for list boxes
3148 {
3149     mpImplLB = NULL;
3150     mnDDLineCount = 0;
3151     mbAutoWidth = sal_False;
3152 
3153     mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
3154 
3155     EnableSaveBackground();
3156 
3157     Window * pBorderWindow = ImplGetBorderWindow();
3158     if( pBorderWindow )
3159     {
3160         SetAccessibleRole(accessibility::AccessibleRole::PANEL);
3161         pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3162     }
3163     else
3164     {
3165         SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3166     }
3167 
3168 }
3169 
3170 // -----------------------------------------------------------------------
3171 
3172 long ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
3173 {
3174     if( rNEvt.GetType() == EVENT_LOSEFOCUS )
3175     {
3176         if( !GetParent()->HasChildPathFocus( sal_True ) )
3177             EndPopupMode();
3178     }
3179 
3180     return FloatingWindow::PreNotify( rNEvt );
3181 }
3182 
3183 // -----------------------------------------------------------------------
3184 
3185 void ImplListBoxFloatingWindow::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
3186 {
3187     FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
3188 
3189     // Fix #60890# ( MBA ): um auch im aufgeklappten Zustand der Listbox die Gr"o\se einfach zu einen
3190     // Aufruf von Resize() "andern zu k"onnen, wird die Position hier ggf. angepa\t
3191     if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
3192     {
3193         Point aPos = GetParent()->GetPosPixel();
3194         aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3195 
3196         if ( nFlags & WINDOW_POSSIZE_X )
3197             aPos.X() = nX;
3198 
3199         if ( nFlags & WINDOW_POSSIZE_Y )
3200             aPos.Y() = nY;
3201 
3202         sal_uInt16 nIndex;
3203         SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
3204     }
3205 
3206 //  if( !IsReallyVisible() )
3207     {
3208         // Die ImplListBox erhaelt kein Resize, weil nicht sichtbar.
3209         // Die Fenster muessen aber ein Resize() erhalten, damit die
3210         // Anzahl der sichtbaren Eintraege fuer PgUp/PgDown stimmt.
3211         // Die Anzahl kann auch nicht von List/Combobox berechnet werden,
3212         // weil hierfuer auch die ggf. vorhandene vertikale Scrollbar
3213         // beruecksichtigt werden muss.
3214         mpImplLB->SetSizePixel( GetOutputSizePixel() );
3215         ((Window*)mpImplLB)->Resize();
3216         ((Window*)mpImplLB->GetMainWindow())->Resize();
3217     }
3218 }
3219 
3220 // -----------------------------------------------------------------------
3221 
3222 void ImplListBoxFloatingWindow::Resize()
3223 {
3224     mpImplLB->GetMainWindow()->ImplClearLayoutData();
3225     FloatingWindow::Resize();
3226 }
3227 
3228 // -----------------------------------------------------------------------
3229 
3230 Size ImplListBoxFloatingWindow::CalcFloatSize()
3231 {
3232     Size aFloatSz( maPrefSz );
3233 
3234     sal_Int32 nLeft, nTop, nRight, nBottom;
3235     GetBorder( nLeft, nTop, nRight, nBottom );
3236 
3237     sal_uInt16 nLines = mpImplLB->GetEntryList()->GetEntryCount();
3238     if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
3239         nLines = mnDDLineCount;
3240 
3241     Size aSz = mpImplLB->CalcSize( nLines );
3242     long nMaxHeight = aSz.Height() + nTop + nBottom;
3243 
3244     if ( mnDDLineCount )
3245         aFloatSz.Height() = nMaxHeight;
3246 
3247     if( mbAutoWidth )
3248     {
3249         // AutoSize erstmal nur fuer die Breite...
3250 
3251         aFloatSz.Width() = aSz.Width() + nLeft + nRight;
3252         aFloatSz.Width() += nRight; // etwas mehr Platz sieht besser aus...
3253 
3254         if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
3255         {
3256             // dann wird noch der vertikale Scrollbar benoetigt
3257             long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
3258             aFloatSz.Width() += nSBWidth;
3259         }
3260     }
3261 
3262     if ( aFloatSz.Height() > nMaxHeight )
3263         aFloatSz.Height() = nMaxHeight;
3264 
3265     // Minimale Hoehe, falls Hoehe nicht auf Float-Hoehe eingestellt wurde.
3266     // Der Parent vom FloatWin muss die DropDown-Combo/Listbox sein.
3267     Size aParentSz = GetParent()->GetSizePixel();
3268     if( !mnDDLineCount && ( aFloatSz.Height() < aParentSz.Height() ) )
3269         aFloatSz.Height() = aParentSz.Height();
3270 
3271     // Nicht schmaler als der Parent werden...
3272     if( aFloatSz.Width() < aParentSz.Width() )
3273         aFloatSz.Width() = aParentSz.Width();
3274 
3275     // Hoehe auf Entries alignen...
3276     long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
3277     long nEntryHeight = mpImplLB->GetEntryHeight();
3278     if ( nInnerHeight % nEntryHeight )
3279     {
3280         nInnerHeight /= nEntryHeight;
3281         nInnerHeight++;
3282         nInnerHeight *= nEntryHeight;
3283         aFloatSz.Height() = nInnerHeight + nTop + nBottom;
3284     }
3285 
3286     return aFloatSz;
3287 }
3288 
3289 // -----------------------------------------------------------------------
3290 
3291 void ImplListBoxFloatingWindow::StartFloat( sal_Bool bStartTracking )
3292 {
3293     if( !IsInPopupMode() )
3294     {
3295         Size aFloatSz = CalcFloatSize();
3296 
3297         SetSizePixel( aFloatSz );
3298         mpImplLB->SetSizePixel( GetOutputSizePixel() );
3299 
3300         sal_uInt16 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
3301         mnPopupModeStartSaveSelection = nPos;
3302 
3303         Size aSz = GetParent()->GetSizePixel();
3304         Point aPos = GetParent()->GetPosPixel();
3305         aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3306         // FIXME: this ugly hack is for Mac/Aqua
3307         // should be replaced by a real mechanism to place the float rectangle
3308         if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3309             GetParent()->IsNativeWidgetEnabled() )
3310         {
3311             sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
3312             aPos.X() += nLeft;
3313             aPos.Y() += nTop;
3314             aSz.Width() -= nLeft + nRight;
3315             aSz.Height() -= nTop + nBottom;
3316         }
3317         Rectangle aRect( aPos, aSz );
3318 
3319         // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3320         // where the document is unmirrored
3321         // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3322         if( GetParent()->GetParent()->ImplIsAntiparallel() )
3323             GetParent()->GetParent()->ImplReMirror( aRect );
3324 
3325         StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
3326 
3327         if( nPos != LISTBOX_ENTRY_NOTFOUND )
3328             mpImplLB->ShowProminentEntry( nPos );
3329 
3330         if( bStartTracking )
3331             mpImplLB->GetMainWindow()->EnableMouseMoveSelect( sal_True );
3332 
3333         if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
3334             mpImplLB->GetMainWindow()->GrabFocus();
3335 
3336         mpImplLB->GetMainWindow()->ImplClearLayoutData();
3337     }
3338 }
3339