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