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