merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / control / ilstbox.cxx
blob79598a1a036a1055a6b728c8d0c60e541d6bebca
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ilstbox.cxx,v $
10 * $Revision: 1.67 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <tools/debug.hxx>
34 #include <vcl/svdata.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/settings.hxx>
37 #include <vcl/event.hxx>
38 #include <vcl/scrbar.hxx>
39 #include <vcl/help.hxx>
40 #include <vcl/lstbox.h>
41 #include <vcl/ilstbox.hxx>
42 #include <vcl/i18nhelp.hxx>
43 #include <vcl/controllayout.hxx>
44 #include <vcl/unohelp.hxx>
45 #ifndef _COM_SUN_STAR_UTIL_XCOLLATOR_HPP_
46 #include <com/sun/star/i18n/XCollator.hpp>
47 #endif
49 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HDL_
50 #include <com/sun/star/accessibility/XAccessible.hpp>
51 #endif
53 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEROLE_HPP_
54 #include <com/sun/star/accessibility/AccessibleRole.hpp>
55 #endif
57 #define MULTILINE_ENTRY_DRAW_FLAGS ( TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_VCENTER )
59 using namespace ::com::sun::star;
61 // =======================================================================
63 void ImplInitFieldSettings( Window* pWin, BOOL bFont, BOOL bForeground, BOOL bBackground )
65 const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
67 if ( bFont )
69 Font aFont = rStyleSettings.GetFieldFont();
70 if ( pWin->IsControlFont() )
71 aFont.Merge( pWin->GetControlFont() );
72 pWin->SetZoomedPointFont( aFont );
75 if ( bFont || bForeground )
77 Color aTextColor = rStyleSettings.GetFieldTextColor();
78 if ( pWin->IsControlForeground() )
79 aTextColor = pWin->GetControlForeground();
80 pWin->SetTextColor( aTextColor );
83 if ( bBackground )
85 if( pWin->IsControlBackground() )
86 pWin->SetBackground( pWin->GetControlBackground() );
87 else
88 pWin->SetBackground( rStyleSettings.GetFieldColor() );
92 // -----------------------------------------------------------------------
94 void ImplInitDropDownButton( PushButton* pButton )
96 if ( pButton->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
97 pButton->SetSymbol( SYMBOL_SPIN_UPDOWN );
98 else
99 pButton->SetSymbol( SYMBOL_SPIN_DOWN );
101 if ( pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
102 && ! pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
103 pButton->SetBackground();
106 // =======================================================================
108 ImplEntryList::ImplEntryList( Window* pWindow )
110 mpWindow = pWindow;
111 mnLastSelected = LISTBOX_ENTRY_NOTFOUND;
112 mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND;
113 mnImages = 0;
114 mbCallSelectionChangedHdl = TRUE;
116 mnMRUCount = 0;
117 mnMaxMRUCount = 0;
120 // -----------------------------------------------------------------------
122 ImplEntryList::~ImplEntryList()
124 Clear();
127 // -----------------------------------------------------------------------
129 void ImplEntryList::Clear()
131 mnImages = 0;
132 for ( USHORT n = GetEntryCount(); n; )
134 ImplEntryType* pImplEntry = GetEntry( --n );
135 delete pImplEntry;
137 List::Clear();
140 // -----------------------------------------------------------------------
142 void ImplEntryList::SelectEntry( USHORT nPos, BOOL bSelect )
144 ImplEntryType* pImplEntry = GetEntry( nPos );
145 if ( pImplEntry &&
146 ( pImplEntry->mbIsSelected != bSelect ) &&
147 ( (pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0 ) )
149 pImplEntry->mbIsSelected = bSelect;
150 if ( mbCallSelectionChangedHdl )
151 maSelectionChangedHdl.Call( (void*)sal_IntPtr(nPos) );
155 // -----------------------------------------------------------------------
157 uno::Reference< i18n::XCollator > ImplGetCollator (lang::Locale &rLocale)
159 static uno::Reference< i18n::XCollator > xCollator;
160 if ( !xCollator.is() )
161 xCollator = vcl::unohelper::CreateCollator();
162 if( xCollator.is() )
163 xCollator->loadDefaultCollator (rLocale, 0);
165 return xCollator;
168 USHORT ImplEntryList::InsertEntry( USHORT nPos, ImplEntryType* pNewEntry, BOOL bSort )
170 if ( !!pNewEntry->maImage )
171 mnImages++;
173 if ( !bSort || !Count() )
175 Insert( pNewEntry, nPos );
177 else
179 lang::Locale aLocale = Application::GetSettings().GetLocale();
180 uno::Reference< i18n::XCollator > xCollator = ImplGetCollator(aLocale);
182 const XubString& rStr = pNewEntry->maStr;
183 ULONG nLow, nHigh, nMid;
185 nHigh = Count();
187 ImplEntryType* pTemp = GetEntry( (USHORT)(nHigh-1) );
191 // XXX even though XCollator::compareString returns a sal_Int32 the only
192 // defined values are {-1, 0, 1} which is compatible with StringCompare
193 StringCompare eComp = xCollator.is() ?
194 (StringCompare)xCollator->compareString (rStr, pTemp->maStr)
195 : COMPARE_EQUAL;
197 // Schnelles Einfuegen bei sortierten Daten
198 if ( eComp != COMPARE_LESS )
200 Insert( pNewEntry, LIST_APPEND );
202 else
204 nLow = mnMRUCount;
205 pTemp = (ImplEntryType*)GetEntry( (USHORT)nLow );
207 eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
208 if ( eComp != COMPARE_GREATER )
210 Insert( pNewEntry, (ULONG)0 );
212 else
214 // Binaeres Suchen
215 nHigh--;
218 nMid = (nLow + nHigh) / 2;
219 pTemp = (ImplEntryType*)GetObject( nMid );
221 eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
223 if ( eComp == COMPARE_LESS )
224 nHigh = nMid-1;
225 else
227 if ( eComp == COMPARE_GREATER )
228 nLow = nMid + 1;
229 else
230 break;
233 while ( nLow <= nHigh );
235 if ( eComp != COMPARE_LESS )
236 nMid++;
238 Insert( pNewEntry, nMid );
242 catch (uno::RuntimeException& )
244 // XXX this is arguable, if the exception occured because pNewEntry is
245 // garbage you wouldn't insert it. If the exception occured because the
246 // Collator implementation is garbage then give the user a chance to see
247 // his stuff
248 Insert( pNewEntry, (ULONG)0 );
253 return (USHORT)GetPos( pNewEntry );
256 // -----------------------------------------------------------------------
258 void ImplEntryList::RemoveEntry( USHORT nPos )
260 ImplEntryType* pImplEntry = (ImplEntryType*)List::Remove( nPos );
261 if ( pImplEntry )
263 if ( !!pImplEntry->maImage )
264 mnImages--;
266 delete pImplEntry;
270 // -----------------------------------------------------------------------
272 USHORT ImplEntryList::FindEntry( const XubString& rString, BOOL bSearchMRUArea ) const
274 USHORT nEntries = GetEntryCount();
275 for ( USHORT n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
277 ImplEntryType* pImplEntry = GetEntry( n );
278 String aComp( vcl::I18nHelper::filterFormattingChars( pImplEntry->maStr ) );
279 if ( aComp == rString )
280 return n;
282 return LISTBOX_ENTRY_NOTFOUND;
285 // -----------------------------------------------------------------------
287 USHORT ImplEntryList::FindMatchingEntry( const XubString& rStr, USHORT nStart, BOOL bForward, BOOL bLazy ) const
289 USHORT nPos = LISTBOX_ENTRY_NOTFOUND;
290 USHORT nEntryCount = GetEntryCount();
291 if ( !bForward )
292 nStart++; // wird sofort dekrementiert
294 const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
295 for ( USHORT n = nStart; bForward ? ( n < nEntryCount ) : n; )
297 if ( !bForward )
298 n--;
300 ImplEntryType* pImplEntry = GetEntry( n );
301 BOOL bMatch = bLazy ? rI18nHelper.MatchString( rStr, pImplEntry->maStr ) != 0 : ( rStr.Match( pImplEntry->maStr ) == STRING_MATCH );
302 if ( bMatch )
304 nPos = n;
305 break;
308 if ( bForward )
309 n++;
312 return nPos;
315 // -----------------------------------------------------------------------
317 USHORT ImplEntryList::FindEntry( const void* pData ) const
319 USHORT nPos = LISTBOX_ENTRY_NOTFOUND;
320 for ( USHORT n = GetEntryCount(); n; )
322 ImplEntryType* pImplEntry = GetEntry( --n );
323 if ( pImplEntry->mpUserData == pData )
325 nPos = n;
326 break;
329 return nPos;
332 // -----------------------------------------------------------------------
334 long ImplEntryList::GetAddedHeight( USHORT i_nEndIndex, USHORT i_nBeginIndex, long i_nBeginHeight ) const
336 long nHeight = i_nBeginHeight;
337 USHORT nStart = i_nEndIndex > i_nBeginIndex ? i_nBeginIndex : i_nEndIndex;
338 USHORT nStop = i_nEndIndex > i_nBeginIndex ? i_nEndIndex : i_nBeginIndex;
339 USHORT nEntryCount = GetEntryCount();
340 if( nStop != LISTBOX_ENTRY_NOTFOUND && nEntryCount != 0 )
342 // sanity check
343 if( nStop > nEntryCount-1 )
344 nStop = nEntryCount-1;
345 if( nStart > nEntryCount-1 )
346 nStart = nEntryCount-1;
348 USHORT nIndex = nStart;
349 while( nIndex != LISTBOX_ENTRY_NOTFOUND && nIndex < nStop )
351 nHeight += GetEntryPtr( nIndex )-> mnHeight;
352 nIndex++;
355 else
356 nHeight = 0;
357 return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
360 // -----------------------------------------------------------------------
362 long ImplEntryList::GetEntryHeight( USHORT nPos ) const
364 ImplEntryType* pImplEntry = GetEntry( nPos );
365 return pImplEntry ? pImplEntry->mnHeight : 0;
368 // -----------------------------------------------------------------------
370 XubString ImplEntryList::GetEntryText( USHORT nPos ) const
372 XubString aEntryText;
373 ImplEntryType* pImplEntry = GetEntry( nPos );
374 if ( pImplEntry )
375 aEntryText = pImplEntry->maStr;
376 return aEntryText;
379 // -----------------------------------------------------------------------
381 BOOL ImplEntryList::HasEntryImage( USHORT nPos ) const
383 BOOL bImage = FALSE;
384 ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
385 if ( pImplEntry )
386 bImage = !!pImplEntry->maImage;
387 return bImage;
390 // -----------------------------------------------------------------------
392 Image ImplEntryList::GetEntryImage( USHORT nPos ) const
394 Image aImage;
395 ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
396 if ( pImplEntry )
397 aImage = pImplEntry->maImage;
398 return aImage;
401 // -----------------------------------------------------------------------
403 void ImplEntryList::SetEntryData( USHORT nPos, void* pNewData )
405 ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
406 if ( pImplEntry )
407 pImplEntry->mpUserData = pNewData;
410 // -----------------------------------------------------------------------
412 void* ImplEntryList::GetEntryData( USHORT nPos ) const
414 ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
415 return pImplEntry ? pImplEntry->mpUserData : NULL;
418 // -----------------------------------------------------------------------
420 void ImplEntryList::SetEntryFlags( USHORT nPos, long nFlags )
422 ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
423 if ( pImplEntry )
424 pImplEntry->mnFlags = nFlags;
427 // -----------------------------------------------------------------------
429 long ImplEntryList::GetEntryFlags( USHORT nPos ) const
431 ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
432 return pImplEntry ? pImplEntry->mnFlags : 0;
435 // -----------------------------------------------------------------------
437 USHORT ImplEntryList::GetSelectEntryCount() const
439 USHORT nSelCount = 0;
440 for ( USHORT n = GetEntryCount(); n; )
442 ImplEntryType* pImplEntry = GetEntry( --n );
443 if ( pImplEntry->mbIsSelected )
444 nSelCount++;
446 return nSelCount;
449 // -----------------------------------------------------------------------
451 XubString ImplEntryList::GetSelectEntry( USHORT nIndex ) const
453 return GetEntryText( GetSelectEntryPos( nIndex ) );
456 // -----------------------------------------------------------------------
458 USHORT ImplEntryList::GetSelectEntryPos( USHORT nIndex ) const
460 USHORT nSelEntryPos = LISTBOX_ENTRY_NOTFOUND;
461 USHORT nSel = 0;
462 USHORT nEntryCount = GetEntryCount();
464 for ( USHORT n = 0; n < nEntryCount; n++ )
466 ImplEntryType* pImplEntry = GetEntry( n );
467 if ( pImplEntry->mbIsSelected )
469 if ( nSel == nIndex )
471 nSelEntryPos = n;
472 break;
474 nSel++;
478 return nSelEntryPos;
481 // -----------------------------------------------------------------------
483 BOOL ImplEntryList::IsEntrySelected( const XubString& rStr ) const
485 return IsEntryPosSelected( FindEntry( rStr ) );
488 // -----------------------------------------------------------------------
490 BOOL ImplEntryList::IsEntryPosSelected( USHORT nIndex ) const
492 ImplEntryType* pImplEntry = GetEntry( nIndex );
493 return pImplEntry ? pImplEntry->mbIsSelected : FALSE;
496 // -----------------------------------------------------------------------
498 bool ImplEntryList::IsEntrySelectable( USHORT nPos ) const
500 ImplEntryType* pImplEntry = GetEntry( nPos );
501 return pImplEntry ? ((pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0) : true;
504 // -----------------------------------------------------------------------
506 USHORT ImplEntryList::FindFirstSelectable( USHORT nPos, bool bForward /* = true */ )
508 if( IsEntrySelectable( nPos ) )
509 return nPos;
511 if( bForward )
513 for( nPos = nPos + 1; nPos < GetEntryCount(); nPos++ )
515 if( IsEntrySelectable( nPos ) )
516 return nPos;
519 else
521 while( nPos )
523 nPos--;
524 if( IsEntrySelectable( nPos ) )
525 return nPos;
529 return LISTBOX_ENTRY_NOTFOUND;
532 // =======================================================================
534 ImplListBoxWindow::ImplListBoxWindow( Window* pParent, WinBits nWinStyle ) :
535 Control( pParent, 0 )
537 mpEntryList = new ImplEntryList( this );
539 mnTop = 0;
540 mnLeft = 0;
541 mnBorder = 1;
542 mnSelectModifier = 0;
543 mnUserDrawEntry = LISTBOX_ENTRY_NOTFOUND;
544 mbTrack = FALSE;
545 mbImgsDiffSz = FALSE;
546 mbTravelSelect = FALSE;
547 mbTrackingSelect = FALSE;
548 mbSelectionChanged = FALSE;
549 mbMouseMoveSelect = FALSE;
550 mbMulti = FALSE;
551 mbStackMode = FALSE;
552 mbGrabFocus = FALSE;
553 mbUserDrawEnabled = FALSE;
554 mbInUserDraw = FALSE;
555 mbReadOnly = FALSE;
556 mbHasFocusRect = FALSE;
557 mbRight = ( nWinStyle & WB_RIGHT ) ? TRUE : FALSE;
558 mbCenter = ( nWinStyle & WB_CENTER ) ? TRUE : FALSE;
559 mbSimpleMode = ( nWinStyle & WB_SIMPLEMODE ) ? TRUE : FALSE;
560 mbSort = ( nWinStyle & WB_SORT ) ? TRUE : FALSE;
562 // pb: #106948# explicit mirroring for calc
563 mbMirroring = FALSE;
565 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
566 mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
567 mnSeparatorPos = LISTBOX_ENTRY_NOTFOUND;
569 SetLineColor();
570 SetTextFillColor();
571 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
573 maSearchTimeout.SetTimeout( 2500 );
574 maSearchTimeout.SetTimeoutHdl( LINK( this, ImplListBoxWindow, SearchStringTimeout ) );
576 ImplInitSettings( TRUE, TRUE, TRUE );
577 ImplCalcMetrics();
580 // -----------------------------------------------------------------------
582 ImplListBoxWindow::~ImplListBoxWindow()
584 maSearchTimeout.Stop();
585 delete mpEntryList;
588 // -----------------------------------------------------------------------
590 void ImplListBoxWindow::ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground )
592 ImplInitFieldSettings( this, bFont, bForeground, bBackground );
595 // -----------------------------------------------------------------------
597 void ImplListBoxWindow::ImplCalcMetrics()
599 mnMaxWidth = 0;
600 mnMaxTxtWidth = 0;
601 mnMaxImgWidth = 0;
602 mnMaxImgTxtWidth= 0;
603 mnMaxImgHeight = 0;
605 mnTextHeight = (USHORT)GetTextHeight();
606 mnMaxTxtHeight = mnTextHeight + mnBorder;
607 mnMaxHeight = mnMaxTxtHeight;
609 if ( maUserItemSize.Height() > mnMaxHeight )
610 mnMaxHeight = (USHORT) maUserItemSize.Height();
611 if ( maUserItemSize.Width() > mnMaxWidth )
612 mnMaxWidth= (USHORT) maUserItemSize.Width();
614 for ( USHORT n = mpEntryList->GetEntryCount(); n; )
616 ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
617 ImplUpdateEntryMetrics( *pEntry );
620 if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
622 Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->mnHeight );
623 maFocusRect.SetSize( aSz );
627 // -----------------------------------------------------------------------
629 IMPL_LINK( ImplListBoxWindow, SearchStringTimeout, Timer*, EMPTYARG )
631 maSearchStr.Erase();
632 return 1;
635 // -----------------------------------------------------------------------
637 void ImplListBoxWindow::Clear()
639 mpEntryList->Clear();
641 mnMaxHeight = mnMaxTxtHeight;
642 mnMaxWidth = 0;
643 mnMaxTxtWidth = 0;
644 mnMaxImgTxtWidth= 0;
645 mnMaxImgWidth = 0;
646 mnMaxImgHeight = 0;
647 mnTop = 0;
648 mnLeft = 0;
649 mbImgsDiffSz = FALSE;
650 delete mpLayoutData, mpLayoutData = NULL;
652 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
654 Invalidate();
657 void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
659 delete mpLayoutData, mpLayoutData = NULL;
660 maUserItemSize = rSz;
661 ImplCalcMetrics();
664 // -----------------------------------------------------------------------
666 struct ImplEntryMetrics
668 BOOL bText;
669 BOOL bImage;
670 long nEntryWidth;
671 long nEntryHeight;
672 long nTextWidth;
673 long nImgWidth;
674 long nImgHeight;
677 // -----------------------------------------------------------------------
679 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
681 ImplEntryMetrics aMetrics;
682 aMetrics.bText = rEntry.maStr.Len() ? TRUE : FALSE;
683 aMetrics.bImage = !!rEntry.maImage;
684 aMetrics.nEntryWidth = 0;
685 aMetrics.nEntryHeight = 0;
686 aMetrics.nTextWidth = 0;
687 aMetrics.nImgWidth = 0;
688 aMetrics.nImgHeight = 0;
690 if ( aMetrics.bText )
692 if( (rEntry.mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
694 // multiline case
695 Size aCurSize( PixelToLogic( GetSizePixel() ) );
696 // set the current size to a large number
697 // GetTextRect should shrink it to the actual size
698 aCurSize.Height() = 0x7fffff;
699 Rectangle aTextRect( Point( 0, 0 ), aCurSize );
700 aTextRect = GetTextRect( aTextRect, rEntry.maStr, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE );
701 aMetrics.nTextWidth = aTextRect.GetWidth();
702 if( aMetrics.nTextWidth > mnMaxTxtWidth )
703 mnMaxTxtWidth = aMetrics.nTextWidth;
704 aMetrics.nEntryWidth = mnMaxTxtWidth;
705 aMetrics.nEntryHeight = aTextRect.GetHeight() + mnBorder;
707 else
709 // normal single line case
710 aMetrics.nTextWidth = (USHORT)GetTextWidth( rEntry.maStr );
711 if( aMetrics.nTextWidth > mnMaxTxtWidth )
712 mnMaxTxtWidth = aMetrics.nTextWidth;
713 aMetrics.nEntryWidth = mnMaxTxtWidth;
714 aMetrics.nEntryHeight = mnTextHeight + mnBorder;
717 if ( aMetrics.bImage )
719 Size aImgSz = rEntry.maImage.GetSizePixel();
720 aMetrics.nImgWidth = (USHORT) CalcZoom( aImgSz.Width() );
721 aMetrics.nImgHeight = (USHORT) CalcZoom( aImgSz.Height() );
723 if( mnMaxImgWidth && ( aMetrics.nImgWidth != mnMaxImgWidth ) )
724 mbImgsDiffSz = TRUE;
725 else if ( mnMaxImgHeight && ( aMetrics.nImgHeight != mnMaxImgHeight ) )
726 mbImgsDiffSz = TRUE;
728 if( aMetrics.nImgWidth > mnMaxImgWidth )
729 mnMaxImgWidth = aMetrics.nImgWidth;
730 if( aMetrics.nImgHeight > mnMaxImgHeight )
731 mnMaxImgHeight = aMetrics.nImgHeight;
733 mnMaxImgTxtWidth = Max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
734 aMetrics.nEntryHeight = Max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
737 if ( IsUserDrawEnabled() || aMetrics.bImage )
739 aMetrics.nEntryWidth = Max( aMetrics.nImgWidth, maUserItemSize.Width() );
740 if ( aMetrics.bText )
741 aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE;
742 aMetrics.nEntryHeight = Max( Max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
743 aMetrics.nEntryHeight );
746 if ( aMetrics.nEntryWidth > mnMaxWidth )
747 mnMaxWidth = aMetrics.nEntryWidth;
748 if ( aMetrics.nEntryHeight > mnMaxHeight )
749 mnMaxHeight = aMetrics.nEntryHeight;
751 rEntry.mnHeight = aMetrics.nEntryHeight;
754 // -----------------------------------------------------------------------
756 void ImplListBoxWindow::ImplCallSelect()
758 if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
760 // Insert the selected entry as MRU, if not allready first MRU
761 USHORT nSelected = GetEntryList()->GetSelectEntryPos( 0 );
762 USHORT nMRUCount = GetEntryList()->GetMRUCount();
763 String aSelected = GetEntryList()->GetEntryText( nSelected );
764 USHORT nFirstMatchingEntryPos = GetEntryList()->FindEntry( aSelected, TRUE );
765 if ( nFirstMatchingEntryPos || !nMRUCount )
767 BOOL bSelectNewEntry = FALSE;
768 if ( nFirstMatchingEntryPos < nMRUCount )
770 RemoveEntry( nFirstMatchingEntryPos );
771 nMRUCount--;
772 if ( nFirstMatchingEntryPos == nSelected )
773 bSelectNewEntry = TRUE;
775 else if ( nMRUCount == GetEntryList()->GetMaxMRUCount() )
777 RemoveEntry( nMRUCount - 1 );
778 nMRUCount--;
781 delete mpLayoutData, mpLayoutData = NULL;
783 ImplEntryType* pNewEntry = new ImplEntryType( aSelected );
784 pNewEntry->mbIsSelected = bSelectNewEntry;
785 GetEntryList()->InsertEntry( 0, pNewEntry, FALSE );
786 ImplUpdateEntryMetrics( *pNewEntry );
787 GetEntryList()->SetMRUCount( ++nMRUCount );
788 SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
789 maMRUChangedHdl.Call( NULL );
793 maSelectHdl.Call( NULL );
794 mbSelectionChanged = FALSE;
797 // -----------------------------------------------------------------------
799 USHORT ImplListBoxWindow::InsertEntry( USHORT nPos, ImplEntryType* pNewEntry )
801 delete mpLayoutData, mpLayoutData = NULL;
802 USHORT nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, mbSort );
804 if( (GetStyle() & WB_WORDBREAK) )
805 pNewEntry->mnFlags |= LISTBOX_ENTRY_FLAG_MULTILINE;
807 ImplUpdateEntryMetrics( *pNewEntry );
808 return nNewPos;
811 // -----------------------------------------------------------------------
813 void ImplListBoxWindow::RemoveEntry( USHORT nPos )
815 delete mpLayoutData, mpLayoutData = NULL;
816 mpEntryList->RemoveEntry( nPos );
817 if( mnCurrentPos >= mpEntryList->GetEntryCount() )
818 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
819 ImplCalcMetrics();
822 // -----------------------------------------------------------------------
824 void ImplListBoxWindow::SetEntryFlags( USHORT nPos, long nFlags )
826 mpEntryList->SetEntryFlags( nPos, nFlags );
827 ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( nPos );
828 if( pEntry )
829 ImplUpdateEntryMetrics( *pEntry );
832 // -----------------------------------------------------------------------
834 void ImplListBoxWindow::ImplShowFocusRect()
836 if ( mbHasFocusRect )
837 HideFocus();
838 ShowFocus( maFocusRect );
839 mbHasFocusRect = TRUE;
842 // -----------------------------------------------------------------------
844 void ImplListBoxWindow::ImplHideFocusRect()
846 if ( mbHasFocusRect )
848 HideFocus();
849 mbHasFocusRect = FALSE;
854 // -----------------------------------------------------------------------
856 USHORT ImplListBoxWindow::GetEntryPosForPoint( const Point& rPoint ) const
858 long nY = mnBorder;
860 USHORT nSelect = mnTop;
861 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nSelect );
862 while( pEntry && rPoint.Y() > pEntry->mnHeight + nY )
864 nY += pEntry->mnHeight;
865 pEntry = mpEntryList->GetEntryPtr( ++nSelect );
867 if( pEntry == NULL )
868 nSelect = LISTBOX_ENTRY_NOTFOUND;
870 return nSelect;
873 // -----------------------------------------------------------------------
875 BOOL ImplListBoxWindow::IsVisible( USHORT i_nEntry ) const
877 BOOL bRet = FALSE;
879 if( i_nEntry >= mnTop )
881 if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
882 PixelToLogic( GetSizePixel() ).Height() )
884 bRet = TRUE;
888 return bRet;
891 // -----------------------------------------------------------------------
893 USHORT ImplListBoxWindow::GetLastVisibleEntry() const
895 USHORT nPos = mnTop;
896 long nWindowHeight = GetSizePixel().Height();
897 USHORT nCount = mpEntryList->GetEntryCount();
898 long nDiff;
899 for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
900 nPos++;
902 if( nDiff > nWindowHeight && nPos > mnTop )
903 nPos--;
905 if( nPos >= nCount )
906 nPos = nCount-1;
908 return nPos;
911 // -----------------------------------------------------------------------
913 void ImplListBoxWindow::MouseButtonDown( const MouseEvent& rMEvt )
915 mbMouseMoveSelect = FALSE; // Nur bis zum ersten MouseButtonDown
916 maSearchStr.Erase();
918 if ( !IsReadOnly() )
920 if( rMEvt.GetClicks() == 1 )
922 USHORT nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
923 if( nSelect != LISTBOX_ENTRY_NOTFOUND )
925 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
926 mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
927 else
928 mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
930 mnCurrentPos = nSelect;
931 mbTrackingSelect = TRUE;
932 SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() );
933 mbTrackingSelect = FALSE;
934 if ( mbGrabFocus )
935 GrabFocus();
937 StartTracking( STARTTRACK_SCROLLREPEAT );
940 if( rMEvt.GetClicks() == 2 )
942 maDoubleClickHdl.Call( this );
945 else // if ( mbGrabFocus )
947 GrabFocus();
951 // -----------------------------------------------------------------------
953 void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
955 if ( rMEvt.IsLeaveWindow() )
957 if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
959 if ( rMEvt.GetPosPixel().Y() < 0 )
961 DeselectAll();
962 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
963 SetTopEntry( 0 );
964 if ( mbStackMode ) // #87072#, #92323#
966 mbTravelSelect = TRUE;
967 mnSelectModifier = rMEvt.GetModifier();
968 ImplCallSelect();
969 mbTravelSelect = FALSE;
975 else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
977 Point aPoint;
978 Rectangle aRect( aPoint, GetOutputSizePixel() );
979 if( aRect.IsInside( rMEvt.GetPosPixel() ) )
981 if ( IsMouseMoveSelect() )
983 USHORT nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
984 if( nSelect == LISTBOX_ENTRY_NOTFOUND )
985 nSelect = mpEntryList->GetEntryCount() - 1;
986 nSelect = Min( nSelect, GetLastVisibleEntry() );
987 nSelect = Min( nSelect, (USHORT) ( mpEntryList->GetEntryCount() - 1 ) );
988 // Select only visible Entries with MouseMove, otherwise Tracking...
989 if ( IsVisible( nSelect ) &&
990 mpEntryList->IsEntrySelectable( nSelect ) &&
991 ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
993 mbTrackingSelect = TRUE;
994 if ( SelectEntries( nSelect, LET_TRACKING, FALSE, FALSE ) )
996 if ( mbStackMode ) // #87072#
998 mbTravelSelect = TRUE;
999 mnSelectModifier = rMEvt.GetModifier();
1000 ImplCallSelect();
1001 mbTravelSelect = FALSE;
1004 mbTrackingSelect = FALSE;
1008 // Falls der DD-Button gedrueckt wurde und jemand mit gedrueckter
1009 // Maustaste in die ListBox faehrt...
1010 if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
1012 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1013 mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
1014 else
1015 mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
1017 if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
1018 mpEntryList->SetSelectionAnchor( 0 );
1020 StartTracking( STARTTRACK_SCROLLREPEAT );
1026 // -----------------------------------------------------------------------
1028 void ImplListBoxWindow::DeselectAll()
1030 while ( GetEntryList()->GetSelectEntryCount() )
1032 USHORT nS = GetEntryList()->GetSelectEntryPos( 0 );
1033 SelectEntry( nS, FALSE );
1037 // -----------------------------------------------------------------------
1039 void ImplListBoxWindow::SelectEntry( USHORT nPos, BOOL bSelect )
1041 if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
1043 ImplHideFocusRect();
1044 if( bSelect )
1046 if( !mbMulti )
1048 // Selektierten Eintrag deselektieren
1049 USHORT nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
1050 if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
1052 //SelectEntryPos( nDeselect, FALSE );
1053 GetEntryList()->SelectEntry( nDeselect, FALSE );
1054 if ( IsUpdateMode() && IsReallyVisible() )
1055 ImplPaint( nDeselect, TRUE );
1058 mpEntryList->SelectEntry( nPos, TRUE );
1059 mnCurrentPos = nPos;
1060 if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
1062 ImplPaint( nPos );
1063 if ( !IsVisible( nPos ) )
1065 delete mpLayoutData, mpLayoutData = NULL;
1066 USHORT nVisibleEntries = GetLastVisibleEntry()-mnTop;
1067 if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
1069 Resize();
1070 SetTopEntry( nPos );
1072 else
1074 SetTopEntry( nPos-nVisibleEntries+1 );
1079 else
1081 mpEntryList->SelectEntry( nPos, FALSE );
1082 ImplPaint( nPos, TRUE );
1084 mbSelectionChanged = TRUE;
1088 // -----------------------------------------------------------------------
1090 BOOL ImplListBoxWindow::SelectEntries( USHORT nSelect, LB_EVENT_TYPE eLET, BOOL bShift, BOOL bCtrl )
1092 BOOL bFocusChanged = FALSE;
1093 BOOL bSelectionChanged = FALSE;
1095 if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
1097 // Hier (Single-ListBox) kann nur ein Eintrag deselektiert werden
1098 if( !mbMulti )
1100 USHORT nDeselect = mpEntryList->GetSelectEntryPos( 0 );
1101 if( nSelect != nDeselect )
1103 SelectEntry( nSelect, TRUE );
1104 mpEntryList->SetLastSelected( nSelect );
1105 bFocusChanged = TRUE;
1106 bSelectionChanged = TRUE;
1109 // MultiListBox ohne Modifier
1110 else if( mbSimpleMode && !bCtrl && !bShift )
1112 USHORT nEntryCount = mpEntryList->GetEntryCount();
1113 for ( USHORT nPos = 0; nPos < nEntryCount; nPos++ )
1115 BOOL bSelect = nPos == nSelect;
1116 if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
1118 SelectEntry( nPos, bSelect );
1119 bFocusChanged = TRUE;
1120 bSelectionChanged = TRUE;
1123 mpEntryList->SetLastSelected( nSelect );
1124 mpEntryList->SetSelectionAnchor( nSelect );
1126 // MultiListBox nur mit CTRL/SHIFT oder nicht im SimpleMode
1127 else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
1129 // Space fuer Selektionswechsel
1130 if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
1132 BOOL bSelect = ( mbStackMode && IsMouseMoveSelect() ) ? TRUE : !mpEntryList->IsEntryPosSelected( nSelect );
1133 if ( mbStackMode )
1135 USHORT n;
1136 if ( bSelect )
1138 // All entries before nSelect must be selected...
1139 for ( n = 0; n < nSelect; n++ )
1140 SelectEntry( n, TRUE );
1142 if ( !bSelect )
1144 for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
1145 SelectEntry( n, FALSE );
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 = TRUE;
1154 bSelectionChanged = TRUE;
1156 else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
1157 ( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
1159 mnCurrentPos = nSelect;
1160 bFocusChanged = TRUE;
1162 USHORT nAnchor = mpEntryList->GetSelectionAnchor();
1163 if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
1165 nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
1167 if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
1169 // Alle Eintraege vom Anchor bis nSelect muessen selektiert sein
1170 USHORT nStart = Min( nSelect, nAnchor );
1171 USHORT nEnd = Max( nSelect, nAnchor );
1172 for ( USHORT n = nStart; n <= nEnd; n++ )
1174 if ( !mpEntryList->IsEntryPosSelected( n ) )
1176 SelectEntry( n, TRUE );
1177 bSelectionChanged = TRUE;
1181 // Ggf. muss noch was deselektiert werden...
1182 USHORT nLast = mpEntryList->GetLastSelected();
1183 if ( nLast != LISTBOX_ENTRY_NOTFOUND )
1185 if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
1187 for ( USHORT n = nSelect+1; n <= nLast; n++ )
1189 if ( mpEntryList->IsEntryPosSelected( n ) )
1191 SelectEntry( n, FALSE );
1192 bSelectionChanged = TRUE;
1196 else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
1198 for ( USHORT n = nLast; n < nSelect; n++ )
1200 if ( mpEntryList->IsEntryPosSelected( n ) )
1202 SelectEntry( n, FALSE );
1203 bSelectionChanged = TRUE;
1208 mpEntryList->SetLastSelected( nSelect );
1211 else if( eLET != LET_TRACKING )
1213 ImplHideFocusRect();
1214 ImplPaint( nSelect, TRUE );
1215 bFocusChanged = TRUE;
1218 else if( bShift )
1220 bFocusChanged = TRUE;
1223 if( bSelectionChanged )
1224 mbSelectionChanged = TRUE;
1226 if( bFocusChanged )
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();
1236 delete mpLayoutData, mpLayoutData = NULL;
1238 return bSelectionChanged;
1241 // -----------------------------------------------------------------------
1243 void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
1245 Point aPoint;
1246 Rectangle aRect( aPoint, GetOutputSizePixel() );
1247 BOOL bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
1249 if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
1251 if ( bInside && !rTEvt.IsTrackingCanceled() )
1253 mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1254 ImplCallSelect();
1256 else
1258 maCancelHdl.Call( NULL );
1259 if ( !mbMulti )
1261 mbTrackingSelect = TRUE;
1262 SelectEntry( mnTrackingSaveSelection, TRUE );
1263 mbTrackingSelect = FALSE;
1264 if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
1266 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1267 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1268 Size aSz( maFocusRect.GetWidth(),
1269 mpEntryList->GetEntryHeight( mnCurrentPos ) );
1270 maFocusRect.SetSize( aSz );
1271 ImplShowFocusRect();
1276 mbTrack = FALSE;
1278 else
1280 BOOL bTrackOrQuickClick = mbTrack;
1281 if( !mbTrack )
1283 if ( bInside )
1285 mbTrack = TRUE;
1288 // Folgender Fall tritt nur auf, wenn man ganz kurz die Maustaste drueckt
1289 if( rTEvt.IsTrackingEnded() && mbTrack )
1291 bTrackOrQuickClick = TRUE;
1292 mbTrack = FALSE;
1296 if( bTrackOrQuickClick )
1298 MouseEvent aMEvt = rTEvt.GetMouseEvent();
1299 Point aPt( aMEvt.GetPosPixel() );
1300 BOOL bShift = aMEvt.IsShift();
1301 BOOL bCtrl = aMEvt.IsMod1();
1303 USHORT nSelect = LISTBOX_ENTRY_NOTFOUND;
1304 if( aPt.Y() < 0 )
1306 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1308 nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
1309 if( nSelect < mnTop )
1310 SetTopEntry( mnTop-1 );
1313 else if( aPt.Y() > GetOutputSizePixel().Height() )
1315 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1317 nSelect = Min( (USHORT)(mnCurrentPos+1), (USHORT)(mpEntryList->GetEntryCount()-1) );
1318 if( nSelect >= GetLastVisibleEntry() )
1319 SetTopEntry( mnTop+1 );
1322 else
1324 nSelect = (USHORT) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (USHORT) mnTop;
1325 nSelect = Min( nSelect, GetLastVisibleEntry() );
1326 nSelect = Min( nSelect, (USHORT) ( mpEntryList->GetEntryCount() - 1 ) );
1329 if ( bInside )
1331 if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
1333 mbTrackingSelect = TRUE;
1334 if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
1336 if ( mbStackMode ) // #87734# (#87072#)
1338 mbTravelSelect = TRUE;
1339 mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1340 ImplCallSelect();
1341 mbTravelSelect = FALSE;
1344 mbTrackingSelect = FALSE;
1347 else
1349 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1351 mbTrackingSelect = TRUE;
1352 SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), FALSE );
1353 mbTrackingSelect = FALSE;
1355 else if ( mbStackMode )
1357 if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
1359 if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1361 BOOL bSelectionChanged = FALSE;
1362 if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
1363 && !mnCurrentPos )
1365 if ( mpEntryList->IsEntryPosSelected( 0 ) )
1367 SelectEntry( 0, FALSE );
1368 bSelectionChanged = TRUE;
1369 nSelect = LISTBOX_ENTRY_NOTFOUND;
1373 else
1375 mbTrackingSelect = TRUE;
1376 bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
1377 mbTrackingSelect = FALSE;
1380 if ( bSelectionChanged )
1382 mbSelectionChanged = TRUE;
1383 mbTravelSelect = TRUE;
1384 mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1385 ImplCallSelect();
1386 mbTravelSelect = FALSE;
1392 mnCurrentPos = nSelect;
1393 if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1395 ImplHideFocusRect();
1397 else
1399 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1400 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1401 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1402 maFocusRect.SetSize( aSz );
1403 ImplShowFocusRect();
1410 // -----------------------------------------------------------------------
1412 void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
1414 if( !ProcessKeyInput( rKEvt ) )
1415 Control::KeyInput( rKEvt );
1418 // -----------------------------------------------------------------------
1420 #define IMPL_SELECT_NODIRECTION 0
1421 #define IMPL_SELECT_UP 1
1422 #define IMPL_SELECT_DOWN 2
1424 BOOL ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
1426 // zu selektierender Eintrag
1427 USHORT nSelect = LISTBOX_ENTRY_NOTFOUND;
1428 LB_EVENT_TYPE eLET = LET_KEYMOVE;
1430 KeyCode aKeyCode = rKEvt.GetKeyCode();
1432 BOOL bShift = aKeyCode.IsShift();
1433 BOOL bCtrl = aKeyCode.IsMod1() || aKeyCode.IsMod3();
1434 BOOL bMod2 = aKeyCode.IsMod2();
1435 BOOL bDone = FALSE;
1437 switch( aKeyCode.GetCode() )
1439 case KEY_UP:
1441 if ( IsReadOnly() )
1443 if ( GetTopEntry() )
1444 SetTopEntry( GetTopEntry()-1 );
1446 else if ( !bMod2 )
1448 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1450 nSelect = mpEntryList->FindFirstSelectable( 0, true );
1452 else if ( mnCurrentPos )
1454 // search first selectable above the current position
1455 nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
1458 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
1459 SetTopEntry( mnTop-1 );
1461 bDone = TRUE;
1463 maSearchStr.Erase();
1465 break;
1467 case KEY_DOWN:
1469 if ( IsReadOnly() )
1471 SetTopEntry( GetTopEntry()+1 );
1473 else if ( !bMod2 )
1475 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1477 nSelect = mpEntryList->FindFirstSelectable( 0, true );
1479 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1481 // search first selectable below the current position
1482 nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
1485 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
1486 SetTopEntry( mnTop+1 );
1488 bDone = TRUE;
1490 maSearchStr.Erase();
1492 break;
1494 case KEY_PAGEUP:
1496 if ( IsReadOnly() )
1498 USHORT nCurVis = GetLastVisibleEntry() - mnTop +1;
1499 SetTopEntry( ( mnTop > nCurVis ) ?
1500 (mnTop-nCurVis) : 0 );
1502 else if ( !bCtrl && !bMod2 )
1504 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1506 nSelect = mpEntryList->FindFirstSelectable( 0, true );
1508 else if ( mnCurrentPos )
1510 if( mnCurrentPos == mnTop )
1512 USHORT nCurVis = GetLastVisibleEntry() - mnTop +1;
1513 SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
1516 // find first selectable starting from mnTop looking foreward
1517 nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
1519 bDone = TRUE;
1521 maSearchStr.Erase();
1523 break;
1525 case KEY_PAGEDOWN:
1527 if ( IsReadOnly() )
1529 SetTopEntry( GetLastVisibleEntry() );
1531 else if ( !bCtrl && !bMod2 )
1533 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1535 nSelect = mpEntryList->FindFirstSelectable( 0, true );
1537 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1539 USHORT nCount = mpEntryList->GetEntryCount();
1540 USHORT nCurVis = GetLastVisibleEntry() - mnTop;
1541 USHORT nTmp = Min( nCurVis, nCount );
1542 nTmp += mnTop - 1;
1543 if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
1545 long nTmp2 = Min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
1546 nTmp2 = Max( (long)0 , nTmp2 );
1547 nTmp = (USHORT)(nTmp2+(nCurVis-1) );
1548 SetTopEntry( (USHORT)nTmp2 );
1550 // find first selectable starting from nTmp looking backwards
1551 nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
1553 bDone = TRUE;
1555 maSearchStr.Erase();
1557 break;
1559 case KEY_HOME:
1561 if ( IsReadOnly() )
1563 SetTopEntry( 0 );
1565 else if ( !bCtrl && !bMod2 )
1567 if ( mnCurrentPos )
1569 nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
1570 if( mnTop != 0 )
1571 SetTopEntry( 0 );
1573 bDone = TRUE;
1576 maSearchStr.Erase();
1578 break;
1580 case KEY_END:
1582 if ( IsReadOnly() )
1584 SetTopEntry( 0xFFFF );
1586 else if ( !bCtrl && !bMod2 )
1588 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1590 nSelect = mpEntryList->FindFirstSelectable( 0, true );
1592 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1594 USHORT nCount = mpEntryList->GetEntryCount();
1595 nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
1596 USHORT nCurVis = GetLastVisibleEntry() - mnTop + 1;
1597 if( nCount > nCurVis )
1598 SetTopEntry( nCount - nCurVis );
1600 bDone = TRUE;
1602 maSearchStr.Erase();
1604 break;
1606 case KEY_LEFT:
1608 if ( !bCtrl && !bMod2 )
1610 ScrollHorz( -HORZ_SCROLL );
1611 bDone = TRUE;
1613 maSearchStr.Erase();
1615 break;
1617 case KEY_RIGHT:
1619 if ( !bCtrl && !bMod2 )
1621 ScrollHorz( HORZ_SCROLL );
1622 bDone = TRUE;
1624 maSearchStr.Erase();
1626 break;
1628 case KEY_RETURN:
1630 if ( !bMod2 && !IsReadOnly() )
1632 mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1633 ImplCallSelect();
1634 bDone = FALSE; // RETURN nicht abfangen.
1636 maSearchStr.Erase();
1638 break;
1640 case KEY_SPACE:
1642 if ( !bMod2 && !IsReadOnly() )
1644 if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
1646 nSelect = mnCurrentPos;
1647 eLET = LET_KEYSPACE;
1649 bDone = TRUE;
1651 maSearchStr.Erase();
1653 break;
1655 case KEY_A:
1657 if( bCtrl && mbMulti )
1659 // paint only once
1660 BOOL bUpdates = IsUpdateMode();
1661 SetUpdateMode( FALSE );
1663 USHORT nEntryCount = mpEntryList->GetEntryCount();
1664 for( USHORT i = 0; i < nEntryCount; i++ )
1665 SelectEntry( i, TRUE );
1667 // restore update mode
1668 SetUpdateMode( bUpdates );
1669 Invalidate();
1671 maSearchStr.Erase();
1673 bDone = TRUE;
1674 break;
1677 // fall through intentional
1678 default:
1680 xub_Unicode c = rKEvt.GetCharCode();
1682 if ( !IsReadOnly() && (c >= 32) && (c != 127) && !rKEvt.GetKeyCode().IsMod2() )
1684 maSearchStr += c;
1685 XubString aTmpSearch( maSearchStr );
1687 nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, mnCurrentPos );
1688 if ( (nSelect == LISTBOX_ENTRY_NOTFOUND) && (aTmpSearch.Len() > 1) )
1690 // Wenn alles die gleichen Buchstaben, dann anderer Such-Modus
1691 BOOL bAllEqual = TRUE;
1692 for ( USHORT n = aTmpSearch.Len(); n && bAllEqual; )
1693 bAllEqual = aTmpSearch.GetChar( --n ) == c;
1694 if ( bAllEqual )
1696 aTmpSearch = c;
1697 nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, mnCurrentPos+1 );
1700 if ( nSelect == LISTBOX_ENTRY_NOTFOUND )
1701 nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, 0 );
1703 if ( nSelect != LISTBOX_ENTRY_NOTFOUND )
1705 USHORT nCurVis = GetLastVisibleEntry() - mnTop + 1;
1706 if( nSelect < mnTop )
1707 SetTopEntry( nSelect );
1708 else if( nSelect >= (mnTop + nCurVis) )
1709 SetTopEntry( nSelect - nCurVis + 1 );
1711 if ( mpEntryList->IsEntryPosSelected( nSelect ) )
1712 nSelect = LISTBOX_ENTRY_NOTFOUND;
1714 maSearchTimeout.Start();
1716 else
1717 maSearchStr.Erase();
1718 bDone = TRUE;
1723 if ( ( nSelect != LISTBOX_ENTRY_NOTFOUND )
1724 && ( ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1725 || ( eLET == LET_KEYSPACE )
1729 DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
1730 if( nSelect >= mpEntryList->GetEntryCount() )
1731 nSelect = mpEntryList->GetEntryCount()-1;
1732 mnCurrentPos = nSelect;
1733 if ( SelectEntries( nSelect, eLET, bShift, bCtrl ) )
1735 mbTravelSelect = TRUE;
1736 mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1737 ImplCallSelect();
1738 mbTravelSelect = FALSE;
1742 return bDone;
1745 // -----------------------------------------------------------------------
1747 void ImplListBoxWindow::ImplPaint( USHORT nPos, BOOL bErase, bool bLayout )
1749 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1751 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1752 if( ! pEntry )
1753 return;
1755 long nWidth = GetOutputSizePixel().Width();
1756 long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1757 Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
1759 if( ! bLayout )
1761 if( mpEntryList->IsEntryPosSelected( nPos ) )
1763 SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
1764 SetFillColor( rStyleSettings.GetHighlightColor() );
1765 SetTextFillColor( rStyleSettings.GetHighlightColor() );
1766 DrawRect( aRect );
1768 else
1770 ImplInitSettings( FALSE, TRUE, FALSE );
1771 if( !IsEnabled() )
1772 SetTextColor( rStyleSettings.GetDisableColor() );
1773 SetTextFillColor();
1774 if( bErase )
1775 Erase( aRect );
1779 if ( IsUserDrawEnabled() )
1781 mbInUserDraw = TRUE;
1782 mnUserDrawEntry = nPos;
1783 aRect.Left() -= mnLeft;
1784 if ( nPos < GetEntryList()->GetMRUCount() )
1785 nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
1786 nPos = sal::static_int_cast<USHORT>(nPos - GetEntryList()->GetMRUCount());
1787 UserDrawEvent aUDEvt( this, aRect, nPos, 0 );
1788 maUserDrawHdl.Call( &aUDEvt );
1789 mbInUserDraw = FALSE;
1791 else
1793 DrawEntry( nPos, TRUE, TRUE, FALSE, bLayout );
1797 // -----------------------------------------------------------------------
1799 void ImplListBoxWindow::DrawEntry( USHORT nPos, BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos, bool bLayout )
1801 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1802 if( ! pEntry )
1803 return;
1805 // Bei Aenderungen in dieser Methode ggf. auch ImplWin::DrawEntry() anpassen.
1807 if ( mbInUserDraw )
1808 nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
1810 long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1811 Size aImgSz;
1813 if( bDrawImage && mpEntryList->HasImages() && !bLayout )
1815 Image aImage = mpEntryList->GetEntryImage( nPos );
1816 if( !!aImage )
1818 aImgSz = aImage.GetSizePixel();
1819 Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
1821 // pb: #106948# explicit mirroring for calc
1822 if ( mbMirroring )
1823 // right aligned
1824 aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
1826 if ( !IsZoom() )
1828 DrawImage( aPtImg, aImage );
1830 else
1832 aImgSz.Width() = CalcZoom( aImgSz.Width() );
1833 aImgSz.Height() = CalcZoom( aImgSz.Height() );
1834 DrawImage( aPtImg, aImgSz, aImage );
1839 if( bDrawText )
1841 MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL;
1842 String* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL;
1843 XubString aStr( mpEntryList->GetEntryText( nPos ) );
1844 if ( aStr.Len() )
1846 long nMaxWidth = Max( static_cast< long >( mnMaxWidth ),
1847 GetOutputSizePixel().Width() - 2*mnBorder );
1848 // a multiline entry should only be as wide a the window
1849 if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1850 nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
1852 Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
1853 Size( nMaxWidth, pEntry->mnHeight ) );
1855 if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
1857 long nImageWidth = Max( mnMaxImgWidth, maUserItemSize.Width() );
1858 aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
1861 if( bLayout )
1862 mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.Len() );
1864 // pb: #106948# explicit mirroring for calc
1865 if ( mbMirroring )
1867 // right aligned
1868 aTextRect.Left() = nMaxWidth + mnBorder - GetTextWidth( aStr ) - mnLeft;
1869 if ( aImgSz.Width() > 0 )
1870 aTextRect.Left() -= ( aImgSz.Width() + IMG_TXT_DISTANCE );
1873 USHORT nDrawStyle = ImplGetTextStyle();
1874 if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1875 nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
1877 DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
1881 if( !bLayout )
1883 if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
1884 ( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
1886 Color aOldLineColor( GetLineColor() );
1887 SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
1888 Point aStartPos( 0, nY );
1889 if ( nPos == mnSeparatorPos )
1890 aStartPos.Y() += pEntry->mnHeight-1;
1891 Point aEndPos( aStartPos );
1892 aEndPos.X() = GetOutputSizePixel().Width();
1893 DrawLine( aStartPos, aEndPos );
1894 SetLineColor( aOldLineColor );
1899 // -----------------------------------------------------------------------
1901 void ImplListBoxWindow::FillLayoutData() const
1903 mpLayoutData = new vcl::ControlLayoutData();
1904 const_cast<ImplListBoxWindow*>(this)->
1905 ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
1908 // -----------------------------------------------------------------------
1910 void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
1912 USHORT nCount = mpEntryList->GetEntryCount();
1914 BOOL bShowFocusRect = mbHasFocusRect;
1915 if ( mbHasFocusRect && ! bLayout )
1916 ImplHideFocusRect();
1918 long nY = 0; // + mnBorder;
1919 long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1921 for( USHORT i = (USHORT)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
1923 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
1924 if( nY + pEntry->mnHeight >= rRect.Top() &&
1925 nY <= rRect.Bottom() + mnMaxHeight )
1927 ImplPaint( i, FALSE, bLayout );
1929 nY += pEntry->mnHeight;
1932 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1933 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1934 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1935 maFocusRect.SetSize( aSz );
1936 if( HasFocus() && bShowFocusRect && !bLayout )
1937 ImplShowFocusRect();
1940 // -----------------------------------------------------------------------
1942 void ImplListBoxWindow::Paint( const Rectangle& rRect )
1944 ImplDoPaint( rRect );
1947 // -----------------------------------------------------------------------
1949 USHORT ImplListBoxWindow::GetDisplayLineCount() const
1951 // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
1953 USHORT nCount = mpEntryList->GetEntryCount();
1954 long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1955 USHORT nEntries = static_cast< USHORT >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
1956 if( nEntries > nCount-mnTop )
1957 nEntries = nCount-mnTop;
1959 return nEntries;
1962 // -----------------------------------------------------------------------
1964 void ImplListBoxWindow::Resize()
1966 Control::Resize();
1968 BOOL bShowFocusRect = mbHasFocusRect;
1969 if ( bShowFocusRect )
1970 ImplHideFocusRect();
1972 if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1974 Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1975 maFocusRect.SetSize( aSz );
1978 if ( bShowFocusRect )
1979 ImplShowFocusRect();
1981 delete mpLayoutData, mpLayoutData = NULL;
1984 // -----------------------------------------------------------------------
1986 void ImplListBoxWindow::GetFocus()
1988 USHORT nPos = mnCurrentPos;
1989 if ( nPos == LISTBOX_ENTRY_NOTFOUND )
1990 nPos = 0;
1991 long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
1992 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1993 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
1994 maFocusRect.SetSize( aSz );
1995 ImplShowFocusRect();
1996 Control::GetFocus();
1999 // -----------------------------------------------------------------------
2001 void ImplListBoxWindow::LoseFocus()
2003 ImplHideFocusRect();
2004 Control::LoseFocus();
2007 // -----------------------------------------------------------------------
2010 void ImplListBoxWindow::RequestHelp( const HelpEvent& rHEvt )
2012 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
2013 Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), String() );
2015 Window::RequestHelp( rHEvt );
2019 // -----------------------------------------------------------------------
2021 void ImplListBoxWindow::SetTopEntry( USHORT nTop )
2023 if( mpEntryList->GetEntryCount() == 0 )
2024 return;
2026 long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2028 USHORT nLastEntry = mpEntryList->GetEntryCount()-1;
2029 if( nTop > nLastEntry )
2030 nTop = nLastEntry;
2031 const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
2032 while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
2033 nTop--;
2035 if ( nTop != mnTop )
2037 delete mpLayoutData, mpLayoutData = NULL;
2038 long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
2039 Update();
2040 ImplHideFocusRect();
2041 mnTop = nTop;
2042 Scroll( 0, nDiff );
2043 Update();
2044 maFocusRect.Top() += nDiff;
2045 maFocusRect.Bottom() += nDiff;
2046 if( HasFocus() )
2047 ImplShowFocusRect();
2048 maScrollHdl.Call( this );
2052 // -----------------------------------------------------------------------
2054 void ImplListBoxWindow::SetLeftIndent( long n )
2056 ScrollHorz( n - mnLeft );
2059 // -----------------------------------------------------------------------
2061 void ImplListBoxWindow::ScrollHorz( long n )
2063 long nDiff = 0;
2064 if ( n > 0 )
2066 long nWidth = GetOutputSizePixel().Width();
2067 if( ( mnMaxWidth - mnLeft + n ) > nWidth )
2068 nDiff = n;
2070 else if ( n < 0 )
2072 if( mnLeft )
2074 long nAbs = -n;
2075 nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
2079 if ( nDiff )
2081 delete mpLayoutData, mpLayoutData = NULL;
2082 mnLeft = sal::static_int_cast<USHORT>(mnLeft + nDiff);
2083 Update();
2084 ImplHideFocusRect();
2085 Scroll( -nDiff, 0 );
2086 Update();
2087 if( HasFocus() )
2088 ImplShowFocusRect();
2089 maScrollHdl.Call( this );
2093 // -----------------------------------------------------------------------
2095 Size ImplListBoxWindow::CalcSize( USHORT nMaxLines ) const
2097 // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2099 Size aSz;
2100 // USHORT nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
2101 aSz.Height() = nMaxLines * mnMaxHeight;
2102 aSz.Width() = mnMaxWidth + 2*mnBorder;
2103 return aSz;
2106 // -----------------------------------------------------------------------
2108 Rectangle ImplListBoxWindow::GetBoundingRectangle( USHORT nItem ) const
2110 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
2111 Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
2112 long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) - mpEntryList->GetAddedHeight( GetTopEntry() );
2113 Rectangle aRect( Point( 0, nY ), aSz );
2114 return aRect;
2118 // -----------------------------------------------------------------------
2120 void ImplListBoxWindow::StateChanged( StateChangedType nType )
2122 Control::StateChanged( nType );
2124 if ( nType == STATE_CHANGE_ZOOM )
2126 ImplInitSettings( TRUE, FALSE, FALSE );
2127 ImplCalcMetrics();
2128 Invalidate();
2130 else if ( nType == STATE_CHANGE_UPDATEMODE )
2132 if ( IsUpdateMode() && IsReallyVisible() )
2133 Invalidate();
2135 else if ( nType == STATE_CHANGE_CONTROLFONT )
2137 ImplInitSettings( TRUE, FALSE, FALSE );
2138 ImplCalcMetrics();
2139 Invalidate();
2141 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2143 ImplInitSettings( FALSE, TRUE, FALSE );
2144 Invalidate();
2146 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2148 ImplInitSettings( FALSE, FALSE, TRUE );
2149 Invalidate();
2151 delete mpLayoutData, mpLayoutData = NULL;
2154 // -----------------------------------------------------------------------
2156 void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
2158 Control::DataChanged( rDCEvt );
2160 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2161 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2162 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2163 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2165 delete mpLayoutData, mpLayoutData = NULL;
2166 ImplInitSettings( TRUE, TRUE, TRUE );
2167 ImplCalcMetrics();
2168 Invalidate();
2172 // -----------------------------------------------------------------------
2174 USHORT ImplListBoxWindow::ImplGetTextStyle() const
2176 USHORT nTextStyle = TEXT_DRAW_VCENTER;
2178 if ( mpEntryList->HasImages() )
2179 nTextStyle |= TEXT_DRAW_LEFT;
2180 else if ( mbCenter )
2181 nTextStyle |= TEXT_DRAW_CENTER;
2182 else if ( mbRight )
2183 nTextStyle |= TEXT_DRAW_RIGHT;
2184 else
2185 nTextStyle |= TEXT_DRAW_LEFT;
2187 return nTextStyle;
2190 // =======================================================================
2192 ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
2193 Control( pParent, nWinStyle ),
2194 maLBWindow( this, nWinStyle&(~WB_BORDER) )
2196 // for native widget rendering we must be able to detect this window type
2197 SetType( WINDOW_LISTBOXWINDOW );
2199 mpVScrollBar = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
2200 mpHScrollBar = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
2201 mpScrollBarBox = new ScrollBarBox( this );
2203 Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
2204 mpVScrollBar->SetScrollHdl( aLink );
2205 mpHScrollBar->SetScrollHdl( aLink );
2207 mbVScroll = FALSE;
2208 mbHScroll = FALSE;
2209 mbAutoHScroll = ( nWinStyle & WB_AUTOHSCROLL ) ? TRUE : FALSE;
2211 maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
2212 maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
2213 maLBWindow.Show();
2216 // -----------------------------------------------------------------------
2218 ImplListBox::~ImplListBox()
2220 delete mpHScrollBar;
2221 delete mpVScrollBar;
2222 delete mpScrollBarBox;
2225 // -----------------------------------------------------------------------
2227 void ImplListBox::Clear()
2229 maLBWindow.Clear();
2230 if ( GetEntryList()->GetMRUCount() )
2232 maLBWindow.GetEntryList()->SetMRUCount( 0 );
2233 maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
2235 mpVScrollBar->SetThumbPos( 0 );
2236 mpHScrollBar->SetThumbPos( 0 );
2237 StateChanged( STATE_CHANGE_DATA );
2240 // -----------------------------------------------------------------------
2242 USHORT ImplListBox::InsertEntry( USHORT nPos, const XubString& rStr )
2244 ImplEntryType* pNewEntry = new ImplEntryType( rStr );
2245 USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2246 StateChanged( STATE_CHANGE_DATA );
2247 return nNewPos;
2250 // -----------------------------------------------------------------------
2252 USHORT ImplListBox::InsertEntry( USHORT nPos, const Image& rImage )
2254 ImplEntryType* pNewEntry = new ImplEntryType( rImage );
2255 USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2256 StateChanged( STATE_CHANGE_DATA );
2257 return nNewPos;
2260 // -----------------------------------------------------------------------
2262 USHORT ImplListBox::InsertEntry( USHORT nPos, const XubString& rStr, const Image& rImage )
2264 ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
2265 USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2266 StateChanged( STATE_CHANGE_DATA );
2267 return nNewPos;
2270 // -----------------------------------------------------------------------
2272 void ImplListBox::RemoveEntry( USHORT nPos )
2274 maLBWindow.RemoveEntry( nPos );
2275 StateChanged( STATE_CHANGE_DATA );
2278 // -----------------------------------------------------------------------
2280 void ImplListBox::SetEntryFlags( USHORT nPos, long nFlags )
2282 maLBWindow.SetEntryFlags( nPos, nFlags );
2285 // -----------------------------------------------------------------------
2287 long ImplListBox::GetEntryFlags( USHORT nPos ) const
2289 return maLBWindow.GetEntryList()->GetEntryFlags( nPos );
2292 // -----------------------------------------------------------------------
2294 void ImplListBox::SelectEntry( USHORT nPos, BOOL bSelect )
2296 maLBWindow.SelectEntry( nPos, bSelect );
2299 // -----------------------------------------------------------------------
2301 void ImplListBox::SetNoSelection()
2303 maLBWindow.DeselectAll();
2306 // -----------------------------------------------------------------------
2308 void ImplListBox::GetFocus()
2310 maLBWindow.GrabFocus();
2313 // -----------------------------------------------------------------------
2315 Window* ImplListBox::GetPreferredKeyInputWindow()
2317 return &maLBWindow;
2320 // -----------------------------------------------------------------------
2322 void ImplListBox::Resize()
2324 Control::Resize();
2325 ImplResizeControls();
2326 ImplCheckScrollBars();
2330 // -----------------------------------------------------------------------
2332 IMPL_LINK( ImplListBox, MRUChanged, void*, EMPTYARG )
2334 StateChanged( STATE_CHANGE_DATA );
2335 return 1;
2338 // -----------------------------------------------------------------------
2340 IMPL_LINK( ImplListBox, LBWindowScrolled, void*, EMPTYARG )
2342 mpVScrollBar->SetThumbPos( GetTopEntry() );
2343 mpHScrollBar->SetThumbPos( GetLeftIndent() );
2345 maScrollHdl.Call( this );
2347 return 1;
2350 // -----------------------------------------------------------------------
2352 IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
2354 USHORT nPos = (USHORT) pSB->GetThumbPos();
2355 if( pSB == mpVScrollBar )
2356 SetTopEntry( nPos );
2357 else if( pSB == mpHScrollBar )
2358 SetLeftIndent( nPos );
2360 return 1;
2363 // -----------------------------------------------------------------------
2365 void ImplListBox::ImplCheckScrollBars()
2367 BOOL bArrange = FALSE;
2369 Size aOutSz = GetOutputSizePixel();
2370 USHORT nEntries = GetEntryList()->GetEntryCount();
2371 USHORT nMaxVisEntries = (USHORT) (aOutSz.Height() / GetEntryHeight());
2373 // vert. ScrollBar
2374 if( nEntries > nMaxVisEntries )
2376 if( !mbVScroll )
2377 bArrange = TRUE;
2378 mbVScroll = TRUE;
2380 // Ueberpruefung des rausgescrollten Bereichs
2381 SetTopEntry( GetTopEntry() ); // MaxTop wird geprueft...
2383 else
2385 if( mbVScroll )
2386 bArrange = TRUE;
2387 mbVScroll = FALSE;
2388 SetTopEntry( 0 );
2391 // horz. ScrollBar
2392 if( mbAutoHScroll )
2394 long nWidth = (USHORT) aOutSz.Width();
2395 if ( mbVScroll )
2396 nWidth -= mpVScrollBar->GetSizePixel().Width();
2398 long nMaxWidth = GetMaxEntryWidth();
2399 if( nWidth < nMaxWidth )
2401 if( !mbHScroll )
2402 bArrange = TRUE;
2403 mbHScroll = TRUE;
2405 if ( !mbVScroll ) // ggf. brauchen wir jetzt doch einen
2407 nMaxVisEntries = (USHORT) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
2408 if( nEntries > nMaxVisEntries )
2410 bArrange = TRUE;
2411 mbVScroll = TRUE;
2413 // Ueberpruefung des rausgescrollten Bereichs
2414 SetTopEntry( GetTopEntry() ); // MaxTop wird geprueft...
2418 // Ueberpruefung des rausgescrollten Bereichs
2419 USHORT nMaxLI = (USHORT) (nMaxWidth - nWidth);
2420 if ( nMaxLI < GetLeftIndent() )
2421 SetLeftIndent( nMaxLI );
2423 else
2425 if( mbHScroll )
2426 bArrange = TRUE;
2427 mbHScroll = FALSE;
2428 SetLeftIndent( 0 );
2432 if( bArrange )
2433 ImplResizeControls();
2435 ImplInitScrollBars();
2438 // -----------------------------------------------------------------------
2440 void ImplListBox::ImplInitScrollBars()
2442 Size aOutSz = maLBWindow.GetOutputSizePixel();
2444 if ( mbVScroll )
2446 USHORT nEntries = GetEntryList()->GetEntryCount();
2447 USHORT nVisEntries = (USHORT) (aOutSz.Height() / GetEntryHeight());
2448 mpVScrollBar->SetRangeMax( nEntries );
2449 mpVScrollBar->SetVisibleSize( nVisEntries );
2450 mpVScrollBar->SetPageSize( nVisEntries - 1 );
2453 if ( mbHScroll )
2455 mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
2456 mpHScrollBar->SetVisibleSize( (USHORT)aOutSz.Width() );
2457 mpHScrollBar->SetLineSize( HORZ_SCROLL );
2458 mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
2462 // -----------------------------------------------------------------------
2464 void ImplListBox::ImplResizeControls()
2466 // Hier werden die Controls nur angeordnet, ob die Scrollbars
2467 // sichtbar sein sollen wird bereits in ImplCheckScrollBars ermittelt.
2469 Size aOutSz = GetOutputSizePixel();
2470 long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2471 nSBWidth = CalcZoom( nSBWidth );
2473 Size aInnerSz( aOutSz );
2474 if ( mbVScroll )
2475 aInnerSz.Width() -= nSBWidth;
2476 if ( mbHScroll )
2477 aInnerSz.Height() -= nSBWidth;
2479 // pb: #106948# explicit mirroring for calc
2480 // Scrollbar on left or right side?
2481 BOOL bMirroring = maLBWindow.IsMirroring();
2482 Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
2483 maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
2485 // ScrollBarBox
2486 if( mbVScroll && mbHScroll )
2488 Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
2489 mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
2490 mpScrollBarBox->Show();
2492 else
2494 mpScrollBarBox->Hide();
2497 // vert. ScrollBar
2498 if( mbVScroll )
2500 // Scrollbar on left or right side?
2501 Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
2502 mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
2503 mpVScrollBar->Show();
2505 else
2507 mpVScrollBar->Hide();
2508 // #107254# Don't reset top entry after resize, but check for max top entry
2509 SetTopEntry( GetTopEntry() );
2512 // horz. ScrollBar
2513 if( mbHScroll )
2515 Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
2516 mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
2517 mpHScrollBar->Show();
2519 else
2521 mpHScrollBar->Hide();
2522 SetLeftIndent( 0 );
2526 // -----------------------------------------------------------------------
2528 void ImplListBox::StateChanged( StateChangedType nType )
2530 if ( nType == STATE_CHANGE_INITSHOW )
2532 ImplCheckScrollBars();
2534 else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
2536 BOOL bUpdate = IsUpdateMode();
2537 maLBWindow.SetUpdateMode( bUpdate );
2538 // mpHScrollBar->SetUpdateMode( bUpdate );
2539 // mpVScrollBar->SetUpdateMode( bUpdate );
2540 if ( bUpdate && IsReallyVisible() )
2541 ImplCheckScrollBars();
2543 else if( nType == STATE_CHANGE_ENABLE )
2545 mpHScrollBar->Enable( IsEnabled() );
2546 mpVScrollBar->Enable( IsEnabled() );
2547 mpScrollBarBox->Enable( IsEnabled() );
2548 Invalidate();
2550 else if ( nType == STATE_CHANGE_ZOOM )
2552 maLBWindow.SetZoom( GetZoom() );
2553 Resize();
2555 else if ( nType == STATE_CHANGE_CONTROLFONT )
2557 maLBWindow.SetControlFont( GetControlFont() );
2559 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2561 maLBWindow.SetControlForeground( GetControlForeground() );
2563 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2565 maLBWindow.SetControlBackground( GetControlBackground() );
2567 else if( nType == STATE_CHANGE_MIRRORING )
2569 maLBWindow.EnableRTL( IsRTLEnabled() );
2570 mpHScrollBar->EnableRTL( IsRTLEnabled() );
2571 mpVScrollBar->EnableRTL( IsRTLEnabled() );
2572 ImplResizeControls();
2575 Control::StateChanged( nType );
2578 // -----------------------------------------------------------------------
2580 void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
2582 // if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2583 // (rDCEvt.GetFlags() & SETTINGS_STYLE) )
2584 // {
2585 // maLBWindow.SetSettings( GetSettings() );
2586 // Resize();
2587 // }
2588 // else
2589 Control::DataChanged( rDCEvt );
2592 // -----------------------------------------------------------------------
2594 long ImplListBox::Notify( NotifyEvent& rNEvt )
2596 long nDone = 0;
2597 if ( rNEvt.GetType() == EVENT_COMMAND )
2599 const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2600 if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2602 const CommandWheelData* pData = rCEvt.GetWheelData();
2603 if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2605 nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
2610 return nDone ? nDone : Window::Notify( rNEvt );
2613 // -----------------------------------------------------------------------
2615 const Wallpaper& ImplListBox::GetDisplayBackground() const
2617 return maLBWindow.GetDisplayBackground();
2620 // -----------------------------------------------------------------------
2622 BOOL ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
2624 BOOL bDone = FALSE;
2625 if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2627 const CommandWheelData* pData = rCEvt.GetWheelData();
2628 if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2630 USHORT nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
2631 KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
2632 bDone = ProcessKeyInput( aKeyEvent );
2635 return bDone;
2638 // -----------------------------------------------------------------------
2640 void ImplListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
2642 BOOL bChanges = GetEntryList()->GetMRUCount() ? TRUE : FALSE;
2644 // Remove old MRU entries
2645 for ( USHORT n = GetEntryList()->GetMRUCount();n; )
2646 maLBWindow.RemoveEntry( --n );
2648 USHORT nMRUCount = 0;
2649 USHORT nEntries = rEntries.GetTokenCount( cSep );
2650 for ( USHORT nEntry = 0; nEntry < nEntries; nEntry++ )
2652 XubString aEntry = rEntries.GetToken( nEntry, cSep );
2653 // Accept only existing entries
2654 if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
2656 ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
2657 maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, FALSE );
2658 bChanges = TRUE;
2662 if ( bChanges )
2664 maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
2665 SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
2666 StateChanged( STATE_CHANGE_DATA );
2670 // -----------------------------------------------------------------------
2672 XubString ImplListBox::GetMRUEntries( xub_Unicode cSep ) const
2674 String aEntries;
2675 for ( USHORT n = 0; n < GetEntryList()->GetMRUCount(); n++ )
2677 aEntries += GetEntryList()->GetEntryText( n );
2678 if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
2679 aEntries += cSep;
2681 return aEntries;
2684 // =======================================================================
2686 ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
2687 Control ( pParent, nWinStyle )
2689 if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2690 && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2691 SetBackground();
2692 else
2693 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2695 mbInUserDraw = FALSE;
2696 mbUserDrawEnabled = FALSE;
2697 mnItemPos = LISTBOX_ENTRY_NOTFOUND;
2700 // -----------------------------------------------------------------------
2702 BOOL ImplWin::SetModeImage( const Image& rImage, BmpColorMode eMode )
2704 if( eMode == BMP_COLOR_NORMAL )
2705 SetImage( rImage );
2706 else if( eMode == BMP_COLOR_HIGHCONTRAST )
2707 maImageHC = rImage;
2708 else
2709 return FALSE;
2710 return TRUE;
2713 // -----------------------------------------------------------------------
2715 const Image& ImplWin::GetModeImage( BmpColorMode eMode ) const
2717 if( eMode == BMP_COLOR_HIGHCONTRAST )
2718 return maImageHC;
2719 else
2720 return maImage;
2723 // -----------------------------------------------------------------------
2725 void ImplWin::MBDown()
2727 if( IsEnabled() )
2728 maMBDownHdl.Call( this );
2731 // -----------------------------------------------------------------------
2733 void ImplWin::MouseButtonDown( const MouseEvent& )
2735 if( IsEnabled() )
2737 // Control::MouseButtonDown( rMEvt );
2738 MBDown();
2742 // -----------------------------------------------------------------------
2744 void ImplWin::FillLayoutData() const
2746 mpLayoutData = new vcl::ControlLayoutData();
2747 const_cast<ImplWin*>(this)->ImplDraw( true );
2750 // -----------------------------------------------------------------------
2752 long ImplWin::PreNotify( NotifyEvent& rNEvt )
2754 long nDone = 0;
2755 const MouseEvent* pMouseEvt = NULL;
2757 if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
2759 if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
2761 // trigger redraw as mouse over state has changed
2762 if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2763 && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2765 GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
2766 GetParent()->GetWindow( WINDOW_BORDER )->Update();
2771 return nDone ? nDone : Control::PreNotify(rNEvt);
2774 // -----------------------------------------------------------------------
2776 void ImplWin::ImplDraw( bool bLayout )
2778 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2780 BOOL bNativeOK = FALSE;
2782 if( ! bLayout )
2784 ControlState nState = CTRL_STATE_ENABLED;
2785 if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2786 && IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
2788 // Repaint the (focused) area similarly to
2789 // ImplSmallBorderWindowView::DrawWindow() in
2790 // vcl/source/window/brdwin.cxx
2791 Window *pWin = GetParent();
2793 ImplControlValue aControlValue;
2794 if ( !pWin->IsEnabled() )
2795 nState &= ~CTRL_STATE_ENABLED;
2796 if ( pWin->HasFocus() )
2797 nState |= CTRL_STATE_FOCUSED;
2799 // The listbox is painted over the entire control including the
2800 // border, but ImplWin does not contain the border => correction
2801 // needed.
2802 sal_Int32 nLeft, nTop, nRight, nBottom;
2803 pWin->GetBorder( nLeft, nTop, nRight, nBottom );
2804 Point aPoint( -nLeft, -nTop );
2805 Region aCtrlRegion( Rectangle( aPoint - GetPosPixel(), pWin->GetSizePixel() ) );
2807 BOOL bMouseOver = FALSE;
2808 if( GetParent() )
2810 Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
2811 while( pChild && (bMouseOver = pChild->IsMouseOver()) == FALSE )
2812 pChild = pChild->GetWindow( WINDOW_NEXT );
2815 if( bMouseOver )
2816 nState |= CTRL_STATE_ROLLOVER;
2818 // if parent has no border, then nobody has drawn the background
2819 // since no border window exists. so draw it here.
2820 WinBits nParentStyle = pWin->GetStyle();
2821 if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
2823 Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
2824 Region aParentReg( aParentRect );
2825 pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentReg,
2826 nState, aControlValue, rtl::OUString() );
2829 bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
2830 aControlValue, rtl::OUString() );
2833 if( IsEnabled() )
2835 if( HasFocus() )
2837 SetTextColor( rStyleSettings.GetHighlightTextColor() );
2838 SetFillColor( rStyleSettings.GetHighlightColor() );
2839 DrawRect( maFocusRect );
2841 else
2843 Color aColor;
2844 if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
2845 aColor = rStyleSettings.GetFieldRolloverTextColor();
2846 else
2847 aColor = rStyleSettings.GetFieldTextColor();
2848 if( IsControlForeground() )
2849 aColor = GetControlForeground();
2850 SetTextColor( aColor );
2851 if ( !bNativeOK )
2852 Erase( maFocusRect );
2855 else // Disabled
2857 SetTextColor( rStyleSettings.GetDisableColor() );
2858 if ( !bNativeOK )
2859 Erase( maFocusRect );
2863 if ( IsUserDrawEnabled() )
2865 mbInUserDraw = TRUE;
2866 UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
2867 maUserDrawHdl.Call( &aUDEvt );
2868 mbInUserDraw = FALSE;
2870 else
2872 DrawEntry( TRUE, TRUE, FALSE, bLayout );
2876 // -----------------------------------------------------------------------
2878 void ImplWin::Paint( const Rectangle& )
2880 ImplDraw();
2883 // -----------------------------------------------------------------------
2885 void ImplWin::DrawEntry( BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos, bool bLayout )
2887 long nBorder = 1;
2888 Size aOutSz = GetOutputSizePixel();
2890 BOOL bImage = !!maImage;
2891 if( bDrawImage && bImage && !bLayout )
2893 USHORT nStyle = 0;
2894 Size aImgSz = maImage.GetSizePixel();
2895 Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
2897 // check for HC mode
2898 Image *pImage = &maImage;
2900 if( !!maImageHC )
2902 if( GetSettings().GetStyleSettings().GetHighContrastMode() )
2903 pImage = &maImageHC;
2906 if ( !IsZoom() )
2908 DrawImage( aPtImg, *pImage, nStyle );
2910 else
2912 aImgSz.Width() = CalcZoom( aImgSz.Width() );
2913 aImgSz.Height() = CalcZoom( aImgSz.Height() );
2914 DrawImage( aPtImg, aImgSz, *pImage, nStyle );
2918 if( bDrawText && maString.Len() )
2920 USHORT nTextStyle = TEXT_DRAW_VCENTER;
2922 if ( bDrawImage && bImage && !bLayout )
2923 nTextStyle |= TEXT_DRAW_LEFT;
2924 else if ( GetStyle() & WB_CENTER )
2925 nTextStyle |= TEXT_DRAW_CENTER;
2926 else if ( GetStyle() & WB_RIGHT )
2927 nTextStyle |= TEXT_DRAW_RIGHT;
2928 else
2929 nTextStyle |= TEXT_DRAW_LEFT;
2931 Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
2933 if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
2935 long nMaxWidth = Max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
2936 aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
2939 MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL;
2940 String* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL;
2941 DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
2944 if( HasFocus() && !bLayout )
2945 ShowFocus( maFocusRect );
2948 // -----------------------------------------------------------------------
2950 void ImplWin::Resize()
2952 Control::Resize();
2953 maFocusRect.SetSize( GetOutputSizePixel() );
2954 Invalidate();
2957 // -----------------------------------------------------------------------
2959 void ImplWin::GetFocus()
2961 ShowFocus( maFocusRect );
2962 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2963 IsNativeWidgetEnabled() &&
2964 IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
2966 Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
2967 if( ! pWin )
2968 pWin = GetParent();
2969 pWin->Invalidate();
2971 else
2972 Invalidate();
2973 Control::GetFocus();
2976 // -----------------------------------------------------------------------
2978 void ImplWin::LoseFocus()
2980 HideFocus();
2981 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2982 IsNativeWidgetEnabled() &&
2983 IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
2985 Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
2986 if( ! pWin )
2987 pWin = GetParent();
2988 pWin->Invalidate();
2990 else
2991 Invalidate();
2992 Control::LoseFocus();
2995 // =======================================================================
2997 ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
2998 PushButton( pParent, nWinStyle ),
2999 mbDown ( FALSE )
3003 // -----------------------------------------------------------------------
3005 void ImplBtn::MBDown()
3007 if( IsEnabled() )
3008 maMBDownHdl.Call( this );
3011 // -----------------------------------------------------------------------
3013 void ImplBtn::MouseButtonDown( const MouseEvent& )
3015 //PushButton::MouseButtonDown( rMEvt );
3016 if( IsEnabled() )
3018 MBDown();
3019 mbDown = TRUE;
3023 // =======================================================================
3025 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
3026 FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW ) // no drop shadow for list boxes
3028 mpImplLB = NULL;
3029 mnDDLineCount = 0;
3030 mbAutoWidth = FALSE;
3032 mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
3034 EnableSaveBackground();
3036 Window * pBorderWindow = ImplGetBorderWindow();
3037 if( pBorderWindow )
3039 SetAccessibleRole(accessibility::AccessibleRole::PANEL);
3040 pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3042 else
3044 SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3049 // -----------------------------------------------------------------------
3051 long ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
3053 if( rNEvt.GetType() == EVENT_LOSEFOCUS )
3055 if( !GetParent()->HasChildPathFocus( TRUE ) )
3056 EndPopupMode();
3059 return FloatingWindow::PreNotify( rNEvt );
3062 // -----------------------------------------------------------------------
3064 void ImplListBoxFloatingWindow::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
3066 FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
3068 // Fix #60890# ( MBA ): um auch im aufgeklappten Zustand der Listbox die Gr"o\se einfach zu einen
3069 // Aufruf von Resize() "andern zu k"onnen, wird die Position hier ggf. angepa\t
3070 if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
3072 Point aPos = GetParent()->GetPosPixel();
3073 aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3075 if ( nFlags & WINDOW_POSSIZE_X )
3076 aPos.X() = nX;
3078 if ( nFlags & WINDOW_POSSIZE_Y )
3079 aPos.Y() = nY;
3081 USHORT nIndex;
3082 SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
3085 // if( !IsReallyVisible() )
3087 // Die ImplListBox erhaelt kein Resize, weil nicht sichtbar.
3088 // Die Fenster muessen aber ein Resize() erhalten, damit die
3089 // Anzahl der sichtbaren Eintraege fuer PgUp/PgDown stimmt.
3090 // Die Anzahl kann auch nicht von List/Combobox berechnet werden,
3091 // weil hierfuer auch die ggf. vorhandene vertikale Scrollbar
3092 // beruecksichtigt werden muss.
3093 mpImplLB->SetSizePixel( GetOutputSizePixel() );
3094 ((Window*)mpImplLB)->Resize();
3095 ((Window*)mpImplLB->GetMainWindow())->Resize();
3099 // -----------------------------------------------------------------------
3101 void ImplListBoxFloatingWindow::Resize()
3103 mpImplLB->GetMainWindow()->ImplClearLayoutData();
3104 FloatingWindow::Resize();
3107 // -----------------------------------------------------------------------
3109 Size ImplListBoxFloatingWindow::CalcFloatSize()
3111 Size aFloatSz( maPrefSz );
3113 sal_Int32 nLeft, nTop, nRight, nBottom;
3114 GetBorder( nLeft, nTop, nRight, nBottom );
3116 USHORT nLines = mpImplLB->GetEntryList()->GetEntryCount();
3117 if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
3118 nLines = mnDDLineCount;
3120 Size aSz = mpImplLB->CalcSize( nLines );
3121 long nMaxHeight = aSz.Height() + nTop + nBottom;
3123 if ( mnDDLineCount )
3124 aFloatSz.Height() = nMaxHeight;
3126 if( mbAutoWidth )
3128 // AutoSize erstmal nur fuer die Breite...
3130 aFloatSz.Width() = aSz.Width() + nLeft + nRight;
3131 aFloatSz.Width() += nRight; // etwas mehr Platz sieht besser aus...
3133 if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
3135 // dann wird noch der vertikale Scrollbar benoetigt
3136 long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
3137 aFloatSz.Width() += nSBWidth;
3141 if ( aFloatSz.Height() > nMaxHeight )
3142 aFloatSz.Height() = nMaxHeight;
3144 // Minimale Hoehe, falls Hoehe nicht auf Float-Hoehe eingestellt wurde.
3145 // Der Parent vom FloatWin muss die DropDown-Combo/Listbox sein.
3146 Size aParentSz = GetParent()->GetSizePixel();
3147 if( !mnDDLineCount && ( aFloatSz.Height() < aParentSz.Height() ) )
3148 aFloatSz.Height() = aParentSz.Height();
3150 // Nicht schmaler als der Parent werden...
3151 if( aFloatSz.Width() < aParentSz.Width() )
3152 aFloatSz.Width() = aParentSz.Width();
3154 // Hoehe auf Entries alignen...
3155 long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
3156 long nEntryHeight = mpImplLB->GetEntryHeight();
3157 if ( nInnerHeight % nEntryHeight )
3159 nInnerHeight /= nEntryHeight;
3160 nInnerHeight++;
3161 nInnerHeight *= nEntryHeight;
3162 aFloatSz.Height() = nInnerHeight + nTop + nBottom;
3165 return aFloatSz;
3168 // -----------------------------------------------------------------------
3170 void ImplListBoxFloatingWindow::StartFloat( BOOL bStartTracking )
3172 if( !IsInPopupMode() )
3174 Size aFloatSz = CalcFloatSize();
3176 SetSizePixel( aFloatSz );
3177 mpImplLB->SetSizePixel( GetOutputSizePixel() );
3179 USHORT nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
3180 mnPopupModeStartSaveSelection = nPos;
3182 Size aSz = GetParent()->GetSizePixel();
3183 Point aPos = GetParent()->GetPosPixel();
3184 aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3185 // FIXME: this ugly hack is for Mac/Aqua
3186 // should be replaced by a real mechanism to place the float rectangle
3187 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3188 GetParent()->IsNativeWidgetEnabled() )
3190 sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
3191 aPos.X() += nLeft;
3192 aPos.Y() += nTop;
3193 aSz.Width() -= nLeft + nRight;
3194 aSz.Height() -= nTop + nBottom;
3196 Rectangle aRect( aPos, aSz );
3198 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3199 // where the document is unmirrored
3200 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3201 if( GetParent()->GetParent()->ImplIsAntiparallel() )
3202 GetParent()->GetParent()->ImplReMirror( aRect );
3204 StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
3206 if( nPos != LISTBOX_ENTRY_NOTFOUND )
3207 mpImplLB->SetTopEntry( nPos );
3209 if( bStartTracking )
3210 mpImplLB->GetMainWindow()->EnableMouseMoveSelect( TRUE );
3212 if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
3213 mpImplLB->GetMainWindow()->GrabFocus();
3215 mpImplLB->GetMainWindow()->ImplClearLayoutData();