xref: /aoo41x/main/svtools/source/contnr/imivctl2.cxx (revision cdf0e10c)
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