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