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