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