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