blob: 8e97ca1cd5978deeaf250849518816f90c00ec1f [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include <tools/debug.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/event.hxx>
#include <vcl/scrbar.hxx>
#include <vcl/help.hxx>
#include <vcl/lstbox.h>
#include <vcl/unohelp.hxx>
#include <vcl/i18nhelp.hxx>
#include <ilstbox.hxx>
#include <controldata.hxx>
#include <svdata.hxx>
#include <com/sun/star/i18n/XCollator.hpp>
#include <com/sun/star/accessibility/XAccessible.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#define MULTILINE_ENTRY_DRAW_FLAGS ( TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_VCENTER )
using namespace ::com::sun::star;
// =======================================================================
void ImplInitFieldSettings( Window* pWin, sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
{
const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
if ( bFont )
{
Font aFont = rStyleSettings.GetFieldFont();
if ( pWin->IsControlFont() )
aFont.Merge( pWin->GetControlFont() );
pWin->SetZoomedPointFont( aFont );
}
if ( bFont || bForeground )
{
Color aTextColor = rStyleSettings.GetFieldTextColor();
if ( pWin->IsControlForeground() )
aTextColor = pWin->GetControlForeground();
pWin->SetTextColor( aTextColor );
}
if ( bBackground )
{
if( pWin->IsControlBackground() )
pWin->SetBackground( pWin->GetControlBackground() );
else
pWin->SetBackground( rStyleSettings.GetFieldColor() );
}
}
// -----------------------------------------------------------------------
void ImplInitDropDownButton( PushButton* pButton )
{
if ( pButton->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
pButton->SetSymbol( SYMBOL_SPIN_UPDOWN );
else
pButton->SetSymbol( SYMBOL_SPIN_DOWN );
if ( pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
&& ! pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
pButton->SetBackground();
}
// =======================================================================
ImplEntryList::ImplEntryList( Window* pWindow )
{
mpWindow = pWindow;
mnLastSelected = LISTBOX_ENTRY_NOTFOUND;
mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND;
mnImages = 0;
mbCallSelectionChangedHdl = sal_True;
mnMRUCount = 0;
mnMaxMRUCount = 0;
}
// -----------------------------------------------------------------------
ImplEntryList::~ImplEntryList()
{
Clear();
}
// -----------------------------------------------------------------------
void ImplEntryList::Clear()
{
mnImages = 0;
for ( sal_uInt16 n = GetEntryCount(); n; )
{
ImplEntryType* pImplEntry = GetEntry( --n );
delete pImplEntry;
}
List::Clear();
}
// -----------------------------------------------------------------------
void ImplEntryList::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
{
ImplEntryType* pImplEntry = GetEntry( nPos );
if ( pImplEntry &&
( pImplEntry->mbIsSelected != bSelect ) &&
( (pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0 ) )
{
pImplEntry->mbIsSelected = bSelect;
if ( mbCallSelectionChangedHdl )
maSelectionChangedHdl.Call( (void*)sal_IntPtr(nPos) );
}
}
// -----------------------------------------------------------------------
uno::Reference< i18n::XCollator > ImplGetCollator (lang::Locale &rLocale)
{
static uno::Reference< i18n::XCollator > xCollator;
if ( !xCollator.is() )
xCollator = vcl::unohelper::CreateCollator();
if( xCollator.is() )
xCollator->loadDefaultCollator (rLocale, 0);
return xCollator;
}
sal_uInt16 ImplEntryList::InsertEntry( sal_uInt16 nPos, ImplEntryType* pNewEntry, sal_Bool bSort )
{
if ( !!pNewEntry->maImage )
mnImages++;
if ( !bSort || !Count() )
{
Insert( pNewEntry, nPos );
}
else
{
lang::Locale aLocale = Application::GetSettings().GetLocale();
uno::Reference< i18n::XCollator > xCollator = ImplGetCollator(aLocale);
const XubString& rStr = pNewEntry->maStr;
sal_uLong nLow, nHigh, nMid;
nHigh = Count();
ImplEntryType* pTemp = GetEntry( (sal_uInt16)(nHigh-1) );
try
{
// XXX even though XCollator::compareString returns a sal_Int32 the only
// defined values are {-1, 0, 1} which is compatible with StringCompare
StringCompare eComp = xCollator.is() ?
(StringCompare)xCollator->compareString (rStr, pTemp->maStr)
: COMPARE_EQUAL;
// Schnelles Einfuegen bei sortierten Daten
if ( eComp != COMPARE_LESS )
{
Insert( pNewEntry, LIST_APPEND );
}
else
{
nLow = mnMRUCount;
pTemp = (ImplEntryType*)GetEntry( (sal_uInt16)nLow );
eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
if ( eComp != COMPARE_GREATER )
{
Insert( pNewEntry, (sal_uLong)0 );
}
else
{
// Binaeres Suchen
nHigh--;
do
{
nMid = (nLow + nHigh) / 2;
pTemp = (ImplEntryType*)GetObject( nMid );
eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
if ( eComp == COMPARE_LESS )
nHigh = nMid-1;
else
{
if ( eComp == COMPARE_GREATER )
nLow = nMid + 1;
else
break;
}
}
while ( nLow <= nHigh );
if ( eComp != COMPARE_LESS )
nMid++;
Insert( pNewEntry, nMid );
}
}
}
catch (uno::RuntimeException& )
{
// XXX this is arguable, if the exception occured because pNewEntry is
// garbage you wouldn't insert it. If the exception occured because the
// Collator implementation is garbage then give the user a chance to see
// his stuff
Insert( pNewEntry, (sal_uLong)0 );
}
}
return (sal_uInt16)GetPos( pNewEntry );
}
// -----------------------------------------------------------------------
void ImplEntryList::RemoveEntry( sal_uInt16 nPos )
{
ImplEntryType* pImplEntry = (ImplEntryType*)List::Remove( nPos );
if ( pImplEntry )
{
if ( !!pImplEntry->maImage )
mnImages--;
delete pImplEntry;
}
}
// -----------------------------------------------------------------------
sal_uInt16 ImplEntryList::FindEntry( const XubString& rString, sal_Bool bSearchMRUArea ) const
{
sal_uInt16 nEntries = GetEntryCount();
for ( sal_uInt16 n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
{
ImplEntryType* pImplEntry = GetEntry( n );
String aComp( vcl::I18nHelper::filterFormattingChars( pImplEntry->maStr ) );
if ( aComp == rString )
return n;
}
return LISTBOX_ENTRY_NOTFOUND;
}
// -----------------------------------------------------------------------
sal_uInt16 ImplEntryList::FindMatchingEntry( const XubString& rStr, sal_uInt16 nStart, sal_Bool bForward, sal_Bool bLazy ) const
{
sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;
sal_uInt16 nEntryCount = GetEntryCount();
if ( !bForward )
nStart++; // wird sofort dekrementiert
const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
for ( sal_uInt16 n = nStart; bForward ? ( n < nEntryCount ) : n; )
{
if ( !bForward )
n--;
ImplEntryType* pImplEntry = GetEntry( n );
sal_Bool bMatch = bLazy ? rI18nHelper.MatchString( rStr, pImplEntry->maStr ) != 0 : ( rStr.Match( pImplEntry->maStr ) == STRING_MATCH );
if ( bMatch )
{
nPos = n;
break;
}
if ( bForward )
n++;
}
return nPos;
}
// -----------------------------------------------------------------------
sal_uInt16 ImplEntryList::FindEntry( const void* pData ) const
{
sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;
for ( sal_uInt16 n = GetEntryCount(); n; )
{
ImplEntryType* pImplEntry = GetEntry( --n );
if ( pImplEntry->mpUserData == pData )
{
nPos = n;
break;
}
}
return nPos;
}
// -----------------------------------------------------------------------
long ImplEntryList::GetAddedHeight( sal_uInt16 i_nEndIndex, sal_uInt16 i_nBeginIndex, long i_nBeginHeight ) const
{
long nHeight = i_nBeginHeight;
sal_uInt16 nStart = i_nEndIndex > i_nBeginIndex ? i_nBeginIndex : i_nEndIndex;
sal_uInt16 nStop = i_nEndIndex > i_nBeginIndex ? i_nEndIndex : i_nBeginIndex;
sal_uInt16 nEntryCount = GetEntryCount();
if( nStop != LISTBOX_ENTRY_NOTFOUND && nEntryCount != 0 )
{
// sanity check
if( nStop > nEntryCount-1 )
nStop = nEntryCount-1;
if( nStart > nEntryCount-1 )
nStart = nEntryCount-1;
sal_uInt16 nIndex = nStart;
while( nIndex != LISTBOX_ENTRY_NOTFOUND && nIndex < nStop )
{
nHeight += GetEntryPtr( nIndex )-> mnHeight;
nIndex++;
}
}
else
nHeight = 0;
return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
}
// -----------------------------------------------------------------------
long ImplEntryList::GetEntryHeight( sal_uInt16 nPos ) const
{
ImplEntryType* pImplEntry = GetEntry( nPos );
return pImplEntry ? pImplEntry->mnHeight : 0;
}
// -----------------------------------------------------------------------
XubString ImplEntryList::GetEntryText( sal_uInt16 nPos ) const
{
XubString aEntryText;
ImplEntryType* pImplEntry = GetEntry( nPos );
if ( pImplEntry )
aEntryText = pImplEntry->maStr;
return aEntryText;
}
// -----------------------------------------------------------------------
sal_Bool ImplEntryList::HasEntryImage( sal_uInt16 nPos ) const
{
sal_Bool bImage = sal_False;
ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
if ( pImplEntry )
bImage = !!pImplEntry->maImage;
return bImage;
}
// -----------------------------------------------------------------------
Image ImplEntryList::GetEntryImage( sal_uInt16 nPos ) const
{
Image aImage;
ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
if ( pImplEntry )
aImage = pImplEntry->maImage;
return aImage;
}
// -----------------------------------------------------------------------
void ImplEntryList::SetEntryData( sal_uInt16 nPos, void* pNewData )
{
ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
if ( pImplEntry )
pImplEntry->mpUserData = pNewData;
}
// -----------------------------------------------------------------------
void* ImplEntryList::GetEntryData( sal_uInt16 nPos ) const
{
ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
return pImplEntry ? pImplEntry->mpUserData : NULL;
}
// -----------------------------------------------------------------------
void ImplEntryList::SetEntryFlags( sal_uInt16 nPos, long nFlags )
{
ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
if ( pImplEntry )
pImplEntry->mnFlags = nFlags;
}
// -----------------------------------------------------------------------
long ImplEntryList::GetEntryFlags( sal_uInt16 nPos ) const
{
ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
return pImplEntry ? pImplEntry->mnFlags : 0;
}
// -----------------------------------------------------------------------
sal_uInt16 ImplEntryList::GetSelectEntryCount() const
{
sal_uInt16 nSelCount = 0;
for ( sal_uInt16 n = GetEntryCount(); n; )
{
ImplEntryType* pImplEntry = GetEntry( --n );
if ( pImplEntry->mbIsSelected )
nSelCount++;
}
return nSelCount;
}
// -----------------------------------------------------------------------
XubString ImplEntryList::GetSelectEntry( sal_uInt16 nIndex ) const
{
return GetEntryText( GetSelectEntryPos( nIndex ) );
}
// -----------------------------------------------------------------------
sal_uInt16 ImplEntryList::GetSelectEntryPos( sal_uInt16 nIndex ) const
{
sal_uInt16 nSelEntryPos = LISTBOX_ENTRY_NOTFOUND;
sal_uInt16 nSel = 0;
sal_uInt16 nEntryCount = GetEntryCount();
for ( sal_uInt16 n = 0; n < nEntryCount; n++ )
{
ImplEntryType* pImplEntry = GetEntry( n );
if ( pImplEntry->mbIsSelected )
{
if ( nSel == nIndex )
{
nSelEntryPos = n;
break;
}
nSel++;
}
}
return nSelEntryPos;
}
// -----------------------------------------------------------------------
sal_Bool ImplEntryList::IsEntrySelected( const XubString& rStr ) const
{
return IsEntryPosSelected( FindEntry( rStr ) );
}
// -----------------------------------------------------------------------
sal_Bool ImplEntryList::IsEntryPosSelected( sal_uInt16 nIndex ) const
{
ImplEntryType* pImplEntry = GetEntry( nIndex );
return pImplEntry ? pImplEntry->mbIsSelected : sal_False;
}
// -----------------------------------------------------------------------
bool ImplEntryList::IsEntrySelectable( sal_uInt16 nPos ) const
{
ImplEntryType* pImplEntry = GetEntry( nPos );
return pImplEntry ? ((pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0) : true;
}
// -----------------------------------------------------------------------
sal_uInt16 ImplEntryList::FindFirstSelectable( sal_uInt16 nPos, bool bForward /* = true */ )
{
if( IsEntrySelectable( nPos ) )
return nPos;
if( bForward )
{
for( nPos = nPos + 1; nPos < GetEntryCount(); nPos++ )
{
if( IsEntrySelectable( nPos ) )
return nPos;
}
}
else
{
while( nPos )
{
nPos--;
if( IsEntrySelectable( nPos ) )
return nPos;
}
}
return LISTBOX_ENTRY_NOTFOUND;
}
// =======================================================================
ImplListBoxWindow::ImplListBoxWindow( Window* pParent, WinBits nWinStyle ) :
Control( pParent, 0 ),
maQuickSelectionEngine( *this )
{
mpEntryList = new ImplEntryList( this );
mnTop = 0;
mnLeft = 0;
mnBorder = 1;
mnSelectModifier = 0;
mnUserDrawEntry = LISTBOX_ENTRY_NOTFOUND;
mbTrack = false;
mbImgsDiffSz = false;
mbTravelSelect = false;
mbTrackingSelect = false;
mbSelectionChanged = false;
mbMouseMoveSelect = false;
mbMulti = false;
mbStackMode = false;
mbGrabFocus = false;
mbUserDrawEnabled = false;
mbInUserDraw = false;
mbReadOnly = false;
mbHasFocusRect = false;
mbRight = ( nWinStyle & WB_RIGHT );
mbCenter = ( nWinStyle & WB_CENTER );
mbSimpleMode = ( nWinStyle & WB_SIMPLEMODE );
mbSort = ( nWinStyle & WB_SORT );
mbEdgeBlending = false;
// pb: #106948# explicit mirroring for calc
mbMirroring = false;
mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
mnSeparatorPos = LISTBOX_ENTRY_NOTFOUND;
meProminentType = PROMINENT_TOP;
SetLineColor();
SetTextFillColor();
SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
ImplInitSettings( sal_True, sal_True, sal_True );
ImplCalcMetrics();
}
// -----------------------------------------------------------------------
ImplListBoxWindow::~ImplListBoxWindow()
{
delete mpEntryList;
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
{
ImplInitFieldSettings( this, bFont, bForeground, bBackground );
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ImplCalcMetrics()
{
mnMaxWidth = 0;
mnMaxTxtWidth = 0;
mnMaxImgWidth = 0;
mnMaxImgTxtWidth= 0;
mnMaxImgHeight = 0;
mnTextHeight = (sal_uInt16)GetTextHeight();
mnMaxTxtHeight = mnTextHeight + mnBorder;
mnMaxHeight = mnMaxTxtHeight;
if ( maUserItemSize.Height() > mnMaxHeight )
mnMaxHeight = (sal_uInt16) maUserItemSize.Height();
if ( maUserItemSize.Width() > mnMaxWidth )
mnMaxWidth= (sal_uInt16) maUserItemSize.Width();
for ( sal_uInt16 n = mpEntryList->GetEntryCount(); n; )
{
ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
ImplUpdateEntryMetrics( *pEntry );
}
if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
{
Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->mnHeight );
maFocusRect.SetSize( aSz );
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::Clear()
{
mpEntryList->Clear();
mnMaxHeight = mnMaxTxtHeight;
mnMaxWidth = 0;
mnMaxTxtWidth = 0;
mnMaxImgTxtWidth= 0;
mnMaxImgWidth = 0;
mnMaxImgHeight = 0;
mnTop = 0;
mnLeft = 0;
mbImgsDiffSz = false;
ImplClearLayoutData();
mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
maQuickSelectionEngine.Reset();
Invalidate();
}
void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
{
ImplClearLayoutData();
maUserItemSize = rSz;
ImplCalcMetrics();
}
// -----------------------------------------------------------------------
struct ImplEntryMetrics
{
sal_Bool bText;
sal_Bool bImage;
long nEntryWidth;
long nEntryHeight;
long nTextWidth;
long nImgWidth;
long nImgHeight;
};
// -----------------------------------------------------------------------
void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
{
ImplEntryMetrics aMetrics;
aMetrics.bText = rEntry.maStr.Len() ? sal_True : sal_False;
aMetrics.bImage = !!rEntry.maImage;
aMetrics.nEntryWidth = 0;
aMetrics.nEntryHeight = 0;
aMetrics.nTextWidth = 0;
aMetrics.nImgWidth = 0;
aMetrics.nImgHeight = 0;
if ( aMetrics.bText )
{
if( (rEntry.mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
{
// multiline case
Size aCurSize( PixelToLogic( GetSizePixel() ) );
// set the current size to a large number
// GetTextRect should shrink it to the actual size
aCurSize.Height() = 0x7fffff;
Rectangle aTextRect( Point( 0, 0 ), aCurSize );
aTextRect = GetTextRect( aTextRect, rEntry.maStr, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE );
aMetrics.nTextWidth = aTextRect.GetWidth();
if( aMetrics.nTextWidth > mnMaxTxtWidth )
mnMaxTxtWidth = aMetrics.nTextWidth;
aMetrics.nEntryWidth = mnMaxTxtWidth;
aMetrics.nEntryHeight = aTextRect.GetHeight() + mnBorder;
}
else
{
// normal single line case
aMetrics.nTextWidth = (sal_uInt16)GetTextWidth( rEntry.maStr );
if( aMetrics.nTextWidth > mnMaxTxtWidth )
mnMaxTxtWidth = aMetrics.nTextWidth;
aMetrics.nEntryWidth = mnMaxTxtWidth;
aMetrics.nEntryHeight = mnTextHeight + mnBorder;
}
}
if ( aMetrics.bImage )
{
Size aImgSz = rEntry.maImage.GetSizePixel();
aMetrics.nImgWidth = (sal_uInt16) CalcZoom( aImgSz.Width() );
aMetrics.nImgHeight = (sal_uInt16) CalcZoom( aImgSz.Height() );
if( mnMaxImgWidth && ( aMetrics.nImgWidth != mnMaxImgWidth ) )
mbImgsDiffSz = true;
else if ( mnMaxImgHeight && ( aMetrics.nImgHeight != mnMaxImgHeight ) )
mbImgsDiffSz = true;
if( aMetrics.nImgWidth > mnMaxImgWidth )
mnMaxImgWidth = aMetrics.nImgWidth;
if( aMetrics.nImgHeight > mnMaxImgHeight )
mnMaxImgHeight = aMetrics.nImgHeight;
mnMaxImgTxtWidth = Max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
aMetrics.nEntryHeight = Max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
}
if ( IsUserDrawEnabled() || aMetrics.bImage )
{
aMetrics.nEntryWidth = Max( aMetrics.nImgWidth, maUserItemSize.Width() );
if ( aMetrics.bText )
aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE;
aMetrics.nEntryHeight = Max( Max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
aMetrics.nEntryHeight );
}
if ( !aMetrics.bText && !aMetrics.bImage && !IsUserDrawEnabled() )
{
// entries which have no (aka an empty) text, and no image, and are not user-drawn, should be
// shown nonetheless
aMetrics.nEntryHeight = mnTextHeight + mnBorder;
}
if ( aMetrics.nEntryWidth > mnMaxWidth )
mnMaxWidth = aMetrics.nEntryWidth;
if ( aMetrics.nEntryHeight > mnMaxHeight )
mnMaxHeight = aMetrics.nEntryHeight;
rEntry.mnHeight = aMetrics.nEntryHeight;
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ImplCallSelect()
{
if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
{
// Insert the selected entry as MRU, if not allready first MRU
sal_uInt16 nSelected = GetEntryList()->GetSelectEntryPos( 0 );
sal_uInt16 nMRUCount = GetEntryList()->GetMRUCount();
String aSelected = GetEntryList()->GetEntryText( nSelected );
sal_uInt16 nFirstMatchingEntryPos = GetEntryList()->FindEntry( aSelected, sal_True );
if ( nFirstMatchingEntryPos || !nMRUCount )
{
sal_Bool bSelectNewEntry = sal_False;
if ( nFirstMatchingEntryPos < nMRUCount )
{
RemoveEntry( nFirstMatchingEntryPos );
nMRUCount--;
if ( nFirstMatchingEntryPos == nSelected )
bSelectNewEntry = sal_True;
}
else if ( nMRUCount == GetEntryList()->GetMaxMRUCount() )
{
RemoveEntry( nMRUCount - 1 );
nMRUCount--;
}
ImplClearLayoutData();
ImplEntryType* pNewEntry = new ImplEntryType( aSelected );
pNewEntry->mbIsSelected = bSelectNewEntry;
GetEntryList()->InsertEntry( 0, pNewEntry, sal_False );
ImplUpdateEntryMetrics( *pNewEntry );
GetEntryList()->SetMRUCount( ++nMRUCount );
SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
maMRUChangedHdl.Call( NULL );
}
}
maSelectHdl.Call( NULL );
mbSelectionChanged = false;
}
// -----------------------------------------------------------------------
sal_uInt16 ImplListBoxWindow::InsertEntry( sal_uInt16 nPos, ImplEntryType* pNewEntry )
{
ImplClearLayoutData();
sal_uInt16 nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, mbSort );
if( (GetStyle() & WB_WORDBREAK) )
pNewEntry->mnFlags |= LISTBOX_ENTRY_FLAG_MULTILINE;
ImplUpdateEntryMetrics( *pNewEntry );
return nNewPos;
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::RemoveEntry( sal_uInt16 nPos )
{
ImplClearLayoutData();
mpEntryList->RemoveEntry( nPos );
if( mnCurrentPos >= mpEntryList->GetEntryCount() )
mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
ImplCalcMetrics();
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::SetEntryFlags( sal_uInt16 nPos, long nFlags )
{
mpEntryList->SetEntryFlags( nPos, nFlags );
ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( nPos );
if( pEntry )
ImplUpdateEntryMetrics( *pEntry );
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ImplShowFocusRect()
{
if ( mbHasFocusRect )
HideFocus();
ShowFocus( maFocusRect );
mbHasFocusRect = true;
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ImplHideFocusRect()
{
if ( mbHasFocusRect )
{
HideFocus();
mbHasFocusRect = false;
}
}
// -----------------------------------------------------------------------
sal_uInt16 ImplListBoxWindow::GetEntryPosForPoint( const Point& rPoint ) const
{
long nY = mnBorder;
sal_uInt16 nSelect = mnTop;
const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nSelect );
while( pEntry && rPoint.Y() > pEntry->mnHeight + nY )
{
nY += pEntry->mnHeight;
pEntry = mpEntryList->GetEntryPtr( ++nSelect );
}
if( pEntry == NULL )
nSelect = LISTBOX_ENTRY_NOTFOUND;
return nSelect;
}
// -----------------------------------------------------------------------
sal_Bool ImplListBoxWindow::IsVisible( sal_uInt16 i_nEntry ) const
{
sal_Bool bRet = sal_False;
if( i_nEntry >= mnTop )
{
if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
PixelToLogic( GetSizePixel() ).Height() )
{
bRet = sal_True;
}
}
return bRet;
}
// -----------------------------------------------------------------------
sal_uInt16 ImplListBoxWindow::GetLastVisibleEntry() const
{
sal_uInt16 nPos = mnTop;
long nWindowHeight = GetSizePixel().Height();
sal_uInt16 nCount = mpEntryList->GetEntryCount();
long nDiff;
for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
nPos++;
if( nDiff > nWindowHeight && nPos > mnTop )
nPos--;
if( nPos >= nCount )
nPos = nCount-1;
return nPos;
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::MouseButtonDown( const MouseEvent& rMEvt )
{
mbMouseMoveSelect = false; // Nur bis zum ersten MouseButtonDown
maQuickSelectionEngine.Reset();
if ( !IsReadOnly() )
{
if( rMEvt.GetClicks() == 1 )
{
sal_uInt16 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
if( nSelect != LISTBOX_ENTRY_NOTFOUND )
{
if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
else
mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
mnCurrentPos = nSelect;
mbTrackingSelect = true;
sal_Bool bCurPosChange = (mnCurrentPos != nSelect);
//SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() );
SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() ,bCurPosChange);
mbTrackingSelect = false;
if ( mbGrabFocus )
GrabFocus();
StartTracking( STARTTRACK_SCROLLREPEAT );
}
}
if( rMEvt.GetClicks() == 2 )
{
maDoubleClickHdl.Call( this );
}
}
else // if ( mbGrabFocus )
{
GrabFocus();
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
{
if ( rMEvt.IsLeaveWindow() )
{
if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
{
if ( rMEvt.GetPosPixel().Y() < 0 )
{
DeselectAll();
mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
SetTopEntry( 0 );
if ( mbStackMode ) // #87072#, #92323#
{
mbTravelSelect = true;
mnSelectModifier = rMEvt.GetModifier();
ImplCallSelect();
mbTravelSelect = false;
}
}
}
}
else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
{
Point aPoint;
Rectangle aRect( aPoint, GetOutputSizePixel() );
if( aRect.IsInside( rMEvt.GetPosPixel() ) )
{
if ( IsMouseMoveSelect() )
{
sal_uInt16 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
if( nSelect == LISTBOX_ENTRY_NOTFOUND )
nSelect = mpEntryList->GetEntryCount() - 1;
nSelect = Min( nSelect, GetLastVisibleEntry() );
nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
// Select only visible Entries with MouseMove, otherwise Tracking...
if ( IsVisible( nSelect ) &&
mpEntryList->IsEntrySelectable( nSelect ) &&
( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
{
mbTrackingSelect = true;
if ( SelectEntries( nSelect, LET_TRACKING, sal_False, sal_False ) )
{
if ( mbStackMode ) // #87072#
{
mbTravelSelect = true;
mnSelectModifier = rMEvt.GetModifier();
ImplCallSelect();
mbTravelSelect = false;
}
// When list box selection change by mouse move, notity
// VCLEVENT_LISTBOX_SELECT vcl event.
else
{
maListItemSelectHdl.Call(NULL);
}
}
mbTrackingSelect = false;
}
}
// Falls der DD-Button gedrueckt wurde und jemand mit gedrueckter
// Maustaste in die ListBox faehrt...
if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
{
if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
else
mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
mpEntryList->SetSelectionAnchor( 0 );
StartTracking( STARTTRACK_SCROLLREPEAT );
}
}
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::DeselectAll()
{
while ( GetEntryList()->GetSelectEntryCount() )
{
sal_uInt16 nS = GetEntryList()->GetSelectEntryPos( 0 );
SelectEntry( nS, sal_False );
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
{
if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
{
ImplHideFocusRect();
if( bSelect )
{
if( !mbMulti )
{
// Selektierten Eintrag deselektieren
sal_uInt16 nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
{
//SelectEntryPos( nDeselect, sal_False );
GetEntryList()->SelectEntry( nDeselect, sal_False );
if ( IsUpdateMode() && IsReallyVisible() )
ImplPaint( nDeselect, sal_True );
}
}
mpEntryList->SelectEntry( nPos, sal_True );
mnCurrentPos = nPos;
if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
{
ImplPaint( nPos );
if ( !IsVisible( nPos ) )
{
ImplClearLayoutData();
sal_uInt16 nVisibleEntries = GetLastVisibleEntry()-mnTop;
if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
{
Resize();
ShowProminentEntry( nPos );
}
else
{
ShowProminentEntry( nPos );
}
}
}
}
else
{
mpEntryList->SelectEntry( nPos, sal_False );
ImplPaint( nPos, sal_True );
}
mbSelectionChanged = true;
}
}
// -----------------------------------------------------------------------
sal_Bool ImplListBoxWindow::SelectEntries( sal_uInt16 nSelect, LB_EVENT_TYPE eLET, sal_Bool bShift, sal_Bool bCtrl, sal_Bool bSelectPosChange /*=FALSE*/ )
{
sal_Bool bFocusChanged = sal_False;
sal_Bool bSelectionChanged = sal_False;
if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
{
// Hier (Single-ListBox) kann nur ein Eintrag deselektiert werden
if( !mbMulti )
{
sal_uInt16 nDeselect = mpEntryList->GetSelectEntryPos( 0 );
if( nSelect != nDeselect )
{
SelectEntry( nSelect, sal_True );
mpEntryList->SetLastSelected( nSelect );
bFocusChanged = sal_True;
bSelectionChanged = sal_True;
}
}
// MultiListBox ohne Modifier
else if( mbSimpleMode && !bCtrl && !bShift )
{
sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
for ( sal_uInt16 nPos = 0; nPos < nEntryCount; nPos++ )
{
sal_Bool bSelect = nPos == nSelect;
if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
{
SelectEntry( nPos, bSelect );
bFocusChanged = sal_True;
bSelectionChanged = sal_True;
}
}
mpEntryList->SetLastSelected( nSelect );
mpEntryList->SetSelectionAnchor( nSelect );
}
// MultiListBox nur mit CTRL/SHIFT oder nicht im SimpleMode
else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
{
// Space fuer Selektionswechsel
if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
{
sal_Bool bSelect = ( mbStackMode && IsMouseMoveSelect() ) ? sal_True : !mpEntryList->IsEntryPosSelected( nSelect );
if ( mbStackMode )
{
sal_uInt16 n;
if ( bSelect )
{
// All entries before nSelect must be selected...
for ( n = 0; n < nSelect; n++ )
SelectEntry( n, sal_True );
}
if ( !bSelect )
{
for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
SelectEntry( n, sal_False );
}
}
SelectEntry( nSelect, bSelect );
mpEntryList->SetLastSelected( nSelect );
mpEntryList->SetSelectionAnchor( mbStackMode ? 0 : nSelect );
if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND );
bFocusChanged = sal_True;
bSelectionChanged = sal_True;
}
else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
{
mnCurrentPos = nSelect;
bFocusChanged = sal_True;
sal_uInt16 nAnchor = mpEntryList->GetSelectionAnchor();
if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
{
nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
}
if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
{
// Alle Eintraege vom Anchor bis nSelect muessen selektiert sein
sal_uInt16 nStart = Min( nSelect, nAnchor );
sal_uInt16 nEnd = Max( nSelect, nAnchor );
for ( sal_uInt16 n = nStart; n <= nEnd; n++ )
{
if ( !mpEntryList->IsEntryPosSelected( n ) )
{
SelectEntry( n, sal_True );
bSelectionChanged = sal_True;
}
}
// Ggf. muss noch was deselektiert werden...
sal_uInt16 nLast = mpEntryList->GetLastSelected();
if ( nLast != LISTBOX_ENTRY_NOTFOUND )
{
if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
{
for ( sal_uInt16 n = nSelect+1; n <= nLast; n++ )
{
if ( mpEntryList->IsEntryPosSelected( n ) )
{
SelectEntry( n, sal_False );
bSelectionChanged = sal_True;
}
}
}
else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
{
for ( sal_uInt16 n = nLast; n < nSelect; n++ )
{
if ( mpEntryList->IsEntryPosSelected( n ) )
{
SelectEntry( n, sal_False );
bSelectionChanged = sal_True;
}
}
}
}
mpEntryList->SetLastSelected( nSelect );
}
}
else if( eLET != LET_TRACKING )
{
ImplHideFocusRect();
ImplPaint( nSelect, sal_True );
bFocusChanged = sal_True;
}
}
else if( bShift )
{
bFocusChanged = sal_True;
}
if( bSelectionChanged )
mbSelectionChanged = true;
if( bFocusChanged )
{
long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop, 0 );
maFocusRect.SetPos( Point( 0, nHeightDiff ) );
Size aSz( maFocusRect.GetWidth(),
mpEntryList->GetEntryHeight( nSelect ) );
maFocusRect.SetSize( aSz );
if( HasFocus() )
ImplShowFocusRect();
if (bSelectPosChange)
{
maFocusHdl.Call(reinterpret_cast<void*>(nSelect));
}
}
ImplClearLayoutData();
}
return bSelectionChanged;
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
{
Point aPoint;
Rectangle aRect( aPoint, GetOutputSizePixel() );
sal_Bool bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
{
if ( bInside && !rTEvt.IsTrackingCanceled() )
{
mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
ImplCallSelect();
}
else
{
maCancelHdl.Call( NULL );
if ( !mbMulti )
{
mbTrackingSelect = true;
SelectEntry( mnTrackingSaveSelection, sal_True );
mbTrackingSelect = false;
if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
{
long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
maFocusRect.SetPos( Point( 0, nHeightDiff ) );
Size aSz( maFocusRect.GetWidth(),
mpEntryList->GetEntryHeight( mnCurrentPos ) );
maFocusRect.SetSize( aSz );
ImplShowFocusRect();
}
}
}
mbTrack = false;
}
else
{
sal_Bool bTrackOrQuickClick = mbTrack;
if( !mbTrack )
{
if ( bInside )
{
mbTrack = true;
}
// Folgender Fall tritt nur auf, wenn man ganz kurz die Maustaste drueckt
if( rTEvt.IsTrackingEnded() && mbTrack )
{
bTrackOrQuickClick = sal_True;
mbTrack = false;
}
}
if( bTrackOrQuickClick )
{
MouseEvent aMEvt = rTEvt.GetMouseEvent();
Point aPt( aMEvt.GetPosPixel() );
sal_Bool bShift = aMEvt.IsShift();
sal_Bool bCtrl = aMEvt.IsMod1();
sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
if( aPt.Y() < 0 )
{
if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
{
nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
if( nSelect < mnTop )
SetTopEntry( mnTop-1 );
}
}
else if( aPt.Y() > GetOutputSizePixel().Height() )
{
if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
{
nSelect = Min( (sal_uInt16)(mnCurrentPos+1), (sal_uInt16)(mpEntryList->GetEntryCount()-1) );
if( nSelect >= GetLastVisibleEntry() )
SetTopEntry( mnTop+1 );
}
}
else
{
nSelect = (sal_uInt16) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (sal_uInt16) mnTop;
nSelect = Min( nSelect, GetLastVisibleEntry() );
nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
}
if ( bInside )
{
if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
{
mbTrackingSelect = true;
if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
{
if ( mbStackMode ) // #87734# (#87072#)
{
mbTravelSelect = true;
mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
ImplCallSelect();
mbTravelSelect = false;
}
}
mbTrackingSelect = false;
}
}
else
{
if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
{
mbTrackingSelect = true;
SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), sal_False );
mbTrackingSelect = false;
}
else if ( mbStackMode )
{
if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
{
if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
{
sal_Bool bSelectionChanged = sal_False;
if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
&& !mnCurrentPos )
{
if ( mpEntryList->IsEntryPosSelected( 0 ) )
{
SelectEntry( 0, sal_False );
bSelectionChanged = sal_True;
nSelect = LISTBOX_ENTRY_NOTFOUND;
}
}
else
{
mbTrackingSelect = true;
bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
mbTrackingSelect = false;
}
if ( bSelectionChanged )
{
mbSelectionChanged = true;
mbTravelSelect = true;
mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
ImplCallSelect();
mbTravelSelect = false;
}
}
}
}
}
mnCurrentPos = nSelect;
if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
{
ImplHideFocusRect();
}
else
{
long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
maFocusRect.SetPos( Point( 0, nHeightDiff ) );
Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
maFocusRect.SetSize( aSz );
ImplShowFocusRect();
}
}
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
{
if( !ProcessKeyInput( rKEvt ) )
Control::KeyInput( rKEvt );
}
// -----------------------------------------------------------------------
#define IMPL_SELECT_NODIRECTION 0
#define IMPL_SELECT_UP 1
#define IMPL_SELECT_DOWN 2
sal_Bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
{
// zu selektierender Eintrag
sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
LB_EVENT_TYPE eLET = LET_KEYMOVE;
KeyCode aKeyCode = rKEvt.GetKeyCode();
sal_Bool bShift = aKeyCode.IsShift();
sal_Bool bCtrl = aKeyCode.IsMod1() || aKeyCode.IsMod3();
sal_Bool bMod2 = aKeyCode.IsMod2();
sal_Bool bDone = sal_False;
switch( aKeyCode.GetCode() )
{
case KEY_UP:
{
if ( IsReadOnly() )
{
if ( GetTopEntry() )
SetTopEntry( GetTopEntry()-1 );
}
else if ( !bMod2 )
{
if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
{
nSelect = mpEntryList->FindFirstSelectable( 0, true );
}
else if ( mnCurrentPos )
{
// search first selectable above the current position
nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
}
if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
SetTopEntry( mnTop-1 );
bDone = sal_True;
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_DOWN:
{
if ( IsReadOnly() )
{
SetTopEntry( GetTopEntry()+1 );
}
else if ( !bMod2 )
{
if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
{
nSelect = mpEntryList->FindFirstSelectable( 0, true );
}
else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
{
// search first selectable below the current position
nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
}
if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
SetTopEntry( mnTop+1 );
bDone = sal_True;
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_PAGEUP:
{
if ( IsReadOnly() )
{
sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
SetTopEntry( ( mnTop > nCurVis ) ?
(mnTop-nCurVis) : 0 );
}
else if ( !bCtrl && !bMod2 )
{
if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
{
nSelect = mpEntryList->FindFirstSelectable( 0, true );
}
else if ( mnCurrentPos )
{
if( mnCurrentPos == mnTop )
{
sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
}
// find first selectable starting from mnTop looking foreward
nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
}
bDone = sal_True;
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_PAGEDOWN:
{
if ( IsReadOnly() )
{
SetTopEntry( GetLastVisibleEntry() );
}
else if ( !bCtrl && !bMod2 )
{
if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
{
nSelect = mpEntryList->FindFirstSelectable( 0, true );
}
else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
{
sal_uInt16 nCount = mpEntryList->GetEntryCount();
sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop;
sal_uInt16 nTmp = Min( nCurVis, nCount );
nTmp += mnTop - 1;
if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
{
long nTmp2 = Min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
nTmp2 = Max( (long)0 , nTmp2 );
nTmp = (sal_uInt16)(nTmp2+(nCurVis-1) );
SetTopEntry( (sal_uInt16)nTmp2 );
}
// find first selectable starting from nTmp looking backwards
nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
}
bDone = sal_True;
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_HOME:
{
if ( IsReadOnly() )
{
SetTopEntry( 0 );
}
else if ( !bCtrl && !bMod2 )
{
if ( mnCurrentPos )
{
nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
if( mnTop != 0 )
SetTopEntry( 0 );
bDone = sal_True;
}
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_END:
{
if ( IsReadOnly() )
{
SetTopEntry( 0xFFFF );
}
else if ( !bCtrl && !bMod2 )
{
if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
{
nSelect = mpEntryList->FindFirstSelectable( 0, true );
}
else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
{
sal_uInt16 nCount = mpEntryList->GetEntryCount();
nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop + 1;
if( nCount > nCurVis )
SetTopEntry( nCount - nCurVis );
}
bDone = sal_True;
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_LEFT:
{
if ( !bCtrl && !bMod2 )
{
ScrollHorz( -HORZ_SCROLL );
bDone = sal_True;
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_RIGHT:
{
if ( !bCtrl && !bMod2 )
{
ScrollHorz( HORZ_SCROLL );
bDone = sal_True;
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_RETURN:
{
if ( !bMod2 && !IsReadOnly() )
{
mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
ImplCallSelect();
bDone = sal_False; // RETURN nicht abfangen.
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_SPACE:
{
if ( !bMod2 && !IsReadOnly() )
{
if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
{
nSelect = mnCurrentPos;
eLET = LET_KEYSPACE;
}
bDone = sal_True;
}
maQuickSelectionEngine.Reset();
}
break;
case KEY_A:
{
if( bCtrl && mbMulti )
{
// paint only once
sal_Bool bUpdates = IsUpdateMode();
SetUpdateMode( sal_False );
sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
for( sal_uInt16 i = 0; i < nEntryCount; i++ )
SelectEntry( i, sal_True );
// restore update mode
SetUpdateMode( bUpdates );
Invalidate();
maQuickSelectionEngine.Reset();
bDone = sal_True;
break;
}
}
// fall through intentional
default:
{
if ( !IsReadOnly() )
{
bDone = maQuickSelectionEngine.HandleKeyEvent( rKEvt );
}
}
break;
}
if ( ( nSelect != LISTBOX_ENTRY_NOTFOUND )
&& ( ( !mpEntryList->IsEntryPosSelected( nSelect ) )
|| ( eLET == LET_KEYSPACE )
)
)
{
DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
if( nSelect >= mpEntryList->GetEntryCount() )
nSelect = mpEntryList->GetEntryCount()-1;
sal_Bool bCurPosChange = (mnCurrentPos != nSelect);
mnCurrentPos = nSelect;
//if ( SelectEntries( nSelect, eLET, bShift, bCtrl ) )
if(SelectEntries( nSelect, eLET, bShift, bCtrl ,bCurPosChange))
{
mbTravelSelect = true;
mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
ImplCallSelect();
mbTravelSelect = false;
}
}
return bDone;
}
// -----------------------------------------------------------------------
namespace
{
static ::vcl::StringEntryIdentifier lcl_getEntry( const ImplEntryList& _rList, sal_uInt16 _nPos, String& _out_entryText )
{
OSL_PRECOND( ( _nPos != LISTBOX_ENTRY_NOTFOUND ), "lcl_getEntry: invalid position!" );
sal_uInt16 nEntryCount( _rList.GetEntryCount() );
if ( _nPos >= nEntryCount )
_nPos = 0;
_out_entryText = _rList.GetEntryText( _nPos );
// ::vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
// => normalize
return reinterpret_cast< ::vcl::StringEntryIdentifier >( _nPos + 1 );
}
static sal_uInt16 lcl_getEntryPos( ::vcl::StringEntryIdentifier _entry )
{
// our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
return static_cast< sal_uInt16 >( reinterpret_cast< sal_Int64 >( _entry ) ) - 1;
}
}
// -----------------------------------------------------------------------
::vcl::StringEntryIdentifier ImplListBoxWindow::CurrentEntry( String& _out_entryText ) const
{
return lcl_getEntry( *GetEntryList(), ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND ) ? 0 : mnCurrentPos + 1, _out_entryText );
}
// -----------------------------------------------------------------------
::vcl::StringEntryIdentifier ImplListBoxWindow::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, String& _out_entryText ) const
{
sal_uInt16 nNextPos = lcl_getEntryPos( _currentEntry ) + 1;
return lcl_getEntry( *GetEntryList(), nNextPos, _out_entryText );
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::SelectEntry( ::vcl::StringEntryIdentifier _entry )
{
sal_uInt16 nSelect = lcl_getEntryPos( _entry );
if ( mpEntryList->IsEntryPosSelected( nSelect ) )
{
// ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
// to select the given entry by typing its starting letters. No need to act.
return;
}
// normalize
OSL_ENSURE( nSelect < mpEntryList->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
if( nSelect >= mpEntryList->GetEntryCount() )
nSelect = mpEntryList->GetEntryCount()-1;
// make visible
ShowProminentEntry( nSelect );
// actually select
mnCurrentPos = nSelect;
if ( SelectEntries( nSelect, LET_KEYMOVE, sal_False, sal_False ) )
{
mbTravelSelect = true;
mnSelectModifier = 0;
ImplCallSelect();
mbTravelSelect = false;
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ImplPaint( sal_uInt16 nPos, sal_Bool bErase, bool bLayout )
{
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
if( ! pEntry )
return;
long nWidth = GetOutputSizePixel().Width();
long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
if( ! bLayout )
{
if( mpEntryList->IsEntryPosSelected( nPos ) )
{
SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
SetFillColor( rStyleSettings.GetHighlightColor() );
SetTextFillColor( rStyleSettings.GetHighlightColor() );
DrawRect( aRect );
}
else
{
ImplInitSettings( sal_False, sal_True, sal_False );
if( !IsEnabled() )
SetTextColor( rStyleSettings.GetDisableColor() );
SetTextFillColor();
if( bErase )
Erase( aRect );
}
}
if ( IsUserDrawEnabled() )
{
mbInUserDraw = true;
mnUserDrawEntry = nPos;
aRect.Left() -= mnLeft;
if ( nPos < GetEntryList()->GetMRUCount() )
nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
nPos = sal::static_int_cast<sal_uInt16>(nPos - GetEntryList()->GetMRUCount());
UserDrawEvent aUDEvt( this, aRect, nPos, 0 );
maUserDrawHdl.Call( &aUDEvt );
mbInUserDraw = false;
}
else
{
DrawEntry( nPos, sal_True, sal_True, sal_False, bLayout );
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::DrawEntry( sal_uInt16 nPos, sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
{
const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
if( ! pEntry )
return;
// Bei Aenderungen in dieser Methode ggf. auch ImplWin::DrawEntry() anpassen.
if ( mbInUserDraw )
nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
Size aImgSz;
if( bDrawImage && mpEntryList->HasImages() && !bLayout )
{
Image aImage = mpEntryList->GetEntryImage( nPos );
if( !!aImage )
{
aImgSz = aImage.GetSizePixel();
Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
// pb: #106948# explicit mirroring for calc
if ( mbMirroring )
// right aligned
aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
if ( !IsZoom() )
{
DrawImage( aPtImg, aImage );
}
else
{
aImgSz.Width() = CalcZoom( aImgSz.Width() );
aImgSz.Height() = CalcZoom( aImgSz.Height() );
DrawImage( aPtImg, aImgSz, aImage );
}
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
if(nEdgeBlendingPercent && aImgSz.Width() && aImgSz.Height())
{
const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
const BitmapEx aBlendFrame(createBlendFrame(aImgSz, nAlpha, rTopLeft, rBottomRight));
if(!aBlendFrame.IsEmpty())
{
DrawBitmapEx(aPtImg, aBlendFrame);
}
}
}
}
if( bDrawText )
{
MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
XubString aStr( mpEntryList->GetEntryText( nPos ) );
if ( aStr.Len() )
{
long nMaxWidth = Max( static_cast< long >( mnMaxWidth ),
GetOutputSizePixel().Width() - 2*mnBorder );
// a multiline entry should only be as wide a the window
if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
Size( nMaxWidth, pEntry->mnHeight ) );
if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
{
long nImageWidth = Max( mnMaxImgWidth, maUserItemSize.Width() );
aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
}
if( bLayout )
mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
// pb: #106948# explicit mirroring for calc
if ( mbMirroring )
{
// right aligned
aTextRect.Left() = nMaxWidth + mnBorder - GetTextWidth( aStr ) - mnLeft;
if ( aImgSz.Width() > 0 )
aTextRect.Left() -= ( aImgSz.Width() + IMG_TXT_DISTANCE );
}
sal_uInt16 nDrawStyle = ImplGetTextStyle();
if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) )
nDrawStyle |= TEXT_DRAW_DISABLE;
DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
}
}
if( !bLayout )
{
if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
{
Color aOldLineColor( GetLineColor() );
SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
Point aStartPos( 0, nY );
if ( nPos == mnSeparatorPos )
aStartPos.Y() += pEntry->mnHeight-1;
Point aEndPos( aStartPos );
aEndPos.X() = GetOutputSizePixel().Width();
DrawLine( aStartPos, aEndPos );
SetLineColor( aOldLineColor );
}
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::FillLayoutData() const
{
mpControlData->mpLayoutData = new vcl::ControlLayoutData();
const_cast<ImplListBoxWindow*>(this)->
ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
{
sal_uInt16 nCount = mpEntryList->GetEntryCount();
sal_Bool bShowFocusRect = mbHasFocusRect;
if ( mbHasFocusRect && ! bLayout )
ImplHideFocusRect();
long nY = 0; // + mnBorder;
long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
for( sal_uInt16 i = (sal_uInt16)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
{
const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
if( nY + pEntry->mnHeight >= rRect.Top() &&
nY <= rRect.Bottom() + mnMaxHeight )
{
ImplPaint( i, sal_False, bLayout );
}
nY += pEntry->mnHeight;
}
long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
maFocusRect.SetPos( Point( 0, nHeightDiff ) );
Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
maFocusRect.SetSize( aSz );
if( HasFocus() && bShowFocusRect && !bLayout )
ImplShowFocusRect();
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::Paint( const Rectangle& rRect )
{
ImplDoPaint( rRect );
}
// -----------------------------------------------------------------------
sal_uInt16 ImplListBoxWindow::GetDisplayLineCount() const
{
// FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
sal_uInt16 nCount = mpEntryList->GetEntryCount();
long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
sal_uInt16 nEntries = static_cast< sal_uInt16 >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
if( nEntries > nCount-mnTop )
nEntries = nCount-mnTop;
return nEntries;
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::Resize()
{
Control::Resize();
sal_Bool bShowFocusRect = mbHasFocusRect;
if ( bShowFocusRect )
ImplHideFocusRect();
if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
{
Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
maFocusRect.SetSize( aSz );
}
if ( bShowFocusRect )
ImplShowFocusRect();
ImplClearLayoutData();
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::GetFocus()
{
sal_uInt16 nPos = mnCurrentPos;
if ( nPos == LISTBOX_ENTRY_NOTFOUND )
nPos = 0;
long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
maFocusRect.SetPos( Point( 0, nHeightDiff ) );
Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
maFocusRect.SetSize( aSz );
ImplShowFocusRect();
Control::GetFocus();
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::LoseFocus()
{
ImplHideFocusRect();
Control::LoseFocus();
}
// -----------------------------------------------------------------------
/*
void ImplListBoxWindow::RequestHelp( const HelpEvent& rHEvt )
{
if ( rHEvt.GetMode() & HELPMODE_BALLOON )
Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), String() );
Window::RequestHelp( rHEvt );
}
*/
// -----------------------------------------------------------------------
void ImplListBoxWindow::SetTopEntry( sal_uInt16 nTop )
{
if( mpEntryList->GetEntryCount() == 0 )
return;
long nWHeight = PixelToLogic( GetSizePixel() ).Height();
sal_uInt16 nLastEntry = mpEntryList->GetEntryCount()-1;
if( nTop > nLastEntry )
nTop = nLastEntry;
const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
nTop--;
if ( nTop != mnTop )
{
ImplClearLayoutData();
long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
Update();
ImplHideFocusRect();
mnTop = nTop;
Scroll( 0, nDiff );
Update();
if( HasFocus() )
ImplShowFocusRect();
maScrollHdl.Call( this );
}
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ShowProminentEntry( sal_uInt16 nEntryPos )
{
if( meProminentType == PROMINENT_MIDDLE )
{
sal_uInt16 nPos = nEntryPos;
long nWHeight = PixelToLogic( GetSizePixel() ).Height();
while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
nEntryPos--;
}
SetTopEntry( nEntryPos );
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::SetLeftIndent( long n )
{
ScrollHorz( n - mnLeft );
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::ScrollHorz( long n )
{
long nDiff = 0;
if ( n > 0 )
{
long nWidth = GetOutputSizePixel().Width();
if( ( mnMaxWidth - mnLeft + n ) > nWidth )
nDiff = n;
}
else if ( n < 0 )
{
if( mnLeft )
{
long nAbs = -n;
nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
}
}
if ( nDiff )
{
ImplClearLayoutData();
mnLeft = sal::static_int_cast<sal_uInt16>(mnLeft + nDiff);
Update();
ImplHideFocusRect();
Scroll( -nDiff, 0 );
Update();
if( HasFocus() )
ImplShowFocusRect();
maScrollHdl.Call( this );
}
}
// -----------------------------------------------------------------------
Size ImplListBoxWindow::CalcSize( sal_uInt16 nMaxLines ) const
{
// FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
Size aSz;
// sal_uInt16 nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
aSz.Height() = nMaxLines * mnMaxHeight;
aSz.Width() = mnMaxWidth + 2*mnBorder;
return aSz;
}
// -----------------------------------------------------------------------
Rectangle ImplListBoxWindow::GetBoundingRectangle( sal_uInt16 nItem ) const
{
const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
//long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) - mpEntryList->GetAddedHeight( GetTopEntry() );
long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeight();
Rectangle aRect( Point( 0, nY ), aSz );
return aRect;
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::StateChanged( StateChangedType nType )
{
Control::StateChanged( nType );
if ( nType == STATE_CHANGE_ZOOM )
{
ImplInitSettings( sal_True, sal_False, sal_False );
ImplCalcMetrics();
Invalidate();
}
else if ( nType == STATE_CHANGE_UPDATEMODE )
{
if ( IsUpdateMode() && IsReallyVisible() )
Invalidate();
}
else if ( nType == STATE_CHANGE_CONTROLFONT )
{
ImplInitSettings( sal_True, sal_False, sal_False );
ImplCalcMetrics();
Invalidate();
}
else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
{
ImplInitSettings( sal_False, sal_True, sal_False );
Invalidate();
}
else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
{
ImplInitSettings( sal_False, sal_False, sal_True );
Invalidate();
}
ImplClearLayoutData();
}
// -----------------------------------------------------------------------
void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
{
Control::DataChanged( rDCEvt );
if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
(rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
(rDCEvt.GetFlags() & SETTINGS_STYLE)) )
{
ImplClearLayoutData();
ImplInitSettings( sal_True, sal_True, sal_True );
ImplCalcMetrics();
Invalidate();
}
}
// -----------------------------------------------------------------------
sal_uInt16 ImplListBoxWindow::ImplGetTextStyle() const
{
sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
if ( mpEntryList->HasImages() )
nTextStyle |= TEXT_DRAW_LEFT;
else if ( mbCenter )
nTextStyle |= TEXT_DRAW_CENTER;
else if ( mbRight )
nTextStyle |= TEXT_DRAW_RIGHT;
else
nTextStyle |= TEXT_DRAW_LEFT;
return nTextStyle;
}
// =======================================================================
ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
Control( pParent, nWinStyle ),
maLBWindow( this, nWinStyle&(~WB_BORDER) )
{
// for native widget rendering we must be able to detect this window type
SetType( WINDOW_LISTBOXWINDOW );
mpVScrollBar = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
mpHScrollBar = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
mpScrollBarBox = new ScrollBarBox( this );
Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
mpVScrollBar->SetScrollHdl( aLink );
mpHScrollBar->SetScrollHdl( aLink );
mbVScroll = false;
mbHScroll = false;
mbAutoHScroll = ( nWinStyle & WB_AUTOHSCROLL );
mbEdgeBlending = false;
maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
maLBWindow.SetEdgeBlending(GetEdgeBlending());
maLBWindow.Show();
}
// -----------------------------------------------------------------------
ImplListBox::~ImplListBox()
{
delete mpHScrollBar;
delete mpVScrollBar;
delete mpScrollBarBox;
}
// -----------------------------------------------------------------------
void ImplListBox::Clear()
{
maLBWindow.Clear();
if ( GetEntryList()->GetMRUCount() )
{
maLBWindow.GetEntryList()->SetMRUCount( 0 );
maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
}
mpVScrollBar->SetThumbPos( 0 );
mpHScrollBar->SetThumbPos( 0 );
StateChanged( STATE_CHANGE_DATA );
}
// -----------------------------------------------------------------------
sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr )
{
ImplEntryType* pNewEntry = new ImplEntryType( rStr );
sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
StateChanged( STATE_CHANGE_DATA );
return nNewPos;
}
// -----------------------------------------------------------------------
sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const Image& rImage )
{
ImplEntryType* pNewEntry = new ImplEntryType( rImage );
sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
StateChanged( STATE_CHANGE_DATA );
return nNewPos;
}
// -----------------------------------------------------------------------
sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr, const Image& rImage )
{
ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
StateChanged( STATE_CHANGE_DATA );
return nNewPos;
}
// -----------------------------------------------------------------------
void ImplListBox::RemoveEntry( sal_uInt16 nPos )
{
maLBWindow.RemoveEntry( nPos );
StateChanged( STATE_CHANGE_DATA );
}
// -----------------------------------------------------------------------
void ImplListBox::SetEntryFlags( sal_uInt16 nPos, long nFlags )
{
maLBWindow.SetEntryFlags( nPos, nFlags );
}
// -----------------------------------------------------------------------
long ImplListBox::GetEntryFlags( sal_uInt16 nPos ) const
{
return maLBWindow.GetEntryList()->GetEntryFlags( nPos );
}
// -----------------------------------------------------------------------
void ImplListBox::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
{
maLBWindow.SelectEntry( nPos, bSelect );
}
// -----------------------------------------------------------------------
void ImplListBox::SetNoSelection()
{
maLBWindow.DeselectAll();
}
// -----------------------------------------------------------------------
void ImplListBox::GetFocus()
{
maLBWindow.GrabFocus();
}
// -----------------------------------------------------------------------
Window* ImplListBox::GetPreferredKeyInputWindow()
{
return &maLBWindow;
}
// -----------------------------------------------------------------------
void ImplListBox::Resize()
{
Control::Resize();
ImplResizeControls();
ImplCheckScrollBars();
}
// -----------------------------------------------------------------------
IMPL_LINK( ImplListBox, MRUChanged, void*, EMPTYARG )
{
StateChanged( STATE_CHANGE_DATA );
return 1;
}
// -----------------------------------------------------------------------
IMPL_LINK( ImplListBox, LBWindowScrolled, void*, EMPTYARG )
{
long nSet = GetTopEntry();
if( nSet > mpVScrollBar->GetRangeMax() )
mpVScrollBar->SetRangeMax( GetEntryList()->GetEntryCount() );
mpVScrollBar->SetThumbPos( GetTopEntry() );
mpHScrollBar->SetThumbPos( GetLeftIndent() );
maScrollHdl.Call( this );
return 1;
}
// -----------------------------------------------------------------------
IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
{
sal_uInt16 nPos = (sal_uInt16) pSB->GetThumbPos();
if( pSB == mpVScrollBar )
SetTopEntry( nPos );
else if( pSB == mpHScrollBar )
SetLeftIndent( nPos );
return 1;
}
// -----------------------------------------------------------------------
void ImplListBox::ImplCheckScrollBars()
{
sal_Bool bArrange = sal_False;
Size aOutSz = GetOutputSizePixel();
sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
sal_uInt16 nMaxVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
// vert. ScrollBar
if( nEntries > nMaxVisEntries )
{
if( !mbVScroll )
bArrange = sal_True;
mbVScroll = true;
// Ueberpruefung des rausgescrollten Bereichs
if( GetEntryList()->GetSelectEntryCount() == 1 &&
GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
else
SetTopEntry( GetTopEntry() ); // MaxTop wird geprueft...
}
else
{
if( mbVScroll )
bArrange = sal_True;
mbVScroll = false;
SetTopEntry( 0 );
}
// horz. ScrollBar
if( mbAutoHScroll )
{
long nWidth = (sal_uInt16) aOutSz.Width();
if ( mbVScroll )
nWidth -= mpVScrollBar->GetSizePixel().Width();
long nMaxWidth = GetMaxEntryWidth();
if( nWidth < nMaxWidth )
{
if( !mbHScroll )
bArrange = sal_True;
mbHScroll = true;
if ( !mbVScroll ) // ggf. brauchen wir jetzt doch einen
{
nMaxVisEntries = (sal_uInt16) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
if( nEntries > nMaxVisEntries )
{
bArrange = sal_True;
mbVScroll = true;
// Ueberpruefung des rausgescrollten Bereichs
if( GetEntryList()->GetSelectEntryCount() == 1 &&
GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
else
SetTopEntry( GetTopEntry() ); // MaxTop wird geprueft...
}
}
// Ueberpruefung des rausgescrollten Bereichs
sal_uInt16 nMaxLI = (sal_uInt16) (nMaxWidth - nWidth);
if ( nMaxLI < GetLeftIndent() )
SetLeftIndent( nMaxLI );
}
else
{
if( mbHScroll )
bArrange = sal_True;
mbHScroll = false;
SetLeftIndent( 0 );
}
}
if( bArrange )
ImplResizeControls();
ImplInitScrollBars();
}
// -----------------------------------------------------------------------
void ImplListBox::ImplInitScrollBars()
{
Size aOutSz = maLBWindow.GetOutputSizePixel();
if ( mbVScroll )
{
sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
sal_uInt16 nVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
mpVScrollBar->SetRangeMax( nEntries );
mpVScrollBar->SetVisibleSize( nVisEntries );
mpVScrollBar->SetPageSize( nVisEntries - 1 );
}
if ( mbHScroll )
{
mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
mpHScrollBar->SetVisibleSize( (sal_uInt16)aOutSz.Width() );
mpHScrollBar->SetLineSize( HORZ_SCROLL );
mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
}
}
// -----------------------------------------------------------------------
void ImplListBox::ImplResizeControls()
{
// Hier werden die Controls nur angeordnet, ob die Scrollbars
// sichtbar sein sollen wird bereits in ImplCheckScrollBars ermittelt.
Size aOutSz = GetOutputSizePixel();
long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
nSBWidth = CalcZoom( nSBWidth );
Size aInnerSz( aOutSz );
if ( mbVScroll )
aInnerSz.Width() -= nSBWidth;
if ( mbHScroll )
aInnerSz.Height() -= nSBWidth;
// pb: #106948# explicit mirroring for calc
// Scrollbar on left or right side?
sal_Bool bMirroring = maLBWindow.IsMirroring();
Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
// ScrollBarBox
if( mbVScroll && mbHScroll )
{
Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
mpScrollBarBox->Show();
}
else
{
mpScrollBarBox->Hide();
}
// vert. ScrollBar
if( mbVScroll )
{
// Scrollbar on left or right side?
Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
mpVScrollBar->Show();
}
else
{
mpVScrollBar->Hide();
// #107254# Don't reset top entry after resize, but check for max top entry
SetTopEntry( GetTopEntry() );
}
// horz. ScrollBar
if( mbHScroll )
{
Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
mpHScrollBar->Show();
}
else
{
mpHScrollBar->Hide();
SetLeftIndent( 0 );
}
}
// -----------------------------------------------------------------------
void ImplListBox::StateChanged( StateChangedType nType )
{
if ( nType == STATE_CHANGE_INITSHOW )
{
ImplCheckScrollBars();
}
else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
{
sal_Bool bUpdate = IsUpdateMode();
maLBWindow.SetUpdateMode( bUpdate );
// mpHScrollBar->SetUpdateMode( bUpdate );
// mpVScrollBar->SetUpdateMode( bUpdate );
if ( bUpdate && IsReallyVisible() )
ImplCheckScrollBars();
}
else if( nType == STATE_CHANGE_ENABLE )
{
mpHScrollBar->Enable( IsEnabled() );
mpVScrollBar->Enable( IsEnabled() );
mpScrollBarBox->Enable( IsEnabled() );
Invalidate();
}
else if ( nType == STATE_CHANGE_ZOOM )
{
maLBWindow.SetZoom( GetZoom() );
Resize();
}
else if ( nType == STATE_CHANGE_CONTROLFONT )
{
maLBWindow.SetControlFont( GetControlFont() );
}
else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
{
maLBWindow.SetControlForeground( GetControlForeground() );
}
else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
{
maLBWindow.SetControlBackground( GetControlBackground() );
}
else if( nType == STATE_CHANGE_MIRRORING )
{
maLBWindow.EnableRTL( IsRTLEnabled() );
mpHScrollBar->EnableRTL( IsRTLEnabled() );
mpVScrollBar->EnableRTL( IsRTLEnabled() );
ImplResizeControls();
}
Control::StateChanged( nType );
}
// -----------------------------------------------------------------------
void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
{
// if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
// (rDCEvt.GetFlags() & SETTINGS_STYLE) )
// {
// maLBWindow.SetSettings( GetSettings() );
// Resize();
// }
// else
Control::DataChanged( rDCEvt );
}
// -----------------------------------------------------------------------
long ImplListBox::Notify( NotifyEvent& rNEvt )
{
long nDone = 0;
if ( rNEvt.GetType() == EVENT_COMMAND )
{
const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
if ( rCEvt.GetCommand() == COMMAND_WHEEL )
{
const CommandWheelData* pData = rCEvt.GetWheelData();
if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
{
nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
}
}
}
return nDone ? nDone : Window::Notify( rNEvt );
}
// -----------------------------------------------------------------------
const Wallpaper& ImplListBox::GetDisplayBackground() const
{
return maLBWindow.GetDisplayBackground();
}
// -----------------------------------------------------------------------
sal_Bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
{
sal_Bool bDone = sal_False;
if ( rCEvt.GetCommand() == COMMAND_WHEEL )
{
const CommandWheelData* pData = rCEvt.GetWheelData();
if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
{
sal_uInt16 nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
bDone = ProcessKeyInput( aKeyEvent );
}
}
return bDone;
}
// -----------------------------------------------------------------------
void ImplListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
{
sal_Bool bChanges = GetEntryList()->GetMRUCount() ? sal_True : sal_False;
// Remove old MRU entries
for ( sal_uInt16 n = GetEntryList()->GetMRUCount();n; )
maLBWindow.RemoveEntry( --n );
sal_uInt16 nMRUCount = 0;
sal_uInt16 nEntries = rEntries.GetTokenCount( cSep );
for ( sal_uInt16 nEntry = 0; nEntry < nEntries; nEntry++ )
{
XubString aEntry = rEntries.GetToken( nEntry, cSep );
// Accept only existing entries
if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
{
ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, sal_False );
bChanges = sal_True;
}
}
if ( bChanges )
{
maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
StateChanged( STATE_CHANGE_DATA );
}
}
// -----------------------------------------------------------------------
XubString ImplListBox::GetMRUEntries( xub_Unicode cSep ) const
{
String aEntries;
for ( sal_uInt16 n = 0; n < GetEntryList()->GetMRUCount(); n++ )
{
aEntries += GetEntryList()->GetEntryText( n );
if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
aEntries += cSep;
}
return aEntries;
}
// -----------------------------------------------------------------------
void ImplListBox::SetEdgeBlending(bool bNew)
{
if(mbEdgeBlending != bNew)
{
mbEdgeBlending = bNew;
maLBWindow.SetEdgeBlending(GetEdgeBlending());
}
}
// =======================================================================
ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
Control ( pParent, nWinStyle )
{
if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
&& ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
SetBackground();
else
SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
mbInUserDraw = false;
mbUserDrawEnabled = false;
mbEdgeBlending = false;
mnItemPos = LISTBOX_ENTRY_NOTFOUND;
}
// -----------------------------------------------------------------------
sal_Bool ImplWin::SetModeImage( const Image& rImage, BmpColorMode eMode )
{
if( eMode == BMP_COLOR_NORMAL )
SetImage( rImage );
else if( eMode == BMP_COLOR_HIGHCONTRAST )
maImageHC = rImage;
else
return sal_False;
return sal_True;
}
// -----------------------------------------------------------------------
const Image& ImplWin::GetModeImage( BmpColorMode eMode ) const
{
if( eMode == BMP_COLOR_HIGHCONTRAST )
return maImageHC;
else
return maImage;
}
// -----------------------------------------------------------------------
void ImplWin::MBDown()
{
if( IsEnabled() )
maMBDownHdl.Call( this );
}
// -----------------------------------------------------------------------
void ImplWin::MouseButtonDown( const MouseEvent& )
{
if( IsEnabled() )
{
// Control::MouseButtonDown( rMEvt );
MBDown();
}
}
// -----------------------------------------------------------------------
void ImplWin::FillLayoutData() const
{
mpControlData->mpLayoutData = new vcl::ControlLayoutData();
const_cast<ImplWin*>(this)->ImplDraw( true );
}
// -----------------------------------------------------------------------
long ImplWin::PreNotify( NotifyEvent& rNEvt )
{
long nDone = 0;
const MouseEvent* pMouseEvt = NULL;
if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
{
if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
{
// trigger redraw as mouse over state has changed
if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
&& ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
{
GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
GetParent()->GetWindow( WINDOW_BORDER )->Update();
}
}
}
return nDone ? nDone : Control::PreNotify(rNEvt);
}
// -----------------------------------------------------------------------
void ImplWin::ImplDraw( bool bLayout )
{
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
sal_Bool bNativeOK = sal_False;
if( ! bLayout )
{
ControlState nState = CTRL_STATE_ENABLED;
if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
&& IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
{
// Repaint the (focused) area similarly to
// ImplSmallBorderWindowView::DrawWindow() in
// vcl/source/window/brdwin.cxx
Window *pWin = GetParent();
ImplControlValue aControlValue;
if ( !pWin->IsEnabled() )
nState &= ~CTRL_STATE_ENABLED;
if ( pWin->HasFocus() )
nState |= CTRL_STATE_FOCUSED;
// The listbox is painted over the entire control including the
// border, but ImplWin does not contain the border => correction
// needed.
sal_Int32 nLeft, nTop, nRight, nBottom;
pWin->GetBorder( nLeft, nTop, nRight, nBottom );
Point aPoint( -nLeft, -nTop );
Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
sal_Bool bMouseOver = sal_False;
if( GetParent() )
{
Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
while( pChild && (bMouseOver = pChild->IsMouseOver()) == sal_False )
pChild = pChild->GetWindow( WINDOW_NEXT );
}
if( bMouseOver )
nState |= CTRL_STATE_ROLLOVER;
// if parent has no border, then nobody has drawn the background
// since no border window exists. so draw it here.
WinBits nParentStyle = pWin->GetStyle();
if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
{
Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentRect,
nState, aControlValue, rtl::OUString() );
}
bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
aControlValue, rtl::OUString() );
}
if( IsEnabled() )
{
if( HasFocus() )
{
SetTextColor( rStyleSettings.GetHighlightTextColor() );
SetFillColor( rStyleSettings.GetHighlightColor() );
DrawRect( maFocusRect );
}
else
{
Color aColor;
if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
aColor = rStyleSettings.GetFieldRolloverTextColor();
else
aColor = rStyleSettings.GetFieldTextColor();
if( IsControlForeground() )
aColor = GetControlForeground();
SetTextColor( aColor );
if ( !bNativeOK )
Erase( maFocusRect );
}
}
else // Disabled
{
SetTextColor( rStyleSettings.GetDisableColor() );
if ( !bNativeOK )
Erase( maFocusRect );
}
}
if ( IsUserDrawEnabled() )
{
mbInUserDraw = true;
UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
maUserDrawHdl.Call( &aUDEvt );
mbInUserDraw = false;
}
else
{
DrawEntry( sal_True, sal_True, sal_False, bLayout );
}
}
// -----------------------------------------------------------------------
void ImplWin::Paint( const Rectangle& )
{
ImplDraw();
}
// -----------------------------------------------------------------------
void ImplWin::DrawEntry( sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
{
long nBorder = 1;
Size aOutSz = GetOutputSizePixel();
sal_Bool bImage = !!maImage;
if( bDrawImage && bImage && !bLayout )
{
sal_uInt16 nStyle = 0;
Size aImgSz = maImage.GetSizePixel();
Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
// check for HC mode
Image *pImage = &maImage;
if( !!maImageHC )
{
if( rStyleSettings.GetHighContrastMode() )
pImage = &maImageHC;
}
if ( !IsZoom() )
{
DrawImage( aPtImg, *pImage, nStyle );
}
else
{
aImgSz.Width() = CalcZoom( aImgSz.Width() );
aImgSz.Height() = CalcZoom( aImgSz.Height() );
DrawImage( aPtImg, aImgSz, *pImage, nStyle );
}
const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
if(nEdgeBlendingPercent)
{
const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
const BitmapEx aBlendFrame(createBlendFrame(aImgSz, nAlpha, rTopLeft, rBottomRight));
if(!aBlendFrame.IsEmpty())
{
DrawBitmapEx(aPtImg, aBlendFrame);
}
}
}
if( bDrawText && maString.Len() )
{
sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
if ( bDrawImage && bImage && !bLayout )
nTextStyle |= TEXT_DRAW_LEFT;
else if ( GetStyle() & WB_CENTER )
nTextStyle |= TEXT_DRAW_CENTER;
else if ( GetStyle() & WB_RIGHT )
nTextStyle |= TEXT_DRAW_RIGHT;
else
nTextStyle |= TEXT_DRAW_LEFT;
Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
{
long nMaxWidth = Max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
}
MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
}
if( HasFocus() && !bLayout )
ShowFocus( maFocusRect );
}
// -----------------------------------------------------------------------
void ImplWin::Resize()
{
Control::Resize();
maFocusRect.SetSize( GetOutputSizePixel() );
Invalidate();
}
// -----------------------------------------------------------------------
void ImplWin::GetFocus()
{
ShowFocus( maFocusRect );
if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
IsNativeWidgetEnabled() &&
IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
{
Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
if( ! pWin )
pWin = GetParent();
pWin->Invalidate();
}
else
Invalidate();
Control::GetFocus();
}
// -----------------------------------------------------------------------
void ImplWin::LoseFocus()
{
HideFocus();
if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
IsNativeWidgetEnabled() &&
IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
{
Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
if( ! pWin )
pWin = GetParent();
pWin->Invalidate();
}
else
Invalidate();
Control::LoseFocus();
}
// =======================================================================
ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
PushButton( pParent, nWinStyle ),
mbDown ( sal_False )
{
}
// -----------------------------------------------------------------------
void ImplBtn::MBDown()
{
if( IsEnabled() )
maMBDownHdl.Call( this );
}
// -----------------------------------------------------------------------
void ImplBtn::MouseButtonDown( const MouseEvent& )
{
//PushButton::MouseButtonDown( rMEvt );
if( IsEnabled() )
{
MBDown();
mbDown = sal_True;
}
}
// =======================================================================
ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW ) // no drop shadow for list boxes
{
mpImplLB = NULL;
mnDDLineCount = 0;
mbAutoWidth = sal_False;
mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
EnableSaveBackground();
Window * pBorderWindow = ImplGetBorderWindow();
if( pBorderWindow )
{
SetAccessibleRole(accessibility::AccessibleRole::PANEL);
pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
}
else
{
SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
}
}
// -----------------------------------------------------------------------
long ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
{
if( rNEvt.GetType() == EVENT_LOSEFOCUS )
{
if( !GetParent()->HasChildPathFocus( sal_True ) )
EndPopupMode();
}
return FloatingWindow::PreNotify( rNEvt );
}
// -----------------------------------------------------------------------
void ImplListBoxFloatingWindow::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
{
FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
// Fix #60890# ( MBA ): um auch im aufgeklappten Zustand der Listbox die Gr"o\se einfach zu einen
// Aufruf von Resize() "andern zu k"onnen, wird die Position hier ggf. angepa\t
if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
{
Point aPos = GetParent()->GetPosPixel();
aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
if ( nFlags & WINDOW_POSSIZE_X )
aPos.X() = nX;
if ( nFlags & WINDOW_POSSIZE_Y )
aPos.Y() = nY;
sal_uInt16 nIndex;
SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
}
// if( !IsReallyVisible() )
{
// Die ImplListBox erhaelt kein Resize, weil nicht sichtbar.
// Die Fenster muessen aber ein Resize() erhalten, damit die
// Anzahl der sichtbaren Eintraege fuer PgUp/PgDown stimmt.
// Die Anzahl kann auch nicht von List/Combobox berechnet werden,
// weil hierfuer auch die ggf. vorhandene vertikale Scrollbar
// beruecksichtigt werden muss.
mpImplLB->SetSizePixel( GetOutputSizePixel() );
((Window*)mpImplLB)->Resize();
((Window*)mpImplLB->GetMainWindow())->Resize();
}
}
// -----------------------------------------------------------------------
void ImplListBoxFloatingWindow::Resize()
{
mpImplLB->GetMainWindow()->ImplClearLayoutData();
FloatingWindow::Resize();
}
// -----------------------------------------------------------------------
Size ImplListBoxFloatingWindow::CalcFloatSize()
{
Size aFloatSz( maPrefSz );
sal_Int32 nLeft, nTop, nRight, nBottom;
GetBorder( nLeft, nTop, nRight, nBottom );
sal_uInt16 nLines = mpImplLB->GetEntryList()->GetEntryCount();
if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
nLines = mnDDLineCount;
Size aSz = mpImplLB->CalcSize( nLines );
long nMaxHeight = aSz.Height() + nTop + nBottom;
if ( mnDDLineCount )
aFloatSz.Height() = nMaxHeight;
if( mbAutoWidth )
{
// AutoSize erstmal nur fuer die Breite...
aFloatSz.Width() = aSz.Width() + nLeft + nRight;
aFloatSz.Width() += nRight; // etwas mehr Platz sieht besser aus...
if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
{
// dann wird noch der vertikale Scrollbar benoetigt
long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
aFloatSz.Width() += nSBWidth;
}
}
if ( aFloatSz.Height() > nMaxHeight )
aFloatSz.Height() = nMaxHeight;
// Minimale Hoehe, falls Hoehe nicht auf Float-Hoehe eingestellt wurde.
// Der Parent vom FloatWin muss die DropDown-Combo/Listbox sein.
Size aParentSz = GetParent()->GetSizePixel();
if( !mnDDLineCount && ( aFloatSz.Height() < aParentSz.Height() ) )
aFloatSz.Height() = aParentSz.Height();
// Nicht schmaler als der Parent werden...
if( aFloatSz.Width() < aParentSz.Width() )
aFloatSz.Width() = aParentSz.Width();
// Hoehe auf Entries alignen...
long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
long nEntryHeight = mpImplLB->GetEntryHeight();
if ( nInnerHeight % nEntryHeight )
{
nInnerHeight /= nEntryHeight;
nInnerHeight++;
nInnerHeight *= nEntryHeight;
aFloatSz.Height() = nInnerHeight + nTop + nBottom;
}
return aFloatSz;
}
// -----------------------------------------------------------------------
void ImplListBoxFloatingWindow::StartFloat( sal_Bool bStartTracking )
{
if( !IsInPopupMode() )
{
Size aFloatSz = CalcFloatSize();
SetSizePixel( aFloatSz );
mpImplLB->SetSizePixel( GetOutputSizePixel() );
sal_uInt16 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
mnPopupModeStartSaveSelection = nPos;
Size aSz = GetParent()->GetSizePixel();
Point aPos = GetParent()->GetPosPixel();
aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
// FIXME: this ugly hack is for Mac/Aqua
// should be replaced by a real mechanism to place the float rectangle
if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
GetParent()->IsNativeWidgetEnabled() )
{
sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
aPos.X() += nLeft;
aPos.Y() += nTop;
aSz.Width() -= nLeft + nRight;
aSz.Height() -= nTop + nBottom;
}
Rectangle aRect( aPos, aSz );
// check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
// where the document is unmirrored
// because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
if( GetParent()->GetParent()->ImplIsAntiparallel() )
GetParent()->GetParent()->ImplReMirror( aRect );
StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
if( nPos != LISTBOX_ENTRY_NOTFOUND )
mpImplLB->ShowProminentEntry( nPos );
if( bStartTracking )
mpImplLB->GetMainWindow()->EnableMouseMoveSelect( sal_True );
if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
mpImplLB->GetMainWindow()->GrabFocus();
mpImplLB->GetMainWindow()->ImplClearLayoutData();
}
}