diff options
Diffstat (limited to 'svtools/source/contnr/imivctl1.cxx')
-rw-r--r-- | svtools/source/contnr/imivctl1.cxx | 4681 |
1 files changed, 4681 insertions, 0 deletions
diff --git a/svtools/source/contnr/imivctl1.cxx b/svtools/source/contnr/imivctl1.cxx new file mode 100644 index 000000000000..dd2ed992536e --- /dev/null +++ b/svtools/source/contnr/imivctl1.cxx @@ -0,0 +1,4681 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 "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 BOOL bEndScrollInvalidate = TRUE; + +// ---------------------------------------------------------------------------------------------- + +class IcnViewEdit_Impl : public MultiLineEdit +{ + Link aCallBackHdl; + Accelerator aAccReturn; + Accelerator aAccEscape; + Timer aTimer; + BOOL bCanceled; + BOOL bAlreadyInCallback; + 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 ); + BOOL EditingCanceled() const { return bCanceled; } + void StopEditing( BOOL bCancel = FALSE ); + 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=FALSE; + pEntryPaintDev = 0; + pCurEditedEntry = 0; + pCurHighlightFrame = 0; + pEdit = 0; + pAnchor = 0; + pDraggedSelection = 0; + pPrevDropTarget = 0; + pHdlEntry = 0; + pHead = NULL; + pCursor = NULL; + bUpdateMode = TRUE; + bEntryEditingEnabled = FALSE; + bInDragDrop = FALSE; + bHighlightFramePressed = 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( 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( BOOL bInCtor ) +{ + StopEntryEditing( TRUE ); + nSelectionCount = 0; + DELETEZ(pDraggedSelection); + bInDragDrop = FALSE; + pCurHighlightFrame = 0; + StopEditTimer(); + CancelUserEvents(); + ShowCursor( FALSE ); + bBoundRectsDirty = 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(); + ULONG nCount = aEntries.Count(); + for( 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( TRUE ); + // Pfeil hoch: delta=-1; Pfeil runter: delta=+1 + Scroll( 0, pScrollBar->GetDelta(), TRUE ); + bEndScrollInvalidate = TRUE; + return 0; +} + +IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl, ScrollBar*, pScrollBar ) +{ + StopEntryEditing( TRUE ); + // Pfeil links: delta=-1; Pfeil rechts: delta=+1 + Scroll( pScrollBar->GetDelta(), 0, TRUE ); + bEndScrollInvalidate = 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( FALSE ); + ShowCursor( TRUE ); +} + +void SvxIconChoiceCtrl_Impl::InsertEntry( SvxIconChoiceCtrlEntry* pEntry, 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, FALSE, TRUE, TRUE /*keep grid map*/ ); + pEntry->nFlags |= ICNVIEW_FLAG_POS_MOVED; + SetEntriesMoved( TRUE ); + } + else + { + // wenn der UpdateMode 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 ); + } + + ULONG nEntryCount = GetEntryCount(); + 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; + + ULONG nCount = aEntries.Count(); + for( 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 ) +{ + 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 = TRUE; + else + bSyncSingleSelection = FALSE; + + if( pEntry == pCurHighlightFrame ) + pCurHighlightFrame = 0; + + if( bInDragDrop ) + { + DELETEZ(pDraggedSelection); + bInDragDrop = 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--; + BOOL bEntryBoundValid = IsBoundingRectValid( pEntry->aRect ); + if( bEntryBoundValid ) + pView->Invalidate( pEntry->aRect ); + + BOOL bSetNewCursor = FALSE; + SvxIconChoiceCtrlEntry* pNewCursor = NULL; + + if( pEntry == pCursor ) + { + bSetNewCursor = TRUE; + pNewCursor = FindNewCursor(); + ShowCursor( FALSE ); + pCursor = 0; + } + + BOOL bCurEntryPosValid = (nFlags & F_ENTRYLISTPOS_VALID) ? TRUE : FALSE; + if( bCurEntryPosValid && aEntries.GetObject(aEntries.Count()-1) != pEntry ) + nFlags &= ~F_ENTRYLISTPOS_VALID; + 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, TRUE ); + } +} + +void SvxIconChoiceCtrl_Impl::SelectEntry( SvxIconChoiceCtrlEntry* pEntry, BOOL bSelect, + BOOL bCallHdl, BOOL bAdd, 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; + USHORT 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, BOOL bSelect, + 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( 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( 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; + BOOL bLockedEntryFound = FALSE; + const ULONG nCount = aEntries.Count(); + for( 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 = TRUE; + } + else + InvalidateBoundingRect( pCur->aRect ); + } + + if( !(nWinBits & (WB_NOVSCROLL | WB_NOHSCROLL)) ) + { + Size aRealOutputSize( pView->GetOutputSizePixel() ); + if( aVirtOutputSize.Width() < aRealOutputSize.Width() || + aVirtOutputSize.Height() < aRealOutputSize.Height() ) + { + ULONG nGridCount = IcnGridMap_Impl::GetGridCount( + aRealOutputSize, (USHORT)nGridDX, (USHORT)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"); + ULONG nCount = aEntries.Count(); + if( nCount ) + { + SvxIconChoiceCtrlEntry* pPrev = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 ); + for( 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 ) + { + ULONG nCount = aEntries.Count(); + for( 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( 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( BOOL bKeepPredecessors ) +{ + static Point aEmptyPoint; + + BOOL bOldUpdate = bUpdateMode; + Rectangle aCurOutputArea( GetOutputRect() ); + if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint ) + bUpdateMode = FALSE; + aAutoArrangeTimer.Stop(); + nFlags &= ~F_MOVED_ENTRIES; + nFlags |= F_ARRANGING; + StopEditTimer(); + ShowCursor( FALSE ); + ResetVirtSize(); + if( !bKeepPredecessors ) + ClearPredecessors(); + bBoundRectsDirty = 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( TRUE ); +} + +void SvxIconChoiceCtrl_Impl::Paint( const Rectangle& rRect ) +{ + bEndScrollInvalidate = 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 + BOOL bfound = FALSE; + for ( ULONG i = 0; i < pView->GetEntryCount() && !bfound; i++) + { + SvxIconChoiceCtrlEntry* pEntry = pView->GetEntry ( i ); + if( pEntry->IsFocused() ) + { + pCursor = pEntry; + bfound=TRUE; + } + } + + if( !bfound ) + pCursor = (SvxIconChoiceCtrlEntry*)aEntries.First(); + } + + // Show Focus at Init-Time + if ( pView->HasFocus() ) + GetFocus(); + + ULONG nCount = pZOrderList->Count(); + if( !nCount ) + return; + + BOOL bResetClipRegion = FALSE; + if( !pView->IsClipRegion() ) + { + Rectangle aOutputArea( GetOutputRect() ); + bResetClipRegion = TRUE; + pView->SetClipRegion( aOutputArea ); + } + + const USHORT nListInitSize = aEntries.Count() > USHRT_MAX ? + USHRT_MAX : (USHORT)aEntries.Count(); + List* pNewZOrderList = new List( nListInitSize ); + List* pPaintedEntries = new List( nListInitSize ); + + 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, 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( ULONG nCur = 0; nCur < nCount; nCur++ ) + pZOrderList->Insert( pPaintedEntries->GetObject(nCur), LIST_APPEND); + } + delete pPaintedEntries; + + if( bResetClipRegion ) + pView->SetClipRegion(); +} + +void SvxIconChoiceCtrl_Impl::RepaintEntries( USHORT nEntryFlagsMask ) +{ + const ULONG nCount = pZOrderList->Count(); + if( !nCount ) + return; + + BOOL bResetClipRegion = FALSE; + Rectangle aOutRect( GetOutputRect() ); + if( !pView->IsClipRegion() ) + { + bResetClipRegion = TRUE; + pView->SetClipRegion( aOutRect ); + } + for( 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; +} + +BOOL SvxIconChoiceCtrl_Impl::MouseButtonDown( const MouseEvent& rMEvt) +{ + BOOL bHandled = TRUE; + bHighlightFramePressed = FALSE; + StopEditTimer(); + BOOL bGotFocus = (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 FALSE; + ToDocPos( aDocPos ); + SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, TRUE ); + if( pEntry ) + MakeEntryVisible( pEntry, FALSE ); + + if( rMEvt.IsShift() && eSelectionMode != SINGLE_SELECTION ) + { + if( pEntry ) + SetCursor_Impl( pCursor, pEntry, rMEvt.IsMod1(), rMEvt.IsShift(), TRUE); + return 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 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 = FALSE; + return bHandled; + } + } + BOOL bSelected = pEntry->IsSelected(); + BOOL bEditingEnabled = IsEntryEditingEnabled(); + + if( rMEvt.GetClicks() == 2 ) + { + DeselectAllBut( pEntry ); + SelectEntry( pEntry, TRUE, TRUE, FALSE, 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 = TRUE; + SetEntryHighlightFrame( pEntry, TRUE ); + } + } + else + { + if( !rMEvt.GetModifier() && rMEvt.IsLeft() ) + { + if( !bSelected ) + { + DeselectAllBut( pEntry, TRUE /* Synchron painten */ ); + SetCursor( pEntry ); + SelectEntry( pEntry, TRUE, TRUE, FALSE, 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; +} + +BOOL SvxIconChoiceCtrl_Impl::MouseButtonUp( const MouseEvent& rMEvt ) +{ + BOOL bHandled = FALSE; + if( rMEvt.IsRight() && (nFlags & (F_DOWN_CTRL | F_DOWN_DESELECT) )) + { + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); + bHandled = 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 = TRUE; + } + else if( nFlags & F_DOWN_DESELECT ) + { + DeselectAllBut( pDocEntry ); + SetCursor( pDocEntry ); + SelectEntry( pDocEntry, TRUE, TRUE, FALSE, TRUE ); + bHandled = TRUE; + } + } + + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); + if( nFlags & F_START_EDITTIMER_IN_MOUSEUP ) + { + bHandled = TRUE; + StartEditTimer(); + nFlags &= ~F_START_EDITTIMER_IN_MOUSEUP; + } + + if((nWinBits & WB_HIGHLIGHTFRAME) && bHighlightFramePressed && pCurHighlightFrame) + { + bHandled = TRUE; + SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame; + pCurHighlightFrame = 0; // Neues painten des Frames erzwingen + bHighlightFramePressed = FALSE; + SetEntryHighlightFrame( pEntry, TRUE ); +#if 0 + CallSelectHandler( pCurHighlightFrame ); +#else + pHdlEntry = pCurHighlightFrame; + pView->ClickIcon(); + + // set focus on Icon + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + SetCursor_Impl( pOldCursor, pHdlEntry, FALSE, FALSE, TRUE ); +#endif + pHdlEntry = 0; + } + return bHandled; +} + +BOOL SvxIconChoiceCtrl_Impl::MouseMove( const MouseEvent& rMEvt ) +{ + const Point aDocPos( pView->PixelToLogic(rMEvt.GetPosPixel()) ); + + if( pView->IsTracking() ) + return FALSE; + else if( nWinBits & WB_HIGHLIGHTFRAME ) + { + SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, TRUE ); + SetEntryHighlightFrame( pEntry ); + } + else + return FALSE; + return 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, FALSE ); + if( nScrollDX || nScrollDY ) + { + pView->HideTracking(); + pView->Scroll( nScrollDX, nScrollDY ); + } + Rectangle aRect( aCurSelectionRect.TopLeft(), aDocPos ); + if( aRect != aCurSelectionRect ) + { + pView->HideTracking(); + BOOL bAdd = (nFlags & F_ADD_MODE) ? TRUE : FALSE; + SelectRect( aRect, bAdd, &aSelectedRectList ); + } + pView->ShowTracking( aRect, SHOWTRACK_SMALL | SHOWTRACK_CLIP ); + } +} + +void SvxIconChoiceCtrl_Impl::SetCursor_Impl( SvxIconChoiceCtrlEntry* pOldCursor, + SvxIconChoiceCtrlEntry* pNewCursor, BOOL bMod1, BOOL bShift, BOOL bPaintSync ) +{ + if( pNewCursor ) + { + SvxIconChoiceCtrlEntry* pFilterEntry = 0; + BOOL bDeselectAll = FALSE; + if( eSelectionMode != SINGLE_SELECTION ) + { + if( !bMod1 && !bShift ) + bDeselectAll = TRUE; + else if( bShift && !bMod1 && !pAnchor ) + { + bDeselectAll = TRUE; + pFilterEntry = pOldCursor; + } + } + if( bDeselectAll ) + DeselectAllBut( pFilterEntry, bPaintSync ); + ShowCursor( 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, TRUE, TRUE, FALSE, bPaintSync ); + aCurSelectionRect = GetEntryBoundRect( pCursor ); + } + } +} + +BOOL SvxIconChoiceCtrl_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + StopEditTimer(); + + BOOL bMod2 = rKEvt.GetKeyCode().IsMod2(); + sal_Unicode cChar = rKEvt.GetCharCode(); + ULONG nPos = (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, FALSE, FALSE, FALSE ); + return TRUE; + } + + if ( bMod2 ) + // no actions with <ALT> + return FALSE; + + BOOL bKeyUsed = TRUE; + BOOL bMod1 = rKEvt.GetKeyCode().IsMod1(); + BOOL bShift = rKEvt.GetKeyCode().IsShift(); + + if( eSelectionMode == SINGLE_SELECTION || eSelectionMode == NO_SELECTION) + { + bShift = FALSE; + bMod1 = FALSE; + } + + if( bMod1 ) + nFlags |= F_ADD_MODE; + BOOL bDeselectAll = FALSE; + if( eSelectionMode != SINGLE_SELECTION ) + { + if( !bMod1 && !bShift ) + bDeselectAll = TRUE; + if( bShift && !bMod1 && !pAnchor ) + bDeselectAll = TRUE; + } + + SvxIconChoiceCtrlEntry* pNewCursor; + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + + USHORT nCode = rKEvt.GetKeyCode().GetCode(); + switch( nCode ) + { + case KEY_UP: + case KEY_PAGEUP: + if( pCursor ) + { + MakeEntryVisible( pCursor ); + if( nCode == KEY_UP ) + pNewCursor = pImpCursor->GoUpDown(pCursor,FALSE); + else + pNewCursor = pImpCursor->GoPageUpDown(pCursor,FALSE); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, 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,TRUE ); + else + pNewCursor=pImpCursor->GoPageUpDown( pCursor,TRUE ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, TRUE ); + + if ( bChooseWithCursor && pNewCursor != NULL) + { + pHdlEntry = pNewCursor;//GetCurEntry(); + pCurHighlightFrame = pHdlEntry; + pView->ClickIcon(); + pCurHighlightFrame = NULL; + } + } + break; + + case KEY_RIGHT: + if( pCursor ) + { + pNewCursor=pImpCursor->GoLeftRight(pCursor,TRUE ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, TRUE ); + } + break; + + case KEY_LEFT: + if( pCursor ) + { + MakeEntryVisible( pCursor ); + pNewCursor = pImpCursor->GoLeftRight(pCursor,FALSE ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, 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( FALSE ); + SetNoSelection(); + ClearSelectedRectList(); + nFlags &= ~F_TRACKING; + } + else + bKeyUsed = FALSE; + break; +#endif + + + case KEY_F2: + if( !bMod1 && !bShift ) + EditTimeoutHdl( 0 ); + else + bKeyUsed = 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 = FALSE; + break; + + case KEY_SPACE: + if( pCursor && eSelectionMode != SINGLE_SELECTION ) + { + if( !bMod1 ) + { + //SelectAll( FALSE ); + SetNoSelection(); + ClearSelectedRectList(); + + // click Icon with spacebar + SetEntryHighlightFrame( GetCurEntry(), 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( TRUE ); + else + bKeyUsed = FALSE; + break; + + case KEY_SUBTRACT: + case KEY_COMMA : + if( bMod1 ) + SetNoSelection(); + else + bKeyUsed = FALSE; + break; + + case KEY_RETURN: + if( bMod1 ) + { + if( pCursor && bEntryEditingEnabled ) + /*pView->*/EditEntry( pCursor ); + } + else + bKeyUsed = FALSE; + break; + + case KEY_END: + if( pCursor ) + { + pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( aEntries.Count() - 1 ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, TRUE ); + } + break; + + case KEY_HOME: + if( pCursor ) + { + pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, TRUE ); + } + break; + + default: + bKeyUsed = 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( 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; + + USHORT 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(); +} + +BOOL SvxIconChoiceCtrl_Impl::CheckHorScrollBar() +{ + if( !pZOrderList || !aHorSBar.IsVisible() ) + return FALSE; + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + if(!( nWinBits & WB_HSCROLL) && !aOrigin.X() ) + { + long nWidth = aOutputSize.Width(); + const ULONG nCount = pZOrderList->Count(); + long nMostRight = 0; + for( ULONG nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pZOrderList->GetObject(nCur); + long nRight = GetEntryBoundRect(pEntry).Right(); + if( nRight > nWidth ) + return 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 TRUE; + } + return FALSE; +} + +BOOL SvxIconChoiceCtrl_Impl::CheckVerScrollBar() +{ + if( !pZOrderList || !aVerSBar.IsVisible() ) + return FALSE; + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + if(!( nWinBits & WB_VSCROLL) && !aOrigin.Y() ) + { + long nDeepest = 0; + long nHeight = aOutputSize.Height(); + const ULONG nCount = pZOrderList->Count(); + for( ULONG nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pZOrderList->GetObject(nCur); + long nBottom = GetEntryBoundRect(pEntry).Bottom(); + if( nBottom > nHeight ) + return 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 TRUE; + } + return 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( TRUE ); + } +} + +void SvxIconChoiceCtrl_Impl::LoseFocus() +{ + StopEditTimer(); + if( pCursor ) + pCursor->ClearFlags( ICNVIEW_FLAG_FOCUSED ); + ShowCursor( FALSE ); + +// HideFocus (); +// pView->Invalidate ( aFocus.aRect ); + + RepaintEntries( ICNVIEW_FLAG_SELECTED ); +} + +void SvxIconChoiceCtrl_Impl::SetUpdateMode( BOOL bUpdate ) +{ + if( bUpdate != bUpdateMode ) + { + bUpdateMode = bUpdate; + if( bUpdate ) + { + AdjustScrollBars(); + pImpCursor->Clear(); + pGridMap->Clear(); + pView->Invalidate(INVALIDATE_NOCHILDREN); + } + } +} + +void SvxIconChoiceCtrl_Impl::PaintEntry( SvxIconChoiceCtrlEntry* pEntry, 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, + BOOL bSelected, BOOL bDropTarget, BOOL bCursored, OutputDevice* pOut, + 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() ); + + BOOL bSolidTextRect = FALSE; + BOOL bSolidImageRect = FALSE; + + if( bDropTarget && ( eSelectionMode != NO_SELECTION ) ) + { + pOut->SetFillColor( rSettings.GetHighlightColor() ); + bSolidTextRect = TRUE; + bSolidImageRect = 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 = 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, USHORT nPaintFlags, + OutputDevice* pOut, const String* pStr, ::vcl::ControlLayoutData* _pLayoutData ) +{ + if( eItem == IcnViewFieldTypeText ) + { + String aText; + if( !pStr ) + aText = pView->GetEntryText( pEntry, 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; + USHORT 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, BOOL bIsBackgroundPainted ) +{ + if( !pOut ) + pOut = pView; + + BOOL bSelected = FALSE; + + if( eSelectionMode != NO_SELECTION ) + bSelected = pEntry->IsSelected(); + + BOOL bCursored = pEntry->IsCursored(); + BOOL bDropTarget = pEntry->IsDropTarget(); + BOOL bNoEmphasis = pEntry->IsBlockingEmphasis(); + + Font aTempFont( pOut->GetFont() ); + + // AutoFontColor + /* + if ( pView->AutoFontColor() ) + { + aTempFont.SetColor ( aFontColor ); + } + */ + + String aEntryText( pView->GetEntryText( pEntry, FALSE ) ); + Rectangle aTextRect( CalcTextRect(pEntry,&rPos,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( ); + } + + BOOL bResetClipRegion = FALSE; + if( !pView->IsClipRegion() && (aVerSBar.IsVisible() || aHorSBar.IsVisible()) ) + { + Rectangle aOutputArea( GetOutputRect() ); + if( aOutputArea.IsOver(aTextRect) || aOutputArea.IsOver(aBmpRect) ) + { + pView->SetClipRegion( aOutputArea ); + bResetClipRegion = 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) ); + USHORT nBmpPaintFlags = PAINTFLAG_VER_CENTERED; + if ( bLargeIconMode ) + nBmpPaintFlags |= PAINTFLAG_HOR_CENTERED; + USHORT 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 ), FALSE ); + + pOut->SetFont( aTempFont ); + if( bResetClipRegion ) + pView->SetClipRegion(); +} + +void SvxIconChoiceCtrl_Impl::SetEntryPos( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos, + BOOL bAdjustAtGrid, BOOL bCheckScrollBars, BOOL bKeepGridMap ) +{ + ShowCursor( FALSE ); + Rectangle aBoundRect( GetEntryBoundRect( pEntry )); + pView->Invalidate( aBoundRect ); + ToTop( pEntry ); + if( !IsAutoArrange() ) + { + BOOL bAdjustVirtSize = 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 = 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 = 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( TRUE ); +} + +void SvxIconChoiceCtrl_Impl::SetNoSelection() +{ + // rekursive Aufrufe ueber SelectEntry abblocken + if( !(nFlags & F_CLEARING_SELECTION )) + { + nFlags |= F_CLEARING_SELECTION; + DeselectAllBut( 0, TRUE ); + nFlags &= ~F_CLEARING_SELECTION; + } +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetEntry( const Point& rDocPos, BOOL bHit ) +{ + CheckBoundingRects(); + // Z-Order-Liste vom Ende her absuchen + 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 ULONG nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); + if( nStartPos != LIST_ENTRY_NOTFOUND ) + { + const ULONG nCount = pZOrderList->Count(); + for( 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; + 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, 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, 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(); + ULONG nCount = aEntries.Count(); + 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 = FALSE; + AdjustScrollBars(); +} + +void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRectsSmart() +{ + nMaxBoundHeight = 0; + pZOrderList->Clear(); + ULONG nCur; + SvxIconChoiceCtrlEntry* pEntry; + const 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 ULONG nCount = aEntries.Count(); + for( 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(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, BOOL bSyncSingleSelection, + BOOL bShowFocusAsync ) +{ + if( pEntry == pCursor ) + { + if( pCursor && eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection && + !pCursor->IsSelected() ) + SelectEntry( pCursor, TRUE, TRUE ); + return; + } + ShowCursor( FALSE ); + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + pCursor = pEntry; + if( pOldCursor ) + { + pOldCursor->ClearFlags( ICNVIEW_FLAG_FOCUSED ); + if( eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection ) + SelectEntry( pOldCursor, FALSE, TRUE ); // alten Cursor deselektieren + } + if( pCursor ) + { + ToTop( pCursor ); + pCursor->SetFlags( ICNVIEW_FLAG_FOCUSED ); + if( eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection ) + SelectEntry( pCursor, TRUE, TRUE ); + if( !bShowFocusAsync ) + ShowCursor( TRUE ); + else + { + if( !nUserEventShowCursor ) + nUserEventShowCursor = + Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl), + EVENTID_SHOW_CURSOR ); + } + } +} + + +void SvxIconChoiceCtrl_Impl::ShowCursor( 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); + } + 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 ); +} + + +BOOL SvxIconChoiceCtrl_Impl::HandleScrollCommand( const CommandEvent& rCmd ) +{ + Rectangle aDocRect( GetDocumentRect() ); + Rectangle aVisRect( GetVisibleRect() ); + if( aVisRect.IsInside( aDocRect )) + return FALSE; + Size aDocSize( aDocRect.GetSize() ); + Size aVisSize( aVisRect.GetSize() ); + BOOL bHor = aDocSize.Width() > aVisSize.Width(); + BOOL bVer = aDocSize.Height() > aVisSize.Height(); + + long nScrollDX = 0, nScrollDY = 0; + + switch( rCmd.GetCommand() ) + { + case COMMAND_STARTAUTOSCROLL: + { + pView->EndTracking(); + USHORT nScrollFlags = 0; + if( bHor ) + nScrollFlags |= AUTOSCROLL_HORZ; + if( bVer ) + nScrollFlags |= AUTOSCROLL_VERT; + if( nScrollFlags ) + { + pView->StartAutoScroll( nScrollFlags ); + return TRUE; + } + } + break; + + case COMMAND_WHEEL: + { + const CommandWheelData* pData = rCmd.GetWheelData(); + if( pData && (COMMAND_WHEEL_SCROLL == pData->GetMode()) && !pData->IsHorz() ) + { + 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 TRUE; + } + return 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 ) + { + 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 == TRUE: Das Rect wurde aufgrund eines ScrollBar-Events berechnet + +void SvxIconChoiceCtrl_Impl::MakeVisible( const Rectangle& rRect, BOOL bScrBar, + 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( FALSE ); + } + + // Origin fuer SV invertieren (damit wir in + // Dokumentkoordinaten scrollen/painten koennen) + aOrigin *= -1; + SetOrigin( aOrigin ); + + 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( 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, FALSE ); + if( !pNewCursor ) + { + pNewCursor = pImpCursor->GoLeftRight( pCursor, TRUE ); + if( !pNewCursor ) + { + pNewCursor = pImpCursor->GoUpDown( pCursor, FALSE ); + if( !pNewCursor ) + pNewCursor = pImpCursor->GoUpDown( pCursor, TRUE ); + } + } + } + else + pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.First(); + DBG_ASSERT(!pNewCursor|| (pCursor&&pCursor!=pNewCursor),"FindNewCursor failed"); + return pNewCursor; +} + +ULONG SvxIconChoiceCtrl_Impl::GetSelectionCount() const +{ + if( (nWinBits & WB_HIGHLIGHTFRAME) && pCurHighlightFrame ) + return 1; + return nSelectionCount; +} + +void SvxIconChoiceCtrl_Impl::ToggleSelection( SvxIconChoiceCtrlEntry* pEntry ) +{ + BOOL bSel; + if( pEntry->IsSelected() ) + bSel = FALSE; + else + bSel = TRUE; + SelectEntry( pEntry, bSel, TRUE, TRUE ); +} + +void SvxIconChoiceCtrl_Impl::DeselectAllBut( SvxIconChoiceCtrlEntry* pThisEntryNot, + BOOL bPaintSync ) +{ + ClearSelectedRectList(); + // + // !!!!!!! Todo: Evtl. Z-Orderlist abarbeiten !!!!!!! + // + ULONG nCount = aEntries.Count(); + for( ULONG nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + if( pEntry != pThisEntryNot && pEntry->IsSelected() ) + SelectEntry( pEntry, FALSE, TRUE, 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, 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, + 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, BOOL bAdd, + SvPtrarr* pOtherRects ) +{ + aCurSelectionRect = rRect; + if( !pZOrderList || !pZOrderList->Count() ) + return; + + // Flag setzen, damit im Select kein ToTop gerufen wird + BOOL bAlreadySelectingRect = nFlags & F_SELECTING_RECT ? TRUE : FALSE; + nFlags |= F_SELECTING_RECT; + + CheckBoundingRects(); + pView->Update(); + const ULONG nCount = pZOrderList->Count(); + + Rectangle aRect( rRect ); + aRect.Justify(); + BOOL bCalcOverlap = (bAdd && pOtherRects && pOtherRects->Count()) ? TRUE : FALSE; + + BOOL bResetClipRegion = FALSE; + if( !pView->IsClipRegion() ) + { + bResetClipRegion = TRUE; + pView->SetClipRegion( GetOutputRect() ); + } + + for( ULONG nPos = 0; nPos < nCount; nPos++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nPos )); + + if( !IsBoundingRectValid( pEntry->aRect )) + FindBoundingRect( pEntry ); + Rectangle aBoundRect( GetHotSpot( pEntry->aRect ) ); + BOOL bSelected = pEntry->IsSelected(); + + BOOL bOverlaps; + if( bCalcOverlap ) + bOverlaps = IsOver( pOtherRects, aBoundRect ); + else + bOverlaps = FALSE; + BOOL bOver = aRect.IsOver( aBoundRect ); + + if( bOver && !bOverlaps ) + { + // Ist im neuen Selektionsrechteck und in keinem alten + // => selektieren + if( !bSelected ) + SelectEntry( pEntry, TRUE, TRUE, TRUE ); + } + else if( !bAdd ) + { + // ist ausserhalb des Selektionsrechtecks + // => Selektion entfernen + if( bSelected ) + SelectEntry( pEntry, FALSE, TRUE, 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, FALSE, TRUE, TRUE ); + } + else + { + // Eintrag eines alten Rects selektieren + if( !bSelected ) + SelectEntry( pEntry, TRUE, TRUE, TRUE ); + } + } + else if( !bOver && bSelected ) + { + // Der Eintrag liegt voellig ausserhalb und wird deshalb desel. + SelectEntry( pEntry, FALSE, TRUE, TRUE ); + } + } + + if( !bAlreadySelectingRect ) + nFlags &= ~F_SELECTING_RECT; + + pView->Update(); + if( bResetClipRegion ) + pView->SetClipRegion(); +} + +void SvxIconChoiceCtrl_Impl::SelectRange( + SvxIconChoiceCtrlEntry* pStart, + SvxIconChoiceCtrlEntry* pEnd, + BOOL bAdd ) +{ + ULONG nFront = GetEntryListPos( pStart ); + ULONG nBack = GetEntryListPos( pEnd ); + ULONG nFirst = std::min( nFront, nBack ); + ULONG nLast = std::max( nFront, nBack ); + 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, FALSE, TRUE, TRUE, TRUE ); + } + } + + // select everything between nFirst and nLast + for ( i=nFirst; i<=nLast; i++ ) + { + pEntry = GetEntry( i ); + if( ! pEntry->IsSelected() ) + SelectEntry( pEntry, TRUE, TRUE, TRUE, TRUE ); + } + + if ( ! bAdd ) + { + // deselect everything behind the last entry if not in + // adding mode + ULONG nEnd = GetEntryCount(); + for ( ; i<nEnd; i++ ) + { + pEntry = GetEntry( i ); + if( pEntry->IsSelected() ) + SelectEntry( pEntry, FALSE, TRUE, TRUE, TRUE ); + } + } +} + +BOOL SvxIconChoiceCtrl_Impl::IsOver( SvPtrarr* pRectList, const Rectangle& rBoundRect ) const +{ + const USHORT nCount = pRectList->Count(); + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + Rectangle* pRect = (Rectangle*)pRectList->GetObject( nCur ); + if( rBoundRect.IsOver( *pRect )) + return TRUE; + } + return 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 USHORT nCount = aSelectedRectList.Count(); + for( USHORT 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, BOOL isInDragDrop, USHORT nBorderWidth) +{ + // Scrolling der View, falls sich der Mauszeiger im Grenzbereich des + // Fensters befindet + long nPixelToScrollX = 0; + long nPixelToScrollY = 0; + Size aWndSize = aOutputSize; + + nBorderWidth = (USHORT)(Min( (long)(aWndSize.Height()-1), (long)nBorderWidth )); + nBorderWidth = (USHORT)(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, TRUE, TRUE ); + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); +} + +BOOL SvxIconChoiceCtrl_Impl::IsTextHit( SvxIconChoiceCtrlEntry* pEntry, const Point& rDocPos ) +{ + Rectangle aRect( CalcTextRect( pEntry )); + if( aRect.IsInside( rDocPos ) ) + return TRUE; + return 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 USHORT nCount = aLists.Count(); + for( USHORT 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; + + BOOL bGo; + if( !pStart ) + bGo = TRUE; + else + bGo = FALSE; + + long nCurRight = 0; + for( USHORT nCur = 0; nCur < rRow.Count(); nCur++ ) + { + SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)rRow[ nCur ]; + if( !bGo && pCur == pStart ) + bGo = 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( 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; + USHORT nColor = ( aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue() ) / 3; + if ( nColor > 128 ) + aPenColor.SetColor ( COL_BLACK ); + else + aPenColor.SetColor( COL_WHITE ); + + aFocus.bOn = TRUE; + aFocus.aPenColor = aPenColor; + aFocus.aRect = rRect; +} + +void SvxIconChoiceCtrl_Impl::HideFocus () +{ + aFocus.bOn = 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, ULONG& rPos ) const +{ + sal_Bool bRet = sal_False; + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + ULONG nEntryCount = GetEntryCount(); + for ( 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( 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( FALSE ); + pView->Invalidate( pEntry->aRect ); + Center( pEntry ); + pView->Invalidate( pEntry->aRect ); + if( pEntry == pCursor ) + ShowCursor( TRUE ); +} + +void SvxIconChoiceCtrl_Impl::EditEntry( SvxIconChoiceCtrlEntry* pEntry ) +{ + DBG_ASSERT(pEntry,"EditEntry: Entry not set"); + if( !pEntry ) + return; + + StopEntryEditing( TRUE ); + DELETEZ(pEdit); + SetNoSelection(); + + pCurEditedEntry = pEntry; + String aEntryText( pView->GetEntryText( pEntry, TRUE ) ); + Rectangle aRect( CalcTextRect( pEntry, 0, 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, 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( BOOL bCancel ) +{ + if( pEdit ) + pEdit->StopEditing( bCancel ); +} + +void SvxIconChoiceCtrl_Impl::LockEntryPos( SvxIconChoiceCtrlEntry* pEntry, BOOL bLock ) +{ + if( bLock ) + pEntry->SetFlags( ICNVIEW_FLAG_POS_LOCKED ); + else + pEntry->ClearFlags( ICNVIEW_FLAG_POS_LOCKED ); +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry( ULONG& rPos ) const +{ + if( !GetSelectionCount() ) + return 0; + + if( (nWinBits & WB_HIGHLIGHTFRAME) && (eSelectionMode == NO_SELECTION) ) + { + rPos = pView->GetEntryListPos( pCurHighlightFrame ); + return pCurHighlightFrame; + } + + ULONG nCount = aEntries.Count(); + if( !pHead ) + { + for( 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( ULONG& rStartPos ) const +{ + ULONG nCount = aEntries.Count(); + if( rStartPos > nCount || !GetSelectionCount() ) + return 0; + if( !pHead ) + { + for( 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( BOOL bSelect, BOOL bPaint ) +{ + bPaint = TRUE; + + ULONG nCount = aEntries.Count(); + for( ULONG nCur = 0; nCur < nCount && (bSelect || GetSelectionCount() ); nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + SelectEntry( pEntry, bSelect, TRUE, TRUE, bPaint ); + } + nFlags &= (~F_ADD_MODE); + pAnchor = 0; +} + +void SvxIconChoiceCtrl_Impl::SaveSelection( List** ppList ) +{ + if( !*ppList ) + *ppList = new List; + 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( FALSE ), + bAlreadyInCallback( FALSE ), + bGrabFocus( FALSE ) +{ + Font aFont( pParent->GetPointFont() ); + aFont.SetTransparent( 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 = 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 = FALSE; + bGrabFocus = TRUE; + CallCallBackHdl_Impl(); + return 1; +} + +IMPL_LINK( IcnViewEdit_Impl, EscapeHdl_Impl, Accelerator*, EMPTYARG ) +{ + bCanceled = TRUE; + bGrabFocus = TRUE; + CallCallBackHdl_Impl(); + return 1; +} + +void IcnViewEdit_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + KeyCode aCode = rKEvt.GetKeyCode(); + USHORT nCode = aCode.GetCode(); + + switch ( nCode ) + { + case KEY_ESCAPE: + bCanceled = TRUE; + bGrabFocus = TRUE; + CallCallBackHdl_Impl(); + break; + + case KEY_RETURN: + bCanceled = FALSE; + bGrabFocus = 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 = FALSE; + aTimer.SetTimeout(10); + aTimer.SetTimeoutHdl(LINK(this,IcnViewEdit_Impl,Timeout_Impl)); + aTimer.Start(); + } + } + return 0; +} + +void IcnViewEdit_Impl::StopEditing( BOOL bCancel ) +{ + if ( !bAlreadyInCallback ) + { + bCanceled = bCancel; + CallCallBackHdl_Impl(); + } +} + +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, ULONG nNewPos ) +{ + ULONG nCurPos = GetEntryListPos( pListEntry ); + if( nCurPos == nNewPos ) + return; + aEntries.List::Remove( nCurPos ); + aEntries.List::Insert( (void*)pListEntry, nNewPos ); + // Eintragspositionen anpassen + 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, USHORT nEntryFlags ) +{ + pEntry->nFlags = nEntryFlags; + if( nEntryFlags & ICNVIEW_FLAG_POS_MOVED ) + nFlags |= F_MOVED_ENTRIES; +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GoLeftRight( SvxIconChoiceCtrlEntry* pStart, BOOL bRight ) +{ + return pImpCursor->GoLeftRight( pStart, bRight ); +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GoUpDown( SvxIconChoiceCtrlEntry* pStart, 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, USHORT _nInitSize , USHORT _nReSize ) : + List( _nInitSize, _nReSize ), + _pOwner( pOwner ) +{ + _pOwner->pHead = 0; +} + +EntryList_Impl::EntryList_Impl( SvxIconChoiceCtrl_Impl* pOwner, USHORT _nBlockSize, USHORT _nInitSize, USHORT _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, ULONG nPos ) +{ + List::Insert( pEntry, nPos ); + if( _pOwner->pHead ) + pEntry->SetBacklink( _pOwner->pHead->pblink ); +} + +SvxIconChoiceCtrlEntry* EntryList_Impl::Remove( 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 ) +{ + ULONG nCur; + + if( eMode == ePositionMode ) + return; + + SvxIconChoiceCtrlPositionMode eOldMode = ePositionMode; + ePositionMode = eMode; + 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; + + ULONG nPos1 = GetEntryListPos( pEntry ); + if( !pHead ) + { + if( pPredecessor ) + { + 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 + + BOOL bSetHead = FALSE; + if( !pPredecessor ) + { + bSetHead = TRUE; + pPredecessor = pHead->pblink; + } + if( pEntry == pHead ) + { + pHead = pHead->pflink; + bSetHead = FALSE; + } + if( pEntry != pPredecessor ) + { + pEntry->Unlink(); + pEntry->SetBacklink( pPredecessor ); + } + if( bSetHead ) + pHead = pEntry; + pEntry->SetFlags( ICNVIEW_FLAG_PRED_SET ); + aAutoArrangeTimer.Start(); +} + +BOOL SvxIconChoiceCtrl_Impl::GetEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry, + SvxIconChoiceCtrlEntry** ppPredecessor ) +{ + *ppPredecessor = 0; + if( !pHead ) + return 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 TRUE; + return FALSE; + } + *ppPredecessor = pEntry->pblink; + if( !(pEntry->nFlags & ICNVIEW_FLAG_PRED_SET) && + (GetEntryListPos( *ppPredecessor ) + 1) == GetEntryListPos( pEntry )) + return FALSE; + return TRUE; +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::FindEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry, + const Point& rPosTopLeft ) +{ + Point aPos( rPosTopLeft ); //TopLeft + Rectangle aCenterRect( CalcBmpRect( pEntry, &aPos )); + Point aNewPos( aCenterRect.Center() ); + ULONG nGrid = GetPredecessorGrid( aNewPos ); + 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( ULONG nCur = 0; nCur < nGrid; nCur++ ) + pCur = pCur->pflink; + + return pCur; +} + +ULONG SvxIconChoiceCtrl_Impl::GetPredecessorGrid( const Point& rPos) const +{ + Point aPos( rPos ); + aPos.X() -= LROFFS_WINBORDER; + aPos.Y() -= TBOFFS_WINBORDER; + USHORT nMaxCol = (USHORT)(aVirtOutputSize.Width() / nGridDX); + if( nMaxCol ) + nMaxCol--; + USHORT nGridX = (USHORT)(aPos.X() / nGridDX); + if( nGridX > nMaxCol ) + nGridX = nMaxCol; + USHORT nGridY = (USHORT)(aPos.Y() / nGridDY); + USHORT nGridsX = (USHORT)(aOutputSize.Width() / nGridDX); + 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 ); + } +} + +BOOL SvxIconChoiceCtrl_Impl::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( !(rHEvt.GetMode() & HELPMODE_QUICK ) ) + return FALSE; + + Point aPos( pView->ScreenToOutputPixel(rHEvt.GetMousePosPixel() ) ); + aPos -= pView->GetMapMode().GetOrigin(); + SvxIconChoiceCtrlEntry* pEntry = GetEntry( aPos, TRUE ); + + if ( !pEntry ) + return FALSE; + + String sQuickHelpText = pEntry->GetQuickHelpText(); + String aEntryText( pView->GetEntryText( pEntry, FALSE ) ); + Rectangle aTextRect( CalcTextRect( pEntry, 0, FALSE, &aEntryText ) ); + if ( ( !aTextRect.IsInside( aPos ) || !aEntryText.Len() ) && !sQuickHelpText.Len() ) + return FALSE; + + Rectangle aOptTextRect( aTextRect ); + aOptTextRect.Bottom() = LONG_MAX; + USHORT 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 TRUE; +} + +void SvxIconChoiceCtrl_Impl::ClearColumnList() +{ + if( !pColumns ) + return; + + const USHORT nCount = pColumns->Count(); + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlColumnInfo* pInfo = (SvxIconChoiceCtrlColumnInfo*) + pColumns->GetObject( nCur ); + delete pInfo; + } + DELETEZ(pColumns); +} + +void SvxIconChoiceCtrl_Impl::SetColumn( USHORT 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( USHORT nIndex ) const +{ + if( !pColumns || nIndex >= pColumns->Count() ) + return 0; + return (const SvxIconChoiceCtrlColumnInfo*)pColumns->GetObject( nIndex ); +} + +const SvxIconChoiceCtrlColumnInfo* SvxIconChoiceCtrl_Impl::GetItemColumn( USHORT nSubItem, + long& rLeft ) const +{ + rLeft = 0; + if( !pColumns ) + return 0; + const USHORT nCount = pColumns->Count(); + const SvxIconChoiceCtrlColumnInfo* pCol = 0; + for( USHORT 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, 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 ); + USHORT 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, + BOOL bKeepHighlightFlags ) +{ + if( pEntry == pCurHighlightFrame ) + return; + + if( !bKeepHighlightFlags ) + bHighlightFramePressed = FALSE; + + HideEntryHighlightFrame(); + pCurHighlightFrame = pEntry; + if( pEntry ) + { + Rectangle aBmpRect( CalcFocusRect(pEntry) ); + DrawHighlightFrame( pView, aBmpRect, FALSE ); + } +} + +void SvxIconChoiceCtrl_Impl::HideEntryHighlightFrame() +{ + if( !pCurHighlightFrame ) + return; + + SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame; + pCurHighlightFrame = 0; + Rectangle aBmpRect( CalcFocusRect(pEntry) ); + DrawHighlightFrame( pView, aBmpRect, 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() ) + { + 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, BOOL bDoNotUpdateWallpaper ) +{ + MapMode aMapMode( pView->GetMapMode() ); + aMapMode.SetOrigin( rPos ); + pView->SetMapMode( aMapMode ); + if( !bDoNotUpdateWallpaper ) + { + BOOL bScrollable = pView->GetBackground().IsScrollable(); + if( pView->HasBackground() && !bScrollable ) + { + Rectangle aRect( GetOutputRect()); + Wallpaper aPaper( pView->GetBackground() ); + aPaper.SetRect( aRect ); + pView->SetBackground( aPaper ); + } + } +} + +ULONG SvxIconChoiceCtrl_Impl::GetGridCount( const Size& rSize, BOOL bCheckScrBars, + 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, (USHORT)nGridDX, (USHORT)nGridDY ); +} + +BOOL SvxIconChoiceCtrl_Impl::HandleShortCutKey( const KeyEvent& rKEvt ) +{ + StopEditTimer(); + + BOOL bRet = FALSE; + + DBG_ASSERT( rKEvt.GetKeyCode().IsMod2(), "*SvxIconChoiceCtrl_Impl::HandleShortCutKey(): no <ALT> pressed!?" ); + + sal_Unicode cChar = rKEvt.GetCharCode(); + ULONG nPos = (ULONG)-1; + + if( cChar && IsMnemonicChar( cChar, nPos ) ) + { + // shortcut is clicked + SvxIconChoiceCtrlEntry* pNewCursor = GetEntry( nPos ); + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + if( pNewCursor != pOldCursor ) + { + SetCursor_Impl( pOldCursor, pNewCursor, FALSE, FALSE, FALSE ); + + if( pNewCursor != NULL ) + { + pHdlEntry = pNewCursor; + pCurHighlightFrame = pHdlEntry; + pView->ClickIcon(); + pCurHighlightFrame = NULL; + } + } + bRet = TRUE; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +void SvxIconChoiceCtrl_Impl::CallEventListeners( ULONG nEvent, void* pData ) +{ + pView->CallImplEventListeners( nEvent, pData ); +} + + |