blob: c689c8957ff57cfd87908acbccfaa08528767c3d [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_svtools.hxx"
#include <limits.h>
#include <tools/debug.hxx>
#include <vcl/wall.hxx>
#include <vcl/help.hxx>
#include <vcl/decoview.hxx>
#include <vcl/svapp.hxx>
#include <tools/poly.hxx>
#include <vcl/lineinfo.hxx>
#include <vcl/i18nhelp.hxx>
#include <vcl/mnemonic.hxx>
#include <vcl/controllayout.hxx>
#include <svtools/ivctrl.hxx>
#include "imivctl.hxx"
#include <svtools/svmedit.hxx>
#include <algorithm>
#include <memory>
#define DD_SCROLL_PIXEL 24
#define IMPICNVIEW_ACC_RETURN 1
#define IMPICNVIEW_ACC_ESCAPE 2
#define DRAWTEXT_FLAGS_ICON \
( TEXT_DRAW_CENTER | TEXT_DRAW_TOP | TEXT_DRAW_ENDELLIPSIS | \
TEXT_DRAW_CLIP | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MNEMONIC )
#define DRAWTEXT_FLAGS_SMALLICON (TEXT_DRAW_LEFT|TEXT_DRAW_ENDELLIPSIS|TEXT_DRAW_CLIP)
#define EVENTID_SHOW_CURSOR ((void*)1)
#define EVENTID_ADJUST_SCROLLBARS ((void*)2)
struct SvxIconChoiceCtrlEntry_Impl
{
SvxIconChoiceCtrlEntry* _pEntry;
Point _aPos;
SvxIconChoiceCtrlEntry_Impl( SvxIconChoiceCtrlEntry* pEntry, const Rectangle& rBoundRect )
: _pEntry( pEntry), _aPos( rBoundRect.TopLeft()) {}
};
static sal_Bool bEndScrollInvalidate = sal_True;
// ----------------------------------------------------------------------------------------------
class IcnViewEdit_Impl : public MultiLineEdit
{
Link aCallBackHdl;
Accelerator aAccReturn;
Accelerator aAccEscape;
Timer aTimer;
sal_Bool bCanceled;
sal_Bool bAlreadyInCallback;
sal_Bool bGrabFocus;
void CallCallBackHdl_Impl();
DECL_LINK( Timeout_Impl, Timer * );
DECL_LINK( ReturnHdl_Impl, Accelerator * );
DECL_LINK( EscapeHdl_Impl, Accelerator * );
public:
IcnViewEdit_Impl(
SvtIconChoiceCtrl* pParent,
const Point& rPos,
const Size& rSize,
const XubString& rData,
const Link& rNotifyEditEnd );
~IcnViewEdit_Impl();
virtual void KeyInput( const KeyEvent& rKEvt );
virtual long PreNotify( NotifyEvent& rNEvt );
sal_Bool EditingCanceled() const { return bCanceled; }
void StopEditing( sal_Bool bCancel = sal_False );
sal_Bool IsGrabFocus() const { return bGrabFocus; }
};
// ----------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------
SvxIconChoiceCtrl_Impl::SvxIconChoiceCtrl_Impl( SvtIconChoiceCtrl* pCurView,
WinBits nWinStyle ) :
aEntries( this ),
aVerSBar( pCurView, WB_DRAG | WB_VSCROLL ),
aHorSBar( pCurView, WB_DRAG | WB_HSCROLL ),
aScrBarBox( pCurView ),
aImageSize( 32, 32 ),
pColumns( 0 )
{
bChooseWithCursor=sal_False;
pEntryPaintDev = 0;
pCurEditedEntry = 0;
pCurHighlightFrame = 0;
pEdit = 0;
pAnchor = 0;
pDraggedSelection = 0;
pPrevDropTarget = 0;
pHdlEntry = 0;
pHead = NULL;
pCursor = NULL;
bUpdateMode = sal_True;
bEntryEditingEnabled = sal_False;
bInDragDrop = sal_False;
bHighlightFramePressed = sal_False;
eSelectionMode = MULTIPLE_SELECTION;
pView = pCurView;
pZOrderList = new List; //SvPtrarr;
ePositionMode = IcnViewPositionModeFree;
SetStyle( nWinStyle );
nFlags = 0;
nUserEventAdjustScrBars = 0;
nUserEventShowCursor = 0;
nMaxVirtWidth = DEFAULT_MAX_VIRT_WIDTH;
nMaxVirtHeight = DEFAULT_MAX_VIRT_HEIGHT;
pDDRefEntry = 0;
pDDDev = 0;
pDDBufDev = 0;
pDDTempDev = 0;
eTextMode = IcnShowTextShort;
pImpCursor = new IcnCursor_Impl( this );
pGridMap = new IcnGridMap_Impl( this );
aVerSBar.SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, ScrollUpDownHdl ) );
aHorSBar.SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl ) );
Link aEndScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, EndScrollHdl ) );
aVerSBar.SetEndScrollHdl( aEndScrollHdl );
aHorSBar.SetEndScrollHdl( aEndScrollHdl );
nHorSBarHeight = aHorSBar.GetSizePixel().Height();
nVerSBarWidth = aVerSBar.GetSizePixel().Width();
aEditTimer.SetTimeout( 800 );
aEditTimer.SetTimeoutHdl(LINK(this,SvxIconChoiceCtrl_Impl,EditTimeoutHdl));
aAutoArrangeTimer.SetTimeout( 100 );
aAutoArrangeTimer.SetTimeoutHdl(LINK(this,SvxIconChoiceCtrl_Impl,AutoArrangeHdl));
aCallSelectHdlTimer.SetTimeout( 500 );
aCallSelectHdlTimer.SetTimeoutHdl( LINK(this,SvxIconChoiceCtrl_Impl,CallSelectHdlHdl));
aDocRectChangedTimer.SetTimeout( 50 );
aDocRectChangedTimer.SetTimeoutHdl(LINK(this,SvxIconChoiceCtrl_Impl,DocRectChangedHdl));
aVisRectChangedTimer.SetTimeout( 50 );
aVisRectChangedTimer.SetTimeoutHdl(LINK(this,SvxIconChoiceCtrl_Impl,VisRectChangedHdl));
Clear( sal_True );
SetGrid( Size(100, 70) );
}
SvxIconChoiceCtrl_Impl::~SvxIconChoiceCtrl_Impl()
{
pCurEditedEntry = 0;
DELETEZ(pEdit);
Clear();
StopEditTimer();
CancelUserEvents();
delete pZOrderList;
delete pImpCursor;
delete pGridMap;
delete pDDDev;
delete pDDBufDev;
delete pDDTempDev;
delete pDraggedSelection;
delete pEntryPaintDev;
ClearSelectedRectList();
ClearColumnList();
}
void SvxIconChoiceCtrl_Impl::Clear( sal_Bool bInCtor )
{
StopEntryEditing( sal_True );
nSelectionCount = 0;
DELETEZ(pDraggedSelection);
bInDragDrop = sal_False;
pCurHighlightFrame = 0;
StopEditTimer();
CancelUserEvents();
ShowCursor( sal_False );
bBoundRectsDirty = sal_False;
nMaxBoundHeight = 0;
nFlags &= ~(F_PAINTED | F_MOVED_ENTRIES);
pCursor = 0;
if( !bInCtor )
{
pImpCursor->Clear();
pGridMap->Clear();
aVirtOutputSize.Width() = 0;
aVirtOutputSize.Height() = 0;
Size aSize( pView->GetOutputSizePixel() );
nMaxVirtWidth = aSize.Width() - nVerSBarWidth;
if( nMaxVirtWidth <= 0 )
nMaxVirtWidth = DEFAULT_MAX_VIRT_WIDTH;
nMaxVirtHeight = aSize.Height() - nHorSBarHeight;
if( nMaxVirtHeight <= 0 )
nMaxVirtHeight = DEFAULT_MAX_VIRT_HEIGHT;
pZOrderList->Clear(); //Remove(0,pZOrderList->Count());
SetOrigin( Point() );
if( bUpdateMode )
pView->Invalidate(INVALIDATE_NOCHILDREN);
}
AdjustScrollBars();
sal_uLong nCount = aEntries.Count();
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
delete pCur;
}
aEntries.Clear();
DocRectChanged();
VisRectChanged();
}
void SvxIconChoiceCtrl_Impl::SetStyle( WinBits nWinStyle )
{
nWinBits = nWinStyle;
nCurTextDrawFlags = DRAWTEXT_FLAGS_ICON;
if( nWinBits & (WB_SMALLICON | WB_DETAILS) )
nCurTextDrawFlags = DRAWTEXT_FLAGS_SMALLICON;
if( nWinBits & WB_NOSELECTION )
eSelectionMode = NO_SELECTION;
if( !(nWinStyle & (WB_ALIGN_TOP | WB_ALIGN_LEFT)))
nWinBits |= WB_ALIGN_LEFT;
if( (nWinStyle & WB_DETAILS))
{
if( !pColumns )
SetColumn( 0, SvxIconChoiceCtrlColumnInfo( 0, 100, IcnViewAlignLeft ));
}
}
IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollUpDownHdl, ScrollBar*, pScrollBar )
{
StopEntryEditing( sal_True );
// Pfeil hoch: delta=-1; Pfeil runter: delta=+1
Scroll( 0, pScrollBar->GetDelta(), sal_True );
bEndScrollInvalidate = sal_True;
return 0;
}
IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl, ScrollBar*, pScrollBar )
{
StopEntryEditing( sal_True );
// Pfeil links: delta=-1; Pfeil rechts: delta=+1
Scroll( pScrollBar->GetDelta(), 0, sal_True );
bEndScrollInvalidate = sal_True;
return 0;
}
IMPL_LINK( SvxIconChoiceCtrl_Impl, EndScrollHdl, void*, EMPTYARG )
{
if( pView->HasBackground() && !pView->GetBackground().IsScrollable() &&
bEndScrollInvalidate )
{
pView->Invalidate(INVALIDATE_NOCHILDREN);
}
return 0;
}
void SvxIconChoiceCtrl_Impl::FontModified()
{
StopEditTimer();
DELETEZ(pDDDev);
DELETEZ(pDDBufDev);
DELETEZ(pDDTempDev);
DELETEZ(pEntryPaintDev);
SetDefaultTextSize();
ShowCursor( sal_False );
ShowCursor( sal_True );
}
void SvxIconChoiceCtrl_Impl::InsertEntry( SvxIconChoiceCtrlEntry* pEntry, sal_uLong nPos,
const Point* pPos )
{
StopEditTimer();
aEntries.Insert( pEntry, nPos );
if( (nFlags & F_ENTRYLISTPOS_VALID) && nPos >= aEntries.Count() - 1 )
pEntry->nPos = aEntries.Count() - 1;
else
nFlags &= ~F_ENTRYLISTPOS_VALID;
pZOrderList->Insert( (void*)pEntry, LIST_APPEND ); //pZOrderList->Count() );
pImpCursor->Clear();
// pGridMap->Clear();
if( pPos )
{
Size aSize( CalcBoundingSize( pEntry ) );
SetBoundingRect_Impl( pEntry, *pPos, aSize );
SetEntryPos( pEntry, *pPos, sal_False, sal_True, sal_True /*keep grid map*/ );
pEntry->nFlags |= ICNVIEW_FLAG_POS_MOVED;
SetEntriesMoved( sal_True );
}
else
{
// wenn der UpdateMode sal_True ist, wollen wir nicht pauschal alle
// BoundRects auf 'zu ueberpruefen' setzen, sondern nur das des
// neuen Eintrags. Deshalb kein InvalidateBoundingRect aufrufen!
pEntry->aRect.Right() = LONG_MAX;
if( bUpdateMode )
{
FindBoundingRect( pEntry );
Rectangle aOutputArea( GetOutputRect() );
pGridMap->OccupyGrids( pEntry );
if( !aOutputArea.IsOver( pEntry->aRect ) )
return; // ist nicht sichtbar
pView->Invalidate( pEntry->aRect );
}
else
InvalidateBoundingRect( pEntry->aRect );
}
}
void SvxIconChoiceCtrl_Impl::CreateAutoMnemonics( MnemonicGenerator* _pGenerator )
{
::std::auto_ptr< MnemonicGenerator > pAutoDeleteOwnGenerator;
if ( !_pGenerator )
{
_pGenerator = new MnemonicGenerator;
pAutoDeleteOwnGenerator.reset( _pGenerator );
}
sal_uLong nEntryCount = GetEntryCount();
sal_uLong i;
// insert texts in generator
for( i = 0; i < nEntryCount; ++i )
{
DBG_ASSERT( GetEntry( i ), "-SvxIconChoiceCtrl_Impl::CreateAutoMnemonics(): more expected than provided!" );
_pGenerator->RegisterMnemonic( GetEntry( i )->GetText() );
}
// exchange texts with generated mnemonics
for( i = 0; i < nEntryCount; ++i )
{
SvxIconChoiceCtrlEntry* pEntry = GetEntry( i );
String aTxt = pEntry->GetText();
if( _pGenerator->CreateMnemonic( aTxt ) )
pEntry->SetText( aTxt );
}
}
Rectangle SvxIconChoiceCtrl_Impl::GetOutputRect() const
{
Point aOrigin( pView->GetMapMode().GetOrigin() );
aOrigin *= -1;
return Rectangle( aOrigin, aOutputSize );
}
void SvxIconChoiceCtrl_Impl::SetListPositions()
{
if( nFlags & F_ENTRYLISTPOS_VALID )
return;
sal_uLong nCount = aEntries.Count();
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
pEntry->nPos = nCur;
}
nFlags |= F_ENTRYLISTPOS_VALID;
}
void SvxIconChoiceCtrl_Impl::RemoveEntry( SvxIconChoiceCtrlEntry* pEntry )
{
sal_Bool bSyncSingleSelection;
// bei Single-Selection wird die Selektion beim Umsetzen des Cursors
// mitgefuehrt. Das soll aber nur erfolgen, wenn ueberhaupt ein
// Eintrag selektiert ist.
if( GetSelectionCount() )
bSyncSingleSelection = sal_True;
else
bSyncSingleSelection = sal_False;
if( pEntry == pCurHighlightFrame )
pCurHighlightFrame = 0;
if( bInDragDrop )
{
DELETEZ(pDraggedSelection);
bInDragDrop = sal_False;
}
if( pEntry->IsSelected() )
CallSelectHandler( 0 );
if( aEntries.Count() == 1 && aEntries.GetObject(0) == pEntry )
{
Clear();
return;
}
StopEditTimer();
if( pEntry == pAnchor )
pAnchor = 0;
if( pEntry->IsSelected() )
nSelectionCount--;
sal_Bool bEntryBoundValid = IsBoundingRectValid( pEntry->aRect );
if( bEntryBoundValid )
pView->Invalidate( pEntry->aRect );
sal_Bool bSetNewCursor = sal_False;
SvxIconChoiceCtrlEntry* pNewCursor = NULL;
if( pEntry == pCursor )
{
bSetNewCursor = sal_True;
pNewCursor = FindNewCursor();
ShowCursor( sal_False );
pCursor = 0;
}
sal_Bool bCurEntryPosValid = (nFlags & F_ENTRYLISTPOS_VALID) ? sal_True : sal_False;
if( bCurEntryPosValid && aEntries.GetObject(aEntries.Count()-1) != pEntry )
nFlags &= ~F_ENTRYLISTPOS_VALID;
sal_uLong nPos = pZOrderList->GetPos( (void*)pEntry );
pZOrderList->Remove( nPos );
if( bCurEntryPosValid )
{
DBG_ASSERT(aEntries.GetObject(pEntry->nPos)==pEntry,"RemoveEntry: Wrong nPos in entry");
aEntries.Remove( pEntry->nPos );
}
else
aEntries.Remove( pEntry );
pImpCursor->Clear();
pGridMap->Clear();
delete pEntry;
if( IsAutoArrange() && aEntries.Count() )
aAutoArrangeTimer.Start();
if( bSetNewCursor )
{
// Fokusrechteck asynchron einblenden, um das Loeschen einer
// Multiselektion zu beschleunigen.
SetCursor( pNewCursor, bSyncSingleSelection, sal_True );
}
}
void SvxIconChoiceCtrl_Impl::SelectEntry( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bSelect,
sal_Bool bCallHdl, sal_Bool bAdd, sal_Bool bSyncPaint )
{
if( eSelectionMode == NO_SELECTION )
return;
if( !bAdd )
{
if ( 0 == ( nFlags & F_CLEARING_SELECTION ) )
{
nFlags |= F_CLEARING_SELECTION;
DeselectAllBut( pEntry, sal_True );
nFlags &= ~F_CLEARING_SELECTION;
}
}
if( pEntry->IsSelected() != bSelect )
{
pHdlEntry = pEntry;
sal_uInt16 nEntryFlags = pEntry->GetFlags();
if( bSelect )
{
nEntryFlags |= ICNVIEW_FLAG_SELECTED;
pEntry->AssignFlags( nEntryFlags );
nSelectionCount++;
if( bCallHdl )
CallSelectHandler( pEntry );
}
else
{
nEntryFlags &= ~( ICNVIEW_FLAG_SELECTED);
pEntry->AssignFlags( nEntryFlags );
nSelectionCount--;
if( bCallHdl )
CallSelectHandler( 0 );
}
EntrySelected( pEntry, bSelect, bSyncPaint );
}
}
void SvxIconChoiceCtrl_Impl::EntrySelected( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bSelect,
sal_Bool bSyncPaint )
{
// bei SingleSelection dafuer sorgen, dass der Cursor immer
// auf dem (einzigen) selektierten Eintrag steht. Aber nur,
// wenn es bereits einen Cursor gibt
if( bSelect && pCursor &&
eSelectionMode == SINGLE_SELECTION &&
pEntry != pCursor )
{
SetCursor( pEntry );
//DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?")
}
// beim Aufziehen nicht, da sonst die Schleife in SelectRect
// nicht richtig funktioniert!
if( !(nFlags & F_SELECTING_RECT) )
ToTop( pEntry );
if( bUpdateMode )
{
if( pEntry == pCursor )
ShowCursor( sal_False );
if( pView->IsTracking() && (bSelect || !pView->HasBackground()) ) // beim Tracken immer synchron
PaintEntry( pEntry );
else if( bSyncPaint ) // synchron & mit virtuellem OutDev!
PaintEntryVirtOutDev( pEntry );
else
{
pView->Invalidate( CalcFocusRect( pEntry ) );
}
if( pEntry == pCursor )
ShowCursor( sal_True );
} // if( bUpdateMode )
// --> OD 2009-05-27 #i101012#
// emit vcl event LISTBOX_SELECT only in case that the given entry is selected.
if ( bSelect )
{
CallEventListeners( VCLEVENT_LISTBOX_SELECT, pEntry );
}
// <--
}
void SvxIconChoiceCtrl_Impl::ResetVirtSize()
{
StopEditTimer();
aVirtOutputSize.Width() = 0;
aVirtOutputSize.Height() = 0;
sal_Bool bLockedEntryFound = sal_False;
const sal_uLong nCount = aEntries.Count();
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
pCur->ClearFlags( ICNVIEW_FLAG_POS_MOVED );
if( pCur->IsPosLocked() )
{
// VirtSize u.a. anpassen
if( !IsBoundingRectValid( pCur->aRect ) )
FindBoundingRect( pCur );
else
AdjustVirtSize( pCur->aRect );
bLockedEntryFound = sal_True;
}
else
InvalidateBoundingRect( pCur->aRect );
}
if( !(nWinBits & (WB_NOVSCROLL | WB_NOHSCROLL)) )
{
Size aRealOutputSize( pView->GetOutputSizePixel() );
if( aVirtOutputSize.Width() < aRealOutputSize.Width() ||
aVirtOutputSize.Height() < aRealOutputSize.Height() )
{
sal_uLong nGridCount = IcnGridMap_Impl::GetGridCount(
aRealOutputSize, (sal_uInt16)nGridDX, (sal_uInt16)nGridDY );
if( nGridCount < nCount )
{
if( nWinBits & WB_ALIGN_TOP )
nMaxVirtWidth = aRealOutputSize.Width() - nVerSBarWidth;
else // WB_ALIGN_LEFT
nMaxVirtHeight = aRealOutputSize.Height() - nHorSBarHeight;
}
}
}
pImpCursor->Clear();
pGridMap->Clear();
VisRectChanged();
}
void SvxIconChoiceCtrl_Impl::AdjustVirtSize( const Rectangle& rRect )
{
long nHeightOffs = 0;
long nWidthOffs = 0;
if( aVirtOutputSize.Width() < (rRect.Right()+LROFFS_WINBORDER) )
nWidthOffs = (rRect.Right()+LROFFS_WINBORDER) - aVirtOutputSize.Width();
if( aVirtOutputSize.Height() < (rRect.Bottom()+TBOFFS_WINBORDER) )
nHeightOffs = (rRect.Bottom()+TBOFFS_WINBORDER) - aVirtOutputSize.Height();
if( nWidthOffs || nHeightOffs )
{
Range aRange;
aVirtOutputSize.Width() += nWidthOffs;
aRange.Max() = aVirtOutputSize.Width();
aHorSBar.SetRange( aRange );
aVirtOutputSize.Height() += nHeightOffs;
aRange.Max() = aVirtOutputSize.Height();
aVerSBar.SetRange( aRange );
pImpCursor->Clear();
pGridMap->OutputSizeChanged();
AdjustScrollBars();
DocRectChanged();
}
}
void SvxIconChoiceCtrl_Impl::InitPredecessors()
{
DBG_ASSERT(!pHead,"SvxIconChoiceCtrl_Impl::InitPredecessors() >> Already initialized");
sal_uLong nCount = aEntries.Count();
if( nCount )
{
SvxIconChoiceCtrlEntry* pPrev = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 );
for( sal_uLong nCur = 1; nCur <= nCount; nCur++ )
{
pPrev->ClearFlags( ICNVIEW_FLAG_POS_LOCKED | ICNVIEW_FLAG_POS_MOVED |
ICNVIEW_FLAG_PRED_SET);
SvxIconChoiceCtrlEntry* pNext;
if( nCur == nCount )
pNext = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 );
else
pNext = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
pPrev->pflink = pNext;
pNext->pblink = pPrev;
pPrev = pNext;
}
pHead = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 );
}
else
pHead = 0;
nFlags &= ~F_MOVED_ENTRIES;
}
void SvxIconChoiceCtrl_Impl::ClearPredecessors()
{
if( pHead )
{
sal_uLong nCount = aEntries.Count();
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
pCur->pflink = 0;
pCur->pblink = 0;
pCur->ClearFlags( ICNVIEW_FLAG_PRED_SET );
}
pHead = 0;
}
}
void SvxIconChoiceCtrl_Impl::Arrange( sal_Bool bKeepPredecessors, long nSetMaxVirtWidth, long nSetMaxVirtHeight )
{
if ( nSetMaxVirtWidth != 0 )
nMaxVirtWidth = nSetMaxVirtWidth;
else
nMaxVirtWidth = aOutputSize.Width();
if ( nSetMaxVirtHeight != 0 )
nMaxVirtHeight = nSetMaxVirtHeight;
else
nMaxVirtHeight = aOutputSize.Height();
ImpArrange( bKeepPredecessors );
}
void SvxIconChoiceCtrl_Impl::ImpArrange( sal_Bool bKeepPredecessors )
{
static Point aEmptyPoint;
sal_Bool bOldUpdate = bUpdateMode;
Rectangle aCurOutputArea( GetOutputRect() );
if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint )
bUpdateMode = sal_False;
aAutoArrangeTimer.Stop();
nFlags &= ~F_MOVED_ENTRIES;
nFlags |= F_ARRANGING;
StopEditTimer();
ShowCursor( sal_False );
ResetVirtSize();
if( !bKeepPredecessors )
ClearPredecessors();
bBoundRectsDirty = sal_False;
SetOrigin( Point() );
VisRectChanged();
RecalcAllBoundingRectsSmart();
// in der Detailsview muss das Invalidieren intelligenter erfolgen
//if( !(nWinBits & WB_DETAILS ))
pView->Invalidate( INVALIDATE_NOCHILDREN );
nFlags &= ~F_ARRANGING;
if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint )
{
MakeVisible( aCurOutputArea );
SetUpdateMode( bOldUpdate );
}
ShowCursor( sal_True );
}
void SvxIconChoiceCtrl_Impl::Paint( const Rectangle& rRect )
{
bEndScrollInvalidate = sal_False;
#if defined(OV_DRAWGRID)
Color aOldColor ( pView->GetLineColor() );
Color aColor( COL_BLACK );
pView->SetLineColor( aColor );
Point aOffs( pView->GetMapMode().GetOrigin());
Size aXSize( pView->GetOutputSizePixel() );
{
Point aStart( LROFFS_WINBORDER, 0 );
Point aEnd( LROFFS_WINBORDER, aXSize.Height());
aStart -= aOffs;
aEnd -= aOffs;
pView->DrawLine( aStart, aEnd );
}
{
Point aStart( 0, TBOFFS_WINBORDER );
Point aEnd( aXSize.Width(), TBOFFS_WINBORDER );
aStart -= aOffs;
aEnd -= aOffs;
pView->DrawLine( aStart, aEnd );
}
for( long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX )
{
Point aStart( nDX+LROFFS_WINBORDER, 0 );
Point aEnd( nDX+LROFFS_WINBORDER, aXSize.Height());
aStart -= aOffs;
aEnd -= aOffs;
pView->DrawLine( aStart, aEnd );
}
for( long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY )
{
Point aStart( 0, nDY+TBOFFS_WINBORDER );
Point aEnd( aXSize.Width(), nDY+TBOFFS_WINBORDER );
aStart -= aOffs;
aEnd -= aOffs;
pView->DrawLine( aStart, aEnd );
}
pView->SetLineColor( aOldColor );
#endif
nFlags |= F_PAINTED;
if( !aEntries.Count() )
return;
if( !pCursor )
{
// set cursor to item with focus-flag
sal_Bool bfound = sal_False;
for ( sal_uLong i = 0; i < pView->GetEntryCount() && !bfound; i++)
{
SvxIconChoiceCtrlEntry* pEntry = pView->GetEntry ( i );
if( pEntry->IsFocused() )
{
pCursor = pEntry;
bfound=sal_True;
}
}
if( !bfound )
pCursor = (SvxIconChoiceCtrlEntry*)aEntries.First();
}
// Show Focus at Init-Time
if ( pView->HasFocus() )
GetFocus();
sal_uLong nCount = pZOrderList->Count();
if( !nCount )
return;
sal_Bool bResetClipRegion = sal_False;
if( !pView->IsClipRegion() )
{
Rectangle aOutputArea( GetOutputRect() );
bResetClipRegion = sal_True;
pView->SetClipRegion( aOutputArea );
}
const sal_uInt16 nListInitSize = aEntries.Count() > USHRT_MAX ?
USHRT_MAX : (sal_uInt16)aEntries.Count();
List* pNewZOrderList = new List( nListInitSize );
List* pPaintedEntries = new List( nListInitSize );
sal_uLong nPos = 0;
while( nCount )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nPos ));
const Rectangle& rBoundRect = GetEntryBoundRect( pEntry );
if( rRect.IsOver( rBoundRect ) )
{
PaintEntry( pEntry, rBoundRect.TopLeft(), pView, sal_True );
// Eintraege, die neu gezeichnet werden, auf Top setzen
pPaintedEntries->Insert( pEntry, LIST_APPEND );
}
else
pNewZOrderList->Insert( pEntry, LIST_APPEND );
nCount--;
nPos++;
}
delete pZOrderList;
pZOrderList = pNewZOrderList;
nCount = pPaintedEntries->Count();
if( nCount )
{
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
pZOrderList->Insert( pPaintedEntries->GetObject(nCur), LIST_APPEND);
}
delete pPaintedEntries;
if( bResetClipRegion )
pView->SetClipRegion();
}
void SvxIconChoiceCtrl_Impl::RepaintEntries( sal_uInt16 nEntryFlagsMask )
{
const sal_uLong nCount = pZOrderList->Count();
if( !nCount )
return;
sal_Bool bResetClipRegion = sal_False;
Rectangle aOutRect( GetOutputRect() );
if( !pView->IsClipRegion() )
{
bResetClipRegion = sal_True;
pView->SetClipRegion( aOutRect );
}
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nCur));
if( pEntry->GetFlags() & nEntryFlagsMask )
{
const Rectangle& rBoundRect = GetEntryBoundRect( pEntry );
if( aOutRect.IsOver( rBoundRect ) )
PaintEntry( pEntry, rBoundRect.TopLeft() );
}
}
if( bResetClipRegion )
pView->SetClipRegion();
}
void SvxIconChoiceCtrl_Impl::InitScrollBarBox()
{
aScrBarBox.SetSizePixel( Size(nVerSBarWidth-1, nHorSBarHeight-1) );
Size aSize( pView->GetOutputSizePixel() );
aScrBarBox.SetPosPixel( Point(aSize.Width()-nVerSBarWidth+1, aSize.Height()-nHorSBarHeight+1));
}
IcnViewFieldType SvxIconChoiceCtrl_Impl::GetItem( SvxIconChoiceCtrlEntry* pEntry,
const Point& rAbsPos )
{
Rectangle aRect( CalcTextRect( pEntry ) );
if( aRect.IsInside( rAbsPos ) )
return IcnViewFieldTypeText;
aRect = CalcBmpRect( pEntry );
if( aRect.IsInside( rAbsPos ) )
return IcnViewFieldTypeImage;
return IcnViewFieldTypeDontknow;
}
sal_Bool SvxIconChoiceCtrl_Impl::MouseButtonDown( const MouseEvent& rMEvt)
{
sal_Bool bHandled = sal_True;
bHighlightFramePressed = sal_False;
StopEditTimer();
sal_Bool bGotFocus = (sal_Bool)(!pView->HasFocus() && !(nWinBits & WB_NOPOINTERFOCUS));
if( !(nWinBits & WB_NOPOINTERFOCUS) )
pView->GrabFocus();
Point aDocPos( rMEvt.GetPosPixel() );
if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height())
return sal_False;
ToDocPos( aDocPos );
SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, sal_True );
if( pEntry )
MakeEntryVisible( pEntry, sal_False );
if( rMEvt.IsShift() && eSelectionMode != SINGLE_SELECTION )
{
if( pEntry )
SetCursor_Impl( pCursor, pEntry, rMEvt.IsMod1(), rMEvt.IsShift(), sal_True);
return sal_True;
}
if( pAnchor && (rMEvt.IsShift() || rMEvt.IsMod1())) // Tastaturselektion?
{
DBG_ASSERT(eSelectionMode != SINGLE_SELECTION,"Invalid selection mode");
if( rMEvt.IsMod1() )
nFlags |= F_ADD_MODE;
if( rMEvt.IsShift() )
{
Rectangle aRect( GetEntryBoundRect( pAnchor ));
if( pEntry )
aRect.Union( GetEntryBoundRect( pEntry ) );
else
{
Rectangle aTempRect( aDocPos, Size(1,1));
aRect.Union( aTempRect );
}
aCurSelectionRect = aRect;
SelectRect( aRect, (nFlags & F_ADD_MODE)!=0, &aSelectedRectList );
}
else if( rMEvt.IsMod1() )
{
AddSelectedRect( aCurSelectionRect );
pAnchor = 0;
aCurSelectionRect.SetPos( aDocPos );
}
if( !pEntry && !(nWinBits & WB_NODRAGSELECTION))
pView->StartTracking( STARTTRACK_SCROLLREPEAT );
return sal_True;
}
else
{
if( !pEntry )
{
if( eSelectionMode == MULTIPLE_SELECTION )
{
if( !rMEvt.IsMod1() ) // Ctrl
{
if( !bGotFocus )
{
SetNoSelection();
ClearSelectedRectList();
}
}
else
nFlags |= F_ADD_MODE;
aCurSelectionRect.SetPos( aDocPos );
pView->StartTracking( STARTTRACK_SCROLLREPEAT );
}
else
bHandled = sal_False;
return bHandled;
}
}
sal_Bool bSelected = pEntry->IsSelected();
sal_Bool bEditingEnabled = IsEntryEditingEnabled();
if( rMEvt.GetClicks() == 2 )
{
DeselectAllBut( pEntry );
SelectEntry( pEntry, sal_True, sal_True, sal_False, sal_True );
pHdlEntry = pEntry;
pView->ClickIcon();
}
else
{
// Inplace-Editing ?
if( rMEvt.IsMod2() ) // Alt?
{
if( bEntryEditingEnabled && pEntry &&
pEntry->IsSelected())
{
if( pView->EditingEntry( pEntry ))
EditEntry( pEntry );
}
}
else if( eSelectionMode == SINGLE_SELECTION )
{
DeselectAllBut( pEntry );
SetCursor( pEntry );
if( bEditingEnabled && bSelected && !rMEvt.GetModifier() &&
rMEvt.IsLeft() && IsTextHit( pEntry, aDocPos ) )
{
nFlags |= F_START_EDITTIMER_IN_MOUSEUP;
}
}
else if( eSelectionMode == NO_SELECTION )
{
if( rMEvt.IsLeft() && (nWinBits & WB_HIGHLIGHTFRAME) )
{
pCurHighlightFrame = 0; // Neues painten des Frames erzwingen
bHighlightFramePressed = sal_True;
SetEntryHighlightFrame( pEntry, sal_True );
}
}
else
{
if( !rMEvt.GetModifier() && rMEvt.IsLeft() )
{
if( !bSelected )
{
DeselectAllBut( pEntry, sal_True /* Synchron painten */ );
SetCursor( pEntry );
SelectEntry( pEntry, sal_True, sal_True, sal_False, sal_True );
}
else
{
// erst im Up deselektieren, falls Move per D&D!
nFlags |= F_DOWN_DESELECT;
if( bEditingEnabled && IsTextHit( pEntry, aDocPos ) &&
rMEvt.IsLeft())
{
nFlags |= F_START_EDITTIMER_IN_MOUSEUP;
}
}
}
else if( rMEvt.IsMod1() )
nFlags |= F_DOWN_CTRL;
}
}
return bHandled;
}
sal_Bool SvxIconChoiceCtrl_Impl::MouseButtonUp( const MouseEvent& rMEvt )
{
sal_Bool bHandled = sal_False;
if( rMEvt.IsRight() && (nFlags & (F_DOWN_CTRL | F_DOWN_DESELECT) ))
{
nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
bHandled = sal_True;
}
Point aDocPos( rMEvt.GetPosPixel() );
ToDocPos( aDocPos );
SvxIconChoiceCtrlEntry* pDocEntry = GetEntry( aDocPos );
if( pDocEntry )
{
if( nFlags & F_DOWN_CTRL )
{
// Ctrl & MultiSelection
ToggleSelection( pDocEntry );
SetCursor( pDocEntry );
bHandled = sal_True;
}
else if( nFlags & F_DOWN_DESELECT )
{
DeselectAllBut( pDocEntry );
SetCursor( pDocEntry );
SelectEntry( pDocEntry, sal_True, sal_True, sal_False, sal_True );
bHandled = sal_True;
}
}
nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
if( nFlags & F_START_EDITTIMER_IN_MOUSEUP )
{
bHandled = sal_True;
StartEditTimer();
nFlags &= ~F_START_EDITTIMER_IN_MOUSEUP;
}
if((nWinBits & WB_HIGHLIGHTFRAME) && bHighlightFramePressed && pCurHighlightFrame)
{
bHandled = sal_True;
SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame;
pCurHighlightFrame = 0; // Neues painten des Frames erzwingen
bHighlightFramePressed = sal_False;
SetEntryHighlightFrame( pEntry, sal_True );
#if 0
CallSelectHandler( pCurHighlightFrame );
#else
pHdlEntry = pCurHighlightFrame;
pView->ClickIcon();
// set focus on Icon
SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
SetCursor_Impl( pOldCursor, pHdlEntry, sal_False, sal_False, sal_True );
#endif
pHdlEntry = 0;
}
return bHandled;
}
sal_Bool SvxIconChoiceCtrl_Impl::MouseMove( const MouseEvent& rMEvt )
{
const Point aDocPos( pView->PixelToLogic(rMEvt.GetPosPixel()) );
if( pView->IsTracking() )
return sal_False;
else if( nWinBits & WB_HIGHLIGHTFRAME )
{
SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, sal_True );
SetEntryHighlightFrame( pEntry );
}
else
return sal_False;
return sal_True;
}
void SvxIconChoiceCtrl_Impl::Tracking( const TrackingEvent& rTEvt )
{
if ( rTEvt.IsTrackingEnded() )
{
// Das Rechteck darf nicht "justified" sein, da seine
// TopLeft-Position u.U. zur Berechnung eines Ankers
// benutzt wird.
AddSelectedRect( aCurSelectionRect );
pView->HideTracking();
nFlags &= ~(F_ADD_MODE);
if( rTEvt.IsTrackingCanceled() )
SetNoSelection();
}
else
{
Point aPosPixel = rTEvt.GetMouseEvent().GetPosPixel();
Point aDocPos( aPosPixel );
ToDocPos( aDocPos );
long nScrollDX, nScrollDY;
CalcScrollOffsets( aPosPixel, nScrollDX, nScrollDY, sal_False );
if( nScrollDX || nScrollDY )
{
pView->HideTracking();
pView->Scroll( nScrollDX, nScrollDY );
}
Rectangle aRect( aCurSelectionRect.TopLeft(), aDocPos );
if( aRect != aCurSelectionRect )
{
pView->HideTracking();
sal_Bool bAdd = (nFlags & F_ADD_MODE) ? sal_True : sal_False;
SelectRect( aRect, bAdd, &aSelectedRectList );
}
pView->ShowTracking( aRect, SHOWTRACK_SMALL | SHOWTRACK_CLIP );
}
}
void SvxIconChoiceCtrl_Impl::SetCursor_Impl( SvxIconChoiceCtrlEntry* pOldCursor,
SvxIconChoiceCtrlEntry* pNewCursor, sal_Bool bMod1, sal_Bool bShift, sal_Bool bPaintSync )
{
if( pNewCursor )
{
SvxIconChoiceCtrlEntry* pFilterEntry = 0;
sal_Bool bDeselectAll = sal_False;
if( eSelectionMode != SINGLE_SELECTION )
{
if( !bMod1 && !bShift )
bDeselectAll = sal_True;
else if( bShift && !bMod1 && !pAnchor )
{
bDeselectAll = sal_True;
pFilterEntry = pOldCursor;
}
}
if( bDeselectAll )
DeselectAllBut( pFilterEntry, bPaintSync );
ShowCursor( sal_False );
MakeEntryVisible( pNewCursor );
SetCursor( pNewCursor );
if( bMod1 && !bShift )
{
if( pAnchor )
{
AddSelectedRect( pAnchor, pOldCursor );
pAnchor = 0;
}
}
else if( bShift )
{
if( !pAnchor )
pAnchor = pOldCursor;
if ( nWinBits & WB_ALIGN_LEFT )
SelectRange( pAnchor, pNewCursor, (nFlags & F_ADD_MODE)!=0 );
else
SelectRect(pAnchor,pNewCursor,(nFlags & F_ADD_MODE)!=0,&aSelectedRectList);
}
else
{
SelectEntry( pCursor, sal_True, sal_True, sal_False, bPaintSync );
aCurSelectionRect = GetEntryBoundRect( pCursor );
CallEventListeners( VCLEVENT_LISTBOX_SELECT, pCursor );
}
}
}
sal_Bool SvxIconChoiceCtrl_Impl::KeyInput( const KeyEvent& rKEvt )
{
StopEditTimer();
sal_Bool bMod2 = rKEvt.GetKeyCode().IsMod2();
sal_Unicode cChar = rKEvt.GetCharCode();
sal_uLong nPos = (sal_uLong)-1;
if ( bMod2 && cChar && IsMnemonicChar( cChar, nPos ) )
{
// shortcut is clicked
SvxIconChoiceCtrlEntry* pNewCursor = GetEntry( nPos );
SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
if ( pNewCursor != pOldCursor )
SetCursor_Impl( pOldCursor, pNewCursor, sal_False, sal_False, sal_False );
return sal_True;
}
if ( bMod2 )
// no actions with <ALT>
return sal_False;
sal_Bool bKeyUsed = sal_True;
sal_Bool bMod1 = rKEvt.GetKeyCode().IsMod1();
sal_Bool bShift = rKEvt.GetKeyCode().IsShift();
if( eSelectionMode == SINGLE_SELECTION || eSelectionMode == NO_SELECTION)
{
bShift = sal_False;
bMod1 = sal_False;
}
if( bMod1 )
nFlags |= F_ADD_MODE;
sal_Bool bDeselectAll = sal_False;
if( eSelectionMode != SINGLE_SELECTION )
{
if( !bMod1 && !bShift )
bDeselectAll = sal_True;
if( bShift && !bMod1 && !pAnchor )
bDeselectAll = sal_True;
}
SvxIconChoiceCtrlEntry* pNewCursor;
SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
switch( nCode )
{
case KEY_UP:
case KEY_PAGEUP:
if( pCursor )
{
MakeEntryVisible( pCursor );
if( nCode == KEY_UP )
pNewCursor = pImpCursor->GoUpDown(pCursor,sal_False);
else
pNewCursor = pImpCursor->GoPageUpDown(pCursor,sal_False);
SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True );
if( !pNewCursor )
{
Rectangle aRect( GetEntryBoundRect( pCursor ) );
if( aRect.Top())
{
aRect.Bottom() -= aRect.Top();
aRect.Top() = 0;
MakeVisible( aRect );
}
}
if ( bChooseWithCursor && pNewCursor != NULL )
{
pHdlEntry = pNewCursor;//GetCurEntry();
pCurHighlightFrame = pHdlEntry;
pView->ClickIcon();
pCurHighlightFrame = NULL;
}
}
break;
case KEY_DOWN:
case KEY_PAGEDOWN:
if( pCursor )
{
if( nCode == KEY_DOWN )
pNewCursor=pImpCursor->GoUpDown( pCursor,sal_True );
else
pNewCursor=pImpCursor->GoPageUpDown( pCursor,sal_True );
SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True );
if ( bChooseWithCursor && pNewCursor != NULL)
{
pHdlEntry = pNewCursor;//GetCurEntry();
pCurHighlightFrame = pHdlEntry;
pView->ClickIcon();
pCurHighlightFrame = NULL;
}
}
break;
case KEY_RIGHT:
if( pCursor )
{
pNewCursor=pImpCursor->GoLeftRight(pCursor,sal_True );
SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True );
}
break;
case KEY_LEFT:
if( pCursor )
{
MakeEntryVisible( pCursor );
pNewCursor = pImpCursor->GoLeftRight(pCursor,sal_False );
SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True );
if( !pNewCursor )
{
Rectangle aRect( GetEntryBoundRect(pCursor));
if( aRect.Left() )
{
aRect.Right() -= aRect.Left();
aRect.Left() = 0;
MakeVisible( aRect );
}
}
}
break;
// wird vom VCL-Tracking gesteuert
#if 0
case KEY_ESCAPE:
if( pView->IsTracking() )
{
HideSelectionRect();
//SelectAll( sal_False );
SetNoSelection();
ClearSelectedRectList();
nFlags &= ~F_TRACKING;
}
else
bKeyUsed = sal_False;
break;
#endif
case KEY_F2:
if( !bMod1 && !bShift )
EditTimeoutHdl( 0 );
else
bKeyUsed = sal_False;
break;
case KEY_F8:
if( rKEvt.GetKeyCode().IsShift() )
{
if( nFlags & F_ADD_MODE )
nFlags &= (~F_ADD_MODE);
else
nFlags |= F_ADD_MODE;
}
else
bKeyUsed = sal_False;
break;
case KEY_SPACE:
if( pCursor && eSelectionMode != SINGLE_SELECTION )
{
if( !bMod1 )
{
//SelectAll( sal_False );
SetNoSelection();
ClearSelectedRectList();
// click Icon with spacebar
SetEntryHighlightFrame( GetCurEntry(), sal_True );
pView->ClickIcon();
pHdlEntry = pCurHighlightFrame;
pCurHighlightFrame=0;
}
else
ToggleSelection( pCursor );
}
break;
#ifdef DBG_UTIL
case KEY_F10:
if( rKEvt.GetKeyCode().IsShift() )
{
if( pCursor )
pView->SetEntryTextMode( IcnShowTextFull, pCursor );
}
if( rKEvt.GetKeyCode().IsMod1() )
{
if( pCursor )
pView->SetEntryTextMode( IcnShowTextShort, pCursor );
}
break;
#endif
case KEY_ADD:
case KEY_DIVIDE :
case KEY_A:
if( bMod1 && (eSelectionMode != SINGLE_SELECTION))
SelectAll( sal_True );
else
bKeyUsed = sal_False;
break;
case KEY_SUBTRACT:
case KEY_COMMA :
if( bMod1 )
SetNoSelection();
else
bKeyUsed = sal_False;
break;
case KEY_RETURN:
if( bMod1 )
{
if( pCursor && bEntryEditingEnabled )
/*pView->*/EditEntry( pCursor );
}
else
bKeyUsed = sal_False;
break;
case KEY_END:
if( pCursor )
{
pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( aEntries.Count() - 1 );
SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True );
}
break;
case KEY_HOME:
if( pCursor )
{
pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 );
SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True );
}
break;
default:
bKeyUsed = sal_False;
}
return bKeyUsed;
}
// Berechnet TopLeft der Scrollbars (nicht ihre Groessen!)
void SvxIconChoiceCtrl_Impl::PositionScrollBars( long nRealWidth, long nRealHeight )
{
// hor scrollbar
Point aPos( 0, nRealHeight );
aPos.Y() -= nHorSBarHeight;
if( aHorSBar.GetPosPixel() != aPos )
aHorSBar.SetPosPixel( aPos );
// ver scrollbar
aPos.X() = nRealWidth; aPos.Y() = 0;
aPos.X() -= nVerSBarWidth;
aPos.X()++;
aPos.Y()--;
if( aVerSBar.GetPosPixel() != aPos )
aVerSBar.SetPosPixel( aPos );
}
void SvxIconChoiceCtrl_Impl::AdjustScrollBars( sal_Bool )
{
Rectangle aOldOutRect( GetOutputRect() );
long nVirtHeight = aVirtOutputSize.Height();
long nVirtWidth = aVirtOutputSize.Width();
Size aOSize( pView->Control::GetOutputSizePixel() );
long nRealHeight = aOSize.Height();
long nRealWidth = aOSize.Width();
PositionScrollBars( nRealWidth, nRealHeight );
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin() );
long nVisibleWidth;
if( nRealWidth > nVirtWidth )
nVisibleWidth = nVirtWidth + aOrigin.X();
else
nVisibleWidth = nRealWidth;
long nVisibleHeight;
if( nRealHeight > nVirtHeight )
nVisibleHeight = nVirtHeight + aOrigin.Y();
else
nVisibleHeight = nRealHeight;
sal_Bool bVerSBar = ( nWinBits & WB_VSCROLL ) != 0;
sal_Bool bHorSBar = ( nWinBits & WB_HSCROLL ) != 0;
sal_Bool bNoVerSBar = ( nWinBits & WB_NOVSCROLL ) != 0;
sal_Bool bNoHorSBar = ( nWinBits & WB_NOHSCROLL ) != 0;
sal_uInt16 nResult = 0;
if( nVirtHeight )
{
// activate ver scrollbar ?
if( !bNoVerSBar && (bVerSBar || ( nVirtHeight > nVisibleHeight)) )
{
nResult = 0x0001;
nRealWidth -= nVerSBarWidth;
if( nRealWidth > nVirtWidth )
nVisibleWidth = nVirtWidth + aOrigin.X();
else
nVisibleWidth = nRealWidth;
nFlags |= F_HOR_SBARSIZE_WITH_VBAR;
}
// activate hor scrollbar ?
if( !bNoHorSBar && (bHorSBar || (nVirtWidth > nVisibleWidth)) )
{
nResult |= 0x0002;
nRealHeight -= nHorSBarHeight;
if( nRealHeight > nVirtHeight )
nVisibleHeight = nVirtHeight + aOrigin.Y();
else
nVisibleHeight = nRealHeight;
// brauchen wir jetzt doch eine senkrechte Scrollbar ?
if( !(nResult & 0x0001) && // nur wenn nicht schon da
( !bNoVerSBar && ((nVirtHeight > nVisibleHeight) || bVerSBar)) )
{
nResult = 3; // beide sind an
nRealWidth -= nVerSBarWidth;
if( nRealWidth > nVirtWidth )
nVisibleWidth = nVirtWidth + aOrigin.X();
else
nVisibleWidth = nRealWidth;
nFlags |= F_VER_SBARSIZE_WITH_HBAR;
}
}
}
// size ver scrollbar
long nThumb = aVerSBar.GetThumbPos();
Size aSize( nVerSBarWidth, nRealHeight );
aSize.Height() += 2;
if( aSize != aVerSBar.GetSizePixel() )
aVerSBar.SetSizePixel( aSize );
aVerSBar.SetVisibleSize( nVisibleHeight );
aVerSBar.SetPageSize( GetScrollBarPageSize( nVisibleHeight ));
if( nResult & 0x0001 )
{
aVerSBar.SetThumbPos( nThumb );
aVerSBar.Show();
}
else
{
aVerSBar.SetThumbPos( 0 );
aVerSBar.Hide();
}
// size hor scrollbar
nThumb = aHorSBar.GetThumbPos();
aSize.Width() = nRealWidth;
aSize.Height() = nHorSBarHeight;
aSize.Width()++;
if( nResult & 0x0001 ) // vertikale Scrollbar ?
{
aSize.Width()++;
nRealWidth++;
}
if( aSize != aHorSBar.GetSizePixel() )
aHorSBar.SetSizePixel( aSize );
aHorSBar.SetVisibleSize( nVisibleWidth );
aHorSBar.SetPageSize( GetScrollBarPageSize(nVisibleWidth ));
if( nResult & 0x0002 )
{
aHorSBar.SetThumbPos( nThumb );
aHorSBar.Show();
}
else
{
aHorSBar.SetThumbPos( 0 );
aHorSBar.Hide();
}
aOutputSize.Width() = nRealWidth;
if( nResult & 0x0002 ) // hor scrollbar ?
nRealHeight++; // weil unterer Rand geclippt wird
aOutputSize.Height() = nRealHeight;
Rectangle aNewOutRect( GetOutputRect() );
if( aNewOutRect != aOldOutRect && pView->HasBackground() )
{
Wallpaper aPaper( pView->GetBackground() );
aPaper.SetRect( aNewOutRect );
pView->SetBackground( aPaper );
}
if( (nResult & (0x0001|0x0002)) == (0x0001|0x0002) )
aScrBarBox.Show();
else
aScrBarBox.Hide();
}
void SvxIconChoiceCtrl_Impl::Resize()
{
StopEditTimer();
InitScrollBarBox();
aOutputSize = pView->GetOutputSizePixel();
pImpCursor->Clear();
pGridMap->OutputSizeChanged();
const Size& rSize = pView->Control::GetOutputSizePixel();
PositionScrollBars( rSize.Width(), rSize.Height() );
// Die ScrollBars werden asynchron ein/ausgeblendet, damit abgeleitete
// Klassen im Resize ein Arrange durchfuehren koennen, ohne dass
// die ScrollBars aufblitzen
// Wenn schon ein Event unterwegs ist, dann braucht kein neues verschickt werden,
// zumindest, solange es nur einen EventTypen gibt
if ( ! nUserEventAdjustScrBars )
nUserEventAdjustScrBars =
Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl),
EVENTID_ADJUST_SCROLLBARS);
if( pView->HasBackground() && !pView->GetBackground().IsScrollable() )
{
Rectangle aRect( GetOutputRect());
Wallpaper aPaper( pView->GetBackground() );
aPaper.SetRect( aRect );
pView->SetBackground( aPaper );
}
VisRectChanged();
}
sal_Bool SvxIconChoiceCtrl_Impl::CheckHorScrollBar()
{
if( !pZOrderList || !aHorSBar.IsVisible() )
return sal_False;
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin() );
if(!( nWinBits & WB_HSCROLL) && !aOrigin.X() )
{
long nWidth = aOutputSize.Width();
const sal_uLong nCount = pZOrderList->Count();
long nMostRight = 0;
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pZOrderList->GetObject(nCur);
long nRight = GetEntryBoundRect(pEntry).Right();
if( nRight > nWidth )
return sal_False;
if( nRight > nMostRight )
nMostRight = nRight;
}
aHorSBar.Hide();
aOutputSize.Height() += nHorSBarHeight;
aVirtOutputSize.Width() = nMostRight;
aHorSBar.SetThumbPos( 0 );
Range aRange;
aRange.Max() = nMostRight - 1;
aHorSBar.SetRange( aRange );
if( aVerSBar.IsVisible() )
{
Size aSize( aVerSBar.GetSizePixel());
aSize.Height() += nHorSBarHeight;
aVerSBar.SetSizePixel( aSize );
}
return sal_True;
}
return sal_False;
}
sal_Bool SvxIconChoiceCtrl_Impl::CheckVerScrollBar()
{
if( !pZOrderList || !aVerSBar.IsVisible() )
return sal_False;
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin() );
if(!( nWinBits & WB_VSCROLL) && !aOrigin.Y() )
{
long nDeepest = 0;
long nHeight = aOutputSize.Height();
const sal_uLong nCount = pZOrderList->Count();
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pZOrderList->GetObject(nCur);
long nBottom = GetEntryBoundRect(pEntry).Bottom();
if( nBottom > nHeight )
return sal_False;
if( nBottom > nDeepest )
nDeepest = nBottom;
}
aVerSBar.Hide();
aOutputSize.Width() += nVerSBarWidth;
aVirtOutputSize.Height() = nDeepest;
aVerSBar.SetThumbPos( 0 );
Range aRange;
aRange.Max() = nDeepest - 1;
aVerSBar.SetRange( aRange );
if( aHorSBar.IsVisible() )
{
Size aSize( aHorSBar.GetSizePixel());
aSize.Width() += nVerSBarWidth;
aHorSBar.SetSizePixel( aSize );
}
return sal_True;
}
return sal_False;
}
// blendet Scrollbars aus, wenn sie nicht mehr benoetigt werden
void SvxIconChoiceCtrl_Impl::CheckScrollBars()
{
CheckVerScrollBar();
if( CheckHorScrollBar() )
CheckVerScrollBar();
if( aVerSBar.IsVisible() && aHorSBar.IsVisible() )
aScrBarBox.Show();
else
aScrBarBox.Hide();
}
void SvxIconChoiceCtrl_Impl::GetFocus()
{
RepaintEntries( ICNVIEW_FLAG_SELECTED );
if( pCursor )
{
pCursor->SetFlags( ICNVIEW_FLAG_FOCUSED );
ShowCursor( sal_True );
}
}
void SvxIconChoiceCtrl_Impl::LoseFocus()
{
StopEditTimer();
if( pCursor )
pCursor->ClearFlags( ICNVIEW_FLAG_FOCUSED );
ShowCursor( sal_False );
// HideFocus ();
// pView->Invalidate ( aFocus.aRect );
RepaintEntries( ICNVIEW_FLAG_SELECTED );
}
void SvxIconChoiceCtrl_Impl::SetUpdateMode( sal_Bool bUpdate )
{
if( bUpdate != bUpdateMode )
{
bUpdateMode = bUpdate;
if( bUpdate )
{
AdjustScrollBars();
pImpCursor->Clear();
pGridMap->Clear();
pView->Invalidate(INVALIDATE_NOCHILDREN);
}
}
}
void SvxIconChoiceCtrl_Impl::PaintEntry( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bIsBackgroundPainted )
{
Point aPos( GetEntryPos( pEntry ) );
PaintEntry( pEntry, aPos, 0, bIsBackgroundPainted );
}
// Prios der Emphasis: bDropTarget => bCursored => bSelected
void SvxIconChoiceCtrl_Impl::PaintEmphasis(
const Rectangle& rTextRect, const Rectangle& rImageRect,
sal_Bool bSelected, sal_Bool bDropTarget, sal_Bool bCursored, OutputDevice* pOut,
sal_Bool bIsBackgroundPainted )
{
static Color aTransparent( COL_TRANSPARENT );
if( !pOut )
pOut = pView;
#ifdef OV_CHECK_EMPH_RECTS
{
Color aXOld( pOut->GetFillColor() );
pOut->SetFillColor( Color( COL_GREEN ));
pOut->DrawRect( rTextRect );
pOut->DrawRect( rImageRect );
pOut->SetFillColor( aXOld );
}
#endif
const StyleSettings& rSettings = pOut->GetSettings().GetStyleSettings();
Color aOldFillColor( pOut->GetFillColor() );
sal_Bool bSolidTextRect = sal_False;
sal_Bool bSolidImageRect = sal_False;
if( bDropTarget && ( eSelectionMode != NO_SELECTION ) )
{
pOut->SetFillColor( rSettings.GetHighlightColor() );
bSolidTextRect = sal_True;
bSolidImageRect = sal_True;
}
else
{
if ( !bSelected || bCursored )
{
if( !pView->HasFontFillColor() )
pOut->SetFillColor( pOut->GetBackground().GetColor() );
else
{
const Color& rFillColor = pView->GetFont().GetFillColor();
pOut->SetFillColor( rFillColor );
if( rFillColor != aTransparent )
bSolidTextRect = sal_True;
}
}
}
// Textrechteck zeichnen
if( !bSolidTextRect )
{
if( !bIsBackgroundPainted )
pOut->Erase( rTextRect );
}
else
{
Color aOldLineColor;
if( bCursored )
{
aOldLineColor = pOut->GetLineColor();
pOut->SetLineColor( Color( COL_GRAY ) );
}
pOut->DrawRect( rTextRect );
if( bCursored )
pOut->SetLineColor( aOldLineColor );
}
// Bildrechteck zeichnen
if( !bSolidImageRect )
{
if( !bIsBackgroundPainted )
pOut->Erase( rImageRect );
}
// die Emphasis des Images muss von der abgeleiteten Klasse gezeichnet werden
// (in der virtuellen Funktion DrawEntryImage)
// else
// pOut->DrawRect( rImageRect );
pOut->SetFillColor( aOldFillColor );
}
void SvxIconChoiceCtrl_Impl::PaintItem( const Rectangle& rRect,
IcnViewFieldType eItem, SvxIconChoiceCtrlEntry* pEntry, sal_uInt16 nPaintFlags,
OutputDevice* pOut, const String* pStr, ::vcl::ControlLayoutData* _pLayoutData )
{
if( eItem == IcnViewFieldTypeText )
{
String aText;
if( !pStr )
aText = pView->GetEntryText( pEntry, sal_False );
else
aText = *pStr;
if ( _pLayoutData )
{
pOut->DrawText( rRect, aText, nCurTextDrawFlags,
&_pLayoutData->m_aUnicodeBoundRects, &_pLayoutData->m_aDisplayText );
}
else
{
Color aOldFontColor = pOut->GetTextColor();
if ( pView->AutoFontColor() )
{
Color aBkgColor( pOut->GetBackground().GetColor() );
Color aFontColor;
sal_uInt16 nColor = ( aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue() ) / 3;
if ( nColor > 127 )
aFontColor.SetColor ( COL_BLACK );
else
aFontColor.SetColor( COL_WHITE );
pOut->SetTextColor( aFontColor );
}
pOut->DrawText( rRect, aText, nCurTextDrawFlags );
if ( pView->AutoFontColor() )
pOut->SetTextColor( aOldFontColor );
if( pEntry->IsFocused() )
{
Rectangle aRect ( CalcFocusRect( (SvxIconChoiceCtrlEntry*)pEntry ) );
/*pView->*/ShowFocus( aRect );
DrawFocusRect( pOut );
}
}
}
else
{
Point aPos( rRect.TopLeft() );
if( nPaintFlags & PAINTFLAG_HOR_CENTERED )
aPos.X() += (rRect.GetWidth() - aImageSize.Width() ) / 2;
if( nPaintFlags & PAINTFLAG_VER_CENTERED )
aPos.Y() += (rRect.GetHeight() - aImageSize.Height() ) / 2;
pView->DrawEntryImage( pEntry, aPos, *pOut );
}
}
void SvxIconChoiceCtrl_Impl::PaintEntryVirtOutDev( SvxIconChoiceCtrlEntry* pEntry )
{
#ifdef OV_NO_VIRT_OUTDEV
PaintEntry( pEntry );
#else
if( !pEntryPaintDev )
{
pEntryPaintDev = new VirtualDevice( *pView );
pEntryPaintDev->SetFont( pView->GetFont() );
pEntryPaintDev->SetLineColor();
//pEntryPaintDev->SetBackground( pView->GetBackground() );
}
const Rectangle& rRect = GetEntryBoundRect( pEntry );
Rectangle aOutRect( GetOutputRect() );
if( !rRect.IsOver( aOutRect ) )
return;
Wallpaper aPaper( pView->GetBackground() );
Rectangle aRect( aPaper.GetRect() );
// Rechteck verschieben, so dass das Boundrect des Entries im
// VirtOut-Dev bei 0,0 liegt.
aRect.Move( -rRect.Left(), -rRect.Top() );
aPaper.SetRect( aRect );
pEntryPaintDev->SetBackground( aPaper );
pEntryPaintDev->SetFont( pView->GetFont() );
Rectangle aPix ( pEntryPaintDev->LogicToPixel(aRect) );
Size aSize( rRect.GetSize() );
pEntryPaintDev->SetOutputSizePixel( aSize );
pEntryPaintDev->DrawOutDev(
Point(), aSize, rRect.TopLeft(), aSize, *pView );
PaintEntry( pEntry, Point(), pEntryPaintDev );
pView->DrawOutDev(
rRect.TopLeft(),
aSize,
Point(),
aSize,
*pEntryPaintDev );
#endif
}
void SvxIconChoiceCtrl_Impl::PaintEntry( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos,
OutputDevice* pOut, sal_Bool bIsBackgroundPainted )
{
if( !pOut )
pOut = pView;
sal_Bool bSelected = sal_False;
if( eSelectionMode != NO_SELECTION )
bSelected = pEntry->IsSelected();
sal_Bool bCursored = pEntry->IsCursored();
sal_Bool bDropTarget = pEntry->IsDropTarget();
sal_Bool bNoEmphasis = pEntry->IsBlockingEmphasis();
Font aTempFont( pOut->GetFont() );
// AutoFontColor
/*
if ( pView->AutoFontColor() )
{
aTempFont.SetColor ( aFontColor );
}
*/
String aEntryText( pView->GetEntryText( pEntry, sal_False ) );
Rectangle aTextRect( CalcTextRect(pEntry,&rPos,sal_False,&aEntryText));
Rectangle aBmpRect( CalcBmpRect(pEntry, &rPos ) );
sal_Bool bShowSelection =
( ( ( bSelected && !bCursored )
|| bDropTarget
)
&& !bNoEmphasis
&& ( eSelectionMode != NO_SELECTION )
);
sal_Bool bActiveSelection = ( 0 != ( nWinBits & WB_NOHIDESELECTION ) ) || pView->HasFocus();
if ( bShowSelection )
{
const StyleSettings& rSettings = pOut->GetSettings().GetStyleSettings();
Font aNewFont( aTempFont );
// bei hart attributierter Font-Fuellcolor muessen wir diese
// hart auf die Highlight-Color setzen
if( pView->HasFontFillColor() )
{
if( (nWinBits & WB_NOHIDESELECTION) || pView->HasFocus() )
aNewFont.SetFillColor( rSettings.GetHighlightColor() );
else
aNewFont.SetFillColor( rSettings.GetDeactiveColor() );
}
Color aWinCol = rSettings.GetWindowTextColor();
if ( !bActiveSelection && rSettings.GetFaceColor().IsBright() == aWinCol.IsBright() )
aNewFont.SetColor( rSettings.GetWindowTextColor() );
else
aNewFont.SetColor( rSettings.GetHighlightTextColor() );
pOut->SetFont( aNewFont );
pOut->SetFillColor( pOut->GetBackground().GetColor() );
pOut->DrawRect( CalcFocusRect( pEntry ) );
pOut->SetFillColor( );
}
sal_Bool bResetClipRegion = sal_False;
if( !pView->IsClipRegion() && (aVerSBar.IsVisible() || aHorSBar.IsVisible()) )
{
Rectangle aOutputArea( GetOutputRect() );
if( aOutputArea.IsOver(aTextRect) || aOutputArea.IsOver(aBmpRect) )
{
pView->SetClipRegion( aOutputArea );
bResetClipRegion = sal_True;
}
}
#ifdef OV_DRAWBOUNDRECT
{
Color aXOldColor = pOut->GetLineColor();
pOut->SetLineColor( Color( COL_LIGHTRED ) );
Rectangle aXRect( pEntry->aRect );
aXRect.SetPos( rPos );
pOut->DrawRect( aXRect );
pOut->SetLineColor( aXOldColor );
}
#endif
sal_Bool bLargeIconMode = WB_ICON == ( nWinBits & (VIEWMODE_MASK) );
sal_uInt16 nBmpPaintFlags = PAINTFLAG_VER_CENTERED;
if ( bLargeIconMode )
nBmpPaintFlags |= PAINTFLAG_HOR_CENTERED;
sal_uInt16 nTextPaintFlags = bLargeIconMode ? PAINTFLAG_HOR_CENTERED : PAINTFLAG_VER_CENTERED;
if( !bNoEmphasis )
PaintEmphasis(aTextRect,aBmpRect,bSelected,bDropTarget,bCursored,pOut,bIsBackgroundPainted);
if ( bShowSelection )
pView->DrawSelectionBackground( CalcFocusRect( pEntry ),
bActiveSelection ? 1 : 2 /* highlight */, sal_False /* check */, sal_True /* border */, sal_False /* ext border only */ );
PaintItem( aBmpRect, IcnViewFieldTypeImage, pEntry, nBmpPaintFlags, pOut );
PaintItem( aTextRect, IcnViewFieldTypeText, pEntry,
nTextPaintFlags, pOut );
// Highlight-Frame zeichnen
if( pEntry == pCurHighlightFrame && !bNoEmphasis )
DrawHighlightFrame( pOut, CalcFocusRect( pEntry ), sal_False );
pOut->SetFont( aTempFont );
if( bResetClipRegion )
pView->SetClipRegion();
}
void SvxIconChoiceCtrl_Impl::SetEntryPos( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos,
sal_Bool bAdjustAtGrid, sal_Bool bCheckScrollBars, sal_Bool bKeepGridMap )
{
ShowCursor( sal_False );
Rectangle aBoundRect( GetEntryBoundRect( pEntry ));
pView->Invalidate( aBoundRect );
ToTop( pEntry );
if( !IsAutoArrange() )
{
sal_Bool bAdjustVirtSize = sal_False;
if( rPos != aBoundRect.TopLeft() )
{
Point aGridOffs(
pEntry->aGridRect.TopLeft() - pEntry->aRect.TopLeft() );
pImpCursor->Clear();
if( !bKeepGridMap )
pGridMap->Clear();
aBoundRect.SetPos( rPos );
pEntry->aRect = aBoundRect;
pEntry->aGridRect.SetPos( rPos + aGridOffs );
bAdjustVirtSize = sal_True;
}
if( bAdjustAtGrid )
{
if( bAdjustVirtSize )
{
// Durch das Ausrichten des (ggf. gerade neu positionierten) Eintrags,
// kann er wieder komplett
// in den sichtbaren Bereich rutschen, so dass u.U. doch keine Scrollbar
// eingeblendet werden muss. Um deshalb ein 'Aufblitzen' der
// Scrollbar(s) zu vermeiden, wird zum Aufplustern der virtuellen
// Ausgabegroesse bereits das ausgerichtete Boundrect des
// Eintrags genommen. Die virtuelle Groesse muss angepasst werden,
// da AdjustEntryAtGrid von ihr abhaengt.
const Rectangle& rBoundRect = GetEntryBoundRect( pEntry );
Rectangle aCenterRect( CalcBmpRect( pEntry, 0 ));
Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) );
Rectangle aNewBoundRect( aNewPos, pEntry->aRect.GetSize());
AdjustVirtSize( aNewBoundRect );
bAdjustVirtSize = sal_False;
}
AdjustEntryAtGrid( pEntry );
ToTop( pEntry );
}
if( bAdjustVirtSize )
AdjustVirtSize( pEntry->aRect );
if( bCheckScrollBars && bUpdateMode )
CheckScrollBars();
pView->Invalidate( pEntry->aRect );
pGridMap->OccupyGrids( pEntry );
}
else
{
SvxIconChoiceCtrlEntry* pPrev = FindEntryPredecessor( pEntry, rPos );
SetEntryPredecessor( pEntry, pPrev );
aAutoArrangeTimer.Start();
}
ShowCursor( sal_True );
}
void SvxIconChoiceCtrl_Impl::SetNoSelection()
{
// rekursive Aufrufe ueber SelectEntry abblocken
if( !(nFlags & F_CLEARING_SELECTION ))
{
nFlags |= F_CLEARING_SELECTION;
DeselectAllBut( 0, sal_True );
nFlags &= ~F_CLEARING_SELECTION;
}
}
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetEntry( const Point& rDocPos, sal_Bool bHit )
{
CheckBoundingRects();
// Z-Order-Liste vom Ende her absuchen
sal_uLong nCount = pZOrderList->Count();
while( nCount )
{
nCount--;
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nCount));
if( pEntry->aRect.IsInside( rDocPos ) )
{
if( bHit )
{
Rectangle aRect = CalcBmpRect( pEntry );
aRect.Top() -= 3;
aRect.Bottom() += 3;
aRect.Left() -= 3;
aRect.Right() += 3;
if( aRect.IsInside( rDocPos ) )
return pEntry;
aRect = CalcTextRect( pEntry );
if( aRect.IsInside( rDocPos ) )
return pEntry;
}
else
return pEntry;
}
}
return 0;
}
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetNextEntry( const Point& rDocPos, SvxIconChoiceCtrlEntry* pCurEntry )
{
CheckBoundingRects();
SvxIconChoiceCtrlEntry* pTarget = 0;
const sal_uLong nStartPos = pZOrderList->GetPos( (void*)pCurEntry );
if( nStartPos != LIST_ENTRY_NOTFOUND )
{
const sal_uLong nCount = pZOrderList->Count();
for( sal_uLong nCur = nStartPos+1; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nCur));
if( pEntry->aRect.IsInside( rDocPos ) )
{
pTarget = pEntry;
break;
}
}
}
return pTarget;
}
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetPrevEntry( const Point& rDocPos, SvxIconChoiceCtrlEntry* pCurEntry )
{
CheckBoundingRects();
SvxIconChoiceCtrlEntry* pTarget = 0;
sal_uLong nStartPos = pZOrderList->GetPos( (void*)pCurEntry );
if( nStartPos != LIST_ENTRY_NOTFOUND && nStartPos != 0 )
{
nStartPos--;
do
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nStartPos));
if( pEntry->aRect.IsInside( rDocPos ) )
{
pTarget = pEntry;
break;
}
} while( nStartPos > 0 );
}
return pTarget;
}
Point SvxIconChoiceCtrl_Impl::GetEntryPos( SvxIconChoiceCtrlEntry* pEntry )
{
return pEntry->aRect.TopLeft();
}
void SvxIconChoiceCtrl_Impl::MakeEntryVisible( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bBound )
{
if ( bBound )
{
const Rectangle& rRect = GetEntryBoundRect( pEntry );
MakeVisible( rRect );
}
else
{
Rectangle aRect = CalcBmpRect( pEntry );
aRect.Union( CalcTextRect( pEntry ) );
aRect.Top() += TBOFFS_BOUND;
aRect.Bottom() += TBOFFS_BOUND;
aRect.Left() += LROFFS_BOUND;
aRect.Right() += LROFFS_BOUND;
MakeVisible( aRect );
}
}
const Rectangle& SvxIconChoiceCtrl_Impl::GetEntryBoundRect( SvxIconChoiceCtrlEntry* pEntry )
{
if( !IsBoundingRectValid( pEntry->aRect ))
FindBoundingRect( pEntry );
return pEntry->aRect;
}
Rectangle SvxIconChoiceCtrl_Impl::CalcBmpRect( SvxIconChoiceCtrlEntry* pEntry, const Point* pPos )
{
Rectangle aBound = GetEntryBoundRect( pEntry );
if( pPos )
aBound.SetPos( *pPos );
Point aPos( aBound.TopLeft() );
switch( nWinBits & (VIEWMODE_MASK) )
{
case WB_ICON:
{
aPos.X() += ( aBound.GetWidth() - aImageSize.Width() ) / 2;
return Rectangle( aPos, aImageSize );
}
case WB_SMALLICON:
case WB_DETAILS:
aPos.Y() += ( aBound.GetHeight() - aImageSize.Height() ) / 2;
//todo: hor. Abstand zum BoundRect?
return Rectangle( aPos, aImageSize );
default:
DBG_ERROR("IconView: Viewmode not set");
return aBound;
}
}
Rectangle SvxIconChoiceCtrl_Impl::CalcTextRect( SvxIconChoiceCtrlEntry* pEntry,
const Point* pEntryPos, sal_Bool bEdit, const String* pStr )
{
String aEntryText;
if( !pStr )
aEntryText = pView->GetEntryText( pEntry, bEdit );
else
aEntryText = *pStr;
const Rectangle aMaxTextRect( CalcMaxTextRect( pEntry ) );
Rectangle aBound( GetEntryBoundRect( pEntry ) );
if( pEntryPos )
aBound.SetPos( *pEntryPos );
Rectangle aTextRect( aMaxTextRect );
if( !bEdit )
aTextRect = pView->GetTextRect( aTextRect, aEntryText, nCurTextDrawFlags );
Size aTextSize( aTextRect.GetSize() );
Point aPos( aBound.TopLeft() );
long nBoundWidth = aBound.GetWidth();
long nBoundHeight = aBound.GetHeight();
switch( nWinBits & (VIEWMODE_MASK) )
{
case WB_ICON:
aPos.Y() += aImageSize.Height();
aPos.Y() += VER_DIST_BMP_STRING;
// beim Editieren etwas mehr Platz
if( bEdit )
{
// 20% rauf
long nMinWidth = (( (aImageSize.Width()*10) / 100 ) * 2 ) +
aImageSize.Width();
if( nMinWidth > nBoundWidth )
nMinWidth = nBoundWidth;
if( aTextSize.Width() < nMinWidth )
aTextSize.Width() = nMinWidth;
// beim Editieren ist Ueberlappung nach unten erlaubt
Size aOptSize = aMaxTextRect.GetSize();
if( aOptSize.Height() > aTextSize.Height() )
aTextSize.Height() = aOptSize.Height();
}
aPos.X() += (nBoundWidth - aTextSize.Width()) / 2;
break;
case WB_SMALLICON:
case WB_DETAILS:
aPos.X() += aImageSize.Width();
aPos.X() += HOR_DIST_BMP_STRING;
aPos.Y() += (nBoundHeight - aTextSize.Height()) / 2;
break;
}
return Rectangle( aPos, aTextSize );
}
long SvxIconChoiceCtrl_Impl::CalcBoundingWidth( SvxIconChoiceCtrlEntry* pEntry ) const
{
long nStringWidth = GetItemSize( pEntry, IcnViewFieldTypeText ).Width();
// nStringWidth += 2*LROFFS_TEXT;
long nWidth = 0;
switch( nWinBits & (VIEWMODE_MASK) )
{
case WB_ICON:
nWidth = Max( nStringWidth, aImageSize.Width() );
break;
case WB_SMALLICON:
case WB_DETAILS:
nWidth = aImageSize.Width();
nWidth += HOR_DIST_BMP_STRING;
nWidth += nStringWidth;
break;
}
return nWidth;
}
long SvxIconChoiceCtrl_Impl::CalcBoundingHeight( SvxIconChoiceCtrlEntry* pEntry ) const
{
long nStringHeight = GetItemSize( pEntry, IcnViewFieldTypeText).Height();
long nHeight = 0;
switch( nWinBits & (VIEWMODE_MASK) )
{
case WB_ICON:
nHeight = aImageSize.Height();
nHeight += VER_DIST_BMP_STRING;
nHeight += nStringHeight;
break;
case WB_SMALLICON:
case WB_DETAILS:
nHeight = Max( aImageSize.Height(), nStringHeight );
break;
}
if( nHeight > nMaxBoundHeight )
{
((SvxIconChoiceCtrl_Impl*)this)->nMaxBoundHeight = nHeight;
((SvxIconChoiceCtrl_Impl*)this)->aHorSBar.SetLineSize( GetScrollBarLineSize() );
((SvxIconChoiceCtrl_Impl*)this)->aVerSBar.SetLineSize( GetScrollBarLineSize() );
}
return nHeight;
}
Size SvxIconChoiceCtrl_Impl::CalcBoundingSize( SvxIconChoiceCtrlEntry* pEntry ) const
{
return Size( CalcBoundingWidth( pEntry ),
CalcBoundingHeight( pEntry ) );
}
void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRects()
{
nMaxBoundHeight = 0;
pZOrderList->Clear();
sal_uLong nCount = aEntries.Count();
sal_uLong nCur;
SvxIconChoiceCtrlEntry* pEntry;
if( !IsAutoArrange() || !pHead )
{
for( nCur = 0; nCur < nCount; nCur++ )
{
pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
FindBoundingRect( pEntry );
pZOrderList->Insert( pEntry, LIST_APPEND );
}
}
else
{
nCur = 0;
pEntry = pHead;
while( nCur != nCount )
{
DBG_ASSERT(pEntry->pflink&&pEntry->pblink,"SvxIconChoiceCtrl_Impl::RecalcAllBoundingRect > Bad link(s)");
FindBoundingRect( pEntry );
pZOrderList->Insert( pEntry, pZOrderList->Count() );
pEntry = pEntry->pflink;
nCur++;
}
}
bBoundRectsDirty = sal_False;
AdjustScrollBars();
}
void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRectsSmart()
{
nMaxBoundHeight = 0;
pZOrderList->Clear();
sal_uLong nCur;
SvxIconChoiceCtrlEntry* pEntry;
const sal_uLong nCount = aEntries.Count();
if( !IsAutoArrange() || !pHead )
{
for( nCur = 0; nCur < nCount; nCur++ )
{
pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
if( IsBoundingRectValid( pEntry->aRect ))
{
Size aBoundSize( pEntry->aRect.GetSize() );
if( aBoundSize.Height() > nMaxBoundHeight )
nMaxBoundHeight = aBoundSize.Height();
}
else
FindBoundingRect( pEntry );
pZOrderList->Insert( pEntry, LIST_APPEND );
}
}
else
{
nCur = 0;
pEntry = pHead;
while( nCur != nCount )
{
DBG_ASSERT(pEntry->pflink&&pEntry->pblink,"SvxIconChoiceCtrl_Impl::RecalcAllBoundingRect > Bad link(s)");
if( IsBoundingRectValid( pEntry->aRect ))
{
Size aBoundSize( pEntry->aRect.GetSize() );
if( aBoundSize.Height() > nMaxBoundHeight )
nMaxBoundHeight = aBoundSize.Height();
}
else
FindBoundingRect( pEntry );
pZOrderList->Insert( pEntry, LIST_APPEND );
pEntry = pEntry->pflink;
nCur++;
}
}
AdjustScrollBars();
}
void SvxIconChoiceCtrl_Impl::UpdateBoundingRects()
{
const sal_uLong nCount = aEntries.Count();
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
GetEntryBoundRect( pEntry );
}
}
void SvxIconChoiceCtrl_Impl::FindBoundingRect( SvxIconChoiceCtrlEntry* pEntry )
{
DBG_ASSERT(!pEntry->IsPosLocked(),"Locked entry pos in FindBoundingRect");
if( pEntry->IsPosLocked() && IsBoundingRectValid( pEntry->aRect) )
{
AdjustVirtSize( pEntry->aRect );
return;
}
Size aSize( CalcBoundingSize( pEntry ) );
Point aPos(pGridMap->GetGridRect(pGridMap->GetUnoccupiedGrid(sal_True)).TopLeft());
SetBoundingRect_Impl( pEntry, aPos, aSize );
}
void SvxIconChoiceCtrl_Impl::SetBoundingRect_Impl( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos,
const Size& /*rBoundingSize*/ )
{
Rectangle aGridRect( rPos, Size(nGridDX, nGridDY) );
pEntry->aGridRect = aGridRect;
Center( pEntry );
AdjustVirtSize( pEntry->aRect );
pGridMap->OccupyGrids( pEntry );
}
void SvxIconChoiceCtrl_Impl::SetCursor( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bSyncSingleSelection,
sal_Bool bShowFocusAsync )
{
if( pEntry == pCursor )
{
if( pCursor && eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection &&
!pCursor->IsSelected() )
SelectEntry( pCursor, sal_True, sal_True );
return;
}
ShowCursor( sal_False );
SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
pCursor = pEntry;
if( pOldCursor )
{
pOldCursor->ClearFlags( ICNVIEW_FLAG_FOCUSED );
if( eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection )
SelectEntry( pOldCursor, sal_False, sal_True ); // alten Cursor deselektieren
}
if( pCursor )
{
ToTop( pCursor );
pCursor->SetFlags( ICNVIEW_FLAG_FOCUSED );
if( eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection )
SelectEntry( pCursor, sal_True, sal_True );
if( !bShowFocusAsync )
ShowCursor( sal_True );
else
{
if( !nUserEventShowCursor )
nUserEventShowCursor =
Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl),
EVENTID_SHOW_CURSOR );
}
}
}
void SvxIconChoiceCtrl_Impl::ShowCursor( sal_Bool bShow )
{
if( !pCursor || !bShow || !pView->HasFocus() )
{
pView->HideFocus();
return;
}
Rectangle aRect ( CalcFocusRect( pCursor ) );
/*pView->*/ShowFocus( aRect );
}
void SvxIconChoiceCtrl_Impl::HideDDIcon()
{
pView->Update();
ImpHideDDIcon();
pDDBufDev = pDDDev;
pDDDev = 0;
}
void SvxIconChoiceCtrl_Impl::ImpHideDDIcon()
{
if( pDDDev )
{
Size aSize( pDDDev->GetOutputSizePixel() );
// pView restaurieren
pView->DrawOutDev( aDDLastRectPos, aSize, Point(), aSize, *pDDDev );
}
}
void SvxIconChoiceCtrl_Impl::ShowDDIcon( SvxIconChoiceCtrlEntry* pRefEntry, const Point& rPosPix )
{
pView->Update();
if( pRefEntry != pDDRefEntry )
{
DELETEZ(pDDDev);
DELETEZ(pDDBufDev);
}
sal_Bool bSelected = pRefEntry->IsSelected();
pRefEntry->ClearFlags( ICNVIEW_FLAG_SELECTED );
if( !pDDDev )
{
if( pDDBufDev )
{
// nicht bei jedem Move ein Device anlegen, da dies besonders
// auf Remote-Clients zu langsam ist
pDDDev = pDDBufDev;
pDDBufDev = 0;
}
else
{
pDDDev = new VirtualDevice( *pView );
pDDDev->SetFont( pView->GetFont() );
}
}
else
{
ImpHideDDIcon();
}
const Rectangle& rRect = GetEntryBoundRect( pRefEntry );
pDDDev->SetOutputSizePixel( rRect.GetSize() );
Point aPos( rPosPix );
ToDocPos( aPos );
Size aSize( pDDDev->GetOutputSizePixel() );
pDDRefEntry = pRefEntry;
aDDLastEntryPos = aPos;
aDDLastRectPos = aPos;
// Hintergrund sichern
pDDDev->DrawOutDev( Point(), aSize, aPos, aSize, *pView );
// Icon in pView malen
pRefEntry->SetFlags( ICNVIEW_FLAG_BLOCK_EMPHASIS );
PaintEntry( pRefEntry, aPos );
pRefEntry->ClearFlags( ICNVIEW_FLAG_BLOCK_EMPHASIS );
if( bSelected )
pRefEntry->SetFlags( ICNVIEW_FLAG_SELECTED );
}
void SvxIconChoiceCtrl_Impl::HideShowDDIcon( SvxIconChoiceCtrlEntry* pRefEntry, const Point& rPosPix )
{
/* In Notfaellen folgenden flackernden Code aktivieren:
HideDDIcon();
ShowDDIcon( pRefEntry, rPosPix );
return;
*/
if( !pDDDev )
{
ShowDDIcon( pRefEntry, rPosPix );
return;
}
if( pRefEntry != pDDRefEntry )
{
HideDDIcon();
ShowDDIcon( pRefEntry, rPosPix );
return;
}
Point aEmptyPoint;
Point aCurEntryPos( rPosPix );
ToDocPos( aCurEntryPos );
const Rectangle& rRect = GetEntryBoundRect( pRefEntry );
Size aEntrySize( rRect.GetSize() );
Rectangle aPrevEntryRect( aDDLastEntryPos, aEntrySize );
Rectangle aCurEntryRect( aCurEntryPos, aEntrySize );
if( !aPrevEntryRect.IsOver( aCurEntryRect ) )
{
HideDDIcon();
ShowDDIcon( pRefEntry, rPosPix );
return;
}
// Ueberlappung des neuen und alten D&D-Pointers!
Rectangle aFullRect( aPrevEntryRect.Union( aCurEntryRect ) );
if( !pDDTempDev )
{
pDDTempDev = new VirtualDevice( *pView );
pDDTempDev->SetFont( pView->GetFont() );
}
Size aFullSize( aFullRect.GetSize() );
Point aFullPos( aFullRect.TopLeft() );
pDDTempDev->SetOutputSizePixel( aFullSize );
// Hintergrund (mit dem alten D&D-Pointer!) sichern
pDDTempDev->DrawOutDev( aEmptyPoint, aFullSize, aFullPos, aFullSize, *pView );
// den alten Buffer in den neuen Buffer pasten
aDDLastRectPos = aDDLastRectPos - aFullPos;
pDDTempDev->DrawOutDev(
aDDLastRectPos,
pDDDev->GetOutputSizePixel(),
aEmptyPoint,
pDDDev->GetOutputSizePixel(),
*pDDDev );
// Swap
VirtualDevice* pTemp = pDDDev;
pDDDev = pDDTempDev;
pDDTempDev = pTemp;
// in den restaurierten Hintergrund den neuen D&D-Pointer zeichnen
pDDTempDev->SetOutputSizePixel( pDDDev->GetOutputSizePixel() );
pDDTempDev->DrawOutDev(
aEmptyPoint, aFullSize, aEmptyPoint, aFullSize, *pDDDev );
Point aRelPos = aCurEntryPos - aFullPos;
pRefEntry->SetFlags( ICNVIEW_FLAG_BLOCK_EMPHASIS );
PaintEntry( pRefEntry, aRelPos, pDDTempDev );
pRefEntry->ClearFlags( ICNVIEW_FLAG_BLOCK_EMPHASIS );
aDDLastRectPos = aFullPos;
aDDLastEntryPos = aCurEntryPos;
pView->DrawOutDev(
aDDLastRectPos,
pDDDev->GetOutputSizePixel(),
aEmptyPoint,
pDDDev->GetOutputSizePixel(),
*pDDTempDev );
}
void SvxIconChoiceCtrl_Impl::InvalidateBoundingRect( SvxIconChoiceCtrlEntry* pEntry )
{
InvalidateBoundingRect( pEntry->aRect );
}
sal_Bool SvxIconChoiceCtrl_Impl::HandleScrollCommand( const CommandEvent& rCmd )
{
Rectangle aDocRect( GetDocumentRect() );
Rectangle aVisRect( GetVisibleRect() );
if( aVisRect.IsInside( aDocRect ))
return sal_False;
Size aDocSize( aDocRect.GetSize() );
Size aVisSize( aVisRect.GetSize() );
sal_Bool bHor = aDocSize.Width() > aVisSize.Width();
sal_Bool bVer = aDocSize.Height() > aVisSize.Height();
long nScrollDX = 0, nScrollDY = 0;
switch( rCmd.GetCommand() )
{
case COMMAND_STARTAUTOSCROLL:
{
pView->EndTracking();
sal_uInt16 nScrollFlags = 0;
if( bHor )
nScrollFlags |= AUTOSCROLL_HORZ;
if( bVer )
nScrollFlags |= AUTOSCROLL_VERT;
if( nScrollFlags )
{
pView->StartAutoScroll( nScrollFlags );
return sal_True;
}
}
break;
case COMMAND_WHEEL:
{
const CommandWheelData* pData = rCmd.GetWheelData();
if( pData && (COMMAND_WHEEL_SCROLL == pData->GetMode()) && !pData->IsHorz() )
{
sal_uLong nScrollLines = pData->GetScrollLines();
if( nScrollLines == COMMAND_WHEEL_PAGESCROLL )
{
nScrollDY = GetScrollBarPageSize( aVisSize.Width() );
if( pData->GetDelta() < 0 )
nScrollDY *= -1;
}
else
{
nScrollDY = pData->GetNotchDelta() * (long)nScrollLines;
nScrollDY *= GetScrollBarLineSize();
}
}
}
break;
case COMMAND_AUTOSCROLL:
{
const CommandScrollData* pData = rCmd.GetAutoScrollData();
if( pData )
{
nScrollDX = pData->GetDeltaX() * GetScrollBarLineSize();
nScrollDY = pData->GetDeltaY() * GetScrollBarLineSize();
}
}
break;
}
if( nScrollDX || nScrollDY )
{
aVisRect.Top() -= nScrollDY;
aVisRect.Bottom() -= nScrollDY;
aVisRect.Left() -= nScrollDX;
aVisRect.Right() -= nScrollDX;
MakeVisible( aVisRect );
return sal_True;
}
return sal_False;
}
void SvxIconChoiceCtrl_Impl::Command( const CommandEvent& rCEvt )
{
// Rollmaus-Event?
if( (rCEvt.GetCommand() == COMMAND_WHEEL) ||
(rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) ||
(rCEvt.GetCommand() == COMMAND_AUTOSCROLL) )
{
#if 1
if( HandleScrollCommand( rCEvt ) )
return;
#else
ScrollBar* pHor = aHorSBar.IsVisible() ? &aHorSBar : 0;
ScrollBar* pVer = aVerSBar.IsVisible() ? &aVerSBar : 0;
if( pView->HandleScrollCommand( rCEvt, pHor, pVer ) )
return;
#endif
}
}
void SvxIconChoiceCtrl_Impl::ToTop( SvxIconChoiceCtrlEntry* pEntry )
{
if( pZOrderList->GetObject( pZOrderList->Count() - 1 ) != pEntry )
{
sal_uLong nPos = pZOrderList->GetPos( (void*)pEntry );
pZOrderList->Remove( nPos );
pZOrderList->Insert( pEntry, LIST_APPEND );
}
}
void SvxIconChoiceCtrl_Impl::ClipAtVirtOutRect( Rectangle& rRect ) const
{
if( rRect.Bottom() >= aVirtOutputSize.Height() )
rRect.Bottom() = aVirtOutputSize.Height() - 1;
if( rRect.Right() >= aVirtOutputSize.Width() )
rRect.Right() = aVirtOutputSize.Width() - 1;
if( rRect.Top() < 0 )
rRect.Top() = 0;
if( rRect.Left() < 0 )
rRect.Left() = 0;
}
// rRect: Bereich des Dokumentes (in Dokumentkoordinaten), der
// sichtbar gemacht werden soll.
// bScrBar == sal_True: Das Rect wurde aufgrund eines ScrollBar-Events berechnet
void SvxIconChoiceCtrl_Impl::MakeVisible( const Rectangle& rRect, sal_Bool bScrBar,
sal_Bool bCallRectChangedHdl )
{
Rectangle aVirtRect( rRect );
ClipAtVirtOutRect( aVirtRect );
Point aOrigin( pView->GetMapMode().GetOrigin() );
// in Dokumentkoordinate umwandeln
aOrigin *= -1;
Rectangle aOutputArea( GetOutputRect() );
if( aOutputArea.IsInside( aVirtRect ) )
return; // ist schon sichtbar
long nDy;
if( aVirtRect.Top() < aOutputArea.Top() )
{
// nach oben scrollen (nDy < 0)
nDy = aVirtRect.Top() - aOutputArea.Top();
}
else if( aVirtRect.Bottom() > aOutputArea.Bottom() )
{
// nach unten scrollen (nDy > 0)
nDy = aVirtRect.Bottom() - aOutputArea.Bottom();
}
else
nDy = 0;
long nDx;
if( aVirtRect.Left() < aOutputArea.Left() )
{
// nach links scrollen (nDx < 0)
nDx = aVirtRect.Left() - aOutputArea.Left();
}
else if( aVirtRect.Right() > aOutputArea.Right() )
{
// nach rechts scrollen (nDx > 0)
nDx = aVirtRect.Right() - aOutputArea.Right();
}
else
nDx = 0;
aOrigin.X() += nDx;
aOrigin.Y() += nDy;
aOutputArea.SetPos( aOrigin );
if( GetUpdateMode() )
{
HideDDIcon();
pView->Update();
ShowCursor( sal_False );
}
// Origin fuer SV invertieren (damit wir in
// Dokumentkoordinaten scrollen/painten koennen)
aOrigin *= -1;
SetOrigin( aOrigin );
sal_Bool bScrollable = pView->GetBackground().IsScrollable();
if( pView->HasBackground() && !bScrollable )
{
Rectangle aRect( GetOutputRect());
Wallpaper aPaper( pView->GetBackground() );
aPaper.SetRect( aRect );
pView->SetBackground( aPaper );
}
if( bScrollable && GetUpdateMode() )
{
// in umgekehrte Richtung scrollen!
pView->Control::Scroll( -nDx, -nDy, aOutputArea,
SCROLL_NOCHILDREN | SCROLL_USECLIPREGION | SCROLL_CLIP );
}
else
pView->Invalidate(INVALIDATE_NOCHILDREN);
if( aHorSBar.IsVisible() || aVerSBar.IsVisible() )
{
if( !bScrBar )
{
aOrigin *= -1;
// Thumbs korrigieren
if(aHorSBar.IsVisible() && aHorSBar.GetThumbPos() != aOrigin.X())
aHorSBar.SetThumbPos( aOrigin.X() );
if(aVerSBar.IsVisible() && aVerSBar.GetThumbPos() != aOrigin.Y())
aVerSBar.SetThumbPos( aOrigin.Y() );
}
}
if( GetUpdateMode() )
ShowCursor( sal_True );
// pruefen, ob ScrollBars noch benoetigt werden
CheckScrollBars();
if( bScrollable && GetUpdateMode() )
pView->Update();
// kann der angeforderte Bereich nicht komplett sichtbar gemacht werden,
// wird auf jeden Fall der Vis-Rect-Changed-Handler gerufen. Eintreten kann der
// Fall z.B. wenn nur wenige Pixel des unteren Randes nicht sichtbar sind,
// eine ScrollBar aber eine groessere Line-Size eingestellt hat.
if( bCallRectChangedHdl || GetOutputRect() != rRect )
VisRectChanged();
}
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::FindNewCursor()
{
SvxIconChoiceCtrlEntry* pNewCursor;
if( pCursor )
{
pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_False );
if( !pNewCursor )
{
pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_True );
if( !pNewCursor )
{
pNewCursor = pImpCursor->GoUpDown( pCursor, sal_False );
if( !pNewCursor )
pNewCursor = pImpCursor->GoUpDown( pCursor, sal_True );
}
}
}
else
pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.First();
DBG_ASSERT(!pNewCursor|| (pCursor&&pCursor!=pNewCursor),"FindNewCursor failed");
return pNewCursor;
}
sal_uLong SvxIconChoiceCtrl_Impl::GetSelectionCount() const
{
if( (nWinBits & WB_HIGHLIGHTFRAME) && pCurHighlightFrame )
return 1;
return nSelectionCount;
}
void SvxIconChoiceCtrl_Impl::ToggleSelection( SvxIconChoiceCtrlEntry* pEntry )
{
sal_Bool bSel;
if( pEntry->IsSelected() )
bSel = sal_False;
else
bSel = sal_True;
SelectEntry( pEntry, bSel, sal_True, sal_True );
}
void SvxIconChoiceCtrl_Impl::DeselectAllBut( SvxIconChoiceCtrlEntry* pThisEntryNot,
sal_Bool bPaintSync )
{
ClearSelectedRectList();
//
// !!!!!!! Todo: Evtl. Z-Orderlist abarbeiten !!!!!!!
//
sal_uLong nCount = aEntries.Count();
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
if( pEntry != pThisEntryNot && pEntry->IsSelected() )
SelectEntry( pEntry, sal_False, sal_True, sal_True, bPaintSync );
}
pAnchor = 0;
nFlags &= (~F_ADD_MODE);
}
Size SvxIconChoiceCtrl_Impl::GetMinGrid() const
{
Size aMinSize( aImageSize );
aMinSize.Width() += 2 * LROFFS_BOUND;
aMinSize.Height() += TBOFFS_BOUND; // PB: einmal Offset reicht (FileDlg)
String aStrDummy( RTL_CONSTASCII_USTRINGPARAM( "XXX" ) );
Size aTextSize( pView->GetTextWidth( aStrDummy ), pView->GetTextHeight() );
if( nWinBits & WB_ICON )
{
aMinSize.Height() += VER_DIST_BMP_STRING;
aMinSize.Height() += aTextSize.Height();
}
else
{
aMinSize.Width() += HOR_DIST_BMP_STRING;
aMinSize.Width() += aTextSize.Width();
}
return aMinSize;
}
void SvxIconChoiceCtrl_Impl::SetGrid( const Size& rSize )
{
Size aSize( rSize );
Size aMinSize( GetMinGrid() );
if( aSize.Width() < aMinSize.Width() )
aSize.Width() = aMinSize.Width();
if( aSize.Height() < aMinSize.Height() )
aSize.Height() = aMinSize.Height();
nGridDX = aSize.Width();
// HACK(Detail-Modus ist noch nicht vollstaendig implementiert!)
// dieses Workaround bringts mit einer Spalte zum Fliegen
if( nWinBits & WB_DETAILS )
{
const SvxIconChoiceCtrlColumnInfo* pCol = GetColumn( 0 );
if( pCol )
((SvxIconChoiceCtrlColumnInfo*)pCol)->SetWidth( nGridDX );
}
nGridDY = aSize.Height();
SetDefaultTextSize();
}
// berechnet die maximale Groesse, die das Textrechteck innerhalb des
// umschliessenden Rechtecks einnehmen kann. Im Modus WB_ICON und
// IcnShowTextFull wird Bottom auf LONG_MAX gesetzt
Rectangle SvxIconChoiceCtrl_Impl::CalcMaxTextRect( const SvxIconChoiceCtrlEntry* pEntry ) const
{
Rectangle aBoundRect;
// keine Endlosrekursion! deshalb das Bound-Rect hier nicht berechnen
if( IsBoundingRectValid( pEntry->aRect ) )
aBoundRect = pEntry->aRect;
else
aBoundRect = pEntry->aGridRect;
Rectangle aBmpRect( ((SvxIconChoiceCtrl_Impl*)this)->CalcBmpRect(
(SvxIconChoiceCtrlEntry*)pEntry ) );
if( nWinBits & WB_ICON )
{
aBoundRect.Top() = aBmpRect.Bottom();
aBoundRect.Top() += VER_DIST_BMP_STRING;
if( aBoundRect.Top() > aBoundRect.Bottom())
aBoundRect.Top() = aBoundRect.Bottom();
aBoundRect.Left() += LROFFS_BOUND;
aBoundRect.Left()++;
aBoundRect.Right() -= LROFFS_BOUND;
aBoundRect.Right()--;
if( aBoundRect.Left() > aBoundRect.Right())
aBoundRect.Left() = aBoundRect.Right();
if( GetEntryTextModeSmart( pEntry ) == IcnShowTextFull )
aBoundRect.Bottom() = LONG_MAX;
}
else
{
aBoundRect.Left() = aBmpRect.Right();
aBoundRect.Left() += HOR_DIST_BMP_STRING;
aBoundRect.Right() -= LROFFS_BOUND;
if( aBoundRect.Left() > aBoundRect.Right() )
aBoundRect.Left() = aBoundRect.Right();
long nHeight = aBoundRect.GetSize().Height();
nHeight = nHeight - aDefaultTextSize.Height();
nHeight /= 2;
aBoundRect.Top() += nHeight;
aBoundRect.Bottom() -= nHeight;
}
return aBoundRect;
}
void SvxIconChoiceCtrl_Impl::SetDefaultTextSize()
{
long nDY = nGridDY;
nDY -= aImageSize.Height();
nDY -= VER_DIST_BMP_STRING;
nDY -= 2*TBOFFS_BOUND;
if( nDY <= 0 )
nDY = 2;
long nDX = nGridDX;
nDX -= 2*LROFFS_BOUND;
nDX -= 2;
if( nDX <= 0 )
nDX = 2;
String aStrDummy( RTL_CONSTASCII_USTRINGPARAM( "X" ) );
long nHeight = pView->GetTextHeight();
if( nDY < nHeight )
nDY = nHeight;
aDefaultTextSize = Size( nDX, nDY );
}
void SvxIconChoiceCtrl_Impl::Center( SvxIconChoiceCtrlEntry* pEntry ) const
{
pEntry->aRect = pEntry->aGridRect;
Size aSize( CalcBoundingSize( pEntry ) );
if( nWinBits & WB_ICON )
{
// horizontal zentrieren
long nBorder = pEntry->aGridRect.GetWidth() - aSize.Width();
pEntry->aRect.Left() += nBorder / 2;
pEntry->aRect.Right() -= nBorder / 2;
}
// vertikal zentrieren
pEntry->aRect.Bottom() = pEntry->aRect.Top() + aSize.Height();
}
// Die Deltas entsprechen Offsets, um die die View auf dem Doc verschoben wird
// links, hoch: Offsets < 0
// rechts, runter: Offsets > 0
void SvxIconChoiceCtrl_Impl::Scroll( long nDeltaX, long nDeltaY, sal_Bool bScrollBar )
{
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin() );
// in Dokumentkoordinate umwandeln
aOrigin *= -1;
aOrigin.Y() += nDeltaY;
aOrigin.X() += nDeltaX;
Rectangle aRect( aOrigin, aOutputSize );
MakeVisible( aRect, bScrollBar );
}
const Size& SvxIconChoiceCtrl_Impl::GetItemSize( SvxIconChoiceCtrlEntry*,
IcnViewFieldType eItem ) const
{
if( eItem == IcnViewFieldTypeText )
return aDefaultTextSize;
return aImageSize;
}
Rectangle SvxIconChoiceCtrl_Impl::CalcFocusRect( SvxIconChoiceCtrlEntry* pEntry )
{
Rectangle aBmpRect( CalcBmpRect( pEntry ) );
Rectangle aTextRect( CalcTextRect( pEntry ) );
Rectangle aBoundRect( GetEntryBoundRect( pEntry ) );
Rectangle aFocusRect( aBoundRect.Left(), aBmpRect.Top() - 1,
aBoundRect.Right() - 4, aTextRect.Bottom() + 1 );
// Das Fokusrechteck soll nicht den Text beruehren
if( aFocusRect.Left() - 1 >= pEntry->aRect.Left() )
aFocusRect.Left()--;
if( aFocusRect.Right() + 1 <= pEntry->aRect.Right() )
aFocusRect.Right()++;
return aFocusRect;
}
// Der 'Hot Spot' sind die inneren 50% der Rechteckflaeche
static Rectangle GetHotSpot( const Rectangle& rRect )
{
Rectangle aResult( rRect );
aResult.Justify();
Size aSize( rRect.GetSize() );
long nDelta = aSize.Width() / 4;
aResult.Left() += nDelta;
aResult.Right() -= nDelta;
nDelta = aSize.Height() / 4;
aResult.Top() += nDelta;
aResult.Bottom() -= nDelta;
return aResult;
}
void SvxIconChoiceCtrl_Impl::SelectRect( SvxIconChoiceCtrlEntry* pEntry1, SvxIconChoiceCtrlEntry* pEntry2,
sal_Bool bAdd, SvPtrarr* pOtherRects )
{
DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr");
Rectangle aRect( GetEntryBoundRect( pEntry1 ) );
aRect.Union( GetEntryBoundRect( pEntry2 ) );
SelectRect( aRect, bAdd, pOtherRects );
}
void SvxIconChoiceCtrl_Impl::SelectRect( const Rectangle& rRect, sal_Bool bAdd,
SvPtrarr* pOtherRects )
{
aCurSelectionRect = rRect;
if( !pZOrderList || !pZOrderList->Count() )
return;
// Flag setzen, damit im Select kein ToTop gerufen wird
sal_Bool bAlreadySelectingRect = nFlags & F_SELECTING_RECT ? sal_True : sal_False;
nFlags |= F_SELECTING_RECT;
CheckBoundingRects();
pView->Update();
const sal_uLong nCount = pZOrderList->Count();
Rectangle aRect( rRect );
aRect.Justify();
sal_Bool bCalcOverlap = (bAdd && pOtherRects && pOtherRects->Count()) ? sal_True : sal_False;
sal_Bool bResetClipRegion = sal_False;
if( !pView->IsClipRegion() )
{
bResetClipRegion = sal_True;
pView->SetClipRegion( GetOutputRect() );
}
for( sal_uLong nPos = 0; nPos < nCount; nPos++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nPos ));
if( !IsBoundingRectValid( pEntry->aRect ))
FindBoundingRect( pEntry );
Rectangle aBoundRect( GetHotSpot( pEntry->aRect ) );
sal_Bool bSelected = pEntry->IsSelected();
sal_Bool bOverlaps;
if( bCalcOverlap )
bOverlaps = IsOver( pOtherRects, aBoundRect );
else
bOverlaps = sal_False;
sal_Bool bOver = aRect.IsOver( aBoundRect );
if( bOver && !bOverlaps )
{
// Ist im neuen Selektionsrechteck und in keinem alten
// => selektieren
if( !bSelected )
SelectEntry( pEntry, sal_True, sal_True, sal_True );
}
else if( !bAdd )
{
// ist ausserhalb des Selektionsrechtecks
// => Selektion entfernen
if( bSelected )
SelectEntry( pEntry, sal_False, sal_True, sal_True );
}
else if( bAdd && bOverlaps )
{
// Der Eintrag befindet sich in einem alten (=>Aufspannen
// mehrerer Rechtecke mit Ctrl!) Selektionsrechteck
// Hier ist noch ein Bug! Der Selektionsstatus eines Eintrags
// in einem vorherigen Rechteck, muss restauriert werden, wenn
// er vom aktuellen Selektionsrechteck beruehrt wurde, jetzt aber
// nicht mehr in ihm liegt. Ich gehe hier der Einfachheit halber
// pauschal davon aus, dass die Eintraege in den alten Rechtecken
// alle selektiert sind. Ebenso ist es falsch, die Schnittmenge
// nur zu deselektieren.
// Loesungsmoeglichkeit: Snapshot der Selektion vor dem Auf-
// spannen des Rechtecks merken
if( aBoundRect.IsOver( rRect))
{
// Schnittmenge zwischen alten Rects & aktuellem Rect desel.
if( bSelected )
SelectEntry( pEntry, sal_False, sal_True, sal_True );
}
else
{
// Eintrag eines alten Rects selektieren
if( !bSelected )
SelectEntry( pEntry, sal_True, sal_True, sal_True );
}
}
else if( !bOver && bSelected )
{
// Der Eintrag liegt voellig ausserhalb und wird deshalb desel.
SelectEntry( pEntry, sal_False, sal_True, sal_True );
}
}
if( !bAlreadySelectingRect )
nFlags &= ~F_SELECTING_RECT;
pView->Update();
if( bResetClipRegion )
pView->SetClipRegion();
}
void SvxIconChoiceCtrl_Impl::SelectRange(
SvxIconChoiceCtrlEntry* pStart,
SvxIconChoiceCtrlEntry* pEnd,
sal_Bool bAdd )
{
sal_uLong nFront = GetEntryListPos( pStart );
sal_uLong nBack = GetEntryListPos( pEnd );
sal_uLong nFirst = std::min( nFront, nBack );
sal_uLong nLast = std::max( nFront, nBack );
sal_uLong i;
SvxIconChoiceCtrlEntry* pEntry;
if ( ! bAdd )
{
// deselect everything before the first entry if not in
// adding mode
for ( i=0; i<nFirst; i++ )
{
pEntry = GetEntry( i );
if( pEntry->IsSelected() )
SelectEntry( pEntry, sal_False, sal_True, sal_True, sal_True );
}
}
// select everything between nFirst and nLast
for ( i=nFirst; i<=nLast; i++ )
{
pEntry = GetEntry( i );
if( ! pEntry->IsSelected() )
SelectEntry( pEntry, sal_True, sal_True, sal_True, sal_True );
}
if ( ! bAdd )
{
// deselect everything behind the last entry if not in
// adding mode
sal_uLong nEnd = GetEntryCount();
for ( ; i<nEnd; i++ )
{
pEntry = GetEntry( i );
if( pEntry->IsSelected() )
SelectEntry( pEntry, sal_False, sal_True, sal_True, sal_True );
}
}
}
sal_Bool SvxIconChoiceCtrl_Impl::IsOver( SvPtrarr* pRectList, const Rectangle& rBoundRect ) const
{
const sal_uInt16 nCount = pRectList->Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
Rectangle* pRect = (Rectangle*)pRectList->GetObject( nCur );
if( rBoundRect.IsOver( *pRect ))
return sal_True;
}
return sal_False;
}
void SvxIconChoiceCtrl_Impl::AddSelectedRect( SvxIconChoiceCtrlEntry* pEntry1,
SvxIconChoiceCtrlEntry* pEntry2 )
{
DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr");
Rectangle aRect( GetEntryBoundRect( pEntry1 ) );
aRect.Union( GetEntryBoundRect( pEntry2 ) );
AddSelectedRect( aRect );
}
void SvxIconChoiceCtrl_Impl::AddSelectedRect( const Rectangle& rRect )
{
Rectangle* pRect = new Rectangle( rRect );
pRect->Justify();
aSelectedRectList.Insert( (void*)pRect, aSelectedRectList.Count() );
}
void SvxIconChoiceCtrl_Impl::ClearSelectedRectList()
{
const sal_uInt16 nCount = aSelectedRectList.Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
Rectangle* pRect = (Rectangle*)aSelectedRectList.GetObject( nCur );
delete pRect;
}
aSelectedRectList.Remove( 0, aSelectedRectList.Count() );
}
void SvxIconChoiceCtrl_Impl::CalcScrollOffsets( const Point& rPosPixel,
long& rX, long& rY, sal_Bool isInDragDrop, sal_uInt16 nBorderWidth)
{
// Scrolling der View, falls sich der Mauszeiger im Grenzbereich des
// Fensters befindet
long nPixelToScrollX = 0;
long nPixelToScrollY = 0;
Size aWndSize = aOutputSize;
nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Height()-1), (long)nBorderWidth ));
nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Width()-1), (long)nBorderWidth ));
if ( rPosPixel.X() < nBorderWidth )
{
if( isInDragDrop )
nPixelToScrollX = -DD_SCROLL_PIXEL;
else
nPixelToScrollX = rPosPixel.X()- nBorderWidth;
}
else if ( rPosPixel.X() > aWndSize.Width() - nBorderWidth )
{
if( isInDragDrop )
nPixelToScrollX = DD_SCROLL_PIXEL;
else
nPixelToScrollX = rPosPixel.X() - (aWndSize.Width() - nBorderWidth);
}
if ( rPosPixel.Y() < nBorderWidth )
{
if( isInDragDrop )
nPixelToScrollY = -DD_SCROLL_PIXEL;
else
nPixelToScrollY = rPosPixel.Y() - nBorderWidth;
}
else if ( rPosPixel.Y() > aWndSize.Height() - nBorderWidth )
{
if( isInDragDrop )
nPixelToScrollY = DD_SCROLL_PIXEL;
else
nPixelToScrollY = rPosPixel.Y() - (aWndSize.Height() - nBorderWidth);
}
rX = nPixelToScrollX;
rY = nPixelToScrollY;
}
IMPL_LINK(SvxIconChoiceCtrl_Impl, AutoArrangeHdl, void*, EMPTYARG )
{
aAutoArrangeTimer.Stop();
Arrange( IsAutoArrange() );
return 0;
}
IMPL_LINK(SvxIconChoiceCtrl_Impl, VisRectChangedHdl, void*, EMPTYARG )
{
aVisRectChangedTimer.Stop();
pView->VisibleRectChanged();
return 0;
}
IMPL_LINK(SvxIconChoiceCtrl_Impl, DocRectChangedHdl, void*, EMPTYARG )
{
aDocRectChangedTimer.Stop();
pView->DocumentRectChanged();
return 0;
}
void SvxIconChoiceCtrl_Impl::PrepareCommandEvent( const CommandEvent& rCEvt )
{
StopEditTimer();
SvxIconChoiceCtrlEntry* pEntry = pView->GetEntry( rCEvt.GetMousePosPixel() );
if( (nFlags & F_DOWN_CTRL) && pEntry && !pEntry->IsSelected() )
SelectEntry( pEntry, sal_True, sal_True );
nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
}
sal_Bool SvxIconChoiceCtrl_Impl::IsTextHit( SvxIconChoiceCtrlEntry* pEntry, const Point& rDocPos )
{
Rectangle aRect( CalcTextRect( pEntry ));
if( aRect.IsInside( rDocPos ) )
return sal_True;
return sal_False;
}
IMPL_LINK(SvxIconChoiceCtrl_Impl, EditTimeoutHdl, Timer*, EMPTYARG )
{
SvxIconChoiceCtrlEntry* pEntry = GetCurEntry();
if( bEntryEditingEnabled && pEntry &&
pEntry->IsSelected())
{
if( pView->EditingEntry( pEntry ))
EditEntry( pEntry );
}
return 0;
}
//
// Funktionen zum Ausrichten der Eintraege am Grid
//
// pStart == 0: Alle Eintraege werden ausgerichtet
// sonst: Alle Eintraege der Zeile ab einschliesslich pStart werden ausgerichtet
void SvxIconChoiceCtrl_Impl::AdjustEntryAtGrid( SvxIconChoiceCtrlEntry* pStart )
{
SvPtrarr aLists;
pImpCursor->CreateGridAjustData( aLists, pStart );
const sal_uInt16 nCount = aLists.Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
AdjustAtGrid( *(SvPtrarr*)aLists[ nCur ], pStart );
IcnCursor_Impl::DestroyGridAdjustData( aLists );
CheckScrollBars();
}
// Richtet eine Zeile aus, erweitert ggf. die Breite; Bricht die Zeile nicht um
void SvxIconChoiceCtrl_Impl::AdjustAtGrid( const SvPtrarr& rRow, SvxIconChoiceCtrlEntry* pStart )
{
if( !rRow.Count() )
return;
sal_Bool bGo;
if( !pStart )
bGo = sal_True;
else
bGo = sal_False;
long nCurRight = 0;
for( sal_uInt16 nCur = 0; nCur < rRow.Count(); nCur++ )
{
SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)rRow[ nCur ];
if( !bGo && pCur == pStart )
bGo = sal_True;
//SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur);
// Massgebend (fuer unser Auge) ist die Bitmap, da sonst
// durch lange Texte der Eintrag stark springen kann
const Rectangle& rBoundRect = GetEntryBoundRect( pCur );
Rectangle aCenterRect( CalcBmpRect( pCur, 0 ));
if( bGo && !pCur->IsPosLocked() )
{
long nWidth = aCenterRect.GetSize().Width();
Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) );
while( aNewPos.X() < nCurRight )
aNewPos.X() += nGridDX;
if( aNewPos != rBoundRect.TopLeft() )
{
SetEntryPos( pCur, aNewPos );
pCur->SetFlags( ICNVIEW_FLAG_POS_MOVED );
nFlags |= F_MOVED_ENTRIES;
}
nCurRight = aNewPos.X() + nWidth;
}
else
{
nCurRight = rBoundRect.Right();
}
}
}
// Richtet Rect am Grid aus, garantiert jedoch nicht, dass die
// neue Pos. frei ist. Die Pos. kann fuer SetEntryPos verwendet werden.
// Das CenterRect beschreibt den Teil des BoundRects, der fuer
// die Berechnung des Ziel-Rechtecks verwendet wird.
Point SvxIconChoiceCtrl_Impl::AdjustAtGrid( const Rectangle& rCenterRect,
const Rectangle& rBoundRect ) const
{
Point aPos( rCenterRect.TopLeft() );
Size aSize( rCenterRect.GetSize() );
aPos.X() -= LROFFS_WINBORDER;
aPos.Y() -= TBOFFS_WINBORDER;
// align (ref ist mitte des rects)
short nGridX = (short)((aPos.X()+(aSize.Width()/2)) / nGridDX);
short nGridY = (short)((aPos.Y()+(aSize.Height()/2)) / nGridDY);
aPos.X() = nGridX * nGridDX;
aPos.Y() = nGridY * nGridDY;
// hor. center
aPos.X() += (nGridDX - rBoundRect.GetSize().Width() ) / 2;
aPos.X() += LROFFS_WINBORDER;
aPos.Y() += TBOFFS_WINBORDER;
return aPos;
}
void SvxIconChoiceCtrl_Impl::SetEntryTextMode( SvxIconChoiceCtrlTextMode eMode, SvxIconChoiceCtrlEntry* pEntry )
{
if( !pEntry )
{
if( eTextMode != eMode )
{
if( eTextMode == IcnShowTextDontKnow )
eTextMode = IcnShowTextShort;
eTextMode = eMode;
Arrange( sal_True );
}
}
else
{
if( pEntry->eTextMode != eMode )
{
pEntry->eTextMode = eMode;
InvalidateEntry( pEntry );
pView->Invalidate( GetEntryBoundRect( pEntry ) );
AdjustVirtSize( pEntry->aRect );
}
}
}
SvxIconChoiceCtrlTextMode SvxIconChoiceCtrl_Impl::GetTextMode( const SvxIconChoiceCtrlEntry* pEntry ) const
{
if( !pEntry )
return eTextMode;
return pEntry->GetTextMode();
}
SvxIconChoiceCtrlTextMode SvxIconChoiceCtrl_Impl::GetEntryTextModeSmart( const SvxIconChoiceCtrlEntry* pEntry ) const
{
DBG_ASSERT(pEntry,"GetEntryTextModeSmart: Entry not set");
SvxIconChoiceCtrlTextMode eMode = pEntry->GetTextMode();
if( eMode == IcnShowTextDontKnow )
return eTextMode;
return eMode;
}
void SvxIconChoiceCtrl_Impl::ShowEntryFocusRect( const SvxIconChoiceCtrlEntry* pEntry )
{
if( !pEntry )
{
pView->HideFocus();
}
else
{
Rectangle aRect ( CalcFocusRect( (SvxIconChoiceCtrlEntry*)pEntry ) );
/*pView->*/ShowFocus( aRect );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Draw my own focusrect, because the focusrect of the outputdevice has got the inverted color
// of the background. But what will we see, if the the backgroundcolor is gray ? - We will see
// a gray focusrect on a gray background !!!
//
void SvxIconChoiceCtrl_Impl::ShowFocus ( Rectangle& rRect )
{
Color aBkgColor ( pView->GetBackground().GetColor() );
Color aPenColor;
sal_uInt16 nColor = ( aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue() ) / 3;
if ( nColor > 128 )
aPenColor.SetColor ( COL_BLACK );
else
aPenColor.SetColor( COL_WHITE );
aFocus.bOn = sal_True;
aFocus.aPenColor = aPenColor;
aFocus.aRect = rRect;
}
void SvxIconChoiceCtrl_Impl::HideFocus ()
{
aFocus.bOn = sal_False;
}
void SvxIconChoiceCtrl_Impl::DrawFocusRect ( OutputDevice* pOut )
{
pOut->SetLineColor( aFocus.aPenColor );
pOut->SetFillColor();
Polygon aPolygon ( aFocus.aRect );
LineInfo aLineInfo ( LINE_DASH );
aLineInfo.SetDashLen ( 1 );
aLineInfo.SetDotLen ( 1L );
aLineInfo.SetDistance ( 1L );
aLineInfo.SetDotCount ( 1 );
pOut->DrawPolyLine ( aPolygon, aLineInfo );
}
sal_Bool SvxIconChoiceCtrl_Impl::IsMnemonicChar( sal_Unicode cChar, sal_uLong& rPos ) const
{
sal_Bool bRet = sal_False;
const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
sal_uLong nEntryCount = GetEntryCount();
for ( sal_uLong i = 0; i < nEntryCount; ++i )
{
if ( rI18nHelper.MatchMnemonic( GetEntry( i )->GetText(), cChar ) )
{
bRet = sal_True;
rPos = i;
break;
}
}
return bRet;
}
//
////////////////////////////////////////////////////////////////////////////////////////////////
IMPL_LINK(SvxIconChoiceCtrl_Impl, UserEventHdl, void*, nId )
{
if( nId == EVENTID_ADJUST_SCROLLBARS )
{
nUserEventAdjustScrBars = 0;
AdjustScrollBars();
}
else if( nId == EVENTID_SHOW_CURSOR )
{
nUserEventShowCursor = 0;
ShowCursor( sal_True );
}
return 0;
}
void SvxIconChoiceCtrl_Impl::CancelUserEvents()
{
if( nUserEventAdjustScrBars )
{
Application::RemoveUserEvent( nUserEventAdjustScrBars );
nUserEventAdjustScrBars = 0;
}
if( nUserEventShowCursor )
{
Application::RemoveUserEvent( nUserEventShowCursor );
nUserEventShowCursor = 0;
}
}
void SvxIconChoiceCtrl_Impl::InvalidateEntry( SvxIconChoiceCtrlEntry* pEntry )
{
if( pEntry == pCursor )
ShowCursor( sal_False );
pView->Invalidate( pEntry->aRect );
Center( pEntry );
pView->Invalidate( pEntry->aRect );
if( pEntry == pCursor )
ShowCursor( sal_True );
}
void SvxIconChoiceCtrl_Impl::EditEntry( SvxIconChoiceCtrlEntry* pEntry )
{
DBG_ASSERT(pEntry,"EditEntry: Entry not set");
if( !pEntry )
return;
StopEntryEditing( sal_True );
DELETEZ(pEdit);
SetNoSelection();
pCurEditedEntry = pEntry;
String aEntryText( pView->GetEntryText( pEntry, sal_True ) );
Rectangle aRect( CalcTextRect( pEntry, 0, sal_True, &aEntryText ) );
MakeVisible( aRect );
Point aPos( aRect.TopLeft() );
aPos = pView->GetPixelPos( aPos );
aRect.SetPos( aPos );
pView->HideFocus();
pEdit = new IcnViewEdit_Impl(
pView,
aRect.TopLeft(),
aRect.GetSize(),
aEntryText,
LINK( this, SvxIconChoiceCtrl_Impl, TextEditEndedHdl ) );
}
IMPL_LINK( SvxIconChoiceCtrl_Impl, TextEditEndedHdl, IcnViewEdit_Impl*, EMPTYARG )
{
DBG_ASSERT(pEdit,"TextEditEnded: pEdit not set");
if( !pEdit )
{
pCurEditedEntry = 0;
return 0;
}
DBG_ASSERT(pCurEditedEntry,"TextEditEnded: pCurEditedEntry not set");
if( !pCurEditedEntry )
{
pEdit->Hide();
if( pEdit->IsGrabFocus() )
pView->GrabFocus();
return 0;
}
String aText;
if ( !pEdit->EditingCanceled() )
aText = pEdit->GetText();
else
aText = pEdit->GetSavedValue();
if( pView->EditedEntry( pCurEditedEntry, aText, pEdit->EditingCanceled() ) )
InvalidateEntry( pCurEditedEntry );
if( !GetSelectionCount() )
SelectEntry( pCurEditedEntry, sal_True );
pEdit->Hide();
if( pEdit->IsGrabFocus() )
pView->GrabFocus();
// Das Edit kann nicht hier geloescht werden, weil es noch in einem
// Handler steht. Es wird im Dtor oder im naechsten EditEntry geloescht.
pCurEditedEntry = 0;
return 0;
}
void SvxIconChoiceCtrl_Impl::StopEntryEditing( sal_Bool bCancel )
{
if( pEdit )
pEdit->StopEditing( bCancel );
}
void SvxIconChoiceCtrl_Impl::LockEntryPos( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bLock )
{
if( bLock )
pEntry->SetFlags( ICNVIEW_FLAG_POS_LOCKED );
else
pEntry->ClearFlags( ICNVIEW_FLAG_POS_LOCKED );
}
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry( sal_uLong& rPos ) const
{
if( !GetSelectionCount() )
return 0;
if( (nWinBits & WB_HIGHLIGHTFRAME) && (eSelectionMode == NO_SELECTION) )
{
rPos = pView->GetEntryListPos( pCurHighlightFrame );
return pCurHighlightFrame;
}
sal_uLong nCount = aEntries.Count();
if( !pHead )
{
for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
if( pEntry->IsSelected() )
{
rPos = nCur;
return pEntry;
}
}
}
else
{
SvxIconChoiceCtrlEntry* pEntry = pHead;
while( nCount-- )
{
if( pEntry->IsSelected() )
{
rPos = GetEntryListPos( pEntry );
return pEntry;
}
pEntry = pEntry->pflink;
if( nCount && pEntry == pHead )
{
DBG_ERROR("SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry > Endlosschleife!");
return 0;
}
}
}
return 0;
}
// kein Round Robin!
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetNextSelectedEntry( sal_uLong& rStartPos ) const
{
sal_uLong nCount = aEntries.Count();
if( rStartPos > nCount || !GetSelectionCount() )
return 0;
if( !pHead )
{
for( sal_uLong nCur = rStartPos+1; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
if( pEntry->IsSelected() )
{
rStartPos = nCur;
return pEntry;
}
}
}
else
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( rStartPos );
pEntry = pEntry->pflink;
while( pEntry != pHead )
{
if( pEntry->IsSelected() )
{
rStartPos = GetEntryListPos( pEntry );
return pEntry;
}
pEntry = pEntry->pflink;
}
}
rStartPos = 0xffffffff;
return 0;
}
void SvxIconChoiceCtrl_Impl::SelectAll( sal_Bool bSelect, sal_Bool bPaint )
{
bPaint = sal_True;
sal_uLong nCount = aEntries.Count();
for( sal_uLong nCur = 0; nCur < nCount && (bSelect || GetSelectionCount() ); nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
SelectEntry( pEntry, bSelect, sal_True, sal_True, bPaint );
}
nFlags &= (~F_ADD_MODE);
pAnchor = 0;
}
void SvxIconChoiceCtrl_Impl::SaveSelection( List** ppList )
{
if( !*ppList )
*ppList = new List;
sal_uLong nPos;
SvxIconChoiceCtrlEntry* pEntry = GetFirstSelectedEntry( nPos );
while( pEntry && GetSelectionCount() != (*ppList)->Count() )
{
(*ppList)->Insert( pEntry, LIST_APPEND );
pEntry = GetNextSelectedEntry( nPos );
}
}
IcnViewEdit_Impl::IcnViewEdit_Impl( SvtIconChoiceCtrl* pParent, const Point& rPos,
const Size& rSize, const XubString& rData, const Link& rNotifyEditEnd ) :
MultiLineEdit( pParent, (pParent->GetStyle() & WB_ICON) ? WB_CENTER : WB_LEFT),
aCallBackHdl( rNotifyEditEnd ),
bCanceled( sal_False ),
bAlreadyInCallback( sal_False ),
bGrabFocus( sal_False )
{
Font aFont( pParent->GetPointFont() );
aFont.SetTransparent( sal_False );
SetControlFont( aFont );
if( !pParent->HasFontFillColor() )
{
Color aColor( pParent->GetBackground().GetColor() );
SetControlBackground( aColor );
}
else
SetControlBackground( aFont.GetFillColor() );
SetControlForeground( aFont.GetColor() );
SetPosPixel( rPos );
SetSizePixel( CalcAdjustedSize(rSize) );
SetText( rData );
SaveValue();
aAccReturn.InsertItem( IMPICNVIEW_ACC_RETURN, KeyCode(KEY_RETURN) );
aAccEscape.InsertItem( IMPICNVIEW_ACC_ESCAPE, KeyCode(KEY_ESCAPE) );
aAccReturn.SetActivateHdl( LINK( this, IcnViewEdit_Impl, ReturnHdl_Impl) );
aAccEscape.SetActivateHdl( LINK( this, IcnViewEdit_Impl, EscapeHdl_Impl) );
GetpApp()->InsertAccel( &aAccReturn);//, ACCEL_ALWAYS );
GetpApp()->InsertAccel( &aAccEscape);//, ACCEL_ALWAYS );
Show();
GrabFocus();
}
IcnViewEdit_Impl::~IcnViewEdit_Impl()
{
if( !bAlreadyInCallback )
{
GetpApp()->RemoveAccel( &aAccReturn );
GetpApp()->RemoveAccel( &aAccEscape );
}
}
void IcnViewEdit_Impl::CallCallBackHdl_Impl()
{
aTimer.Stop();
if ( !bAlreadyInCallback )
{
bAlreadyInCallback = sal_True;
GetpApp()->RemoveAccel( &aAccReturn );
GetpApp()->RemoveAccel( &aAccEscape );
Hide();
aCallBackHdl.Call( this );
}
}
IMPL_LINK( IcnViewEdit_Impl, Timeout_Impl, Timer*, EMPTYARG )
{
CallCallBackHdl_Impl();
return 0;
}
IMPL_LINK( IcnViewEdit_Impl, ReturnHdl_Impl, Accelerator*, EMPTYARG )
{
bCanceled = sal_False;
bGrabFocus = sal_True;
CallCallBackHdl_Impl();
return 1;
}
IMPL_LINK( IcnViewEdit_Impl, EscapeHdl_Impl, Accelerator*, EMPTYARG )
{
bCanceled = sal_True;
bGrabFocus = sal_True;
CallCallBackHdl_Impl();
return 1;
}
void IcnViewEdit_Impl::KeyInput( const KeyEvent& rKEvt )
{
KeyCode aCode = rKEvt.GetKeyCode();
sal_uInt16 nCode = aCode.GetCode();
switch ( nCode )
{
case KEY_ESCAPE:
bCanceled = sal_True;
bGrabFocus = sal_True;
CallCallBackHdl_Impl();
break;
case KEY_RETURN:
bCanceled = sal_False;
bGrabFocus = sal_True;
CallCallBackHdl_Impl();
break;
default:
MultiLineEdit::KeyInput( rKEvt );
}
}
long IcnViewEdit_Impl::PreNotify( NotifyEvent& rNEvt )
{
if( rNEvt.GetType() == EVENT_LOSEFOCUS )
{
if ( !bAlreadyInCallback &&
((!Application::GetFocusWindow()) || !IsChild(Application::GetFocusWindow())))
{
bCanceled = sal_False;
aTimer.SetTimeout(10);
aTimer.SetTimeoutHdl(LINK(this,IcnViewEdit_Impl,Timeout_Impl));
aTimer.Start();
}
}
return 0;
}
void IcnViewEdit_Impl::StopEditing( sal_Bool bCancel )
{
if ( !bAlreadyInCallback )
{
bCanceled = bCancel;
CallCallBackHdl_Impl();
}
}
sal_uLong SvxIconChoiceCtrl_Impl::GetEntryListPos( SvxIconChoiceCtrlEntry* pEntry ) const
{
if( !(nFlags & F_ENTRYLISTPOS_VALID ))
((SvxIconChoiceCtrl_Impl*)this)->SetListPositions();
return pEntry->nPos;
}
void SvxIconChoiceCtrl_Impl::SetEntryListPos( SvxIconChoiceCtrlEntry* pListEntry, sal_uLong nNewPos )
{
sal_uLong nCurPos = GetEntryListPos( pListEntry );
if( nCurPos == nNewPos )
return;
aEntries.List::Remove( nCurPos );
aEntries.List::Insert( (void*)pListEntry, nNewPos );
// Eintragspositionen anpassen
sal_uLong nStart, nEnd;
if( nNewPos < nCurPos )
{
nStart = nNewPos;
nEnd = nCurPos;
}
else
{
nStart = nCurPos;
nEnd = nNewPos;
}
for( ; nStart <= nEnd; nStart++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nStart );
pEntry->nPos = nStart;
}
}
void SvxIconChoiceCtrl_Impl::SetEntryFlags( SvxIconChoiceCtrlEntry* pEntry, sal_uInt16 nEntryFlags )
{
pEntry->nFlags = nEntryFlags;
if( nEntryFlags & ICNVIEW_FLAG_POS_MOVED )
nFlags |= F_MOVED_ENTRIES;
}
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GoLeftRight( SvxIconChoiceCtrlEntry* pStart, sal_Bool bRight )
{
return pImpCursor->GoLeftRight( pStart, bRight );
}
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GoUpDown( SvxIconChoiceCtrlEntry* pStart, sal_Bool bDown )
{
return pImpCursor->GoUpDown( pStart, bDown );
}
void SvxIconChoiceCtrl_Impl::InitSettings()
{
const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings();
if( !pView->HasFont() )
{
// Unit aus den Settings ist Point
Font aFont( rStyleSettings.GetFieldFont() );
//const Font& rFont = pView->GetFont();
//if( pView->HasFontTextColor() )
aFont.SetColor( rStyleSettings.GetWindowTextColor() );
//if( pView->HasFontFillColor() )
//aFont.SetFillColor( rFont.GetFillColor() );
pView->SetPointFont( aFont );
SetDefaultTextSize();
}
//if( !pView->HasFontTextColor() )
pView->SetTextColor( rStyleSettings.GetFieldTextColor() );
//if( !pView->HasFontFillColor() )
pView->SetTextFillColor();
//if( !pView->HasBackground() )
pView->SetBackground( rStyleSettings.GetFieldColor());
long nScrBarSize = rStyleSettings.GetScrollBarSize();
if( nScrBarSize != nHorSBarHeight || nScrBarSize != nVerSBarWidth )
{
nHorSBarHeight = nScrBarSize;
Size aSize( aHorSBar.GetSizePixel() );
aSize.Height() = nScrBarSize;
aHorSBar.Hide();
aHorSBar.SetSizePixel( aSize );
nVerSBarWidth = nScrBarSize;
aSize = aVerSBar.GetSizePixel();
aSize.Width() = nScrBarSize;
aVerSBar.Hide();
aVerSBar.SetSizePixel( aSize );
Size aOSize( pView->Control::GetOutputSizePixel() );
PositionScrollBars( aOSize.Width(), aOSize.Height() );
AdjustScrollBars();
}
}
EntryList_Impl::EntryList_Impl( SvxIconChoiceCtrl_Impl* pOwner, sal_uInt16 _nInitSize , sal_uInt16 _nReSize ) :
List( _nInitSize, _nReSize ),
_pOwner( pOwner )
{
_pOwner->pHead = 0;
}
EntryList_Impl::EntryList_Impl( SvxIconChoiceCtrl_Impl* pOwner, sal_uInt16 _nBlockSize, sal_uInt16 _nInitSize, sal_uInt16 _nReSize ) :
List( _nBlockSize, _nInitSize, _nReSize ),
_pOwner( pOwner )
{
_pOwner->pHead = 0;
}
EntryList_Impl::~EntryList_Impl()
{
_pOwner->pHead = 0;
}
void EntryList_Impl::Clear()
{
_pOwner->pHead = 0;
List::Clear();
}
void EntryList_Impl::Insert( SvxIconChoiceCtrlEntry* pEntry, sal_uLong nPos )
{
List::Insert( pEntry, nPos );
if( _pOwner->pHead )
pEntry->SetBacklink( _pOwner->pHead->pblink );
}
SvxIconChoiceCtrlEntry* EntryList_Impl::Remove( sal_uLong nPos )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)List::Remove( nPos );
DBG_ASSERT(pEntry,"EntryList_Impl::Remove > Entry not found");
Removed_Impl( pEntry );
return pEntry;
}
void EntryList_Impl::Remove( SvxIconChoiceCtrlEntry* pEntry )
{
List::Remove( (void*)pEntry );
Removed_Impl( pEntry );
}
void EntryList_Impl::Removed_Impl( SvxIconChoiceCtrlEntry* pEntry )
{
if( _pOwner->pHead )
{
if( _pOwner->pHead == pEntry )
{
if( _pOwner->pHead != pEntry->pflink )
_pOwner->pHead = pEntry->pflink;
else
{
DBG_ASSERT(!Count(),"EntryList_Impl::Remove > Invalid predecessor" );
_pOwner->pHead = 0;
}
}
pEntry->Unlink();
}
}
void SvxIconChoiceCtrl_Impl::SetPositionMode( SvxIconChoiceCtrlPositionMode eMode )
{
sal_uLong nCur;
if( eMode == ePositionMode )
return;
SvxIconChoiceCtrlPositionMode eOldMode = ePositionMode;
ePositionMode = eMode;
sal_uLong nCount = aEntries.Count();
if( eOldMode == IcnViewPositionModeAutoArrange )
{
// positionieren wir verschobene Eintraege 'hart' gibts noch Probleme
// mit ungewollten Ueberlappungen, da diese Eintrage im Arrange
// nicht beruecksichtigt werden.
#if 1
if( aEntries.Count() )
aAutoArrangeTimer.Start();
#else
if( pHead )
{
// verschobene Eintraege 'hart' auf ihre Position setzen
nCur = nCount;
SvxIconChoiceCtrlEntry* pEntry = pHead;
while( nCur )
{
SvxIconChoiceCtrlEntry* pPred;
if( GetEntryPredecessor( pEntry, &pPred ))
SetEntryFlags( pEntry, ICNVIEW_FLAG_POS_MOVED );
pEntry = pEntry->pflink;
nCur--;
}
ClearPredecessors();
}
#endif
return;
}
if( ePositionMode == IcnViewPositionModeAutoArrange )
{
List aMovedEntries;
for( nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur );
if( pEntry->GetFlags() & (ICNVIEW_FLAG_POS_LOCKED | ICNVIEW_FLAG_POS_MOVED))
{
SvxIconChoiceCtrlEntry_Impl* pE = new SvxIconChoiceCtrlEntry_Impl(
pEntry, GetEntryBoundRect( pEntry ));
aMovedEntries.Insert( pE, LIST_APPEND );
}
}
nCount = aMovedEntries.Count();
for( nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlEntry_Impl* pE = (SvxIconChoiceCtrlEntry_Impl*)aMovedEntries.GetObject(nCur);
SetEntryPos( pE->_pEntry, pE->_aPos );
}
for( nCur = 0; nCur < nCount; nCur++ )
delete (SvxIconChoiceCtrlEntry_Impl*)aMovedEntries.GetObject( nCur );
if( aEntries.Count() )
aAutoArrangeTimer.Start();
}
else if( ePositionMode == IcnViewPositionModeAutoAdjust )
{
AdjustEntryAtGrid( 0 );
}
}
void SvxIconChoiceCtrl_Impl::SetEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
SvxIconChoiceCtrlEntry* pPredecessor )
{
if( !IsAutoArrange() )
return;
if( pEntry == pPredecessor )
return;
sal_uLong nPos1 = GetEntryListPos( pEntry );
if( !pHead )
{
if( pPredecessor )
{
sal_uLong nPos2 = GetEntryListPos( pPredecessor );
if( nPos1 == (nPos2 + 1) )
return; // ist schon Vorgaenger
}
else if( !nPos1 )
return;
}
if( !pHead )
InitPredecessors();
if( !pPredecessor && pHead == pEntry )
return; // ist schon der Erste
sal_Bool bSetHead = sal_False;
if( !pPredecessor )
{
bSetHead = sal_True;
pPredecessor = pHead->pblink;
}
if( pEntry == pHead )
{
pHead = pHead->pflink;
bSetHead = sal_False;
}
if( pEntry != pPredecessor )
{
pEntry->Unlink();
pEntry->SetBacklink( pPredecessor );
}
if( bSetHead )
pHead = pEntry;
pEntry->SetFlags( ICNVIEW_FLAG_PRED_SET );
aAutoArrangeTimer.Start();
}
sal_Bool SvxIconChoiceCtrl_Impl::GetEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
SvxIconChoiceCtrlEntry** ppPredecessor )
{
*ppPredecessor = 0;
if( !pHead )
return sal_False;
DBG_ASSERT(pEntry->pblink,"GetEntryPredecessor: Backward link not set");
DBG_ASSERT(pEntry->pflink,"GetEntryPredecessor: Forward link not set");
if( pEntry == pHead )
{
SvxIconChoiceCtrlEntry* pFirst = (SvxIconChoiceCtrlEntry*)aEntries.GetObject(0);
if( pFirst != pEntry )
return sal_True;
return sal_False;
}
*ppPredecessor = pEntry->pblink;
if( !(pEntry->nFlags & ICNVIEW_FLAG_PRED_SET) &&
(GetEntryListPos( *ppPredecessor ) + 1) == GetEntryListPos( pEntry ))
return sal_False;
return sal_True;
}
SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::FindEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
const Point& rPosTopLeft )
{
Point aPos( rPosTopLeft ); //TopLeft
Rectangle aCenterRect( CalcBmpRect( pEntry, &aPos ));
Point aNewPos( aCenterRect.Center() );
sal_uLong nGrid = GetPredecessorGrid( aNewPos );
sal_uLong nCount = aEntries.Count();
if( nGrid == ULONG_MAX )
return 0;
if( nGrid >= nCount )
nGrid = nCount - 1;
if( !pHead )
return (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nGrid );
SvxIconChoiceCtrlEntry* pCur = pHead; // Grid 0
// todo: Liste von hinten aufrollen wenn nGrid > nCount/2
for( sal_uLong nCur = 0; nCur < nGrid; nCur++ )
pCur = pCur->pflink;
return pCur;
}
sal_uLong SvxIconChoiceCtrl_Impl::GetPredecessorGrid( const Point& rPos) const
{
Point aPos( rPos );
aPos.X() -= LROFFS_WINBORDER;
aPos.Y() -= TBOFFS_WINBORDER;
sal_uInt16 nMaxCol = (sal_uInt16)(aVirtOutputSize.Width() / nGridDX);
if( nMaxCol )
nMaxCol--;
sal_uInt16 nGridX = (sal_uInt16)(aPos.X() / nGridDX);
if( nGridX > nMaxCol )
nGridX = nMaxCol;
sal_uInt16 nGridY = (sal_uInt16)(aPos.Y() / nGridDY);
sal_uInt16 nGridsX = (sal_uInt16)(aOutputSize.Width() / nGridDX);
sal_uLong nGrid = (nGridY * nGridsX) + nGridX;
long nMiddle = (nGridX * nGridDX) + (nGridDX / 2);
if( rPos.X() < nMiddle )
{
if( !nGrid )
nGrid = ULONG_MAX;
else
nGrid--;
}
return nGrid;
}
void SvxIconChoiceCtrl_Impl::Flush()
{
if( aAutoArrangeTimer.IsActive() )
{
AutoArrangeHdl( 0 );
}
}
sal_Bool SvxIconChoiceCtrl_Impl::RequestHelp( const HelpEvent& rHEvt )
{
if ( !(rHEvt.GetMode() & HELPMODE_QUICK ) )
return sal_False;
Point aPos( pView->ScreenToOutputPixel(rHEvt.GetMousePosPixel() ) );
aPos -= pView->GetMapMode().GetOrigin();
SvxIconChoiceCtrlEntry* pEntry = GetEntry( aPos, sal_True );
if ( !pEntry )
return sal_False;
String sQuickHelpText = pEntry->GetQuickHelpText();
String aEntryText( pView->GetEntryText( pEntry, sal_False ) );
Rectangle aTextRect( CalcTextRect( pEntry, 0, sal_False, &aEntryText ) );
if ( ( !aTextRect.IsInside( aPos ) || !aEntryText.Len() ) && !sQuickHelpText.Len() )
return sal_False;
Rectangle aOptTextRect( aTextRect );
aOptTextRect.Bottom() = LONG_MAX;
sal_uInt16 nNewFlags = nCurTextDrawFlags;
nNewFlags &= ~( TEXT_DRAW_CLIP | TEXT_DRAW_ENDELLIPSIS );
aOptTextRect = pView->GetTextRect( aOptTextRect, aEntryText, nNewFlags );
if ( aOptTextRect != aTextRect || sQuickHelpText.Len() > 0 )
{
//aTextRect.Right() = aTextRect.Left() + aRealSize.Width() + 4;
Point aPt( aOptTextRect.TopLeft() );
aPt += pView->GetMapMode().GetOrigin();
aPt = pView->OutputToScreenPixel( aPt );
// Border der Tiphilfe abziehen
aPt.Y() -= 1;
aPt.X() -= 3;
aOptTextRect.SetPos( aPt );
String sHelpText;
if ( sQuickHelpText.Len() > 0 )
sHelpText = sQuickHelpText;
else
sHelpText = aEntryText;
Help::ShowQuickHelp( (Window*)pView, aOptTextRect, sHelpText, QUICKHELP_LEFT | QUICKHELP_VCENTER );
}
return sal_True;
}
void SvxIconChoiceCtrl_Impl::ClearColumnList()
{
if( !pColumns )
return;
const sal_uInt16 nCount = pColumns->Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
SvxIconChoiceCtrlColumnInfo* pInfo = (SvxIconChoiceCtrlColumnInfo*)
pColumns->GetObject( nCur );
delete pInfo;
}
DELETEZ(pColumns);
}
void SvxIconChoiceCtrl_Impl::SetColumn( sal_uInt16 nIndex, const SvxIconChoiceCtrlColumnInfo& rInfo)
{
if( !pColumns )
pColumns = new SvPtrarr;
while( pColumns->Count() < nIndex + 1 )
pColumns->Insert( (void*)0, pColumns->Count() );
SvxIconChoiceCtrlColumnInfo* pInfo =
(SvxIconChoiceCtrlColumnInfo*)pColumns->GetObject(nIndex);
if( !pInfo )
{
pInfo = new SvxIconChoiceCtrlColumnInfo( rInfo );
pColumns->Insert( (void*)pInfo, nIndex );
}
else
{
delete pInfo;
pInfo = new SvxIconChoiceCtrlColumnInfo( rInfo );
pColumns->Replace( pInfo, nIndex );
}
// HACK(Detail-Modus ist noch nicht vollstaendig implementiert!)
// dieses Workaround bringts mit einer Spalte zum Fliegen
if( !nIndex && (nWinBits & WB_DETAILS) )
nGridDX = pInfo->GetWidth();
if( GetUpdateMode() )
Arrange( IsAutoArrange() );
}
const SvxIconChoiceCtrlColumnInfo* SvxIconChoiceCtrl_Impl::GetColumn( sal_uInt16 nIndex ) const
{
if( !pColumns || nIndex >= pColumns->Count() )
return 0;
return (const SvxIconChoiceCtrlColumnInfo*)pColumns->GetObject( nIndex );
}
const SvxIconChoiceCtrlColumnInfo* SvxIconChoiceCtrl_Impl::GetItemColumn( sal_uInt16 nSubItem,
long& rLeft ) const
{
rLeft = 0;
if( !pColumns )
return 0;
const sal_uInt16 nCount = pColumns->Count();
const SvxIconChoiceCtrlColumnInfo* pCol = 0;
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
pCol = (const SvxIconChoiceCtrlColumnInfo*)pColumns->GetObject( nCur );
if( !pCol || pCol->GetSubItem() == nSubItem )
return pCol;
rLeft += pCol->GetWidth();
}
return pCol;
}
void SvxIconChoiceCtrl_Impl::DrawHighlightFrame(
OutputDevice* pOut, const Rectangle& rBmpRect, sal_Bool bHide )
{
Rectangle aBmpRect( rBmpRect );
long nBorder = 2;
if( aImageSize.Width() < 32 )
nBorder = 1;
aBmpRect.Right() += nBorder;
aBmpRect.Left() -= nBorder;
aBmpRect.Bottom() += nBorder;
aBmpRect.Top() -= nBorder;
if ( bHide )
pView->Invalidate( aBmpRect );
else
{
DecorationView aDecoView( pOut );
sal_uInt16 nDecoFlags;
if ( bHighlightFramePressed )
nDecoFlags = FRAME_HIGHLIGHT_TESTBACKGROUND | FRAME_HIGHLIGHT_IN;
else
nDecoFlags = FRAME_HIGHLIGHT_TESTBACKGROUND | FRAME_HIGHLIGHT_OUT;
aDecoView.DrawHighlightFrame( aBmpRect, nDecoFlags );
}
}
void SvxIconChoiceCtrl_Impl::SetEntryHighlightFrame( SvxIconChoiceCtrlEntry* pEntry,
sal_Bool bKeepHighlightFlags )
{
if( pEntry == pCurHighlightFrame )
return;
if( !bKeepHighlightFlags )
bHighlightFramePressed = sal_False;
HideEntryHighlightFrame();
pCurHighlightFrame = pEntry;
if( pEntry )
{
Rectangle aBmpRect( CalcFocusRect(pEntry) );
DrawHighlightFrame( pView, aBmpRect, sal_False );
}
}
void SvxIconChoiceCtrl_Impl::HideEntryHighlightFrame()
{
if( !pCurHighlightFrame )
return;
SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame;
pCurHighlightFrame = 0;
Rectangle aBmpRect( CalcFocusRect(pEntry) );
DrawHighlightFrame( pView, aBmpRect, sal_True );
}
void SvxIconChoiceCtrl_Impl::CallSelectHandler( SvxIconChoiceCtrlEntry* )
{
// Bei aktiviertem Single-Click-Modus sollte der Selektionshandler
// synchron gerufen werden, weil die Selektion automatisch
// weggenommen wird, wenn der Mauszeiger nicht mehr das Objekt
// beruehrt. Es kann sonst zu fehlenden Select-Aufrufen kommen,
// wenn das Objekt aus einer Mausbewegung heraus selektiert wird,
// weil beim Ausloesen des Timers der Mauszeiger das Objekt u.U.
// schon verlassen hat.
// Fuer spezielle Faelle (=>SfxFileDialog!) koennen synchrone
// Aufrufe auch per WB_NOASYNCSELECTHDL erzwungen werden.
if( nWinBits & (WB_NOASYNCSELECTHDL | WB_HIGHLIGHTFRAME) )
{
pHdlEntry = 0;
pView->ClickIcon();
//pView->Select();
}
else
aCallSelectHdlTimer.Start();
}
IMPL_LINK( SvxIconChoiceCtrl_Impl, CallSelectHdlHdl, void*, EMPTYARG )
{
pHdlEntry = 0;
pView->ClickIcon();
//pView->Select();
return 0;
}
Point SvxIconChoiceCtrl_Impl::GetPopupMenuPosPixel() const
{
Point aResult;
if( !GetSelectionCount() )
return aResult;
SvxIconChoiceCtrlEntry* pEntry = GetCurEntry();
if( !pEntry || !pEntry->IsSelected() )
{
sal_uLong nNext;
pEntry = GetFirstSelectedEntry( nNext );
}
if( pEntry )
{
Rectangle aRect( ((SvxIconChoiceCtrl_Impl*)this)->CalcBmpRect( pEntry ) );
aResult = aRect.Center();
aResult = pView->GetPixelPos( aResult );
}
return aResult;
}
void SvxIconChoiceCtrl_Impl::SetOrigin( const Point& rPos, sal_Bool bDoNotUpdateWallpaper )
{
MapMode aMapMode( pView->GetMapMode() );
aMapMode.SetOrigin( rPos );
pView->SetMapMode( aMapMode );
if( !bDoNotUpdateWallpaper )
{
sal_Bool bScrollable = pView->GetBackground().IsScrollable();
if( pView->HasBackground() && !bScrollable )
{
Rectangle aRect( GetOutputRect());
Wallpaper aPaper( pView->GetBackground() );
aPaper.SetRect( aRect );
pView->SetBackground( aPaper );
}
}
}
sal_uLong SvxIconChoiceCtrl_Impl::GetGridCount( const Size& rSize, sal_Bool bCheckScrBars,
sal_Bool bSmartScrBar ) const
{
Size aSize( rSize );
if( bCheckScrBars && aHorSBar.IsVisible() )
aSize.Height() -= nHorSBarHeight;
else if( bSmartScrBar && (nWinBits & WB_ALIGN_LEFT) )
aSize.Height() -= nHorSBarHeight;
if( bCheckScrBars && aVerSBar.IsVisible() )
aSize.Width() -= nVerSBarWidth;
else if( bSmartScrBar && (nWinBits & WB_ALIGN_TOP) )
aSize.Width() -= nVerSBarWidth;
if( aSize.Width() < 0 )
aSize.Width() = 0;
if( aSize.Height() < 0 )
aSize.Height() = 0;
return IcnGridMap_Impl::GetGridCount( aSize, (sal_uInt16)nGridDX, (sal_uInt16)nGridDY );
}
sal_Bool SvxIconChoiceCtrl_Impl::HandleShortCutKey( const KeyEvent& rKEvt )
{
StopEditTimer();
sal_Bool bRet = sal_False;
DBG_ASSERT( rKEvt.GetKeyCode().IsMod2(), "*SvxIconChoiceCtrl_Impl::HandleShortCutKey(): no <ALT> pressed!?" );
sal_Unicode cChar = rKEvt.GetCharCode();
sal_uLong nPos = (sal_uLong)-1;
if( cChar && IsMnemonicChar( cChar, nPos ) )
{
// shortcut is clicked
SvxIconChoiceCtrlEntry* pNewCursor = GetEntry( nPos );
SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
if( pNewCursor != pOldCursor )
{
SetCursor_Impl( pOldCursor, pNewCursor, sal_False, sal_False, sal_False );
if( pNewCursor != NULL )
{
pHdlEntry = pNewCursor;
pCurHighlightFrame = pHdlEntry;
pView->ClickIcon();
pCurHighlightFrame = NULL;
}
}
bRet = sal_True;
}
return bRet;
}
// -----------------------------------------------------------------------
void SvxIconChoiceCtrl_Impl::CallEventListeners( sal_uLong nEvent, void* pData )
{
pView->CallImplEventListeners( nEvent, pData );
}