blob: a8f1e0f39222012c3791a170d6d065629cd75c9e [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"
#include <limits.h>
#ifndef _METRIC_HXX
#include <vcl/metric.hxx>
#endif
#include <vcl/svapp.hxx>
#ifdef DBG_UTIL
#include <vcl/sound.hxx>
#endif
#include <svtools/svlbox.hxx>
#include <svtools/svicnvw.hxx>
#include <svimpicn.hxx>
#ifndef _SVLBITM_HXX
#include <svtools/svlbitm.hxx>
#endif
#include <svl/svarray.hxx>
#define VIEWMODE_ICON 0x0001 // Text unter Bitmap
#define VIEWMODE_NAME 0x0002 // Text rechts neben Bitmap
#define VIEWMODE_TEXT 0x0004 // Text ohne Bitmap
#define DD_SCROLL_PIXEL 10
// alle Angaben in Pixel
#define ICONVIEW_OFFS_BMP_STRING 3
// fuer das Bounding-Rectangle
#define LROFFS_BOUND 2
#define TBOFFS_BOUND 2
// fuer das Focus-Rectangle um Icons
#define LROFFS_ICON 2
#define TBOFFS_ICON 2
#define NAMEVIEW_OFFS_BMP_STRING 3
// Abstaende von Fensterraendern
#define LROFFS_WINBORDER 4
#define TBOFFS_WINBORDER 4
// Breitenoffset Highlight-Rect bei Text
#define LROFFS_TEXT 2
#define ICNVIEWDATA(xPtr) (SvIcnVwDataEntry*)(pView->GetViewDataEntry(xPtr))
#define ICNVIEWDATA2(xPtr) (SvIcnVwDataEntry*)(pView->pView->GetViewDataEntry(xPtr))
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// -------------------------------------------------------------------------
// Hilfsfunktionen von Thomas Hosemann zur mehrzeiligen Ausgabe von
// Strings. Die Funktionen werden spaeter in StarView integriert.
// -------------------------------------------------------------------------
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// keine doppelten Defines
#ifdef TEXT_DRAW_CLIP
#undef TEXT_DRAW_CLIP
#endif
#ifdef TEXT_DRAW_MULTILINE
#undef TEXT_DRAW_MULTILINE
#endif
#ifdef TEXT_DRAW_WORDBREAK
#undef TEXT_DRAW_WORDBREAK
#endif
// #define TEXT_DRAW_DISABLE ((sal_uInt16)0x0001)
// #define TEXT_DRAW_3DLOOK ((sal_uInt16)0x0002)
// #define TEXT_DRAW_MNEMONIC ((sal_uInt16)0x0004)
#define TEXT_DRAW_LEFT ((sal_uInt16)0x0010)
#define TEXT_DRAW_CENTER ((sal_uInt16)0x0020)
#define TEXT_DRAW_RIGHT ((sal_uInt16)0x0040)
#define TEXT_DRAW_TOP ((sal_uInt16)0x0080)
#define TEXT_DRAW_VCENTER ((sal_uInt16)0x0100)
#define TEXT_DRAW_BOTTOM ((sal_uInt16)0x0200)
#define TEXT_DRAW_ENDELLIPSIS ((sal_uInt16)0x0400)
#define TEXT_DRAW_PATHELLIPSIS ((sal_uInt16)0x0800)
#define TEXT_DRAW_CLIP ((sal_uInt16)0x1000)
#define TEXT_DRAW_MULTILINE ((sal_uInt16)0x2000)
#define TEXT_DRAW_WORDBREAK ((sal_uInt16)0x4000)
XubString GetEllipsisString( OutputDevice* pDev,
const XubString& rStr, long nMaxWidth,
sal_uInt16 nStyle = TEXT_DRAW_ENDELLIPSIS )
{
XubString aStr = rStr;
if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
{
sal_uInt16 nIndex = pDev->GetTextBreak( rStr, nMaxWidth );
if ( nIndex != STRING_LEN )
{
aStr.Erase( nIndex );
if ( nIndex > 1 )
{
aStr.AppendAscii("...");
while ( aStr.Len() &&
(pDev->GetTextWidth( aStr ) > nMaxWidth) )
{
if ( (nIndex > 1) || (nIndex == aStr.Len()) )
nIndex--;
aStr.Erase( nIndex, 1 );
}
}
if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) )
aStr += rStr.GetChar( 0 );
}
}
return aStr;
}
class TextLineInfo
{
private:
long mnWidth;
sal_uInt16 mnIndex;
sal_uInt16 mnLen;
public:
TextLineInfo( long nWidth, sal_uInt16 nIndex, sal_uInt16 nLen )
{
mnWidth = nWidth;
mnIndex = nIndex;
mnLen = nLen;
}
long GetWidth() const { return mnWidth; }
sal_uInt16 GetIndex() const { return mnIndex; }
sal_uInt16 GetLen() const { return mnLen; }
};
#define MULTITEXTLINEINFO_RESIZE 16
typedef TextLineInfo* PTextLineInfo;
class MultiTextLineInfo
{
private:
PTextLineInfo* mpLines;
sal_uInt16 mnLines;
sal_uInt16 mnSize;
public:
MultiTextLineInfo();
~MultiTextLineInfo();
void AddLine( TextLineInfo* pLine );
void Clear();
TextLineInfo* GetLine( sal_uInt16 nLine ) const
{ return mpLines[nLine]; }
sal_uInt16 Count() const { return mnLines; }
private:
MultiTextLineInfo( const MultiTextLineInfo& );
MultiTextLineInfo& operator=( const MultiTextLineInfo& );
};
MultiTextLineInfo::MultiTextLineInfo()
{
mpLines = new PTextLineInfo[MULTITEXTLINEINFO_RESIZE];
mnLines = 0;
mnSize = MULTITEXTLINEINFO_RESIZE;
}
MultiTextLineInfo::~MultiTextLineInfo()
{
for ( sal_uInt16 i = 0; i < mnLines; i++ )
delete mpLines[i];
delete [] mpLines;
}
void MultiTextLineInfo::AddLine( TextLineInfo* pLine )
{
if ( mnSize == mnLines )
{
mnSize += MULTITEXTLINEINFO_RESIZE;
PTextLineInfo* pNewLines = new PTextLineInfo[mnSize];
memcpy( pNewLines, mpLines, mnLines*sizeof(PTextLineInfo) );
mpLines = pNewLines;
}
mpLines[mnLines] = pLine;
mnLines++;
}
void MultiTextLineInfo::Clear()
{
for ( sal_uInt16 i = 0; i < mnLines; i++ )
delete mpLines[i];
mnLines = 0;
}
// -----------------------------------------------------------------------
long GetTextLines( OutputDevice* pDev, MultiTextLineInfo& rLineInfo,
long nWidth, const XubString& rStr,
sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK )
{
rLineInfo.Clear();
if ( !rStr.Len() )
return 0;
if ( nWidth <= 0 )
nWidth = 1;
sal_uInt16 nStartPos = 0; // Start-Position der Zeile
sal_uInt16 nLastLineLen = 0; // Zeilenlaenge bis zum vorherigen Wort
sal_uInt16 nLastWordPos = 0; // Position des letzten Wortanfangs
sal_uInt16 i = 0;
sal_uInt16 nPos; // StartPositon der Zeile (nur Temp)
sal_uInt16 nLen; // Laenge der Zeile (nur Temp)
sal_uInt16 nStrLen = rStr.Len();
long nMaxLineWidth = 0; // Maximale Zeilenlaenge
long nLineWidth; // Aktuelle Zeilenlaenge
long nLastLineWidth = 0; // Zeilenlaenge der letzten Zeile
xub_Unicode c;
xub_Unicode c2;
const xub_Unicode* pStr = rStr.GetBuffer();
sal_Bool bHardBreak = sal_False;
do
{
c = pStr[i];
// Auf Zeilenende ermitteln
if ( (c == _CR) || (c == _LF) )
bHardBreak = sal_True;
else
bHardBreak = sal_False;
// Testen, ob ein Wortende erreicht ist
if ( bHardBreak || (i == nStrLen) ||
(((c == ' ') || (c == '-')) && (nStyle & TEXT_DRAW_WORDBREAK)) )
{
nLen = i-nStartPos;
if ( c == '-' )
nLen++;
nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLen );
// Findet ein Zeilenumbruch statt
if ( bHardBreak || (i == nStrLen) ||
((nLineWidth >= nWidth) && (nStyle & TEXT_DRAW_WORDBREAK)) )
{
nPos = nStartPos;
if ( (nLineWidth >= nWidth) && (nStyle & TEXT_DRAW_WORDBREAK) )
{
nLineWidth = nLastLineWidth;
nLen = nLastLineLen;
nStartPos = nLastWordPos;
nLastLineLen = i-nStartPos;
nLastWordPos = nStartPos+nLastLineLen+1;
if ( c == '-' )
nLastLineLen++;
else if ( bHardBreak && (i > nStartPos) )
i--;
}
else
{
nStartPos = i;
// Zeilenende-Zeichen und '-' beruecksichtigen
if ( bHardBreak )
{
nStartPos++;
c2 = pStr[i+1];
if ( (c != c2) && ((c2 == _CR) || (c2 == _LF)) )
{
nStartPos++;
i++;
}
}
else if ( c != '-' )
nStartPos++;
nLastWordPos = nStartPos;
nLastLineLen = 0;
}
if ( nLineWidth > nMaxLineWidth )
nMaxLineWidth = nLineWidth;
if ( nLen || bHardBreak )
rLineInfo.AddLine( new TextLineInfo( nLineWidth, nPos, nLen ) );
// Testen, ob aktuelles Wort noch auf die Zeile passt,
// denn ansonsten mueessen wir es auftrennen
if ( nLastLineLen )
{
nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLastLineLen );
if ( nLineWidth > nWidth )
{
// Wenn ein Wortumbruch in einem Wort stattfindet,
// ist die maximale Zeilenlaenge die Laenge
// des laengsten Wortes
if ( nLineWidth > nMaxLineWidth )
nMaxLineWidth = nLineWidth;
// Solange Wort auftrennen, bis es auf eine Zeile passt
do
{
nPos = pDev->GetTextBreak( rStr, nWidth, nStartPos, nLastLineLen );
nLen = nPos-nStartPos;
if ( !nLen )
{
nPos++;
nLen++;
}
nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLen );
rLineInfo.AddLine( new TextLineInfo( nLineWidth, nStartPos, nLen ) );
nStartPos = nPos;
nLastLineLen = nLastLineLen - nLen;
nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLastLineLen );
}
while ( nLineWidth > nWidth );
}
nLastLineWidth = nLineWidth;
// Bei Stringende muessen wir die letzte Zeile auch noch
// dranhaengen
if ( (i == nStrLen) && nLastLineLen )
rLineInfo.AddLine( new TextLineInfo( nLastLineWidth, nStartPos, nLastLineLen ) );
}
else
nLastLineWidth = 0;
}
else
{
nLastLineWidth = nLineWidth;
nLastLineLen = nLen;
nLastWordPos = nStartPos+nLastLineLen;
if ( c != '-' )
nLastWordPos++;
}
}
i++;
}
while ( i <= nStrLen );
return nMaxLineWidth;
}
// -----------------------------------------------------------------------
sal_uInt16 GetTextLines( OutputDevice* pDev, const Rectangle& rRect,
const XubString& rStr,
sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK,
long* pMaxWidth = NULL )
{
MultiTextLineInfo aMultiLineInfo;
long nMaxWidth = GetTextLines( pDev, aMultiLineInfo,
rRect.GetWidth(), rStr, nStyle );
if ( pMaxWidth )
*pMaxWidth = nMaxWidth;
return aMultiLineInfo.Count();
}
// -----------------------------------------------------------------------
Rectangle GetTextRect( OutputDevice* pDev, const Rectangle& rRect,
const XubString& rStr,
sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK )
{
Rectangle aRect = rRect;
sal_uInt16 nLines;
long nWidth = rRect.GetWidth();
long nMaxWidth;
long nTextHeight;
if ( nStyle & TEXT_DRAW_MULTILINE )
{
MultiTextLineInfo aMultiLineInfo;
TextLineInfo* pLineInfo;
sal_uInt16 nFormatLines;
nMaxWidth = 0;
GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle );
nFormatLines = aMultiLineInfo.Count();
nTextHeight = pDev->GetTextHeight();
nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight);
if ( nFormatLines <= nLines )
nLines = nFormatLines;
else
{
if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
nLines = nFormatLines;
else
nMaxWidth = nWidth;
}
for ( sal_uInt16 i = 0; i < nLines; i++ )
{
pLineInfo = aMultiLineInfo.GetLine( i );
if ( pLineInfo->GetWidth() > nMaxWidth )
nMaxWidth = pLineInfo->GetWidth();
}
}
else
{
nLines = 1;
nMaxWidth = pDev->GetTextWidth( rStr );
nTextHeight = pDev->GetTextHeight();
if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ENDELLIPSIS) )
nMaxWidth = nWidth;
}
if ( nStyle & TEXT_DRAW_RIGHT )
aRect.Left() = aRect.Right()-nMaxWidth+1;
else if ( nStyle & TEXT_DRAW_CENTER )
{
aRect.Left() += (nWidth-nMaxWidth)/2;
aRect.Right() = aRect.Left()+nMaxWidth-1;
}
else
aRect.Right() = aRect.Left()+nMaxWidth-1;
if ( nStyle & TEXT_DRAW_BOTTOM )
aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
else if ( nStyle & TEXT_DRAW_VCENTER )
{
aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2;
aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
}
else
aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
return aRect;
}
// -----------------------------------------------------------------------
void DrawText( OutputDevice* pDev, const Rectangle& rRect,
const XubString& rStr, sal_uInt16 nStyle = 0 )
{
if ( !rStr.Len() || rRect.IsEmpty() )
return;
Point aPos = rRect.TopLeft();
long nWidth = rRect.GetWidth();
long nHeight = rRect.GetHeight();
FontAlign eAlign = pDev->GetFont().GetAlign();
if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
return;
// Mehrzeiligen Text behandeln wir anders
if ( nStyle & TEXT_DRAW_MULTILINE )
{
String aLastLine;
Region aOldRegion;
MultiTextLineInfo aMultiLineInfo;
TextLineInfo* pLineInfo;
long nTextHeight = pDev->GetTextHeight();
long nMaxTextWidth;
sal_uInt16 i;
sal_uInt16 nLines = (sal_uInt16)(nHeight/nTextHeight);
sal_uInt16 nFormatLines;
sal_Bool bIsClipRegion = sal_False;
nMaxTextWidth = GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle );
nFormatLines = aMultiLineInfo.Count();
if ( nFormatLines > nLines )
{
if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
{
// Letzte Zeile zusammenbauen und kuerzen
nFormatLines = nLines-1;
pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
aLastLine = rStr.Copy( pLineInfo->GetIndex() );
aLastLine.ConvertLineEnd( LINEEND_LF );
aLastLine.SearchAndReplace( _LF, ' ' );
aLastLine = GetEllipsisString( pDev, aLastLine, nWidth, nStyle );
nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
nStyle |= TEXT_DRAW_TOP;
}
}
else
{
if ( nMaxTextWidth <= nWidth )
nStyle &= ~TEXT_DRAW_CLIP;
}
// Clipping setzen
if ( nStyle & TEXT_DRAW_CLIP )
{
bIsClipRegion = pDev->IsClipRegion();
if ( bIsClipRegion )
{
aOldRegion = pDev->GetClipRegion();
pDev->IntersectClipRegion( rRect );
}
else
{
Region aRegion( rRect );
pDev->SetClipRegion( aRegion );
}
}
// Vertikales Alignment
if ( nStyle & TEXT_DRAW_BOTTOM )
aPos.Y() += nHeight-(nFormatLines*nTextHeight);
else if ( nStyle & TEXT_DRAW_VCENTER )
aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
// Font Alignment
if ( eAlign == ALIGN_BOTTOM )
aPos.Y() += nTextHeight;
else if ( eAlign == ALIGN_BASELINE )
aPos.Y() += pDev->GetFontMetric().GetAscent();
// Alle Zeilen ausgeben, bis auf die letzte
for ( i = 0; i < nFormatLines; i++ )
{
pLineInfo = aMultiLineInfo.GetLine( i );
if ( nStyle & TEXT_DRAW_RIGHT )
aPos.X() += nWidth-pLineInfo->GetWidth();
else if ( nStyle & TEXT_DRAW_CENTER )
aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
pDev->DrawText( aPos, rStr, pLineInfo->GetIndex(), pLineInfo->GetLen() );
aPos.Y() += nTextHeight;
aPos.X() = rRect.Left();
}
// Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
// da die Zeile gekuerzt wurde
if ( aLastLine.Len() )
pDev->DrawText( aPos, aLastLine );
// Clipping zuruecksetzen
if ( nStyle & TEXT_DRAW_CLIP )
{
if ( bIsClipRegion )
pDev->SetClipRegion( aOldRegion );
else
pDev->SetClipRegion();
}
}
else
{
XubString aStr = rStr;
Size aTextSize(pDev->GetTextWidth( aStr ), pDev->GetTextHeight());
// Evt. Text kuerzen
if ( aTextSize.Width() > nWidth )
{
if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
{
aStr = GetEllipsisString( pDev, rStr, nWidth, nStyle );
nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
nStyle |= TEXT_DRAW_LEFT;
aTextSize.Width() = pDev->GetTextWidth(aStr);
}
}
else
{
if ( aTextSize.Height() <= nHeight )
nStyle &= ~TEXT_DRAW_CLIP;
}
// Vertikales Alignment
if ( nStyle & TEXT_DRAW_RIGHT )
aPos.X() += nWidth-aTextSize.Width();
else if ( nStyle & TEXT_DRAW_CENTER )
aPos.X() += (nWidth-aTextSize.Width())/2;
// Font Alignment
if ( eAlign == ALIGN_BOTTOM )
aPos.Y() += aTextSize.Height();
else if ( eAlign == ALIGN_BASELINE )
aPos.Y() += pDev->GetFontMetric().GetAscent();
if ( nStyle & TEXT_DRAW_BOTTOM )
aPos.Y() += nHeight-aTextSize.Height();
else if ( nStyle & TEXT_DRAW_VCENTER )
aPos.Y() += (nHeight-aTextSize.Height())/2;
if ( nStyle & TEXT_DRAW_CLIP )
{
sal_Bool bIsClipRegion = pDev->IsClipRegion();
if ( bIsClipRegion )
{
Region aOldRegion = pDev->GetClipRegion();
pDev->IntersectClipRegion( rRect );
pDev->DrawText( aPos, aStr );
pDev->SetClipRegion( aOldRegion );
}
else
{
Region aRegion( rRect );
pDev->SetClipRegion( aRegion );
pDev->DrawText( aPos, aStr );
pDev->SetClipRegion();
}
}
else
pDev->DrawText( aPos, aStr );
}
}
// -----------------------------------------------------------------------
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
#define DRAWTEXT_FLAGS (TEXT_DRAW_CENTER|TEXT_DRAW_TOP|TEXT_DRAW_ENDELLIPSIS|\
TEXT_DRAW_CLIP|TEXT_DRAW_MULTILINE|TEXT_DRAW_WORDBREAK)
class ImpIcnCursor
{
SvImpIconView* pView;
SvPtrarr* pColumns;
SvPtrarr* pRows;
sal_Bool* pGridMap;
long nGridDX, nGridDY;
long nGridCols, nGridRows;
long nCols;
long nRows;
short nDeltaWidth;
short nDeltaHeight;
SvLBoxEntry* pCurEntry;
void SetDeltas();
void ImplCreate();
void Create() { if( !pColumns ) ImplCreate(); }
sal_uInt16 GetSortListPos( SvPtrarr* pList, long nValue, int bVertical);
SvLBoxEntry* SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom,sal_uInt16 nPref,
sal_Bool bDown, sal_Bool bSimple );
SvLBoxEntry* SearchRow(sal_uInt16 nRow,sal_uInt16 nRight,sal_uInt16 nLeft,sal_uInt16 nPref,
sal_Bool bRight, sal_Bool bSimple );
void ExpandGrid();
void CreateGridMap();
// Rueckgabe sal_False: Eintrag liegt nicht in der GridMap. rGridx,y werden
// dann an nGridCols, nGridRows geclippt
sal_Bool GetGrid( const Point& rDocPos, sal_uInt16& rGridX, sal_uInt16& rGridY ) const;
void SetGridUsed( sal_uInt16 nDX, sal_uInt16 nDY, sal_Bool bUsed )
{
pGridMap[ (nDY * nGridCols) + nDX ] = bUsed;
}
sal_Bool IsGridUsed( sal_uInt16 nDX, sal_uInt16 nDY )
{
return pGridMap[ (nDY * nGridCols) + nDX ];
}
public:
ImpIcnCursor( SvImpIconView* pOwner );
~ImpIcnCursor();
void Clear( sal_Bool bGridToo = sal_True );
// fuer Cursortravelling usw.
SvLBoxEntry* GoLeftRight( SvLBoxEntry*, sal_Bool bRight );
SvLBoxEntry* GoUpDown( SvLBoxEntry*, sal_Bool bDown );
// Rueckgaebe: sal_False == Das leere Rect steht hinter dem letzten
// Eintrag; d.h. beim naechsten Einfuegen ergibt sich das naechste
// leere Rechteck durch Addition. Hinweis: Das Rechteck kann dann
// ausserhalb des View-Space liegen
sal_Bool FindEmptyGridRect( Rectangle& rRect );
// Erzeugt fuer jede Zeile (Hoehe=nGridDY) eine nach BoundRect.Left()
// sortierte Liste der Eintraege, die in ihr stehen. Eine Liste kann
// leer sein. Die Listen gehen in das Eigentum des Rufenden ueber und
// muessen mit DestroyGridAdjustData geloescht werden
void CreateGridAjustData( SvPtrarr& pLists, SvLBoxEntry* pRow=0);
static void DestroyGridAdjustData( SvPtrarr& rLists );
void SetGridUsed( const Rectangle&, sal_Bool bUsed = sal_True );
};
SvImpIconView::SvImpIconView( SvIconView* pCurView, SvLBoxTreeList* pTree,
WinBits i_nWinStyle ) :
aVerSBar( pCurView, WB_DRAG | WB_VSCROLL ),
aHorSBar( pCurView, WB_DRAG | WB_HSCROLL )
{
pView = pCurView;
pModel = pTree;
pCurParent = 0;
pZOrderList = new SvPtrarr;
SetStyle( i_nWinStyle );
nHorDist = 0;
nVerDist = 0;
nFlags = 0;
nCurUserEvent = 0;
nMaxVirtWidth = 200;
pDDRefEntry = 0;
pDDDev = 0;
pDDBufDev = 0;
pDDTempDev = 0;
eTextMode = ShowTextShort;
pImpCursor = new ImpIcnCursor( this );
aVerSBar.SetScrollHdl( LINK( this, SvImpIconView, ScrollUpDownHdl ) );
aHorSBar.SetScrollHdl( LINK( this, SvImpIconView, ScrollLeftRightHdl ) );
nHorSBarHeight = aHorSBar.GetSizePixel().Height();
nVerSBarWidth = aVerSBar.GetSizePixel().Width();
aMouseMoveTimer.SetTimeout( 20 );
aMouseMoveTimer.SetTimeoutHdl(LINK(this,SvImpIconView,MouseMoveTimeoutHdl));
aEditTimer.SetTimeout( 800 );
aEditTimer.SetTimeoutHdl(LINK(this,SvImpIconView,EditTimeoutHdl));
Clear( sal_True );
}
SvImpIconView::~SvImpIconView()
{
StopEditTimer();
CancelUserEvent();
delete pZOrderList;
delete pImpCursor;
delete pDDDev;
delete pDDBufDev;
delete pDDTempDev;
ClearSelectedRectList();
}
void SvImpIconView::Clear( sal_Bool bInCtor )
{
StopEditTimer();
CancelUserEvent();
nMaxBmpWidth = 0;
nMaxBmpHeight = 0;
nMaxTextWidth = 0;
bMustRecalcBoundingRects = sal_False;
nMaxBoundHeight = 0;
//XXX
nFlags |= F_GRID_INSERT;
nFlags &= ~F_PAINTED;
SetNextEntryPos( Point( LROFFS_WINBORDER, TBOFFS_WINBORDER ) );
pCursor = 0;
if( !bInCtor )
{
pImpCursor->Clear();
aVirtOutputSize.Width() = 0;
aVirtOutputSize.Height() = 0;
pZOrderList->Remove(0,pZOrderList->Count());
MapMode aMapMode( pView->GetMapMode());
aMapMode.SetOrigin( Point() );
pView->SetMapMode( aMapMode );
if( pView->IsUpdateMode() )
pView->Invalidate();
}
AdjustScrollBars();
}
void SvImpIconView::SetStyle( const WinBits i_nWinStyle )
{
nViewMode = VIEWMODE_TEXT;
if( i_nWinStyle & WB_NAME )
nViewMode = VIEWMODE_NAME;
if( i_nWinStyle & WB_ICON )
nViewMode = VIEWMODE_ICON;
}
IMPL_LINK( SvImpIconView, ScrollUpDownHdl, ScrollBar *, pScrollBar )
{
pView->EndEditing( sal_True );
// Pfeil hoch: delta=-1; Pfeil runter: delta=+1
Scroll( 0, pScrollBar->GetDelta(), sal_True );
return 0;
}
IMPL_LINK( SvImpIconView, ScrollLeftRightHdl, ScrollBar *, pScrollBar )
{
pView->EndEditing( sal_True );
// Pfeil links: delta=-1; Pfeil rechts: delta=+1
Scroll( pScrollBar->GetDelta(), 0, sal_True );
return 0;
}
void SvImpIconView::ChangedFont()
{
StopEditTimer();
ImpArrange();
}
void SvImpIconView::CheckAllSizes()
{
nMaxTextWidth = 0;
nMaxBmpWidth = 0;
nMaxBmpHeight = 0;
SvLBoxEntry* pEntry = pModel->First();
while( pEntry )
{
CheckSizes( pEntry );
pEntry = pModel->Next( pEntry );
}
}
void SvImpIconView::CheckSizes( SvLBoxEntry* pEntry,
const SvIcnVwDataEntry* pViewData )
{
Size aSize;
if( !pViewData )
pViewData = ICNVIEWDATA(pEntry);
SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
if( pStringItem )
{
aSize = GetItemSize( pView, pEntry, pStringItem, pViewData );
if( aSize.Width() > nMaxTextWidth )
{
nMaxTextWidth = aSize.Width();
if( !(nFlags & F_GRIDMODE ) )
bMustRecalcBoundingRects = sal_True;
}
}
SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
if( pBmpItem )
{
aSize = GetItemSize( pView, pEntry, pBmpItem, pViewData );
if( aSize.Width() > nMaxBmpWidth )
{
nMaxBmpWidth = aSize.Width();
nMaxBmpWidth += (2*LROFFS_ICON);
if( !(nFlags & F_GRIDMODE ) )
bMustRecalcBoundingRects = sal_True;
}
if( aSize.Height() > nMaxBmpHeight )
{
nMaxBmpHeight = aSize.Height();
nMaxBmpHeight += (2*TBOFFS_ICON);;
if( !(nFlags & F_GRIDMODE ) )
bMustRecalcBoundingRects = sal_True;
}
}
}
void SvImpIconView::EntryInserted( SvLBoxEntry* pEntry )
{
if( pModel->GetParent(pEntry) == pCurParent )
{
StopEditTimer();
DBG_ASSERT(pZOrderList->GetPos(pEntry)==0xffff,"EntryInserted:ZOrder?");
pZOrderList->Insert( pEntry, pZOrderList->Count() );
if( nFlags & F_GRIDMODE )
pImpCursor->Clear( sal_False );
else
pImpCursor->Clear( sal_True );
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
CheckSizes( pEntry, pViewData );
if( pView->IsUpdateMode() )
{
FindBoundingRect( pEntry, pViewData );
PaintEntry( pEntry, pViewData );
}
else
InvalidateBoundingRect( pViewData->aRect );
}
}
void SvImpIconView::RemovingEntry( SvLBoxEntry* pEntry )
{
if( pModel->GetParent(pEntry) == pCurParent)
{
StopEditTimer();
DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"RemovingEntry:ZOrder?");
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
if( IsBoundingRectValid( pViewData->aRect ) )
{
// bei gueltigem Bounding-Rect muss in EntryRemoved eine
// Sonderbehandlung erfolgen
nFlags |= F_ENTRY_REMOVED;
pView->Invalidate( pViewData->aRect );
}
if( pEntry == pCursor )
{
SvLBoxEntry* pNewCursor = GetNewCursor();
ShowCursor( sal_False );
pCursor = 0; // damit er nicht deselektiert wird
SetCursor( pNewCursor );
}
sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry );
pZOrderList->Remove( nPos, 1 );
pImpCursor->Clear();
}
}
void SvImpIconView::EntryRemoved()
{
if( (nFlags & (F_ENTRY_REMOVED | F_PAINTED)) == (F_ENTRY_REMOVED | F_PAINTED))
{
// Ein Eintrag mit gueltigem BoundRect wurde geloescht und wir
// haben schon mal gepaintet. In diesem Fall muessen wir die
// Position des naechsten Eintrags, der eingefuegt wird oder noch
// kein gueltiges BoundRect hat, "suchen" d.h. ein "Loch" in
// der View auffuellen.
nFlags &= ~( F_ENTRY_REMOVED | F_GRID_INSERT );
}
}
void SvImpIconView::MovingEntry( SvLBoxEntry* pEntry )
{
DBG_ASSERT(pEntry,"MovingEntry: 0!");
pNextCursor = 0;
StopEditTimer();
if( pModel->GetParent(pEntry) == pCurParent )
{
DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"MovingEntry:ZOrder?");
nFlags |= F_MOVING_SIBLING;
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
if( IsBoundingRectValid( pViewData->aRect ) )
pView->Invalidate( pViewData->aRect );
// falls Eintrag seinen Parent wechselt vorsichtshalber
// die neue Cursorposition berechnen
if( pEntry == pCursor )
pNextCursor = GetNewCursor();
pImpCursor->Clear();
}
}
void SvImpIconView::EntryMoved( SvLBoxEntry* pEntry )
{
ShowCursor( sal_False );
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
if( pModel->GetParent(pEntry)==pCurParent )
{
if( nFlags & F_MOVING_SIBLING )
{
// die Neu-Positionierung eines Eintrags bei D&D innerhalb
// einer IconView findet bereits in NotifyMoving statt
// (MovingEntry/EntryMoved wird dann nicht mehr gerufen)
ToTop( pEntry );
}
else
{
pImpCursor->Clear();
pZOrderList->Insert( pEntry, pZOrderList->Count() );
DBG_ASSERT(pZOrderList->Count()==pModel->GetChildCount(pCurParent),"EntryMoved:Bad zorder count");
FindBoundingRect( pEntry, pViewData );
}
PaintEntry( pEntry, pViewData );
}
else
{
if( pEntry == pCursor )
{
DBG_ASSERT(pNextCursor,"EntryMoved: Next cursor bad");
SetCursor( pNextCursor );
}
pImpCursor->Clear();
sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry );
pZOrderList->Remove( nPos, 1 );
pView->Select( pEntry, sal_False );
// wenn er nochmal in dieser View auftaucht, muss sein
// Bounding-Rect neu berechnet werden
InvalidateBoundingRect( pViewData->aRect );
}
nFlags &= (~F_MOVING_SIBLING);
}
void SvImpIconView::TreeInserted( SvLBoxEntry* pEntry )
{
EntryMoved( pEntry ); // vorlaeufig
}
void SvImpIconView::EntryExpanded( SvLBoxEntry* )
{
}
void SvImpIconView::EntryCollapsed( SvLBoxEntry*)
{
}
void SvImpIconView::CollapsingEntry( SvLBoxEntry* )
{
}
void SvImpIconView::EntrySelected( SvLBoxEntry* pEntry, sal_Bool bSelect )
{
if( pModel->GetParent(pEntry) != pCurParent )
return;
// bei SingleSelection dafuer sorgen, dass der Cursor immer
// auf dem (einzigen) selektierten Eintrag steht
if( bSelect && pCursor &&
pView->GetSelectionMode() == SINGLE_SELECTION &&
pEntry != pCursor )
{
SetCursor( pEntry );
DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?");
}
// bei Gummibandselektion ist uns das zu teuer
if( !(nFlags & F_RUBBERING ))
ToTop( pEntry );
if( pView->IsUpdateMode() )
{
if( pEntry == pCursor )
ShowCursor( sal_False );
if( nFlags & F_RUBBERING )
PaintEntry( pEntry );
else
pView->Invalidate( GetBoundingRect( pEntry ) );
if( pEntry == pCursor )
ShowCursor( sal_True );
}
}
void SvImpIconView::SetNextEntryPos(const Point& rPos)
{
aPrevBoundRect.SetPos( rPos );
aPrevBoundRect.Right() = LONG_MAX; // dont know
}
Point SvImpIconView::FindNextEntryPos( const Size& rBoundSize )
{
if( nFlags & F_GRIDMODE )
{
if( nFlags & F_GRID_INSERT )
{
if( aPrevBoundRect.Right() != LONG_MAX )
{
// passt der naechste Entry noch in die Zeile ?
long nNextWidth = aPrevBoundRect.Right() + nGridDX + LROFFS_WINBORDER;
if( nNextWidth > aVirtOutputSize.Width() )
{
// darf aVirtOutputSize verbreitert werden ?
if( nNextWidth < nMaxVirtWidth )
{
// verbreitern & in Zeile aufnehmen
aPrevBoundRect.Left() += nGridDX;
}
else
{
// erhoehen & neue Zeile beginnen
aPrevBoundRect.Top() += nGridDY;
aPrevBoundRect.Left() = LROFFS_WINBORDER;
}
}
else
{
// in die Zeile aufnehmen
aPrevBoundRect.Left() += nGridDX;
}
}
aPrevBoundRect.SetSize( Size( nGridDX, nGridDY ) );
}
else
{
if( !pImpCursor->FindEmptyGridRect( aPrevBoundRect ) )
{
// mitten in den Entries gibts keine Loecher mehr,
// wir koennen also wieder ins "Fast Insert" springen
nFlags |= F_GRID_INSERT;
}
}
}
else
{
if( aPrevBoundRect.Right() != LONG_MAX )
{
// passt der naechste Entry noch in die Zeile ?
long nNextWidth=aPrevBoundRect.Right()+rBoundSize.Width()+LROFFS_BOUND+nHorDist;
if( nNextWidth > aVirtOutputSize.Width() )
{
// darf aVirtOutputSize verbreitert werden ?
if( nNextWidth < nMaxVirtWidth )
{
// verbreitern & in Zeile aufnehmen
aPrevBoundRect.SetPos( aPrevBoundRect.TopRight() );
aPrevBoundRect.Left() += nHorDist;
}
else
{
// erhoehen & neue Zeile beginnen
aPrevBoundRect.Top() += nMaxBoundHeight + nVerDist + TBOFFS_BOUND;
aPrevBoundRect.Left() = LROFFS_WINBORDER;
}
}
else
{
// in die Zeile aufnehmen
aPrevBoundRect.SetPos( aPrevBoundRect.TopRight() );
aPrevBoundRect.Left() += nHorDist;
}
}
aPrevBoundRect.SetSize( rBoundSize );
}
return aPrevBoundRect.TopLeft();
}
void SvImpIconView::ResetVirtSize()
{
StopEditTimer();
aVirtOutputSize.Width() = 0;
aVirtOutputSize.Height() = 0;
sal_Bool bLockedEntryFound = sal_False;
nFlags &= (~F_GRID_INSERT);
SvLBoxEntry* pCur = pModel->FirstChild( pCurParent );
while( pCur )
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur);
if( pViewData->IsEntryPosLocked() )
{
// VirtSize u.a. anpassen
if( !IsBoundingRectValid( pViewData->aRect ) )
FindBoundingRect( pCur, pViewData );
else
AdjustVirtSize( pViewData->aRect );
bLockedEntryFound = sal_True;
}
else
InvalidateBoundingRect( pViewData->aRect );
pCur = pModel->NextSibling( pCur );
}
if( !bLockedEntryFound )
{
//XXX
nFlags |= F_GRID_INSERT;
}
SetNextEntryPos( Point( LROFFS_WINBORDER, TBOFFS_WINBORDER ) );
pImpCursor->Clear();
}
void SvImpIconView::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();
AdjustScrollBars();
}
}
void SvImpIconView::Arrange()
{
nMaxVirtWidth = aOutputSize.Width();
ImpArrange();
}
void SvImpIconView::ImpArrange()
{
StopEditTimer();
ShowCursor( sal_False );
ResetVirtSize();
bMustRecalcBoundingRects = sal_False;
MapMode aMapMode( pView->GetMapMode());
aMapMode.SetOrigin( Point() );
pView->SetMapMode( aMapMode );
CheckAllSizes();
RecalcAllBoundingRectsSmart();
pView->Invalidate();
ShowCursor( sal_True );
}
void SvImpIconView::Paint( const Rectangle& rRect )
{
if( !pView->IsUpdateMode() )
return;
#if defined(DBG_UTIL) && defined(OV_DRAWGRID)
if( nFlags & F_GRIDMODE )
{
Color aOldColor = pView->GetLineColor();
Color aNewColor( COL_BLACK );
pView->SetLineColor( aNewColor );
Point aOffs( pView->GetMapMode().GetOrigin());
Size aXSize( pView->GetOutputSizePixel() );
for( long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX )
{
Point aStart( nDX+LROFFS_BOUND, 0 );
Point aEnd( nDX+LROFFS_BOUND, aXSize.Height());
aStart -= aOffs;
aEnd -= aOffs;
pView->DrawLine( aStart, aEnd );
}
for( long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY )
{
Point aStart( 0, nDY+TBOFFS_BOUND );
Point aEnd( aXSize.Width(), nDY+TBOFFS_BOUND );
aStart -= aOffs;
aEnd -= aOffs;
pView->DrawLine( aStart, aEnd );
}
pView->SetLineColor( aOldColor );
}
#endif
nFlags |= F_PAINTED;
if( !(pModel->HasChilds( pCurParent ) ))
return;
if( !pCursor )
pCursor = pModel->FirstChild( pCurParent );
sal_uInt16 nCount = pZOrderList->Count();
if( !nCount )
return;
SvPtrarr* pNewZOrderList = new SvPtrarr;
SvPtrarr* pPaintedEntries = new SvPtrarr;
sal_uInt16 nPos = 0;
while( nCount )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nPos ));
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
const Rectangle& rBoundRect = GetBoundingRect( pEntry, pViewData );
if( rRect.IsOver( rBoundRect ) )
{
PaintEntry( pEntry, rBoundRect.TopLeft(), pViewData );
// Eintraege, die neu gezeichnet werden, auf Top setzen
pPaintedEntries->Insert( pEntry, pPaintedEntries->Count() );
}
else
pNewZOrderList->Insert( pEntry, pNewZOrderList->Count() );
nCount--;
nPos++;
}
delete pZOrderList;
pZOrderList = pNewZOrderList;
nCount = pPaintedEntries->Count();
if( nCount )
{
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
pZOrderList->Insert( pPaintedEntries->GetObject( nCur ),pZOrderList->Count());
}
delete pPaintedEntries;
Rectangle aRect;
if( GetResizeRect( aRect ))
PaintResizeRect( aRect );
}
sal_Bool SvImpIconView::GetResizeRect( Rectangle& rRect )
{
if( aHorSBar.IsVisible() && aVerSBar.IsVisible() )
{
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin());
aOrigin *= -1;
aOrigin.X() += aOutputSize.Width();
aOrigin.Y() += aOutputSize.Height();
rRect.SetPos( aOrigin );
rRect.SetSize( Size( nVerSBarWidth, nHorSBarHeight));
return sal_True;
}
return sal_False;
}
void SvImpIconView::PaintResizeRect( const Rectangle& rRect )
{
const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings();
Color aNewColor = rStyleSettings.GetFaceColor();
Color aOldColor = pView->GetFillColor();
pView->SetFillColor( aNewColor );
pView->DrawRect( rRect );
pView->SetFillColor( aOldColor );
}
void SvImpIconView::RepaintSelectionItems()
{
DBG_ERROR("RepaintSelectionItems");
pView->Invalidate(); // vorlaeufig
}
SvLBoxItem* SvImpIconView::GetItem( SvLBoxEntry* pEntry,
const Point& rAbsPos )
{
Rectangle aRect;
SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
if( pStringItem )
{
aRect = CalcTextRect( pEntry, pStringItem );
if( aRect.IsInside( rAbsPos ) )
return pStringItem;
}
SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
if( pBmpItem )
{
aRect = CalcBmpRect( pEntry );
if( aRect.IsInside( rAbsPos ) )
return pBmpItem;
}
return 0;
}
void SvImpIconView::CalcDocPos( Point& aMaeuschenPos )
{
aMaeuschenPos -= pView->GetMapMode().GetOrigin();
}
void SvImpIconView::MouseButtonDown( const MouseEvent& rMEvt)
{
StopEditTimer();
pView->GrabFocus();
Point aDocPos( rMEvt.GetPosPixel() );
if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height())
return;
CalcDocPos( aDocPos );
SvLBoxEntry* pEntry = GetEntry( aDocPos );
if( !pEntry )
{
if( pView->GetSelectionMode() != SINGLE_SELECTION )
{
if( !rMEvt.IsMod1() ) // Ctrl
{
pView->SelectAll( sal_False );
ClearSelectedRectList();
}
else
nFlags |= F_ADD_MODE;
nFlags |= F_RUBBERING;
aCurSelectionRect.SetPos( aDocPos );
pView->CaptureMouse();
}
return;
}
sal_Bool bSelected = pView->IsSelected( pEntry );
sal_Bool bEditingEnabled = pView->IsInplaceEditingEnabled();
if( rMEvt.GetClicks() == 2 )
{
DeselectAllBut( pEntry );
pView->pHdlEntry = pEntry;
pView->DoubleClickHdl();
}
else
{
// Inplace-Editing ?
if( rMEvt.IsMod2() ) // Alt?
{
if( bEditingEnabled )
{
SvLBoxItem* pItem = GetItem(pEntry,aDocPos);
if( pItem )
pView->EditingRequest( pEntry, pItem, aDocPos);
}
}
else if( pView->GetSelectionMode() == SINGLE_SELECTION )
{
DeselectAllBut( pEntry );
SetCursor( pEntry );
pView->Select( pEntry, sal_True );
if( bEditingEnabled && bSelected && !rMEvt.GetModifier() &&
rMEvt.IsLeft() && IsTextHit( pEntry, aDocPos ) )
{
nFlags |= F_START_EDITTIMER_IN_MOUSEUP;
}
}
else
{
if( !rMEvt.GetModifier() )
{
if( !bSelected )
{
DeselectAllBut( pEntry );
SetCursor( pEntry );
pView->Select( pEntry, sal_True );
}
else
{
// erst im Up deselektieren, falls Move per D&D!
nFlags |= F_DOWN_DESELECT;
if( bEditingEnabled && IsTextHit( pEntry, aDocPos ) &&
rMEvt.IsLeft())
{
nFlags |= F_START_EDITTIMER_IN_MOUSEUP;
}
}
}
else if( rMEvt.IsMod1() )
nFlags |= F_DOWN_CTRL;
}
}
}
void SvImpIconView::MouseButtonUp( const MouseEvent& rMEvt )
{
aMouseMoveTimer.Stop();
pView->ReleaseMouse();
// HACK, da Einar noch nicht PrepareCommandEvent aufruft
if( rMEvt.IsRight() && (nFlags & (F_DOWN_CTRL | F_DOWN_DESELECT) ))
nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
if( nFlags & F_RUBBERING )
{
aMouseMoveTimer.Stop();
AddSelectedRect( aCurSelectionRect );
HideSelectionRect();
nFlags &= ~(F_RUBBERING | F_ADD_MODE);
}
SvLBoxEntry* pEntry = pView->GetEntry( rMEvt.GetPosPixel(), sal_True );
if( pEntry )
{
if( nFlags & F_DOWN_CTRL )
{
// Ctrl & MultiSelection
ToggleSelection( pEntry );
SetCursor( pEntry );
}
else if( nFlags & F_DOWN_DESELECT )
{
DeselectAllBut( pEntry );
SetCursor( pEntry );
pView->Select( pEntry, sal_True );
}
}
nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
if( nFlags & F_START_EDITTIMER_IN_MOUSEUP )
{
StartEditTimer();
nFlags &= ~F_START_EDITTIMER_IN_MOUSEUP;
}
}
void SvImpIconView::MouseMove( const MouseEvent& rMEvt )
{
if( nFlags & F_RUBBERING )
{
const Point& rPosPixel = rMEvt.GetPosPixel();
if( !aMouseMoveTimer.IsActive() )
{
aMouseMoveEvent = rMEvt;
aMouseMoveTimer.Start();
// ausserhalb des Fensters liegende Move-Events muessen
// vom Timer kommen, damit die Scrollgeschwindigkeit
// unabhaengig von Mausbewegungen ist.
if( rPosPixel.X() < 0 || rPosPixel.Y() < 0 )
return;
const Size& rSize = pView->GetOutputSizePixel();
if( rPosPixel.X() > rSize.Width() || rPosPixel.Y() > rSize.Height())
return;
}
if( &rMEvt != &aMouseMoveEvent )
aMouseMoveEvent = rMEvt;
long nScrollDX, nScrollDY;
CalcScrollOffsets(rMEvt.GetPosPixel(),nScrollDX,nScrollDY,sal_False );
sal_Bool bSelRectHidden = sal_False;
if( nScrollDX || nScrollDY )
{
HideSelectionRect();
bSelRectHidden = sal_True;
pView->Scroll( nScrollDX, nScrollDY );
}
Point aDocPos( rMEvt.GetPosPixel() );
aDocPos = pView->PixelToLogic( aDocPos );
Rectangle aRect( aCurSelectionRect.TopLeft(), aDocPos );
if( aRect != aCurSelectionRect )
{
HideSelectionRect();
bSelRectHidden = sal_True;
sal_Bool bAdd = (nFlags & F_ADD_MODE) ? sal_True : sal_False;
SelectRect( aRect, bAdd, &aSelectedRectList );
}
if( bSelRectHidden )
DrawSelectionRect( aRect );
}
}
sal_Bool SvImpIconView::KeyInput( const KeyEvent& rKEvt )
{
StopEditTimer();
sal_Bool bKeyUsed = sal_True;
sal_Bool bMod1 = rKEvt.GetKeyCode().IsMod1();
sal_Bool bInAddMode = (sal_Bool)((nFlags & F_ADD_MODE) != 0);
int bDeselAll = (pView->GetSelectionMode() != SINGLE_SELECTION) &&
!bInAddMode;
SvLBoxEntry* pNewCursor;
sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
switch( nCode )
{
case KEY_UP:
if( pCursor )
{
MakeVisible( pCursor );
pNewCursor = pImpCursor->GoUpDown(pCursor,sal_False);
if( pNewCursor )
{
if( bDeselAll )
pView->SelectAll( sal_False );
ShowCursor( sal_False );
MakeVisible( pNewCursor );
SetCursor( pNewCursor );
if( !bInAddMode )
pView->Select( pCursor, sal_True );
}
else
{
Rectangle aRect( GetBoundingRect( pCursor ) );
if( aRect.Top())
{
aRect.Bottom() -= aRect.Top();
aRect.Top() = 0;
MakeVisible( aRect );
}
}
}
break;
case KEY_DOWN:
if( pCursor )
{
pNewCursor=pImpCursor->GoUpDown( pCursor,sal_True );
if( pNewCursor )
{
MakeVisible( pCursor );
if( bDeselAll )
pView->SelectAll( sal_False );
ShowCursor( sal_False );
MakeVisible( pNewCursor );
SetCursor( pNewCursor );
if( !bInAddMode )
pView->Select( pCursor, sal_True );
}
}
break;
case KEY_RIGHT:
if( pCursor )
{
pNewCursor=pImpCursor->GoLeftRight(pCursor,sal_True );
if( pNewCursor )
{
MakeVisible( pCursor );
if( bDeselAll )
pView->SelectAll( sal_False );
ShowCursor( sal_False );
MakeVisible( pNewCursor );
SetCursor( pNewCursor );
if( !bInAddMode )
pView->Select( pCursor, sal_True );
}
}
break;
case KEY_LEFT:
if( pCursor )
{
MakeVisible( pCursor );
pNewCursor = pImpCursor->GoLeftRight(pCursor,sal_False );
if( pNewCursor )
{
if( bDeselAll )
pView->SelectAll( sal_False );
ShowCursor( sal_False );
MakeVisible( pNewCursor );
SetCursor( pNewCursor );
if( !bInAddMode )
pView->Select( pCursor, sal_True );
}
else
{
Rectangle aRect( GetBoundingRect(pCursor));
if( aRect.Left() )
{
aRect.Right() -= aRect.Left();
aRect.Left() = 0;
MakeVisible( aRect );
}
}
}
break;
case KEY_ESCAPE:
if( nFlags & F_RUBBERING )
{
HideSelectionRect();
pView->SelectAll( sal_False );
nFlags &= ~F_RUBBERING;
}
break;
case KEY_F8:
if( rKEvt.GetKeyCode().IsShift() )
{
if( nFlags & F_ADD_MODE )
nFlags &= (~F_ADD_MODE);
else
nFlags |= F_ADD_MODE;
}
break;
#ifdef OS2
case KEY_F9:
if( rKEvt.GetKeyCode().IsShift() )
{
if( pCursor && pView->IsInplaceEditingEnabled() )
pView->EditEntry( pCursor );
}
break;
#endif
case KEY_SPACE:
if( pCursor )
{
ToggleSelection( pCursor );
}
break;
case KEY_PAGEDOWN:
break;
case KEY_PAGEUP:
break;
case KEY_ADD:
case KEY_DIVIDE :
if( bMod1 )
pView->SelectAll( sal_True );
break;
case KEY_SUBTRACT:
case KEY_COMMA :
if( bMod1 )
pView->SelectAll( sal_False );
break;
case KEY_RETURN:
if( bMod1 )
{
if( pCursor && pView->IsInplaceEditingEnabled() )
pView->EditEntry( pCursor );
}
break;
default:
bKeyUsed = sal_False;
}
return bKeyUsed;
}
void SvImpIconView::PositionScrollBars( long nRealWidth, long nRealHeight )
{
// hor scrollbar
Point aPos( 0, nRealHeight );
aPos.Y() -= nHorSBarHeight;
#ifdef OS2
aPos.Y()++;
#endif
if( aHorSBar.GetPosPixel() != aPos )
aHorSBar.SetPosPixel( aPos );
// ver scrollbar
aPos.X() = nRealWidth; aPos.Y() = 0;
aPos.X() -= nVerSBarWidth;
#if defined(WNT)
aPos.X()++;
aPos.Y()--;
#endif
#ifdef OS2
aPos.Y()--;
aPos.X()++;
#endif
if( aVerSBar.GetPosPixel() != aPos )
aVerSBar.SetPosPixel( aPos );
}
void SvImpIconView::AdjustScrollBars()
{
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;
bool bVerSBar = (pView->GetStyle() & WB_VSCROLL) ? true : false;
bool bHorSBar = (pView->GetStyle() & WB_HSCROLL) ? true : false;
sal_uInt16 nResult = 0;
if( nVirtHeight )
{
// activate ver scrollbar ?
if( 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( 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
( (nVirtHeight > nVisibleHeight) || bVerSBar) )
{
nResult = 3; // both are active
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 );
#if defined(WNT)
aSize.Height() += 2;
#endif
#ifdef OS2
aSize.Height() += 3;
#endif
if( aSize != aVerSBar.GetSizePixel() )
aVerSBar.SetSizePixel( aSize );
aVerSBar.SetVisibleSize( nVisibleHeight );
aVerSBar.SetPageSize( (nVisibleHeight*75)/100 );
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;
#if defined(WNT)
aSize.Width()++;
#endif
#ifdef OS2
aSize.Width() += 3;
if( nResult & 0x0001 ) // vertikale Scrollbar ?
aSize.Width()--;
#endif
#if defined(WNT)
if( nResult & 0x0001 ) // vertikale Scrollbar ?
{
aSize.Width()++;
nRealWidth++;
}
#endif
if( aSize != aHorSBar.GetSizePixel() )
aHorSBar.SetSizePixel( aSize );
aHorSBar.SetVisibleSize( nVisibleWidth ); //nRealWidth );
aHorSBar.SetPageSize( (nVisibleWidth*75)/100 );
if( nResult & 0x0002 )
{
aHorSBar.SetThumbPos( nThumb );
aHorSBar.Show();
}
else
{
aHorSBar.SetThumbPos( 0 );
aHorSBar.Hide();
}
#ifdef OS2
nRealWidth++;
#endif
aOutputSize.Width() = nRealWidth;
#if defined(WNT)
if( nResult & 0x0002 ) // hor scrollbar ?
nRealHeight++; // weil unterer Rand geclippt wird
#endif
#ifdef OS2
if( nResult & 0x0002 ) // hor scrollbar ?
nRealHeight++;
#endif
aOutputSize.Height() = nRealHeight;
}
void __EXPORT SvImpIconView::Resize()
{
StopEditTimer();
Rectangle aRect;
if( GetResizeRect(aRect) )
pView->Invalidate( aRect );
aOutputSize = pView->GetOutputSizePixel();
pImpCursor->Clear();
#if 1
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 (SfxExplorerIconView!)
nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpIconView,UserEventHdl),0);
#else
AdjustScrollBars();
if( GetResizeRect(aRect) )
PaintResizeRect( aRect );
#endif
}
sal_Bool SvImpIconView::CheckHorScrollBar()
{
if( !pZOrderList || !aHorSBar.IsVisible() )
return sal_False;
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin() );
if(!(pView->GetStyle() & WB_HSCROLL) && !aOrigin.X() )
{
long nWidth = aOutputSize.Width();
sal_uInt16 nCount = pZOrderList->Count();
long nMostRight = 0;
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur);
long nRight = GetBoundingRect(pEntry).Right();
if( nRight > nWidth )
return sal_False;
if( nRight > nMostRight )
nMostRight = nRight;
}
aHorSBar.Hide();
aOutputSize.Height() += nHorSBarHeight;
aVirtOutputSize.Width() = nMostRight;
aHorSBar.SetThumbPos( 0 );
Range aRange;
aRange.Max() = nMostRight - 1;
aHorSBar.SetRange( aRange );
if( aVerSBar.IsVisible() )
{
Size aSize( aVerSBar.GetSizePixel());
aSize.Height() += nHorSBarHeight;
aVerSBar.SetSizePixel( aSize );
}
return sal_True;
}
return sal_False;
}
sal_Bool SvImpIconView::CheckVerScrollBar()
{
if( !pZOrderList || !aVerSBar.IsVisible() )
return sal_False;
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin() );
if(!(pView->GetStyle() & WB_VSCROLL) && !aOrigin.Y() )
{
long nDeepest = 0;
long nHeight = aOutputSize.Height();
sal_uInt16 nCount = pZOrderList->Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur);
long nBottom = GetBoundingRect(pEntry).Bottom();
if( nBottom > nHeight )
return sal_False;
if( nBottom > nDeepest )
nDeepest = nBottom;
}
aVerSBar.Hide();
aOutputSize.Width() += nVerSBarWidth;
aVirtOutputSize.Height() = nDeepest;
aVerSBar.SetThumbPos( 0 );
Range aRange;
aRange.Max() = nDeepest - 1;
aVerSBar.SetRange( aRange );
if( aHorSBar.IsVisible() )
{
Size aSize( aHorSBar.GetSizePixel());
aSize.Width() += nVerSBarWidth;
aHorSBar.SetSizePixel( aSize );
}
return sal_True;
}
return sal_False;
}
// blendet Scrollbars aus, wenn sie nicht mehr benoetigt werden
void SvImpIconView::CheckScrollBars()
{
CheckVerScrollBar();
if( CheckHorScrollBar() )
CheckVerScrollBar();
}
void __EXPORT SvImpIconView::GetFocus()
{
if( pCursor )
{
pView->SetEntryFocus( pCursor, sal_True );
ShowCursor( sal_True );
}
}
void __EXPORT SvImpIconView::LoseFocus()
{
StopEditTimer();
if( pCursor )
pView->SetEntryFocus( pCursor,sal_False );
ShowCursor( sal_False );
}
void SvImpIconView::UpdateAll()
{
AdjustScrollBars();
pImpCursor->Clear();
pView->Invalidate();
}
void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData )
{
Point aPos( GetEntryPosition( pEntry ) );
PaintEntry( pEntry, aPos, pViewData );
}
void SvImpIconView::PaintEmphasis( const Rectangle& rRect, sal_Bool bSelected,
sal_Bool bCursored, OutputDevice* pOut )
{
// HACK fuer D&D
if( nFlags & F_NO_EMPHASIS )
return;
if( !pOut )
pOut = pView;
// Selektion painten
Color aOldFillColor = pOut->GetFillColor();
Color aOldLineColor = pOut->GetLineColor();
Color aNewColor;
const StyleSettings& rStyleSettings = pOut->GetSettings().GetStyleSettings();
if( bSelected )
{
aNewColor = rStyleSettings.GetHighlightColor();
}
else
{
#ifndef OS2
aNewColor =rStyleSettings.GetFieldColor();
#else
aNewColor = pOut->GetBackground().GetColor();
#endif
}
if( bCursored )
{
pOut->SetLineColor( Color( COL_BLACK ) );
}
pOut->SetFillColor( aNewColor );
pOut->DrawRect( rRect );
pOut->SetFillColor( aOldFillColor );
pOut->SetLineColor( aOldLineColor );
}
void SvImpIconView::PaintItem( const Rectangle& rRect,
SvLBoxItem* pItem, SvLBoxEntry* pEntry, sal_uInt16 nPaintFlags,
OutputDevice* pOut )
{
if( nViewMode == VIEWMODE_ICON && pItem->IsA() == SV_ITEM_ID_LBOXSTRING )
{
const String& rStr = ((SvLBoxString*)pItem)->GetText();
DrawText( pOut, rRect, rStr, DRAWTEXT_FLAGS );
}
else
{
Point aPos( rRect.TopLeft() );
const Size& rSize = GetItemSize( pView, pEntry, pItem );
if( nPaintFlags & PAINTFLAG_HOR_CENTERED )
aPos.X() += (rRect.GetWidth() - rSize.Width() ) / 2;
if( nPaintFlags & PAINTFLAG_VER_CENTERED )
aPos.Y() += (rRect.GetHeight() - rSize.Height() ) / 2;
pItem->Paint( aPos, *(SvLBox*)pOut, 0, pEntry );
}
}
void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, const Point& rPos,
SvIcnVwDataEntry* pViewData, OutputDevice* pOut )
{
if( !pView->IsUpdateMode() )
return;
if( !pOut )
pOut = pView;
SvLBoxContextBmp* pBmpItem;
pView->PreparePaint( pEntry );
if( !pViewData )
pViewData = ICNVIEWDATA(pEntry);
SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
sal_Bool bSelected = pViewData->IsSelected();
sal_Bool bCursored = pViewData->IsCursored();
Font aTempFont( pOut->GetFont() );
// waehrend D&D nicht die Fontfarbe wechseln, da sonst auch die
// Emphasis gezeichnet werden muss! (weisser Adler auf weissem Grund)
if( bSelected && !(nFlags & F_NO_EMPHASIS) )
{
const StyleSettings& rStyleSettings = pOut->GetSettings().GetStyleSettings();
Font aNewFont( aTempFont );
aNewFont.SetColor( rStyleSettings.GetHighlightTextColor() );
pOut->SetFont( aNewFont );
}
Rectangle aTextRect( CalcTextRect(pEntry,pStringItem,&rPos,sal_False,pViewData));
Rectangle aBmpRect( CalcBmpRect(pEntry, &rPos, pViewData ) );
switch( nViewMode )
{
case VIEWMODE_ICON:
pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
PaintEmphasis( aBmpRect, bSelected, bCursored, pOut );
PaintItem( aBmpRect, pBmpItem, pEntry,
PAINTFLAG_HOR_CENTERED | PAINTFLAG_VER_CENTERED, pOut );
PaintEmphasis( aTextRect, bSelected, sal_False, pOut );
PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_HOR_CENTERED, pOut );
break;
case VIEWMODE_NAME:
pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
PaintEmphasis( aBmpRect, bSelected, bCursored, pOut );
PaintItem( aBmpRect, pBmpItem, pEntry, PAINTFLAG_VER_CENTERED, pOut );
PaintEmphasis( aTextRect, bSelected, sal_False, pOut );
PaintItem( aTextRect, pStringItem, pEntry,PAINTFLAG_VER_CENTERED, pOut );
break;
case VIEWMODE_TEXT:
PaintEmphasis( aTextRect, bSelected, bCursored, pOut );
PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_VER_CENTERED, pOut );
break;
}
pOut->SetFont( aTempFont );
}
void SvImpIconView::SetEntryPosition( SvLBoxEntry* pEntry, const Point& rPos,
sal_Bool bAdjustAtGrid, sal_Bool bCheckScrollBars )
{
if( pModel->GetParent(pEntry) == pCurParent )
{
ShowCursor( sal_False );
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
Rectangle aBoundRect( GetBoundingRect( pEntry, pViewData ));
pView->Invalidate( aBoundRect );
ToTop( pEntry );
if( rPos != aBoundRect.TopLeft() )
{
Point aGridOffs = pViewData->aGridRect.TopLeft() -
pViewData->aRect.TopLeft();
pImpCursor->Clear();
nFlags &= ~F_GRID_INSERT;
aBoundRect.SetPos( rPos );
pViewData->aRect = aBoundRect;
pViewData->aGridRect.SetPos( rPos + aGridOffs );
AdjustVirtSize( aBoundRect );
}
//HACK(Billigloesung, die noch verbessert werden muss)
if( bAdjustAtGrid )
{
AdjustAtGrid( pEntry );
ToTop( pEntry );
}
if( bCheckScrollBars && pView->IsUpdateMode() )
CheckScrollBars();
PaintEntry( pEntry, pViewData );
ShowCursor( sal_True );
}
}
void SvImpIconView::ViewDataInitialized( SvLBoxEntry*)
{
}
void SvImpIconView::ModelHasEntryInvalidated( SvListEntry* pEntry )
{
if( pEntry == pCursor )
ShowCursor( sal_False );
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
pView->Invalidate( pViewData->aRect );
if( nFlags & F_GRIDMODE )
Center( (SvLBoxEntry*)pEntry, pViewData );
else
pViewData->aRect.SetSize( CalcBoundingSize(
(SvLBoxEntry*)pEntry, pViewData ) );
ViewDataInitialized( (SvLBoxEntry*)pEntry );
pView->Invalidate( pViewData->aRect );
if( pEntry == pCursor )
ShowCursor( sal_True );
}
void SvImpIconView::InvalidateEntry( SvLBoxEntry* pEntry )
{
const Rectangle& rRect = GetBoundingRect( pEntry );
pView->Invalidate( rRect );
}
void SvImpIconView::SetNoSelection()
{
}
void SvImpIconView::SetDragDropMode( DragDropMode )
{
}
void SvImpIconView::SetSelectionMode( SelectionMode )
{
}
sal_Bool SvImpIconView::IsEntryInView( SvLBoxEntry* )
{
return sal_False;
}
SvLBoxEntry* SvImpIconView::GetDropTarget( const Point& rPos )
{
Point aDocPos( rPos );
CalcDocPos( aDocPos );
SvLBoxEntry* pTarget = GetEntry( aDocPos );
if( !pTarget || !pTarget->HasChilds() )
pTarget = pCurParent;
return pTarget;
}
SvLBoxEntry* SvImpIconView::GetEntry( const Point& rDocPos )
{
CheckBoundingRects();
SvLBoxEntry* pTarget = 0;
// Z-Order-Liste vom Ende her absuchen
sal_uInt16 nCount = pZOrderList->Count();
while( nCount )
{
nCount--;
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nCount));
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
if( pViewData->aRect.IsInside( rDocPos ) )
{
pTarget = pEntry;
break;
}
}
return pTarget;
}
SvLBoxEntry* SvImpIconView::GetNextEntry( const Point& rDocPos, SvLBoxEntry* pCurEntry )
{
CheckBoundingRects();
SvLBoxEntry* pTarget = 0;
sal_uInt16 nStartPos = pZOrderList->GetPos( (void*)pCurEntry );
if( nStartPos != USHRT_MAX )
{
sal_uInt16 nCount = pZOrderList->Count();
for( sal_uInt16 nCur = nStartPos+1; nCur < nCount; nCur++ )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nCur));
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
if( pViewData->aRect.IsInside( rDocPos ) )
{
pTarget = pEntry;
break;
}
}
}
return pTarget;
}
SvLBoxEntry* SvImpIconView::GetPrevEntry( const Point& rDocPos, SvLBoxEntry* pCurEntry )
{
CheckBoundingRects();
SvLBoxEntry* pTarget = 0;
sal_uInt16 nStartPos = pZOrderList->GetPos( (void*)pCurEntry );
if( nStartPos != USHRT_MAX && nStartPos != 0 )
{
nStartPos--;
do
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nStartPos));
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
if( pViewData->aRect.IsInside( rDocPos ) )
{
pTarget = pEntry;
break;
}
} while( nStartPos > 0 );
}
return pTarget;
}
Point SvImpIconView::GetEntryPosition( SvLBoxEntry* pEntry )
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
DBG_ASSERT(pViewData,"Entry not in model");
return pViewData->aRect.TopLeft();
}
const Rectangle& SvImpIconView::GetBoundingRect( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData )
{
if( !pViewData )
pViewData = ICNVIEWDATA(pEntry);
DBG_ASSERT(pViewData,"Entry not in model");
if( !IsBoundingRectValid( pViewData->aRect ))
FindBoundingRect( pEntry, pViewData );
return pViewData->aRect;
}
void SvImpIconView::SetSpaceBetweenEntries( long nHor, long nVer )
{
nHorDist = nHor;
nVerDist = nVer;
}
Rectangle SvImpIconView::CalcBmpRect( SvLBoxEntry* pEntry, const Point* pPos,
SvIcnVwDataEntry* pViewData )
{
if( !pViewData )
pViewData = ICNVIEWDATA(pEntry);
Rectangle aBound = GetBoundingRect( pEntry, pViewData );
if( pPos )
aBound.SetPos( *pPos );
Point aPos( aBound.TopLeft() );
switch( nViewMode )
{
case VIEWMODE_ICON:
{
aPos.X() += ( aBound.GetWidth() - nMaxBmpWidth ) / 2;
Size aSize( nMaxBmpWidth, nMaxBmpHeight );
// das Bitmap-Rechteck soll nicht das TextRect beruehren
aSize.Height() -= 3;
return Rectangle( aPos, aSize );
}
case VIEWMODE_NAME:
return Rectangle( aPos,
Size( nMaxBmpWidth, aBound.GetHeight() ));
case VIEWMODE_TEXT:
return Rectangle( aPos, aBound.GetSize() );
default:
{
Rectangle aRect;
return aRect;
}
}
}
Rectangle SvImpIconView::CalcTextRect( SvLBoxEntry* pEntry,
SvLBoxString* pItem, const Point* pPos, sal_Bool bForInplaceEdit,
SvIcnVwDataEntry* pViewData )
{
long nBmpHeight, nBmpWidth;
if( !pItem )
pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
if( !pViewData )
pViewData = ICNVIEWDATA(pEntry);
Size aTextSize( GetItemSize( pView, pEntry, pItem, pViewData ));
aTextSize.Width() += 2*LROFFS_TEXT;
Size aContextBmpSize(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry));
Rectangle aBound = GetBoundingRect( pEntry, pViewData );
if( pPos )
aBound.SetPos( *pPos );
Point aPos( aBound.TopLeft() );
switch( nViewMode )
{
case VIEWMODE_ICON:
nBmpHeight = aContextBmpSize.Height();
if( nBmpHeight < nMaxBmpHeight )
nBmpHeight = nMaxBmpHeight;
aPos.Y() += nBmpHeight;
// beim Inplace-Editieren, spendieren wir ein bisschen mehr Platz
if( bForInplaceEdit )
{
// 20% rauf
long nMinWidth = (( (aContextBmpSize.Width()*10) / 100 ) * 2 ) +
aContextBmpSize.Width();
if( nMinWidth > aBound.GetWidth() )
nMinWidth = aBound.GetWidth();
if( aTextSize.Width() < nMinWidth )
aTextSize.Width() = nMinWidth;
// beim Inplace-Ed. darfs auch untere Eintraege ueberlappen
Rectangle aMaxGridTextRect = CalcMaxTextRect(pEntry, pViewData);
Size aOptSize = aMaxGridTextRect.GetSize();
if( aOptSize.Height() > aTextSize.Height() )
aTextSize.Height() = aOptSize.Height();
}
aPos.X() += ( aBound.GetWidth() - aTextSize.Width() ) / 2;
break;
case VIEWMODE_NAME:
nBmpWidth = aContextBmpSize.Width();
if( nBmpWidth < nMaxBmpWidth )
nBmpWidth = nMaxBmpWidth;
aPos.X() += nBmpWidth;
// vertikal ausrichten
aPos.Y() += ( nBmpWidth - aTextSize.Height() ) / 2;
break;
}
Rectangle aRect( aPos, aTextSize );
// KNALLT BEIM D&D, WENN GECLIPPT WIRD (In DrawText von Thomas)
// ClipAtVirtOutRect( aRect );
return aRect;
}
long SvImpIconView::CalcBoundingWidth( SvLBoxEntry* pEntry,
const SvIcnVwDataEntry* pViewData ) const
{
DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP),"No Bitmaps");
DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),"No Text");
long nStringWidth = GetItemSize( pView, pEntry, pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),pViewData).Width();
nStringWidth += 2*LROFFS_TEXT;
long nBmpWidth = pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry).Width();
long nWidth = 0;
switch( nViewMode )
{
case VIEWMODE_ICON:
nWidth = Max( nStringWidth, nBmpWidth );
nWidth = Max( nWidth, nMaxBmpWidth );
break;
case VIEWMODE_NAME:
nWidth = Max( nBmpWidth, nMaxBmpWidth );
nWidth += NAMEVIEW_OFFS_BMP_STRING; // Abstand Bitmap String
nWidth += nStringWidth;
break;
case VIEWMODE_TEXT:
nWidth = nStringWidth;
break;
}
return nWidth;
}
long SvImpIconView::CalcBoundingHeight( SvLBoxEntry* pEntry,
const SvIcnVwDataEntry* pViewData ) const
{
DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP),"No Bitmaps");
DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),"No Text");
long nStringHeight = GetItemSize(pView,pEntry,pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),pViewData).Height();
long nBmpHeight = pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry).Height();
long nHeight = 0;
switch( nViewMode )
{
case VIEWMODE_ICON:
nHeight = Max( nBmpHeight, nMaxBmpHeight );
nHeight += ICONVIEW_OFFS_BMP_STRING; // Abstand Bitmap String
nHeight += nStringHeight;
break;
case VIEWMODE_NAME:
nHeight = Max( nBmpHeight, nMaxBmpHeight );
nHeight = Max( nHeight, nStringHeight );
break;
case VIEWMODE_TEXT:
nHeight = nStringHeight;
break;
}
if( nHeight > nMaxBoundHeight )
{
((SvImpIconView*)this)->nMaxBoundHeight = nHeight;
((SvImpIconView*)this)->aHorSBar.SetLineSize( nHeight / 2 );
((SvImpIconView*)this)->aVerSBar.SetLineSize( nHeight / 2 );
}
return nHeight;
}
Size SvImpIconView::CalcBoundingSize( SvLBoxEntry* pEntry,
SvIcnVwDataEntry* pViewData ) const
{
if( !pViewData )
pViewData = ICNVIEWDATA(pEntry);
return Size( CalcBoundingWidth(pEntry,pViewData),
CalcBoundingHeight(pEntry,pViewData) );
}
void SvImpIconView::RecalcAllBoundingRects()
{
nMaxBoundHeight = 0;
pZOrderList->Remove(0, pZOrderList->Count() );
SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent );
while( pEntry )
{
FindBoundingRect( pEntry );
pZOrderList->Insert( pEntry, pZOrderList->Count() );
pEntry = pModel->NextSibling( pEntry );
}
bMustRecalcBoundingRects = sal_False;
AdjustScrollBars();
}
void SvImpIconView::RecalcAllBoundingRectsSmart()
{
nMaxBoundHeight = 0;
pZOrderList->Remove(0, pZOrderList->Count() );
SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent );
while( pEntry )
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
if( IsBoundingRectValid( pViewData->aRect ))
{
Size aBoundSize( pViewData->aRect.GetSize() );
if( aBoundSize.Height() > nMaxBoundHeight )
nMaxBoundHeight = aBoundSize.Height();
pZOrderList->Insert( pEntry, pZOrderList->Count() );
}
else
{
FindBoundingRect( pEntry, pViewData );
}
pZOrderList->Insert( pEntry, pZOrderList->Count() );
pEntry = pModel->NextSibling( pEntry );
}
AdjustScrollBars();
}
void SvImpIconView::UpdateBoundingRects()
{
SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent );
while( pEntry )
{
GetBoundingRect( pEntry );
pEntry = pModel->NextSibling( pEntry );
}
}
void SvImpIconView::FindBoundingRect( SvLBoxEntry* pEntry,
SvIcnVwDataEntry* pViewData )
{
if( !pViewData )
pViewData = ICNVIEWDATA(pEntry);
Size aSize( CalcBoundingSize( pEntry, pViewData ) );
Point aPos;
DBG_ASSERT(!pViewData->IsEntryPosLocked(),"Locked entry pos in FindBoundingRect");
// damits in der IconView nicht drunter & drueber geht
if( pViewData->IsEntryPosLocked() && IsBoundingRectValid(pViewData->aRect) )
{
AdjustVirtSize( pViewData->aRect );
return;
}
aPos = FindNextEntryPos( aSize );
if( nFlags & F_GRIDMODE )
{
Rectangle aGridRect( aPos, Size(nGridDX, nGridDY) );
pViewData->aGridRect = aGridRect;
Center( pEntry, pViewData );
AdjustVirtSize( pViewData->aRect );
pImpCursor->SetGridUsed( pViewData->aRect );
}
else
{
pViewData->aRect = Rectangle( aPos, aSize );
AdjustVirtSize( pViewData->aRect );
}
}
void SvImpIconView::SetCursor( SvLBoxEntry* pEntry )
{
if( pEntry == pCursor )
return;
ShowCursor( sal_False );
if( pCursor )
{
pView->SetEntryFocus( pCursor, sal_False );
if( pView->GetSelectionMode() == SINGLE_SELECTION )
pView->Select( pCursor, sal_False );
}
pCursor = pEntry;
ToTop( pCursor );
if( pCursor )
{
pView->SetEntryFocus(pCursor, sal_True );
if( pView->GetSelectionMode() == SINGLE_SELECTION )
pView->Select( pCursor, sal_True );
ShowCursor( sal_True );
}
}
void SvImpIconView::ShowCursor( sal_Bool bShow )
{
if( !pCursor || !bShow || !pView->HasFocus() )
{
pView->HideFocus();
return;
}
Rectangle aRect ( CalcFocusRect( pCursor ) );
pView->ShowFocus( aRect );
}
void SvImpIconView::HideDDIcon()
{
pView->Update();
ImpHideDDIcon();
pDDBufDev = pDDDev;
pDDDev = 0;
}
void SvImpIconView::ImpHideDDIcon()
{
if( pDDDev )
{
Size aSize( pDDDev->GetOutputSizePixel() );
// pView restaurieren
pView->DrawOutDev( aDDLastRectPos, aSize, Point(), aSize, *pDDDev );
}
}
void SvImpIconView::ShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPosPix )
{
pView->Update();
if( pRefEntry != pDDRefEntry )
{
DELETEZ(pDDDev);
DELETEZ(pDDBufDev);
}
sal_Bool bSelected = pView->SvListView::Select( pRefEntry, sal_False );
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 = GetBoundingRect( pRefEntry );
pDDDev->SetOutputSizePixel( rRect.GetSize() );
Point aPos( rPosPix );
CalcDocPos( aPos );
Size aSize( pDDDev->GetOutputSizePixel() );
pDDRefEntry = pRefEntry;
aDDLastEntryPos = aPos;
aDDLastRectPos = aPos;
// Hintergrund sichern
pDDDev->DrawOutDev( Point(), aSize, aPos, aSize, *pView );
// Icon in pView malen
nFlags |= F_NO_EMPHASIS;
PaintEntry( pRefEntry, aPos );
nFlags &= ~F_NO_EMPHASIS;
if( bSelected )
pView->SvListView::Select( pRefEntry, sal_True );
}
void SvImpIconView::HideShowDDIcon( SvLBoxEntry* 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 );
CalcDocPos( aCurEntryPos );
const Rectangle& rRect = GetBoundingRect( 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;
nFlags |= F_NO_EMPHASIS;
PaintEntry( pRefEntry, aRelPos, 0, pDDTempDev );
nFlags &= ~F_NO_EMPHASIS;
aDDLastRectPos = aFullPos;
aDDLastEntryPos = aCurEntryPos;
pView->DrawOutDev(
aDDLastRectPos,
pDDDev->GetOutputSizePixel(),
aEmptyPoint,
pDDDev->GetOutputSizePixel(),
*pDDTempDev );
sal_Bool bSelected = pView->SvListView::Select( pRefEntry, sal_False );
if( bSelected )
pView->SvListView::Select( pRefEntry, sal_True );
}
void SvImpIconView::ShowTargetEmphasis( SvLBoxEntry* pEntry, sal_Bool )
{
CheckBoundingRects();
Rectangle aRect;
if( pEntry != pCurParent &&
(pEntry->HasChilds() || pEntry->HasChildsOnDemand()) )
aRect = CalcBmpRect( pEntry );
else
{
aRect.SetSize( aOutputSize );
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin());
aOrigin *= -1; // in Doc-Koord wandeln
aRect.SetPos( aOrigin );
aRect.Left()++; aRect.Top()++;
aRect.Right()--; aRect.Bottom()--;
}
ImpDrawXORRect( aRect );
}
sal_Bool SvImpIconView::NotifyMoving( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry,
SvLBoxEntry*& rpNewPar, sal_uLong& rNewChildPos )
{
if( pTarget == pCurParent && pModel->GetParent(pEntry) == pCurParent )
{
// D&D innerhalb einer Childlist
StopEditTimer();
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
Size aSize( pViewData->aRect.GetSize() );
Point aNewPos = FindNextEntryPos( aSize );
AdjustVirtSize( Rectangle( aNewPos, aSize ) );
SetEntryPosition( pEntry, aNewPos, sal_False, sal_True );
return sal_False;
}
return pView->SvLBox::NotifyMoving(pTarget,pEntry,rpNewPar,rNewChildPos);
}
sal_Bool SvImpIconView::NotifyCopying( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry,
SvLBoxEntry*& rpNewParent, sal_uLong& rNewChildPos )
{
return pView->SvLBox::NotifyCopying(pTarget,pEntry,rpNewParent,rNewChildPos);
}
void SvImpIconView::WriteDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo)
{
SvLBoxEntry* pCurEntry = GetCurEntry();
Point aEntryPos;
if( pCurEntry )
{
aEntryPos = rPos;
aEntryPos -= GetEntryPosition( pCurEntry );
}
pInfo->nMouseRelX = aEntryPos.X();
pInfo->nMouseRelY = aEntryPos.Y();
}
void SvImpIconView::ReadDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo )
{
Point aDropPos( rPos );
aDropPos.X() -= pInfo->nMouseRelX;
aDropPos.Y() -= pInfo->nMouseRelY;
SetNextEntryPos( aDropPos );
}
void SvImpIconView::InvalidateBoundingRect( SvLBoxEntry* pEntry )
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
InvalidateBoundingRect( pViewData->aRect );
}
void SvImpIconView::PrepareCommandEvent( const Point& rPt )
{
aMouseMoveTimer.Stop();
StopEditTimer();
nFlags |= F_CMD_ARRIVED;
SvLBoxEntry* pEntry = pView->GetEntry( rPt, sal_True );
if( (nFlags & F_DOWN_CTRL) && pEntry && !pView->IsSelected(pEntry) )
pView->Select( pEntry, sal_True );
nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
}
void SvImpIconView::SttDrag( const Point& rPos )
{
PrepareCommandEvent( rPos );
nFlags |= F_DRAG_SOURCE;
ShowCursor( sal_False );
}
void SvImpIconView::EndDrag()
{
ShowCursor( sal_True );
nFlags &= (~F_DRAG_SOURCE);
}
void SvImpIconView::ToTop( SvLBoxEntry* pEntry )
{
DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"ToTop:ZOrder?");
if( pZOrderList->GetObject( pZOrderList->Count() -1 ) != pEntry )
{
sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry );
pZOrderList->Remove( nPos, 1 );
pZOrderList->Insert( pEntry, pZOrderList->Count() );
}
}
void SvImpIconView::SetCurParent( SvLBoxEntry* pNewParent )
{
Clear();
pCurParent = pNewParent;
ImpArrange();
}
void SvImpIconView::ClipAtVirtOutRect( Rectangle& rRect ) const
{
if( rRect.Bottom() >= aVirtOutputSize.Height() )
rRect.Bottom() = aVirtOutputSize.Height() - 1;
if( rRect.Right() >= aVirtOutputSize.Width() )
rRect.Right() = aVirtOutputSize.Width() - 1;
if( rRect.Top() < 0 )
rRect.Top() = 0;
if( rRect.Left() < 0 )
rRect.Left() = 0;
}
// rRect: Bereich des Dokumentes (in Dokumentkoordinaten), der
// sichtbar gemacht werden soll.
// bScrBar == sal_True: Das Rect wurde aufgrund eines ScrollBar-Events berechnet
void SvImpIconView::MakeVisible( const Rectangle& rRect, sal_Bool bScrBar )
{
Rectangle aRect( rRect );
ClipAtVirtOutRect( aRect );
MapMode aMapMode( pView->GetMapMode() );
Point aOrigin( aMapMode.GetOrigin() );
// in Dokumentkoordinate umwandeln
aOrigin *= -1;
Rectangle aOutputArea( aOrigin, aOutputSize );
if( aOutputArea.IsInside( aRect ) )
return; // ist schon sichtbar
long nDy;
if( aRect.Top() < aOutputArea.Top() )
{
// nach oben scrollen (nDy < 0)
nDy = aRect.Top() - aOutputArea.Top();
}
else if( aRect.Bottom() > aOutputArea.Bottom() )
{
// nach unten scrollen (nDy > 0)
nDy = aRect.Bottom() - aOutputArea.Bottom();
}
else
nDy = 0;
long nDx;
if( aRect.Left() < aOutputArea.Left() )
{
// nach links scrollen (nDx < 0)
nDx = aRect.Left() - aOutputArea.Left();
}
else if( aRect.Right() > aOutputArea.Right() )
{
// nach rechts scrollen (nDx > 0)
nDx = aRect.Right() - aOutputArea.Right();
}
else
nDx = 0;
aOrigin.X() += nDx;
aOrigin.Y() += nDy;
aOutputArea.SetPos( aOrigin );
pView->Update();
// Origin fuer SV invertieren (damit wir in
// Dokumentkoordinaten scrollen/painten koennen)
aOrigin *= -1;
aMapMode.SetOrigin( aOrigin );
pView->SetMapMode( aMapMode );
// in umgekehrte Richtung scrollen!
pView->Control::Scroll( -nDx, -nDy, aOutputArea, sal_True );
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() );
}
}
// pruefen, ob ScrollBars noch benoetigt werden
CheckScrollBars();
pView->Update();
}
SvLBoxEntry* SvImpIconView::GetNewCursor()
{
SvLBoxEntry* pNewCursor;
if( pCursor )
{
pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_False );
if( !pNewCursor )
{
pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_True );
if( !pNewCursor )
{
pNewCursor = pImpCursor->GoUpDown( pCursor, sal_False );
if( !pNewCursor )
pNewCursor = pImpCursor->GoUpDown( pCursor, sal_True );
}
}
}
else
pNewCursor = pModel->FirstChild( pCurParent );
DBG_ASSERT(!pNewCursor|| (pCursor&&pCursor!=pNewCursor),"GetNewCursor failed");
return pNewCursor;
}
sal_uInt16 SvImpIconView:: GetSelectionCount() const
{
sal_uInt16 nSelected = 0;
SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent);
while( pEntry )
{
if( pView->IsSelected( pEntry ) )
nSelected++;
pEntry = pModel->NextSibling( pEntry );
}
return nSelected;
}
void SvImpIconView::ToggleSelection( SvLBoxEntry* pEntry )
{
sal_Bool bSel;
if( pView->IsSelected( pEntry ) )
bSel = sal_False;
else
bSel = sal_True;
pView->Select( pEntry, bSel );
}
void SvImpIconView::DeselectAllBut( SvLBoxEntry* pThisEntryNot )
{
ClearSelectedRectList();
SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent );
while( pEntry )
{
if( pEntry != pThisEntryNot && pView->IsSelected( pEntry ))
pView->Select( pEntry, sal_False );
pEntry = pModel->NextSibling( pEntry );
}
}
#define ICN_ROWS 50
#define ICN_COLS 30
ImpIcnCursor::ImpIcnCursor( SvImpIconView* pOwner )
{
pView = pOwner;
pColumns = 0;
pRows = 0;
pCurEntry = 0;
nDeltaWidth = 0;
nDeltaHeight= 0;
nCols = 0;
nRows = 0;
nGridCols = 0;
nGridRows = 0;
pGridMap = 0;
}
ImpIcnCursor::~ImpIcnCursor()
{
delete[] pColumns;
delete[] pRows;
delete pGridMap;
}
sal_uInt16 ImpIcnCursor::GetSortListPos( SvPtrarr* pList, long nValue,
int bVertical )
{
sal_uInt16 nCount = (sal_uInt16)pList->Count();
if( !nCount )
return 0;
sal_uInt16 nCurPos = 0;
long nPrevValue = LONG_MIN;
while( nCount )
{
const Rectangle& rRect=
pView->GetBoundingRect((SvLBoxEntry*)(pList->GetObject(nCurPos)));
long nCurValue;
if( bVertical )
nCurValue = rRect.Top();
else
nCurValue = rRect.Left();
if( nValue >= nPrevValue && nValue <= nCurValue )
return (sal_uInt16)nCurPos;
nPrevValue = nCurValue;
nCount--;
nCurPos++;
}
return pList->Count();
}
void ImpIcnCursor::ImplCreate()
{
pView->CheckBoundingRects();
DBG_ASSERT(pColumns==0&&pRows==0,"ImplCreate: Not cleared");
SetDeltas();
pColumns = new SvPtrarr[ nCols ];
pRows = new SvPtrarr[ nRows ];
DELETEZ(pGridMap);
SvLBoxTreeList* pModel = pView->pModel;
SvLBoxEntry* pEntry = pModel->FirstChild( pView->pCurParent );
while( pEntry )
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry);
// const Rectangle& rRect = pView->GetBoundingRect( pEntry );
Rectangle rRect( pView->CalcBmpRect( pEntry,0,pViewData ) );
short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / nDeltaHeight );
short nX = (short)( ((rRect.Left()+rRect.Right())/2) / nDeltaWidth );
// Rundungsfehler abfangen
if( nY >= nRows )
nY = sal::static_int_cast< short >(nRows - 1);
if( nX >= nCols )
nX = sal::static_int_cast< short >(nCols - 1);
sal_uInt16 nIns = GetSortListPos( &pColumns[nX], rRect.Top(), sal_True );
pColumns[ nX ].Insert( pEntry, nIns );
nIns = GetSortListPos( &pRows[nY], rRect.Left(), sal_False );
pRows[ nY ].Insert( pEntry, nIns );
pViewData->nX = nX;
pViewData->nY = nY;
pEntry = pModel->NextSibling( pEntry );
}
}
void ImpIcnCursor::CreateGridMap()
{
if( pGridMap )
return;
const Size& rSize = pView->aVirtOutputSize;
long nWidth = rSize.Width();
if( nWidth < pView->nMaxVirtWidth )
nWidth = pView->nMaxVirtWidth;
nWidth -= 2*LROFFS_WINBORDER;
if( nWidth <= 0 )
nWidth = 1;
nGridDX = pView->nGridDX;
nGridDY = pView->nGridDY;
// Hinweis: Wegen der Abrundung bei Berechnung von nGridCols
// ist es moeglich, dass Eintrage nicht im Grid liegen. Diese
// wurden typischerweise manuell verschoben und gelockt
nGridCols = nWidth / nGridDX;
if( !nGridCols ) nGridCols = 1;
nGridRows = rSize.Height() / nGridDY;
// nRows nicht abrunden, da zur Vermeidung von Ueberlappungen
// das gesamte BoundingRect des Eintrags zur Markierung im Grid
// herangezogen wird.
if( (nGridRows * nGridDY) < rSize.Height() )
nGridRows++;
else if( !nGridRows )
nGridRows = 1;
//XXX
//nGridRows += 50; // in fuenfziger-Schritten
pGridMap = new sal_Bool[ nGridRows*nGridCols];
memset( (void*)pGridMap, 0, nGridRows*nGridCols );
SvLBoxTreeList* pModel = pView->pModel;
SvLBoxEntry* pEntry = pModel->FirstChild( pView->pCurParent );
while( pEntry )
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry);
const Rectangle& rRect = pViewData->aRect;
// nur, wenn der Entry schon plaziert ist
if( pView->IsBoundingRectValid( rRect ))
{
// Alle vom Eintrag beruehrten Grids kennzeichnen
SetGridUsed( pView->GetBoundingRect( pEntry, pViewData ) );
}
pEntry = pModel->NextSibling( pEntry );
}
}
sal_Bool ImpIcnCursor::GetGrid( const Point& rDocPos, sal_uInt16& rGridX, sal_uInt16& rGridY ) const
{
Point aPos( rDocPos );
aPos.X() -= LROFFS_WINBORDER;
aPos.Y() -= TBOFFS_WINBORDER;
rGridX = (sal_uInt16)(aPos.X() / nGridDX);
rGridY = (sal_uInt16)(aPos.Y() / nGridDY);
sal_Bool bInGrid = sal_True;
if( rGridX >= nGridCols )
{
rGridX = sal::static_int_cast< sal_uInt16 >(nGridCols - 1);
bInGrid = sal_False;
}
if( rGridY >= nGridRows )
{
rGridY = sal::static_int_cast< sal_uInt16 >(nGridRows - 1);
if( !bInGrid )
return sal_False; // beide Koordinaten nicht im Grid
}
return sal_True;
}
void ImpIcnCursor::SetGridUsed( const Rectangle& rRect, sal_Bool bUsed )
{
CreateGridMap();
sal_uInt16 nTLX, nTLY, nBRX, nBRY;
sal_Bool bTLInGrid = GetGrid( rRect.TopLeft(), nTLX, nTLY );
sal_Bool bBRInGrid = GetGrid( rRect.BottomRight(), nBRX, nBRY );
if( !bTLInGrid && !bBRInGrid )
return;
for( sal_uInt16 nCurY = nTLY; nCurY <= nBRY; nCurY++ )
{
for( sal_uInt16 nCurX = nTLX; nCurX <= nBRX; nCurX++ )
{
SetGridUsed( nCurX, nCurY, bUsed );
}
}
}
void ImpIcnCursor::Clear( sal_Bool bGridToo )
{
if( pColumns )
{
delete[] pColumns;
delete[] pRows;
pColumns = 0;
pRows = 0;
pCurEntry = 0;
nDeltaWidth = 0;
nDeltaHeight = 0;
}
if( bGridToo && pGridMap )
{
DELETEZ(pGridMap);
nGridRows = 0;
nGridCols = 0;
}
}
SvLBoxEntry* ImpIcnCursor::SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom,
sal_uInt16, sal_Bool bDown, sal_Bool bSimple )
{
DBG_ASSERT(pCurEntry,"SearchCol: No reference entry");
SvPtrarr* pList = &(pColumns[ nCol ]);
sal_uInt16 nCount = pList->Count();
if( !nCount )
return 0;
const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry);
if( bSimple )
{
sal_uInt16 nListPos = pList->GetPos( pCurEntry );
DBG_ASSERT(nListPos!=0xffff,"Entry not in Col-List");
if( bDown )
{
while( nListPos < nCount-1 )
{
nListPos++;
SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos );
const Rectangle& rRect = pView->GetBoundingRect( pEntry );
if( rRect.Top() > rRefRect.Top() )
return pEntry;
}
return 0;
}
else
{
while( nListPos )
{
nListPos--;
if( nListPos < nCount )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos );
const Rectangle& rRect = pView->GetBoundingRect( pEntry );
if( rRect.Top() < rRefRect.Top() )
return pEntry;
}
}
return 0;
}
}
if( nTop > nBottom )
{
sal_uInt16 nTemp = nTop;
nTop = nBottom;
nBottom = nTemp;
}
long nMinDistance = LONG_MAX;
SvLBoxEntry* pResult = 0;
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur ));
if( pEntry != pCurEntry )
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry);
sal_uInt16 nY = pViewData->nY;
if( nY >= nTop && nY <= nBottom )
{
const Rectangle& rRect = pView->GetBoundingRect( pEntry );
long nDistance = rRect.Top() - rRefRect.Top();
if( nDistance < 0 )
nDistance *= -1;
if( nDistance && nDistance < nMinDistance )
{
nMinDistance = nDistance;
pResult = pEntry;
}
}
}
}
return pResult;
}
SvLBoxEntry* ImpIcnCursor::SearchRow(sal_uInt16 nRow,sal_uInt16 nLeft,sal_uInt16 nRight,
sal_uInt16, sal_Bool bRight, sal_Bool bSimple )
{
DBG_ASSERT(pCurEntry,"SearchRow: No reference entry");
SvPtrarr* pList = &(pRows[ nRow ]);
sal_uInt16 nCount = pList->Count();
if( !nCount )
return 0;
const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry);
if( bSimple )
{
sal_uInt16 nListPos = pList->GetPos( pCurEntry );
DBG_ASSERT(nListPos!=0xffff,"Entry not in Row-List");
if( bRight )
{
while( nListPos < nCount-1 )
{
nListPos++;
SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos );
const Rectangle& rRect = pView->GetBoundingRect( pEntry );
if( rRect.Left() > rRefRect.Left() )
return pEntry;
}
return 0;
}
else
{
while( nListPos )
{
nListPos--;
if( nListPos < nCount )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos );
const Rectangle& rRect = pView->GetBoundingRect( pEntry );
if( rRect.Left() < rRefRect.Left() )
return pEntry;
}
}
return 0;
}
}
if( nRight < nLeft )
{
sal_uInt16 nTemp = nRight;
nRight = nLeft;
nLeft = nTemp;
}
long nMinDistance = LONG_MAX;
SvLBoxEntry* pResult = 0;
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur ));
if( pEntry != pCurEntry )
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry);
sal_uInt16 nX = pViewData->nX;
if( nX >= nLeft && nX <= nRight )
{
const Rectangle& rRect = pView->GetBoundingRect( pEntry );
long nDistance = rRect.Left() - rRefRect.Left();
if( nDistance < 0 )
nDistance *= -1;
if( nDistance && nDistance < nMinDistance )
{
nMinDistance = nDistance;
pResult = pEntry;
}
}
}
}
return pResult;
}
/*
Sucht ab dem uebergebenen Eintrag den naechsten rechts- bzw.
linksstehenden. Suchverfahren am Beispiel bRight = sal_True:
c
b c
a b c
S 1 1 1 ====> Suchrichtung
a b c
b c
c
S : Startposition
1 : erstes Suchrechteck
a,b,c : 2., 3., 4. Suchrechteck
*/
SvLBoxEntry* ImpIcnCursor::GoLeftRight( SvLBoxEntry* pIcnEntry, sal_Bool bRight )
{
SvLBoxEntry* pResult;
pCurEntry = pIcnEntry;
Create();
SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pIcnEntry);
sal_uInt16 nY = pViewData->nY;
sal_uInt16 nX = pViewData->nX;
DBG_ASSERT(nY< nRows,"GoLeftRight:Bad column");
DBG_ASSERT(nX< nCols,"GoLeftRight:Bad row");
// Nachbar auf gleicher Zeile ?
if( bRight )
pResult = SearchRow(
nY, nX, sal::static_int_cast< sal_uInt16 >(nCols-1), nX, sal_True, sal_True );
else
pResult = SearchRow( nY, nX ,0, nX, sal_False, sal_True );
if( pResult )
return pResult;
long nCurCol = nX;
long nColOffs, nLastCol;
if( bRight )
{
nColOffs = 1;
nLastCol = nCols;
}
else
{
nColOffs = -1;
nLastCol = -1; // 0-1
}
sal_uInt16 nRowMin = nY;
sal_uInt16 nRowMax = nY;
do
{
SvLBoxEntry* pEntry = SearchCol((sal_uInt16)nCurCol,nRowMin,nRowMax,nY,sal_True, sal_False);
if( pEntry )
return pEntry;
if( nRowMin )
nRowMin--;
if( nRowMax < (nRows-1))
nRowMax++;
nCurCol += nColOffs;
} while( nCurCol != nLastCol );
return 0;
}
SvLBoxEntry* ImpIcnCursor::GoUpDown( SvLBoxEntry* pIcnEntry, sal_Bool bDown)
{
SvLBoxEntry* pResult;
pCurEntry = pIcnEntry;
Create();
SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pIcnEntry);
sal_uInt16 nY = pViewData->nY;
sal_uInt16 nX = pViewData->nX;
DBG_ASSERT(nY<nRows,"GoUpDown:Bad column");
DBG_ASSERT(nX<nCols,"GoUpDown:Bad row");
// Nachbar in gleicher Spalte ?
if( bDown )
pResult = SearchCol(
nX, nY, sal::static_int_cast< sal_uInt16 >(nRows-1), nY, sal_True, sal_True );
else
pResult = SearchCol( nX, nY ,0, nY, sal_False, sal_True );
if( pResult )
return pResult;
long nCurRow = nY;
long nRowOffs, nLastRow;
if( bDown )
{
nRowOffs = 1;
nLastRow = nRows;
}
else
{
nRowOffs = -1;
nLastRow = -1; // 0-1
}
sal_uInt16 nColMin = nX;
sal_uInt16 nColMax = nX;
do
{
SvLBoxEntry* pEntry = SearchRow((sal_uInt16)nCurRow,nColMin,nColMax,nX,sal_True, sal_False);
if( pEntry )
return pEntry;
if( nColMin )
nColMin--;
if( nColMax < (nCols-1))
nColMax++;
nCurRow += nRowOffs;
} while( nCurRow != nLastRow );
return 0;
}
void ImpIcnCursor::SetDeltas()
{
const Size& rSize = pView->aVirtOutputSize;
if( pView->nFlags & F_GRIDMODE )
{
nGridDX = pView->nGridDX;
nGridDY = pView->nGridDY;
}
else
{
nGridDX = 20;
nGridDY = 20;
}
nCols = rSize.Width() / nGridDX;
if( !nCols )
nCols = 1;
nRows = rSize.Height() / nGridDY;
if( (nRows * nGridDY) < rSize.Height() )
nRows++;
if( !nRows )
nRows = 1;
nDeltaWidth = (short)(rSize.Width() / nCols);
nDeltaHeight = (short)(rSize.Height() / nRows);
if( !nDeltaHeight )
{
nDeltaHeight = 1;
DBG_WARNING("SetDeltas:Bad height");
}
if( !nDeltaWidth )
{
nDeltaWidth = 1;
DBG_WARNING("SetDeltas:Bad width");
}
}
void ImpIcnCursor::ExpandGrid()
{
if( pGridMap )
{
long nNewGridRows = nGridRows + 20;
unsigned char* pTempMap = new unsigned char[ nNewGridRows * nGridCols ];
memcpy( pTempMap, pGridMap, nGridRows * nGridCols );
delete pGridMap;
pGridMap = pTempMap;
nGridRows = nNewGridRows;
}
}
sal_Bool ImpIcnCursor::FindEmptyGridRect( Rectangle& rRect )
{
CreateGridMap();
sal_uInt16 nCount = (sal_uInt16)(nGridCols * nGridRows);
if( !nCount )
return sal_False;
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
if( !pGridMap[ nCur ] )
{
sal_uInt16 nCol = (sal_uInt16)(nCur % nGridCols);
sal_uInt16 nRow = (sal_uInt16)(nCur / nGridCols);
rRect.Top() = nRow * nGridDY + TBOFFS_WINBORDER;
rRect.Bottom() = rRect.Top() + nGridDY;
rRect.Left() = nCol * nGridDX+ LROFFS_WINBORDER;
rRect.Right() = rRect.Left() + nGridDX;
SetGridUsed( nCol, nRow, sal_True );
//XXX
//if( nRow + 5 > nGridRows )
// ExpandGrid();
DBG_ASSERT(pGridMap[nCur],"SetGridUsed failed");
return sal_True;
}
}
// Gridmap ist voll: Um eine Zeile erweitern
rRect.Top() = nGridRows * nGridDY + TBOFFS_WINBORDER;
rRect.Bottom() = rRect.Top() + nGridDY;
rRect.Left() = LROFFS_WINBORDER;
rRect.Right() = rRect.Left() + nGridDX;
return sal_False;
//XXX
//ExpandGrid();
//return sal_True;
}
void ImpIcnCursor::CreateGridAjustData( SvPtrarr& rLists, SvLBoxEntry* pRefEntry)
{
if( !pRefEntry )
{
sal_uInt16 nAdjustRows = (sal_uInt16)(pView->aVirtOutputSize.Height() / pView->nGridDY);
nAdjustRows++; // wg. Abrundung!
if( !nAdjustRows )
return;
for( sal_uInt16 nCurList = 0; nCurList < nAdjustRows; nCurList++ )
{
SvPtrarr* pRow = new SvPtrarr;
rLists.Insert( (void*)pRow, nCurList );
}
SvLBoxEntry* pEntry = pView->pModel->FirstChild( pView->pCurParent );
while( pEntry )
{
const Rectangle& rRect = pView->GetBoundingRect( pEntry );
short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY );
sal_uInt16 nIns = GetSortListPos((SvPtrarr*)rLists[nY],rRect.Left(),sal_False);
((SvPtrarr*)rLists[ nY ])->Insert( pEntry, nIns );
pEntry = pView->pModel->NextSibling( pEntry );
}
}
else
{
// Aufbau eines hor. "Schlauchs" auf der RefEntry-Zeile
// UEBERLEGEN: BoundingRect nehmen wg. Ueberlappungen???
Rectangle rRefRect( pView->CalcBmpRect( pRefEntry ) );
//const Rectangle& rRefRect = pView->GetBoundingRect( pRefEntry );
short nRefRow = (short)( ((rRefRect.Top()+rRefRect.Bottom())/2) / pView->nGridDY );
SvPtrarr* pRow = new SvPtrarr;
rLists.Insert( (void*)pRow, 0 );
SvLBoxEntry* pEntry = pView->pModel->FirstChild( pView->pCurParent );
while( pEntry )
{
Rectangle rRect( pView->CalcBmpRect(pEntry) );
//const Rectangle& rRect = pView->GetBoundingRect( pEntry );
short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY );
if( nY == nRefRow )
{
sal_uInt16 nIns = GetSortListPos( pRow, rRect.Left(), sal_False );
pRow->Insert( pEntry, nIns );
}
pEntry = pView->pModel->NextSibling( pEntry );
}
}
}
//static
void ImpIcnCursor::DestroyGridAdjustData( SvPtrarr& rLists )
{
sal_uInt16 nCount = rLists.Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
SvPtrarr* pArr = (SvPtrarr*)rLists[ nCur ];
delete pArr;
}
rLists.Remove( 0, rLists.Count() );
}
void SvImpIconView::SetGrid( long nDX, long nDY )
{
nGridDX = nDX;
nGridDY = nDY;
nFlags |= F_GRIDMODE;
}
Rectangle SvImpIconView::CalcMaxTextRect( const SvLBoxEntry* pEntry,
const SvIcnVwDataEntry* pViewData ) const
{
Rectangle aRect = pViewData->aGridRect;
long nBmpHeight = ((SvLBoxEntry*)pEntry)->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,(SvLBoxEntry*)pEntry).Height();
aRect.Top() += nBmpHeight;
aRect.Top() += ICONVIEW_OFFS_BMP_STRING;
if( aRect.Top() > aRect.Bottom())
aRect.Top() = aRect.Bottom();
aRect.Left() += LROFFS_BOUND;
aRect.Left()++;
aRect.Right() -= LROFFS_BOUND;
aRect.Right()--;
if( aRect.Left() > aRect.Right())
aRect.Left() = aRect.Right();
if( GetTextMode( pEntry, pViewData ) == ShowTextFull )
aRect.Bottom() = LONG_MAX;
return aRect;
}
void SvImpIconView::Center( SvLBoxEntry* pEntry,
SvIcnVwDataEntry* pViewData ) const
{
SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
const String& rEntryText = pStringItem->GetText();
Rectangle aTextRect = CalcMaxTextRect(pEntry,pViewData);
aTextRect = GetTextRect( pView, aTextRect, rEntryText, DRAWTEXT_FLAGS );
pViewData->aTextSize = aTextRect.GetSize();
pViewData->aRect = pViewData->aGridRect;
Size aSize( CalcBoundingSize( pEntry, pViewData ) );
long nBorder = pViewData->aGridRect.GetWidth() - aSize.Width();
pViewData->aRect.Left() += nBorder / 2;
pViewData->aRect.Right() -= nBorder / 2;
pViewData->aRect.Bottom() = pViewData->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 SvImpIconView::Scroll( long nDeltaX, long nDeltaY, sal_Bool bScrollBar )
{
const MapMode& rMapMode = pView->GetMapMode();
Point aOrigin( rMapMode.GetOrigin() );
// in Dokumentkoordinate umwandeln
aOrigin *= -1;
aOrigin.Y() += nDeltaY;
aOrigin.X() += nDeltaX;
Rectangle aRect( aOrigin, aOutputSize );
MakeVisible( aRect, bScrollBar );
}
const Size& SvImpIconView::GetItemSize( SvIconView* pIconView,
SvLBoxEntry* pEntry, SvLBoxItem* pItem, const SvIcnVwDataEntry* pViewData) const
{
if( (nFlags & F_GRIDMODE) && pItem->IsA() == SV_ITEM_ID_LBOXSTRING )
{
if( !pViewData )
pViewData = ICNVIEWDATA(pEntry);
return pViewData->aTextSize;
}
else
return pItem->GetSize( pIconView, pEntry );
}
Rectangle SvImpIconView::CalcFocusRect( SvLBoxEntry* pEntry )
{
#if !defined(OS2)
SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
DBG_ASSERT(pStringItem,"Text not set");
return CalcTextRect( pEntry, pStringItem );
#else
return CalcBmpRect( pEntry );
#endif
}
void SvImpIconView::SelectRect( const Rectangle& rRect, sal_Bool bAdd,
SvPtrarr* pOtherRects, short nBorderOffs )
{
if( !pZOrderList || !pZOrderList->Count() )
return;
CheckBoundingRects();
pView->Update();
sal_uInt16 nCount = pZOrderList->Count();
Rectangle aRect( rRect );
aRect.Justify();
if( nBorderOffs )
{
aRect.Left() -= nBorderOffs;
aRect.Right() += nBorderOffs;
aRect.Top() -= nBorderOffs;
aRect.Bottom() += nBorderOffs;
}
sal_Bool bCalcOverlap = (bAdd && pOtherRects && pOtherRects->Count()) ? sal_True : sal_False;
for( sal_uInt16 nPos = 0; nPos < nCount; nPos++ )
{
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nPos ));
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
DBG_ASSERT(pViewData,"Entry not in model");
if( !IsBoundingRectValid( pViewData->aRect ))
FindBoundingRect( pEntry, pViewData );
const Rectangle& rBoundRect = pViewData->aRect;
sal_Bool bSelected = pViewData->IsSelected();
sal_Bool bOverlaps;
if( bCalcOverlap )
bOverlaps = IsOver( pOtherRects, rBoundRect );
else
bOverlaps = sal_False;
sal_Bool bOver = aRect.IsOver( rBoundRect );
if( bOver && !bOverlaps )
{
// Ist im neuen Selektionsrechteck und in keinem alten
// => selektieren
if( !bSelected )
pView->Select( pEntry, sal_True );
}
else if( !bAdd )
{
// ist ausserhalb des Selektionsrechtecks
// => Selektion entfernen
if( bSelected )
pView->Select( pEntry, sal_False );
}
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( rBoundRect.IsOver( rRect))
{
// Schnittmenge zwischen alten Rects & aktuellem Rect desel.
if( bSelected )
pView->Select( pEntry, sal_False );
}
else
{
// Eintrag eines alten Rects selektieren
if( !bSelected )
pView->Select( pEntry, sal_True );
}
}
else if( !bOver && bSelected )
{
// Der Eintrag liegt voellig ausserhalb und wird deshalb desel.
pView->Select( pEntry, sal_False );
}
}
pView->Update();
}
sal_Bool SvImpIconView::IsOver( SvPtrarr* pRectList, const Rectangle& rBoundRect ) const
{
sal_uInt16 nCount = pRectList->Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
Rectangle* pRect = (Rectangle*)pRectList->GetObject( nCur );
if( rBoundRect.IsOver( *pRect ))
return sal_True;
}
return sal_False;
}
void SvImpIconView::AddSelectedRect( const Rectangle& rRect, short nBorderOffs )
{
Rectangle* pRect = new Rectangle( rRect );
pRect->Justify();
if( nBorderOffs )
{
pRect->Left() -= nBorderOffs;
pRect->Right() += nBorderOffs;
pRect->Top() -= nBorderOffs;
pRect->Bottom() += nBorderOffs;
}
aSelectedRectList.Insert( (void*)pRect, aSelectedRectList.Count() );
}
void SvImpIconView::ClearSelectedRectList()
{
sal_uInt16 nCount = aSelectedRectList.Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
Rectangle* pRect = (Rectangle*)aSelectedRectList.GetObject( nCur );
delete pRect;
}
aSelectedRectList.Remove( 0, aSelectedRectList.Count() );
}
void SvImpIconView::DrawSelectionRect( const Rectangle& rRect )
{
pView->HideTracking();
nFlags |= F_SELRECT_VISIBLE;
pView->ShowTracking( rRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
aCurSelectionRect = rRect;
}
void SvImpIconView::HideSelectionRect()
{
if( nFlags & F_SELRECT_VISIBLE )
{
pView->HideTracking();
nFlags &= ~F_SELRECT_VISIBLE;
}
}
void SvImpIconView::ImpDrawXORRect( const Rectangle& rRect )
{
RasterOp eOldOp = pView->GetRasterOp();
pView->SetRasterOp( ROP_XOR );
Color aOldColor = pView->GetFillColor();
pView->SetFillColor();
pView->DrawRect( rRect );
pView->SetFillColor( aOldColor );
pView->SetRasterOp( eOldOp );
}
void SvImpIconView::CalcScrollOffsets( const Point& rPosPixel,
long& rX, long& rY, sal_Bool bInDragDrop, sal_uInt16 nBorderWidth)
{
// Scrolling der View, falls sich der Mauszeiger im Grenzbereich des
// Fensters befindet
long nPixelToScrollX = 0;
long nPixelToScrollY = 0;
Size aWndSize = aOutputSize;
nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Height()-1), (long)nBorderWidth ));
nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Width()-1), (long)nBorderWidth ));
if ( rPosPixel.X() < nBorderWidth )
{
if( bInDragDrop )
nPixelToScrollX = -DD_SCROLL_PIXEL;
else
nPixelToScrollX = rPosPixel.X()- nBorderWidth;
}
else if ( rPosPixel.X() > aWndSize.Width() - nBorderWidth )
{
if( bInDragDrop )
nPixelToScrollX = DD_SCROLL_PIXEL;
else
nPixelToScrollX = rPosPixel.X() - (aWndSize.Width() - nBorderWidth);
}
if ( rPosPixel.Y() < nBorderWidth )
{
if( bInDragDrop )
nPixelToScrollY = -DD_SCROLL_PIXEL;
else
nPixelToScrollY = rPosPixel.Y() - nBorderWidth;
}
else if ( rPosPixel.Y() > aWndSize.Height() - nBorderWidth )
{
if( bInDragDrop )
nPixelToScrollY = DD_SCROLL_PIXEL;
else
nPixelToScrollY = rPosPixel.Y() - (aWndSize.Height() - nBorderWidth);
}
rX = nPixelToScrollX;
rY = nPixelToScrollY;
}
IMPL_LINK(SvImpIconView, MouseMoveTimeoutHdl, Timer*, pTimer )
{
pTimer->Start();
MouseMove( aMouseMoveEvent );
return 0;
}
void SvImpIconView::EndTracking()
{
pView->ReleaseMouse();
if( nFlags & F_RUBBERING )
{
aMouseMoveTimer.Stop();
nFlags &= ~(F_RUBBERING | F_ADD_MODE);
}
}
sal_Bool SvImpIconView::IsTextHit( SvLBoxEntry* pEntry, const Point& rDocPos )
{
SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
if( pItem )
{
Rectangle aRect( CalcTextRect( pEntry, pItem ));
if( aRect.IsInside( rDocPos ) )
return sal_True;
}
return sal_False;
}
IMPL_LINK(SvImpIconView, EditTimeoutHdl, Timer*, EMPTYARG )
{
SvLBoxEntry* pEntry = GetCurEntry();
if( pView->IsInplaceEditingEnabled() && pEntry &&
pView->IsSelected( pEntry ))
{
pView->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 SvImpIconView::AdjustAtGrid( SvLBoxEntry* pStart )
{
SvPtrarr aLists;
pImpCursor->CreateGridAjustData( aLists, pStart );
sal_uInt16 nCount = aLists.Count();
for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
{
AdjustAtGrid( *(SvPtrarr*)aLists[ nCur ], pStart );
}
ImpIcnCursor::DestroyGridAdjustData( aLists );
CheckScrollBars();
}
// Richtet eine Zeile aus, erweitert ggf. die Breite; Bricht die Zeile nicht um
void SvImpIconView::AdjustAtGrid( const SvPtrarr& rRow, SvLBoxEntry* pStart )
{
if( !rRow.Count() )
return;
sal_Bool bGo;
if( !pStart )
bGo = sal_True;
else
bGo = sal_False;
long nCurRight = 0;
for( sal_uInt16 nCur = 0; nCur < rRow.Count(); nCur++ )
{
SvLBoxEntry* pCur = (SvLBoxEntry*)rRow[ nCur ];
if( !bGo && pCur == pStart )
bGo = sal_True;
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur);
// Massgebend (fuer das menschliche Auge) ist die Bitmap, da sonst
// durch lange Texte der Eintrag stark springen kann
const Rectangle& rBoundRect = GetBoundingRect( pCur, pViewData );
Rectangle aCenterRect( CalcBmpRect( pCur, 0, pViewData ));
if( bGo && !pViewData->IsEntryPosLocked() )
{
long nWidth = aCenterRect.GetSize().Width();
Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) );
while( aNewPos.X() < nCurRight )
aNewPos.X() += nGridDX;
if( aNewPos != rBoundRect.TopLeft() )
SetEntryPosition( pCur, aNewPos );
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 SvImpIconView::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 SvImpIconView::SetTextMode( SvIconViewTextMode eMode, SvLBoxEntry* pEntry )
{
if( !pEntry )
{
if( eTextMode != eMode )
{
if( eTextMode == ShowTextDontKnow )
eTextMode = ShowTextShort;
eTextMode = eMode;
pView->Arrange();
}
}
else
{
SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry);
if( pViewData->eTextMode != eMode )
{
pViewData->eTextMode = eMode;
pModel->InvalidateEntry( pEntry );
AdjustVirtSize( pViewData->aRect );
}
}
}
SvIconViewTextMode SvImpIconView::GetTextMode( const SvLBoxEntry* pEntry,
const SvIcnVwDataEntry* pViewData ) const
{
if( !pEntry )
return eTextMode;
else
{
if( !pViewData )
pViewData = ICNVIEWDATA(((SvLBoxEntry*)pEntry));
return pViewData->GetTextMode();
}
}
SvIconViewTextMode SvImpIconView::GetEntryTextModeSmart( const SvLBoxEntry* pEntry,
const SvIcnVwDataEntry* pViewData ) const
{
DBG_ASSERT(pEntry,"GetEntryTextModeSmart: Entry not set");
if( !pViewData )
pViewData = ICNVIEWDATA(((SvLBoxEntry*)pEntry));
SvIconViewTextMode eMode = pViewData->GetTextMode();
if( eMode == ShowTextDontKnow )
return eTextMode;
return eMode;
}
void SvImpIconView::ShowFocusRect( const SvLBoxEntry* pEntry )
{
if( !pEntry )
pView->HideFocus();
else
{
Rectangle aRect ( CalcFocusRect( (SvLBoxEntry*)pEntry ) );
pView->ShowFocus( aRect );
}
}
IMPL_LINK(SvImpIconView, UserEventHdl, void*, EMPTYARG )
{
nCurUserEvent = 0;
AdjustScrollBars();
Rectangle aRect;
if( GetResizeRect(aRect) )
PaintResizeRect( aRect );
return 0;
}
void SvImpIconView::CancelUserEvent()
{
if( nCurUserEvent )
{
Application::RemoveUserEvent( nCurUserEvent );
nCurUserEvent = 0;
}
}