summaryrefslogtreecommitdiff
path: root/svtools/source/contnr/svimpicn.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svtools/source/contnr/svimpicn.cxx')
-rw-r--r--svtools/source/contnr/svimpicn.cxx4222
1 files changed, 4222 insertions, 0 deletions
diff --git a/svtools/source/contnr/svimpicn.cxx b/svtools/source/contnr/svimpicn.cxx
new file mode 100644
index 000000000000..5d0f83c01d78
--- /dev/null
+++ b/svtools/source/contnr/svimpicn.cxx
@@ -0,0 +1,4222 @@
+/*************************************************************************
+ *
+ * $RCSfile: svimpicn.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:58:56 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (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.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <limits.h>
+#ifndef _METRIC_HXX
+#include <vcl/metric.hxx>
+#endif
+#ifndef _SV_SVAPP_HXX
+#include <vcl/svapp.hxx>
+#endif
+#ifdef DBG_UTIL
+#include <vcl/sound.hxx>
+#endif
+
+#pragma hdrstop
+
+#include <svlbox.hxx>
+#include <svicnvw.hxx>
+#ifndef _SVIMPICN_HXX
+#include <svimpicn.hxx>
+#endif
+#ifndef _SVLBITM_HXX
+#include <svlbitm.hxx>
+#endif
+#ifndef _SVARRAY_HXX
+#include "svarray.hxx"
+#endif
+
+
+
+#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 ((USHORT)0x0001)
+// #define TEXT_DRAW_3DLOOK ((USHORT)0x0002)
+// #define TEXT_DRAW_MNEMONIC ((USHORT)0x0004)
+#define TEXT_DRAW_LEFT ((USHORT)0x0010)
+#define TEXT_DRAW_CENTER ((USHORT)0x0020)
+#define TEXT_DRAW_RIGHT ((USHORT)0x0040)
+#define TEXT_DRAW_TOP ((USHORT)0x0080)
+#define TEXT_DRAW_VCENTER ((USHORT)0x0100)
+#define TEXT_DRAW_BOTTOM ((USHORT)0x0200)
+#define TEXT_DRAW_ENDELLIPSIS ((USHORT)0x0400)
+#define TEXT_DRAW_PATHELLIPSIS ((USHORT)0x0800)
+#define TEXT_DRAW_CLIP ((USHORT)0x1000)
+#define TEXT_DRAW_MULTILINE ((USHORT)0x2000)
+#define TEXT_DRAW_WORDBREAK ((USHORT)0x4000)
+
+XubString GetEllipsisString( OutputDevice* pDev,
+ const XubString& rStr, long nMaxWidth,
+ USHORT nStyle = TEXT_DRAW_ENDELLIPSIS )
+{
+ XubString aStr = rStr;
+
+ if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
+ {
+ USHORT 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;
+ USHORT mnIndex;
+ USHORT mnLen;
+
+public:
+ TextLineInfo( long nWidth, USHORT nIndex, USHORT nLen )
+ {
+ mnWidth = nWidth;
+ mnIndex = nIndex;
+ mnLen = nLen;
+ }
+
+ long GetWidth() const { return mnWidth; }
+ USHORT GetIndex() const { return mnIndex; }
+ USHORT GetLen() const { return mnLen; }
+};
+
+#define MULTITEXTLINEINFO_RESIZE 16
+typedef TextLineInfo* PTextLineInfo;
+
+class MultiTextLineInfo
+{
+private:
+ PTextLineInfo* mpLines;
+ USHORT mnLines;
+ USHORT mnSize;
+
+public:
+ MultiTextLineInfo();
+ ~MultiTextLineInfo();
+
+ void AddLine( TextLineInfo* pLine );
+ void Clear();
+
+ TextLineInfo* GetLine( USHORT nLine ) const
+ { return mpLines[nLine]; }
+ USHORT 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 ( USHORT 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 ( USHORT i = 0; i < mnLines; i++ )
+ delete mpLines[i];
+ mnLines = 0;
+}
+
+// -----------------------------------------------------------------------
+
+long GetTextLines( OutputDevice* pDev, MultiTextLineInfo& rLineInfo,
+ long nWidth, const XubString& rStr,
+ USHORT nStyle = TEXT_DRAW_WORDBREAK )
+{
+ rLineInfo.Clear();
+ if ( !rStr.Len() )
+ return 0;
+ if ( nWidth <= 0 )
+ nWidth = 1;
+
+ USHORT nStartPos = 0; // Start-Position der Zeile
+ USHORT nLastLineLen = 0; // Zeilenlaenge bis zum vorherigen Wort
+ USHORT nLastWordPos = 0; // Position des letzten Wortanfangs
+ USHORT i = 0;
+ USHORT nPos; // StartPositon der Zeile (nur Temp)
+ USHORT nLen; // Laenge der Zeile (nur Temp)
+ USHORT 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();
+ BOOL bHardBreak = FALSE;
+
+ do
+ {
+ c = pStr[i];
+
+ // Auf Zeilenende ermitteln
+ if ( (c == _CR) || (c == _LF) )
+ bHardBreak = TRUE;
+ else
+ bHardBreak = 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 -= 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;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT GetTextLines( OutputDevice* pDev, const Rectangle& rRect,
+ const XubString& rStr,
+ USHORT 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,
+ USHORT nStyle = TEXT_DRAW_WORDBREAK )
+{
+ Rectangle aRect = rRect;
+ USHORT nLines;
+ long nWidth = rRect.GetWidth();
+ long nMaxWidth;
+ long nTextHeight;
+
+ if ( nStyle & TEXT_DRAW_MULTILINE )
+ {
+ MultiTextLineInfo aMultiLineInfo;
+ TextLineInfo* pLineInfo;
+ USHORT nFormatLines;
+
+ nMaxWidth = 0;
+ GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle );
+ nFormatLines = aMultiLineInfo.Count();
+ nTextHeight = pDev->GetTextHeight();
+ nLines = (USHORT)(aRect.GetHeight()/nTextHeight);
+ if ( nFormatLines <= nLines )
+ nLines = nFormatLines;
+ else
+ {
+ if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
+ nLines = nFormatLines;
+ else
+ nMaxWidth = nWidth;
+ }
+ for ( USHORT 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, USHORT 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;
+ USHORT i;
+ USHORT nLines = (USHORT)(nHeight/nTextHeight);
+ USHORT nFormatLines;
+ BOOL bIsClipRegion;
+ 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 )
+ {
+ 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;
+ 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(); }
+
+ USHORT GetSortListPos( SvPtrarr* pList, long nValue, int bVertical);
+ SvLBoxEntry* SearchCol(USHORT nCol,USHORT nTop,USHORT nBottom,USHORT nPref,
+ BOOL bDown, BOOL bSimple );
+ SvLBoxEntry* SearchRow(USHORT nRow,USHORT nRight,USHORT nLeft,USHORT nPref,
+ BOOL bRight, BOOL bSimple );
+
+ void ExpandGrid();
+ void CreateGridMap();
+ // Rueckgabe FALSE: Eintrag liegt nicht in der GridMap. rGridx,y werden
+ // dann an nGridCols, nGridRows geclippt
+ BOOL GetGrid( const Point& rDocPos, USHORT& rGridX, USHORT& rGridY ) const;
+ void SetGridUsed( USHORT nDX, USHORT nDY, BOOL bUsed )
+ {
+ pGridMap[ (nDY * nGridCols) + nDX ] = bUsed;
+ }
+ BOOL IsGridUsed( USHORT nDX, USHORT nDY )
+ {
+ return pGridMap[ (nDY * nGridCols) + nDX ];
+ }
+public:
+ ImpIcnCursor( SvImpIconView* pOwner );
+ ~ImpIcnCursor();
+ void Clear( BOOL bGridToo = TRUE );
+
+ // fuer Cursortravelling usw.
+ SvLBoxEntry* GoLeftRight( SvLBoxEntry*, BOOL bRight );
+ SvLBoxEntry* GoUpDown( SvLBoxEntry*, BOOL bDown );
+
+ // Rueckgaebe: 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
+ 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&, BOOL bUsed = TRUE );
+};
+
+
+
+
+SvImpIconView::SvImpIconView( SvIconView* pCurView, SvLBoxTreeList* pTree,
+ WinBits nWinStyle ) :
+ aVerSBar( pCurView, WB_DRAG | WB_VSCROLL ),
+ aHorSBar( pCurView, WB_DRAG | WB_HSCROLL )
+{
+ pView = pCurView;
+ pModel = pTree;
+ pCurParent = 0;
+ pZOrderList = new SvPtrarr;
+ SetWindowBits( 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( TRUE );
+}
+
+SvImpIconView::~SvImpIconView()
+{
+ StopEditTimer();
+ CancelUserEvent();
+ delete pZOrderList;
+ delete pImpCursor;
+ delete pDDDev;
+ delete pDDBufDev;
+ delete pDDTempDev;
+ ClearSelectedRectList();
+}
+
+void SvImpIconView::Clear( BOOL bInCtor )
+{
+ StopEditTimer();
+ CancelUserEvent();
+ nMaxBmpWidth = 0;
+ nMaxBmpHeight = 0;
+ nMaxTextWidth = 0;
+ bMustRecalcBoundingRects = 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::SetWindowBits( WinBits nWinStyle )
+{
+ nWinBits = nWinStyle;
+ nViewMode = VIEWMODE_TEXT;
+ if( nWinStyle & WB_NAME )
+ nViewMode = VIEWMODE_NAME;
+ if( nWinStyle & WB_ICON )
+ nViewMode = VIEWMODE_ICON;
+}
+
+
+IMPL_LINK( SvImpIconView, ScrollUpDownHdl, ScrollBar *, pScrollBar )
+{
+ pView->EndEditing( TRUE );
+ // Pfeil hoch: delta=-1; Pfeil runter: delta=+1
+ Scroll( 0, pScrollBar->GetDelta(), TRUE );
+ return 0;
+}
+
+IMPL_LINK( SvImpIconView, ScrollLeftRightHdl, ScrollBar *, pScrollBar )
+{
+ pView->EndEditing( TRUE );
+ // Pfeil links: delta=-1; Pfeil rechts: delta=+1
+ Scroll( pScrollBar->GetDelta(), 0, 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 = 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 = TRUE;
+ }
+ if( aSize.Height() > nMaxBmpHeight )
+ {
+ nMaxBmpHeight = aSize.Height();
+ nMaxBmpHeight += (2*TBOFFS_ICON);;
+ if( !(nFlags & F_GRIDMODE ) )
+ bMustRecalcBoundingRects = 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( FALSE );
+ else
+ pImpCursor->Clear( 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( FALSE );
+ pCursor = 0; // damit er nicht deselektiert wird
+ SetCursor( pNewCursor );
+ }
+ USHORT 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( 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();
+ USHORT nPos = pZOrderList->GetPos( (void*)pEntry );
+ pZOrderList->Remove( nPos, 1 );
+ pView->Select( pEntry, 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, 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( FALSE );
+ if( nFlags & F_RUBBERING )
+ PaintEntry( pEntry );
+ else
+ pView->Invalidate( GetBoundingRect( pEntry ) );
+ if( pEntry == pCursor )
+ ShowCursor( 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;
+ BOOL bLockedEntryFound = 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 = 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( FALSE );
+ ResetVirtSize();
+ bMustRecalcBoundingRects = FALSE;
+ MapMode aMapMode( pView->GetMapMode());
+ aMapMode.SetOrigin( Point() );
+ pView->SetMapMode( aMapMode );
+ CheckAllSizes();
+ RecalcAllBoundingRectsSmart();
+ pView->Invalidate();
+ ShowCursor( 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 );
+
+ USHORT nCount = pZOrderList->Count();
+ if( !nCount )
+ return;
+
+ SvPtrarr* pNewZOrderList = new SvPtrarr;
+ SvPtrarr* pPaintedEntries = new SvPtrarr;
+
+ USHORT 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( USHORT nCur = 0; nCur < nCount; nCur++ )
+ pZOrderList->Insert( pPaintedEntries->GetObject( nCur ),pZOrderList->Count());
+ }
+ delete pPaintedEntries;
+
+ Rectangle aRect;
+ if( GetResizeRect( aRect ))
+ PaintResizeRect( aRect );
+}
+
+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 TRUE;
+ }
+ return 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( FALSE );
+ ClearSelectedRectList();
+ }
+ else
+ nFlags |= F_ADD_MODE;
+ nFlags |= F_RUBBERING;
+ aCurSelectionRect.SetPos( aDocPos );
+ pView->CaptureMouse();
+ }
+ return;
+ }
+
+ BOOL bSelected = pView->IsSelected( pEntry );
+ 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, 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, 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(), 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, 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,FALSE );
+ BOOL bSelRectHidden = FALSE;
+ if( nScrollDX || nScrollDY )
+ {
+ HideSelectionRect();
+ bSelRectHidden = TRUE;
+ pView->Scroll( nScrollDX, nScrollDY );
+ }
+ Point aDocPos( rMEvt.GetPosPixel() );
+ aDocPos = pView->PixelToLogic( aDocPos );
+ Rectangle aRect( aCurSelectionRect.TopLeft(), aDocPos );
+ if( aRect != aCurSelectionRect )
+ {
+ HideSelectionRect();
+ bSelRectHidden = TRUE;
+ BOOL bAdd = (nFlags & F_ADD_MODE) ? TRUE : FALSE;
+ SelectRect( aRect, bAdd, &aSelectedRectList );
+ }
+ if( bSelRectHidden )
+ DrawSelectionRect( aRect );
+ }
+}
+
+BOOL SvImpIconView::KeyInput( const KeyEvent& rKEvt )
+{
+ StopEditTimer();
+ BOOL bKeyUsed = TRUE;
+ BOOL bMod1 = rKEvt.GetKeyCode().IsMod1();
+ BOOL bInAddMode = (BOOL)((nFlags & F_ADD_MODE) != 0);
+ int bDeselAll = (pView->GetSelectionMode() != SINGLE_SELECTION) &&
+ !bInAddMode;
+ SvLBoxEntry* pNewCursor;
+ USHORT nCode = rKEvt.GetKeyCode().GetCode();
+ switch( nCode )
+ {
+ case KEY_UP:
+ if( pCursor )
+ {
+ MakeVisible( pCursor );
+ pNewCursor = pImpCursor->GoUpDown(pCursor,FALSE);
+ if( pNewCursor )
+ {
+ if( bDeselAll )
+ pView->SelectAll( FALSE );
+ ShowCursor( FALSE );
+ MakeVisible( pNewCursor );
+ SetCursor( pNewCursor );
+ if( !bInAddMode )
+ pView->Select( pCursor, 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,TRUE );
+ if( pNewCursor )
+ {
+ MakeVisible( pCursor );
+ if( bDeselAll )
+ pView->SelectAll( FALSE );
+ ShowCursor( FALSE );
+ MakeVisible( pNewCursor );
+ SetCursor( pNewCursor );
+ if( !bInAddMode )
+ pView->Select( pCursor, TRUE );
+ }
+ }
+ break;
+
+ case KEY_RIGHT:
+ if( pCursor )
+ {
+ pNewCursor=pImpCursor->GoLeftRight(pCursor,TRUE );
+ if( pNewCursor )
+ {
+ MakeVisible( pCursor );
+ if( bDeselAll )
+ pView->SelectAll( FALSE );
+ ShowCursor( FALSE );
+ MakeVisible( pNewCursor );
+ SetCursor( pNewCursor );
+ if( !bInAddMode )
+ pView->Select( pCursor, TRUE );
+ }
+ }
+ break;
+
+ case KEY_LEFT:
+ if( pCursor )
+ {
+ MakeVisible( pCursor );
+ pNewCursor = pImpCursor->GoLeftRight(pCursor,FALSE );
+ if( pNewCursor )
+ {
+ if( bDeselAll )
+ pView->SelectAll( FALSE );
+ ShowCursor( FALSE );
+ MakeVisible( pNewCursor );
+ SetCursor( pNewCursor );
+ if( !bInAddMode )
+ pView->Select( pCursor, 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( 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( TRUE );
+ break;
+
+ case KEY_SUBTRACT:
+ case KEY_COMMA :
+ if( bMod1 )
+ pView->SelectAll( FALSE );
+ break;
+
+ case KEY_RETURN:
+ if( bMod1 )
+ {
+ if( pCursor && pView->IsInplaceEditingEnabled() )
+ pView->EditEntry( pCursor );
+ }
+ break;
+
+ default:
+ bKeyUsed = FALSE;
+
+ }
+ return bKeyUsed;
+}
+
+
+void SvImpIconView::PositionScrollBars( long nRealWidth, long nRealHeight )
+{
+ // hor scrollbar
+ Point aPos( 0, nRealHeight );
+ aPos.Y() -= nHorSBarHeight;
+
+#ifdef WIN
+ // vom linken und unteren Rand ein Pixel abschneiden
+ aPos.Y()++;
+ aPos.X()--;
+#endif
+#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(WIN) || defined(WNT)
+ aPos.X()++;
+ aPos.Y()--;
+#endif
+
+#ifdef OS2
+ aPos.Y()--;
+ aPos.X()++;
+#endif
+
+#ifdef MAC
+ aPos.Y()--;
+ aPos.X()++;
+#endif
+ if( aVerSBar.GetPosPixel() != aPos )
+ aVerSBar.SetPosPixel( aPos );
+}
+
+
+
+void SvImpIconView::AdjustScrollBars( BOOL bVirtSizeGrowedOnly )
+{
+ 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;
+
+ int bVerSBar = pView->nWindowStyle & WB_VSCROLL;
+ int bHorSBar = pView->nWindowStyle & WB_HSCROLL;
+
+ USHORT 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(WIN) || defined(WNT)
+ aSize.Height() += 2;
+#endif
+#ifdef OS2
+ aSize.Height() += 3;
+#endif
+#ifdef MAC
+ aSize.Height() += 2;
+#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(WIN) || defined(WNT)
+ aSize.Width()++;
+#endif
+#ifdef OS2
+ aSize.Width() += 3;
+ if( nResult & 0x0001 ) // vertikale Scrollbar ?
+ aSize.Width()--;
+#endif
+#if defined(WIN) || 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(WIN) || 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
+}
+
+BOOL SvImpIconView::CheckHorScrollBar()
+{
+ if( !pZOrderList || !aHorSBar.IsVisible() )
+ return FALSE;
+ const MapMode& rMapMode = pView->GetMapMode();
+ Point aOrigin( rMapMode.GetOrigin() );
+ if(!(pView->nWindowStyle & WB_HSCROLL) && !aOrigin.X() )
+ {
+ long nWidth = aOutputSize.Width();
+ USHORT nCount = pZOrderList->Count();
+ long nMostRight = 0;
+ for( USHORT nCur = 0; nCur < nCount; nCur++ )
+ {
+ SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur);
+ long nRight = GetBoundingRect(pEntry).Right();
+ if( nRight > nWidth )
+ return FALSE;
+ if( nRight > nMostRight )
+ nMostRight = nRight;
+ }
+ aHorSBar.Hide();
+ aOutputSize.Height() += nHorSBarHeight;
+ aVirtOutputSize.Width() = nMostRight;
+ aHorSBar.SetThumbPos( 0 );
+ Range aRange;
+ aRange.Max() = nMostRight - 1;
+ aHorSBar.SetRange( aRange );
+ if( aVerSBar.IsVisible() )
+ {
+ Size aSize( aVerSBar.GetSizePixel());
+ aSize.Height() += nHorSBarHeight;
+ aVerSBar.SetSizePixel( aSize );
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL SvImpIconView::CheckVerScrollBar()
+{
+ if( !pZOrderList || !aVerSBar.IsVisible() )
+ return FALSE;
+ const MapMode& rMapMode = pView->GetMapMode();
+ Point aOrigin( rMapMode.GetOrigin() );
+ if(!(pView->nWindowStyle & WB_VSCROLL) && !aOrigin.Y() )
+ {
+ long nDeepest = 0;
+ long nHeight = aOutputSize.Height();
+ USHORT nCount = pZOrderList->Count();
+ for( USHORT nCur = 0; nCur < nCount; nCur++ )
+ {
+ SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur);
+ long nBottom = GetBoundingRect(pEntry).Bottom();
+ if( nBottom > nHeight )
+ return FALSE;
+ if( nBottom > nDeepest )
+ nDeepest = nBottom;
+ }
+ aVerSBar.Hide();
+ aOutputSize.Width() += nVerSBarWidth;
+ aVirtOutputSize.Height() = nDeepest;
+ aVerSBar.SetThumbPos( 0 );
+ Range aRange;
+ aRange.Max() = nDeepest - 1;
+ aVerSBar.SetRange( aRange );
+ if( aHorSBar.IsVisible() )
+ {
+ Size aSize( aHorSBar.GetSizePixel());
+ aSize.Width() += nVerSBarWidth;
+ aHorSBar.SetSizePixel( aSize );
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+// blendet Scrollbars aus, wenn sie nicht mehr benoetigt werden
+void SvImpIconView::CheckScrollBars()
+{
+ CheckVerScrollBar();
+ if( CheckHorScrollBar() )
+ CheckVerScrollBar();
+}
+
+
+void __EXPORT SvImpIconView::GetFocus()
+{
+ if( pCursor )
+ {
+ pView->SetEntryFocus( pCursor, TRUE );
+ ShowCursor( TRUE );
+ }
+}
+
+void __EXPORT SvImpIconView::LoseFocus()
+{
+ StopEditTimer();
+ if( pCursor )
+ pView->SetEntryFocus( pCursor,FALSE );
+ ShowCursor( FALSE );
+}
+
+void SvImpIconView::UpdateAll()
+{
+ AdjustScrollBars();
+ pImpCursor->Clear();
+ pView->Invalidate();
+}
+
+void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData )
+{
+ Point aPos( GetEntryPos( pEntry ) );
+ PaintEntry( pEntry, aPos, pViewData );
+}
+
+void SvImpIconView::PaintEmphasis( const Rectangle& rRect, BOOL bSelected,
+ BOOL bInUse, 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, USHORT 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));
+
+ BOOL bSelected = pViewData->IsSelected();
+ BOOL bCursored = pViewData->IsCursored();
+ BOOL bInUse = pEntry->HasInUseEmphasis();
+
+ 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,FALSE,pViewData));
+ Rectangle aBmpRect( CalcBmpRect(pEntry, &rPos, pViewData ) );
+
+ switch( nViewMode )
+ {
+ case VIEWMODE_ICON:
+ pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
+ PaintEmphasis( aBmpRect, bSelected, bInUse, bCursored, pOut );
+ PaintItem( aBmpRect, pBmpItem, pEntry,
+ PAINTFLAG_HOR_CENTERED | PAINTFLAG_VER_CENTERED, pOut );
+ PaintEmphasis( aTextRect, bSelected, FALSE, 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, bInUse, bCursored, pOut );
+ PaintItem( aBmpRect, pBmpItem, pEntry, PAINTFLAG_VER_CENTERED, pOut );
+ PaintEmphasis( aTextRect, bSelected, FALSE, FALSE, pOut );
+ PaintItem( aTextRect, pStringItem, pEntry,PAINTFLAG_VER_CENTERED, pOut );
+ break;
+
+ case VIEWMODE_TEXT:
+ PaintEmphasis( aTextRect, bSelected, FALSE, bCursored, pOut );
+ PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_VER_CENTERED, pOut );
+ break;
+ }
+ pOut->SetFont( aTempFont );
+}
+
+void SvImpIconView::SetEntryPos( SvLBoxEntry* pEntry, const Point& rPos,
+ BOOL bAdjustAtGrid, BOOL bCheckScrollBars )
+{
+ if( pModel->GetParent(pEntry) == pCurParent )
+ {
+ ShowCursor( FALSE );
+ long nVirtHeightOffs = 0;
+ long nVirtWidthOffs = 0;
+ 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( TRUE );
+ }
+}
+
+void SvImpIconView::ViewDataInitialized( SvLBoxEntry*)
+{
+}
+
+void SvImpIconView::ModelHasEntryInvalidated( SvListEntry* pEntry )
+{
+ if( pEntry == pCursor )
+ ShowCursor( 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( 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 )
+{
+}
+
+BOOL SvImpIconView::IsEntryInView( SvLBoxEntry* )
+{
+ return 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
+ USHORT 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;
+ USHORT nStartPos = pZOrderList->GetPos( (void*)pCurEntry );
+ if( nStartPos != USHRT_MAX )
+ {
+ USHORT nCount = pZOrderList->Count();
+ for( USHORT 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;
+ USHORT 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::GetEntryPos( 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, 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);
+#ifndef VCL
+ aMaxGridTextRect.Bottom() = LONG_MAX - 1;
+ aMaxGridTextRect = GetTextRect( pView, aMaxGridTextRect,pItem->GetText(), DRAWTEXT_FLAGS );
+#endif
+ 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 = 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( FALSE );
+ if( pCursor )
+ {
+ pView->SetEntryFocus( pCursor, FALSE );
+ if( pView->GetSelectionMode() == SINGLE_SELECTION )
+ pView->Select( pCursor, FALSE );
+ }
+ pCursor = pEntry;
+ ToTop( pCursor );
+ if( pCursor )
+ {
+ pView->SetEntryFocus(pCursor, TRUE );
+ if( pView->GetSelectionMode() == SINGLE_SELECTION )
+ pView->Select( pCursor, TRUE );
+ ShowCursor( TRUE );
+ }
+}
+
+
+void SvImpIconView::ShowCursor( 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);
+ }
+ BOOL bSelected = pView->SvListView::Select( pRefEntry, 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, 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 );
+
+ BOOL bSelected = pView->SvListView::Select( pRefEntry, FALSE );
+ if( bSelected )
+ pView->SvListView::Select( pRefEntry, TRUE );
+}
+
+void SvImpIconView::ShowTargetEmphasis( SvLBoxEntry* pEntry, BOOL bShow )
+{
+ 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 );
+}
+
+BOOL SvImpIconView::NotifyMoving( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry,
+ SvLBoxEntry*& rpNewPar, 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 ) );
+ SetEntryPos( pEntry, aNewPos, FALSE, TRUE );
+ return FALSE;
+ }
+ return pView->SvLBox::NotifyMoving(pTarget,pEntry,rpNewPar,rNewChildPos);
+}
+
+BOOL SvImpIconView::NotifyCopying( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry,
+ SvLBoxEntry*& rpNewParent, 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 -= GetEntryPos( 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 CommandEvent& rCEvt )
+{
+ aMouseMoveTimer.Stop();
+ StopEditTimer();
+ nFlags |= F_CMD_ARRIVED;
+ SvLBoxEntry* pEntry = pView->GetEntry( rCEvt.GetMousePosPixel(), TRUE );
+ if( (nFlags & F_DOWN_CTRL) && pEntry && !pView->IsSelected(pEntry) )
+ pView->Select( pEntry, TRUE );
+ nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
+}
+
+void SvImpIconView::Command( const CommandEvent& rCEvt )
+{
+ PrepareCommandEvent( rCEvt );
+ if( rCEvt.GetCommand() == COMMAND_STARTDRAG )
+ {
+ nFlags |= F_DRAG_SOURCE;
+ if( GetSelectionCount() )
+ {
+ ShowCursor( FALSE );
+ pView->BeginDrag( rCEvt.GetMousePosPixel() );
+ ShowCursor( 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 )
+ {
+ USHORT 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 == TRUE: Das Rect wurde aufgrund eines ScrollBar-Events berechnet
+
+void SvImpIconView::MakeVisible( const Rectangle& rRect, 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, 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, FALSE );
+ if( !pNewCursor )
+ {
+ pNewCursor = pImpCursor->GoLeftRight( pCursor, TRUE );
+ if( !pNewCursor )
+ {
+ pNewCursor = pImpCursor->GoUpDown( pCursor, FALSE );
+ if( !pNewCursor )
+ pNewCursor = pImpCursor->GoUpDown( pCursor, TRUE );
+ }
+ }
+ }
+ else
+ pNewCursor = pModel->FirstChild( pCurParent );
+ DBG_ASSERT(!pNewCursor|| (pCursor&&pCursor!=pNewCursor),"GetNewCursor failed");
+ return pNewCursor;
+}
+
+
+USHORT SvImpIconView:: GetSelectionCount() const
+{
+ USHORT 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 )
+{
+ BOOL bSel;
+ if( pView->IsSelected( pEntry ) )
+ bSel = FALSE;
+ else
+ bSel = 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, 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;
+}
+
+USHORT ImpIcnCursor::GetSortListPos( SvPtrarr* pList, long nValue,
+ int bVertical )
+{
+ USHORT nCount = (USHORT)pList->Count();
+ if( !nCount )
+ return 0;
+
+ USHORT 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 (USHORT)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 = nRows - 1;
+ if( nX >= nCols )
+ nX = nCols - 1;
+
+ USHORT nIns = GetSortListPos( &pColumns[nX], rRect.Top(), TRUE );
+ pColumns[ nX ].Insert( pEntry, nIns );
+
+ nIns = GetSortListPos( &pRows[nY], rRect.Left(), 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 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 );
+ }
+}
+
+BOOL ImpIcnCursor::GetGrid( const Point& rDocPos, USHORT& rGridX, USHORT& rGridY ) const
+{
+ Point aPos( rDocPos );
+ aPos.X() -= LROFFS_WINBORDER;
+ aPos.Y() -= TBOFFS_WINBORDER;
+ rGridX = (USHORT)(aPos.X() / nGridDX);
+ rGridY = (USHORT)(aPos.Y() / nGridDY);
+ BOOL bInGrid = TRUE;
+ if( rGridX >= nGridCols )
+ {
+ rGridX = nGridCols - 1;
+ bInGrid = FALSE;
+ }
+ if( rGridY >= nGridRows )
+ {
+ rGridY = nGridRows - 1;
+ if( !bInGrid )
+ return FALSE; // beide Koordinaten nicht im Grid
+ }
+ return TRUE;
+}
+
+void ImpIcnCursor::SetGridUsed( const Rectangle& rRect, BOOL bUsed )
+{
+ CreateGridMap();
+ USHORT nTLX, nTLY, nBRX, nBRY;
+
+ BOOL bTLInGrid = GetGrid( rRect.TopLeft(), nTLX, nTLY );
+ BOOL bBRInGrid = GetGrid( rRect.BottomRight(), nBRX, nBRY );
+
+ if( !bTLInGrid && !bBRInGrid )
+ return;
+
+ for( USHORT nCurY = nTLY; nCurY <= nBRY; nCurY++ )
+ {
+ for( USHORT nCurX = nTLX; nCurX <= nBRX; nCurX++ )
+ {
+ SetGridUsed( nCurX, nCurY, bUsed );
+ }
+ }
+}
+
+void ImpIcnCursor::Clear( 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(USHORT nCol,USHORT nTop,USHORT nBottom,
+ USHORT nPref, BOOL bDown, BOOL bSimple )
+{
+ DBG_ASSERT(pCurEntry,"SearchCol: No reference entry");
+ SvPtrarr* pList = &(pColumns[ nCol ]);
+ USHORT nCount = pList->Count();
+ if( !nCount )
+ return 0;
+
+ const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry);
+
+ if( bSimple )
+ {
+ USHORT 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 )
+ {
+ USHORT nTemp = nTop;
+ nTop = nBottom;
+ nBottom = nTemp;
+ }
+ long nMinDistance = LONG_MAX;
+ SvLBoxEntry* pResult = 0;
+ for( USHORT nCur = 0; nCur < nCount; nCur++ )
+ {
+ SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur ));
+ if( pEntry != pCurEntry )
+ {
+ SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry);
+ USHORT 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(USHORT nRow,USHORT nLeft,USHORT nRight,
+ USHORT nPref, BOOL bRight, BOOL bSimple )
+{
+ DBG_ASSERT(pCurEntry,"SearchRow: No reference entry");
+ SvPtrarr* pList = &(pRows[ nRow ]);
+ USHORT nCount = pList->Count();
+ if( !nCount )
+ return 0;
+
+ const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry);
+
+ if( bSimple )
+ {
+ USHORT 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 )
+ {
+ USHORT nTemp = nRight;
+ nRight = nLeft;
+ nLeft = nTemp;
+ }
+ long nMinDistance = LONG_MAX;
+ SvLBoxEntry* pResult = 0;
+ for( USHORT nCur = 0; nCur < nCount; nCur++ )
+ {
+ SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur ));
+ if( pEntry != pCurEntry )
+ {
+ SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry);
+ USHORT 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 = 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* pEntry, BOOL bRight )
+{
+ SvLBoxEntry* pResult;
+ pCurEntry = pEntry;
+ Create();
+ SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry);
+ USHORT nY = pViewData->nY;
+ USHORT 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 ,nCols-1, nX, TRUE, TRUE );
+ else
+ pResult = SearchRow( nY, nX ,0, nX, FALSE, TRUE );
+ if( pResult )
+ return pResult;
+
+ long nCurCol = nX;
+
+ long nColOffs, nLastCol;
+ if( bRight )
+ {
+ nColOffs = 1;
+ nLastCol = nCols;
+ }
+ else
+ {
+ nColOffs = -1;
+ nLastCol = -1; // 0-1
+ }
+
+ USHORT nRowMin = nY;
+ USHORT nRowMax = nY;
+ do
+ {
+ SvLBoxEntry* pEntry = SearchCol((USHORT)nCurCol,nRowMin,nRowMax,nY,TRUE, FALSE);
+ if( pEntry )
+ return pEntry;
+ if( nRowMin )
+ nRowMin--;
+ if( nRowMax < (nRows-1))
+ nRowMax++;
+ nCurCol += nColOffs;
+ } while( nCurCol != nLastCol );
+ return 0;
+}
+
+SvLBoxEntry* ImpIcnCursor::GoUpDown( SvLBoxEntry* pEntry, BOOL bDown)
+{
+ SvLBoxEntry* pResult;
+ pCurEntry = pEntry;
+ Create();
+ SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry);
+ USHORT nY = pViewData->nY;
+ USHORT 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 ,nRows-1, nY, TRUE, TRUE );
+ else
+ pResult = SearchCol( nX, nY ,0, nY, FALSE, TRUE );
+ if( pResult )
+ return pResult;
+
+ long nCurRow = nY;
+
+ long nRowOffs, nLastRow;
+ if( bDown )
+ {
+ nRowOffs = 1;
+ nLastRow = nRows;
+ }
+ else
+ {
+ nRowOffs = -1;
+ nLastRow = -1; // 0-1
+ }
+
+ USHORT nColMin = nX;
+ USHORT nColMax = nX;
+ do
+ {
+ SvLBoxEntry* pEntry = SearchRow((USHORT)nCurRow,nColMin,nColMax,nX,TRUE, 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 ];
+ memset( pTempMap, nNewGridRows * nGridCols, 0 );
+ memcpy( pTempMap, pGridMap, nGridRows * nGridCols );
+ delete pGridMap;
+ pGridMap = pTempMap;
+ nGridRows = nNewGridRows;
+ }
+}
+
+BOOL ImpIcnCursor::FindEmptyGridRect( Rectangle& rRect )
+{
+ CreateGridMap();
+ USHORT nCount = (USHORT)(nGridCols * nGridRows);
+ if( !nCount )
+ return FALSE;
+ for( USHORT nCur = 0; nCur < nCount; nCur++ )
+ {
+ if( !pGridMap[ nCur ] )
+ {
+ USHORT nCol = (USHORT)(nCur % nGridCols);
+ USHORT nRow = (USHORT)(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, TRUE );
+
+ //XXX
+ //if( nRow + 5 > nGridRows )
+ // ExpandGrid();
+ DBG_ASSERT(pGridMap[nCur],"SetGridUsed failed");
+ return 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 FALSE;
+ //XXX
+ //ExpandGrid();
+ //return TRUE;
+}
+
+void ImpIcnCursor::CreateGridAjustData( SvPtrarr& rLists, SvLBoxEntry* pRefEntry)
+{
+ if( !pRefEntry )
+ {
+ USHORT nRows = (USHORT)(pView->aVirtOutputSize.Height() / pView->nGridDY);
+ nRows++; // wg. Abrundung!
+
+ if( !nRows )
+ return;
+ for( USHORT nCurList = 0; nCurList < nRows; 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 );
+ USHORT nIns = GetSortListPos((SvPtrarr*)rLists[nY],rRect.Left(),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 )
+ {
+ USHORT nIns = GetSortListPos( pRow, rRect.Left(), FALSE );
+ pRow->Insert( pEntry, nIns );
+ }
+ pEntry = pView->pModel->NextSibling( pEntry );
+ }
+ }
+}
+
+//static
+void ImpIcnCursor::DestroyGridAdjustData( SvPtrarr& rLists )
+{
+ USHORT nCount = rLists.Count();
+ for( USHORT 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, 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* pView,
+ 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( pView, 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, BOOL bAdd,
+ SvPtrarr* pOtherRects, short nBorderOffs )
+{
+ if( !pZOrderList || !pZOrderList->Count() )
+ return;
+
+ CheckBoundingRects();
+ pView->Update();
+ USHORT nCount = pZOrderList->Count();
+
+ Rectangle aRect( rRect );
+ aRect.Justify();
+ if( nBorderOffs )
+ {
+ aRect.Left() -= nBorderOffs;
+ aRect.Right() += nBorderOffs;
+ aRect.Top() -= nBorderOffs;
+ aRect.Bottom() += nBorderOffs;
+ }
+ BOOL bCalcOverlap = (bAdd && pOtherRects && pOtherRects->Count()) ? TRUE : FALSE;
+
+ for( USHORT 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;
+ BOOL bSelected = pViewData->IsSelected();
+
+ BOOL bOverlaps;
+ if( bCalcOverlap )
+ bOverlaps = IsOver( pOtherRects, rBoundRect );
+ else
+ bOverlaps = FALSE;
+ BOOL bOver = aRect.IsOver( rBoundRect );
+
+ if( bOver && !bOverlaps )
+ {
+ // Ist im neuen Selektionsrechteck und in keinem alten
+ // => selektieren
+ if( !bSelected )
+ pView->Select( pEntry, TRUE );
+ }
+ else if( !bAdd )
+ {
+ // ist ausserhalb des Selektionsrechtecks
+ // => Selektion entfernen
+ if( bSelected )
+ pView->Select( pEntry, 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, FALSE );
+ }
+ else
+ {
+ // Eintrag eines alten Rects selektieren
+ if( !bSelected )
+ pView->Select( pEntry, TRUE );
+ }
+ }
+ else if( !bOver && bSelected )
+ {
+ // Der Eintrag liegt voellig ausserhalb und wird deshalb desel.
+ pView->Select( pEntry, FALSE );
+ }
+ }
+ pView->Update();
+}
+
+BOOL SvImpIconView::IsOver( SvPtrarr* pRectList, const Rectangle& rBoundRect ) const
+{
+ USHORT nCount = pRectList->Count();
+ for( USHORT nCur = 0; nCur < nCount; nCur++ )
+ {
+ Rectangle* pRect = (Rectangle*)pRectList->GetObject( nCur );
+ if( rBoundRect.IsOver( *pRect ))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void 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()
+{
+ USHORT nCount = aSelectedRectList.Count();
+ for( USHORT nCur = 0; nCur < nCount; nCur++ )
+ {
+ Rectangle* pRect = (Rectangle*)aSelectedRectList.GetObject( nCur );
+ delete pRect;
+ }
+ aSelectedRectList.Remove( 0, aSelectedRectList.Count() );
+}
+
+
+void 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, BOOL bInDragDrop, USHORT nBorderWidth)
+{
+ // Scrolling der View, falls sich der Mauszeiger im Grenzbereich des
+ // Fensters befindet
+ long nPixelToScrollX = 0;
+ long nPixelToScrollY = 0;
+ Size aWndSize = aOutputSize;
+
+ nBorderWidth = (USHORT)(Min( (long)(aWndSize.Height()-1), (long)nBorderWidth ));
+ nBorderWidth = (USHORT)(Min( (long)(aWndSize.Width()-1), (long)nBorderWidth ));
+
+ if ( rPosPixel.X() < nBorderWidth )
+ {
+ if( 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);
+ }
+}
+
+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 TRUE;
+ }
+ return FALSE;
+}
+
+IMPL_LINK(SvImpIconView, EditTimeoutHdl, Timer*, pTimer )
+{
+ 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 );
+ USHORT nCount = aLists.Count();
+ for( USHORT 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;
+
+ BOOL bGo;
+ if( !pStart )
+ bGo = TRUE;
+ else
+ bGo = FALSE;
+
+ long nCurRight = 0;
+ for( USHORT nCur = 0; nCur < rRow.Count(); nCur++ )
+ {
+ SvLBoxEntry* pCur = (SvLBoxEntry*)rRow[ nCur ];
+ if( !bGo && pCur == pStart )
+ bGo = 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() )
+ SetEntryPos( 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;
+ }
+}
+
+