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 31 #include <limits.h> 32 #ifndef _METRIC_HXX 33 #include <vcl/metric.hxx> 34 #endif 35 #include <vcl/svapp.hxx> 36 #ifdef DBG_UTIL 37 #include <vcl/sound.hxx> 38 #endif 39 40 #include <svtools/svlbox.hxx> 41 #include <svtools/svicnvw.hxx> 42 #include <svimpicn.hxx> 43 #ifndef _SVLBITM_HXX 44 #include <svtools/svlbitm.hxx> 45 #endif 46 #include <svl/svarray.hxx> 47 48 49 50 #define VIEWMODE_ICON 0x0001 // Text unter Bitmap 51 #define VIEWMODE_NAME 0x0002 // Text rechts neben Bitmap 52 #define VIEWMODE_TEXT 0x0004 // Text ohne Bitmap 53 54 #define DD_SCROLL_PIXEL 10 55 56 // alle Angaben in Pixel 57 58 #define ICONVIEW_OFFS_BMP_STRING 3 59 60 // fuer das Bounding-Rectangle 61 #define LROFFS_BOUND 2 62 #define TBOFFS_BOUND 2 63 64 // fuer das Focus-Rectangle um Icons 65 #define LROFFS_ICON 2 66 #define TBOFFS_ICON 2 67 68 #define NAMEVIEW_OFFS_BMP_STRING 3 69 70 // Abstaende von Fensterraendern 71 #define LROFFS_WINBORDER 4 72 #define TBOFFS_WINBORDER 4 73 74 // Breitenoffset Highlight-Rect bei Text 75 #define LROFFS_TEXT 2 76 77 78 #define ICNVIEWDATA(xPtr) (SvIcnVwDataEntry*)(pView->GetViewDataEntry(xPtr)) 79 #define ICNVIEWDATA2(xPtr) (SvIcnVwDataEntry*)(pView->pView->GetViewDataEntry(xPtr)) 80 81 //-------------------------------------------------------------------------- 82 //-------------------------------------------------------------------------- 83 //-------------------------------------------------------------------------- 84 // ------------------------------------------------------------------------- 85 // Hilfsfunktionen von Thomas Hosemann zur mehrzeiligen Ausgabe von 86 // Strings. Die Funktionen werden spaeter in StarView integriert. 87 // ------------------------------------------------------------------------- 88 //-------------------------------------------------------------------------- 89 //-------------------------------------------------------------------------- 90 //-------------------------------------------------------------------------- 91 92 // keine doppelten Defines 93 #ifdef TEXT_DRAW_CLIP 94 #undef TEXT_DRAW_CLIP 95 #endif 96 #ifdef TEXT_DRAW_MULTILINE 97 #undef TEXT_DRAW_MULTILINE 98 #endif 99 #ifdef TEXT_DRAW_WORDBREAK 100 #undef TEXT_DRAW_WORDBREAK 101 #endif 102 103 // #define TEXT_DRAW_DISABLE ((sal_uInt16)0x0001) 104 // #define TEXT_DRAW_3DLOOK ((sal_uInt16)0x0002) 105 // #define TEXT_DRAW_MNEMONIC ((sal_uInt16)0x0004) 106 #define TEXT_DRAW_LEFT ((sal_uInt16)0x0010) 107 #define TEXT_DRAW_CENTER ((sal_uInt16)0x0020) 108 #define TEXT_DRAW_RIGHT ((sal_uInt16)0x0040) 109 #define TEXT_DRAW_TOP ((sal_uInt16)0x0080) 110 #define TEXT_DRAW_VCENTER ((sal_uInt16)0x0100) 111 #define TEXT_DRAW_BOTTOM ((sal_uInt16)0x0200) 112 #define TEXT_DRAW_ENDELLIPSIS ((sal_uInt16)0x0400) 113 #define TEXT_DRAW_PATHELLIPSIS ((sal_uInt16)0x0800) 114 #define TEXT_DRAW_CLIP ((sal_uInt16)0x1000) 115 #define TEXT_DRAW_MULTILINE ((sal_uInt16)0x2000) 116 #define TEXT_DRAW_WORDBREAK ((sal_uInt16)0x4000) 117 118 XubString GetEllipsisString( OutputDevice* pDev, 119 const XubString& rStr, long nMaxWidth, 120 sal_uInt16 nStyle = TEXT_DRAW_ENDELLIPSIS ) 121 { 122 XubString aStr = rStr; 123 124 if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) 125 { 126 sal_uInt16 nIndex = pDev->GetTextBreak( rStr, nMaxWidth ); 127 if ( nIndex != STRING_LEN ) 128 { 129 aStr.Erase( nIndex ); 130 if ( nIndex > 1 ) 131 { 132 aStr.AppendAscii("..."); 133 while ( aStr.Len() && 134 (pDev->GetTextWidth( aStr ) > nMaxWidth) ) 135 { 136 if ( (nIndex > 1) || (nIndex == aStr.Len()) ) 137 nIndex--; 138 aStr.Erase( nIndex, 1 ); 139 } 140 } 141 142 if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) ) 143 aStr += rStr.GetChar( 0 ); 144 } 145 } 146 147 return aStr; 148 } 149 150 class TextLineInfo 151 { 152 private: 153 long mnWidth; 154 sal_uInt16 mnIndex; 155 sal_uInt16 mnLen; 156 157 public: 158 TextLineInfo( long nWidth, sal_uInt16 nIndex, sal_uInt16 nLen ) 159 { 160 mnWidth = nWidth; 161 mnIndex = nIndex; 162 mnLen = nLen; 163 } 164 165 long GetWidth() const { return mnWidth; } 166 sal_uInt16 GetIndex() const { return mnIndex; } 167 sal_uInt16 GetLen() const { return mnLen; } 168 }; 169 170 #define MULTITEXTLINEINFO_RESIZE 16 171 typedef TextLineInfo* PTextLineInfo; 172 173 class MultiTextLineInfo 174 { 175 private: 176 PTextLineInfo* mpLines; 177 sal_uInt16 mnLines; 178 sal_uInt16 mnSize; 179 180 public: 181 MultiTextLineInfo(); 182 ~MultiTextLineInfo(); 183 184 void AddLine( TextLineInfo* pLine ); 185 void Clear(); 186 187 TextLineInfo* GetLine( sal_uInt16 nLine ) const 188 { return mpLines[nLine]; } 189 sal_uInt16 Count() const { return mnLines; } 190 191 private: 192 MultiTextLineInfo( const MultiTextLineInfo& ); 193 MultiTextLineInfo& operator=( const MultiTextLineInfo& ); 194 }; 195 196 MultiTextLineInfo::MultiTextLineInfo() 197 { 198 mpLines = new PTextLineInfo[MULTITEXTLINEINFO_RESIZE]; 199 mnLines = 0; 200 mnSize = MULTITEXTLINEINFO_RESIZE; 201 } 202 203 MultiTextLineInfo::~MultiTextLineInfo() 204 { 205 for ( sal_uInt16 i = 0; i < mnLines; i++ ) 206 delete mpLines[i]; 207 delete [] mpLines; 208 } 209 210 void MultiTextLineInfo::AddLine( TextLineInfo* pLine ) 211 { 212 if ( mnSize == mnLines ) 213 { 214 mnSize += MULTITEXTLINEINFO_RESIZE; 215 PTextLineInfo* pNewLines = new PTextLineInfo[mnSize]; 216 memcpy( pNewLines, mpLines, mnLines*sizeof(PTextLineInfo) ); 217 mpLines = pNewLines; 218 } 219 220 mpLines[mnLines] = pLine; 221 mnLines++; 222 } 223 224 void MultiTextLineInfo::Clear() 225 { 226 for ( sal_uInt16 i = 0; i < mnLines; i++ ) 227 delete mpLines[i]; 228 mnLines = 0; 229 } 230 231 // ----------------------------------------------------------------------- 232 233 long GetTextLines( OutputDevice* pDev, MultiTextLineInfo& rLineInfo, 234 long nWidth, const XubString& rStr, 235 sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK ) 236 { 237 rLineInfo.Clear(); 238 if ( !rStr.Len() ) 239 return 0; 240 if ( nWidth <= 0 ) 241 nWidth = 1; 242 243 sal_uInt16 nStartPos = 0; // Start-Position der Zeile 244 sal_uInt16 nLastLineLen = 0; // Zeilenlaenge bis zum vorherigen Wort 245 sal_uInt16 nLastWordPos = 0; // Position des letzten Wortanfangs 246 sal_uInt16 i = 0; 247 sal_uInt16 nPos; // StartPositon der Zeile (nur Temp) 248 sal_uInt16 nLen; // Laenge der Zeile (nur Temp) 249 sal_uInt16 nStrLen = rStr.Len(); 250 long nMaxLineWidth = 0; // Maximale Zeilenlaenge 251 long nLineWidth; // Aktuelle Zeilenlaenge 252 long nLastLineWidth = 0; // Zeilenlaenge der letzten Zeile 253 xub_Unicode c; 254 xub_Unicode c2; 255 const xub_Unicode* pStr = rStr.GetBuffer(); 256 sal_Bool bHardBreak = sal_False; 257 258 do 259 { 260 c = pStr[i]; 261 262 // Auf Zeilenende ermitteln 263 if ( (c == _CR) || (c == _LF) ) 264 bHardBreak = sal_True; 265 else 266 bHardBreak = sal_False; 267 268 // Testen, ob ein Wortende erreicht ist 269 if ( bHardBreak || (i == nStrLen) || 270 (((c == ' ') || (c == '-')) && (nStyle & TEXT_DRAW_WORDBREAK)) ) 271 { 272 nLen = i-nStartPos; 273 if ( c == '-' ) 274 nLen++; 275 nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLen ); 276 277 // Findet ein Zeilenumbruch statt 278 if ( bHardBreak || (i == nStrLen) || 279 ((nLineWidth >= nWidth) && (nStyle & TEXT_DRAW_WORDBREAK)) ) 280 { 281 nPos = nStartPos; 282 283 if ( (nLineWidth >= nWidth) && (nStyle & TEXT_DRAW_WORDBREAK) ) 284 { 285 nLineWidth = nLastLineWidth; 286 nLen = nLastLineLen; 287 nStartPos = nLastWordPos; 288 nLastLineLen = i-nStartPos; 289 nLastWordPos = nStartPos+nLastLineLen+1; 290 if ( c == '-' ) 291 nLastLineLen++; 292 else if ( bHardBreak && (i > nStartPos) ) 293 i--; 294 } 295 else 296 { 297 nStartPos = i; 298 // Zeilenende-Zeichen und '-' beruecksichtigen 299 if ( bHardBreak ) 300 { 301 nStartPos++; 302 c2 = pStr[i+1]; 303 if ( (c != c2) && ((c2 == _CR) || (c2 == _LF)) ) 304 { 305 nStartPos++; 306 i++; 307 } 308 } 309 else if ( c != '-' ) 310 nStartPos++; 311 nLastWordPos = nStartPos; 312 nLastLineLen = 0; 313 } 314 315 if ( nLineWidth > nMaxLineWidth ) 316 nMaxLineWidth = nLineWidth; 317 318 if ( nLen || bHardBreak ) 319 rLineInfo.AddLine( new TextLineInfo( nLineWidth, nPos, nLen ) ); 320 321 // Testen, ob aktuelles Wort noch auf die Zeile passt, 322 // denn ansonsten mueessen wir es auftrennen 323 if ( nLastLineLen ) 324 { 325 nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLastLineLen ); 326 if ( nLineWidth > nWidth ) 327 { 328 // Wenn ein Wortumbruch in einem Wort stattfindet, 329 // ist die maximale Zeilenlaenge die Laenge 330 // des laengsten Wortes 331 if ( nLineWidth > nMaxLineWidth ) 332 nMaxLineWidth = nLineWidth; 333 334 // Solange Wort auftrennen, bis es auf eine Zeile passt 335 do 336 { 337 nPos = pDev->GetTextBreak( rStr, nWidth, nStartPos, nLastLineLen ); 338 nLen = nPos-nStartPos; 339 if ( !nLen ) 340 { 341 nPos++; 342 nLen++; 343 } 344 nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLen ); 345 rLineInfo.AddLine( new TextLineInfo( nLineWidth, nStartPos, nLen ) ); 346 nStartPos = nPos; 347 nLastLineLen = nLastLineLen - nLen; 348 nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLastLineLen ); 349 } 350 while ( nLineWidth > nWidth ); 351 } 352 nLastLineWidth = nLineWidth; 353 354 // Bei Stringende muessen wir die letzte Zeile auch noch 355 // dranhaengen 356 if ( (i == nStrLen) && nLastLineLen ) 357 rLineInfo.AddLine( new TextLineInfo( nLastLineWidth, nStartPos, nLastLineLen ) ); 358 } 359 else 360 nLastLineWidth = 0; 361 } 362 else 363 { 364 nLastLineWidth = nLineWidth; 365 nLastLineLen = nLen; 366 nLastWordPos = nStartPos+nLastLineLen; 367 if ( c != '-' ) 368 nLastWordPos++; 369 } 370 } 371 372 i++; 373 } 374 while ( i <= nStrLen ); 375 376 return nMaxLineWidth; 377 } 378 379 // ----------------------------------------------------------------------- 380 381 sal_uInt16 GetTextLines( OutputDevice* pDev, const Rectangle& rRect, 382 const XubString& rStr, 383 sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK, 384 long* pMaxWidth = NULL ) 385 { 386 MultiTextLineInfo aMultiLineInfo; 387 long nMaxWidth = GetTextLines( pDev, aMultiLineInfo, 388 rRect.GetWidth(), rStr, nStyle ); 389 if ( pMaxWidth ) 390 *pMaxWidth = nMaxWidth; 391 return aMultiLineInfo.Count(); 392 } 393 394 // ----------------------------------------------------------------------- 395 396 Rectangle GetTextRect( OutputDevice* pDev, const Rectangle& rRect, 397 const XubString& rStr, 398 sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK ) 399 { 400 Rectangle aRect = rRect; 401 sal_uInt16 nLines; 402 long nWidth = rRect.GetWidth(); 403 long nMaxWidth; 404 long nTextHeight; 405 406 if ( nStyle & TEXT_DRAW_MULTILINE ) 407 { 408 MultiTextLineInfo aMultiLineInfo; 409 TextLineInfo* pLineInfo; 410 sal_uInt16 nFormatLines; 411 412 nMaxWidth = 0; 413 GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle ); 414 nFormatLines = aMultiLineInfo.Count(); 415 nTextHeight = pDev->GetTextHeight(); 416 nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight); 417 if ( nFormatLines <= nLines ) 418 nLines = nFormatLines; 419 else 420 { 421 if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) ) 422 nLines = nFormatLines; 423 else 424 nMaxWidth = nWidth; 425 } 426 for ( sal_uInt16 i = 0; i < nLines; i++ ) 427 { 428 pLineInfo = aMultiLineInfo.GetLine( i ); 429 if ( pLineInfo->GetWidth() > nMaxWidth ) 430 nMaxWidth = pLineInfo->GetWidth(); 431 } 432 } 433 else 434 { 435 nLines = 1; 436 nMaxWidth = pDev->GetTextWidth( rStr ); 437 nTextHeight = pDev->GetTextHeight(); 438 if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ENDELLIPSIS) ) 439 nMaxWidth = nWidth; 440 } 441 442 if ( nStyle & TEXT_DRAW_RIGHT ) 443 aRect.Left() = aRect.Right()-nMaxWidth+1; 444 else if ( nStyle & TEXT_DRAW_CENTER ) 445 { 446 aRect.Left() += (nWidth-nMaxWidth)/2; 447 aRect.Right() = aRect.Left()+nMaxWidth-1; 448 } 449 else 450 aRect.Right() = aRect.Left()+nMaxWidth-1; 451 452 if ( nStyle & TEXT_DRAW_BOTTOM ) 453 aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1; 454 else if ( nStyle & TEXT_DRAW_VCENTER ) 455 { 456 aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2; 457 aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1; 458 } 459 else 460 aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1; 461 462 return aRect; 463 } 464 465 // ----------------------------------------------------------------------- 466 467 void DrawText( OutputDevice* pDev, const Rectangle& rRect, 468 const XubString& rStr, sal_uInt16 nStyle = 0 ) 469 { 470 if ( !rStr.Len() || rRect.IsEmpty() ) 471 return; 472 473 Point aPos = rRect.TopLeft(); 474 long nWidth = rRect.GetWidth(); 475 long nHeight = rRect.GetHeight(); 476 FontAlign eAlign = pDev->GetFont().GetAlign(); 477 478 if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) ) 479 return; 480 481 // Mehrzeiligen Text behandeln wir anders 482 if ( nStyle & TEXT_DRAW_MULTILINE ) 483 { 484 String aLastLine; 485 Region aOldRegion; 486 MultiTextLineInfo aMultiLineInfo; 487 TextLineInfo* pLineInfo; 488 long nTextHeight = pDev->GetTextHeight(); 489 long nMaxTextWidth; 490 sal_uInt16 i; 491 sal_uInt16 nLines = (sal_uInt16)(nHeight/nTextHeight); 492 sal_uInt16 nFormatLines; 493 sal_Bool bIsClipRegion = sal_False; 494 nMaxTextWidth = GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle ); 495 496 nFormatLines = aMultiLineInfo.Count(); 497 if ( nFormatLines > nLines ) 498 { 499 if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) 500 { 501 // Letzte Zeile zusammenbauen und kuerzen 502 nFormatLines = nLines-1; 503 pLineInfo = aMultiLineInfo.GetLine( nFormatLines ); 504 aLastLine = rStr.Copy( pLineInfo->GetIndex() ); 505 aLastLine.ConvertLineEnd( LINEEND_LF ); 506 aLastLine.SearchAndReplace( _LF, ' ' ); 507 aLastLine = GetEllipsisString( pDev, aLastLine, nWidth, nStyle ); 508 nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM); 509 nStyle |= TEXT_DRAW_TOP; 510 } 511 } 512 else 513 { 514 if ( nMaxTextWidth <= nWidth ) 515 nStyle &= ~TEXT_DRAW_CLIP; 516 } 517 518 // Clipping setzen 519 if ( nStyle & TEXT_DRAW_CLIP ) 520 { 521 bIsClipRegion = pDev->IsClipRegion(); 522 if ( bIsClipRegion ) 523 { 524 aOldRegion = pDev->GetClipRegion(); 525 pDev->IntersectClipRegion( rRect ); 526 } 527 else 528 { 529 Region aRegion( rRect ); 530 pDev->SetClipRegion( aRegion ); 531 } 532 } 533 534 // Vertikales Alignment 535 if ( nStyle & TEXT_DRAW_BOTTOM ) 536 aPos.Y() += nHeight-(nFormatLines*nTextHeight); 537 else if ( nStyle & TEXT_DRAW_VCENTER ) 538 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2; 539 540 // Font Alignment 541 if ( eAlign == ALIGN_BOTTOM ) 542 aPos.Y() += nTextHeight; 543 else if ( eAlign == ALIGN_BASELINE ) 544 aPos.Y() += pDev->GetFontMetric().GetAscent(); 545 546 // Alle Zeilen ausgeben, bis auf die letzte 547 for ( i = 0; i < nFormatLines; i++ ) 548 { 549 pLineInfo = aMultiLineInfo.GetLine( i ); 550 if ( nStyle & TEXT_DRAW_RIGHT ) 551 aPos.X() += nWidth-pLineInfo->GetWidth(); 552 else if ( nStyle & TEXT_DRAW_CENTER ) 553 aPos.X() += (nWidth-pLineInfo->GetWidth())/2; 554 pDev->DrawText( aPos, rStr, pLineInfo->GetIndex(), pLineInfo->GetLen() ); 555 aPos.Y() += nTextHeight; 556 aPos.X() = rRect.Left(); 557 } 558 559 // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben, 560 // da die Zeile gekuerzt wurde 561 if ( aLastLine.Len() ) 562 pDev->DrawText( aPos, aLastLine ); 563 564 // Clipping zuruecksetzen 565 if ( nStyle & TEXT_DRAW_CLIP ) 566 { 567 if ( bIsClipRegion ) 568 pDev->SetClipRegion( aOldRegion ); 569 else 570 pDev->SetClipRegion(); 571 } 572 } 573 else 574 { 575 XubString aStr = rStr; 576 Size aTextSize(pDev->GetTextWidth( aStr ), pDev->GetTextHeight()); 577 578 // Evt. Text kuerzen 579 if ( aTextSize.Width() > nWidth ) 580 { 581 if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) 582 { 583 aStr = GetEllipsisString( pDev, rStr, nWidth, nStyle ); 584 nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT); 585 nStyle |= TEXT_DRAW_LEFT; 586 aTextSize.Width() = pDev->GetTextWidth(aStr); 587 } 588 } 589 else 590 { 591 if ( aTextSize.Height() <= nHeight ) 592 nStyle &= ~TEXT_DRAW_CLIP; 593 } 594 595 // Vertikales Alignment 596 if ( nStyle & TEXT_DRAW_RIGHT ) 597 aPos.X() += nWidth-aTextSize.Width(); 598 else if ( nStyle & TEXT_DRAW_CENTER ) 599 aPos.X() += (nWidth-aTextSize.Width())/2; 600 601 // Font Alignment 602 if ( eAlign == ALIGN_BOTTOM ) 603 aPos.Y() += aTextSize.Height(); 604 else if ( eAlign == ALIGN_BASELINE ) 605 aPos.Y() += pDev->GetFontMetric().GetAscent(); 606 607 if ( nStyle & TEXT_DRAW_BOTTOM ) 608 aPos.Y() += nHeight-aTextSize.Height(); 609 else if ( nStyle & TEXT_DRAW_VCENTER ) 610 aPos.Y() += (nHeight-aTextSize.Height())/2; 611 612 if ( nStyle & TEXT_DRAW_CLIP ) 613 { 614 sal_Bool bIsClipRegion = pDev->IsClipRegion(); 615 if ( bIsClipRegion ) 616 { 617 Region aOldRegion = pDev->GetClipRegion(); 618 pDev->IntersectClipRegion( rRect ); 619 pDev->DrawText( aPos, aStr ); 620 pDev->SetClipRegion( aOldRegion ); 621 } 622 else 623 { 624 Region aRegion( rRect ); 625 pDev->SetClipRegion( aRegion ); 626 pDev->DrawText( aPos, aStr ); 627 pDev->SetClipRegion(); 628 } 629 } 630 else 631 pDev->DrawText( aPos, aStr ); 632 } 633 } 634 635 // ----------------------------------------------------------------------- 636 637 638 //-------------------------------------------------------------------------- 639 //-------------------------------------------------------------------------- 640 //-------------------------------------------------------------------------- 641 642 643 #define DRAWTEXT_FLAGS (TEXT_DRAW_CENTER|TEXT_DRAW_TOP|TEXT_DRAW_ENDELLIPSIS|\ 644 TEXT_DRAW_CLIP|TEXT_DRAW_MULTILINE|TEXT_DRAW_WORDBREAK) 645 646 647 class ImpIcnCursor 648 { 649 SvImpIconView* pView; 650 SvPtrarr* pColumns; 651 SvPtrarr* pRows; 652 sal_Bool* pGridMap; 653 long nGridDX, nGridDY; 654 long nGridCols, nGridRows; 655 long nCols; 656 long nRows; 657 short nDeltaWidth; 658 short nDeltaHeight; 659 SvLBoxEntry* pCurEntry; 660 void SetDeltas(); 661 void ImplCreate(); 662 void Create() { if( !pColumns ) ImplCreate(); } 663 664 sal_uInt16 GetSortListPos( SvPtrarr* pList, long nValue, int bVertical); 665 SvLBoxEntry* SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom,sal_uInt16 nPref, 666 sal_Bool bDown, sal_Bool bSimple ); 667 SvLBoxEntry* SearchRow(sal_uInt16 nRow,sal_uInt16 nRight,sal_uInt16 nLeft,sal_uInt16 nPref, 668 sal_Bool bRight, sal_Bool bSimple ); 669 670 void ExpandGrid(); 671 void CreateGridMap(); 672 // Rueckgabe sal_False: Eintrag liegt nicht in der GridMap. rGridx,y werden 673 // dann an nGridCols, nGridRows geclippt 674 sal_Bool GetGrid( const Point& rDocPos, sal_uInt16& rGridX, sal_uInt16& rGridY ) const; 675 void SetGridUsed( sal_uInt16 nDX, sal_uInt16 nDY, sal_Bool bUsed ) 676 { 677 pGridMap[ (nDY * nGridCols) + nDX ] = bUsed; 678 } 679 sal_Bool IsGridUsed( sal_uInt16 nDX, sal_uInt16 nDY ) 680 { 681 return pGridMap[ (nDY * nGridCols) + nDX ]; 682 } 683 public: 684 ImpIcnCursor( SvImpIconView* pOwner ); 685 ~ImpIcnCursor(); 686 void Clear( sal_Bool bGridToo = sal_True ); 687 688 // fuer Cursortravelling usw. 689 SvLBoxEntry* GoLeftRight( SvLBoxEntry*, sal_Bool bRight ); 690 SvLBoxEntry* GoUpDown( SvLBoxEntry*, sal_Bool bDown ); 691 692 // Rueckgaebe: sal_False == Das leere Rect steht hinter dem letzten 693 // Eintrag; d.h. beim naechsten Einfuegen ergibt sich das naechste 694 // leere Rechteck durch Addition. Hinweis: Das Rechteck kann dann 695 // ausserhalb des View-Space liegen 696 sal_Bool FindEmptyGridRect( Rectangle& rRect ); 697 698 // Erzeugt fuer jede Zeile (Hoehe=nGridDY) eine nach BoundRect.Left() 699 // sortierte Liste der Eintraege, die in ihr stehen. Eine Liste kann 700 // leer sein. Die Listen gehen in das Eigentum des Rufenden ueber und 701 // muessen mit DestroyGridAdjustData geloescht werden 702 void CreateGridAjustData( SvPtrarr& pLists, SvLBoxEntry* pRow=0); 703 static void DestroyGridAdjustData( SvPtrarr& rLists ); 704 void SetGridUsed( const Rectangle&, sal_Bool bUsed = sal_True ); 705 }; 706 707 708 709 710 SvImpIconView::SvImpIconView( SvIconView* pCurView, SvLBoxTreeList* pTree, 711 WinBits i_nWinStyle ) : 712 aVerSBar( pCurView, WB_DRAG | WB_VSCROLL ), 713 aHorSBar( pCurView, WB_DRAG | WB_HSCROLL ) 714 { 715 pView = pCurView; 716 pModel = pTree; 717 pCurParent = 0; 718 pZOrderList = new SvPtrarr; 719 SetStyle( i_nWinStyle ); 720 nHorDist = 0; 721 nVerDist = 0; 722 nFlags = 0; 723 nCurUserEvent = 0; 724 nMaxVirtWidth = 200; 725 pDDRefEntry = 0; 726 pDDDev = 0; 727 pDDBufDev = 0; 728 pDDTempDev = 0; 729 eTextMode = ShowTextShort; 730 pImpCursor = new ImpIcnCursor( this ); 731 732 aVerSBar.SetScrollHdl( LINK( this, SvImpIconView, ScrollUpDownHdl ) ); 733 aHorSBar.SetScrollHdl( LINK( this, SvImpIconView, ScrollLeftRightHdl ) ); 734 nHorSBarHeight = aHorSBar.GetSizePixel().Height(); 735 nVerSBarWidth = aVerSBar.GetSizePixel().Width(); 736 737 aMouseMoveTimer.SetTimeout( 20 ); 738 aMouseMoveTimer.SetTimeoutHdl(LINK(this,SvImpIconView,MouseMoveTimeoutHdl)); 739 740 aEditTimer.SetTimeout( 800 ); 741 aEditTimer.SetTimeoutHdl(LINK(this,SvImpIconView,EditTimeoutHdl)); 742 743 Clear( sal_True ); 744 } 745 746 SvImpIconView::~SvImpIconView() 747 { 748 StopEditTimer(); 749 CancelUserEvent(); 750 delete pZOrderList; 751 delete pImpCursor; 752 delete pDDDev; 753 delete pDDBufDev; 754 delete pDDTempDev; 755 ClearSelectedRectList(); 756 } 757 758 void SvImpIconView::Clear( sal_Bool bInCtor ) 759 { 760 StopEditTimer(); 761 CancelUserEvent(); 762 nMaxBmpWidth = 0; 763 nMaxBmpHeight = 0; 764 nMaxTextWidth = 0; 765 bMustRecalcBoundingRects = sal_False; 766 nMaxBoundHeight = 0; 767 768 //XXX 769 nFlags |= F_GRID_INSERT; 770 nFlags &= ~F_PAINTED; 771 SetNextEntryPos( Point( LROFFS_WINBORDER, TBOFFS_WINBORDER ) ); 772 pCursor = 0; 773 if( !bInCtor ) 774 { 775 pImpCursor->Clear(); 776 aVirtOutputSize.Width() = 0; 777 aVirtOutputSize.Height() = 0; 778 pZOrderList->Remove(0,pZOrderList->Count()); 779 MapMode aMapMode( pView->GetMapMode()); 780 aMapMode.SetOrigin( Point() ); 781 pView->SetMapMode( aMapMode ); 782 if( pView->IsUpdateMode() ) 783 pView->Invalidate(); 784 } 785 AdjustScrollBars(); 786 } 787 788 void SvImpIconView::SetStyle( const WinBits i_nWinStyle ) 789 { 790 nViewMode = VIEWMODE_TEXT; 791 if( i_nWinStyle & WB_NAME ) 792 nViewMode = VIEWMODE_NAME; 793 if( i_nWinStyle & WB_ICON ) 794 nViewMode = VIEWMODE_ICON; 795 } 796 797 798 IMPL_LINK( SvImpIconView, ScrollUpDownHdl, ScrollBar *, pScrollBar ) 799 { 800 pView->EndEditing( sal_True ); 801 // Pfeil hoch: delta=-1; Pfeil runter: delta=+1 802 Scroll( 0, pScrollBar->GetDelta(), sal_True ); 803 return 0; 804 } 805 806 IMPL_LINK( SvImpIconView, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) 807 { 808 pView->EndEditing( sal_True ); 809 // Pfeil links: delta=-1; Pfeil rechts: delta=+1 810 Scroll( pScrollBar->GetDelta(), 0, sal_True ); 811 return 0; 812 } 813 814 void SvImpIconView::ChangedFont() 815 { 816 StopEditTimer(); 817 ImpArrange(); 818 } 819 820 821 void SvImpIconView::CheckAllSizes() 822 { 823 nMaxTextWidth = 0; 824 nMaxBmpWidth = 0; 825 nMaxBmpHeight = 0; 826 SvLBoxEntry* pEntry = pModel->First(); 827 while( pEntry ) 828 { 829 CheckSizes( pEntry ); 830 pEntry = pModel->Next( pEntry ); 831 } 832 } 833 834 void SvImpIconView::CheckSizes( SvLBoxEntry* pEntry, 835 const SvIcnVwDataEntry* pViewData ) 836 { 837 Size aSize; 838 839 if( !pViewData ) 840 pViewData = ICNVIEWDATA(pEntry); 841 842 SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 843 if( pStringItem ) 844 { 845 aSize = GetItemSize( pView, pEntry, pStringItem, pViewData ); 846 if( aSize.Width() > nMaxTextWidth ) 847 { 848 nMaxTextWidth = aSize.Width(); 849 if( !(nFlags & F_GRIDMODE ) ) 850 bMustRecalcBoundingRects = sal_True; 851 } 852 } 853 SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); 854 if( pBmpItem ) 855 { 856 aSize = GetItemSize( pView, pEntry, pBmpItem, pViewData ); 857 if( aSize.Width() > nMaxBmpWidth ) 858 { 859 nMaxBmpWidth = aSize.Width(); 860 nMaxBmpWidth += (2*LROFFS_ICON); 861 if( !(nFlags & F_GRIDMODE ) ) 862 bMustRecalcBoundingRects = sal_True; 863 } 864 if( aSize.Height() > nMaxBmpHeight ) 865 { 866 nMaxBmpHeight = aSize.Height(); 867 nMaxBmpHeight += (2*TBOFFS_ICON);; 868 if( !(nFlags & F_GRIDMODE ) ) 869 bMustRecalcBoundingRects = sal_True; 870 } 871 } 872 } 873 874 void SvImpIconView::EntryInserted( SvLBoxEntry* pEntry ) 875 { 876 if( pModel->GetParent(pEntry) == pCurParent ) 877 { 878 StopEditTimer(); 879 DBG_ASSERT(pZOrderList->GetPos(pEntry)==0xffff,"EntryInserted:ZOrder?"); 880 pZOrderList->Insert( pEntry, pZOrderList->Count() ); 881 if( nFlags & F_GRIDMODE ) 882 pImpCursor->Clear( sal_False ); 883 else 884 pImpCursor->Clear( sal_True ); 885 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 886 CheckSizes( pEntry, pViewData ); 887 if( pView->IsUpdateMode() ) 888 { 889 FindBoundingRect( pEntry, pViewData ); 890 PaintEntry( pEntry, pViewData ); 891 } 892 else 893 InvalidateBoundingRect( pViewData->aRect ); 894 } 895 } 896 897 void SvImpIconView::RemovingEntry( SvLBoxEntry* pEntry ) 898 { 899 if( pModel->GetParent(pEntry) == pCurParent) 900 { 901 StopEditTimer(); 902 DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"RemovingEntry:ZOrder?"); 903 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 904 if( IsBoundingRectValid( pViewData->aRect ) ) 905 { 906 // bei gueltigem Bounding-Rect muss in EntryRemoved eine 907 // Sonderbehandlung erfolgen 908 nFlags |= F_ENTRY_REMOVED; 909 pView->Invalidate( pViewData->aRect ); 910 } 911 if( pEntry == pCursor ) 912 { 913 SvLBoxEntry* pNewCursor = GetNewCursor(); 914 ShowCursor( sal_False ); 915 pCursor = 0; // damit er nicht deselektiert wird 916 SetCursor( pNewCursor ); 917 } 918 sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry ); 919 pZOrderList->Remove( nPos, 1 ); 920 pImpCursor->Clear(); 921 } 922 } 923 924 void SvImpIconView::EntryRemoved() 925 { 926 if( (nFlags & (F_ENTRY_REMOVED | F_PAINTED)) == (F_ENTRY_REMOVED | F_PAINTED)) 927 { 928 // Ein Eintrag mit gueltigem BoundRect wurde geloescht und wir 929 // haben schon mal gepaintet. In diesem Fall muessen wir die 930 // Position des naechsten Eintrags, der eingefuegt wird oder noch 931 // kein gueltiges BoundRect hat, "suchen" d.h. ein "Loch" in 932 // der View auffuellen. 933 nFlags &= ~( F_ENTRY_REMOVED | F_GRID_INSERT ); 934 } 935 } 936 937 938 void SvImpIconView::MovingEntry( SvLBoxEntry* pEntry ) 939 { 940 DBG_ASSERT(pEntry,"MovingEntry: 0!"); 941 pNextCursor = 0; 942 StopEditTimer(); 943 if( pModel->GetParent(pEntry) == pCurParent ) 944 { 945 DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"MovingEntry:ZOrder?"); 946 nFlags |= F_MOVING_SIBLING; 947 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 948 if( IsBoundingRectValid( pViewData->aRect ) ) 949 pView->Invalidate( pViewData->aRect ); 950 // falls Eintrag seinen Parent wechselt vorsichtshalber 951 // die neue Cursorposition berechnen 952 if( pEntry == pCursor ) 953 pNextCursor = GetNewCursor(); 954 pImpCursor->Clear(); 955 } 956 } 957 958 959 void SvImpIconView::EntryMoved( SvLBoxEntry* pEntry ) 960 { 961 ShowCursor( sal_False ); 962 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 963 if( pModel->GetParent(pEntry)==pCurParent ) 964 { 965 if( nFlags & F_MOVING_SIBLING ) 966 { 967 // die Neu-Positionierung eines Eintrags bei D&D innerhalb 968 // einer IconView findet bereits in NotifyMoving statt 969 // (MovingEntry/EntryMoved wird dann nicht mehr gerufen) 970 ToTop( pEntry ); 971 } 972 else 973 { 974 pImpCursor->Clear(); 975 pZOrderList->Insert( pEntry, pZOrderList->Count() ); 976 DBG_ASSERT(pZOrderList->Count()==pModel->GetChildCount(pCurParent),"EntryMoved:Bad zorder count"); 977 FindBoundingRect( pEntry, pViewData ); 978 } 979 PaintEntry( pEntry, pViewData ); 980 } 981 else 982 { 983 if( pEntry == pCursor ) 984 { 985 DBG_ASSERT(pNextCursor,"EntryMoved: Next cursor bad"); 986 SetCursor( pNextCursor ); 987 } 988 pImpCursor->Clear(); 989 sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry ); 990 pZOrderList->Remove( nPos, 1 ); 991 pView->Select( pEntry, sal_False ); 992 // wenn er nochmal in dieser View auftaucht, muss sein 993 // Bounding-Rect neu berechnet werden 994 InvalidateBoundingRect( pViewData->aRect ); 995 } 996 nFlags &= (~F_MOVING_SIBLING); 997 } 998 999 void SvImpIconView::TreeInserted( SvLBoxEntry* pEntry ) 1000 { 1001 EntryMoved( pEntry ); // vorlaeufig 1002 } 1003 1004 void SvImpIconView::EntryExpanded( SvLBoxEntry* ) 1005 { 1006 } 1007 1008 void SvImpIconView::EntryCollapsed( SvLBoxEntry*) 1009 { 1010 } 1011 1012 void SvImpIconView::CollapsingEntry( SvLBoxEntry* ) 1013 { 1014 } 1015 1016 void SvImpIconView::EntrySelected( SvLBoxEntry* pEntry, sal_Bool bSelect ) 1017 { 1018 if( pModel->GetParent(pEntry) != pCurParent ) 1019 return; 1020 1021 // bei SingleSelection dafuer sorgen, dass der Cursor immer 1022 // auf dem (einzigen) selektierten Eintrag steht 1023 if( bSelect && pCursor && 1024 pView->GetSelectionMode() == SINGLE_SELECTION && 1025 pEntry != pCursor ) 1026 { 1027 SetCursor( pEntry ); 1028 DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?"); 1029 } 1030 // bei Gummibandselektion ist uns das zu teuer 1031 if( !(nFlags & F_RUBBERING )) 1032 ToTop( pEntry ); 1033 if( pView->IsUpdateMode() ) 1034 { 1035 if( pEntry == pCursor ) 1036 ShowCursor( sal_False ); 1037 if( nFlags & F_RUBBERING ) 1038 PaintEntry( pEntry ); 1039 else 1040 pView->Invalidate( GetBoundingRect( pEntry ) ); 1041 if( pEntry == pCursor ) 1042 ShowCursor( sal_True ); 1043 } 1044 } 1045 1046 void SvImpIconView::SetNextEntryPos(const Point& rPos) 1047 { 1048 aPrevBoundRect.SetPos( rPos ); 1049 aPrevBoundRect.Right() = LONG_MAX; // dont know 1050 } 1051 1052 Point SvImpIconView::FindNextEntryPos( const Size& rBoundSize ) 1053 { 1054 if( nFlags & F_GRIDMODE ) 1055 { 1056 if( nFlags & F_GRID_INSERT ) 1057 { 1058 if( aPrevBoundRect.Right() != LONG_MAX ) 1059 { 1060 // passt der naechste Entry noch in die Zeile ? 1061 long nNextWidth = aPrevBoundRect.Right() + nGridDX + LROFFS_WINBORDER; 1062 if( nNextWidth > aVirtOutputSize.Width() ) 1063 { 1064 // darf aVirtOutputSize verbreitert werden ? 1065 if( nNextWidth < nMaxVirtWidth ) 1066 { 1067 // verbreitern & in Zeile aufnehmen 1068 aPrevBoundRect.Left() += nGridDX; 1069 } 1070 else 1071 { 1072 // erhoehen & neue Zeile beginnen 1073 aPrevBoundRect.Top() += nGridDY; 1074 aPrevBoundRect.Left() = LROFFS_WINBORDER; 1075 } 1076 } 1077 else 1078 { 1079 // in die Zeile aufnehmen 1080 aPrevBoundRect.Left() += nGridDX; 1081 } 1082 } 1083 aPrevBoundRect.SetSize( Size( nGridDX, nGridDY ) ); 1084 } 1085 else 1086 { 1087 if( !pImpCursor->FindEmptyGridRect( aPrevBoundRect ) ) 1088 { 1089 // mitten in den Entries gibts keine Loecher mehr, 1090 // wir koennen also wieder ins "Fast Insert" springen 1091 nFlags |= F_GRID_INSERT; 1092 } 1093 } 1094 } 1095 else 1096 { 1097 if( aPrevBoundRect.Right() != LONG_MAX ) 1098 { 1099 // passt der naechste Entry noch in die Zeile ? 1100 long nNextWidth=aPrevBoundRect.Right()+rBoundSize.Width()+LROFFS_BOUND+nHorDist; 1101 if( nNextWidth > aVirtOutputSize.Width() ) 1102 { 1103 // darf aVirtOutputSize verbreitert werden ? 1104 if( nNextWidth < nMaxVirtWidth ) 1105 { 1106 // verbreitern & in Zeile aufnehmen 1107 aPrevBoundRect.SetPos( aPrevBoundRect.TopRight() ); 1108 aPrevBoundRect.Left() += nHorDist; 1109 } 1110 else 1111 { 1112 // erhoehen & neue Zeile beginnen 1113 aPrevBoundRect.Top() += nMaxBoundHeight + nVerDist + TBOFFS_BOUND; 1114 aPrevBoundRect.Left() = LROFFS_WINBORDER; 1115 } 1116 } 1117 else 1118 { 1119 // in die Zeile aufnehmen 1120 aPrevBoundRect.SetPos( aPrevBoundRect.TopRight() ); 1121 aPrevBoundRect.Left() += nHorDist; 1122 } 1123 } 1124 aPrevBoundRect.SetSize( rBoundSize ); 1125 } 1126 return aPrevBoundRect.TopLeft(); 1127 } 1128 1129 void SvImpIconView::ResetVirtSize() 1130 { 1131 StopEditTimer(); 1132 aVirtOutputSize.Width() = 0; 1133 aVirtOutputSize.Height() = 0; 1134 sal_Bool bLockedEntryFound = sal_False; 1135 nFlags &= (~F_GRID_INSERT); 1136 SvLBoxEntry* pCur = pModel->FirstChild( pCurParent ); 1137 while( pCur ) 1138 { 1139 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur); 1140 if( pViewData->IsEntryPosLocked() ) 1141 { 1142 // VirtSize u.a. anpassen 1143 if( !IsBoundingRectValid( pViewData->aRect ) ) 1144 FindBoundingRect( pCur, pViewData ); 1145 else 1146 AdjustVirtSize( pViewData->aRect ); 1147 bLockedEntryFound = sal_True; 1148 } 1149 else 1150 InvalidateBoundingRect( pViewData->aRect ); 1151 1152 pCur = pModel->NextSibling( pCur ); 1153 } 1154 if( !bLockedEntryFound ) 1155 { 1156 //XXX 1157 nFlags |= F_GRID_INSERT; 1158 } 1159 1160 SetNextEntryPos( Point( LROFFS_WINBORDER, TBOFFS_WINBORDER ) ); 1161 pImpCursor->Clear(); 1162 } 1163 1164 1165 void SvImpIconView::AdjustVirtSize( const Rectangle& rRect ) 1166 { 1167 long nHeightOffs = 0; 1168 long nWidthOffs = 0; 1169 1170 if( aVirtOutputSize.Width() < (rRect.Right()+LROFFS_WINBORDER) ) 1171 nWidthOffs = (rRect.Right()+LROFFS_WINBORDER) - aVirtOutputSize.Width(); 1172 1173 if( aVirtOutputSize.Height() < (rRect.Bottom()+TBOFFS_WINBORDER) ) 1174 nHeightOffs = (rRect.Bottom()+TBOFFS_WINBORDER) - aVirtOutputSize.Height(); 1175 1176 if( nWidthOffs || nHeightOffs ) 1177 { 1178 Range aRange; 1179 aVirtOutputSize.Width() += nWidthOffs; 1180 aRange.Max() = aVirtOutputSize.Width(); 1181 aHorSBar.SetRange( aRange ); 1182 1183 aVirtOutputSize.Height() += nHeightOffs; 1184 aRange.Max() = aVirtOutputSize.Height(); 1185 aVerSBar.SetRange( aRange ); 1186 1187 pImpCursor->Clear(); 1188 AdjustScrollBars(); 1189 } 1190 } 1191 1192 void SvImpIconView::Arrange() 1193 { 1194 nMaxVirtWidth = aOutputSize.Width(); 1195 ImpArrange(); 1196 } 1197 1198 void SvImpIconView::ImpArrange() 1199 { 1200 StopEditTimer(); 1201 ShowCursor( sal_False ); 1202 ResetVirtSize(); 1203 bMustRecalcBoundingRects = sal_False; 1204 MapMode aMapMode( pView->GetMapMode()); 1205 aMapMode.SetOrigin( Point() ); 1206 pView->SetMapMode( aMapMode ); 1207 CheckAllSizes(); 1208 RecalcAllBoundingRectsSmart(); 1209 pView->Invalidate(); 1210 ShowCursor( sal_True ); 1211 } 1212 1213 void SvImpIconView::Paint( const Rectangle& rRect ) 1214 { 1215 if( !pView->IsUpdateMode() ) 1216 return; 1217 1218 #if defined(DBG_UTIL) && defined(OV_DRAWGRID) 1219 if( nFlags & F_GRIDMODE ) 1220 { 1221 Color aOldColor = pView->GetLineColor(); 1222 Color aNewColor( COL_BLACK ); 1223 pView->SetLineColor( aNewColor ); 1224 Point aOffs( pView->GetMapMode().GetOrigin()); 1225 Size aXSize( pView->GetOutputSizePixel() ); 1226 for( long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX ) 1227 { 1228 Point aStart( nDX+LROFFS_BOUND, 0 ); 1229 Point aEnd( nDX+LROFFS_BOUND, aXSize.Height()); 1230 aStart -= aOffs; 1231 aEnd -= aOffs; 1232 pView->DrawLine( aStart, aEnd ); 1233 } 1234 for( long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY ) 1235 { 1236 Point aStart( 0, nDY+TBOFFS_BOUND ); 1237 Point aEnd( aXSize.Width(), nDY+TBOFFS_BOUND ); 1238 aStart -= aOffs; 1239 aEnd -= aOffs; 1240 pView->DrawLine( aStart, aEnd ); 1241 } 1242 pView->SetLineColor( aOldColor ); 1243 } 1244 #endif 1245 nFlags |= F_PAINTED; 1246 1247 if( !(pModel->HasChilds( pCurParent ) )) 1248 return; 1249 if( !pCursor ) 1250 pCursor = pModel->FirstChild( pCurParent ); 1251 1252 sal_uInt16 nCount = pZOrderList->Count(); 1253 if( !nCount ) 1254 return; 1255 1256 SvPtrarr* pNewZOrderList = new SvPtrarr; 1257 SvPtrarr* pPaintedEntries = new SvPtrarr; 1258 1259 sal_uInt16 nPos = 0; 1260 while( nCount ) 1261 { 1262 SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nPos )); 1263 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 1264 const Rectangle& rBoundRect = GetBoundingRect( pEntry, pViewData ); 1265 if( rRect.IsOver( rBoundRect ) ) 1266 { 1267 PaintEntry( pEntry, rBoundRect.TopLeft(), pViewData ); 1268 // Eintraege, die neu gezeichnet werden, auf Top setzen 1269 pPaintedEntries->Insert( pEntry, pPaintedEntries->Count() ); 1270 } 1271 else 1272 pNewZOrderList->Insert( pEntry, pNewZOrderList->Count() ); 1273 1274 nCount--; 1275 nPos++; 1276 } 1277 delete pZOrderList; 1278 pZOrderList = pNewZOrderList; 1279 nCount = pPaintedEntries->Count(); 1280 if( nCount ) 1281 { 1282 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 1283 pZOrderList->Insert( pPaintedEntries->GetObject( nCur ),pZOrderList->Count()); 1284 } 1285 delete pPaintedEntries; 1286 1287 Rectangle aRect; 1288 if( GetResizeRect( aRect )) 1289 PaintResizeRect( aRect ); 1290 } 1291 1292 sal_Bool SvImpIconView::GetResizeRect( Rectangle& rRect ) 1293 { 1294 if( aHorSBar.IsVisible() && aVerSBar.IsVisible() ) 1295 { 1296 const MapMode& rMapMode = pView->GetMapMode(); 1297 Point aOrigin( rMapMode.GetOrigin()); 1298 aOrigin *= -1; 1299 aOrigin.X() += aOutputSize.Width(); 1300 aOrigin.Y() += aOutputSize.Height(); 1301 rRect.SetPos( aOrigin ); 1302 rRect.SetSize( Size( nVerSBarWidth, nHorSBarHeight)); 1303 return sal_True; 1304 } 1305 return sal_False; 1306 } 1307 1308 void SvImpIconView::PaintResizeRect( const Rectangle& rRect ) 1309 { 1310 const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings(); 1311 Color aNewColor = rStyleSettings.GetFaceColor(); 1312 Color aOldColor = pView->GetFillColor(); 1313 pView->SetFillColor( aNewColor ); 1314 pView->DrawRect( rRect ); 1315 pView->SetFillColor( aOldColor ); 1316 } 1317 1318 void SvImpIconView::RepaintSelectionItems() 1319 { 1320 DBG_ERROR("RepaintSelectionItems"); 1321 pView->Invalidate(); // vorlaeufig 1322 } 1323 1324 SvLBoxItem* SvImpIconView::GetItem( SvLBoxEntry* pEntry, 1325 const Point& rAbsPos ) 1326 { 1327 Rectangle aRect; 1328 SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 1329 if( pStringItem ) 1330 { 1331 aRect = CalcTextRect( pEntry, pStringItem ); 1332 if( aRect.IsInside( rAbsPos ) ) 1333 return pStringItem; 1334 } 1335 SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); 1336 if( pBmpItem ) 1337 { 1338 aRect = CalcBmpRect( pEntry ); 1339 if( aRect.IsInside( rAbsPos ) ) 1340 return pBmpItem; 1341 } 1342 return 0; 1343 } 1344 1345 void SvImpIconView::CalcDocPos( Point& aMaeuschenPos ) 1346 { 1347 aMaeuschenPos -= pView->GetMapMode().GetOrigin(); 1348 } 1349 1350 void SvImpIconView::MouseButtonDown( const MouseEvent& rMEvt) 1351 { 1352 StopEditTimer(); 1353 pView->GrabFocus(); 1354 Point aDocPos( rMEvt.GetPosPixel() ); 1355 if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height()) 1356 return; 1357 CalcDocPos( aDocPos ); 1358 SvLBoxEntry* pEntry = GetEntry( aDocPos ); 1359 if( !pEntry ) 1360 { 1361 if( pView->GetSelectionMode() != SINGLE_SELECTION ) 1362 { 1363 if( !rMEvt.IsMod1() ) // Ctrl 1364 { 1365 pView->SelectAll( sal_False ); 1366 ClearSelectedRectList(); 1367 } 1368 else 1369 nFlags |= F_ADD_MODE; 1370 nFlags |= F_RUBBERING; 1371 aCurSelectionRect.SetPos( aDocPos ); 1372 pView->CaptureMouse(); 1373 } 1374 return; 1375 } 1376 1377 sal_Bool bSelected = pView->IsSelected( pEntry ); 1378 sal_Bool bEditingEnabled = pView->IsInplaceEditingEnabled(); 1379 1380 if( rMEvt.GetClicks() == 2 ) 1381 { 1382 DeselectAllBut( pEntry ); 1383 pView->pHdlEntry = pEntry; 1384 pView->DoubleClickHdl(); 1385 } 1386 else 1387 { 1388 // Inplace-Editing ? 1389 if( rMEvt.IsMod2() ) // Alt? 1390 { 1391 if( bEditingEnabled ) 1392 { 1393 SvLBoxItem* pItem = GetItem(pEntry,aDocPos); 1394 if( pItem ) 1395 pView->EditingRequest( pEntry, pItem, aDocPos); 1396 } 1397 } 1398 else if( pView->GetSelectionMode() == SINGLE_SELECTION ) 1399 { 1400 DeselectAllBut( pEntry ); 1401 SetCursor( pEntry ); 1402 pView->Select( pEntry, sal_True ); 1403 if( bEditingEnabled && bSelected && !rMEvt.GetModifier() && 1404 rMEvt.IsLeft() && IsTextHit( pEntry, aDocPos ) ) 1405 { 1406 nFlags |= F_START_EDITTIMER_IN_MOUSEUP; 1407 } 1408 } 1409 else 1410 { 1411 if( !rMEvt.GetModifier() ) 1412 { 1413 if( !bSelected ) 1414 { 1415 DeselectAllBut( pEntry ); 1416 SetCursor( pEntry ); 1417 pView->Select( pEntry, sal_True ); 1418 } 1419 else 1420 { 1421 // erst im Up deselektieren, falls Move per D&D! 1422 nFlags |= F_DOWN_DESELECT; 1423 if( bEditingEnabled && IsTextHit( pEntry, aDocPos ) && 1424 rMEvt.IsLeft()) 1425 { 1426 nFlags |= F_START_EDITTIMER_IN_MOUSEUP; 1427 } 1428 } 1429 } 1430 else if( rMEvt.IsMod1() ) 1431 nFlags |= F_DOWN_CTRL; 1432 } 1433 } 1434 } 1435 1436 void SvImpIconView::MouseButtonUp( const MouseEvent& rMEvt ) 1437 { 1438 aMouseMoveTimer.Stop(); 1439 pView->ReleaseMouse(); 1440 // HACK, da Einar noch nicht PrepareCommandEvent aufruft 1441 if( rMEvt.IsRight() && (nFlags & (F_DOWN_CTRL | F_DOWN_DESELECT) )) 1442 nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); 1443 1444 if( nFlags & F_RUBBERING ) 1445 { 1446 aMouseMoveTimer.Stop(); 1447 AddSelectedRect( aCurSelectionRect ); 1448 HideSelectionRect(); 1449 nFlags &= ~(F_RUBBERING | F_ADD_MODE); 1450 } 1451 1452 SvLBoxEntry* pEntry = pView->GetEntry( rMEvt.GetPosPixel(), sal_True ); 1453 if( pEntry ) 1454 { 1455 if( nFlags & F_DOWN_CTRL ) 1456 { 1457 // Ctrl & MultiSelection 1458 ToggleSelection( pEntry ); 1459 SetCursor( pEntry ); 1460 } 1461 else if( nFlags & F_DOWN_DESELECT ) 1462 { 1463 DeselectAllBut( pEntry ); 1464 SetCursor( pEntry ); 1465 pView->Select( pEntry, sal_True ); 1466 } 1467 } 1468 1469 nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); 1470 if( nFlags & F_START_EDITTIMER_IN_MOUSEUP ) 1471 { 1472 StartEditTimer(); 1473 nFlags &= ~F_START_EDITTIMER_IN_MOUSEUP; 1474 } 1475 } 1476 1477 void SvImpIconView::MouseMove( const MouseEvent& rMEvt ) 1478 { 1479 if( nFlags & F_RUBBERING ) 1480 { 1481 const Point& rPosPixel = rMEvt.GetPosPixel(); 1482 if( !aMouseMoveTimer.IsActive() ) 1483 { 1484 aMouseMoveEvent = rMEvt; 1485 aMouseMoveTimer.Start(); 1486 // ausserhalb des Fensters liegende Move-Events muessen 1487 // vom Timer kommen, damit die Scrollgeschwindigkeit 1488 // unabhaengig von Mausbewegungen ist. 1489 if( rPosPixel.X() < 0 || rPosPixel.Y() < 0 ) 1490 return; 1491 const Size& rSize = pView->GetOutputSizePixel(); 1492 if( rPosPixel.X() > rSize.Width() || rPosPixel.Y() > rSize.Height()) 1493 return; 1494 } 1495 1496 if( &rMEvt != &aMouseMoveEvent ) 1497 aMouseMoveEvent = rMEvt; 1498 1499 long nScrollDX, nScrollDY; 1500 1501 CalcScrollOffsets(rMEvt.GetPosPixel(),nScrollDX,nScrollDY,sal_False ); 1502 sal_Bool bSelRectHidden = sal_False; 1503 if( nScrollDX || nScrollDY ) 1504 { 1505 HideSelectionRect(); 1506 bSelRectHidden = sal_True; 1507 pView->Scroll( nScrollDX, nScrollDY ); 1508 } 1509 Point aDocPos( rMEvt.GetPosPixel() ); 1510 aDocPos = pView->PixelToLogic( aDocPos ); 1511 Rectangle aRect( aCurSelectionRect.TopLeft(), aDocPos ); 1512 if( aRect != aCurSelectionRect ) 1513 { 1514 HideSelectionRect(); 1515 bSelRectHidden = sal_True; 1516 sal_Bool bAdd = (nFlags & F_ADD_MODE) ? sal_True : sal_False; 1517 SelectRect( aRect, bAdd, &aSelectedRectList ); 1518 } 1519 if( bSelRectHidden ) 1520 DrawSelectionRect( aRect ); 1521 } 1522 } 1523 1524 sal_Bool SvImpIconView::KeyInput( const KeyEvent& rKEvt ) 1525 { 1526 StopEditTimer(); 1527 sal_Bool bKeyUsed = sal_True; 1528 sal_Bool bMod1 = rKEvt.GetKeyCode().IsMod1(); 1529 sal_Bool bInAddMode = (sal_Bool)((nFlags & F_ADD_MODE) != 0); 1530 int bDeselAll = (pView->GetSelectionMode() != SINGLE_SELECTION) && 1531 !bInAddMode; 1532 SvLBoxEntry* pNewCursor; 1533 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); 1534 switch( nCode ) 1535 { 1536 case KEY_UP: 1537 if( pCursor ) 1538 { 1539 MakeVisible( pCursor ); 1540 pNewCursor = pImpCursor->GoUpDown(pCursor,sal_False); 1541 if( pNewCursor ) 1542 { 1543 if( bDeselAll ) 1544 pView->SelectAll( sal_False ); 1545 ShowCursor( sal_False ); 1546 MakeVisible( pNewCursor ); 1547 SetCursor( pNewCursor ); 1548 if( !bInAddMode ) 1549 pView->Select( pCursor, sal_True ); 1550 } 1551 else 1552 { 1553 Rectangle aRect( GetBoundingRect( pCursor ) ); 1554 if( aRect.Top()) 1555 { 1556 aRect.Bottom() -= aRect.Top(); 1557 aRect.Top() = 0; 1558 MakeVisible( aRect ); 1559 } 1560 } 1561 } 1562 break; 1563 1564 case KEY_DOWN: 1565 if( pCursor ) 1566 { 1567 pNewCursor=pImpCursor->GoUpDown( pCursor,sal_True ); 1568 if( pNewCursor ) 1569 { 1570 MakeVisible( pCursor ); 1571 if( bDeselAll ) 1572 pView->SelectAll( sal_False ); 1573 ShowCursor( sal_False ); 1574 MakeVisible( pNewCursor ); 1575 SetCursor( pNewCursor ); 1576 if( !bInAddMode ) 1577 pView->Select( pCursor, sal_True ); 1578 } 1579 } 1580 break; 1581 1582 case KEY_RIGHT: 1583 if( pCursor ) 1584 { 1585 pNewCursor=pImpCursor->GoLeftRight(pCursor,sal_True ); 1586 if( pNewCursor ) 1587 { 1588 MakeVisible( pCursor ); 1589 if( bDeselAll ) 1590 pView->SelectAll( sal_False ); 1591 ShowCursor( sal_False ); 1592 MakeVisible( pNewCursor ); 1593 SetCursor( pNewCursor ); 1594 if( !bInAddMode ) 1595 pView->Select( pCursor, sal_True ); 1596 } 1597 } 1598 break; 1599 1600 case KEY_LEFT: 1601 if( pCursor ) 1602 { 1603 MakeVisible( pCursor ); 1604 pNewCursor = pImpCursor->GoLeftRight(pCursor,sal_False ); 1605 if( pNewCursor ) 1606 { 1607 if( bDeselAll ) 1608 pView->SelectAll( sal_False ); 1609 ShowCursor( sal_False ); 1610 MakeVisible( pNewCursor ); 1611 SetCursor( pNewCursor ); 1612 if( !bInAddMode ) 1613 pView->Select( pCursor, sal_True ); 1614 } 1615 else 1616 { 1617 Rectangle aRect( GetBoundingRect(pCursor)); 1618 if( aRect.Left() ) 1619 { 1620 aRect.Right() -= aRect.Left(); 1621 aRect.Left() = 0; 1622 MakeVisible( aRect ); 1623 } 1624 } 1625 } 1626 break; 1627 1628 case KEY_ESCAPE: 1629 if( nFlags & F_RUBBERING ) 1630 { 1631 HideSelectionRect(); 1632 pView->SelectAll( sal_False ); 1633 nFlags &= ~F_RUBBERING; 1634 } 1635 break; 1636 1637 case KEY_F8: 1638 if( rKEvt.GetKeyCode().IsShift() ) 1639 { 1640 if( nFlags & F_ADD_MODE ) 1641 nFlags &= (~F_ADD_MODE); 1642 else 1643 nFlags |= F_ADD_MODE; 1644 } 1645 break; 1646 1647 #ifdef OS2 1648 case KEY_F9: 1649 if( rKEvt.GetKeyCode().IsShift() ) 1650 { 1651 if( pCursor && pView->IsInplaceEditingEnabled() ) 1652 pView->EditEntry( pCursor ); 1653 } 1654 break; 1655 #endif 1656 1657 case KEY_SPACE: 1658 if( pCursor ) 1659 { 1660 ToggleSelection( pCursor ); 1661 } 1662 break; 1663 1664 1665 case KEY_PAGEDOWN: 1666 break; 1667 case KEY_PAGEUP: 1668 break; 1669 1670 case KEY_ADD: 1671 case KEY_DIVIDE : 1672 if( bMod1 ) 1673 pView->SelectAll( sal_True ); 1674 break; 1675 1676 case KEY_SUBTRACT: 1677 case KEY_COMMA : 1678 if( bMod1 ) 1679 pView->SelectAll( sal_False ); 1680 break; 1681 1682 case KEY_RETURN: 1683 if( bMod1 ) 1684 { 1685 if( pCursor && pView->IsInplaceEditingEnabled() ) 1686 pView->EditEntry( pCursor ); 1687 } 1688 break; 1689 1690 default: 1691 bKeyUsed = sal_False; 1692 1693 } 1694 return bKeyUsed; 1695 } 1696 1697 1698 void SvImpIconView::PositionScrollBars( long nRealWidth, long nRealHeight ) 1699 { 1700 // hor scrollbar 1701 Point aPos( 0, nRealHeight ); 1702 aPos.Y() -= nHorSBarHeight; 1703 1704 #ifdef OS2 1705 aPos.Y()++; 1706 #endif 1707 if( aHorSBar.GetPosPixel() != aPos ) 1708 aHorSBar.SetPosPixel( aPos ); 1709 1710 // ver scrollbar 1711 aPos.X() = nRealWidth; aPos.Y() = 0; 1712 aPos.X() -= nVerSBarWidth; 1713 1714 #if defined(WNT) 1715 aPos.X()++; 1716 aPos.Y()--; 1717 #endif 1718 1719 #ifdef OS2 1720 aPos.Y()--; 1721 aPos.X()++; 1722 #endif 1723 1724 if( aVerSBar.GetPosPixel() != aPos ) 1725 aVerSBar.SetPosPixel( aPos ); 1726 } 1727 1728 1729 1730 void SvImpIconView::AdjustScrollBars() 1731 { 1732 long nVirtHeight = aVirtOutputSize.Height(); 1733 long nVirtWidth = aVirtOutputSize.Width(); 1734 1735 Size aOSize( pView->Control::GetOutputSizePixel() ); 1736 long nRealHeight = aOSize.Height(); 1737 long nRealWidth = aOSize.Width(); 1738 1739 PositionScrollBars( nRealWidth, nRealHeight ); 1740 1741 const MapMode& rMapMode = pView->GetMapMode(); 1742 Point aOrigin( rMapMode.GetOrigin() ); 1743 1744 long nVisibleWidth; 1745 if( nRealWidth > nVirtWidth ) 1746 nVisibleWidth = nVirtWidth + aOrigin.X(); 1747 else 1748 nVisibleWidth = nRealWidth; 1749 1750 long nVisibleHeight; 1751 if( nRealHeight > nVirtHeight ) 1752 nVisibleHeight = nVirtHeight + aOrigin.Y(); 1753 else 1754 nVisibleHeight = nRealHeight; 1755 1756 bool bVerSBar = (pView->GetStyle() & WB_VSCROLL) ? true : false; 1757 bool bHorSBar = (pView->GetStyle() & WB_HSCROLL) ? true : false; 1758 1759 sal_uInt16 nResult = 0; 1760 if( nVirtHeight ) 1761 { 1762 // activate ver scrollbar ? 1763 if( bVerSBar || ( nVirtHeight > nVisibleHeight) ) 1764 { 1765 nResult = 0x0001; 1766 nRealWidth -= nVerSBarWidth; 1767 1768 if( nRealWidth > nVirtWidth ) 1769 nVisibleWidth = nVirtWidth + aOrigin.X(); 1770 else 1771 nVisibleWidth = nRealWidth; 1772 1773 nFlags |= F_HOR_SBARSIZE_WITH_VBAR; 1774 } 1775 // activate hor scrollbar ? 1776 if( bHorSBar || (nVirtWidth > nVisibleWidth) ) 1777 { 1778 nResult |= 0x0002; 1779 nRealHeight -= nHorSBarHeight; 1780 1781 if( nRealHeight > nVirtHeight ) 1782 nVisibleHeight = nVirtHeight + aOrigin.Y(); 1783 else 1784 nVisibleHeight = nRealHeight; 1785 1786 // brauchen wir jetzt doch eine senkrechte Scrollbar ? 1787 if( !(nResult & 0x0001) && // nur wenn nicht schon da 1788 ( (nVirtHeight > nVisibleHeight) || bVerSBar) ) 1789 { 1790 nResult = 3; // both are active 1791 nRealWidth -= nVerSBarWidth; 1792 1793 if( nRealWidth > nVirtWidth ) 1794 nVisibleWidth = nVirtWidth + aOrigin.X(); 1795 else 1796 nVisibleWidth = nRealWidth; 1797 1798 nFlags |= F_VER_SBARSIZE_WITH_HBAR; 1799 } 1800 } 1801 } 1802 1803 // size ver scrollbar 1804 long nThumb = aVerSBar.GetThumbPos(); 1805 Size aSize( nVerSBarWidth, nRealHeight ); 1806 #if defined(WNT) 1807 aSize.Height() += 2; 1808 #endif 1809 #ifdef OS2 1810 aSize.Height() += 3; 1811 #endif 1812 if( aSize != aVerSBar.GetSizePixel() ) 1813 aVerSBar.SetSizePixel( aSize ); 1814 aVerSBar.SetVisibleSize( nVisibleHeight ); 1815 aVerSBar.SetPageSize( (nVisibleHeight*75)/100 ); 1816 if( nResult & 0x0001 ) 1817 { 1818 aVerSBar.SetThumbPos( nThumb ); 1819 aVerSBar.Show(); 1820 } 1821 else 1822 { 1823 aVerSBar.SetThumbPos( 0 ); 1824 aVerSBar.Hide(); 1825 } 1826 1827 // size hor scrollbar 1828 nThumb = aHorSBar.GetThumbPos(); 1829 aSize.Width() = nRealWidth; 1830 aSize.Height() = nHorSBarHeight; 1831 #if defined(WNT) 1832 aSize.Width()++; 1833 #endif 1834 #ifdef OS2 1835 aSize.Width() += 3; 1836 if( nResult & 0x0001 ) // vertikale Scrollbar ? 1837 aSize.Width()--; 1838 #endif 1839 #if defined(WNT) 1840 if( nResult & 0x0001 ) // vertikale Scrollbar ? 1841 { 1842 aSize.Width()++; 1843 nRealWidth++; 1844 } 1845 #endif 1846 if( aSize != aHorSBar.GetSizePixel() ) 1847 aHorSBar.SetSizePixel( aSize ); 1848 aHorSBar.SetVisibleSize( nVisibleWidth ); //nRealWidth ); 1849 aHorSBar.SetPageSize( (nVisibleWidth*75)/100 ); 1850 if( nResult & 0x0002 ) 1851 { 1852 aHorSBar.SetThumbPos( nThumb ); 1853 aHorSBar.Show(); 1854 } 1855 else 1856 { 1857 aHorSBar.SetThumbPos( 0 ); 1858 aHorSBar.Hide(); 1859 } 1860 1861 #ifdef OS2 1862 nRealWidth++; 1863 #endif 1864 aOutputSize.Width() = nRealWidth; 1865 #if defined(WNT) 1866 if( nResult & 0x0002 ) // hor scrollbar ? 1867 nRealHeight++; // weil unterer Rand geclippt wird 1868 #endif 1869 #ifdef OS2 1870 if( nResult & 0x0002 ) // hor scrollbar ? 1871 nRealHeight++; 1872 #endif 1873 aOutputSize.Height() = nRealHeight; 1874 } 1875 1876 void __EXPORT SvImpIconView::Resize() 1877 { 1878 StopEditTimer(); 1879 Rectangle aRect; 1880 if( GetResizeRect(aRect) ) 1881 pView->Invalidate( aRect ); 1882 aOutputSize = pView->GetOutputSizePixel(); 1883 pImpCursor->Clear(); 1884 1885 #if 1 1886 const Size& rSize = pView->Control::GetOutputSizePixel(); 1887 PositionScrollBars( rSize.Width(), rSize.Height() ); 1888 // Die ScrollBars werden asynchron ein/ausgeblendet, damit abgeleitete 1889 // Klassen im Resize ein Arrange durchfuehren koennen, ohne dass 1890 // die ScrollBars aufblitzen (SfxExplorerIconView!) 1891 nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpIconView,UserEventHdl),0); 1892 #else 1893 AdjustScrollBars(); 1894 if( GetResizeRect(aRect) ) 1895 PaintResizeRect( aRect ); 1896 #endif 1897 } 1898 1899 sal_Bool SvImpIconView::CheckHorScrollBar() 1900 { 1901 if( !pZOrderList || !aHorSBar.IsVisible() ) 1902 return sal_False; 1903 const MapMode& rMapMode = pView->GetMapMode(); 1904 Point aOrigin( rMapMode.GetOrigin() ); 1905 if(!(pView->GetStyle() & WB_HSCROLL) && !aOrigin.X() ) 1906 { 1907 long nWidth = aOutputSize.Width(); 1908 sal_uInt16 nCount = pZOrderList->Count(); 1909 long nMostRight = 0; 1910 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 1911 { 1912 SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur); 1913 long nRight = GetBoundingRect(pEntry).Right(); 1914 if( nRight > nWidth ) 1915 return sal_False; 1916 if( nRight > nMostRight ) 1917 nMostRight = nRight; 1918 } 1919 aHorSBar.Hide(); 1920 aOutputSize.Height() += nHorSBarHeight; 1921 aVirtOutputSize.Width() = nMostRight; 1922 aHorSBar.SetThumbPos( 0 ); 1923 Range aRange; 1924 aRange.Max() = nMostRight - 1; 1925 aHorSBar.SetRange( aRange ); 1926 if( aVerSBar.IsVisible() ) 1927 { 1928 Size aSize( aVerSBar.GetSizePixel()); 1929 aSize.Height() += nHorSBarHeight; 1930 aVerSBar.SetSizePixel( aSize ); 1931 } 1932 return sal_True; 1933 } 1934 return sal_False; 1935 } 1936 1937 sal_Bool SvImpIconView::CheckVerScrollBar() 1938 { 1939 if( !pZOrderList || !aVerSBar.IsVisible() ) 1940 return sal_False; 1941 const MapMode& rMapMode = pView->GetMapMode(); 1942 Point aOrigin( rMapMode.GetOrigin() ); 1943 if(!(pView->GetStyle() & WB_VSCROLL) && !aOrigin.Y() ) 1944 { 1945 long nDeepest = 0; 1946 long nHeight = aOutputSize.Height(); 1947 sal_uInt16 nCount = pZOrderList->Count(); 1948 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 1949 { 1950 SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur); 1951 long nBottom = GetBoundingRect(pEntry).Bottom(); 1952 if( nBottom > nHeight ) 1953 return sal_False; 1954 if( nBottom > nDeepest ) 1955 nDeepest = nBottom; 1956 } 1957 aVerSBar.Hide(); 1958 aOutputSize.Width() += nVerSBarWidth; 1959 aVirtOutputSize.Height() = nDeepest; 1960 aVerSBar.SetThumbPos( 0 ); 1961 Range aRange; 1962 aRange.Max() = nDeepest - 1; 1963 aVerSBar.SetRange( aRange ); 1964 if( aHorSBar.IsVisible() ) 1965 { 1966 Size aSize( aHorSBar.GetSizePixel()); 1967 aSize.Width() += nVerSBarWidth; 1968 aHorSBar.SetSizePixel( aSize ); 1969 } 1970 return sal_True; 1971 } 1972 return sal_False; 1973 } 1974 1975 1976 // blendet Scrollbars aus, wenn sie nicht mehr benoetigt werden 1977 void SvImpIconView::CheckScrollBars() 1978 { 1979 CheckVerScrollBar(); 1980 if( CheckHorScrollBar() ) 1981 CheckVerScrollBar(); 1982 } 1983 1984 1985 void __EXPORT SvImpIconView::GetFocus() 1986 { 1987 if( pCursor ) 1988 { 1989 pView->SetEntryFocus( pCursor, sal_True ); 1990 ShowCursor( sal_True ); 1991 } 1992 } 1993 1994 void __EXPORT SvImpIconView::LoseFocus() 1995 { 1996 StopEditTimer(); 1997 if( pCursor ) 1998 pView->SetEntryFocus( pCursor,sal_False ); 1999 ShowCursor( sal_False ); 2000 } 2001 2002 void SvImpIconView::UpdateAll() 2003 { 2004 AdjustScrollBars(); 2005 pImpCursor->Clear(); 2006 pView->Invalidate(); 2007 } 2008 2009 void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData ) 2010 { 2011 Point aPos( GetEntryPosition( pEntry ) ); 2012 PaintEntry( pEntry, aPos, pViewData ); 2013 } 2014 2015 void SvImpIconView::PaintEmphasis( const Rectangle& rRect, sal_Bool bSelected, 2016 sal_Bool bCursored, OutputDevice* pOut ) 2017 { 2018 // HACK fuer D&D 2019 if( nFlags & F_NO_EMPHASIS ) 2020 return; 2021 2022 if( !pOut ) 2023 pOut = pView; 2024 2025 // Selektion painten 2026 Color aOldFillColor = pOut->GetFillColor(); 2027 Color aOldLineColor = pOut->GetLineColor(); 2028 Color aNewColor; 2029 const StyleSettings& rStyleSettings = pOut->GetSettings().GetStyleSettings(); 2030 if( bSelected ) 2031 { 2032 aNewColor = rStyleSettings.GetHighlightColor(); 2033 } 2034 else 2035 { 2036 #ifndef OS2 2037 aNewColor =rStyleSettings.GetFieldColor(); 2038 #else 2039 aNewColor = pOut->GetBackground().GetColor(); 2040 #endif 2041 } 2042 2043 if( bCursored ) 2044 { 2045 pOut->SetLineColor( Color( COL_BLACK ) ); 2046 } 2047 pOut->SetFillColor( aNewColor ); 2048 pOut->DrawRect( rRect ); 2049 pOut->SetFillColor( aOldFillColor ); 2050 pOut->SetLineColor( aOldLineColor ); 2051 } 2052 2053 void SvImpIconView::PaintItem( const Rectangle& rRect, 2054 SvLBoxItem* pItem, SvLBoxEntry* pEntry, sal_uInt16 nPaintFlags, 2055 OutputDevice* pOut ) 2056 { 2057 if( nViewMode == VIEWMODE_ICON && pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) 2058 { 2059 const String& rStr = ((SvLBoxString*)pItem)->GetText(); 2060 DrawText( pOut, rRect, rStr, DRAWTEXT_FLAGS ); 2061 } 2062 else 2063 { 2064 Point aPos( rRect.TopLeft() ); 2065 const Size& rSize = GetItemSize( pView, pEntry, pItem ); 2066 if( nPaintFlags & PAINTFLAG_HOR_CENTERED ) 2067 aPos.X() += (rRect.GetWidth() - rSize.Width() ) / 2; 2068 if( nPaintFlags & PAINTFLAG_VER_CENTERED ) 2069 aPos.Y() += (rRect.GetHeight() - rSize.Height() ) / 2; 2070 pItem->Paint( aPos, *(SvLBox*)pOut, 0, pEntry ); 2071 } 2072 } 2073 2074 void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, const Point& rPos, 2075 SvIcnVwDataEntry* pViewData, OutputDevice* pOut ) 2076 { 2077 if( !pView->IsUpdateMode() ) 2078 return; 2079 2080 if( !pOut ) 2081 pOut = pView; 2082 2083 SvLBoxContextBmp* pBmpItem; 2084 2085 pView->PreparePaint( pEntry ); 2086 2087 if( !pViewData ) 2088 pViewData = ICNVIEWDATA(pEntry); 2089 2090 SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 2091 2092 sal_Bool bSelected = pViewData->IsSelected(); 2093 sal_Bool bCursored = pViewData->IsCursored(); 2094 2095 Font aTempFont( pOut->GetFont() ); 2096 // waehrend D&D nicht die Fontfarbe wechseln, da sonst auch die 2097 // Emphasis gezeichnet werden muss! (weisser Adler auf weissem Grund) 2098 if( bSelected && !(nFlags & F_NO_EMPHASIS) ) 2099 { 2100 const StyleSettings& rStyleSettings = pOut->GetSettings().GetStyleSettings(); 2101 Font aNewFont( aTempFont ); 2102 aNewFont.SetColor( rStyleSettings.GetHighlightTextColor() ); 2103 pOut->SetFont( aNewFont ); 2104 } 2105 Rectangle aTextRect( CalcTextRect(pEntry,pStringItem,&rPos,sal_False,pViewData)); 2106 Rectangle aBmpRect( CalcBmpRect(pEntry, &rPos, pViewData ) ); 2107 2108 switch( nViewMode ) 2109 { 2110 case VIEWMODE_ICON: 2111 pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); 2112 PaintEmphasis( aBmpRect, bSelected, bCursored, pOut ); 2113 PaintItem( aBmpRect, pBmpItem, pEntry, 2114 PAINTFLAG_HOR_CENTERED | PAINTFLAG_VER_CENTERED, pOut ); 2115 PaintEmphasis( aTextRect, bSelected, sal_False, pOut ); 2116 PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_HOR_CENTERED, pOut ); 2117 break; 2118 2119 case VIEWMODE_NAME: 2120 pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); 2121 PaintEmphasis( aBmpRect, bSelected, bCursored, pOut ); 2122 PaintItem( aBmpRect, pBmpItem, pEntry, PAINTFLAG_VER_CENTERED, pOut ); 2123 PaintEmphasis( aTextRect, bSelected, sal_False, pOut ); 2124 PaintItem( aTextRect, pStringItem, pEntry,PAINTFLAG_VER_CENTERED, pOut ); 2125 break; 2126 2127 case VIEWMODE_TEXT: 2128 PaintEmphasis( aTextRect, bSelected, bCursored, pOut ); 2129 PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_VER_CENTERED, pOut ); 2130 break; 2131 } 2132 pOut->SetFont( aTempFont ); 2133 } 2134 2135 void SvImpIconView::SetEntryPosition( SvLBoxEntry* pEntry, const Point& rPos, 2136 sal_Bool bAdjustAtGrid, sal_Bool bCheckScrollBars ) 2137 { 2138 if( pModel->GetParent(pEntry) == pCurParent ) 2139 { 2140 ShowCursor( sal_False ); 2141 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2142 Rectangle aBoundRect( GetBoundingRect( pEntry, pViewData )); 2143 pView->Invalidate( aBoundRect ); 2144 ToTop( pEntry ); 2145 if( rPos != aBoundRect.TopLeft() ) 2146 { 2147 Point aGridOffs = pViewData->aGridRect.TopLeft() - 2148 pViewData->aRect.TopLeft(); 2149 pImpCursor->Clear(); 2150 nFlags &= ~F_GRID_INSERT; 2151 aBoundRect.SetPos( rPos ); 2152 pViewData->aRect = aBoundRect; 2153 pViewData->aGridRect.SetPos( rPos + aGridOffs ); 2154 AdjustVirtSize( aBoundRect ); 2155 } 2156 //HACK(Billigloesung, die noch verbessert werden muss) 2157 if( bAdjustAtGrid ) 2158 { 2159 AdjustAtGrid( pEntry ); 2160 ToTop( pEntry ); 2161 } 2162 if( bCheckScrollBars && pView->IsUpdateMode() ) 2163 CheckScrollBars(); 2164 2165 PaintEntry( pEntry, pViewData ); 2166 ShowCursor( sal_True ); 2167 } 2168 } 2169 2170 void SvImpIconView::ViewDataInitialized( SvLBoxEntry*) 2171 { 2172 } 2173 2174 void SvImpIconView::ModelHasEntryInvalidated( SvListEntry* pEntry ) 2175 { 2176 if( pEntry == pCursor ) 2177 ShowCursor( sal_False ); 2178 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2179 pView->Invalidate( pViewData->aRect ); 2180 2181 if( nFlags & F_GRIDMODE ) 2182 Center( (SvLBoxEntry*)pEntry, pViewData ); 2183 else 2184 pViewData->aRect.SetSize( CalcBoundingSize( 2185 (SvLBoxEntry*)pEntry, pViewData ) ); 2186 2187 ViewDataInitialized( (SvLBoxEntry*)pEntry ); 2188 pView->Invalidate( pViewData->aRect ); 2189 if( pEntry == pCursor ) 2190 ShowCursor( sal_True ); 2191 } 2192 2193 2194 void SvImpIconView::InvalidateEntry( SvLBoxEntry* pEntry ) 2195 { 2196 const Rectangle& rRect = GetBoundingRect( pEntry ); 2197 pView->Invalidate( rRect ); 2198 } 2199 2200 void SvImpIconView::SetNoSelection() 2201 { 2202 } 2203 2204 void SvImpIconView::SetDragDropMode( DragDropMode ) 2205 { 2206 } 2207 2208 void SvImpIconView::SetSelectionMode( SelectionMode ) 2209 { 2210 } 2211 2212 sal_Bool SvImpIconView::IsEntryInView( SvLBoxEntry* ) 2213 { 2214 return sal_False; 2215 } 2216 2217 SvLBoxEntry* SvImpIconView::GetDropTarget( const Point& rPos ) 2218 { 2219 Point aDocPos( rPos ); 2220 CalcDocPos( aDocPos ); 2221 SvLBoxEntry* pTarget = GetEntry( aDocPos ); 2222 if( !pTarget || !pTarget->HasChilds() ) 2223 pTarget = pCurParent; 2224 return pTarget; 2225 } 2226 2227 SvLBoxEntry* SvImpIconView::GetEntry( const Point& rDocPos ) 2228 { 2229 CheckBoundingRects(); 2230 SvLBoxEntry* pTarget = 0; 2231 // Z-Order-Liste vom Ende her absuchen 2232 sal_uInt16 nCount = pZOrderList->Count(); 2233 while( nCount ) 2234 { 2235 nCount--; 2236 SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nCount)); 2237 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2238 if( pViewData->aRect.IsInside( rDocPos ) ) 2239 { 2240 pTarget = pEntry; 2241 break; 2242 } 2243 } 2244 return pTarget; 2245 } 2246 2247 SvLBoxEntry* SvImpIconView::GetNextEntry( const Point& rDocPos, SvLBoxEntry* pCurEntry ) 2248 { 2249 CheckBoundingRects(); 2250 SvLBoxEntry* pTarget = 0; 2251 sal_uInt16 nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); 2252 if( nStartPos != USHRT_MAX ) 2253 { 2254 sal_uInt16 nCount = pZOrderList->Count(); 2255 for( sal_uInt16 nCur = nStartPos+1; nCur < nCount; nCur++ ) 2256 { 2257 SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nCur)); 2258 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2259 if( pViewData->aRect.IsInside( rDocPos ) ) 2260 { 2261 pTarget = pEntry; 2262 break; 2263 } 2264 } 2265 } 2266 return pTarget; 2267 } 2268 2269 SvLBoxEntry* SvImpIconView::GetPrevEntry( const Point& rDocPos, SvLBoxEntry* pCurEntry ) 2270 { 2271 CheckBoundingRects(); 2272 SvLBoxEntry* pTarget = 0; 2273 sal_uInt16 nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); 2274 if( nStartPos != USHRT_MAX && nStartPos != 0 ) 2275 { 2276 nStartPos--; 2277 do 2278 { 2279 SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nStartPos)); 2280 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2281 if( pViewData->aRect.IsInside( rDocPos ) ) 2282 { 2283 pTarget = pEntry; 2284 break; 2285 } 2286 } while( nStartPos > 0 ); 2287 } 2288 return pTarget; 2289 } 2290 2291 2292 Point SvImpIconView::GetEntryPosition( SvLBoxEntry* pEntry ) 2293 { 2294 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2295 DBG_ASSERT(pViewData,"Entry not in model"); 2296 return pViewData->aRect.TopLeft(); 2297 } 2298 2299 const Rectangle& SvImpIconView::GetBoundingRect( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData ) 2300 { 2301 if( !pViewData ) 2302 pViewData = ICNVIEWDATA(pEntry); 2303 DBG_ASSERT(pViewData,"Entry not in model"); 2304 if( !IsBoundingRectValid( pViewData->aRect )) 2305 FindBoundingRect( pEntry, pViewData ); 2306 return pViewData->aRect; 2307 } 2308 2309 void SvImpIconView::SetSpaceBetweenEntries( long nHor, long nVer ) 2310 { 2311 nHorDist = nHor; 2312 nVerDist = nVer; 2313 } 2314 2315 Rectangle SvImpIconView::CalcBmpRect( SvLBoxEntry* pEntry, const Point* pPos, 2316 SvIcnVwDataEntry* pViewData ) 2317 { 2318 if( !pViewData ) 2319 pViewData = ICNVIEWDATA(pEntry); 2320 2321 Rectangle aBound = GetBoundingRect( pEntry, pViewData ); 2322 if( pPos ) 2323 aBound.SetPos( *pPos ); 2324 Point aPos( aBound.TopLeft() ); 2325 2326 switch( nViewMode ) 2327 { 2328 case VIEWMODE_ICON: 2329 { 2330 aPos.X() += ( aBound.GetWidth() - nMaxBmpWidth ) / 2; 2331 Size aSize( nMaxBmpWidth, nMaxBmpHeight ); 2332 // das Bitmap-Rechteck soll nicht das TextRect beruehren 2333 aSize.Height() -= 3; 2334 return Rectangle( aPos, aSize ); 2335 } 2336 2337 case VIEWMODE_NAME: 2338 return Rectangle( aPos, 2339 Size( nMaxBmpWidth, aBound.GetHeight() )); 2340 2341 case VIEWMODE_TEXT: 2342 return Rectangle( aPos, aBound.GetSize() ); 2343 2344 default: 2345 { 2346 Rectangle aRect; 2347 return aRect; 2348 } 2349 } 2350 } 2351 2352 Rectangle SvImpIconView::CalcTextRect( SvLBoxEntry* pEntry, 2353 SvLBoxString* pItem, const Point* pPos, sal_Bool bForInplaceEdit, 2354 SvIcnVwDataEntry* pViewData ) 2355 { 2356 long nBmpHeight, nBmpWidth; 2357 2358 if( !pItem ) 2359 pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 2360 2361 if( !pViewData ) 2362 pViewData = ICNVIEWDATA(pEntry); 2363 2364 Size aTextSize( GetItemSize( pView, pEntry, pItem, pViewData )); 2365 aTextSize.Width() += 2*LROFFS_TEXT; 2366 2367 Size aContextBmpSize(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry)); 2368 Rectangle aBound = GetBoundingRect( pEntry, pViewData ); 2369 if( pPos ) 2370 aBound.SetPos( *pPos ); 2371 Point aPos( aBound.TopLeft() ); 2372 2373 switch( nViewMode ) 2374 { 2375 case VIEWMODE_ICON: 2376 nBmpHeight = aContextBmpSize.Height(); 2377 if( nBmpHeight < nMaxBmpHeight ) 2378 nBmpHeight = nMaxBmpHeight; 2379 aPos.Y() += nBmpHeight; 2380 2381 // beim Inplace-Editieren, spendieren wir ein bisschen mehr Platz 2382 if( bForInplaceEdit ) 2383 { 2384 // 20% rauf 2385 long nMinWidth = (( (aContextBmpSize.Width()*10) / 100 ) * 2 ) + 2386 aContextBmpSize.Width(); 2387 if( nMinWidth > aBound.GetWidth() ) 2388 nMinWidth = aBound.GetWidth(); 2389 2390 if( aTextSize.Width() < nMinWidth ) 2391 aTextSize.Width() = nMinWidth; 2392 2393 // beim Inplace-Ed. darfs auch untere Eintraege ueberlappen 2394 Rectangle aMaxGridTextRect = CalcMaxTextRect(pEntry, pViewData); 2395 Size aOptSize = aMaxGridTextRect.GetSize(); 2396 if( aOptSize.Height() > aTextSize.Height() ) 2397 aTextSize.Height() = aOptSize.Height(); 2398 } 2399 2400 2401 aPos.X() += ( aBound.GetWidth() - aTextSize.Width() ) / 2; 2402 break; 2403 2404 case VIEWMODE_NAME: 2405 nBmpWidth = aContextBmpSize.Width(); 2406 if( nBmpWidth < nMaxBmpWidth ) 2407 nBmpWidth = nMaxBmpWidth; 2408 aPos.X() += nBmpWidth; 2409 // vertikal ausrichten 2410 aPos.Y() += ( nBmpWidth - aTextSize.Height() ) / 2; 2411 break; 2412 } 2413 2414 Rectangle aRect( aPos, aTextSize ); 2415 // KNALLT BEIM D&D, WENN GECLIPPT WIRD (In DrawText von Thomas) 2416 // ClipAtVirtOutRect( aRect ); 2417 return aRect; 2418 } 2419 2420 2421 long SvImpIconView::CalcBoundingWidth( SvLBoxEntry* pEntry, 2422 const SvIcnVwDataEntry* pViewData ) const 2423 { 2424 DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP),"No Bitmaps"); 2425 DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),"No Text"); 2426 long nStringWidth = GetItemSize( pView, pEntry, pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),pViewData).Width(); 2427 nStringWidth += 2*LROFFS_TEXT; 2428 long nBmpWidth = pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry).Width(); 2429 long nWidth = 0; 2430 2431 switch( nViewMode ) 2432 { 2433 case VIEWMODE_ICON: 2434 nWidth = Max( nStringWidth, nBmpWidth ); 2435 nWidth = Max( nWidth, nMaxBmpWidth ); 2436 break; 2437 2438 case VIEWMODE_NAME: 2439 nWidth = Max( nBmpWidth, nMaxBmpWidth ); 2440 nWidth += NAMEVIEW_OFFS_BMP_STRING; // Abstand Bitmap String 2441 nWidth += nStringWidth; 2442 break; 2443 2444 case VIEWMODE_TEXT: 2445 nWidth = nStringWidth; 2446 break; 2447 } 2448 return nWidth; 2449 } 2450 2451 long SvImpIconView::CalcBoundingHeight( SvLBoxEntry* pEntry, 2452 const SvIcnVwDataEntry* pViewData ) const 2453 { 2454 DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP),"No Bitmaps"); 2455 DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),"No Text"); 2456 long nStringHeight = GetItemSize(pView,pEntry,pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),pViewData).Height(); 2457 long nBmpHeight = pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry).Height(); 2458 long nHeight = 0; 2459 2460 switch( nViewMode ) 2461 { 2462 case VIEWMODE_ICON: 2463 nHeight = Max( nBmpHeight, nMaxBmpHeight ); 2464 nHeight += ICONVIEW_OFFS_BMP_STRING; // Abstand Bitmap String 2465 nHeight += nStringHeight; 2466 break; 2467 2468 case VIEWMODE_NAME: 2469 nHeight = Max( nBmpHeight, nMaxBmpHeight ); 2470 nHeight = Max( nHeight, nStringHeight ); 2471 break; 2472 2473 case VIEWMODE_TEXT: 2474 nHeight = nStringHeight; 2475 break; 2476 } 2477 if( nHeight > nMaxBoundHeight ) 2478 { 2479 ((SvImpIconView*)this)->nMaxBoundHeight = nHeight; 2480 ((SvImpIconView*)this)->aHorSBar.SetLineSize( nHeight / 2 ); 2481 ((SvImpIconView*)this)->aVerSBar.SetLineSize( nHeight / 2 ); 2482 } 2483 return nHeight; 2484 } 2485 2486 Size SvImpIconView::CalcBoundingSize( SvLBoxEntry* pEntry, 2487 SvIcnVwDataEntry* pViewData ) const 2488 { 2489 if( !pViewData ) 2490 pViewData = ICNVIEWDATA(pEntry); 2491 return Size( CalcBoundingWidth(pEntry,pViewData), 2492 CalcBoundingHeight(pEntry,pViewData) ); 2493 } 2494 2495 void SvImpIconView::RecalcAllBoundingRects() 2496 { 2497 nMaxBoundHeight = 0; 2498 pZOrderList->Remove(0, pZOrderList->Count() ); 2499 SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); 2500 while( pEntry ) 2501 { 2502 FindBoundingRect( pEntry ); 2503 pZOrderList->Insert( pEntry, pZOrderList->Count() ); 2504 pEntry = pModel->NextSibling( pEntry ); 2505 } 2506 bMustRecalcBoundingRects = sal_False; 2507 AdjustScrollBars(); 2508 } 2509 2510 void SvImpIconView::RecalcAllBoundingRectsSmart() 2511 { 2512 nMaxBoundHeight = 0; 2513 pZOrderList->Remove(0, pZOrderList->Count() ); 2514 SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); 2515 while( pEntry ) 2516 { 2517 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2518 if( IsBoundingRectValid( pViewData->aRect )) 2519 { 2520 Size aBoundSize( pViewData->aRect.GetSize() ); 2521 if( aBoundSize.Height() > nMaxBoundHeight ) 2522 nMaxBoundHeight = aBoundSize.Height(); 2523 pZOrderList->Insert( pEntry, pZOrderList->Count() ); 2524 } 2525 else 2526 { 2527 FindBoundingRect( pEntry, pViewData ); 2528 } 2529 pZOrderList->Insert( pEntry, pZOrderList->Count() ); 2530 pEntry = pModel->NextSibling( pEntry ); 2531 } 2532 AdjustScrollBars(); 2533 } 2534 2535 void SvImpIconView::UpdateBoundingRects() 2536 { 2537 SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); 2538 while( pEntry ) 2539 { 2540 GetBoundingRect( pEntry ); 2541 pEntry = pModel->NextSibling( pEntry ); 2542 } 2543 } 2544 2545 void SvImpIconView::FindBoundingRect( SvLBoxEntry* pEntry, 2546 SvIcnVwDataEntry* pViewData ) 2547 { 2548 if( !pViewData ) 2549 pViewData = ICNVIEWDATA(pEntry); 2550 2551 Size aSize( CalcBoundingSize( pEntry, pViewData ) ); 2552 Point aPos; 2553 2554 DBG_ASSERT(!pViewData->IsEntryPosLocked(),"Locked entry pos in FindBoundingRect"); 2555 // damits in der IconView nicht drunter & drueber geht 2556 if( pViewData->IsEntryPosLocked() && IsBoundingRectValid(pViewData->aRect) ) 2557 { 2558 AdjustVirtSize( pViewData->aRect ); 2559 return; 2560 } 2561 2562 aPos = FindNextEntryPos( aSize ); 2563 2564 if( nFlags & F_GRIDMODE ) 2565 { 2566 Rectangle aGridRect( aPos, Size(nGridDX, nGridDY) ); 2567 pViewData->aGridRect = aGridRect; 2568 Center( pEntry, pViewData ); 2569 AdjustVirtSize( pViewData->aRect ); 2570 pImpCursor->SetGridUsed( pViewData->aRect ); 2571 } 2572 else 2573 { 2574 pViewData->aRect = Rectangle( aPos, aSize ); 2575 AdjustVirtSize( pViewData->aRect ); 2576 } 2577 } 2578 2579 2580 void SvImpIconView::SetCursor( SvLBoxEntry* pEntry ) 2581 { 2582 if( pEntry == pCursor ) 2583 return; 2584 2585 ShowCursor( sal_False ); 2586 if( pCursor ) 2587 { 2588 pView->SetEntryFocus( pCursor, sal_False ); 2589 if( pView->GetSelectionMode() == SINGLE_SELECTION ) 2590 pView->Select( pCursor, sal_False ); 2591 } 2592 pCursor = pEntry; 2593 ToTop( pCursor ); 2594 if( pCursor ) 2595 { 2596 pView->SetEntryFocus(pCursor, sal_True ); 2597 if( pView->GetSelectionMode() == SINGLE_SELECTION ) 2598 pView->Select( pCursor, sal_True ); 2599 ShowCursor( sal_True ); 2600 } 2601 } 2602 2603 2604 void SvImpIconView::ShowCursor( sal_Bool bShow ) 2605 { 2606 if( !pCursor || !bShow || !pView->HasFocus() ) 2607 { 2608 pView->HideFocus(); 2609 return; 2610 } 2611 Rectangle aRect ( CalcFocusRect( pCursor ) ); 2612 pView->ShowFocus( aRect ); 2613 } 2614 2615 2616 void SvImpIconView::HideDDIcon() 2617 { 2618 pView->Update(); 2619 ImpHideDDIcon(); 2620 pDDBufDev = pDDDev; 2621 pDDDev = 0; 2622 } 2623 2624 void SvImpIconView::ImpHideDDIcon() 2625 { 2626 if( pDDDev ) 2627 { 2628 Size aSize( pDDDev->GetOutputSizePixel() ); 2629 // pView restaurieren 2630 pView->DrawOutDev( aDDLastRectPos, aSize, Point(), aSize, *pDDDev ); 2631 } 2632 } 2633 2634 2635 void SvImpIconView::ShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPosPix ) 2636 { 2637 pView->Update(); 2638 if( pRefEntry != pDDRefEntry ) 2639 { 2640 DELETEZ(pDDDev); 2641 DELETEZ(pDDBufDev); 2642 } 2643 sal_Bool bSelected = pView->SvListView::Select( pRefEntry, sal_False ); 2644 if( !pDDDev ) 2645 { 2646 if( pDDBufDev ) 2647 { 2648 // nicht bei jedem Move ein Device anlegen, da dies besonders 2649 // auf Remote-Clients zu langsam ist 2650 pDDDev = pDDBufDev; 2651 pDDBufDev = 0; 2652 } 2653 else 2654 { 2655 pDDDev = new VirtualDevice( *pView ); 2656 pDDDev->SetFont( pView->GetFont() ); 2657 } 2658 } 2659 else 2660 { 2661 ImpHideDDIcon(); 2662 } 2663 const Rectangle& rRect = GetBoundingRect( pRefEntry ); 2664 pDDDev->SetOutputSizePixel( rRect.GetSize() ); 2665 2666 Point aPos( rPosPix ); 2667 CalcDocPos( aPos ); 2668 2669 Size aSize( pDDDev->GetOutputSizePixel() ); 2670 pDDRefEntry = pRefEntry; 2671 aDDLastEntryPos = aPos; 2672 aDDLastRectPos = aPos; 2673 2674 // Hintergrund sichern 2675 pDDDev->DrawOutDev( Point(), aSize, aPos, aSize, *pView ); 2676 // Icon in pView malen 2677 nFlags |= F_NO_EMPHASIS; 2678 PaintEntry( pRefEntry, aPos ); 2679 nFlags &= ~F_NO_EMPHASIS; 2680 if( bSelected ) 2681 pView->SvListView::Select( pRefEntry, sal_True ); 2682 } 2683 2684 void SvImpIconView::HideShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPosPix ) 2685 { 2686 /* In Notfaellen folgenden flackernden Code aktivieren: 2687 2688 HideDDIcon(); 2689 ShowDDIcon( pRefEntry, rPosPix ); 2690 return; 2691 */ 2692 if( !pDDDev ) 2693 { 2694 ShowDDIcon( pRefEntry, rPosPix ); 2695 return; 2696 } 2697 2698 if( pRefEntry != pDDRefEntry ) 2699 { 2700 HideDDIcon(); 2701 ShowDDIcon( pRefEntry, rPosPix ); 2702 return; 2703 } 2704 2705 Point aEmptyPoint; 2706 2707 Point aCurEntryPos( rPosPix ); 2708 CalcDocPos( aCurEntryPos ); 2709 2710 const Rectangle& rRect = GetBoundingRect( pRefEntry ); 2711 Size aEntrySize( rRect.GetSize() ); 2712 Rectangle aPrevEntryRect( aDDLastEntryPos, aEntrySize ); 2713 Rectangle aCurEntryRect( aCurEntryPos, aEntrySize ); 2714 2715 if( !aPrevEntryRect.IsOver( aCurEntryRect ) ) 2716 { 2717 HideDDIcon(); 2718 ShowDDIcon( pRefEntry, rPosPix ); 2719 return; 2720 } 2721 2722 // Ueberlappung des neuen und alten D&D-Pointers! 2723 2724 Rectangle aFullRect( aPrevEntryRect.Union( aCurEntryRect ) ); 2725 if( !pDDTempDev ) 2726 { 2727 pDDTempDev = new VirtualDevice( *pView ); 2728 pDDTempDev->SetFont( pView->GetFont() ); 2729 } 2730 2731 Size aFullSize( aFullRect.GetSize() ); 2732 Point aFullPos( aFullRect.TopLeft() ); 2733 2734 pDDTempDev->SetOutputSizePixel( aFullSize ); 2735 2736 // Hintergrund (mit dem alten D&D-Pointer!) sichern 2737 pDDTempDev->DrawOutDev( aEmptyPoint, aFullSize, aFullPos, aFullSize, *pView ); 2738 // den alten Buffer in den neuen Buffer pasten 2739 aDDLastRectPos = aDDLastRectPos - aFullPos; 2740 2741 pDDTempDev->DrawOutDev( 2742 aDDLastRectPos, 2743 pDDDev->GetOutputSizePixel(), 2744 aEmptyPoint, 2745 pDDDev->GetOutputSizePixel(), 2746 *pDDDev ); 2747 2748 // Swap 2749 VirtualDevice* pTemp = pDDDev; 2750 pDDDev = pDDTempDev; 2751 pDDTempDev = pTemp; 2752 2753 // in den restaurierten Hintergrund den neuen D&D-Pointer zeichnen 2754 pDDTempDev->SetOutputSizePixel( pDDDev->GetOutputSizePixel() ); 2755 pDDTempDev->DrawOutDev( 2756 aEmptyPoint, aFullSize, aEmptyPoint, aFullSize, *pDDDev ); 2757 Point aRelPos = aCurEntryPos - aFullPos; 2758 nFlags |= F_NO_EMPHASIS; 2759 PaintEntry( pRefEntry, aRelPos, 0, pDDTempDev ); 2760 nFlags &= ~F_NO_EMPHASIS; 2761 2762 aDDLastRectPos = aFullPos; 2763 aDDLastEntryPos = aCurEntryPos; 2764 2765 pView->DrawOutDev( 2766 aDDLastRectPos, 2767 pDDDev->GetOutputSizePixel(), 2768 aEmptyPoint, 2769 pDDDev->GetOutputSizePixel(), 2770 *pDDTempDev ); 2771 2772 sal_Bool bSelected = pView->SvListView::Select( pRefEntry, sal_False ); 2773 if( bSelected ) 2774 pView->SvListView::Select( pRefEntry, sal_True ); 2775 } 2776 2777 void SvImpIconView::ShowTargetEmphasis( SvLBoxEntry* pEntry, sal_Bool ) 2778 { 2779 CheckBoundingRects(); 2780 Rectangle aRect; 2781 if( pEntry != pCurParent && 2782 (pEntry->HasChilds() || pEntry->HasChildsOnDemand()) ) 2783 aRect = CalcBmpRect( pEntry ); 2784 else 2785 { 2786 aRect.SetSize( aOutputSize ); 2787 const MapMode& rMapMode = pView->GetMapMode(); 2788 Point aOrigin( rMapMode.GetOrigin()); 2789 aOrigin *= -1; // in Doc-Koord wandeln 2790 aRect.SetPos( aOrigin ); 2791 aRect.Left()++; aRect.Top()++; 2792 aRect.Right()--; aRect.Bottom()--; 2793 } 2794 ImpDrawXORRect( aRect ); 2795 } 2796 2797 sal_Bool SvImpIconView::NotifyMoving( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, 2798 SvLBoxEntry*& rpNewPar, sal_uLong& rNewChildPos ) 2799 { 2800 if( pTarget == pCurParent && pModel->GetParent(pEntry) == pCurParent ) 2801 { 2802 // D&D innerhalb einer Childlist 2803 StopEditTimer(); 2804 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2805 Size aSize( pViewData->aRect.GetSize() ); 2806 Point aNewPos = FindNextEntryPos( aSize ); 2807 AdjustVirtSize( Rectangle( aNewPos, aSize ) ); 2808 SetEntryPosition( pEntry, aNewPos, sal_False, sal_True ); 2809 return sal_False; 2810 } 2811 return pView->SvLBox::NotifyMoving(pTarget,pEntry,rpNewPar,rNewChildPos); 2812 } 2813 2814 sal_Bool SvImpIconView::NotifyCopying( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, 2815 SvLBoxEntry*& rpNewParent, sal_uLong& rNewChildPos ) 2816 { 2817 return pView->SvLBox::NotifyCopying(pTarget,pEntry,rpNewParent,rNewChildPos); 2818 } 2819 2820 void SvImpIconView::WriteDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo) 2821 { 2822 SvLBoxEntry* pCurEntry = GetCurEntry(); 2823 Point aEntryPos; 2824 if( pCurEntry ) 2825 { 2826 aEntryPos = rPos; 2827 aEntryPos -= GetEntryPosition( pCurEntry ); 2828 } 2829 pInfo->nMouseRelX = aEntryPos.X(); 2830 pInfo->nMouseRelY = aEntryPos.Y(); 2831 } 2832 2833 void SvImpIconView::ReadDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo ) 2834 { 2835 Point aDropPos( rPos ); 2836 aDropPos.X() -= pInfo->nMouseRelX; 2837 aDropPos.Y() -= pInfo->nMouseRelY; 2838 SetNextEntryPos( aDropPos ); 2839 } 2840 2841 void SvImpIconView::InvalidateBoundingRect( SvLBoxEntry* pEntry ) 2842 { 2843 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 2844 InvalidateBoundingRect( pViewData->aRect ); 2845 } 2846 2847 void SvImpIconView::PrepareCommandEvent( const Point& rPt ) 2848 { 2849 aMouseMoveTimer.Stop(); 2850 StopEditTimer(); 2851 nFlags |= F_CMD_ARRIVED; 2852 SvLBoxEntry* pEntry = pView->GetEntry( rPt, sal_True ); 2853 if( (nFlags & F_DOWN_CTRL) && pEntry && !pView->IsSelected(pEntry) ) 2854 pView->Select( pEntry, sal_True ); 2855 nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); 2856 } 2857 2858 void SvImpIconView::SttDrag( const Point& rPos ) 2859 { 2860 PrepareCommandEvent( rPos ); 2861 2862 nFlags |= F_DRAG_SOURCE; 2863 ShowCursor( sal_False ); 2864 } 2865 2866 void SvImpIconView::EndDrag() 2867 { 2868 ShowCursor( sal_True ); 2869 nFlags &= (~F_DRAG_SOURCE); 2870 } 2871 2872 void SvImpIconView::ToTop( SvLBoxEntry* pEntry ) 2873 { 2874 DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"ToTop:ZOrder?"); 2875 if( pZOrderList->GetObject( pZOrderList->Count() -1 ) != pEntry ) 2876 { 2877 sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry ); 2878 pZOrderList->Remove( nPos, 1 ); 2879 pZOrderList->Insert( pEntry, pZOrderList->Count() ); 2880 } 2881 } 2882 2883 void SvImpIconView::SetCurParent( SvLBoxEntry* pNewParent ) 2884 { 2885 Clear(); 2886 pCurParent = pNewParent; 2887 ImpArrange(); 2888 } 2889 2890 void SvImpIconView::ClipAtVirtOutRect( Rectangle& rRect ) const 2891 { 2892 if( rRect.Bottom() >= aVirtOutputSize.Height() ) 2893 rRect.Bottom() = aVirtOutputSize.Height() - 1; 2894 if( rRect.Right() >= aVirtOutputSize.Width() ) 2895 rRect.Right() = aVirtOutputSize.Width() - 1; 2896 if( rRect.Top() < 0 ) 2897 rRect.Top() = 0; 2898 if( rRect.Left() < 0 ) 2899 rRect.Left() = 0; 2900 } 2901 2902 // rRect: Bereich des Dokumentes (in Dokumentkoordinaten), der 2903 // sichtbar gemacht werden soll. 2904 // bScrBar == sal_True: Das Rect wurde aufgrund eines ScrollBar-Events berechnet 2905 2906 void SvImpIconView::MakeVisible( const Rectangle& rRect, sal_Bool bScrBar ) 2907 { 2908 Rectangle aRect( rRect ); 2909 ClipAtVirtOutRect( aRect ); 2910 MapMode aMapMode( pView->GetMapMode() ); 2911 Point aOrigin( aMapMode.GetOrigin() ); 2912 // in Dokumentkoordinate umwandeln 2913 aOrigin *= -1; 2914 2915 Rectangle aOutputArea( aOrigin, aOutputSize ); 2916 if( aOutputArea.IsInside( aRect ) ) 2917 return; // ist schon sichtbar 2918 2919 long nDy; 2920 if( aRect.Top() < aOutputArea.Top() ) 2921 { 2922 // nach oben scrollen (nDy < 0) 2923 nDy = aRect.Top() - aOutputArea.Top(); 2924 } 2925 else if( aRect.Bottom() > aOutputArea.Bottom() ) 2926 { 2927 // nach unten scrollen (nDy > 0) 2928 nDy = aRect.Bottom() - aOutputArea.Bottom(); 2929 } 2930 else 2931 nDy = 0; 2932 2933 long nDx; 2934 if( aRect.Left() < aOutputArea.Left() ) 2935 { 2936 // nach links scrollen (nDx < 0) 2937 nDx = aRect.Left() - aOutputArea.Left(); 2938 } 2939 else if( aRect.Right() > aOutputArea.Right() ) 2940 { 2941 // nach rechts scrollen (nDx > 0) 2942 nDx = aRect.Right() - aOutputArea.Right(); 2943 } 2944 else 2945 nDx = 0; 2946 2947 aOrigin.X() += nDx; 2948 aOrigin.Y() += nDy; 2949 aOutputArea.SetPos( aOrigin ); 2950 2951 pView->Update(); 2952 2953 // Origin fuer SV invertieren (damit wir in 2954 // Dokumentkoordinaten scrollen/painten koennen) 2955 aOrigin *= -1; 2956 aMapMode.SetOrigin( aOrigin ); 2957 pView->SetMapMode( aMapMode ); 2958 2959 // in umgekehrte Richtung scrollen! 2960 pView->Control::Scroll( -nDx, -nDy, aOutputArea, sal_True ); 2961 if( aHorSBar.IsVisible() || aVerSBar.IsVisible() ) 2962 { 2963 if( !bScrBar ) 2964 { 2965 aOrigin *= -1; 2966 // Thumbs korrigieren 2967 if(aHorSBar.IsVisible() && aHorSBar.GetThumbPos() != aOrigin.X()) 2968 aHorSBar.SetThumbPos( aOrigin.X() ); 2969 if(aVerSBar.IsVisible() && aVerSBar.GetThumbPos() != aOrigin.Y()) 2970 aVerSBar.SetThumbPos( aOrigin.Y() ); 2971 } 2972 } 2973 // pruefen, ob ScrollBars noch benoetigt werden 2974 CheckScrollBars(); 2975 pView->Update(); 2976 } 2977 2978 2979 SvLBoxEntry* SvImpIconView::GetNewCursor() 2980 { 2981 SvLBoxEntry* pNewCursor; 2982 if( pCursor ) 2983 { 2984 pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_False ); 2985 if( !pNewCursor ) 2986 { 2987 pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_True ); 2988 if( !pNewCursor ) 2989 { 2990 pNewCursor = pImpCursor->GoUpDown( pCursor, sal_False ); 2991 if( !pNewCursor ) 2992 pNewCursor = pImpCursor->GoUpDown( pCursor, sal_True ); 2993 } 2994 } 2995 } 2996 else 2997 pNewCursor = pModel->FirstChild( pCurParent ); 2998 DBG_ASSERT(!pNewCursor|| (pCursor&&pCursor!=pNewCursor),"GetNewCursor failed"); 2999 return pNewCursor; 3000 } 3001 3002 3003 sal_uInt16 SvImpIconView:: GetSelectionCount() const 3004 { 3005 sal_uInt16 nSelected = 0; 3006 SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent); 3007 while( pEntry ) 3008 { 3009 if( pView->IsSelected( pEntry ) ) 3010 nSelected++; 3011 pEntry = pModel->NextSibling( pEntry ); 3012 } 3013 return nSelected; 3014 } 3015 3016 3017 void SvImpIconView::ToggleSelection( SvLBoxEntry* pEntry ) 3018 { 3019 sal_Bool bSel; 3020 if( pView->IsSelected( pEntry ) ) 3021 bSel = sal_False; 3022 else 3023 bSel = sal_True; 3024 pView->Select( pEntry, bSel ); 3025 } 3026 3027 void SvImpIconView::DeselectAllBut( SvLBoxEntry* pThisEntryNot ) 3028 { 3029 ClearSelectedRectList(); 3030 SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); 3031 while( pEntry ) 3032 { 3033 if( pEntry != pThisEntryNot && pView->IsSelected( pEntry )) 3034 pView->Select( pEntry, sal_False ); 3035 pEntry = pModel->NextSibling( pEntry ); 3036 } 3037 } 3038 3039 #define ICN_ROWS 50 3040 #define ICN_COLS 30 3041 3042 ImpIcnCursor::ImpIcnCursor( SvImpIconView* pOwner ) 3043 { 3044 pView = pOwner; 3045 pColumns = 0; 3046 pRows = 0; 3047 pCurEntry = 0; 3048 nDeltaWidth = 0; 3049 nDeltaHeight= 0; 3050 nCols = 0; 3051 nRows = 0; 3052 nGridCols = 0; 3053 nGridRows = 0; 3054 pGridMap = 0; 3055 } 3056 3057 ImpIcnCursor::~ImpIcnCursor() 3058 { 3059 delete[] pColumns; 3060 delete[] pRows; 3061 delete pGridMap; 3062 } 3063 3064 sal_uInt16 ImpIcnCursor::GetSortListPos( SvPtrarr* pList, long nValue, 3065 int bVertical ) 3066 { 3067 sal_uInt16 nCount = (sal_uInt16)pList->Count(); 3068 if( !nCount ) 3069 return 0; 3070 3071 sal_uInt16 nCurPos = 0; 3072 long nPrevValue = LONG_MIN; 3073 while( nCount ) 3074 { 3075 const Rectangle& rRect= 3076 pView->GetBoundingRect((SvLBoxEntry*)(pList->GetObject(nCurPos))); 3077 long nCurValue; 3078 if( bVertical ) 3079 nCurValue = rRect.Top(); 3080 else 3081 nCurValue = rRect.Left(); 3082 if( nValue >= nPrevValue && nValue <= nCurValue ) 3083 return (sal_uInt16)nCurPos; 3084 nPrevValue = nCurValue; 3085 nCount--; 3086 nCurPos++; 3087 } 3088 return pList->Count(); 3089 } 3090 3091 void ImpIcnCursor::ImplCreate() 3092 { 3093 pView->CheckBoundingRects(); 3094 DBG_ASSERT(pColumns==0&&pRows==0,"ImplCreate: Not cleared"); 3095 3096 SetDeltas(); 3097 3098 pColumns = new SvPtrarr[ nCols ]; 3099 pRows = new SvPtrarr[ nRows ]; 3100 3101 DELETEZ(pGridMap); 3102 3103 SvLBoxTreeList* pModel = pView->pModel; 3104 SvLBoxEntry* pEntry = pModel->FirstChild( pView->pCurParent ); 3105 while( pEntry ) 3106 { 3107 SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); 3108 // const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3109 Rectangle rRect( pView->CalcBmpRect( pEntry,0,pViewData ) ); 3110 short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / nDeltaHeight ); 3111 short nX = (short)( ((rRect.Left()+rRect.Right())/2) / nDeltaWidth ); 3112 3113 // Rundungsfehler abfangen 3114 if( nY >= nRows ) 3115 nY = sal::static_int_cast< short >(nRows - 1); 3116 if( nX >= nCols ) 3117 nX = sal::static_int_cast< short >(nCols - 1); 3118 3119 sal_uInt16 nIns = GetSortListPos( &pColumns[nX], rRect.Top(), sal_True ); 3120 pColumns[ nX ].Insert( pEntry, nIns ); 3121 3122 nIns = GetSortListPos( &pRows[nY], rRect.Left(), sal_False ); 3123 pRows[ nY ].Insert( pEntry, nIns ); 3124 3125 pViewData->nX = nX; 3126 pViewData->nY = nY; 3127 3128 pEntry = pModel->NextSibling( pEntry ); 3129 } 3130 } 3131 3132 void ImpIcnCursor::CreateGridMap() 3133 { 3134 if( pGridMap ) 3135 return; 3136 3137 const Size& rSize = pView->aVirtOutputSize; 3138 long nWidth = rSize.Width(); 3139 if( nWidth < pView->nMaxVirtWidth ) 3140 nWidth = pView->nMaxVirtWidth; 3141 nWidth -= 2*LROFFS_WINBORDER; 3142 if( nWidth <= 0 ) 3143 nWidth = 1; 3144 3145 nGridDX = pView->nGridDX; 3146 nGridDY = pView->nGridDY; 3147 3148 // Hinweis: Wegen der Abrundung bei Berechnung von nGridCols 3149 // ist es moeglich, dass Eintrage nicht im Grid liegen. Diese 3150 // wurden typischerweise manuell verschoben und gelockt 3151 nGridCols = nWidth / nGridDX; 3152 if( !nGridCols ) nGridCols = 1; 3153 3154 nGridRows = rSize.Height() / nGridDY; 3155 // nRows nicht abrunden, da zur Vermeidung von Ueberlappungen 3156 // das gesamte BoundingRect des Eintrags zur Markierung im Grid 3157 // herangezogen wird. 3158 if( (nGridRows * nGridDY) < rSize.Height() ) 3159 nGridRows++; 3160 else if( !nGridRows ) 3161 nGridRows = 1; 3162 3163 //XXX 3164 //nGridRows += 50; // in fuenfziger-Schritten 3165 3166 pGridMap = new sal_Bool[ nGridRows*nGridCols]; 3167 memset( (void*)pGridMap, 0, nGridRows*nGridCols ); 3168 3169 SvLBoxTreeList* pModel = pView->pModel; 3170 SvLBoxEntry* pEntry = pModel->FirstChild( pView->pCurParent ); 3171 while( pEntry ) 3172 { 3173 SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); 3174 const Rectangle& rRect = pViewData->aRect; 3175 // nur, wenn der Entry schon plaziert ist 3176 if( pView->IsBoundingRectValid( rRect )) 3177 { 3178 // Alle vom Eintrag beruehrten Grids kennzeichnen 3179 SetGridUsed( pView->GetBoundingRect( pEntry, pViewData ) ); 3180 } 3181 pEntry = pModel->NextSibling( pEntry ); 3182 } 3183 } 3184 3185 sal_Bool ImpIcnCursor::GetGrid( const Point& rDocPos, sal_uInt16& rGridX, sal_uInt16& rGridY ) const 3186 { 3187 Point aPos( rDocPos ); 3188 aPos.X() -= LROFFS_WINBORDER; 3189 aPos.Y() -= TBOFFS_WINBORDER; 3190 rGridX = (sal_uInt16)(aPos.X() / nGridDX); 3191 rGridY = (sal_uInt16)(aPos.Y() / nGridDY); 3192 sal_Bool bInGrid = sal_True; 3193 if( rGridX >= nGridCols ) 3194 { 3195 rGridX = sal::static_int_cast< sal_uInt16 >(nGridCols - 1); 3196 bInGrid = sal_False; 3197 } 3198 if( rGridY >= nGridRows ) 3199 { 3200 rGridY = sal::static_int_cast< sal_uInt16 >(nGridRows - 1); 3201 if( !bInGrid ) 3202 return sal_False; // beide Koordinaten nicht im Grid 3203 } 3204 return sal_True; 3205 } 3206 3207 void ImpIcnCursor::SetGridUsed( const Rectangle& rRect, sal_Bool bUsed ) 3208 { 3209 CreateGridMap(); 3210 sal_uInt16 nTLX, nTLY, nBRX, nBRY; 3211 3212 sal_Bool bTLInGrid = GetGrid( rRect.TopLeft(), nTLX, nTLY ); 3213 sal_Bool bBRInGrid = GetGrid( rRect.BottomRight(), nBRX, nBRY ); 3214 3215 if( !bTLInGrid && !bBRInGrid ) 3216 return; 3217 3218 for( sal_uInt16 nCurY = nTLY; nCurY <= nBRY; nCurY++ ) 3219 { 3220 for( sal_uInt16 nCurX = nTLX; nCurX <= nBRX; nCurX++ ) 3221 { 3222 SetGridUsed( nCurX, nCurY, bUsed ); 3223 } 3224 } 3225 } 3226 3227 void ImpIcnCursor::Clear( sal_Bool bGridToo ) 3228 { 3229 if( pColumns ) 3230 { 3231 delete[] pColumns; 3232 delete[] pRows; 3233 pColumns = 0; 3234 pRows = 0; 3235 pCurEntry = 0; 3236 nDeltaWidth = 0; 3237 nDeltaHeight = 0; 3238 } 3239 if( bGridToo && pGridMap ) 3240 { 3241 DELETEZ(pGridMap); 3242 nGridRows = 0; 3243 nGridCols = 0; 3244 } 3245 } 3246 3247 SvLBoxEntry* ImpIcnCursor::SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom, 3248 sal_uInt16, sal_Bool bDown, sal_Bool bSimple ) 3249 { 3250 DBG_ASSERT(pCurEntry,"SearchCol: No reference entry"); 3251 SvPtrarr* pList = &(pColumns[ nCol ]); 3252 sal_uInt16 nCount = pList->Count(); 3253 if( !nCount ) 3254 return 0; 3255 3256 const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry); 3257 3258 if( bSimple ) 3259 { 3260 sal_uInt16 nListPos = pList->GetPos( pCurEntry ); 3261 DBG_ASSERT(nListPos!=0xffff,"Entry not in Col-List"); 3262 if( bDown ) 3263 { 3264 while( nListPos < nCount-1 ) 3265 { 3266 nListPos++; 3267 SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); 3268 const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3269 if( rRect.Top() > rRefRect.Top() ) 3270 return pEntry; 3271 } 3272 return 0; 3273 } 3274 else 3275 { 3276 while( nListPos ) 3277 { 3278 nListPos--; 3279 if( nListPos < nCount ) 3280 { 3281 SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); 3282 const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3283 if( rRect.Top() < rRefRect.Top() ) 3284 return pEntry; 3285 } 3286 } 3287 return 0; 3288 } 3289 } 3290 3291 if( nTop > nBottom ) 3292 { 3293 sal_uInt16 nTemp = nTop; 3294 nTop = nBottom; 3295 nBottom = nTemp; 3296 } 3297 long nMinDistance = LONG_MAX; 3298 SvLBoxEntry* pResult = 0; 3299 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 3300 { 3301 SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur )); 3302 if( pEntry != pCurEntry ) 3303 { 3304 SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); 3305 sal_uInt16 nY = pViewData->nY; 3306 if( nY >= nTop && nY <= nBottom ) 3307 { 3308 const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3309 long nDistance = rRect.Top() - rRefRect.Top(); 3310 if( nDistance < 0 ) 3311 nDistance *= -1; 3312 if( nDistance && nDistance < nMinDistance ) 3313 { 3314 nMinDistance = nDistance; 3315 pResult = pEntry; 3316 } 3317 } 3318 } 3319 } 3320 return pResult; 3321 } 3322 3323 SvLBoxEntry* ImpIcnCursor::SearchRow(sal_uInt16 nRow,sal_uInt16 nLeft,sal_uInt16 nRight, 3324 sal_uInt16, sal_Bool bRight, sal_Bool bSimple ) 3325 { 3326 DBG_ASSERT(pCurEntry,"SearchRow: No reference entry"); 3327 SvPtrarr* pList = &(pRows[ nRow ]); 3328 sal_uInt16 nCount = pList->Count(); 3329 if( !nCount ) 3330 return 0; 3331 3332 const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry); 3333 3334 if( bSimple ) 3335 { 3336 sal_uInt16 nListPos = pList->GetPos( pCurEntry ); 3337 DBG_ASSERT(nListPos!=0xffff,"Entry not in Row-List"); 3338 if( bRight ) 3339 { 3340 while( nListPos < nCount-1 ) 3341 { 3342 nListPos++; 3343 SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); 3344 const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3345 if( rRect.Left() > rRefRect.Left() ) 3346 return pEntry; 3347 } 3348 return 0; 3349 } 3350 else 3351 { 3352 while( nListPos ) 3353 { 3354 nListPos--; 3355 if( nListPos < nCount ) 3356 { 3357 SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); 3358 const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3359 if( rRect.Left() < rRefRect.Left() ) 3360 return pEntry; 3361 } 3362 } 3363 return 0; 3364 } 3365 3366 } 3367 if( nRight < nLeft ) 3368 { 3369 sal_uInt16 nTemp = nRight; 3370 nRight = nLeft; 3371 nLeft = nTemp; 3372 } 3373 long nMinDistance = LONG_MAX; 3374 SvLBoxEntry* pResult = 0; 3375 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 3376 { 3377 SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur )); 3378 if( pEntry != pCurEntry ) 3379 { 3380 SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); 3381 sal_uInt16 nX = pViewData->nX; 3382 if( nX >= nLeft && nX <= nRight ) 3383 { 3384 const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3385 long nDistance = rRect.Left() - rRefRect.Left(); 3386 if( nDistance < 0 ) 3387 nDistance *= -1; 3388 if( nDistance && nDistance < nMinDistance ) 3389 { 3390 nMinDistance = nDistance; 3391 pResult = pEntry; 3392 } 3393 } 3394 } 3395 } 3396 return pResult; 3397 } 3398 3399 3400 3401 /* 3402 Sucht ab dem uebergebenen Eintrag den naechsten rechts- bzw. 3403 linksstehenden. Suchverfahren am Beispiel bRight = sal_True: 3404 3405 c 3406 b c 3407 a b c 3408 S 1 1 1 ====> Suchrichtung 3409 a b c 3410 b c 3411 c 3412 3413 S : Startposition 3414 1 : erstes Suchrechteck 3415 a,b,c : 2., 3., 4. Suchrechteck 3416 */ 3417 3418 SvLBoxEntry* ImpIcnCursor::GoLeftRight( SvLBoxEntry* pIcnEntry, sal_Bool bRight ) 3419 { 3420 SvLBoxEntry* pResult; 3421 pCurEntry = pIcnEntry; 3422 Create(); 3423 SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pIcnEntry); 3424 sal_uInt16 nY = pViewData->nY; 3425 sal_uInt16 nX = pViewData->nX; 3426 DBG_ASSERT(nY< nRows,"GoLeftRight:Bad column"); 3427 DBG_ASSERT(nX< nCols,"GoLeftRight:Bad row"); 3428 // Nachbar auf gleicher Zeile ? 3429 if( bRight ) 3430 pResult = SearchRow( 3431 nY, nX, sal::static_int_cast< sal_uInt16 >(nCols-1), nX, sal_True, sal_True ); 3432 else 3433 pResult = SearchRow( nY, nX ,0, nX, sal_False, sal_True ); 3434 if( pResult ) 3435 return pResult; 3436 3437 long nCurCol = nX; 3438 3439 long nColOffs, nLastCol; 3440 if( bRight ) 3441 { 3442 nColOffs = 1; 3443 nLastCol = nCols; 3444 } 3445 else 3446 { 3447 nColOffs = -1; 3448 nLastCol = -1; // 0-1 3449 } 3450 3451 sal_uInt16 nRowMin = nY; 3452 sal_uInt16 nRowMax = nY; 3453 do 3454 { 3455 SvLBoxEntry* pEntry = SearchCol((sal_uInt16)nCurCol,nRowMin,nRowMax,nY,sal_True, sal_False); 3456 if( pEntry ) 3457 return pEntry; 3458 if( nRowMin ) 3459 nRowMin--; 3460 if( nRowMax < (nRows-1)) 3461 nRowMax++; 3462 nCurCol += nColOffs; 3463 } while( nCurCol != nLastCol ); 3464 return 0; 3465 } 3466 3467 SvLBoxEntry* ImpIcnCursor::GoUpDown( SvLBoxEntry* pIcnEntry, sal_Bool bDown) 3468 { 3469 SvLBoxEntry* pResult; 3470 pCurEntry = pIcnEntry; 3471 Create(); 3472 SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pIcnEntry); 3473 sal_uInt16 nY = pViewData->nY; 3474 sal_uInt16 nX = pViewData->nX; 3475 DBG_ASSERT(nY<nRows,"GoUpDown:Bad column"); 3476 DBG_ASSERT(nX<nCols,"GoUpDown:Bad row"); 3477 3478 // Nachbar in gleicher Spalte ? 3479 if( bDown ) 3480 pResult = SearchCol( 3481 nX, nY, sal::static_int_cast< sal_uInt16 >(nRows-1), nY, sal_True, sal_True ); 3482 else 3483 pResult = SearchCol( nX, nY ,0, nY, sal_False, sal_True ); 3484 if( pResult ) 3485 return pResult; 3486 3487 long nCurRow = nY; 3488 3489 long nRowOffs, nLastRow; 3490 if( bDown ) 3491 { 3492 nRowOffs = 1; 3493 nLastRow = nRows; 3494 } 3495 else 3496 { 3497 nRowOffs = -1; 3498 nLastRow = -1; // 0-1 3499 } 3500 3501 sal_uInt16 nColMin = nX; 3502 sal_uInt16 nColMax = nX; 3503 do 3504 { 3505 SvLBoxEntry* pEntry = SearchRow((sal_uInt16)nCurRow,nColMin,nColMax,nX,sal_True, sal_False); 3506 if( pEntry ) 3507 return pEntry; 3508 if( nColMin ) 3509 nColMin--; 3510 if( nColMax < (nCols-1)) 3511 nColMax++; 3512 nCurRow += nRowOffs; 3513 } while( nCurRow != nLastRow ); 3514 return 0; 3515 } 3516 3517 void ImpIcnCursor::SetDeltas() 3518 { 3519 const Size& rSize = pView->aVirtOutputSize; 3520 if( pView->nFlags & F_GRIDMODE ) 3521 { 3522 nGridDX = pView->nGridDX; 3523 nGridDY = pView->nGridDY; 3524 } 3525 else 3526 { 3527 nGridDX = 20; 3528 nGridDY = 20; 3529 } 3530 nCols = rSize.Width() / nGridDX; 3531 if( !nCols ) 3532 nCols = 1; 3533 nRows = rSize.Height() / nGridDY; 3534 if( (nRows * nGridDY) < rSize.Height() ) 3535 nRows++; 3536 if( !nRows ) 3537 nRows = 1; 3538 3539 nDeltaWidth = (short)(rSize.Width() / nCols); 3540 nDeltaHeight = (short)(rSize.Height() / nRows); 3541 if( !nDeltaHeight ) 3542 { 3543 nDeltaHeight = 1; 3544 DBG_WARNING("SetDeltas:Bad height"); 3545 } 3546 if( !nDeltaWidth ) 3547 { 3548 nDeltaWidth = 1; 3549 DBG_WARNING("SetDeltas:Bad width"); 3550 } 3551 } 3552 3553 3554 void ImpIcnCursor::ExpandGrid() 3555 { 3556 if( pGridMap ) 3557 { 3558 long nNewGridRows = nGridRows + 20; 3559 unsigned char* pTempMap = new unsigned char[ nNewGridRows * nGridCols ]; 3560 memcpy( pTempMap, pGridMap, nGridRows * nGridCols ); 3561 delete pGridMap; 3562 pGridMap = pTempMap; 3563 nGridRows = nNewGridRows; 3564 } 3565 } 3566 3567 sal_Bool ImpIcnCursor::FindEmptyGridRect( Rectangle& rRect ) 3568 { 3569 CreateGridMap(); 3570 sal_uInt16 nCount = (sal_uInt16)(nGridCols * nGridRows); 3571 if( !nCount ) 3572 return sal_False; 3573 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 3574 { 3575 if( !pGridMap[ nCur ] ) 3576 { 3577 sal_uInt16 nCol = (sal_uInt16)(nCur % nGridCols); 3578 sal_uInt16 nRow = (sal_uInt16)(nCur / nGridCols); 3579 rRect.Top() = nRow * nGridDY + TBOFFS_WINBORDER; 3580 rRect.Bottom() = rRect.Top() + nGridDY; 3581 rRect.Left() = nCol * nGridDX+ LROFFS_WINBORDER; 3582 rRect.Right() = rRect.Left() + nGridDX; 3583 SetGridUsed( nCol, nRow, sal_True ); 3584 3585 //XXX 3586 //if( nRow + 5 > nGridRows ) 3587 // ExpandGrid(); 3588 DBG_ASSERT(pGridMap[nCur],"SetGridUsed failed"); 3589 return sal_True; 3590 } 3591 } 3592 // Gridmap ist voll: Um eine Zeile erweitern 3593 rRect.Top() = nGridRows * nGridDY + TBOFFS_WINBORDER; 3594 rRect.Bottom() = rRect.Top() + nGridDY; 3595 rRect.Left() = LROFFS_WINBORDER; 3596 rRect.Right() = rRect.Left() + nGridDX; 3597 return sal_False; 3598 //XXX 3599 //ExpandGrid(); 3600 //return sal_True; 3601 } 3602 3603 void ImpIcnCursor::CreateGridAjustData( SvPtrarr& rLists, SvLBoxEntry* pRefEntry) 3604 { 3605 if( !pRefEntry ) 3606 { 3607 sal_uInt16 nAdjustRows = (sal_uInt16)(pView->aVirtOutputSize.Height() / pView->nGridDY); 3608 nAdjustRows++; // wg. Abrundung! 3609 3610 if( !nAdjustRows ) 3611 return; 3612 for( sal_uInt16 nCurList = 0; nCurList < nAdjustRows; nCurList++ ) 3613 { 3614 SvPtrarr* pRow = new SvPtrarr; 3615 rLists.Insert( (void*)pRow, nCurList ); 3616 } 3617 SvLBoxEntry* pEntry = pView->pModel->FirstChild( pView->pCurParent ); 3618 while( pEntry ) 3619 { 3620 const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3621 short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY ); 3622 sal_uInt16 nIns = GetSortListPos((SvPtrarr*)rLists[nY],rRect.Left(),sal_False); 3623 ((SvPtrarr*)rLists[ nY ])->Insert( pEntry, nIns ); 3624 pEntry = pView->pModel->NextSibling( pEntry ); 3625 } 3626 } 3627 else 3628 { 3629 // Aufbau eines hor. "Schlauchs" auf der RefEntry-Zeile 3630 3631 // UEBERLEGEN: BoundingRect nehmen wg. Ueberlappungen??? 3632 3633 Rectangle rRefRect( pView->CalcBmpRect( pRefEntry ) ); 3634 //const Rectangle& rRefRect = pView->GetBoundingRect( pRefEntry ); 3635 short nRefRow = (short)( ((rRefRect.Top()+rRefRect.Bottom())/2) / pView->nGridDY ); 3636 SvPtrarr* pRow = new SvPtrarr; 3637 rLists.Insert( (void*)pRow, 0 ); 3638 SvLBoxEntry* pEntry = pView->pModel->FirstChild( pView->pCurParent ); 3639 while( pEntry ) 3640 { 3641 Rectangle rRect( pView->CalcBmpRect(pEntry) ); 3642 //const Rectangle& rRect = pView->GetBoundingRect( pEntry ); 3643 short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY ); 3644 if( nY == nRefRow ) 3645 { 3646 sal_uInt16 nIns = GetSortListPos( pRow, rRect.Left(), sal_False ); 3647 pRow->Insert( pEntry, nIns ); 3648 } 3649 pEntry = pView->pModel->NextSibling( pEntry ); 3650 } 3651 } 3652 } 3653 3654 //static 3655 void ImpIcnCursor::DestroyGridAdjustData( SvPtrarr& rLists ) 3656 { 3657 sal_uInt16 nCount = rLists.Count(); 3658 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 3659 { 3660 SvPtrarr* pArr = (SvPtrarr*)rLists[ nCur ]; 3661 delete pArr; 3662 } 3663 rLists.Remove( 0, rLists.Count() ); 3664 } 3665 3666 void SvImpIconView::SetGrid( long nDX, long nDY ) 3667 { 3668 nGridDX = nDX; 3669 nGridDY = nDY; 3670 nFlags |= F_GRIDMODE; 3671 } 3672 3673 Rectangle SvImpIconView::CalcMaxTextRect( const SvLBoxEntry* pEntry, 3674 const SvIcnVwDataEntry* pViewData ) const 3675 { 3676 Rectangle aRect = pViewData->aGridRect; 3677 long nBmpHeight = ((SvLBoxEntry*)pEntry)->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,(SvLBoxEntry*)pEntry).Height(); 3678 aRect.Top() += nBmpHeight; 3679 aRect.Top() += ICONVIEW_OFFS_BMP_STRING; 3680 if( aRect.Top() > aRect.Bottom()) 3681 aRect.Top() = aRect.Bottom(); 3682 aRect.Left() += LROFFS_BOUND; 3683 aRect.Left()++; 3684 aRect.Right() -= LROFFS_BOUND; 3685 aRect.Right()--; 3686 if( aRect.Left() > aRect.Right()) 3687 aRect.Left() = aRect.Right(); 3688 if( GetTextMode( pEntry, pViewData ) == ShowTextFull ) 3689 aRect.Bottom() = LONG_MAX; 3690 return aRect; 3691 } 3692 3693 void SvImpIconView::Center( SvLBoxEntry* pEntry, 3694 SvIcnVwDataEntry* pViewData ) const 3695 { 3696 SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 3697 const String& rEntryText = pStringItem->GetText(); 3698 3699 Rectangle aTextRect = CalcMaxTextRect(pEntry,pViewData); 3700 aTextRect = GetTextRect( pView, aTextRect, rEntryText, DRAWTEXT_FLAGS ); 3701 pViewData->aTextSize = aTextRect.GetSize(); 3702 3703 pViewData->aRect = pViewData->aGridRect; 3704 Size aSize( CalcBoundingSize( pEntry, pViewData ) ); 3705 long nBorder = pViewData->aGridRect.GetWidth() - aSize.Width(); 3706 pViewData->aRect.Left() += nBorder / 2; 3707 pViewData->aRect.Right() -= nBorder / 2; 3708 pViewData->aRect.Bottom() = pViewData->aRect.Top() + aSize.Height(); 3709 } 3710 3711 3712 // Die Deltas entsprechen Offsets, um die die View auf dem Doc verschoben wird 3713 // links, hoch: Offsets < 0 3714 // rechts, runter: Offsets > 0 3715 void SvImpIconView::Scroll( long nDeltaX, long nDeltaY, sal_Bool bScrollBar ) 3716 { 3717 const MapMode& rMapMode = pView->GetMapMode(); 3718 Point aOrigin( rMapMode.GetOrigin() ); 3719 // in Dokumentkoordinate umwandeln 3720 aOrigin *= -1; 3721 aOrigin.Y() += nDeltaY; 3722 aOrigin.X() += nDeltaX; 3723 Rectangle aRect( aOrigin, aOutputSize ); 3724 MakeVisible( aRect, bScrollBar ); 3725 } 3726 3727 3728 const Size& SvImpIconView::GetItemSize( SvIconView* pIconView, 3729 SvLBoxEntry* pEntry, SvLBoxItem* pItem, const SvIcnVwDataEntry* pViewData) const 3730 { 3731 if( (nFlags & F_GRIDMODE) && pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) 3732 { 3733 if( !pViewData ) 3734 pViewData = ICNVIEWDATA(pEntry); 3735 return pViewData->aTextSize; 3736 } 3737 else 3738 return pItem->GetSize( pIconView, pEntry ); 3739 } 3740 3741 Rectangle SvImpIconView::CalcFocusRect( SvLBoxEntry* pEntry ) 3742 { 3743 #if !defined(OS2) 3744 SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 3745 DBG_ASSERT(pStringItem,"Text not set"); 3746 return CalcTextRect( pEntry, pStringItem ); 3747 #else 3748 return CalcBmpRect( pEntry ); 3749 #endif 3750 } 3751 3752 3753 void SvImpIconView::SelectRect( const Rectangle& rRect, sal_Bool bAdd, 3754 SvPtrarr* pOtherRects, short nBorderOffs ) 3755 { 3756 if( !pZOrderList || !pZOrderList->Count() ) 3757 return; 3758 3759 CheckBoundingRects(); 3760 pView->Update(); 3761 sal_uInt16 nCount = pZOrderList->Count(); 3762 3763 Rectangle aRect( rRect ); 3764 aRect.Justify(); 3765 if( nBorderOffs ) 3766 { 3767 aRect.Left() -= nBorderOffs; 3768 aRect.Right() += nBorderOffs; 3769 aRect.Top() -= nBorderOffs; 3770 aRect.Bottom() += nBorderOffs; 3771 } 3772 sal_Bool bCalcOverlap = (bAdd && pOtherRects && pOtherRects->Count()) ? sal_True : sal_False; 3773 3774 for( sal_uInt16 nPos = 0; nPos < nCount; nPos++ ) 3775 { 3776 SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nPos )); 3777 3778 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 3779 DBG_ASSERT(pViewData,"Entry not in model"); 3780 if( !IsBoundingRectValid( pViewData->aRect )) 3781 FindBoundingRect( pEntry, pViewData ); 3782 const Rectangle& rBoundRect = pViewData->aRect; 3783 sal_Bool bSelected = pViewData->IsSelected(); 3784 3785 sal_Bool bOverlaps; 3786 if( bCalcOverlap ) 3787 bOverlaps = IsOver( pOtherRects, rBoundRect ); 3788 else 3789 bOverlaps = sal_False; 3790 sal_Bool bOver = aRect.IsOver( rBoundRect ); 3791 3792 if( bOver && !bOverlaps ) 3793 { 3794 // Ist im neuen Selektionsrechteck und in keinem alten 3795 // => selektieren 3796 if( !bSelected ) 3797 pView->Select( pEntry, sal_True ); 3798 } 3799 else if( !bAdd ) 3800 { 3801 // ist ausserhalb des Selektionsrechtecks 3802 // => Selektion entfernen 3803 if( bSelected ) 3804 pView->Select( pEntry, sal_False ); 3805 } 3806 else if( bAdd && bOverlaps ) 3807 { 3808 // Der Eintrag befindet sich in einem alten (=>Aufspannen 3809 // mehrerer Rechtecke mit Ctrl!) Selektionsrechteck 3810 3811 // Hier ist noch ein Bug! Der Selektionsstatus eines Eintrags 3812 // in einem vorherigen Rechteck, muss restauriert werden, wenn 3813 // er vom aktuellen Selektionsrechteck beruehrt wurde, jetzt aber 3814 // nicht mehr in ihm liegt. Ich gehe hier der Einfachheit halber 3815 // pauschal davon aus, dass die Eintraege in den alten Rechtecken 3816 // alle selektiert sind. Ebenso ist es falsch, die Schnittmenge 3817 // nur zu deselektieren. 3818 // Loesungsmoeglichkeit: Snapshot der Selektion vor dem Auf- 3819 // spannen des Rechtecks merken 3820 if( rBoundRect.IsOver( rRect)) 3821 { 3822 // Schnittmenge zwischen alten Rects & aktuellem Rect desel. 3823 if( bSelected ) 3824 pView->Select( pEntry, sal_False ); 3825 } 3826 else 3827 { 3828 // Eintrag eines alten Rects selektieren 3829 if( !bSelected ) 3830 pView->Select( pEntry, sal_True ); 3831 } 3832 } 3833 else if( !bOver && bSelected ) 3834 { 3835 // Der Eintrag liegt voellig ausserhalb und wird deshalb desel. 3836 pView->Select( pEntry, sal_False ); 3837 } 3838 } 3839 pView->Update(); 3840 } 3841 3842 sal_Bool SvImpIconView::IsOver( SvPtrarr* pRectList, const Rectangle& rBoundRect ) const 3843 { 3844 sal_uInt16 nCount = pRectList->Count(); 3845 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 3846 { 3847 Rectangle* pRect = (Rectangle*)pRectList->GetObject( nCur ); 3848 if( rBoundRect.IsOver( *pRect )) 3849 return sal_True; 3850 } 3851 return sal_False; 3852 } 3853 3854 void SvImpIconView::AddSelectedRect( const Rectangle& rRect, short nBorderOffs ) 3855 { 3856 Rectangle* pRect = new Rectangle( rRect ); 3857 pRect->Justify(); 3858 if( nBorderOffs ) 3859 { 3860 pRect->Left() -= nBorderOffs; 3861 pRect->Right() += nBorderOffs; 3862 pRect->Top() -= nBorderOffs; 3863 pRect->Bottom() += nBorderOffs; 3864 } 3865 aSelectedRectList.Insert( (void*)pRect, aSelectedRectList.Count() ); 3866 } 3867 3868 void SvImpIconView::ClearSelectedRectList() 3869 { 3870 sal_uInt16 nCount = aSelectedRectList.Count(); 3871 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 3872 { 3873 Rectangle* pRect = (Rectangle*)aSelectedRectList.GetObject( nCur ); 3874 delete pRect; 3875 } 3876 aSelectedRectList.Remove( 0, aSelectedRectList.Count() ); 3877 } 3878 3879 3880 void SvImpIconView::DrawSelectionRect( const Rectangle& rRect ) 3881 { 3882 pView->HideTracking(); 3883 nFlags |= F_SELRECT_VISIBLE; 3884 pView->ShowTracking( rRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW ); 3885 aCurSelectionRect = rRect; 3886 } 3887 3888 void SvImpIconView::HideSelectionRect() 3889 { 3890 if( nFlags & F_SELRECT_VISIBLE ) 3891 { 3892 pView->HideTracking(); 3893 nFlags &= ~F_SELRECT_VISIBLE; 3894 } 3895 } 3896 3897 void SvImpIconView::ImpDrawXORRect( const Rectangle& rRect ) 3898 { 3899 RasterOp eOldOp = pView->GetRasterOp(); 3900 pView->SetRasterOp( ROP_XOR ); 3901 Color aOldColor = pView->GetFillColor(); 3902 pView->SetFillColor(); 3903 pView->DrawRect( rRect ); 3904 pView->SetFillColor( aOldColor ); 3905 pView->SetRasterOp( eOldOp ); 3906 } 3907 3908 void SvImpIconView::CalcScrollOffsets( const Point& rPosPixel, 3909 long& rX, long& rY, sal_Bool bInDragDrop, sal_uInt16 nBorderWidth) 3910 { 3911 // Scrolling der View, falls sich der Mauszeiger im Grenzbereich des 3912 // Fensters befindet 3913 long nPixelToScrollX = 0; 3914 long nPixelToScrollY = 0; 3915 Size aWndSize = aOutputSize; 3916 3917 nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Height()-1), (long)nBorderWidth )); 3918 nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Width()-1), (long)nBorderWidth )); 3919 3920 if ( rPosPixel.X() < nBorderWidth ) 3921 { 3922 if( bInDragDrop ) 3923 nPixelToScrollX = -DD_SCROLL_PIXEL; 3924 else 3925 nPixelToScrollX = rPosPixel.X()- nBorderWidth; 3926 } 3927 else if ( rPosPixel.X() > aWndSize.Width() - nBorderWidth ) 3928 { 3929 if( bInDragDrop ) 3930 nPixelToScrollX = DD_SCROLL_PIXEL; 3931 else 3932 nPixelToScrollX = rPosPixel.X() - (aWndSize.Width() - nBorderWidth); 3933 } 3934 if ( rPosPixel.Y() < nBorderWidth ) 3935 { 3936 if( bInDragDrop ) 3937 nPixelToScrollY = -DD_SCROLL_PIXEL; 3938 else 3939 nPixelToScrollY = rPosPixel.Y() - nBorderWidth; 3940 } 3941 else if ( rPosPixel.Y() > aWndSize.Height() - nBorderWidth ) 3942 { 3943 if( bInDragDrop ) 3944 nPixelToScrollY = DD_SCROLL_PIXEL; 3945 else 3946 nPixelToScrollY = rPosPixel.Y() - (aWndSize.Height() - nBorderWidth); 3947 } 3948 3949 rX = nPixelToScrollX; 3950 rY = nPixelToScrollY; 3951 } 3952 3953 IMPL_LINK(SvImpIconView, MouseMoveTimeoutHdl, Timer*, pTimer ) 3954 { 3955 pTimer->Start(); 3956 MouseMove( aMouseMoveEvent ); 3957 return 0; 3958 } 3959 3960 void SvImpIconView::EndTracking() 3961 { 3962 pView->ReleaseMouse(); 3963 if( nFlags & F_RUBBERING ) 3964 { 3965 aMouseMoveTimer.Stop(); 3966 nFlags &= ~(F_RUBBERING | F_ADD_MODE); 3967 } 3968 } 3969 3970 sal_Bool SvImpIconView::IsTextHit( SvLBoxEntry* pEntry, const Point& rDocPos ) 3971 { 3972 SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 3973 if( pItem ) 3974 { 3975 Rectangle aRect( CalcTextRect( pEntry, pItem )); 3976 if( aRect.IsInside( rDocPos ) ) 3977 return sal_True; 3978 } 3979 return sal_False; 3980 } 3981 3982 IMPL_LINK(SvImpIconView, EditTimeoutHdl, Timer*, EMPTYARG ) 3983 { 3984 SvLBoxEntry* pEntry = GetCurEntry(); 3985 if( pView->IsInplaceEditingEnabled() && pEntry && 3986 pView->IsSelected( pEntry )) 3987 { 3988 pView->EditEntry( pEntry ); 3989 } 3990 return 0; 3991 } 3992 3993 3994 // 3995 // Funktionen zum Ausrichten der Eintraege am Grid 3996 // 3997 3998 // pStart == 0: Alle Eintraege werden ausgerichtet 3999 // sonst: Alle Eintraege der Zeile ab einschliesslich pStart werden ausgerichtet 4000 void SvImpIconView::AdjustAtGrid( SvLBoxEntry* pStart ) 4001 { 4002 SvPtrarr aLists; 4003 pImpCursor->CreateGridAjustData( aLists, pStart ); 4004 sal_uInt16 nCount = aLists.Count(); 4005 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) 4006 { 4007 AdjustAtGrid( *(SvPtrarr*)aLists[ nCur ], pStart ); 4008 } 4009 ImpIcnCursor::DestroyGridAdjustData( aLists ); 4010 CheckScrollBars(); 4011 } 4012 4013 // Richtet eine Zeile aus, erweitert ggf. die Breite; Bricht die Zeile nicht um 4014 void SvImpIconView::AdjustAtGrid( const SvPtrarr& rRow, SvLBoxEntry* pStart ) 4015 { 4016 if( !rRow.Count() ) 4017 return; 4018 4019 sal_Bool bGo; 4020 if( !pStart ) 4021 bGo = sal_True; 4022 else 4023 bGo = sal_False; 4024 4025 long nCurRight = 0; 4026 for( sal_uInt16 nCur = 0; nCur < rRow.Count(); nCur++ ) 4027 { 4028 SvLBoxEntry* pCur = (SvLBoxEntry*)rRow[ nCur ]; 4029 if( !bGo && pCur == pStart ) 4030 bGo = sal_True; 4031 4032 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur); 4033 // Massgebend (fuer das menschliche Auge) ist die Bitmap, da sonst 4034 // durch lange Texte der Eintrag stark springen kann 4035 const Rectangle& rBoundRect = GetBoundingRect( pCur, pViewData ); 4036 Rectangle aCenterRect( CalcBmpRect( pCur, 0, pViewData )); 4037 if( bGo && !pViewData->IsEntryPosLocked() ) 4038 { 4039 long nWidth = aCenterRect.GetSize().Width(); 4040 Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) ); 4041 while( aNewPos.X() < nCurRight ) 4042 aNewPos.X() += nGridDX; 4043 if( aNewPos != rBoundRect.TopLeft() ) 4044 SetEntryPosition( pCur, aNewPos ); 4045 nCurRight = aNewPos.X() + nWidth; 4046 } 4047 else 4048 { 4049 nCurRight = rBoundRect.Right(); 4050 } 4051 } 4052 } 4053 4054 // Richtet Rect am Grid aus, garantiert jedoch nicht, dass die 4055 // neue Pos. frei ist. Die Pos. kann fuer SetEntryPos verwendet werden. 4056 // Das CenterRect beschreibt den Teil des BoundRects, der fuer 4057 // die Berechnung des Ziel-Rechtecks verwendet wird. 4058 Point SvImpIconView::AdjustAtGrid( const Rectangle& rCenterRect, 4059 const Rectangle& rBoundRect ) const 4060 { 4061 Point aPos( rCenterRect.TopLeft() ); 4062 Size aSize( rCenterRect.GetSize() ); 4063 4064 aPos.X() -= LROFFS_WINBORDER; 4065 aPos.Y() -= TBOFFS_WINBORDER; 4066 4067 // align (ref ist mitte des rects) 4068 short nGridX = (short)((aPos.X()+(aSize.Width()/2)) / nGridDX); 4069 short nGridY = (short)((aPos.Y()+(aSize.Height()/2)) / nGridDY); 4070 aPos.X() = nGridX * nGridDX; 4071 aPos.Y() = nGridY * nGridDY; 4072 // hor. center 4073 aPos.X() += (nGridDX - rBoundRect.GetSize().Width() ) / 2; 4074 4075 aPos.X() += LROFFS_WINBORDER; 4076 aPos.Y() += TBOFFS_WINBORDER; 4077 4078 return aPos; 4079 } 4080 4081 4082 void SvImpIconView::SetTextMode( SvIconViewTextMode eMode, SvLBoxEntry* pEntry ) 4083 { 4084 if( !pEntry ) 4085 { 4086 if( eTextMode != eMode ) 4087 { 4088 if( eTextMode == ShowTextDontKnow ) 4089 eTextMode = ShowTextShort; 4090 eTextMode = eMode; 4091 pView->Arrange(); 4092 } 4093 } 4094 else 4095 { 4096 SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); 4097 if( pViewData->eTextMode != eMode ) 4098 { 4099 pViewData->eTextMode = eMode; 4100 pModel->InvalidateEntry( pEntry ); 4101 AdjustVirtSize( pViewData->aRect ); 4102 } 4103 } 4104 } 4105 4106 SvIconViewTextMode SvImpIconView::GetTextMode( const SvLBoxEntry* pEntry, 4107 const SvIcnVwDataEntry* pViewData ) const 4108 { 4109 if( !pEntry ) 4110 return eTextMode; 4111 else 4112 { 4113 if( !pViewData ) 4114 pViewData = ICNVIEWDATA(((SvLBoxEntry*)pEntry)); 4115 return pViewData->GetTextMode(); 4116 } 4117 } 4118 4119 SvIconViewTextMode SvImpIconView::GetEntryTextModeSmart( const SvLBoxEntry* pEntry, 4120 const SvIcnVwDataEntry* pViewData ) const 4121 { 4122 DBG_ASSERT(pEntry,"GetEntryTextModeSmart: Entry not set"); 4123 if( !pViewData ) 4124 pViewData = ICNVIEWDATA(((SvLBoxEntry*)pEntry)); 4125 SvIconViewTextMode eMode = pViewData->GetTextMode(); 4126 if( eMode == ShowTextDontKnow ) 4127 return eTextMode; 4128 return eMode; 4129 } 4130 4131 void SvImpIconView::ShowFocusRect( const SvLBoxEntry* pEntry ) 4132 { 4133 if( !pEntry ) 4134 pView->HideFocus(); 4135 else 4136 { 4137 Rectangle aRect ( CalcFocusRect( (SvLBoxEntry*)pEntry ) ); 4138 pView->ShowFocus( aRect ); 4139 } 4140 } 4141 4142 IMPL_LINK(SvImpIconView, UserEventHdl, void*, EMPTYARG ) 4143 { 4144 nCurUserEvent = 0; 4145 AdjustScrollBars(); 4146 Rectangle aRect; 4147 if( GetResizeRect(aRect) ) 4148 PaintResizeRect( aRect ); 4149 return 0; 4150 } 4151 4152 void SvImpIconView::CancelUserEvent() 4153 { 4154 if( nCurUserEvent ) 4155 { 4156 Application::RemoveUserEvent( nCurUserEvent ); 4157 nCurUserEvent = 0; 4158 } 4159 } 4160 4161 4162