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 7 : IcnCursor_Impl::IcnCursor_Impl( SvxIconChoiceCtrl_Impl* pOwner )
23 : {
24 7 : pView = pOwner;
25 7 : pCurEntry = 0;
26 7 : nDeltaWidth = 0;
27 7 : nDeltaHeight= 0;
28 7 : nCols = 0;
29 7 : nRows = 0;
30 7 : }
31 :
32 5 : IcnCursor_Impl::~IcnCursor_Impl()
33 : {
34 5 : }
35 :
36 0 : sal_uInt16 IcnCursor_Impl::GetSortListPos( SvxIconChoiceCtrlEntryPtrVec& rList, long nValue,
37 : bool 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(xColumns==0&&xRows==0,"ImplCreate: Not cleared");
66 :
67 0 : SetDeltas();
68 :
69 0 : xColumns.reset(new IconChoiceMap);
70 0 : xRows.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 = (*xColumns)[nX];
88 0 : sal_uInt16 nIns = GetSortListPos( rColEntry, rRect.Top(), true );
89 0 : rColEntry.insert( rColEntry.begin() + nIns, pEntry );
90 :
91 0 : SvxIconChoiceCtrlEntryPtrVec& rRowEntry = (*xRows)[nY];
92 0 : nIns = GetSortListPos( rRowEntry, rRect.Left(), 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 373 : void IcnCursor_Impl::Clear()
104 : {
105 373 : if( xColumns )
106 : {
107 0 : xColumns.reset();
108 0 : xRows.reset();
109 0 : pCurEntry = 0;
110 0 : nDeltaWidth = 0;
111 0 : nDeltaHeight = 0;
112 : }
113 373 : }
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 = xColumns->find( nCol );
120 0 : if ( mapIt == xColumns->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 = xRows->find( nRow );
199 0 : if ( mapIt == xRows->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, 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, 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, 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(), 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(), 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 7 : IcnGridMap_Impl::IcnGridMap_Impl(SvxIconChoiceCtrl_Impl* pView)
535 : {
536 7 : _pView = pView;
537 7 : _pGridMap = 0;
538 7 : _nGridCols = 0;
539 7 : _nGridRows = 0;
540 7 : }
541 :
542 5 : IcnGridMap_Impl::~IcnGridMap_Impl()
543 : {
544 5 : delete[] _pGridMap, _pGridMap=0;
545 5 : }
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 : size_t nNewCellCount = static_cast<size_t>(nNewGridRows) * nNewGridCols;
561 0 : bool* pNewGridMap = new bool[nNewCellCount];
562 0 : memset(pNewGridMap, 0, nNewCellCount * sizeof(bool));
563 0 : size_t nOldCellCount = static_cast<size_t>(_nGridRows) * _nGridCols;
564 0 : memcpy(pNewGridMap, _pGridMap, nOldCellCount * sizeof(bool));
565 0 : delete[] _pGridMap;
566 0 : _pGridMap = pNewGridMap;
567 0 : _nGridRows = nNewGridRows;
568 0 : _nGridCols = nNewGridCols;
569 : }
570 0 : }
571 :
572 65 : void IcnGridMap_Impl::Create_Impl()
573 : {
574 : DBG_ASSERT(!_pGridMap,"Unnecessary call to IcnGridMap_Impl::Create_Impl()");
575 65 : if( _pGridMap )
576 65 : return;
577 65 : GetMinMapSize( _nGridCols, _nGridRows );
578 65 : if( _pView->nWinBits & WB_ALIGN_TOP )
579 0 : _nGridRows += 50; // avoid resize of gridmap too often
580 : else
581 65 : _nGridCols += 50;
582 :
583 65 : size_t nCellCount = static_cast<size_t>(_nGridRows) * _nGridCols;
584 65 : _pGridMap = new bool[nCellCount];
585 65 : memset(_pGridMap, 0, nCellCount * sizeof(bool));
586 :
587 65 : const size_t nCount = _pView->aEntries.size();
588 304 : for( size_t nCur=0; nCur < nCount; nCur++ )
589 239 : OccupyGrids( _pView->aEntries[ nCur ] );
590 : }
591 :
592 347 : void IcnGridMap_Impl::GetMinMapSize( sal_uInt16& rDX, sal_uInt16& rDY ) const
593 : {
594 : long nX, nY;
595 347 : if( _pView->nWinBits & WB_ALIGN_TOP )
596 : {
597 : // The view grows in vertical direction. Its max. width is _pView->nMaxVirtWidth
598 0 : nX = _pView->nMaxVirtWidth;
599 0 : if( !nX )
600 0 : nX = _pView->pView->GetOutputSizePixel().Width();
601 0 : if( !(_pView->nFlags & F_ARRANGING) )
602 0 : nX -= _pView->nVerSBarWidth;
603 :
604 0 : nY = _pView->aVirtOutputSize.Height();
605 : }
606 : else
607 : {
608 : // The view grows in horizontal direction. Its max. height is _pView->nMaxVirtHeight
609 347 : nY = _pView->nMaxVirtHeight;
610 347 : if( !nY )
611 0 : nY = _pView->pView->GetOutputSizePixel().Height();
612 347 : if( !(_pView->nFlags & F_ARRANGING) )
613 57 : nY -= _pView->nHorSBarHeight;
614 347 : nX = _pView->aVirtOutputSize.Width();
615 : }
616 :
617 347 : if( !nX )
618 65 : nX = DEFAULT_MAX_VIRT_WIDTH;
619 347 : if( !nY )
620 0 : nY = DEFAULT_MAX_VIRT_HEIGHT;
621 :
622 347 : long nDX = nX / _pView->nGridDX;
623 347 : long nDY = nY / _pView->nGridDY;
624 :
625 347 : if( !nDX )
626 0 : nDX++;
627 347 : if( !nDY )
628 0 : nDY++;
629 :
630 347 : rDX = (sal_uInt16)nDX;
631 347 : rDY = (sal_uInt16)nDY;
632 347 : }
633 :
634 288 : GridId IcnGridMap_Impl::GetGrid( sal_uInt16 nGridX, sal_uInt16 nGridY )
635 : {
636 288 : Create();
637 288 : if( _pView->nWinBits & WB_ALIGN_TOP )
638 0 : return nGridX + ( static_cast<GridId>(nGridY) * _nGridCols );
639 : else
640 288 : return nGridY + ( static_cast<GridId>(nGridX) * _nGridRows );
641 : }
642 :
643 288 : GridId IcnGridMap_Impl::GetGrid( const Point& rDocPos, bool* pbClipped )
644 : {
645 288 : Create();
646 :
647 288 : long nX = rDocPos.X();
648 288 : long nY = rDocPos.Y();
649 288 : nX -= LROFFS_WINBORDER;
650 288 : nY -= TBOFFS_WINBORDER;
651 288 : nX /= _pView->nGridDX;
652 288 : nY /= _pView->nGridDY;
653 288 : bool bClipped = false;
654 288 : if( nX >= _nGridCols )
655 : {
656 0 : nX = _nGridCols - 1;
657 0 : bClipped = true;
658 : }
659 288 : if( nY >= _nGridRows )
660 : {
661 0 : nY = _nGridRows - 1;
662 0 : bClipped = true;
663 : }
664 288 : GridId nId = GetGrid( (sal_uInt16)nX, (sal_uInt16)nY );
665 288 : if( pbClipped )
666 0 : *pbClipped = bClipped;
667 : DBG_ASSERT(nId <(sal_uLong)(_nGridCols*_nGridRows),"GetGrid failed");
668 288 : return nId;
669 : }
670 :
671 260 : Rectangle IcnGridMap_Impl::GetGridRect( GridId nId )
672 : {
673 260 : Create();
674 : sal_uInt16 nGridX, nGridY;
675 260 : GetGridCoord( nId, nGridX, nGridY );
676 260 : const long nLeft = nGridX * _pView->nGridDX+ LROFFS_WINBORDER;
677 260 : const long nTop = nGridY * _pView->nGridDY + TBOFFS_WINBORDER;
678 : return Rectangle(
679 : nLeft, nTop,
680 : nLeft + _pView->nGridDX,
681 260 : nTop + _pView->nGridDY );
682 : }
683 :
684 260 : GridId IcnGridMap_Impl::GetUnoccupiedGrid( bool bOccupyFound )
685 : {
686 260 : Create();
687 260 : sal_uLong nStart = 0;
688 260 : bool bExpanded = false;
689 :
690 : while( true )
691 : {
692 260 : const sal_uLong nCount = (sal_uInt16)(_nGridCols * _nGridRows);
693 650 : for( sal_uLong nCur = nStart; nCur < nCount; nCur++ )
694 : {
695 650 : if( !_pGridMap[ nCur ] )
696 : {
697 260 : if( bOccupyFound )
698 260 : _pGridMap[ nCur ] = true;
699 260 : return (GridId)nCur;
700 : }
701 : }
702 : DBG_ASSERT(!bExpanded,"ExpandGrid failed");
703 0 : if( bExpanded )
704 0 : return 0; // prevent never ending loop
705 0 : bExpanded = true;
706 0 : Expand();
707 0 : nStart = nCount;
708 0 : }
709 : }
710 :
711 : // An entry only means that there's a GridRect lying under its center. This
712 : // variant is much faster than allocating via the bounding rectangle but can
713 : // lead to small overlaps.
714 527 : void IcnGridMap_Impl::OccupyGrids( const SvxIconChoiceCtrlEntry* pEntry, bool bOccupy )
715 : {
716 527 : if( !_pGridMap || !SvxIconChoiceCtrl_Impl::IsBoundingRectValid( pEntry->aRect ))
717 766 : return;
718 288 : OccupyGrid( GetGrid( pEntry->aRect.Center()), bOccupy );
719 : }
720 :
721 63 : void IcnGridMap_Impl::Clear()
722 : {
723 63 : if( _pGridMap )
724 : {
725 63 : delete[] _pGridMap, _pGridMap=0;
726 63 : _nGridRows = 0;
727 63 : _nGridCols = 0;
728 63 : _aLastOccupiedGrid.SetEmpty();
729 : }
730 63 : }
731 :
732 0 : sal_uLong IcnGridMap_Impl::GetGridCount( const Size& rSizePixel, sal_uInt16 nDX, sal_uInt16 nDY)
733 : {
734 0 : long ndx = (rSizePixel.Width() - LROFFS_WINBORDER) / nDX;
735 0 : if( ndx < 0 ) ndx *= -1;
736 0 : long ndy = (rSizePixel.Height() - TBOFFS_WINBORDER) / nDY;
737 0 : if( ndy < 0 ) ndy *= -1;
738 0 : return (sal_uLong)(ndx * ndy);
739 : }
740 :
741 282 : void IcnGridMap_Impl::OutputSizeChanged()
742 : {
743 282 : if( _pGridMap )
744 : {
745 : sal_uInt16 nCols, nRows;
746 282 : GetMinMapSize( nCols, nRows );
747 282 : if( _pView->nWinBits & WB_ALIGN_TOP )
748 : {
749 0 : if( nCols != _nGridCols )
750 0 : Clear();
751 0 : else if( nRows >= _nGridRows )
752 0 : Expand();
753 : }
754 : else
755 : {
756 282 : if( nRows != _nGridRows )
757 0 : Clear();
758 282 : else if( nCols >= _nGridCols )
759 0 : Expand();
760 : }
761 : }
762 282 : }
763 :
764 : // Independently of the view's alignment (TOP or LEFT), the gridmap
765 : // should contain the data in a continuous region, to make it possible
766 : // to copy the whole block if the gridmap needs to be expanded.
767 260 : void IcnGridMap_Impl::GetGridCoord( GridId nId, sal_uInt16& rGridX, sal_uInt16& rGridY )
768 : {
769 260 : Create();
770 260 : if( _pView->nWinBits & WB_ALIGN_TOP )
771 : {
772 0 : rGridX = (sal_uInt16)(nId % _nGridCols);
773 0 : rGridY = (sal_uInt16)(nId / _nGridCols);
774 : }
775 : else
776 : {
777 260 : rGridX = (sal_uInt16)(nId / _nGridRows);
778 260 : rGridY = (sal_uInt16)(nId % _nGridRows);
779 : }
780 260 : }
781 :
782 :
783 :
784 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|