xref: /trunk/main/svtools/source/contnr/imivctl2.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svtools.hxx"
30 #include "imivctl.hxx"
31 
32 IcnCursor_Impl::IcnCursor_Impl( SvxIconChoiceCtrl_Impl* pOwner )
33 {
34     pView       = pOwner;
35     pColumns    = 0;
36     pRows       = 0;
37     pCurEntry   = 0;
38     nDeltaWidth = 0;
39     nDeltaHeight= 0;
40     nCols       = 0;
41     nRows       = 0;
42 }
43 
44 IcnCursor_Impl::~IcnCursor_Impl()
45 {
46     delete[] pColumns;
47     delete[] pRows;
48 }
49 
50 sal_uInt16 IcnCursor_Impl::GetSortListPos( SvPtrarr* pList, long nValue,
51     int bVertical )
52 {
53     sal_uInt16 nCount = (sal_uInt16)pList->Count();
54     if( !nCount )
55         return 0;
56 
57     sal_uInt16 nCurPos = 0;
58     long nPrevValue = LONG_MIN;
59     while( nCount )
60     {
61         const Rectangle& rRect=
62             pView->GetEntryBoundRect((SvxIconChoiceCtrlEntry*)(pList->GetObject(nCurPos)));
63         long nCurValue;
64         if( bVertical )
65             nCurValue = rRect.Top();
66         else
67             nCurValue = rRect.Left();
68         if( nValue >= nPrevValue && nValue <= nCurValue )
69             return (sal_uInt16)nCurPos;
70         nPrevValue = nCurValue;
71         nCount--;
72         nCurPos++;
73     }
74     return pList->Count();
75 }
76 
77 void IcnCursor_Impl::ImplCreate()
78 {
79     pView->CheckBoundingRects();
80     DBG_ASSERT(pColumns==0&&pRows==0,"ImplCreate: Not cleared");
81 
82     SetDeltas();
83 
84     pColumns = new SvPtrarr[ nCols ];
85     pRows = new SvPtrarr[ nRows ];
86 
87     sal_uLong nCount = pView->aEntries.Count();
88     for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
89     {
90         SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nCur );
91         // const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
92         Rectangle rRect( pView->CalcBmpRect( pEntry,0 ) );
93         short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / nDeltaHeight );
94         short nX = (short)( ((rRect.Left()+rRect.Right())/2) / nDeltaWidth );
95 
96         // Rundungsfehler abfangen
97         if( nY >= nRows )
98             nY = sal::static_int_cast< short >(nRows - 1);
99         if( nX >= nCols )
100             nX = sal::static_int_cast< short >(nCols - 1);
101 
102         sal_uInt16 nIns = GetSortListPos( &pColumns[nX], rRect.Top(), sal_True );
103         pColumns[ nX ].Insert( pEntry, nIns );
104 
105         nIns = GetSortListPos( &pRows[nY], rRect.Left(), sal_False );
106         pRows[ nY ].Insert( pEntry, nIns );
107 
108         pEntry->nX = nX;
109         pEntry->nY = nY;
110     }
111 }
112 
113 
114 
115 
116 void IcnCursor_Impl::Clear()
117 {
118     if( pColumns )
119     {
120         delete[] pColumns;
121         delete[] pRows;
122         pColumns = 0;
123         pRows = 0;
124         pCurEntry = 0;
125         nDeltaWidth = 0;
126         nDeltaHeight = 0;
127     }
128 }
129 
130 SvxIconChoiceCtrlEntry* IcnCursor_Impl::SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom,
131     sal_uInt16, sal_Bool bDown, sal_Bool bSimple  )
132 {
133     DBG_ASSERT(pCurEntry,"SearchCol: No reference entry");
134     SvPtrarr* pList = &(pColumns[ nCol ]);
135     const sal_uInt16 nCount = pList->Count();
136     if( !nCount )
137         return 0;
138 
139     const Rectangle& rRefRect = pView->GetEntryBoundRect(pCurEntry);
140 
141     if( bSimple )
142     {
143         sal_uInt16 nListPos = pList->GetPos( pCurEntry );
144         DBG_ASSERT(nListPos!=0xffff,"Entry not in Col-List");
145         if( bDown )
146         {
147             while( nListPos < nCount-1 )
148             {
149                 nListPos++;
150                 SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pList->GetObject( nListPos );
151                 const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
152                 if( rRect.Top() > rRefRect.Top() )
153                     return pEntry;
154             }
155             return 0;
156         }
157         else
158         {
159             while( nListPos )
160             {
161                 nListPos--;
162                 if( nListPos < nCount )
163                 {
164                     SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pList->GetObject( nListPos );
165                     const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
166                     if( rRect.Top() < rRefRect.Top() )
167                         return pEntry;
168                 }
169             }
170             return 0;
171         }
172     }
173 
174     if( nTop > nBottom )
175     {
176         sal_uInt16 nTemp = nTop;
177         nTop = nBottom;
178         nBottom = nTemp;
179     }
180     long nMinDistance = LONG_MAX;
181     SvxIconChoiceCtrlEntry* pResult = 0;
182     for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
183     {
184         SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pList->GetObject( nCur ));
185         if( pEntry != pCurEntry )
186         {
187             sal_uInt16 nY = pEntry->nY;
188             if( nY >= nTop && nY <= nBottom )
189             {
190                 const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
191                 long nDistance = rRect.Top() - rRefRect.Top();
192                 if( nDistance < 0 )
193                     nDistance *= -1;
194                 if( nDistance && nDistance < nMinDistance )
195                 {
196                     nMinDistance = nDistance;
197                     pResult = pEntry;
198                 }
199             }
200         }
201     }
202     return pResult;
203 }
204 
205 SvxIconChoiceCtrlEntry* IcnCursor_Impl::SearchRow(sal_uInt16 nRow,sal_uInt16 nLeft,sal_uInt16 nRight,
206     sal_uInt16, sal_Bool bRight, sal_Bool bSimple )
207 {
208     DBG_ASSERT(pCurEntry,"SearchRow: No reference entry");
209     SvPtrarr* pList = &(pRows[ nRow ]);
210     const sal_uInt16 nCount = pList->Count();
211     if( !nCount )
212         return 0;
213 
214     const Rectangle& rRefRect = pView->GetEntryBoundRect(pCurEntry);
215 
216     if( bSimple )
217     {
218         sal_uInt16 nListPos = pList->GetPos( pCurEntry );
219         DBG_ASSERT(nListPos!=0xffff,"Entry not in Row-List");
220         if( bRight )
221         {
222             while( nListPos < nCount-1 )
223             {
224                 nListPos++;
225                 SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pList->GetObject( nListPos );
226                 const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
227                 if( rRect.Left() > rRefRect.Left() )
228                     return pEntry;
229             }
230             return 0;
231         }
232         else
233         {
234             while( nListPos )
235             {
236                 nListPos--;
237                 if( nListPos < nCount )
238                 {
239                     SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pList->GetObject( nListPos );
240                     const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
241                     if( rRect.Left() < rRefRect.Left() )
242                         return pEntry;
243                 }
244             }
245             return 0;
246         }
247 
248     }
249     if( nRight < nLeft )
250     {
251         sal_uInt16 nTemp = nRight;
252         nRight = nLeft;
253         nLeft = nTemp;
254     }
255     long nMinDistance = LONG_MAX;
256     SvxIconChoiceCtrlEntry* pResult = 0;
257     for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
258     {
259         SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pList->GetObject( nCur ));
260         if( pEntry != pCurEntry )
261         {
262             sal_uInt16 nX = pEntry->nX;
263             if( nX >= nLeft && nX <= nRight )
264             {
265                 const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
266                 long nDistance = rRect.Left() - rRefRect.Left();
267                 if( nDistance < 0 )
268                     nDistance *= -1;
269                 if( nDistance && nDistance < nMinDistance )
270                 {
271                     nMinDistance = nDistance;
272                     pResult = pEntry;
273                 }
274             }
275         }
276     }
277     return pResult;
278 }
279 
280 
281 
282 /*
283     Sucht ab dem uebergebenen Eintrag den naechsten rechts- bzw.
284     linksstehenden. Suchverfahren am Beispiel bRight = sal_True:
285 
286                   c
287                 b c
288               a b c
289             S 1 1 1      ====> Suchrichtung
290               a b c
291                 b c
292                   c
293 
294     S : Startposition
295     1 : erstes Suchrechteck
296     a,b,c : 2., 3., 4. Suchrechteck
297 */
298 
299 SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoLeftRight( SvxIconChoiceCtrlEntry* pCtrlEntry, sal_Bool bRight )
300 {
301     SvxIconChoiceCtrlEntry* pResult;
302     pCurEntry = pCtrlEntry;
303     Create();
304     sal_uInt16 nY = pCtrlEntry->nY;
305     sal_uInt16 nX = pCtrlEntry->nX;
306     DBG_ASSERT(nY< nRows,"GoLeftRight:Bad column");
307     DBG_ASSERT(nX< nCols,"GoLeftRight:Bad row");
308     // Nachbar auf gleicher Zeile ?
309     if( bRight )
310         pResult = SearchRow(
311             nY, nX, sal::static_int_cast< sal_uInt16 >(nCols-1), nX, sal_True, sal_True );
312     else
313         pResult = SearchRow( nY, nX ,0, nX, sal_False, sal_True );
314     if( pResult )
315         return pResult;
316 
317     long nCurCol = nX;
318 
319     long nColOffs, nLastCol;
320     if( bRight )
321     {
322         nColOffs = 1;
323         nLastCol = nCols;
324     }
325     else
326     {
327         nColOffs = -1;
328         nLastCol = -1;   // 0-1
329     }
330 
331     sal_uInt16 nRowMin = nY;
332     sal_uInt16 nRowMax = nY;
333     do
334     {
335         SvxIconChoiceCtrlEntry* pEntry = SearchCol((sal_uInt16)nCurCol,nRowMin,nRowMax,nY,sal_True, sal_False);
336         if( pEntry )
337             return pEntry;
338         if( nRowMin )
339             nRowMin--;
340         if( nRowMax < (nRows-1))
341             nRowMax++;
342         nCurCol += nColOffs;
343     } while( nCurCol != nLastCol );
344     return 0;
345 }
346 
347 SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoPageUpDown( SvxIconChoiceCtrlEntry* pStart, sal_Bool bDown)
348 {
349     if( pView->IsAutoArrange() && !(pView->nWinBits & WB_ALIGN_TOP) )
350     {
351         const long nPos = (long)pView->GetEntryListPos( pStart );
352         long nEntriesInView = (pView->aOutputSize.Height() / pView->nGridDY);
353         nEntriesInView *=
354             ((pView->aOutputSize.Width()+(pView->nGridDX/2)) / pView->nGridDX );
355         long nNewPos = nPos;
356         if( bDown )
357         {
358             nNewPos += nEntriesInView;
359             if( nNewPos >= (long)pView->aEntries.Count() )
360                 nNewPos = pView->aEntries.Count() - 1;
361         }
362         else
363         {
364             nNewPos -= nEntriesInView;
365             if( nNewPos < 0 )
366                 nNewPos = 0;
367         }
368         if( nPos != nNewPos )
369             return (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( (sal_uLong)nNewPos );
370         return 0;
371     }
372     long nOpt = pView->GetEntryBoundRect( pStart ).Top();
373     if( bDown )
374     {
375         nOpt += pView->aOutputSize.Height();
376         nOpt -= pView->nGridDY;
377     }
378     else
379     {
380         nOpt -= pView->aOutputSize.Height();
381         nOpt += pView->nGridDY;
382     }
383     if( nOpt < 0 )
384         nOpt = 0;
385 
386     long nPrevErr = LONG_MAX;
387 
388     SvxIconChoiceCtrlEntry* pPrev = pStart;
389     SvxIconChoiceCtrlEntry* pNext = GoUpDown( pStart, bDown );
390     while( pNext )
391     {
392         long nCur = pView->GetEntryBoundRect( pNext ).Top();
393         long nErr = nOpt - nCur;
394         if( nErr < 0 )
395             nErr *= -1;
396         if( nErr > nPrevErr )
397             return pPrev;
398         nPrevErr = nErr;
399         pPrev = pNext;
400         pNext = GoUpDown( pNext, bDown );
401     }
402     if( pPrev != pStart )
403         return pPrev;
404     return 0;
405 }
406 
407 SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoUpDown( SvxIconChoiceCtrlEntry* pCtrlEntry, sal_Bool bDown)
408 {
409     if( pView->IsAutoArrange() && !(pView->nWinBits & WB_ALIGN_TOP) )
410     {
411         sal_uLong nPos = pView->GetEntryListPos( pCtrlEntry );
412         if( bDown && nPos < (pView->aEntries.Count() - 1) )
413             return (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nPos + 1 );
414         else if( !bDown && nPos > 0 )
415             return (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nPos - 1 );
416         return 0;
417     }
418 
419     SvxIconChoiceCtrlEntry* pResult;
420     pCurEntry = pCtrlEntry;
421     Create();
422     sal_uInt16 nY = pCtrlEntry->nY;
423     sal_uInt16 nX = pCtrlEntry->nX;
424     DBG_ASSERT(nY<nRows,"GoUpDown:Bad column");
425     DBG_ASSERT(nX<nCols,"GoUpDown:Bad row");
426 
427     // Nachbar in gleicher Spalte ?
428     if( bDown )
429         pResult = SearchCol(
430             nX, nY, sal::static_int_cast< sal_uInt16 >(nRows-1), nY, sal_True, sal_True );
431     else
432         pResult = SearchCol( nX, nY ,0, nY, sal_False, sal_True );
433     if( pResult )
434         return pResult;
435 
436     long nCurRow = nY;
437 
438     long nRowOffs, nLastRow;
439     if( bDown )
440     {
441         nRowOffs = 1;
442         nLastRow = nRows;
443     }
444     else
445     {
446         nRowOffs = -1;
447         nLastRow = -1;   // 0-1
448     }
449 
450     sal_uInt16 nColMin = nX;
451     sal_uInt16 nColMax = nX;
452     do
453     {
454         SvxIconChoiceCtrlEntry* pEntry = SearchRow((sal_uInt16)nCurRow,nColMin,nColMax,nX,sal_True, sal_False);
455         if( pEntry )
456             return pEntry;
457         if( nColMin )
458             nColMin--;
459         if( nColMax < (nCols-1))
460             nColMax++;
461         nCurRow += nRowOffs;
462     } while( nCurRow != nLastRow );
463     return 0;
464 }
465 
466 void IcnCursor_Impl::SetDeltas()
467 {
468     const Size& rSize = pView->aVirtOutputSize;
469     nCols = rSize.Width() / pView->nGridDX;
470     if( !nCols )
471         nCols = 1;
472     nRows = rSize.Height() / pView->nGridDY;
473     if( (nRows * pView->nGridDY) < rSize.Height() )
474         nRows++;
475     if( !nRows )
476         nRows = 1;
477 
478     nDeltaWidth = (short)(rSize.Width() / nCols);
479     nDeltaHeight = (short)(rSize.Height() / nRows);
480     if( !nDeltaHeight )
481     {
482         nDeltaHeight = 1;
483         DBG_WARNING("SetDeltas:Bad height");
484     }
485     if( !nDeltaWidth )
486     {
487         nDeltaWidth = 1;
488         DBG_WARNING("SetDeltas:Bad width");
489     }
490 }
491 
492 void IcnCursor_Impl::CreateGridAjustData( SvPtrarr& rLists, SvxIconChoiceCtrlEntry* pRefEntry)
493 {
494     if( !pRefEntry )
495     {
496         sal_uInt16 nGridRows = (sal_uInt16)(pView->aVirtOutputSize.Height() / pView->nGridDY);
497         nGridRows++; // wg. Abrundung!
498 
499         if( !nGridRows )
500             return;
501         for( sal_uInt16 nCurList = 0; nCurList < nGridRows; nCurList++ )
502         {
503             SvPtrarr* pRow = new SvPtrarr;
504             rLists.Insert( (void*)pRow, nCurList );
505         }
506         const sal_uLong nCount = pView->aEntries.Count();
507         for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
508         {
509             SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nCur );
510             const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
511             short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY );
512             sal_uInt16 nIns = GetSortListPos((SvPtrarr*)rLists[nY],rRect.Left(),sal_False);
513             ((SvPtrarr*)rLists[ nY ])->Insert( pEntry, nIns );
514         }
515     }
516     else
517     {
518         // Aufbau eines hor. "Schlauchs" auf der RefEntry-Zeile
519         // UEBERLEGEN: BoundingRect nehmen wg. Ueberlappungen???
520         Rectangle rRefRect( pView->CalcBmpRect( pRefEntry ) );
521         //const Rectangle& rRefRect = pView->GetEntryBoundRect( pRefEntry );
522         short nRefRow = (short)( ((rRefRect.Top()+rRefRect.Bottom())/2) / pView->nGridDY );
523         SvPtrarr* pRow = new SvPtrarr;
524         rLists.Insert( (void*)pRow, 0 );
525         sal_uLong nCount = pView->aEntries.Count();
526         for( sal_uLong nCur = 0; nCur < nCount; nCur++ )
527         {
528             SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nCur );
529             Rectangle rRect( pView->CalcBmpRect(pEntry) );
530             //const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
531             short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY );
532             if( nY == nRefRow )
533             {
534                 sal_uInt16 nIns = GetSortListPos( pRow, rRect.Left(), sal_False );
535                 pRow->Insert( pEntry, nIns );
536             }
537         }
538     }
539 }
540 
541 //static
542 void IcnCursor_Impl::DestroyGridAdjustData( SvPtrarr& rLists )
543 {
544     const sal_uInt16 nCount = rLists.Count();
545     for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
546     {
547         SvPtrarr* pArr = (SvPtrarr*)rLists[ nCur ];
548         delete pArr;
549     }
550     rLists.Remove( 0, rLists.Count() );
551 }
552 
553 IcnGridMap_Impl::IcnGridMap_Impl(SvxIconChoiceCtrl_Impl* pView)
554 {
555     _pView = pView;
556     _pGridMap = 0;
557     _nGridCols = 0;
558     _nGridRows = 0;
559 }
560 
561 IcnGridMap_Impl::~IcnGridMap_Impl()
562 {
563     delete[] _pGridMap, _pGridMap=0;
564 }
565 
566 void IcnGridMap_Impl::Expand()
567 {
568     if( !_pGridMap )
569         Create_Impl();
570     else
571     {
572         sal_uInt16 nNewGridRows = _nGridRows;
573         sal_uInt16 nNewGridCols = _nGridCols;
574         if( _pView->nWinBits & WB_ALIGN_TOP )
575             nNewGridRows += 50;
576         else
577             nNewGridCols += 50;
578 
579         sal_Bool* pNewGridMap = new sal_Bool[nNewGridRows*nNewGridCols];
580         memset( pNewGridMap, 0, nNewGridRows * nNewGridCols * sizeof(sal_Bool) );
581         memcpy( pNewGridMap, _pGridMap, _nGridRows * _nGridCols * sizeof(sal_Bool) );
582         delete[] _pGridMap;
583         _pGridMap = pNewGridMap;
584         _nGridRows = nNewGridRows;
585         _nGridCols = nNewGridCols;
586     }
587 }
588 
589 void IcnGridMap_Impl::Create_Impl()
590 {
591     DBG_ASSERT(!_pGridMap,"Unnecessary call to IcnGridMap_Impl::Create_Impl()");
592     if( _pGridMap )
593         return;
594     GetMinMapSize( _nGridCols, _nGridRows );
595     if( _pView->nWinBits & WB_ALIGN_TOP )
596         _nGridRows += 50;  // avoid resize of gridmap too often
597     else
598         _nGridCols += 50;
599 
600     _pGridMap = new sal_Bool[ _nGridRows * _nGridCols];
601     memset( (void*)_pGridMap, 0, _nGridRows * _nGridCols );
602 
603     const sal_uLong nCount = _pView->aEntries.Count();
604     for( sal_uLong nCur=0; nCur < nCount; nCur++ )
605         OccupyGrids( (SvxIconChoiceCtrlEntry*)_pView->aEntries.GetObject( nCur ));
606 }
607 
608 void IcnGridMap_Impl::GetMinMapSize( sal_uInt16& rDX, sal_uInt16& rDY ) const
609 {
610     long nX, nY;
611     if( _pView->nWinBits & WB_ALIGN_TOP )
612     {
613         // The view grows in vertical direction. Its max. width is _pView->nMaxVirtWidth
614         nX = _pView->nMaxVirtWidth;
615         if( !nX )
616             nX = _pView->pView->GetOutputSizePixel().Width();
617         if( !(_pView->nFlags & F_ARRANGING) )
618             nX -= _pView->nVerSBarWidth;
619 
620         nY = _pView->aVirtOutputSize.Height();
621     }
622     else
623     {
624         // The view grows in horizontal direction. Its max. height is _pView->nMaxVirtHeight
625         nY = _pView->nMaxVirtHeight;
626         if( !nY )
627             nY = _pView->pView->GetOutputSizePixel().Height();
628         if( !(_pView->nFlags & F_ARRANGING) )
629             nY -= _pView->nHorSBarHeight;
630         nX = _pView->aVirtOutputSize.Width();
631     }
632 
633     if( !nX )
634         nX = DEFAULT_MAX_VIRT_WIDTH;
635     if( !nY )
636         nY = DEFAULT_MAX_VIRT_HEIGHT;
637 
638     long nDX = nX / _pView->nGridDX;
639     long nDY = nY / _pView->nGridDY;
640 
641     if( !nDX )
642         nDX++;
643     if( !nDY )
644         nDY++;
645 
646     rDX = (sal_uInt16)nDX;
647     rDY = (sal_uInt16)nDY;
648 }
649 
650 GridId IcnGridMap_Impl::GetGrid( sal_uInt16 nGridX, sal_uInt16 nGridY )
651 {
652     Create();
653     if( _pView->nWinBits & WB_ALIGN_TOP )
654         return nGridX + ( nGridY * _nGridCols );
655     else
656         return nGridY + ( nGridX * _nGridRows );
657 }
658 
659 GridId IcnGridMap_Impl::GetGrid( const Point& rDocPos, sal_Bool* pbClipped )
660 {
661     Create();
662 
663     long nX = rDocPos.X();
664     long nY = rDocPos.Y();
665     nX -= LROFFS_WINBORDER;
666     nY -= TBOFFS_WINBORDER;
667     nX /= _pView->nGridDX;
668     nY /= _pView->nGridDY;
669     sal_Bool bClipped = sal_False;
670     if( nX >= _nGridCols )
671     {
672         nX = _nGridCols - 1;
673         bClipped = sal_True;
674     }
675     if( nY >= _nGridRows )
676     {
677         nY = _nGridRows - 1;
678         bClipped = sal_True;
679     }
680     GridId nId = GetGrid( (sal_uInt16)nX, (sal_uInt16)nY );
681     if( pbClipped )
682         *pbClipped = bClipped;
683     DBG_ASSERT(nId <(sal_uLong)(_nGridCols*_nGridRows),"GetGrid failed");
684     return nId;
685 }
686 
687 Rectangle IcnGridMap_Impl::GetGridRect( GridId nId )
688 {
689     Create();
690     sal_uInt16 nGridX, nGridY;
691     GetGridCoord( nId, nGridX, nGridY );
692     const long nLeft = nGridX * _pView->nGridDX+ LROFFS_WINBORDER;
693     const long nTop = nGridY * _pView->nGridDY + TBOFFS_WINBORDER;
694     return Rectangle(
695         nLeft, nTop,
696         nLeft + _pView->nGridDX,
697         nTop + _pView->nGridDY );
698 }
699 
700 GridId IcnGridMap_Impl::GetUnoccupiedGrid( sal_Bool bOccupyFound )
701 {
702     Create();
703     sal_uLong nStart = 0;
704     sal_Bool bExpanded = sal_False;
705 
706     while( 1 )
707     {
708         const sal_uLong nCount = (sal_uInt16)(_nGridCols * _nGridRows);
709         for( sal_uLong nCur = nStart; nCur < nCount; nCur++ )
710         {
711             if( !_pGridMap[ nCur ] )
712             {
713                 if( bOccupyFound )
714                     _pGridMap[ nCur ] = sal_True;
715                 return (GridId)nCur;
716             }
717         }
718         DBG_ASSERT(!bExpanded,"ExpandGrid failed");
719         if( bExpanded )
720             return 0; // prevent never ending loop
721         bExpanded = sal_True;
722         Expand();
723         nStart = nCount;
724     }
725 }
726 
727 // ein Eintrag belegt nur das unter seinem Zentrum liegende GridRect
728 // diese Variante ist bedeutend schneller als die Belegung ueber das
729 // Bounding-Rect, kann aber zu kleinen Ueberlappungen fuehren
730 #define OCCUPY_CENTER
731 
732 void IcnGridMap_Impl::OccupyGrids( const SvxIconChoiceCtrlEntry* pEntry, sal_Bool bOccupy )
733 {
734     if( !_pGridMap || !_pView->IsBoundingRectValid( pEntry->aRect ))
735         return;
736 #ifndef OCCUPY_CENTER
737     OccupyGrids( pEntry->aRect, bOccupy );
738 #else
739     OccupyGrid( GetGrid( pEntry->aRect.Center()), bOccupy );
740 #endif
741 
742 }
743 
744 void IcnGridMap_Impl::OccupyGrids( const Rectangle& rRect, sal_Bool bUsed )
745 {
746     if( !_pGridMap )
747         return;
748 
749     if( bUsed )
750     {
751         if( _aLastOccupiedGrid == rRect )
752             return;
753         _aLastOccupiedGrid = rRect;
754     }
755     else
756         _aLastOccupiedGrid.SetEmpty();
757 
758     sal_Bool bTopLeftClipped, bBottomRightClipped;
759     GridId nIdTL = GetGrid( rRect.TopLeft(), &bTopLeftClipped );
760     GridId nIdBR = GetGrid( rRect.BottomRight(), &bBottomRightClipped );
761 
762     if( bTopLeftClipped && bBottomRightClipped )
763         return;
764 
765     sal_uInt16 nX1,nX2,nY1,nY2;
766     GetGridCoord( nIdTL, nX1, nY1 );
767     GetGridCoord( nIdBR, nX2, nY2 );
768     sal_uInt16 nTemp;
769     if( nX1 > nX2 )
770     {
771         nTemp = nX1;
772         nX1 = nX2;
773         nX2 = nTemp;
774     }
775     if( nY1 > nY2 )
776     {
777         nTemp = nY1;
778         nY1 = nY2;
779         nY2 = nTemp;
780     }
781     for( ; nX1 <= nX2; nX1++ )
782         for( ; nY1 <= nY2; nY1++ )
783             OccupyGrid( GetGrid( nX1, nY1 ) );
784 }
785 
786 void IcnGridMap_Impl::Clear()
787 {
788     if( _pGridMap )
789     {
790         delete[] _pGridMap, _pGridMap=0;
791         _nGridRows = 0;
792         _nGridCols = 0;
793         _aLastOccupiedGrid.SetEmpty();
794     }
795 }
796 
797 sal_uLong IcnGridMap_Impl::GetGridCount( const Size& rSizePixel, sal_uInt16 nDX, sal_uInt16 nDY)
798 {
799     long ndx = (rSizePixel.Width() - LROFFS_WINBORDER) / nDX;
800     if( ndx < 0 ) ndx *= -1;
801     long ndy = (rSizePixel.Height() - TBOFFS_WINBORDER) / nDY;
802     if( ndy < 0 ) ndy *= -1;
803     return (sal_uLong)(ndx * ndy);
804 }
805 
806 void IcnGridMap_Impl::OutputSizeChanged()
807 {
808     if( _pGridMap )
809     {
810         sal_uInt16 nCols, nRows;
811         GetMinMapSize( nCols, nRows );
812         if( _pView->nWinBits & WB_ALIGN_TOP )
813         {
814             if( nCols != _nGridCols )
815                 Clear();
816             else if( nRows >= _nGridRows )
817                 Expand();
818         }
819         else
820         {
821             if( nRows != _nGridRows )
822                 Clear();
823             else if( nCols >= _nGridCols )
824                 Expand();
825         }
826     }
827 }
828 
829 // Independendly of the views alignment (TOP or LEFT) the gridmap
830 // should contain the data in a continues region, to make it possible
831 // to copy the whole block if the gridmap needs to be expanded.
832 void IcnGridMap_Impl::GetGridCoord( GridId nId, sal_uInt16& rGridX, sal_uInt16& rGridY )
833 {
834     Create();
835     if( _pView->nWinBits & WB_ALIGN_TOP )
836     {
837         rGridX = (sal_uInt16)(nId % _nGridCols);
838         rGridY = (sal_uInt16)(nId / _nGridCols);
839     }
840     else
841     {
842         rGridX = (sal_uInt16)(nId / _nGridRows);
843         rGridY = (sal_uInt16)(nId % _nGridRows);
844     }
845 }
846 
847 
848 
849