Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "imivctl.hxx"
21 :
22 0 : IcnCursor_Impl::IcnCursor_Impl( SvxIconChoiceCtrl_Impl* pOwner )
23 : {
24 0 : pView = pOwner;
25 0 : pCurEntry = 0;
26 0 : nDeltaWidth = 0;
27 0 : nDeltaHeight= 0;
28 0 : nCols = 0;
29 0 : nRows = 0;
30 0 : }
31 :
32 0 : IcnCursor_Impl::~IcnCursor_Impl()
33 : {
34 0 : }
35 :
36 0 : sal_uInt16 IcnCursor_Impl::GetSortListPos( SvxIconChoiceCtrlEntryPtrVec& rList, long nValue,
37 : int bVertical )
38 : {
39 0 : sal_uInt16 nCount = rList.size();
40 0 : if( !nCount )
41 0 : return 0;
42 :
43 0 : sal_uInt16 nCurPos = 0;
44 0 : long nPrevValue = LONG_MIN;
45 0 : while( nCount )
46 : {
47 0 : const Rectangle& rRect = pView->GetEntryBoundRect( rList[nCurPos] );
48 : long nCurValue;
49 0 : if( bVertical )
50 0 : nCurValue = rRect.Top();
51 : else
52 0 : nCurValue = rRect.Left();
53 0 : if( nValue >= nPrevValue && nValue <= nCurValue )
54 0 : return (sal_uInt16)nCurPos;
55 0 : nPrevValue = nCurValue;
56 0 : nCount--;
57 0 : nCurPos++;
58 : }
59 0 : return rList.size();
60 : }
61 :
62 0 : void IcnCursor_Impl::ImplCreate()
63 : {
64 0 : pView->CheckBoundingRects();
65 : DBG_ASSERT(pColumns==0&&pRows==0,"ImplCreate: Not cleared");
66 :
67 0 : SetDeltas();
68 :
69 0 : pColumns.reset(new IconChoiceMap);
70 0 : pRows.reset(new IconChoiceMap);
71 :
72 0 : size_t nCount = pView->aEntries.size();
73 0 : for( size_t nCur = 0; nCur < nCount; nCur++ )
74 : {
75 0 : SvxIconChoiceCtrlEntry* pEntry = pView->aEntries[ nCur ];
76 : // const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
77 0 : Rectangle rRect( pView->CalcBmpRect( pEntry,0 ) );
78 0 : short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / nDeltaHeight );
79 0 : short nX = (short)( ((rRect.Left()+rRect.Right())/2) / nDeltaWidth );
80 :
81 : // capture rounding errors
82 0 : if( nY >= nRows )
83 0 : nY = sal::static_int_cast< short >(nRows - 1);
84 0 : if( nX >= nCols )
85 0 : nX = sal::static_int_cast< short >(nCols - 1);
86 :
87 0 : SvxIconChoiceCtrlEntryPtrVec& rColEntry = (*pColumns)[nX];
88 0 : sal_uInt16 nIns = GetSortListPos( rColEntry, rRect.Top(), sal_True );
89 0 : rColEntry.insert( rColEntry.begin() + nIns, pEntry );
90 :
91 0 : SvxIconChoiceCtrlEntryPtrVec& rRowEntry = (*pRows)[nY];
92 0 : nIns = GetSortListPos( rRowEntry, rRect.Left(), sal_False );
93 0 : rRowEntry.insert( rRowEntry.begin() + nIns, pEntry );
94 :
95 0 : pEntry->nX = nX;
96 0 : pEntry->nY = nY;
97 : }
98 0 : }
99 :
100 :
101 :
102 :
103 0 : void IcnCursor_Impl::Clear()
104 : {
105 0 : if( pColumns )
106 : {
107 0 : pColumns.reset();
108 0 : pRows.reset();
109 0 : pCurEntry = 0;
110 0 : nDeltaWidth = 0;
111 0 : nDeltaHeight = 0;
112 : }
113 0 : }
114 :
115 0 : SvxIconChoiceCtrlEntry* IcnCursor_Impl::SearchCol(sal_uInt16 nCol, sal_uInt16 nTop, sal_uInt16 nBottom,
116 : sal_uInt16, bool bDown, bool bSimple )
117 : {
118 : DBG_ASSERT(pCurEntry, "SearchCol: No reference entry");
119 0 : IconChoiceMap::iterator mapIt = pColumns->find( nCol );
120 0 : if ( mapIt == pColumns->end() )
121 0 : return 0;
122 0 : SvxIconChoiceCtrlEntryPtrVec const & rList = mapIt->second;
123 0 : const sal_uInt16 nCount = rList.size();
124 0 : if( !nCount )
125 0 : return 0;
126 :
127 0 : const Rectangle& rRefRect = pView->GetEntryBoundRect(pCurEntry);
128 :
129 0 : if( bSimple )
130 : {
131 0 : SvxIconChoiceCtrlEntryPtrVec::const_iterator it = std::find( rList.begin(), rList.end(), pCurEntry );
132 : DBG_ASSERT( it != rList.end(), "Entry not in Col-List" );
133 0 : if( bDown )
134 : {
135 0 : while( ++it != rList.end() )
136 : {
137 0 : SvxIconChoiceCtrlEntry* pEntry = *it;
138 0 : const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
139 0 : if( rRect.Top() > rRefRect.Top() )
140 0 : return pEntry;
141 : }
142 0 : return 0;
143 : }
144 : else
145 : {
146 0 : SvxIconChoiceCtrlEntryPtrVec::const_reverse_iterator it2(it);
147 0 : while (it2 != rList.rend())
148 : {
149 0 : SvxIconChoiceCtrlEntry* pEntry = *it2;
150 0 : const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
151 0 : if( rRect.Top() < rRefRect.Top() )
152 0 : return pEntry;
153 0 : ++it2;
154 : }
155 0 : return 0;
156 : }
157 : }
158 :
159 0 : if( nTop > nBottom )
160 : {
161 0 : sal_uInt16 nTemp = nTop;
162 0 : nTop = nBottom;
163 0 : nBottom = nTemp;
164 : }
165 0 : long nMinDistance = LONG_MAX;
166 0 : SvxIconChoiceCtrlEntry* pResult = 0;
167 0 : for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
168 : {
169 0 : SvxIconChoiceCtrlEntry* pEntry = rList[ nCur ];
170 0 : if( pEntry != pCurEntry )
171 : {
172 0 : sal_uInt16 nY = pEntry->nY;
173 0 : if( nY >= nTop && nY <= nBottom )
174 : {
175 0 : const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
176 0 : long nDistance = rRect.Top() - rRefRect.Top();
177 0 : if( nDistance < 0 )
178 0 : nDistance *= -1;
179 0 : if( nDistance && nDistance < nMinDistance )
180 : {
181 0 : nMinDistance = nDistance;
182 0 : pResult = pEntry;
183 : }
184 : }
185 : }
186 : }
187 0 : return pResult;
188 : }
189 :
190 0 : SvxIconChoiceCtrlEntry* IcnCursor_Impl::SearchRow(sal_uInt16 nRow, sal_uInt16 nLeft, sal_uInt16 nRight,
191 : sal_uInt16, bool bRight, bool bSimple )
192 : {
193 : DBG_ASSERT(pCurEntry,"SearchRow: No reference entry");
194 0 : IconChoiceMap::iterator mapIt = pRows->find( nRow );
195 0 : if ( mapIt == pRows->end() )
196 0 : return 0;
197 0 : SvxIconChoiceCtrlEntryPtrVec const & rList = mapIt->second;
198 0 : const sal_uInt16 nCount = rList.size();
199 0 : if( !nCount )
200 0 : return 0;
201 :
202 0 : const Rectangle& rRefRect = pView->GetEntryBoundRect(pCurEntry);
203 :
204 0 : if( bSimple )
205 : {
206 0 : SvxIconChoiceCtrlEntryPtrVec::const_iterator it = std::find( rList.begin(), rList.end(), pCurEntry );
207 : DBG_ASSERT( it != rList.end(), "Entry not in Row-List" );
208 0 : if( bRight )
209 : {
210 0 : while( ++it != rList.end() )
211 : {
212 0 : SvxIconChoiceCtrlEntry* pEntry = *it;
213 0 : const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
214 0 : if( rRect.Left() > rRefRect.Left() )
215 0 : return pEntry;
216 : }
217 0 : return 0;
218 : }
219 : else
220 : {
221 0 : SvxIconChoiceCtrlEntryPtrVec::const_reverse_iterator it2(it);
222 0 : while (it2 != rList.rend())
223 : {
224 0 : SvxIconChoiceCtrlEntry* pEntry = *it2;
225 0 : const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
226 0 : if( rRect.Left() < rRefRect.Left() )
227 0 : return pEntry;
228 0 : ++it2;
229 : }
230 0 : return 0;
231 : }
232 :
233 : }
234 0 : if( nRight < nLeft )
235 : {
236 0 : sal_uInt16 nTemp = nRight;
237 0 : nRight = nLeft;
238 0 : nLeft = nTemp;
239 : }
240 0 : long nMinDistance = LONG_MAX;
241 0 : SvxIconChoiceCtrlEntry* pResult = 0;
242 0 : for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
243 : {
244 0 : SvxIconChoiceCtrlEntry* pEntry = rList[ nCur ];
245 0 : if( pEntry != pCurEntry )
246 : {
247 0 : sal_uInt16 nX = pEntry->nX;
248 0 : if( nX >= nLeft && nX <= nRight )
249 : {
250 0 : const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
251 0 : long nDistance = rRect.Left() - rRefRect.Left();
252 0 : if( nDistance < 0 )
253 0 : nDistance *= -1;
254 0 : if( nDistance && nDistance < nMinDistance )
255 : {
256 0 : nMinDistance = nDistance;
257 0 : pResult = pEntry;
258 : }
259 : }
260 : }
261 : }
262 0 : return pResult;
263 : }
264 :
265 :
266 :
267 : /*
268 : Searches, starting from the passed value, the next entry to the left/to the
269 : right. Example for bRight = sal_True:
270 :
271 : c
272 : b c
273 : a b c
274 : S 1 1 1 ====> search direction
275 : a b c
276 : b c
277 : c
278 :
279 : S : starting position
280 : 1 : first searched rectangle
281 : a,b,c : 2nd, 3rd, 4th searched rectangle
282 : */
283 :
284 0 : SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoLeftRight( SvxIconChoiceCtrlEntry* pCtrlEntry, sal_Bool bRight )
285 : {
286 : SvxIconChoiceCtrlEntry* pResult;
287 0 : pCurEntry = pCtrlEntry;
288 0 : Create();
289 0 : sal_uInt16 nY = pCtrlEntry->nY;
290 0 : sal_uInt16 nX = pCtrlEntry->nX;
291 : DBG_ASSERT(nY< nRows,"GoLeftRight:Bad column");
292 : DBG_ASSERT(nX< nCols,"GoLeftRight:Bad row");
293 : // neighbor in same row?
294 0 : if( bRight )
295 : pResult = SearchRow(
296 0 : nY, nX, sal::static_int_cast< sal_uInt16 >(nCols-1), nX, sal_True, sal_True );
297 : else
298 0 : pResult = SearchRow( nY, nX ,0, nX, sal_False, sal_True );
299 0 : if( pResult )
300 0 : return pResult;
301 :
302 0 : long nCurCol = nX;
303 :
304 : long nColOffs, nLastCol;
305 0 : if( bRight )
306 : {
307 0 : nColOffs = 1;
308 0 : nLastCol = nCols;
309 : }
310 : else
311 : {
312 0 : nColOffs = -1;
313 0 : nLastCol = -1; // 0-1
314 : }
315 :
316 0 : sal_uInt16 nRowMin = nY;
317 0 : sal_uInt16 nRowMax = nY;
318 0 : do
319 : {
320 0 : SvxIconChoiceCtrlEntry* pEntry = SearchCol((sal_uInt16)nCurCol,nRowMin,nRowMax,nY,sal_True, sal_False);
321 0 : if( pEntry )
322 0 : return pEntry;
323 0 : if( nRowMin )
324 0 : nRowMin--;
325 0 : if( nRowMax < (nRows-1))
326 0 : nRowMax++;
327 0 : nCurCol += nColOffs;
328 : } while( nCurCol != nLastCol );
329 0 : return 0;
330 : }
331 :
332 0 : SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoPageUpDown( SvxIconChoiceCtrlEntry* pStart, sal_Bool bDown)
333 : {
334 0 : if( pView->IsAutoArrange() && !(pView->nWinBits & WB_ALIGN_TOP) )
335 : {
336 0 : const long nPos = (long)pView->GetEntryListPos( pStart );
337 0 : long nEntriesInView = (pView->aOutputSize.Height() / pView->nGridDY);
338 : nEntriesInView *=
339 0 : ((pView->aOutputSize.Width()+(pView->nGridDX/2)) / pView->nGridDX );
340 0 : long nNewPos = nPos;
341 0 : if( bDown )
342 : {
343 0 : nNewPos += nEntriesInView;
344 0 : if( nNewPos >= (long)pView->aEntries.size() )
345 0 : nNewPos = pView->aEntries.size() - 1;
346 : }
347 : else
348 : {
349 0 : nNewPos -= nEntriesInView;
350 0 : if( nNewPos < 0 )
351 0 : nNewPos = 0;
352 : }
353 0 : if( nPos != nNewPos )
354 0 : return pView->aEntries[ (size_t)nNewPos ];
355 0 : return 0;
356 : }
357 0 : long nOpt = pView->GetEntryBoundRect( pStart ).Top();
358 0 : if( bDown )
359 : {
360 0 : nOpt += pView->aOutputSize.Height();
361 0 : nOpt -= pView->nGridDY;
362 : }
363 : else
364 : {
365 0 : nOpt -= pView->aOutputSize.Height();
366 0 : nOpt += pView->nGridDY;
367 : }
368 0 : if( nOpt < 0 )
369 0 : nOpt = 0;
370 :
371 0 : long nPrevErr = LONG_MAX;
372 :
373 0 : SvxIconChoiceCtrlEntry* pPrev = pStart;
374 0 : SvxIconChoiceCtrlEntry* pNext = GoUpDown( pStart, bDown );
375 0 : while( pNext )
376 : {
377 0 : long nCur = pView->GetEntryBoundRect( pNext ).Top();
378 0 : long nErr = nOpt - nCur;
379 0 : if( nErr < 0 )
380 0 : nErr *= -1;
381 0 : if( nErr > nPrevErr )
382 0 : return pPrev;
383 0 : nPrevErr = nErr;
384 0 : pPrev = pNext;
385 0 : pNext = GoUpDown( pNext, bDown );
386 : }
387 0 : if( pPrev != pStart )
388 0 : return pPrev;
389 0 : return 0;
390 : }
391 :
392 0 : SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoUpDown( SvxIconChoiceCtrlEntry* pCtrlEntry, sal_Bool bDown)
393 : {
394 0 : if( pView->IsAutoArrange() && !(pView->nWinBits & WB_ALIGN_TOP) )
395 : {
396 0 : sal_uLong nPos = pView->GetEntryListPos( pCtrlEntry );
397 0 : if( bDown && nPos < (pView->aEntries.size() - 1) )
398 0 : return pView->aEntries[ nPos + 1 ];
399 0 : else if( !bDown && nPos > 0 )
400 0 : return pView->aEntries[ nPos - 1 ];
401 0 : return 0;
402 : }
403 :
404 : SvxIconChoiceCtrlEntry* pResult;
405 0 : pCurEntry = pCtrlEntry;
406 0 : Create();
407 0 : sal_uInt16 nY = pCtrlEntry->nY;
408 0 : sal_uInt16 nX = pCtrlEntry->nX;
409 : DBG_ASSERT(nY<nRows,"GoUpDown:Bad column");
410 : DBG_ASSERT(nX<nCols,"GoUpDown:Bad row");
411 :
412 : // neighbor in same column?
413 0 : if( bDown )
414 : pResult = SearchCol(
415 0 : nX, nY, sal::static_int_cast< sal_uInt16 >(nRows-1), nY, sal_True, sal_True );
416 : else
417 0 : pResult = SearchCol( nX, nY ,0, nY, sal_False, sal_True );
418 0 : if( pResult )
419 0 : return pResult;
420 :
421 0 : long nCurRow = nY;
422 :
423 : long nRowOffs, nLastRow;
424 0 : if( bDown )
425 : {
426 0 : nRowOffs = 1;
427 0 : nLastRow = nRows;
428 : }
429 : else
430 : {
431 0 : nRowOffs = -1;
432 0 : nLastRow = -1; // 0-1
433 : }
434 :
435 0 : sal_uInt16 nColMin = nX;
436 0 : sal_uInt16 nColMax = nX;
437 0 : do
438 : {
439 0 : SvxIconChoiceCtrlEntry* pEntry = SearchRow((sal_uInt16)nCurRow,nColMin,nColMax,nX,sal_True, sal_False);
440 0 : if( pEntry )
441 0 : return pEntry;
442 0 : if( nColMin )
443 0 : nColMin--;
444 0 : if( nColMax < (nCols-1))
445 0 : nColMax++;
446 0 : nCurRow += nRowOffs;
447 : } while( nCurRow != nLastRow );
448 0 : return 0;
449 : }
450 :
451 0 : void IcnCursor_Impl::SetDeltas()
452 : {
453 0 : const Size& rSize = pView->aVirtOutputSize;
454 0 : nCols = rSize.Width() / pView->nGridDX;
455 0 : if( !nCols )
456 0 : nCols = 1;
457 0 : nRows = rSize.Height() / pView->nGridDY;
458 0 : if( (nRows * pView->nGridDY) < rSize.Height() )
459 0 : nRows++;
460 0 : if( !nRows )
461 0 : nRows = 1;
462 :
463 0 : nDeltaWidth = (short)(rSize.Width() / nCols);
464 0 : nDeltaHeight = (short)(rSize.Height() / nRows);
465 0 : if( !nDeltaHeight )
466 : {
467 0 : nDeltaHeight = 1;
468 : DBG_WARNING("SetDeltas:Bad height");
469 : }
470 0 : if( !nDeltaWidth )
471 : {
472 0 : nDeltaWidth = 1;
473 : DBG_WARNING("SetDeltas:Bad width");
474 : }
475 0 : }
476 :
477 0 : void IcnCursor_Impl::CreateGridAjustData( IconChoiceMap& rLists, SvxIconChoiceCtrlEntry* pRefEntry)
478 : {
479 0 : if( !pRefEntry )
480 : {
481 0 : sal_uInt16 nGridRows = (sal_uInt16)(pView->aVirtOutputSize.Height() / pView->nGridDY);
482 0 : nGridRows++; // because we round down later!
483 :
484 0 : if( !nGridRows )
485 0 : return;
486 0 : const size_t nCount = pView->aEntries.size();
487 0 : for( size_t nCur = 0; nCur < nCount; nCur++ )
488 : {
489 0 : SvxIconChoiceCtrlEntry* pEntry = pView->aEntries[ nCur ];
490 0 : const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
491 0 : short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY );
492 0 : sal_uInt16 nIns = GetSortListPos( rLists[nY], rRect.Left(), sal_False );
493 0 : rLists[ nY ].insert( rLists[ nY ].begin() + nIns, pEntry );
494 : }
495 : }
496 : else
497 : {
498 : // build a horizontal "tube" in the RefEntry line
499 : // STOP AND THINK: maybe use bounding rectangle because of overlaps?
500 0 : Rectangle rRefRect( pView->CalcBmpRect( pRefEntry ) );
501 : //const Rectangle& rRefRect = pView->GetEntryBoundRect( pRefEntry );
502 0 : short nRefRow = (short)( ((rRefRect.Top()+rRefRect.Bottom())/2) / pView->nGridDY );
503 0 : SvxIconChoiceCtrlEntryPtrVec& rRow = rLists[0];
504 0 : size_t nCount = pView->aEntries.size();
505 0 : for( size_t nCur = 0; nCur < nCount; nCur++ )
506 : {
507 0 : SvxIconChoiceCtrlEntry* pEntry = pView->aEntries[ nCur ];
508 0 : Rectangle rRect( pView->CalcBmpRect(pEntry) );
509 : //const Rectangle& rRect = pView->GetEntryBoundRect( pEntry );
510 0 : short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY );
511 0 : if( nY == nRefRow )
512 : {
513 0 : sal_uInt16 nIns = GetSortListPos( rRow, rRect.Left(), sal_False );
514 0 : rRow.insert( rRow.begin() + nIns, pEntry );
515 : }
516 : }
517 : }
518 : }
519 :
520 : //static
521 0 : void IcnCursor_Impl::DestroyGridAdjustData( IconChoiceMap& rLists )
522 : {
523 0 : rLists.clear();
524 0 : }
525 :
526 0 : IcnGridMap_Impl::IcnGridMap_Impl(SvxIconChoiceCtrl_Impl* pView)
527 : {
528 0 : _pView = pView;
529 0 : _pGridMap = 0;
530 0 : _nGridCols = 0;
531 0 : _nGridRows = 0;
532 0 : }
533 :
534 0 : IcnGridMap_Impl::~IcnGridMap_Impl()
535 : {
536 0 : delete[] _pGridMap, _pGridMap=0;
537 0 : }
538 :
539 0 : void IcnGridMap_Impl::Expand()
540 : {
541 0 : if( !_pGridMap )
542 0 : Create_Impl();
543 : else
544 : {
545 0 : sal_uInt16 nNewGridRows = _nGridRows;
546 0 : sal_uInt16 nNewGridCols = _nGridCols;
547 0 : if( _pView->nWinBits & WB_ALIGN_TOP )
548 0 : nNewGridRows += 50;
549 : else
550 0 : nNewGridCols += 50;
551 :
552 0 : sal_Bool* pNewGridMap = new sal_Bool[nNewGridRows*nNewGridCols];
553 0 : memset( pNewGridMap, 0, nNewGridRows * nNewGridCols * sizeof(sal_Bool) );
554 0 : memcpy( pNewGridMap, _pGridMap, _nGridRows * _nGridCols * sizeof(sal_Bool) );
555 0 : delete[] _pGridMap;
556 0 : _pGridMap = pNewGridMap;
557 0 : _nGridRows = nNewGridRows;
558 0 : _nGridCols = nNewGridCols;
559 : }
560 0 : }
561 :
562 0 : void IcnGridMap_Impl::Create_Impl()
563 : {
564 : DBG_ASSERT(!_pGridMap,"Unnecessary call to IcnGridMap_Impl::Create_Impl()");
565 0 : if( _pGridMap )
566 0 : return;
567 0 : GetMinMapSize( _nGridCols, _nGridRows );
568 0 : if( _pView->nWinBits & WB_ALIGN_TOP )
569 0 : _nGridRows += 50; // avoid resize of gridmap too often
570 : else
571 0 : _nGridCols += 50;
572 :
573 0 : _pGridMap = new sal_Bool[ _nGridRows * _nGridCols];
574 0 : memset( (void*)_pGridMap, 0, _nGridRows * _nGridCols );
575 :
576 0 : const size_t nCount = _pView->aEntries.size();
577 0 : for( size_t nCur=0; nCur < nCount; nCur++ )
578 0 : OccupyGrids( _pView->aEntries[ nCur ] );
579 : }
580 :
581 0 : void IcnGridMap_Impl::GetMinMapSize( sal_uInt16& rDX, sal_uInt16& rDY ) const
582 : {
583 : long nX, nY;
584 0 : if( _pView->nWinBits & WB_ALIGN_TOP )
585 : {
586 : // The view grows in vertical direction. Its max. width is _pView->nMaxVirtWidth
587 0 : nX = _pView->nMaxVirtWidth;
588 0 : if( !nX )
589 0 : nX = _pView->pView->GetOutputSizePixel().Width();
590 0 : if( !(_pView->nFlags & F_ARRANGING) )
591 0 : nX -= _pView->nVerSBarWidth;
592 :
593 0 : nY = _pView->aVirtOutputSize.Height();
594 : }
595 : else
596 : {
597 : // The view grows in horizontal direction. Its max. height is _pView->nMaxVirtHeight
598 0 : nY = _pView->nMaxVirtHeight;
599 0 : if( !nY )
600 0 : nY = _pView->pView->GetOutputSizePixel().Height();
601 0 : if( !(_pView->nFlags & F_ARRANGING) )
602 0 : nY -= _pView->nHorSBarHeight;
603 0 : nX = _pView->aVirtOutputSize.Width();
604 : }
605 :
606 0 : if( !nX )
607 0 : nX = DEFAULT_MAX_VIRT_WIDTH;
608 0 : if( !nY )
609 0 : nY = DEFAULT_MAX_VIRT_HEIGHT;
610 :
611 0 : long nDX = nX / _pView->nGridDX;
612 0 : long nDY = nY / _pView->nGridDY;
613 :
614 0 : if( !nDX )
615 0 : nDX++;
616 0 : if( !nDY )
617 0 : nDY++;
618 :
619 0 : rDX = (sal_uInt16)nDX;
620 0 : rDY = (sal_uInt16)nDY;
621 0 : }
622 :
623 0 : GridId IcnGridMap_Impl::GetGrid( sal_uInt16 nGridX, sal_uInt16 nGridY )
624 : {
625 0 : Create();
626 0 : if( _pView->nWinBits & WB_ALIGN_TOP )
627 0 : return nGridX + ( nGridY * _nGridCols );
628 : else
629 0 : return nGridY + ( nGridX * _nGridRows );
630 : }
631 :
632 0 : GridId IcnGridMap_Impl::GetGrid( const Point& rDocPos, sal_Bool* pbClipped )
633 : {
634 0 : Create();
635 :
636 0 : long nX = rDocPos.X();
637 0 : long nY = rDocPos.Y();
638 0 : nX -= LROFFS_WINBORDER;
639 0 : nY -= TBOFFS_WINBORDER;
640 0 : nX /= _pView->nGridDX;
641 0 : nY /= _pView->nGridDY;
642 0 : sal_Bool bClipped = sal_False;
643 0 : if( nX >= _nGridCols )
644 : {
645 0 : nX = _nGridCols - 1;
646 0 : bClipped = sal_True;
647 : }
648 0 : if( nY >= _nGridRows )
649 : {
650 0 : nY = _nGridRows - 1;
651 0 : bClipped = sal_True;
652 : }
653 0 : GridId nId = GetGrid( (sal_uInt16)nX, (sal_uInt16)nY );
654 0 : if( pbClipped )
655 0 : *pbClipped = bClipped;
656 : DBG_ASSERT(nId <(sal_uLong)(_nGridCols*_nGridRows),"GetGrid failed");
657 0 : return nId;
658 : }
659 :
660 0 : Rectangle IcnGridMap_Impl::GetGridRect( GridId nId )
661 : {
662 0 : Create();
663 : sal_uInt16 nGridX, nGridY;
664 0 : GetGridCoord( nId, nGridX, nGridY );
665 0 : const long nLeft = nGridX * _pView->nGridDX+ LROFFS_WINBORDER;
666 0 : const long nTop = nGridY * _pView->nGridDY + TBOFFS_WINBORDER;
667 : return Rectangle(
668 : nLeft, nTop,
669 : nLeft + _pView->nGridDX,
670 0 : nTop + _pView->nGridDY );
671 : }
672 :
673 0 : GridId IcnGridMap_Impl::GetUnoccupiedGrid( sal_Bool bOccupyFound )
674 : {
675 0 : Create();
676 0 : sal_uLong nStart = 0;
677 0 : sal_Bool bExpanded = sal_False;
678 :
679 0 : while( 1 )
680 : {
681 0 : const sal_uLong nCount = (sal_uInt16)(_nGridCols * _nGridRows);
682 0 : for( sal_uLong nCur = nStart; nCur < nCount; nCur++ )
683 : {
684 0 : if( !_pGridMap[ nCur ] )
685 : {
686 0 : if( bOccupyFound )
687 0 : _pGridMap[ nCur ] = sal_True;
688 0 : return (GridId)nCur;
689 : }
690 : }
691 : DBG_ASSERT(!bExpanded,"ExpandGrid failed");
692 0 : if( bExpanded )
693 0 : return 0; // prevent never ending loop
694 0 : bExpanded = sal_True;
695 0 : Expand();
696 0 : nStart = nCount;
697 : }
698 : }
699 :
700 : // An entry only means that there's a GridRect lying under its center. This
701 : // variant is much faster than allocating via the bounding rectangle but can
702 : // lead to small overlaps.
703 0 : void IcnGridMap_Impl::OccupyGrids( const SvxIconChoiceCtrlEntry* pEntry, sal_Bool bOccupy )
704 : {
705 0 : if( !_pGridMap || !_pView->IsBoundingRectValid( pEntry->aRect ))
706 0 : return;
707 0 : OccupyGrid( GetGrid( pEntry->aRect.Center()), bOccupy );
708 : }
709 :
710 0 : void IcnGridMap_Impl::Clear()
711 : {
712 0 : if( _pGridMap )
713 : {
714 0 : delete[] _pGridMap, _pGridMap=0;
715 0 : _nGridRows = 0;
716 0 : _nGridCols = 0;
717 0 : _aLastOccupiedGrid.SetEmpty();
718 : }
719 0 : }
720 :
721 0 : sal_uLong IcnGridMap_Impl::GetGridCount( const Size& rSizePixel, sal_uInt16 nDX, sal_uInt16 nDY)
722 : {
723 0 : long ndx = (rSizePixel.Width() - LROFFS_WINBORDER) / nDX;
724 0 : if( ndx < 0 ) ndx *= -1;
725 0 : long ndy = (rSizePixel.Height() - TBOFFS_WINBORDER) / nDY;
726 0 : if( ndy < 0 ) ndy *= -1;
727 0 : return (sal_uLong)(ndx * ndy);
728 : }
729 :
730 0 : void IcnGridMap_Impl::OutputSizeChanged()
731 : {
732 0 : if( _pGridMap )
733 : {
734 : sal_uInt16 nCols, nRows;
735 0 : GetMinMapSize( nCols, nRows );
736 0 : if( _pView->nWinBits & WB_ALIGN_TOP )
737 : {
738 0 : if( nCols != _nGridCols )
739 0 : Clear();
740 0 : else if( nRows >= _nGridRows )
741 0 : Expand();
742 : }
743 : else
744 : {
745 0 : if( nRows != _nGridRows )
746 0 : Clear();
747 0 : else if( nCols >= _nGridCols )
748 0 : Expand();
749 : }
750 : }
751 0 : }
752 :
753 : // Independently of the view's alignment (TOP or LEFT), the gridmap
754 : // should contain the data in a continuous region, to make it possible
755 : // to copy the whole block if the gridmap needs to be expanded.
756 0 : void IcnGridMap_Impl::GetGridCoord( GridId nId, sal_uInt16& rGridX, sal_uInt16& rGridY )
757 : {
758 0 : Create();
759 0 : if( _pView->nWinBits & WB_ALIGN_TOP )
760 : {
761 0 : rGridX = (sal_uInt16)(nId % _nGridCols);
762 0 : rGridY = (sal_uInt16)(nId / _nGridCols);
763 : }
764 : else
765 : {
766 0 : rGridX = (sal_uInt16)(nId / _nGridRows);
767 0 : rGridY = (sal_uInt16)(nId % _nGridRows);
768 : }
769 0 : }
770 :
771 :
772 :
773 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|