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