1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sdext.hxx" 26 27 #include "PresenterSlideSorter.hxx" 28 #include "PresenterButton.hxx" 29 #include "PresenterCanvasHelper.hxx" 30 #include "PresenterComponent.hxx" 31 #include "PresenterGeometryHelper.hxx" 32 #include "PresenterHelper.hxx" 33 #include "PresenterPaintManager.hxx" 34 #include "PresenterPaneBase.hxx" 35 #include "PresenterScrollBar.hxx" 36 #include "PresenterUIPainter.hxx" 37 #include "PresenterWindowManager.hxx" 38 #include <com/sun/star/awt/PosSize.hpp> 39 #include <com/sun/star/awt/XWindowPeer.hpp> 40 #include <com/sun/star/container/XNameAccess.hpp> 41 #include <com/sun/star/container/XNamed.hpp> 42 #include <com/sun/star/drawing/XSlideSorterBase.hpp> 43 #include <com/sun/star/drawing/framework/XConfigurationController.hpp> 44 #include <com/sun/star/drawing/framework/XControllerManager.hpp> 45 #include <com/sun/star/rendering/CompositeOperation.hpp> 46 #include <com/sun/star/rendering/TextDirection.hpp> 47 #include <com/sun/star/rendering/XPolyPolygon2D.hpp> 48 #include <com/sun/star/util/Color.hpp> 49 #include <algorithm> 50 #include <math.h> 51 #include <boost/bind.hpp> 52 53 using namespace ::com::sun::star; 54 using namespace ::com::sun::star::uno; 55 using namespace ::com::sun::star::drawing::framework; 56 using ::rtl::OUString; 57 58 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString))) 59 60 namespace { 61 const static sal_Int32 gnVerticalGap (10); 62 const static sal_Int32 gnVerticalBorder (10); 63 const static sal_Int32 gnHorizontalGap (10); 64 const static sal_Int32 gnHorizontalBorder (10); 65 66 const static double gnMinimalPreviewWidth (200); 67 const static double gnPreferredPreviewWidth (300); 68 const static double gnMaximalPreviewWidth (400); 69 const static sal_Int32 gnPreferredColumnCount (6); 70 const static double gnMinimalHorizontalPreviewGap(15); 71 const static double gnPreferredHorizontalPreviewGap(25); 72 const static double gnMaximalHorizontalPreviewGap(50); 73 const static double gnMinimalVerticalPreviewGap(15); 74 const static double gnPreferredVerticalPreviewGap(25); 75 const static double gnMaximalVerticalPreviewGap(50); 76 77 const static sal_Int32 gnHorizontalLabelBorder (3); 78 const static sal_Int32 gnHorizontalLabelPadding (5); 79 80 const static sal_Int32 gnVerticalButtonPadding (gnVerticalGap); 81 } 82 83 namespace sdext { namespace presenter { 84 85 namespace { 86 sal_Int32 round (const double nValue) { return sal::static_int_cast<sal_Int32>(0.5 + nValue); } 87 sal_Int32 floor (const double nValue) { return sal::static_int_cast<sal_Int32>(nValue); } 88 } 89 90 91 92 //===== PresenterSlideSorter::Layout ========================================== 93 94 class PresenterSlideSorter::Layout 95 { 96 public: 97 enum Orientation { Horizontal, Vertical }; 98 Layout ( 99 const Orientation eOrientation, 100 const ::rtl::Reference<PresenterScrollBar>& rpHorizontalScrollBar, 101 const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar); 102 103 void Update (const geometry::RealRectangle2D& rBoundingBox, const double nSlideAspectRatio); 104 void SetupVisibleArea (void); 105 void UpdateScrollBars (void); 106 bool IsScrollBarNeeded (const sal_Int32 nSlideCount); 107 geometry::RealPoint2D GetLocalPosition (const geometry::RealPoint2D& rWindowPoint) const; 108 geometry::RealPoint2D GetWindowPosition(const geometry::RealPoint2D& rLocalPoint) const; 109 sal_Int32 GetColumn (const geometry::RealPoint2D& rLocalPoint, 110 const bool bReturnInvalidValue = false) const; 111 sal_Int32 GetRow (const geometry::RealPoint2D& rLocalPoint, 112 const bool bReturnInvalidValue = false) const; 113 sal_Int32 GetSlideIndexForPosition (const css::geometry::RealPoint2D& rPoint) const; 114 css::geometry::RealPoint2D GetPoint ( 115 const sal_Int32 nSlideIndex, 116 const sal_Int32 nRelativeHorizontalPosition, 117 const sal_Int32 nRelativeVerticalPosition) const; 118 css::awt::Rectangle GetBoundingBox (const sal_Int32 nSlideIndex) const; 119 void ForAllVisibleSlides (const ::boost::function<void(sal_Int32)>& rAction); 120 sal_Int32 GetFirstVisibleSlideIndex (void) const; 121 sal_Int32 GetLastVisibleSlideIndex (void) const; 122 bool SetHorizontalOffset (const double nOffset); 123 bool SetVerticalOffset (const double nOffset); 124 Orientation GetOrientation (void) const; 125 126 css::geometry::RealRectangle2D maBoundingBox; 127 css::geometry::IntegerSize2D maPreviewSize; 128 sal_Int32 mnHorizontalOffset; 129 sal_Int32 mnVerticalOffset; 130 sal_Int32 mnHorizontalGap; 131 sal_Int32 mnVerticalGap; 132 sal_Int32 mnHorizontalBorder; 133 sal_Int32 mnVerticalBorder; 134 sal_Int32 mnRowCount; 135 sal_Int32 mnColumnCount; 136 sal_Int32 mnSlideCount; 137 sal_Int32 mnSlideIndexAtMouse; 138 sal_Int32 mnFirstVisibleColumn; 139 sal_Int32 mnLastVisibleColumn; 140 sal_Int32 mnFirstVisibleRow; 141 sal_Int32 mnLastVisibleRow; 142 143 private: 144 Orientation meOrientation; 145 ::rtl::Reference<PresenterScrollBar> mpHorizontalScrollBar; 146 ::rtl::Reference<PresenterScrollBar> mpVerticalScrollBar; 147 148 sal_Int32 GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const; 149 sal_Int32 GetRow (const sal_Int32 nSlideIndex) const; 150 sal_Int32 GetColumn (const sal_Int32 nSlideIndex) const; 151 }; 152 153 154 155 156 //==== PresenterSlideSorter::MouseOverManager ================================= 157 158 class PresenterSlideSorter::MouseOverManager 159 : ::boost::noncopyable 160 { 161 public: 162 MouseOverManager ( 163 const Reference<container::XIndexAccess>& rxSlides, 164 const ::boost::shared_ptr<PresenterTheme>& rpTheme, 165 const Reference<awt::XWindow>& rxInvalidateTarget, 166 const ::boost::shared_ptr<PresenterPaintManager>& rpPaintManager); 167 ~MouseOverManager (void); 168 169 void Paint ( 170 const sal_Int32 nSlideIndex, 171 const Reference<rendering::XCanvas>& rxCanvas, 172 const Reference<rendering::XPolyPolygon2D>& rxClip); 173 174 void SetSlide ( 175 const sal_Int32 nSlideIndex, 176 const awt::Rectangle& rBox); 177 178 private: 179 Reference<rendering::XCanvas> mxCanvas; 180 const Reference<container::XIndexAccess> mxSlides; 181 SharedBitmapDescriptor mpLeftLabelBitmap; 182 SharedBitmapDescriptor mpCenterLabelBitmap; 183 SharedBitmapDescriptor mpRightLabelBitmap; 184 PresenterTheme::SharedFontDescriptor mpFont; 185 sal_Int32 mnSlideIndex; 186 awt::Rectangle maSlideBoundingBox; 187 OUString msText; 188 Reference<rendering::XBitmap> mxBitmap; 189 Reference<awt::XWindow> mxInvalidateTarget; 190 ::boost::shared_ptr<PresenterPaintManager> mpPaintManager; 191 192 void SetCanvas ( 193 const Reference<rendering::XCanvas>& rxCanvas); 194 /** Create a bitmap that shows the given text and is not wider than the 195 given maximal width. 196 */ 197 Reference<rendering::XBitmap> CreateBitmap ( 198 const OUString& rsText, 199 const sal_Int32 nMaximalWidth) const; 200 void Invalidate (void); 201 geometry::IntegerSize2D CalculateLabelSize ( 202 const OUString& rsText) const; 203 OUString GetFittingText (const OUString& rsText, const double nMaximalWidth) const; 204 void PaintButtonBackground ( 205 const Reference<rendering::XBitmapCanvas>& rxCanvas, 206 const geometry::IntegerSize2D& rSize) const; 207 }; 208 209 210 211 212 //==== PresenterSlideSorter::CurrentSlideFrameRenderer ======================== 213 214 class PresenterSlideSorter::CurrentSlideFrameRenderer 215 { 216 public: 217 CurrentSlideFrameRenderer ( 218 const css::uno::Reference<css::uno::XComponentContext>& rxContext, 219 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas); 220 ~CurrentSlideFrameRenderer (void); 221 222 void PaintCurrentSlideFrame ( 223 const awt::Rectangle& rSlideBoundingBox, 224 const Reference<rendering::XCanvas>& rxCanvas, 225 const geometry::RealRectangle2D& rClipBox); 226 227 /** Enlarge the given rectangle to include the current slide indicator. 228 */ 229 awt::Rectangle GetBoundingBox ( 230 const awt::Rectangle& rSlideBoundingBox); 231 232 private: 233 SharedBitmapDescriptor mpTopLeft; 234 SharedBitmapDescriptor mpTop; 235 SharedBitmapDescriptor mpTopRight; 236 SharedBitmapDescriptor mpLeft; 237 SharedBitmapDescriptor mpRight; 238 SharedBitmapDescriptor mpBottomLeft; 239 SharedBitmapDescriptor mpBottom; 240 SharedBitmapDescriptor mpBottomRight; 241 sal_Int32 mnTopFrameSize; 242 sal_Int32 mnLeftFrameSize; 243 sal_Int32 mnRightFrameSize; 244 sal_Int32 mnBottomFrameSize; 245 246 void PaintBitmapOnce( 247 const css::uno::Reference<css::rendering::XBitmap>& rxBitmap, 248 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas, 249 const Reference<rendering::XPolyPolygon2D>& rxClip, 250 const double nX, 251 const double nY); 252 void PaintBitmapTiled( 253 const css::uno::Reference<css::rendering::XBitmap>& rxBitmap, 254 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas, 255 const geometry::RealRectangle2D& rClipBox, 256 const double nX, 257 const double nY, 258 const double nWidth, 259 const double nHeight); 260 }; 261 262 263 264 265 //===== PresenterSlideSorter ================================================== 266 267 PresenterSlideSorter::PresenterSlideSorter ( 268 const Reference<uno::XComponentContext>& rxContext, 269 const Reference<XResourceId>& rxViewId, 270 const Reference<frame::XController>& rxController, 271 const ::rtl::Reference<PresenterController>& rpPresenterController) 272 : PresenterSlideSorterInterfaceBase(m_aMutex), 273 mxComponentContext(rxContext), 274 mxViewId(rxViewId), 275 mxPane(), 276 mxCanvas(), 277 mxWindow(), 278 mpPresenterController(rpPresenterController), 279 mxSlideShowController(mpPresenterController->GetSlideShowController()), 280 mxPreviewCache(), 281 mbIsPaintPending(true), 282 mbIsLayoutPending(true), 283 mpLayout(), 284 mpHorizontalScrollBar(), 285 mpVerticalScrollBar(), 286 mpCloseButton(), 287 mpMouseOverManager(), 288 mnSlideIndexMousePressed(-1), 289 mnCurrentSlideIndex(-1), 290 mnSeparatorY(0), 291 maSeparatorColor(0x00ffffff), 292 maCloseButtonCenter(), 293 maCurrentSlideFrameBoundingBox(), 294 mpCurrentSlideFrameRenderer(), 295 mxPreviewFrame() 296 { 297 if ( ! rxContext.is() 298 || ! rxViewId.is() 299 || ! rxController.is() 300 || rpPresenterController.get()==NULL) 301 { 302 throw lang::IllegalArgumentException(); 303 } 304 305 if ( ! mxSlideShowController.is()) 306 throw RuntimeException(); 307 308 try 309 { 310 // Get pane and window. 311 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW); 312 Reference<XConfigurationController> xCC ( 313 xCM->getConfigurationController(), UNO_QUERY_THROW); 314 Reference<lang::XMultiComponentFactory> xFactory ( 315 mxComponentContext->getServiceManager(), UNO_QUERY_THROW); 316 317 mxPane = Reference<XPane>(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW); 318 mxWindow = mxPane->getWindow(); 319 320 // Add window listener. 321 mxWindow->addWindowListener(this); 322 mxWindow->addPaintListener(this); 323 mxWindow->addMouseListener(this); 324 mxWindow->addMouseMotionListener(this); 325 mxWindow->setVisible(sal_True); 326 327 // Remember the current slide. 328 mnCurrentSlideIndex = mxSlideShowController->getCurrentSlideIndex(); 329 330 // Set the orientation. 331 const bool bIsVertical (true); 332 333 // Create the scroll bar. 334 if (bIsVertical) 335 mpVerticalScrollBar = ::rtl::Reference<PresenterScrollBar>( 336 new PresenterVerticalScrollBar( 337 rxContext, 338 mxWindow, 339 mpPresenterController->GetPaintManager(), 340 ::boost::bind(&PresenterSlideSorter::SetVerticalOffset,this,_1))); 341 else 342 mpHorizontalScrollBar = ::rtl::Reference<PresenterScrollBar>( 343 new PresenterHorizontalScrollBar( 344 rxContext, 345 mxWindow, 346 mpPresenterController->GetPaintManager(), 347 ::boost::bind(&PresenterSlideSorter::SetHorizontalOffset,this,_1))); 348 mpCloseButton = PresenterButton::Create( 349 rxContext, 350 mpPresenterController, 351 mpPresenterController->GetTheme(), 352 mxWindow, 353 mxCanvas, 354 A2S("SlideSorterCloser")); 355 356 if (mpPresenterController->GetTheme().get() != NULL) 357 { 358 PresenterTheme::SharedFontDescriptor pFont ( 359 mpPresenterController->GetTheme()->GetFont(A2S("ButtonFont"))); 360 if (pFont.get() != NULL) 361 maSeparatorColor = pFont->mnColor; 362 } 363 364 // Create the layout. 365 mpLayout.reset(new Layout( 366 Layout::Vertical, 367 mpHorizontalScrollBar, 368 mpVerticalScrollBar)); 369 370 // Create the preview cache. 371 mxPreviewCache = Reference<drawing::XSlidePreviewCache>( 372 xFactory->createInstanceWithContext( 373 OUString::createFromAscii("com.sun.star.drawing.PresenterPreviewCache"), 374 mxComponentContext), 375 UNO_QUERY_THROW); 376 Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY); 377 mxPreviewCache->setDocumentSlides(xSlides, rxController->getModel()); 378 mxPreviewCache->addPreviewCreationNotifyListener(this); 379 if (xSlides.is()) 380 { 381 mpLayout->mnSlideCount = xSlides->getCount(); 382 } 383 384 // Create the mouse over manager. 385 mpMouseOverManager.reset(new MouseOverManager( 386 Reference<container::XIndexAccess>(mxSlideShowController, UNO_QUERY), 387 mpPresenterController->GetTheme(), 388 mxWindow, 389 mpPresenterController->GetPaintManager())); 390 391 // Listen for changes of the current slide. 392 Reference<beans::XPropertySet> xControllerProperties (rxController, UNO_QUERY_THROW); 393 xControllerProperties->addPropertyChangeListener( 394 OUString::createFromAscii("CurrentPage"), 395 this); 396 397 // Move the current slide in the center of the window. 398 const awt::Rectangle aCurrentSlideBBox (mpLayout->GetBoundingBox(mnCurrentSlideIndex)); 399 const awt::Rectangle aWindowBox (mxWindow->getPosSize()); 400 SetHorizontalOffset(aCurrentSlideBBox.X - aWindowBox.Width/2.0); 401 } 402 catch (RuntimeException&) 403 { 404 disposing(); 405 throw; 406 } 407 } 408 409 410 411 412 PresenterSlideSorter::~PresenterSlideSorter (void) 413 { 414 } 415 416 417 418 419 void SAL_CALL PresenterSlideSorter::disposing (void) 420 { 421 mxComponentContext = NULL; 422 mxViewId = NULL; 423 mxPane = NULL; 424 425 if (mpVerticalScrollBar.is()) 426 { 427 Reference<lang::XComponent> xComponent ( 428 static_cast<XWeak*>(mpVerticalScrollBar.get()), UNO_QUERY); 429 mpVerticalScrollBar = NULL; 430 if (xComponent.is()) 431 xComponent->dispose(); 432 } 433 if (mpHorizontalScrollBar.is()) 434 { 435 Reference<lang::XComponent> xComponent ( 436 static_cast<XWeak*>(mpHorizontalScrollBar.get()), UNO_QUERY); 437 mpHorizontalScrollBar = NULL; 438 if (xComponent.is()) 439 xComponent->dispose(); 440 } 441 if (mpCloseButton.is()) 442 { 443 Reference<lang::XComponent> xComponent ( 444 static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY); 445 mpCloseButton = NULL; 446 if (xComponent.is()) 447 xComponent->dispose(); 448 } 449 450 if (mxCanvas.is()) 451 { 452 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY); 453 if (xComponent.is()) 454 xComponent->removeEventListener(static_cast<awt::XWindowListener*>(this)); 455 mxCanvas = NULL; 456 } 457 mpPresenterController = NULL; 458 mxSlideShowController = NULL; 459 mpLayout.reset(); 460 mpMouseOverManager.reset(); 461 462 if (mxPreviewCache.is()) 463 { 464 mxPreviewCache->removePreviewCreationNotifyListener(this); 465 466 Reference<XComponent> xComponent (mxPreviewCache, UNO_QUERY); 467 mxPreviewCache = NULL; 468 if (xComponent.is()) 469 xComponent->dispose(); 470 } 471 472 if (mxWindow.is()) 473 { 474 mxWindow->removeWindowListener(this); 475 mxWindow->removePaintListener(this); 476 mxWindow->removeMouseListener(this); 477 mxWindow->removeMouseMotionListener(this); 478 } 479 } 480 481 482 483 484 void PresenterSlideSorter::SetActiveState (const bool bIsActive) 485 { 486 (void)bIsActive; 487 } 488 489 490 491 492 //----- lang::XEventListener -------------------------------------------------- 493 494 void SAL_CALL PresenterSlideSorter::disposing (const lang::EventObject& rEventObject) 495 throw (RuntimeException) 496 { 497 if (rEventObject.Source == mxWindow) 498 { 499 mxWindow = NULL; 500 dispose(); 501 } 502 else if (rEventObject.Source == mxPreviewCache) 503 { 504 mxPreviewCache = NULL; 505 dispose(); 506 } 507 else if (rEventObject.Source == mxCanvas) 508 { 509 mxCanvas = NULL; 510 if (mpHorizontalScrollBar.is()) 511 mpHorizontalScrollBar->SetCanvas(NULL); 512 mbIsLayoutPending = true; 513 mbIsPaintPending = true; 514 515 mpPresenterController->GetPaintManager()->Invalidate(mxWindow); 516 } 517 } 518 519 520 521 522 //----- XWindowListener ------------------------------------------------------- 523 524 void SAL_CALL PresenterSlideSorter::windowResized (const awt::WindowEvent& rEvent) 525 throw (uno::RuntimeException) 526 { 527 (void)rEvent; 528 ThrowIfDisposed(); 529 mbIsLayoutPending = true; 530 mpPresenterController->GetPaintManager()->Invalidate(mxWindow); 531 } 532 533 534 535 536 void SAL_CALL PresenterSlideSorter::windowMoved (const awt::WindowEvent& rEvent) 537 throw (uno::RuntimeException) 538 { 539 (void)rEvent; 540 ThrowIfDisposed(); 541 } 542 543 544 545 546 void SAL_CALL PresenterSlideSorter::windowShown (const lang::EventObject& rEvent) 547 throw (uno::RuntimeException) 548 { 549 (void)rEvent; 550 ThrowIfDisposed(); 551 mbIsLayoutPending = true; 552 mpPresenterController->GetPaintManager()->Invalidate(mxWindow); 553 } 554 555 556 557 558 void SAL_CALL PresenterSlideSorter::windowHidden (const lang::EventObject& rEvent) 559 throw (uno::RuntimeException) 560 { 561 (void)rEvent; 562 ThrowIfDisposed(); 563 } 564 565 566 567 568 //----- XPaintListener -------------------------------------------------------- 569 570 void SAL_CALL PresenterSlideSorter::windowPaint (const css::awt::PaintEvent& rEvent) 571 throw (RuntimeException) 572 { 573 (void)rEvent; 574 575 // Deactivated views must not be painted. 576 if ( ! mbIsPresenterViewActive) 577 return; 578 579 Paint(rEvent.UpdateRect); 580 581 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); 582 if (xSpriteCanvas.is()) 583 xSpriteCanvas->updateScreen(sal_False); 584 } 585 586 587 588 589 //----- XMouseListener -------------------------------------------------------- 590 591 void SAL_CALL PresenterSlideSorter::mousePressed (const css::awt::MouseEvent& rEvent) 592 throw(css::uno::RuntimeException) 593 { 594 const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y); 595 mnSlideIndexMousePressed = mpLayout->GetSlideIndexForPosition(aPosition); 596 } 597 598 599 600 601 void SAL_CALL PresenterSlideSorter::mouseReleased (const css::awt::MouseEvent& rEvent) 602 throw(css::uno::RuntimeException) 603 { 604 const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y); 605 const sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition)); 606 607 if (nSlideIndex == mnSlideIndexMousePressed && mnSlideIndexMousePressed >= 0) 608 { 609 switch (rEvent.ClickCount) 610 { 611 case 1: 612 default: 613 GotoSlide(nSlideIndex); 614 break; 615 616 case 2: 617 OSL_ASSERT(mpPresenterController.get()!=NULL); 618 OSL_ASSERT(mpPresenterController->GetWindowManager().get()!=NULL); 619 mpPresenterController->GetWindowManager()->SetSlideSorterState(false); 620 GotoSlide(nSlideIndex); 621 break; 622 } 623 } 624 } 625 626 627 628 629 void SAL_CALL PresenterSlideSorter::mouseEntered (const css::awt::MouseEvent& rEvent) 630 throw(css::uno::RuntimeException) 631 { 632 (void)rEvent; 633 } 634 635 636 637 638 void SAL_CALL PresenterSlideSorter::mouseExited (const css::awt::MouseEvent& rEvent) 639 throw(css::uno::RuntimeException) 640 { 641 (void)rEvent; 642 mnSlideIndexMousePressed = -1; 643 if (mpMouseOverManager.get() != NULL) 644 mpMouseOverManager->SetSlide(mnSlideIndexMousePressed, awt::Rectangle(0,0,0,0)); 645 } 646 647 648 649 650 //----- XMouseMotionListener -------------------------------------------------- 651 652 void SAL_CALL PresenterSlideSorter::mouseMoved (const css::awt::MouseEvent& rEvent) 653 throw (css::uno::RuntimeException) 654 { 655 if (mpMouseOverManager.get() != NULL) 656 { 657 const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y); 658 sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition)); 659 660 if (nSlideIndex < 0) 661 mnSlideIndexMousePressed = -1; 662 663 if (nSlideIndex < 0) 664 { 665 mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0)); 666 } 667 else 668 { 669 mpMouseOverManager->SetSlide( 670 nSlideIndex, 671 mpLayout->GetBoundingBox(nSlideIndex)); 672 } 673 } 674 } 675 676 677 678 679 void SAL_CALL PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent& rEvent) 680 throw (css::uno::RuntimeException) 681 { 682 (void)rEvent; 683 } 684 685 686 687 688 //----- XResourceId ----------------------------------------------------------- 689 690 Reference<XResourceId> SAL_CALL PresenterSlideSorter::getResourceId (void) 691 throw (RuntimeException) 692 { 693 ThrowIfDisposed(); 694 return mxViewId; 695 } 696 697 698 699 700 sal_Bool SAL_CALL PresenterSlideSorter::isAnchorOnly (void) 701 throw (RuntimeException) 702 { 703 return false; 704 } 705 706 707 708 709 //----- XPropertyChangeListener ----------------------------------------------- 710 711 void SAL_CALL PresenterSlideSorter::propertyChange ( 712 const css::beans::PropertyChangeEvent& rEvent) 713 throw(css::uno::RuntimeException) 714 { 715 (void)rEvent; 716 } 717 718 719 720 721 //----- XSlidePreviewCacheListener -------------------------------------------- 722 723 void SAL_CALL PresenterSlideSorter::notifyPreviewCreation ( 724 sal_Int32 nSlideIndex) 725 throw(css::uno::RuntimeException) 726 { 727 OSL_ASSERT(mpLayout.get()!=NULL); 728 729 awt::Rectangle aBBox (mpLayout->GetBoundingBox(nSlideIndex)); 730 mpPresenterController->GetPaintManager()->Invalidate(mxWindow, aBBox, true); 731 } 732 733 734 735 736 //----- XDrawView ------------------------------------------------------------- 737 738 void SAL_CALL PresenterSlideSorter::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide) 739 throw (RuntimeException) 740 { 741 (void)rxSlide; 742 743 ThrowIfDisposed(); 744 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); 745 746 if (mxSlideShowController.is()) 747 { 748 const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex()); 749 if (nNewCurrentSlideIndex != mnCurrentSlideIndex) 750 { 751 mnCurrentSlideIndex = nNewCurrentSlideIndex; 752 753 // Request a repaint of the previous current slide to hide its 754 // current slide indicator. 755 mpPresenterController->GetPaintManager()->Invalidate( 756 mxWindow, 757 maCurrentSlideFrameBoundingBox); 758 759 // Request a repaint of the new current slide to show its 760 // current slide indicator. 761 maCurrentSlideFrameBoundingBox = mpCurrentSlideFrameRenderer->GetBoundingBox( 762 mpLayout->GetBoundingBox(mnCurrentSlideIndex)); 763 mpPresenterController->GetPaintManager()->Invalidate( 764 mxWindow, 765 maCurrentSlideFrameBoundingBox); 766 } 767 } 768 } 769 770 771 772 773 Reference<drawing::XDrawPage> SAL_CALL PresenterSlideSorter::getCurrentPage (void) 774 throw (RuntimeException) 775 { 776 ThrowIfDisposed(); 777 return NULL; 778 } 779 780 781 782 783 //----------------------------------------------------------------------------- 784 785 void PresenterSlideSorter::UpdateLayout (void) 786 { 787 if ( ! mxWindow.is()) 788 return; 789 790 mbIsLayoutPending = false; 791 mbIsPaintPending = true; 792 793 const awt::Rectangle aWindowBox (mxWindow->getPosSize()); 794 awt::Rectangle aCenterBox (aWindowBox); 795 sal_Int32 nLeftBorderWidth (aWindowBox.X); 796 797 // Get border width. 798 PresenterPaneContainer::SharedPaneDescriptor pPane ( 799 mpPresenterController->GetPaneContainer()->FindViewURL( 800 mxViewId->getResourceURL())); 801 do 802 { 803 if (pPane.get() == NULL) 804 break; 805 if ( ! pPane->mxPane.is()) 806 break; 807 808 Reference<drawing::framework::XPaneBorderPainter> xBorderPainter ( 809 pPane->mxPane->GetPaneBorderPainter()); 810 if ( ! xBorderPainter.is()) 811 break; 812 aCenterBox = xBorderPainter->addBorder ( 813 mxViewId->getAnchor()->getResourceURL(), 814 awt::Rectangle(0, 0, aWindowBox.Width, aWindowBox.Height), 815 drawing::framework::BorderType_INNER_BORDER); 816 } 817 while(false); 818 819 // Place vertical separator. 820 mnSeparatorY = aWindowBox.Height - mpCloseButton->GetSize().Height - gnVerticalButtonPadding; 821 822 PlaceCloseButton(pPane, aWindowBox, nLeftBorderWidth); 823 824 geometry::RealRectangle2D aUpperBox( 825 gnHorizontalBorder, 826 gnVerticalBorder, 827 aWindowBox.Width - 2*gnHorizontalBorder, 828 mnSeparatorY - gnVerticalGap); 829 830 // Determine whether the scroll bar has to be displayed. 831 aUpperBox = PlaceScrollBars(aUpperBox); 832 833 mpLayout->Update(aUpperBox, GetSlideAspectRatio()); 834 mpLayout->SetupVisibleArea(); 835 mpLayout->UpdateScrollBars(); 836 837 // Tell the preview cache about some of the values. 838 mxPreviewCache->setPreviewSize(mpLayout->maPreviewSize); 839 mxPreviewCache->setVisibleRange( 840 mpLayout->GetFirstVisibleSlideIndex(), 841 mpLayout->GetLastVisibleSlideIndex()); 842 843 // Clear the frame polygon so that it is re-created on the next paint. 844 mxPreviewFrame = NULL; 845 } 846 847 848 849 850 geometry::RealRectangle2D PresenterSlideSorter::PlaceScrollBars ( 851 const geometry::RealRectangle2D& rUpperBox) 852 { 853 mpLayout->Update(rUpperBox, GetSlideAspectRatio()); 854 bool bIsScrollBarNeeded (false); 855 Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY_THROW); 856 if (xSlides.is()) 857 bIsScrollBarNeeded = mpLayout->IsScrollBarNeeded(xSlides->getCount()); 858 859 if (mpLayout->GetOrientation() == Layout::Vertical) 860 { 861 if (mpVerticalScrollBar.get() != NULL) 862 { 863 if (bIsScrollBarNeeded) 864 { 865 // Place vertical scroll bar at right border. 866 mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D( 867 rUpperBox.X2 - mpVerticalScrollBar->GetSize(), 868 rUpperBox.Y1, 869 rUpperBox.X2, 870 rUpperBox.Y2)); 871 mpVerticalScrollBar->SetVisible(true); 872 873 // Reduce area covered by the scroll bar from the available 874 // space. 875 return geometry::RealRectangle2D( 876 rUpperBox.X1, 877 rUpperBox.Y1, 878 rUpperBox.X2 - mpVerticalScrollBar->GetSize() - gnHorizontalGap, 879 rUpperBox.Y2); 880 } 881 else 882 mpVerticalScrollBar->SetVisible(false); 883 } 884 } 885 else 886 { 887 if (mpHorizontalScrollBar.get() != NULL) 888 { 889 if (bIsScrollBarNeeded) 890 { 891 // Place horixontal scroll bar at the bottom. 892 mpHorizontalScrollBar->SetPosSize(geometry::RealRectangle2D( 893 rUpperBox.X1, 894 rUpperBox.Y2 - mpHorizontalScrollBar->GetSize(), 895 rUpperBox.X2, 896 rUpperBox.Y2)); 897 mpHorizontalScrollBar->SetVisible(true); 898 899 // Reduce area covered by the scroll bar from the available 900 // space. 901 return geometry::RealRectangle2D( 902 rUpperBox.X1, 903 rUpperBox.Y1, 904 rUpperBox.X2, 905 rUpperBox.Y2 - mpHorizontalScrollBar->GetSize() - gnVerticalGap); 906 } 907 else 908 mpHorizontalScrollBar->SetVisible(false); 909 } 910 } 911 912 return rUpperBox; 913 } 914 915 916 917 918 void PresenterSlideSorter::PlaceCloseButton ( 919 const PresenterPaneContainer::SharedPaneDescriptor& rpPane, 920 const awt::Rectangle& rCenterBox, 921 const sal_Int32 nLeftBorderWidth) 922 { 923 // Place button. When the callout is near the center then the button is 924 // centered over the callout. Otherwise it is centered with respect to 925 // the whole window. 926 sal_Int32 nCloseButtonCenter (rCenterBox.Width/2); 927 if (rpPane.get() != NULL && rpPane->mxPane.is()) 928 { 929 const sal_Int32 nCalloutCenter (rpPane->mxPane->GetCalloutAnchor().X - nLeftBorderWidth); 930 const sal_Int32 nDistanceFromWindowCenter (abs(nCalloutCenter - rCenterBox.Width/2)); 931 const sal_Int32 nButtonWidth (mpCloseButton->GetSize().Width); 932 const static sal_Int32 nMaxDistanceForCalloutCentering (nButtonWidth * 2); 933 if (nDistanceFromWindowCenter < nMaxDistanceForCalloutCentering) 934 { 935 if (nCalloutCenter < nButtonWidth/2) 936 nCloseButtonCenter = nButtonWidth/2; 937 else if (nCalloutCenter > rCenterBox.Width-nButtonWidth/2) 938 nCloseButtonCenter = rCenterBox.Width-nButtonWidth/2; 939 else 940 nCloseButtonCenter = nCalloutCenter; 941 } 942 } 943 mpCloseButton->SetCenter(geometry::RealPoint2D( 944 nCloseButtonCenter, 945 rCenterBox.Height - mpCloseButton->GetSize().Height/ 2)); 946 } 947 948 949 950 951 void PresenterSlideSorter::ClearBackground ( 952 const Reference<rendering::XCanvas>& rxCanvas, 953 const awt::Rectangle& rUpdateBox) 954 { 955 OSL_ASSERT(rxCanvas.is()); 956 957 const awt::Rectangle aWindowBox (mxWindow->getPosSize()); 958 mpPresenterController->GetCanvasHelper()->Paint( 959 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()), 960 rxCanvas, 961 rUpdateBox, 962 awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height), 963 awt::Rectangle()); 964 } 965 966 967 968 969 double PresenterSlideSorter::GetSlideAspectRatio (void) const 970 { 971 double nSlideAspectRatio (28.0/21.0); 972 973 try 974 { 975 Reference<container::XIndexAccess> xSlides(mxSlideShowController, UNO_QUERY_THROW); 976 if (mxSlideShowController.is() && xSlides->getCount()>0) 977 { 978 Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW); 979 sal_Int32 nWidth (28000); 980 sal_Int32 nHeight (21000); 981 if ((xProperties->getPropertyValue(OUString::createFromAscii("Width")) >>= nWidth) 982 && (xProperties->getPropertyValue(OUString::createFromAscii("Height")) >>= nHeight) 983 && nHeight > 0) 984 { 985 nSlideAspectRatio = double(nWidth) / double(nHeight); 986 } 987 } 988 } 989 catch (RuntimeException&) 990 { 991 OSL_ASSERT(false); 992 } 993 994 return nSlideAspectRatio; 995 } 996 997 998 999 1000 Reference<rendering::XBitmap> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex) 1001 { 1002 if (nSlideIndex < 0 || nSlideIndex>=mpLayout->mnSlideCount) 1003 return NULL; 1004 else if (mxPane.is()) 1005 return mxPreviewCache->getSlidePreview(nSlideIndex, mxPane->getCanvas()); 1006 else 1007 return NULL; 1008 } 1009 1010 1011 1012 1013 void PresenterSlideSorter::PaintPreview ( 1014 const Reference<rendering::XCanvas>& rxCanvas, 1015 const css::awt::Rectangle& rUpdateBox, 1016 const sal_Int32 nSlideIndex) 1017 { 1018 OSL_ASSERT(rxCanvas.is()); 1019 1020 geometry::IntegerSize2D aSize (mpLayout->maPreviewSize); 1021 1022 if (PresenterGeometryHelper::AreRectanglesDisjoint( 1023 rUpdateBox, 1024 mpLayout->GetBoundingBox(nSlideIndex))) 1025 { 1026 return; 1027 } 1028 1029 Reference<rendering::XBitmap> xPreview (GetPreview(nSlideIndex)); 1030 1031 const geometry::RealPoint2D aTopLeft ( 1032 mpLayout->GetWindowPosition( 1033 mpLayout->GetPoint(nSlideIndex, -1, -1))); 1034 1035 // Create clip rectangle as intersection of the current update area and 1036 // the bounding box of all previews. 1037 geometry::RealRectangle2D aBoundingBox (mpLayout->maBoundingBox); 1038 aBoundingBox.Y2 += 1; 1039 const geometry::RealRectangle2D aClipBox ( 1040 PresenterGeometryHelper::Intersection( 1041 PresenterGeometryHelper::ConvertRectangle(rUpdateBox), 1042 aBoundingBox)); 1043 Reference<rendering::XPolyPolygon2D> xClip ( 1044 PresenterGeometryHelper::CreatePolygon(aClipBox, rxCanvas->getDevice())); 1045 1046 const rendering::ViewState aViewState (geometry::AffineMatrix2D(1,0,0, 0,1,0), xClip); 1047 1048 1049 rendering::RenderState aRenderState ( 1050 geometry::AffineMatrix2D( 1051 1, 0, aTopLeft.X, 1052 0, 1, aTopLeft.Y), 1053 NULL, 1054 Sequence<double>(4), 1055 rendering::CompositeOperation::SOURCE); 1056 1057 1058 // Emphasize the current slide. 1059 if (nSlideIndex == mnCurrentSlideIndex) 1060 { 1061 if (mpCurrentSlideFrameRenderer.get() != NULL) 1062 { 1063 const awt::Rectangle aSlideBoundingBox( 1064 sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.X), 1065 sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.Y), 1066 aSize.Width, 1067 aSize.Height); 1068 maCurrentSlideFrameBoundingBox 1069 = mpCurrentSlideFrameRenderer->GetBoundingBox(aSlideBoundingBox); 1070 mpCurrentSlideFrameRenderer->PaintCurrentSlideFrame ( 1071 aSlideBoundingBox, 1072 mxCanvas, 1073 aClipBox); 1074 } 1075 } 1076 1077 // Paint the preview. 1078 if (xPreview.is()) 1079 { 1080 aSize = xPreview->getSize(); 1081 if (aSize.Width > 0 && aSize.Height > 0) 1082 { 1083 rxCanvas->drawBitmap(xPreview, aViewState, aRenderState); 1084 } 1085 } 1086 1087 // Create a polygon that is used to paint a frame around previews. Its 1088 // coordinates are chosen in the local coordinate system of a preview. 1089 if ( ! mxPreviewFrame.is()) 1090 mxPreviewFrame = PresenterGeometryHelper::CreatePolygon( 1091 awt::Rectangle(-1, -1, aSize.Width+2, aSize.Height+2), 1092 rxCanvas->getDevice()); 1093 1094 // Paint a border around the preview. 1095 if (mxPreviewFrame.is()) 1096 { 1097 const geometry::RealRectangle2D aBox (0, 0, aSize.Width, aSize.Height); 1098 const util::Color aFrameColor (0x00000000); 1099 PresenterCanvasHelper::SetDeviceColor(aRenderState, aFrameColor); 1100 rxCanvas->drawPolyPolygon(mxPreviewFrame, aViewState, aRenderState); 1101 } 1102 1103 // Paint mouse over effect. 1104 mpMouseOverManager->Paint(nSlideIndex, mxCanvas, xClip); 1105 } 1106 1107 1108 1109 1110 void PresenterSlideSorter::Paint (const awt::Rectangle& rUpdateBox) 1111 { 1112 const bool bCanvasChanged ( ! mxCanvas.is()); 1113 if ( ! ProvideCanvas()) 1114 return; 1115 1116 if (mpLayout->mnRowCount<=0 || mpLayout->mnColumnCount<=0) 1117 { 1118 OSL_ASSERT(mpLayout->mnRowCount>0 || mpLayout->mnColumnCount>0); 1119 return; 1120 } 1121 1122 mbIsPaintPending = false; 1123 1124 ClearBackground(mxCanvas, rUpdateBox); 1125 1126 // Give the canvas to the controls. 1127 if (bCanvasChanged) 1128 { 1129 if (mpHorizontalScrollBar.is()) 1130 mpHorizontalScrollBar->SetCanvas(mxCanvas); 1131 if (mpVerticalScrollBar.is()) 1132 mpVerticalScrollBar->SetCanvas(mxCanvas); 1133 if (mpCloseButton.is()) 1134 mpCloseButton->SetCanvas(mxCanvas, mxWindow); 1135 } 1136 1137 // Now that the controls have a canvas we can do the layouting. 1138 if (mbIsLayoutPending) 1139 UpdateLayout(); 1140 1141 // Paint the horizontal separator. 1142 rendering::RenderState aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0), 1143 NULL, Sequence<double>(4), rendering::CompositeOperation::SOURCE); 1144 PresenterCanvasHelper::SetDeviceColor(aRenderState, maSeparatorColor); 1145 mxCanvas->drawLine( 1146 geometry::RealPoint2D(0, mnSeparatorY), 1147 geometry::RealPoint2D(mxWindow->getPosSize().Width, mnSeparatorY), 1148 rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), NULL), 1149 aRenderState); 1150 1151 // Paint the slides. 1152 if ( ! PresenterGeometryHelper::AreRectanglesDisjoint( 1153 rUpdateBox, 1154 PresenterGeometryHelper::ConvertRectangle(mpLayout->maBoundingBox))) 1155 { 1156 mpLayout->ForAllVisibleSlides( 1157 ::boost::bind(&PresenterSlideSorter::PaintPreview, this, mxCanvas, rUpdateBox, _1)); 1158 } 1159 1160 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); 1161 if (xSpriteCanvas.is()) 1162 xSpriteCanvas->updateScreen(sal_False); 1163 } 1164 1165 1166 1167 1168 void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset) 1169 { 1170 if (mpLayout->SetHorizontalOffset(nXOffset)) 1171 { 1172 mxPreviewCache->setVisibleRange( 1173 mpLayout->GetFirstVisibleSlideIndex(), 1174 mpLayout->GetLastVisibleSlideIndex()); 1175 1176 mpPresenterController->GetPaintManager()->Invalidate(mxWindow); 1177 } 1178 } 1179 1180 1181 1182 1183 void PresenterSlideSorter::SetVerticalOffset (const double nYOffset) 1184 { 1185 if (mpLayout->SetVerticalOffset(nYOffset)) 1186 { 1187 mxPreviewCache->setVisibleRange( 1188 mpLayout->GetFirstVisibleSlideIndex(), 1189 mpLayout->GetLastVisibleSlideIndex()); 1190 1191 mpPresenterController->GetPaintManager()->Invalidate(mxWindow); 1192 } 1193 } 1194 1195 1196 1197 1198 void PresenterSlideSorter::GotoSlide (const sal_Int32 nSlideIndex) 1199 { 1200 mxSlideShowController->gotoSlideIndex(nSlideIndex); 1201 mpPresenterController->HideSlideSorter(); 1202 } 1203 1204 1205 1206 1207 bool PresenterSlideSorter::ProvideCanvas (void) 1208 { 1209 if ( ! mxCanvas.is()) 1210 { 1211 if (mxPane.is()) 1212 mxCanvas = mxPane->getCanvas(); 1213 1214 // Register as event listener so that we are informed when the 1215 // canvas is disposed (and we have to fetch another one). 1216 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY); 1217 if (xComponent.is()) 1218 xComponent->addEventListener(static_cast<awt::XWindowListener*>(this)); 1219 1220 // Tell the scrollbar about the canvas. 1221 if (mpHorizontalScrollBar.is()) 1222 mpHorizontalScrollBar->SetCanvas(mxCanvas); 1223 1224 mpCurrentSlideFrameRenderer.reset( 1225 new CurrentSlideFrameRenderer(mxComponentContext, mxCanvas)); 1226 } 1227 return mxCanvas.is(); 1228 } 1229 1230 1231 1232 1233 void PresenterSlideSorter::ThrowIfDisposed (void) 1234 throw (lang::DisposedException) 1235 { 1236 if (rBHelper.bDisposed || rBHelper.bInDispose) 1237 { 1238 throw lang::DisposedException ( 1239 OUString(RTL_CONSTASCII_USTRINGPARAM( 1240 "PresenterSlideSorter has been already disposed")), 1241 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this))); 1242 } 1243 } 1244 1245 1246 1247 1248 //===== PresenterSlideSorter::Layout ========================================== 1249 1250 PresenterSlideSorter::Layout::Layout ( 1251 const Orientation eOrientation, 1252 const ::rtl::Reference<PresenterScrollBar>& rpHorizontalScrollBar, 1253 const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar) 1254 : maBoundingBox(), 1255 maPreviewSize(), 1256 mnHorizontalOffset(0), 1257 mnVerticalOffset(0), 1258 mnHorizontalGap(0), 1259 mnVerticalGap(0), 1260 mnHorizontalBorder(0), 1261 mnVerticalBorder(0), 1262 mnRowCount(1), 1263 mnColumnCount(1), 1264 mnSlideCount(0), 1265 mnSlideIndexAtMouse(-1), 1266 mnFirstVisibleColumn(-1), 1267 mnLastVisibleColumn(-1), 1268 mnFirstVisibleRow(-1), 1269 mnLastVisibleRow(-1), 1270 meOrientation(eOrientation), 1271 mpHorizontalScrollBar(rpHorizontalScrollBar), 1272 mpVerticalScrollBar(rpVerticalScrollBar) 1273 { 1274 } 1275 1276 1277 1278 1279 void PresenterSlideSorter::Layout::Update ( 1280 const geometry::RealRectangle2D& rBoundingBox, 1281 const double nSlideAspectRatio) 1282 { 1283 maBoundingBox = rBoundingBox; 1284 1285 mnHorizontalBorder = gnHorizontalBorder; 1286 mnVerticalBorder = gnVerticalBorder; 1287 1288 const double nWidth (rBoundingBox.X2 - rBoundingBox.X1 - 2*mnHorizontalBorder); 1289 const double nHeight (rBoundingBox.Y2 - rBoundingBox.Y1 - 2*mnVerticalBorder); 1290 if (nWidth<=0 || nHeight<=0) 1291 return; 1292 1293 double nPreviewWidth; 1294 1295 // Determine column count, preview width, and horizontal gap (borders 1296 // are half the gap). Try to use the preferred values. Try more to 1297 // stay in the valid intervalls. This last constraint may be not 1298 // fullfilled in some cases. 1299 const double nElementWidth = nWidth / gnPreferredColumnCount; 1300 if (nElementWidth < gnMinimalPreviewWidth + gnMinimalHorizontalPreviewGap) 1301 { 1302 // The preferred column count is too large. 1303 // Can we use the preferred preview width? 1304 if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth) 1305 { 1306 // Yes. 1307 nPreviewWidth = gnPreferredPreviewWidth; 1308 mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap) 1309 / (nPreviewWidth+gnPreferredHorizontalPreviewGap)); 1310 mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount); 1311 } 1312 else 1313 { 1314 // No. Set the column count to 1 and adapt preview width and 1315 // gap. 1316 mnColumnCount = 1; 1317 mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap); 1318 if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth) 1319 nPreviewWidth = nWidth - gnMinimalHorizontalPreviewGap; 1320 else 1321 nPreviewWidth = ::std::max(gnMinimalPreviewWidth, nWidth-mnHorizontalGap); 1322 } 1323 } 1324 else if (nElementWidth > gnMaximalPreviewWidth + gnMaximalHorizontalPreviewGap) 1325 { 1326 // The preferred column count is too small. 1327 nPreviewWidth = gnPreferredPreviewWidth; 1328 mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap) 1329 / (nPreviewWidth+gnPreferredHorizontalPreviewGap)); 1330 mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount); 1331 } 1332 else 1333 { 1334 // The preferred column count is possible. Determine gap and 1335 // preview width. 1336 mnColumnCount = gnPreferredColumnCount; 1337 if (nElementWidth - gnPreferredPreviewWidth < gnMinimalHorizontalPreviewGap) 1338 { 1339 // Use the minimal gap and adapt the preview width. 1340 mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap); 1341 nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount; 1342 } 1343 else if (nElementWidth - gnPreferredPreviewWidth <= gnMaximalHorizontalPreviewGap) 1344 { 1345 // Use the maximal gap and adapt the preview width. 1346 mnHorizontalGap = round(gnMaximalHorizontalPreviewGap); 1347 nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount; 1348 } 1349 else 1350 { 1351 // Use the preferred preview width and adapt the gap. 1352 nPreviewWidth = gnPreferredPreviewWidth; 1353 mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount); 1354 } 1355 } 1356 1357 // Now determine the row count, preview height, and vertical gap. 1358 const double nPreviewHeight = nPreviewWidth / nSlideAspectRatio; 1359 mnRowCount = ::std::max( 1360 sal_Int32(1), 1361 sal_Int32(ceil((nHeight+gnPreferredVerticalPreviewGap) 1362 / (nPreviewHeight + gnPreferredVerticalPreviewGap)))); 1363 mnVerticalGap = round(gnPreferredVerticalPreviewGap); 1364 1365 maPreviewSize = geometry::IntegerSize2D(floor(nPreviewWidth), floor(nPreviewHeight)); 1366 1367 // Reset the offset. 1368 if (meOrientation == Horizontal) 1369 { 1370 mnVerticalOffset = round(-(nHeight 1371 - mnRowCount*maPreviewSize.Height - (mnRowCount-1)*mnVerticalGap) 1372 / 2); 1373 mnHorizontalOffset = 0; 1374 } 1375 else 1376 { 1377 mnVerticalOffset = 0; 1378 mnHorizontalOffset = round(-(nWidth 1379 - mnColumnCount*maPreviewSize.Width 1380 - (mnColumnCount-1)*mnHorizontalGap) 1381 / 2); 1382 } 1383 } 1384 1385 1386 1387 1388 void PresenterSlideSorter::Layout::SetupVisibleArea (void) 1389 { 1390 geometry::RealPoint2D aPoint (GetLocalPosition( 1391 geometry::RealPoint2D(maBoundingBox.X1, maBoundingBox.Y1))); 1392 if (meOrientation == Horizontal) 1393 { 1394 mnFirstVisibleColumn = ::std::max(sal_Int32(0), GetColumn(aPoint)); 1395 mnFirstVisibleRow = 0; 1396 } 1397 else 1398 { 1399 mnFirstVisibleColumn = 0; 1400 mnFirstVisibleRow = ::std::max(sal_Int32(0), GetRow(aPoint)); 1401 } 1402 1403 aPoint = GetLocalPosition(geometry::RealPoint2D( maBoundingBox.X2, maBoundingBox.Y2)); 1404 if (meOrientation == Horizontal) 1405 { 1406 mnLastVisibleColumn = GetColumn(aPoint, true); 1407 mnLastVisibleRow = mnRowCount - 1; 1408 } 1409 else 1410 { 1411 mnLastVisibleColumn = mnColumnCount - 1; 1412 mnLastVisibleRow = GetRow(aPoint, true); 1413 } 1414 } 1415 1416 1417 1418 1419 bool PresenterSlideSorter::Layout::IsScrollBarNeeded (const sal_Int32 nSlideCount) 1420 { 1421 geometry::RealPoint2D aBottomRight; 1422 if (GetOrientation() == Layout::Vertical) 1423 aBottomRight = GetPoint( 1424 mnColumnCount * (GetRow(nSlideCount)+1) - 1, +1, +1); 1425 else 1426 aBottomRight = GetPoint( 1427 mnRowCount * (GetColumn(nSlideCount)+1) - 1, +1, +1); 1428 return aBottomRight.X > maBoundingBox.X2-maBoundingBox.X1 1429 || aBottomRight.Y > maBoundingBox.Y2-maBoundingBox.Y1; 1430 } 1431 1432 1433 1434 1435 geometry::RealPoint2D PresenterSlideSorter::Layout::GetLocalPosition( 1436 const geometry::RealPoint2D& rWindowPoint) const 1437 { 1438 return css::geometry::RealPoint2D( 1439 rWindowPoint.X - maBoundingBox.X1 + mnHorizontalOffset, 1440 rWindowPoint.Y - maBoundingBox.Y1 + mnVerticalOffset); 1441 } 1442 1443 1444 1445 1446 geometry::RealPoint2D PresenterSlideSorter::Layout::GetWindowPosition( 1447 const geometry::RealPoint2D& rLocalPoint) const 1448 { 1449 return css::geometry::RealPoint2D( 1450 rLocalPoint.X - mnHorizontalOffset + maBoundingBox.X1, 1451 rLocalPoint.Y - mnVerticalOffset + maBoundingBox.Y1); 1452 } 1453 1454 1455 1456 1457 sal_Int32 PresenterSlideSorter::Layout::GetColumn ( 1458 const css::geometry::RealPoint2D& rLocalPoint, 1459 const bool bReturnInvalidValue) const 1460 { 1461 const sal_Int32 nColumn(floor( 1462 (rLocalPoint.X + mnHorizontalGap/2.0) / (maPreviewSize.Width+mnHorizontalGap))); 1463 if (bReturnInvalidValue 1464 || (nColumn>=mnFirstVisibleColumn && nColumn<=mnLastVisibleColumn)) 1465 { 1466 return nColumn; 1467 } 1468 else 1469 return -1; 1470 } 1471 1472 1473 1474 1475 sal_Int32 PresenterSlideSorter::Layout::GetRow ( 1476 const css::geometry::RealPoint2D& rLocalPoint, 1477 const bool bReturnInvalidValue) const 1478 { 1479 const sal_Int32 nRow (floor( 1480 (rLocalPoint.Y + mnVerticalGap/2.0) / (maPreviewSize.Height+mnVerticalGap))); 1481 if (bReturnInvalidValue 1482 || (nRow>=mnFirstVisibleRow && nRow<=mnLastVisibleRow)) 1483 { 1484 return nRow; 1485 } 1486 else 1487 return -1; 1488 } 1489 1490 1491 1492 1493 sal_Int32 PresenterSlideSorter::Layout::GetSlideIndexForPosition ( 1494 const css::geometry::RealPoint2D& rWindowPoint) const 1495 { 1496 if ( ! PresenterGeometryHelper::IsInside(maBoundingBox, rWindowPoint)) 1497 return -1; 1498 1499 const css::geometry::RealPoint2D aLocalPosition (GetLocalPosition(rWindowPoint)); 1500 const sal_Int32 nColumn (GetColumn(aLocalPosition)); 1501 const sal_Int32 nRow (GetRow(aLocalPosition)); 1502 1503 if (nColumn < 0 || nRow < 0) 1504 return -1; 1505 else 1506 { 1507 sal_Int32 nIndex (GetIndex(nRow, nColumn)); 1508 if (nIndex >= mnSlideCount) 1509 return -1; 1510 else 1511 return nIndex; 1512 } 1513 } 1514 1515 1516 1517 1518 geometry::RealPoint2D PresenterSlideSorter::Layout::GetPoint ( 1519 const sal_Int32 nSlideIndex, 1520 const sal_Int32 nRelativeHorizontalPosition, 1521 const sal_Int32 nRelativeVerticalPosition) const 1522 { 1523 sal_Int32 nColumn (GetColumn(nSlideIndex)); 1524 sal_Int32 nRow (GetRow(nSlideIndex)); 1525 1526 geometry::RealPoint2D aPosition ( 1527 mnHorizontalBorder + nColumn*(maPreviewSize.Width+mnHorizontalGap), 1528 mnVerticalBorder + nRow*(maPreviewSize.Height+mnVerticalGap)); 1529 1530 if (nRelativeHorizontalPosition >= 0) 1531 { 1532 if (nRelativeHorizontalPosition > 0) 1533 aPosition.X += maPreviewSize.Width; 1534 else 1535 aPosition.X += maPreviewSize.Width / 2.0; 1536 } 1537 if (nRelativeVerticalPosition >= 0) 1538 { 1539 if (nRelativeVerticalPosition > 0) 1540 aPosition.Y += maPreviewSize.Height; 1541 else 1542 aPosition.Y += maPreviewSize.Height / 2.0; 1543 } 1544 1545 return aPosition; 1546 } 1547 1548 1549 1550 1551 awt::Rectangle PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex) const 1552 { 1553 const geometry::RealPoint2D aWindowPosition(GetWindowPosition(GetPoint(nSlideIndex, -1, -1))); 1554 return PresenterGeometryHelper::ConvertRectangle( 1555 geometry::RealRectangle2D( 1556 aWindowPosition.X, 1557 aWindowPosition.Y, 1558 aWindowPosition.X + maPreviewSize.Width, 1559 aWindowPosition.Y + maPreviewSize.Height)); 1560 } 1561 1562 1563 1564 1565 void PresenterSlideSorter::Layout::ForAllVisibleSlides (const ::boost::function<void(sal_Int32)>& rAction) 1566 { 1567 for (sal_Int32 nRow=mnFirstVisibleRow; nRow<=mnLastVisibleRow; ++nRow) 1568 { 1569 for (sal_Int32 nColumn=mnFirstVisibleColumn; nColumn<=mnLastVisibleColumn; ++nColumn) 1570 { 1571 const sal_Int32 nSlideIndex (GetIndex(nRow, nColumn)); 1572 if (nSlideIndex >= mnSlideCount) 1573 return; 1574 rAction(nSlideIndex); 1575 } 1576 } 1577 } 1578 1579 1580 1581 1582 sal_Int32 PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex (void) const 1583 { 1584 return GetIndex(mnFirstVisibleRow, mnFirstVisibleColumn); 1585 } 1586 1587 1588 1589 1590 sal_Int32 PresenterSlideSorter::Layout::GetLastVisibleSlideIndex (void) const 1591 { 1592 return ::std::min( 1593 GetIndex(mnLastVisibleRow, mnLastVisibleColumn), 1594 mnSlideCount); 1595 } 1596 1597 1598 1599 1600 bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset) 1601 { 1602 if (mnHorizontalOffset != nOffset) 1603 { 1604 mnHorizontalOffset = round(nOffset); 1605 SetupVisibleArea(); 1606 UpdateScrollBars(); 1607 return true; 1608 } 1609 else 1610 return false; 1611 } 1612 1613 1614 1615 1616 bool PresenterSlideSorter::Layout::SetVerticalOffset (const double nOffset) 1617 { 1618 if (mnVerticalOffset != nOffset) 1619 { 1620 mnVerticalOffset = round(nOffset); 1621 SetupVisibleArea(); 1622 UpdateScrollBars(); 1623 return true; 1624 } 1625 else 1626 return false; 1627 } 1628 1629 1630 1631 1632 PresenterSlideSorter::Layout::Orientation 1633 PresenterSlideSorter::Layout::GetOrientation (void) const 1634 { 1635 return meOrientation; 1636 } 1637 1638 1639 1640 1641 void PresenterSlideSorter::Layout::UpdateScrollBars (void) 1642 { 1643 sal_Int32 nTotalColumnCount (0); 1644 sal_Int32 nTotalRowCount (0); 1645 if (meOrientation == Horizontal) 1646 { 1647 nTotalColumnCount = sal_Int32(ceil(double(mnSlideCount) / double(mnRowCount))); 1648 nTotalRowCount = mnRowCount; 1649 } 1650 else 1651 { 1652 nTotalColumnCount = mnColumnCount; 1653 nTotalRowCount = sal_Int32(ceil(double(mnSlideCount) / double(mnColumnCount))); 1654 } 1655 1656 if (mpHorizontalScrollBar.get() != NULL) 1657 { 1658 mpHorizontalScrollBar->SetTotalSize( 1659 nTotalColumnCount * maPreviewSize.Width 1660 + (nTotalColumnCount-1) * mnHorizontalGap 1661 + 2*mnHorizontalBorder); 1662 mpHorizontalScrollBar->SetThumbPosition(mnHorizontalOffset, false); 1663 mpHorizontalScrollBar->SetThumbSize(maBoundingBox.X2 - maBoundingBox.X1 + 1); 1664 mpHorizontalScrollBar->SetLineHeight(maPreviewSize.Width); 1665 } 1666 if (mpVerticalScrollBar.get() != NULL) 1667 { 1668 mpVerticalScrollBar->SetTotalSize( 1669 nTotalRowCount * maPreviewSize.Height 1670 + (nTotalRowCount-1) * mnVerticalGap 1671 + 2*mnVerticalGap); 1672 mpVerticalScrollBar->SetThumbPosition(mnVerticalOffset, false); 1673 mpVerticalScrollBar->SetThumbSize(maBoundingBox.Y2 - maBoundingBox.Y1 + 1); 1674 mpVerticalScrollBar->SetLineHeight(maPreviewSize.Height); 1675 } 1676 1677 1678 1679 // No place yet for the vertical scroll bar. 1680 } 1681 1682 1683 1684 1685 sal_Int32 PresenterSlideSorter::Layout::GetIndex ( 1686 const sal_Int32 nRow, 1687 const sal_Int32 nColumn) const 1688 { 1689 if (meOrientation == Horizontal) 1690 return nColumn * mnRowCount + nRow; 1691 else 1692 return nRow * mnColumnCount + nColumn; 1693 } 1694 1695 1696 1697 1698 sal_Int32 PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex) const 1699 { 1700 if (meOrientation == Horizontal) 1701 return nSlideIndex % mnRowCount; 1702 else 1703 return nSlideIndex / mnColumnCount; 1704 } 1705 1706 1707 1708 1709 sal_Int32 PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex) const 1710 { 1711 if (meOrientation == Horizontal) 1712 return nSlideIndex / mnRowCount; 1713 else 1714 return nSlideIndex % mnColumnCount; 1715 } 1716 1717 1718 1719 1720 //===== PresenterSlideSorter::MouseOverManager ================================ 1721 1722 PresenterSlideSorter::MouseOverManager::MouseOverManager ( 1723 const Reference<container::XIndexAccess>& rxSlides, 1724 const ::boost::shared_ptr<PresenterTheme>& rpTheme, 1725 const Reference<awt::XWindow>& rxInvalidateTarget, 1726 const ::boost::shared_ptr<PresenterPaintManager>& rpPaintManager) 1727 : mxCanvas(), 1728 mxSlides(rxSlides), 1729 mpLeftLabelBitmap(), 1730 mpCenterLabelBitmap(), 1731 mpRightLabelBitmap(), 1732 mpFont(), 1733 mnSlideIndex(-1), 1734 maSlideBoundingBox(), 1735 mxInvalidateTarget(rxInvalidateTarget), 1736 mpPaintManager(rpPaintManager) 1737 { 1738 if (rpTheme.get()!=NULL) 1739 { 1740 ::boost::shared_ptr<PresenterBitmapContainer> pBitmaps (rpTheme->GetBitmapContainer()); 1741 if (pBitmaps.get() != NULL) 1742 { 1743 mpLeftLabelBitmap = pBitmaps->GetBitmap(A2S("LabelLeft")); 1744 mpCenterLabelBitmap = pBitmaps->GetBitmap(A2S("LabelCenter")); 1745 mpRightLabelBitmap = pBitmaps->GetBitmap(A2S("LabelRight")); 1746 } 1747 1748 mpFont = rpTheme->GetFont(A2S("SlideSorterLabelFont")); 1749 } 1750 } 1751 1752 1753 1754 1755 PresenterSlideSorter::MouseOverManager::~MouseOverManager (void) 1756 { 1757 } 1758 1759 1760 1761 1762 void PresenterSlideSorter::MouseOverManager::Paint ( 1763 const sal_Int32 nSlideIndex, 1764 const Reference<rendering::XCanvas>& rxCanvas, 1765 const Reference<rendering::XPolyPolygon2D>& rxClip) 1766 { 1767 if (nSlideIndex != mnSlideIndex) 1768 return; 1769 1770 if (mxCanvas != rxCanvas) 1771 SetCanvas(rxCanvas); 1772 if (rxCanvas != NULL) 1773 { 1774 if ( ! mxBitmap.is()) 1775 mxBitmap = CreateBitmap(msText, maSlideBoundingBox.Width); 1776 if (mxBitmap.is()) 1777 { 1778 geometry::IntegerSize2D aSize (mxBitmap->getSize()); 1779 const double nXOffset (maSlideBoundingBox.X 1780 + (maSlideBoundingBox.Width - aSize.Width) / 2.0); 1781 const double nYOffset (maSlideBoundingBox.Y 1782 + (maSlideBoundingBox.Height - aSize.Height) / 2.0); 1783 rxCanvas->drawBitmap( 1784 mxBitmap, 1785 rendering::ViewState( 1786 geometry::AffineMatrix2D(1,0,0, 0,1,0), 1787 rxClip), 1788 rendering::RenderState( 1789 geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset), 1790 NULL, 1791 Sequence<double>(4), 1792 rendering::CompositeOperation::SOURCE)); 1793 } 1794 } 1795 } 1796 1797 1798 1799 1800 void PresenterSlideSorter::MouseOverManager::SetCanvas ( 1801 const Reference<rendering::XCanvas>& rxCanvas) 1802 { 1803 mxCanvas = rxCanvas; 1804 if (mpFont.get() != NULL) 1805 mpFont->PrepareFont(Reference<rendering::XCanvas>(mxCanvas, UNO_QUERY)); 1806 } 1807 1808 1809 1810 1811 void PresenterSlideSorter::MouseOverManager::SetSlide ( 1812 const sal_Int32 nSlideIndex, 1813 const awt::Rectangle& rBox) 1814 { 1815 if (mnSlideIndex == nSlideIndex) 1816 return; 1817 1818 mnSlideIndex = -1; 1819 Invalidate(); 1820 1821 maSlideBoundingBox = rBox; 1822 mnSlideIndex = nSlideIndex; 1823 1824 if (nSlideIndex >= 0) 1825 { 1826 if (mxSlides.get() != NULL) 1827 { 1828 msText = OUString(); 1829 1830 Reference<beans::XPropertySet> xSlideProperties(mxSlides->getByIndex(nSlideIndex), UNO_QUERY); 1831 if (xSlideProperties.is()) 1832 xSlideProperties->getPropertyValue(A2S("LinkDisplayName")) >>= msText; 1833 1834 if (msText.getLength() == 0) 1835 msText = A2S("Slide ") + OUString::valueOf(nSlideIndex + 1); 1836 } 1837 } 1838 else 1839 { 1840 msText = OUString(); 1841 } 1842 mxBitmap = NULL; 1843 1844 Invalidate(); 1845 } 1846 1847 1848 1849 1850 Reference<rendering::XBitmap> PresenterSlideSorter::MouseOverManager::CreateBitmap ( 1851 const OUString& rsText, 1852 const sal_Int32 nMaximalWidth) const 1853 { 1854 if ( ! mxCanvas.is()) 1855 return NULL; 1856 1857 if (mpFont.get()==NULL || !mpFont->mxFont.is()) 1858 return NULL; 1859 1860 // Long text has to be shortened. 1861 const OUString sText (GetFittingText(rsText, nMaximalWidth 1862 - 2*gnHorizontalLabelBorder 1863 - 2*gnHorizontalLabelPadding)); 1864 1865 // Determine the size of the label. Its height is defined by the 1866 // bitmaps that are used to paints its background. The width is defined 1867 // by the text. 1868 geometry::IntegerSize2D aLabelSize (CalculateLabelSize(sText)); 1869 1870 // Create a new bitmap that will contain the complete label. 1871 Reference<rendering::XBitmap> xBitmap ( 1872 mxCanvas->getDevice()->createCompatibleAlphaBitmap(aLabelSize)); 1873 1874 if ( ! xBitmap.is()) 1875 return NULL; 1876 1877 Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap, UNO_QUERY); 1878 if ( ! xBitmapCanvas.is()) 1879 return NULL; 1880 1881 // Paint the background. 1882 PaintButtonBackground(xBitmapCanvas, aLabelSize); 1883 1884 // Paint the text. 1885 if (sText.getLength() > 0) 1886 { 1887 1888 const rendering::StringContext aContext (sText, 0, sText.getLength()); 1889 const Reference<rendering::XTextLayout> xLayout (mpFont->mxFont->createTextLayout( 1890 aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0)); 1891 const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds()); 1892 1893 const double nXOffset = (aLabelSize.Width - aTextBBox.X2 + aTextBBox.X1) / 2; 1894 const double nYOffset = aLabelSize.Height 1895 - (aLabelSize.Height - aTextBBox.Y2 + aTextBBox.Y1)/2 - aTextBBox.Y2; 1896 1897 const rendering::ViewState aViewState( 1898 geometry::AffineMatrix2D(1,0,0, 0,1,0), 1899 NULL); 1900 1901 rendering::RenderState aRenderState ( 1902 geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset), 1903 NULL, 1904 Sequence<double>(4), 1905 rendering::CompositeOperation::SOURCE); 1906 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor); 1907 1908 xBitmapCanvas->drawText( 1909 aContext, 1910 mpFont->mxFont, 1911 aViewState, 1912 aRenderState, 1913 rendering::TextDirection::WEAK_LEFT_TO_RIGHT); 1914 } 1915 1916 return xBitmap; 1917 } 1918 1919 1920 1921 1922 OUString PresenterSlideSorter::MouseOverManager::GetFittingText ( 1923 const OUString& rsText, 1924 const double nMaximalWidth) const 1925 { 1926 const double nTextWidth ( 1927 PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText).Width); 1928 if (nTextWidth > nMaximalWidth) 1929 { 1930 // Text is too wide. Shorten it by removing characters from the end 1931 // and replacing them by ellipses. 1932 1933 // Guess a start value of the final string length. 1934 double nBestWidth (0); 1935 OUString sBestCandidate; 1936 sal_Int32 nLength (round(rsText.getLength() * nMaximalWidth / nTextWidth)); 1937 const OUString sEllipses (A2S("...")); 1938 while (true) 1939 { 1940 const OUString sCandidate (rsText.copy(0,nLength) + sEllipses); 1941 const double nWidth ( 1942 PresenterCanvasHelper::GetTextSize(mpFont->mxFont, sCandidate).Width); 1943 if (nWidth > nMaximalWidth) 1944 { 1945 // Candidate still too wide, shorten it. 1946 nLength -= 1; 1947 if (nLength <= 0) 1948 break; 1949 } 1950 else if (nWidth < nMaximalWidth) 1951 { 1952 // Candidate short enough. 1953 if (nWidth > nBestWidth) 1954 { 1955 // Best length so far. 1956 sBestCandidate = sCandidate; 1957 nBestWidth = nWidth; 1958 nLength += 1; 1959 if (nLength >= rsText.getLength()) 1960 break; 1961 } 1962 else 1963 break; 1964 } 1965 else 1966 { 1967 // Candidate is exactly as long as it may be. Use it 1968 // without looking any further. 1969 sBestCandidate = sCandidate; 1970 break; 1971 } 1972 } 1973 return sBestCandidate; 1974 } 1975 else 1976 return rsText; 1977 } 1978 1979 1980 1981 1982 geometry::IntegerSize2D PresenterSlideSorter::MouseOverManager::CalculateLabelSize ( 1983 const OUString& rsText) const 1984 { 1985 // Height is specified by the label bitmaps. 1986 sal_Int32 nHeight (32); 1987 if (mpCenterLabelBitmap.get() != NULL) 1988 { 1989 Reference<rendering::XBitmap> xBitmap (mpCenterLabelBitmap->GetNormalBitmap()); 1990 if (xBitmap.is()) 1991 nHeight = xBitmap->getSize().Height; 1992 } 1993 1994 // Width is specified by text width and maximal width. 1995 const geometry::RealSize2D aTextSize ( 1996 PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText)); 1997 1998 const sal_Int32 nWidth (round(aTextSize.Width + 2*gnHorizontalLabelPadding)); 1999 2000 return geometry::IntegerSize2D(nWidth, nHeight); 2001 } 2002 2003 2004 2005 2006 void PresenterSlideSorter::MouseOverManager::PaintButtonBackground ( 2007 const Reference<rendering::XBitmapCanvas>& rxCanvas, 2008 const geometry::IntegerSize2D& rSize) const 2009 { 2010 // Get the bitmaps for painting the label background. 2011 Reference<rendering::XBitmap> xLeftLabelBitmap; 2012 if (mpLeftLabelBitmap.get() != NULL) 2013 xLeftLabelBitmap = mpLeftLabelBitmap->GetNormalBitmap(); 2014 2015 Reference<rendering::XBitmap> xCenterLabelBitmap; 2016 if (mpCenterLabelBitmap.get() != NULL) 2017 xCenterLabelBitmap = mpCenterLabelBitmap->GetNormalBitmap(); 2018 2019 Reference<rendering::XBitmap> xRightLabelBitmap; 2020 if (mpRightLabelBitmap.get() != NULL) 2021 xRightLabelBitmap = mpRightLabelBitmap->GetNormalBitmap(); 2022 2023 PresenterUIPainter::PaintHorizontalBitmapComposite ( 2024 Reference<rendering::XCanvas>(rxCanvas, UNO_QUERY), 2025 awt::Rectangle(0,0, rSize.Width,rSize.Height), 2026 awt::Rectangle(0,0, rSize.Width,rSize.Height), 2027 xLeftLabelBitmap, 2028 xCenterLabelBitmap, 2029 xRightLabelBitmap); 2030 } 2031 2032 2033 2034 2035 void PresenterSlideSorter::MouseOverManager::Invalidate (void) 2036 { 2037 if (mpPaintManager.get() != NULL) 2038 mpPaintManager->Invalidate(mxInvalidateTarget, maSlideBoundingBox, true); 2039 } 2040 2041 2042 2043 2044 //===== PresenterSlideSorter::CurrentSlideFrameRenderer ======================= 2045 2046 PresenterSlideSorter::CurrentSlideFrameRenderer::CurrentSlideFrameRenderer ( 2047 const css::uno::Reference<css::uno::XComponentContext>& rxContext, 2048 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas) 2049 : mpTopLeft(), 2050 mpTop(), 2051 mpTopRight(), 2052 mpLeft(), 2053 mpRight(), 2054 mpBottomLeft(), 2055 mpBottom(), 2056 mpBottomRight(), 2057 mnTopFrameSize(0), 2058 mnLeftFrameSize(0), 2059 mnRightFrameSize(0), 2060 mnBottomFrameSize(0) 2061 { 2062 PresenterConfigurationAccess aConfiguration ( 2063 rxContext, 2064 OUString::createFromAscii("/org.openoffice.Office.extension.PresenterScreen/"), 2065 PresenterConfigurationAccess::READ_ONLY); 2066 Reference<container::XHierarchicalNameAccess> xBitmaps ( 2067 aConfiguration.GetConfigurationNode( 2068 A2S("PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps")), 2069 UNO_QUERY); 2070 if ( ! xBitmaps.is()) 2071 return; 2072 2073 PresenterBitmapContainer aContainer ( 2074 A2S("PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"), 2075 ::boost::shared_ptr<PresenterBitmapContainer>(), 2076 rxContext, 2077 rxCanvas, 2078 PresenterComponent::GetBasePath(rxContext)); 2079 2080 mpTopLeft = aContainer.GetBitmap(A2S("TopLeft")); 2081 mpTop = aContainer.GetBitmap(A2S("Top")); 2082 mpTopRight = aContainer.GetBitmap(A2S("TopRight")); 2083 mpLeft = aContainer.GetBitmap(A2S("Left")); 2084 mpRight = aContainer.GetBitmap(A2S("Right")); 2085 mpBottomLeft = aContainer.GetBitmap(A2S("BottomLeft")); 2086 mpBottom = aContainer.GetBitmap(A2S("Bottom")); 2087 mpBottomRight = aContainer.GetBitmap(A2S("BottomRight")); 2088 2089 // Determine size of frame. 2090 if (mpTop.get() != NULL) 2091 mnTopFrameSize = mpTop->mnHeight; 2092 if (mpLeft.get() != NULL) 2093 mnLeftFrameSize = mpLeft->mnWidth; 2094 if (mpRight.get() != NULL) 2095 mnRightFrameSize = mpRight->mnWidth; 2096 if (mpBottom.get() != NULL) 2097 mnBottomFrameSize = mpBottom->mnHeight; 2098 2099 if (mpTopLeft.get() != NULL) 2100 { 2101 mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopLeft->mnHeight); 2102 mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpTopLeft->mnWidth); 2103 } 2104 if (mpTopRight.get() != NULL) 2105 { 2106 mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopRight->mnHeight); 2107 mnRightFrameSize = ::std::max(mnRightFrameSize, mpTopRight->mnWidth); 2108 } 2109 if (mpBottomLeft.get() != NULL) 2110 { 2111 mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpBottomLeft->mnWidth); 2112 mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomLeft->mnHeight); 2113 } 2114 if (mpBottomRight.get() != NULL) 2115 { 2116 mnRightFrameSize = ::std::max(mnRightFrameSize, mpBottomRight->mnWidth); 2117 mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomRight->mnHeight); 2118 } 2119 } 2120 2121 2122 2123 2124 PresenterSlideSorter::CurrentSlideFrameRenderer::~CurrentSlideFrameRenderer (void) 2125 { 2126 } 2127 2128 2129 2130 2131 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintCurrentSlideFrame ( 2132 const awt::Rectangle& rSlideBoundingBox, 2133 const Reference<rendering::XCanvas>& rxCanvas, 2134 const geometry::RealRectangle2D& rClipBox) 2135 { 2136 if ( ! rxCanvas.is()) 2137 return; 2138 2139 const Reference<rendering::XPolyPolygon2D> xClip ( 2140 PresenterGeometryHelper::CreatePolygon(rClipBox, rxCanvas->getDevice())); 2141 2142 if (mpTop.get() != NULL) 2143 { 2144 PaintBitmapTiled( 2145 mpTop->GetNormalBitmap(), 2146 rxCanvas, 2147 rClipBox, 2148 rSlideBoundingBox.X, 2149 rSlideBoundingBox.Y - mpTop->mnHeight, 2150 rSlideBoundingBox.Width, 2151 mpTop->mnHeight); 2152 } 2153 if (mpLeft.get() != NULL) 2154 { 2155 PaintBitmapTiled( 2156 mpLeft->GetNormalBitmap(), 2157 rxCanvas, 2158 rClipBox, 2159 rSlideBoundingBox.X - mpLeft->mnWidth, 2160 rSlideBoundingBox.Y, 2161 mpLeft->mnWidth, 2162 rSlideBoundingBox.Height); 2163 } 2164 if (mpRight.get() != NULL) 2165 { 2166 PaintBitmapTiled( 2167 mpRight->GetNormalBitmap(), 2168 rxCanvas, 2169 rClipBox, 2170 rSlideBoundingBox.X + rSlideBoundingBox.Width, 2171 rSlideBoundingBox.Y, 2172 mpRight->mnWidth, 2173 rSlideBoundingBox.Height); 2174 } 2175 if (mpBottom.get() != NULL) 2176 { 2177 PaintBitmapTiled( 2178 mpBottom->GetNormalBitmap(), 2179 rxCanvas, 2180 rClipBox, 2181 rSlideBoundingBox.X, 2182 rSlideBoundingBox.Y + rSlideBoundingBox.Height, 2183 rSlideBoundingBox.Width, 2184 mpBottom->mnHeight); 2185 } 2186 if (mpTopLeft.get() != NULL) 2187 { 2188 PaintBitmapOnce( 2189 mpTopLeft->GetNormalBitmap(), 2190 rxCanvas, 2191 xClip, 2192 rSlideBoundingBox.X - mpTopLeft->mnWidth, 2193 rSlideBoundingBox.Y - mpTopLeft->mnHeight); 2194 } 2195 if (mpTopRight.get() != NULL) 2196 { 2197 PaintBitmapOnce( 2198 mpTopRight->GetNormalBitmap(), 2199 rxCanvas, 2200 xClip, 2201 rSlideBoundingBox.X + rSlideBoundingBox.Width, 2202 rSlideBoundingBox.Y - mpTopLeft->mnHeight); 2203 } 2204 if (mpBottomLeft.get() != NULL) 2205 { 2206 PaintBitmapOnce( 2207 mpBottomLeft->GetNormalBitmap(), 2208 rxCanvas, 2209 xClip, 2210 rSlideBoundingBox.X - mpBottomLeft->mnWidth, 2211 rSlideBoundingBox.Y + rSlideBoundingBox.Height); 2212 } 2213 if (mpBottomRight.get() != NULL) 2214 { 2215 PaintBitmapOnce( 2216 mpBottomRight->GetNormalBitmap(), 2217 rxCanvas, 2218 xClip, 2219 rSlideBoundingBox.X + rSlideBoundingBox.Width, 2220 rSlideBoundingBox.Y + rSlideBoundingBox.Height); 2221 } 2222 } 2223 2224 2225 2226 2227 awt::Rectangle PresenterSlideSorter::CurrentSlideFrameRenderer::GetBoundingBox ( 2228 const awt::Rectangle& rSlideBoundingBox) 2229 { 2230 return awt::Rectangle( 2231 rSlideBoundingBox.X - mnLeftFrameSize, 2232 rSlideBoundingBox.Y - mnTopFrameSize, 2233 rSlideBoundingBox.Width + mnLeftFrameSize + mnRightFrameSize, 2234 rSlideBoundingBox.Height + mnTopFrameSize + mnBottomFrameSize); 2235 } 2236 2237 2238 2239 2240 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapOnce( 2241 const css::uno::Reference<css::rendering::XBitmap>& rxBitmap, 2242 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas, 2243 const Reference<rendering::XPolyPolygon2D>& rxClip, 2244 const double nX, 2245 const double nY) 2246 { 2247 OSL_ASSERT(rxCanvas.is()); 2248 if ( ! rxBitmap.is()) 2249 return; 2250 2251 const rendering::ViewState aViewState( 2252 geometry::AffineMatrix2D(1,0,0, 0,1,0), 2253 rxClip); 2254 2255 const rendering::RenderState aRenderState ( 2256 geometry::AffineMatrix2D( 2257 1, 0, nX, 2258 0, 1, nY), 2259 NULL, 2260 Sequence<double>(4), 2261 rendering::CompositeOperation::SOURCE); 2262 2263 rxCanvas->drawBitmap( 2264 rxBitmap, 2265 aViewState, 2266 aRenderState); 2267 } 2268 2269 2270 2271 2272 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapTiled( 2273 const css::uno::Reference<css::rendering::XBitmap>& rxBitmap, 2274 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas, 2275 const geometry::RealRectangle2D& rClipBox, 2276 const double nX0, 2277 const double nY0, 2278 const double nWidth, 2279 const double nHeight) 2280 { 2281 OSL_ASSERT(rxCanvas.is()); 2282 if ( ! rxBitmap.is()) 2283 return; 2284 2285 geometry::IntegerSize2D aSize (rxBitmap->getSize()); 2286 2287 const rendering::ViewState aViewState( 2288 geometry::AffineMatrix2D(1,0,0, 0,1,0), 2289 PresenterGeometryHelper::CreatePolygon( 2290 PresenterGeometryHelper::Intersection( 2291 rClipBox, 2292 geometry::RealRectangle2D(nX0,nY0,nX0+nWidth,nY0+nHeight)), 2293 rxCanvas->getDevice())); 2294 2295 rendering::RenderState aRenderState ( 2296 geometry::AffineMatrix2D( 2297 1, 0, nX0, 2298 0, 1, nY0), 2299 NULL, 2300 Sequence<double>(4), 2301 rendering::CompositeOperation::SOURCE); 2302 2303 const double nX1 = nX0 + nWidth; 2304 const double nY1 = nY0 + nHeight; 2305 for (double nY=nY0; nY<nY1; nY+=aSize.Height) 2306 for (double nX=nX0; nX<nX1; nX+=aSize.Width) 2307 { 2308 aRenderState.AffineTransform.m02 = nX; 2309 aRenderState.AffineTransform.m12 = nY; 2310 rxCanvas->drawBitmap( 2311 rxBitmap, 2312 aViewState, 2313 aRenderState); 2314 } 2315 } 2316 2317 } } // end of namespace ::sdext::presenter 2318