1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/settings.hxx>
21 #include "PresenterToolBar.hxx"
22 
23 #include "PresenterBitmapContainer.hxx"
24 #include "PresenterCanvasHelper.hxx"
25 #include "PresenterGeometryHelper.hxx"
26 #include "PresenterPaintManager.hxx"
27 #include "PresenterTimer.hxx"
28 #include "PresenterWindowManager.hxx"
29 
30 #include <cppuhelper/compbase.hxx>
31 #include <com/sun/star/awt/XWindowPeer.hpp>
32 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
33 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
34 #include <com/sun/star/drawing/framework/XPane.hpp>
35 #include <com/sun/star/geometry/AffineMatrix2D.hpp>
36 #include <com/sun/star/rendering/CompositeOperation.hpp>
37 #include <com/sun/star/rendering/RenderState.hpp>
38 #include <com/sun/star/rendering/TextDirection.hpp>
39 #include <com/sun/star/rendering/ViewState.hpp>
40 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
41 #include <com/sun/star/util/Color.hpp>
42 #include <rtl/ustrbuf.hxx>
43 
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::drawing::framework;
47 
48 namespace sdext::presenter {
49 
50 const sal_Int32 gnGapSize (20);
51 
52 namespace {
53 
54     class Text
55     {
56     public:
57         Text();
58         Text (
59             const OUString& rsText,
60             const PresenterTheme::SharedFontDescriptor& rpFont);
61 
62         void SetText (const OUString& rsText);
63         const OUString& GetText() const;
64         const PresenterTheme::SharedFontDescriptor& GetFont() const;
65 
66         void Paint (
67             const Reference<rendering::XCanvas>& rxCanvas,
68             const rendering::ViewState& rViewState,
69             const awt::Rectangle& rBoundingBox);
70 
71         geometry::RealRectangle2D GetBoundingBox (
72             const Reference<rendering::XCanvas>& rxCanvas);
73 
74     private:
75         OUString msText;
76         PresenterTheme::SharedFontDescriptor mpFont;
77     };
78 
79     class ElementMode
80     {
81     public:
82         ElementMode();
83         ElementMode(const ElementMode&) = delete;
84         ElementMode& operator=(const ElementMode&) = delete;
85 
86         SharedBitmapDescriptor mpIcon;
87         OUString msAction;
88         Text maText;
89 
90         void ReadElementMode (
91             const Reference<beans::XPropertySet>& rxProperties,
92             const OUString& rsModeName,
93             std::shared_ptr<ElementMode> const & rpDefaultMode,
94             ::sdext::presenter::PresenterToolBar::Context const & rContext);
95     };
96     typedef std::shared_ptr<ElementMode> SharedElementMode;
97 
98 }  // end of anonymous namespace
99 
100 class PresenterToolBar::Context
101 {
102 public:
103     Context() = default;
104     Context(const Context&) = delete;
105     Context& operator=(const Context&) = delete;
106     Reference<drawing::XPresenterHelper> mxPresenterHelper;
107     css::uno::Reference<css::rendering::XCanvas> mxCanvas;
108 };
109 
110 //===== PresenterToolBar::Element =============================================
111 
112 namespace {
113     typedef cppu::WeakComponentImplHelper<
114         css::document::XEventListener,
115         css::frame::XStatusListener
116         > ElementInterfaceBase;
117 
118     class Element
119         : private ::cppu::BaseMutex,
120           public ElementInterfaceBase
121     {
122     public:
123         explicit Element (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
124         Element(const Element&) = delete;
125         Element& operator=(const Element&) = delete;
126 
127         virtual void SAL_CALL disposing() override;
128 
129         virtual void SetModes (
130             const SharedElementMode& rpNormalMode,
131             const SharedElementMode& rpMouseOverMode,
132             const SharedElementMode& rpSelectedMode,
133             const SharedElementMode& rpDisabledMode,
134             const SharedElementMode& rpMouseOverSelectedMode);
135         void CurrentSlideHasChanged();
136         void SetLocation (const awt::Point& rLocation);
137         void SetSize (const geometry::RealSize2D& rSize);
138         virtual void Paint (
139             const Reference<rendering::XCanvas>& rxCanvas,
140             const rendering::ViewState& rViewState) = 0;
141         awt::Size const & GetBoundingSize (
142             const Reference<rendering::XCanvas>& rxCanvas);
143         awt::Rectangle GetBoundingBox() const;
144         virtual bool SetState (const bool bIsOver, const bool bIsPressed);
145         void Invalidate (const bool bSynchronous);
146         bool IsOutside (const awt::Rectangle& rBox);
147         virtual bool IsFilling() const;
148         void UpdateState();
149 
150         // lang::XEventListener
151 
152         virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
153 
154         // document::XEventListener
155 
156         virtual void SAL_CALL notifyEvent (const css::document::EventObject& rEvent) override;
157 
158         // frame::XStatusListener
159 
160         virtual void SAL_CALL statusChanged (const css::frame::FeatureStateEvent& rEvent) override;
161 
162     protected:
163         ::rtl::Reference<PresenterToolBar> mpToolBar;
164         awt::Point maLocation;
165         awt::Size maSize;
166         SharedElementMode mpNormal;
167         SharedElementMode mpMouseOver;
168         SharedElementMode mpSelected;
169         SharedElementMode mpDisabled;
170         SharedElementMode mpMouseOverSelected;
171         SharedElementMode mpMode;
172         bool mbIsOver;
173         bool mbIsPressed;
174         bool mbIsSelected;
175 
176         virtual awt::Size CreateBoundingSize (
177             const Reference<rendering::XCanvas>& rxCanvas) = 0;
178 
IsEnabled() const179         bool IsEnabled() const { return mbIsEnabled;}
180     private:
181         bool mbIsEnabled;
182     };
183 
184 } // end of anonymous namespace
185 
186 class PresenterToolBar::ElementContainerPart
187     : public ::std::vector<rtl::Reference<Element> >
188 {
189 };
190 
191 //===== Button ================================================================
192 
193 namespace {
194 
195     class Button : public Element
196     {
197     public:
198         static ::rtl::Reference<Element> Create (
199             const ::rtl::Reference<PresenterToolBar>& rpToolBar);
200 
201         virtual void SAL_CALL disposing() override;
202 
203         virtual void Paint (
204             const Reference<rendering::XCanvas>& rxCanvas,
205             const rendering::ViewState& rViewState) override;
206 
207         // lang::XEventListener
208 
209         virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
210 
211     protected:
212         virtual awt::Size CreateBoundingSize (
213             const Reference<rendering::XCanvas>& rxCanvas) override;
214 
215     private:
216         bool mbIsListenerRegistered;
217 
218         Button (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
219         void Initialize();
220         void PaintIcon (
221             const Reference<rendering::XCanvas>& rxCanvas,
222             const sal_Int32 nTextHeight,
223             const rendering::ViewState& rViewState);
224         PresenterBitmapDescriptor::Mode GetMode() const;
225     };
226 
227 //===== Label =================================================================
228 
229     class Label : public Element
230     {
231     public:
232         explicit Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
233 
234         void SetText (const OUString& rsText);
235         virtual void Paint (
236             const Reference<rendering::XCanvas>& rxCanvas,
237             const rendering::ViewState& rViewState) override;
238         virtual bool SetState (const bool bIsOver, const bool bIsPressed) override;
239 
240     protected:
241         virtual awt::Size CreateBoundingSize (
242             const Reference<rendering::XCanvas>& rxCanvas) override;
243     };
244 
245 // Some specialized controls.
246 
247     class TimeFormatter
248     {
249     public:
250         static OUString FormatTime (const oslDateTime& rTime);
251     };
252 
253     class TimeLabel : public Label
254     {
255     public:
256         void ConnectToTimer();
257         virtual void TimeHasChanged (const oslDateTime& rCurrentTime) = 0;
258     protected:
259         explicit TimeLabel(const ::rtl::Reference<PresenterToolBar>& rpToolBar);
260         using Element::disposing;
261         virtual void SAL_CALL disposing() override;
262     private:
263         class Listener : public PresenterClockTimer::Listener
264         {
265         public:
Listener(const::rtl::Reference<TimeLabel> & rxLabel)266             explicit Listener (const ::rtl::Reference<TimeLabel>& rxLabel)
267                 : mxLabel(rxLabel) {}
~Listener()268             virtual ~Listener() {}
TimeHasChanged(const oslDateTime & rCurrentTime)269             virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override
270             { if (mxLabel.is()) mxLabel->TimeHasChanged(rCurrentTime); }
271         private:
272             ::rtl::Reference<TimeLabel> mxLabel;
273         };
274         std::shared_ptr<PresenterClockTimer::Listener> mpListener;
275     };
276 
277     class CurrentTimeLabel : public TimeLabel
278     {
279     public:
280         static ::rtl::Reference<Element> Create (
281             const ::rtl::Reference<PresenterToolBar>& rpToolBar);
282         virtual void SetModes (
283             const SharedElementMode& rpNormalMode,
284             const SharedElementMode& rpMouseOverMode,
285             const SharedElementMode& rpSelectedMode,
286             const SharedElementMode& rpDisabledMode,
287             const SharedElementMode& rpMouseOverSelectedMode) override;
288     private:
289         CurrentTimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
290         virtual ~CurrentTimeLabel() override;
291         virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
292     };
293 
294     class PresentationTimeLabel : public TimeLabel, public IPresentationTime
295     {
296     public:
297         static ::rtl::Reference<Element> Create (
298             const ::rtl::Reference<PresenterToolBar>& rpToolBar);
299         virtual void SetModes (
300             const SharedElementMode& rpNormalMode,
301             const SharedElementMode& rpMouseOverMode,
302             const SharedElementMode& rpSelectedMode,
303             const SharedElementMode& rpDisabledMode,
304             const SharedElementMode& rpMouseOverSelectedMode) override;
305         virtual void restart() override;
306         virtual bool isPaused() override;
307         virtual void setPauseStatus(const bool pauseStatus) override;
308         TimeValue getPauseTimeValue() const;
309         void setPauseTimeValue(const TimeValue pauseTime);
310     private:
311         TimeValue maStartTimeValue;
312         TimeValue pauseTimeValue;
313         PresentationTimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
314         bool paused;
315         virtual ~PresentationTimeLabel() override;
316         virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
317     };
318 
319     class VerticalSeparator : public Element
320     {
321     public:
322         explicit VerticalSeparator (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
323         virtual void Paint (
324             const Reference<rendering::XCanvas>& rxCanvas,
325             const rendering::ViewState& rViewState) override;
326         virtual bool IsFilling() const override;
327 
328     protected:
329         virtual awt::Size CreateBoundingSize (
330             const Reference<rendering::XCanvas>& rxCanvas) override;
331     };
332 
333     class HorizontalSeparator : public Element
334     {
335     public:
336         explicit HorizontalSeparator (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
337         virtual void Paint (
338             const Reference<rendering::XCanvas>& rxCanvas,
339             const rendering::ViewState& rViewState) override;
340         virtual bool IsFilling() const override;
341 
342     protected:
343         virtual awt::Size CreateBoundingSize (
344             const Reference<rendering::XCanvas>& rxCanvas) override;
345     };
346 } // end of anonymous namespace
347 
348 //===== PresenterToolBar ======================================================
349 
PresenterToolBar(const Reference<XComponentContext> & rxContext,const css::uno::Reference<css::awt::XWindow> & rxWindow,const css::uno::Reference<css::rendering::XCanvas> & rxCanvas,const::rtl::Reference<PresenterController> & rpPresenterController,const Anchor eAnchor)350 PresenterToolBar::PresenterToolBar (
351     const Reference<XComponentContext>& rxContext,
352     const css::uno::Reference<css::awt::XWindow>& rxWindow,
353     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
354     const ::rtl::Reference<PresenterController>& rpPresenterController,
355     const Anchor eAnchor)
356     : PresenterToolBarInterfaceBase(m_aMutex),
357       mxComponentContext(rxContext),
358       maElementContainer(),
359       mpCurrentContainerPart(),
360       mxWindow(rxWindow),
361       mxCanvas(rxCanvas),
362       mxSlideShowController(),
363       mxCurrentSlide(),
364       mpPresenterController(rpPresenterController),
365       mbIsLayoutPending(false),
366       meAnchor(eAnchor),
367       maMinimalSize()
368 {
369 }
370 
Initialize(const OUString & rsConfigurationPath)371 void PresenterToolBar::Initialize (
372     const OUString& rsConfigurationPath)
373 {
374     try
375     {
376         CreateControls(rsConfigurationPath);
377 
378         if (mxWindow.is())
379         {
380             mxWindow->addWindowListener(this);
381             mxWindow->addPaintListener(this);
382             mxWindow->addMouseListener(this);
383             mxWindow->addMouseMotionListener(this);
384 
385             Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
386             if (xPeer.is())
387                 xPeer->setBackground(util::Color(0xff000000));
388 
389             mxWindow->setVisible(true);
390         }
391 
392         mxSlideShowController = mpPresenterController->GetSlideShowController();
393         UpdateSlideNumber();
394         mbIsLayoutPending = true;
395     }
396     catch (RuntimeException&)
397     {
398         mpCurrentContainerPart.reset();
399         maElementContainer.clear();
400         throw;
401     }
402 }
403 
~PresenterToolBar()404 PresenterToolBar::~PresenterToolBar()
405 {
406 }
407 
disposing()408 void SAL_CALL PresenterToolBar::disposing()
409 {
410     if (mxWindow.is())
411     {
412         mxWindow->removeWindowListener(this);
413         mxWindow->removePaintListener(this);
414         mxWindow->removeMouseListener(this);
415         mxWindow->removeMouseMotionListener(this);
416         mxWindow = nullptr;
417     }
418 
419     // Dispose tool bar elements.
420     for (const auto& rxPart : maElementContainer)
421     {
422         OSL_ASSERT(rxPart != nullptr);
423         for (rtl::Reference<Element>& pElement : *rxPart)
424         {
425             if (pElement)
426             {
427                 Reference<lang::XComponent> xComponent (
428                     static_cast<XWeak*>(pElement.get()), UNO_QUERY);
429                 if (xComponent.is())
430                     xComponent->dispose();
431             }
432         }
433     }
434 
435     mpCurrentContainerPart.reset();
436     maElementContainer.clear();
437 }
438 
InvalidateArea(const awt::Rectangle & rRepaintBox,const bool bSynchronous)439 void PresenterToolBar::InvalidateArea (
440     const awt::Rectangle& rRepaintBox,
441     const bool bSynchronous)
442 {
443     std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
444     if (!xManager)
445         return;
446     xManager->Invalidate(
447         mxWindow,
448         rRepaintBox,
449         bSynchronous);
450 }
451 
RequestLayout()452 void PresenterToolBar::RequestLayout()
453 {
454     mbIsLayoutPending = true;
455 
456     std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
457     if (!xManager)
458         return;
459 
460     xManager->Invalidate(mxWindow);
461 }
462 
GetMinimalSize()463 geometry::RealSize2D const & PresenterToolBar::GetMinimalSize()
464 {
465     if (mbIsLayoutPending)
466         Layout(mxCanvas);
467     return maMinimalSize;
468 }
469 
GetPresenterController() const470 const ::rtl::Reference<PresenterController>& PresenterToolBar::GetPresenterController() const
471 {
472     return mpPresenterController;
473 }
474 
GetComponentContext() const475 const Reference<XComponentContext>& PresenterToolBar::GetComponentContext() const
476 {
477     return mxComponentContext;
478 }
479 
480 //-----  lang::XEventListener -------------------------------------------------
481 
disposing(const lang::EventObject & rEventObject)482 void SAL_CALL PresenterToolBar::disposing (const lang::EventObject& rEventObject)
483 {
484     if (rEventObject.Source == mxWindow)
485         mxWindow = nullptr;
486 }
487 
488 //----- XWindowListener -------------------------------------------------------
489 
windowResized(const awt::WindowEvent &)490 void SAL_CALL PresenterToolBar::windowResized (const awt::WindowEvent&)
491 {
492     mbIsLayoutPending = true;
493 }
494 
windowMoved(const awt::WindowEvent &)495 void SAL_CALL PresenterToolBar::windowMoved (const awt::WindowEvent&) {}
496 
windowShown(const lang::EventObject &)497 void SAL_CALL PresenterToolBar::windowShown (const lang::EventObject&)
498 {
499     mbIsLayoutPending = true;
500 }
501 
windowHidden(const lang::EventObject &)502 void SAL_CALL PresenterToolBar::windowHidden (const lang::EventObject&) {}
503 
504 //----- XPaintListener --------------------------------------------------------
windowPaint(const css::awt::PaintEvent & rEvent)505 void SAL_CALL PresenterToolBar::windowPaint (const css::awt::PaintEvent& rEvent)
506 {
507     if ( ! mxCanvas.is())
508         return;
509 
510     if ( ! mbIsPresenterViewActive)
511         return;
512 
513     const rendering::ViewState aViewState (
514         geometry::AffineMatrix2D(1,0,0, 0,1,0),
515         PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice()));
516 
517     if (mbIsLayoutPending)
518         Layout(mxCanvas);
519 
520     Paint(rEvent.UpdateRect, aViewState);
521 
522     // Make the back buffer visible.
523     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
524     if (xSpriteCanvas.is())
525         xSpriteCanvas->updateScreen(false);
526 }
527 
528 //----- XMouseListener --------------------------------------------------------
mousePressed(const css::awt::MouseEvent & rEvent)529 void SAL_CALL PresenterToolBar::mousePressed (const css::awt::MouseEvent& rEvent)
530 {
531         ThrowIfDisposed();
532         CheckMouseOver(rEvent, true, true);
533 }
534 
mouseReleased(const css::awt::MouseEvent & rEvent)535 void SAL_CALL PresenterToolBar::mouseReleased (const css::awt::MouseEvent& rEvent)
536 {
537         ThrowIfDisposed();
538         CheckMouseOver(rEvent, true);
539 }
540 
mouseEntered(const css::awt::MouseEvent & rEvent)541 void SAL_CALL PresenterToolBar::mouseEntered (const css::awt::MouseEvent& rEvent)
542 {
543         ThrowIfDisposed();
544         CheckMouseOver(rEvent, true);
545 }
546 
mouseExited(const css::awt::MouseEvent & rEvent)547 void SAL_CALL PresenterToolBar::mouseExited (const css::awt::MouseEvent& rEvent)
548 {
549         ThrowIfDisposed();
550         CheckMouseOver(rEvent, false);
551  }
552 
553 //----- XMouseMotionListener --------------------------------------------------
554 
mouseMoved(const css::awt::MouseEvent & rEvent)555 void SAL_CALL PresenterToolBar::mouseMoved (const css::awt::MouseEvent& rEvent)
556 {
557         ThrowIfDisposed();
558         CheckMouseOver(rEvent, true);
559  }
560 
mouseDragged(const css::awt::MouseEvent &)561 void SAL_CALL PresenterToolBar::mouseDragged (const css::awt::MouseEvent&)
562 {
563     ThrowIfDisposed();
564 }
565 
566 //----- XDrawView -------------------------------------------------------------
567 
setCurrentPage(const Reference<drawing::XDrawPage> & rxSlide)568 void SAL_CALL PresenterToolBar::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
569 {
570     if (rxSlide != mxCurrentSlide)
571     {
572         mxCurrentSlide = rxSlide;
573         UpdateSlideNumber();
574     }
575 }
576 
getCurrentPage()577 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBar::getCurrentPage()
578 {
579     return mxCurrentSlide;
580 }
581 
582 
CreateControls(const OUString & rsConfigurationPath)583 void PresenterToolBar::CreateControls (
584     const OUString& rsConfigurationPath)
585 {
586     if ( ! mxWindow.is())
587         return;
588 
589     // Expand the macro in the bitmap file names.
590     PresenterConfigurationAccess aConfiguration (
591         mxComponentContext,
592         "/org.openoffice.Office.PresenterScreen/",
593         PresenterConfigurationAccess::READ_ONLY);
594 
595     mpCurrentContainerPart = std::make_shared<ElementContainerPart>();
596     maElementContainer.clear();
597     maElementContainer.push_back(mpCurrentContainerPart);
598 
599     Reference<container::XHierarchicalNameAccess> xToolBarNode (
600         aConfiguration.GetConfigurationNode(rsConfigurationPath),
601         UNO_QUERY);
602     if (!xToolBarNode.is())
603         return;
604 
605     Reference<container::XNameAccess> xEntries (
606         PresenterConfigurationAccess::GetConfigurationNode(xToolBarNode, "Entries"),
607         UNO_QUERY);
608     Context aContext;
609     aContext.mxPresenterHelper = mpPresenterController->GetPresenterHelper();
610     aContext.mxCanvas = mxCanvas;
611     if (xEntries.is()
612         && aContext.mxPresenterHelper.is()
613         && aContext.mxCanvas.is())
614     {
615         PresenterConfigurationAccess::ForAll(
616             xEntries,
617             [this, &aContext] (OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
618             {
619                 return this->ProcessEntry(xProps, aContext);
620             });
621     }
622 }
623 
ProcessEntry(const Reference<beans::XPropertySet> & rxProperties,Context const & rContext)624 void PresenterToolBar::ProcessEntry (
625     const Reference<beans::XPropertySet>& rxProperties,
626     Context const & rContext)
627 {
628     if ( ! rxProperties.is())
629         return;
630 
631     // Type has to be present.
632     OUString sType;
633     if ( ! (PresenterConfigurationAccess::GetProperty(rxProperties, "Type") >>= sType))
634         return;
635 
636     // Read mode specific values.
637     SharedElementMode pNormalMode  = std::make_shared<ElementMode>();
638     SharedElementMode pMouseOverMode = std::make_shared<ElementMode>();
639     SharedElementMode pSelectedMode = std::make_shared<ElementMode>();
640     SharedElementMode pDisabledMode = std::make_shared<ElementMode>();
641     SharedElementMode pMouseOverSelectedMode = std::make_shared<ElementMode>();
642     pNormalMode->ReadElementMode(rxProperties, "Normal", pNormalMode, rContext);
643     pMouseOverMode->ReadElementMode(rxProperties, "MouseOver", pNormalMode, rContext);
644     pSelectedMode->ReadElementMode(rxProperties, "Selected", pNormalMode, rContext);
645     pDisabledMode->ReadElementMode(rxProperties, "Disabled", pNormalMode, rContext);
646     pMouseOverSelectedMode->ReadElementMode(rxProperties, "MouseOverSelected", pSelectedMode, rContext);
647 
648     // Create new element.
649     ::rtl::Reference<Element> pElement;
650     if ( sType == "Button" )
651         pElement = Button::Create(this);
652     else if ( sType == "CurrentTimeLabel" )
653         pElement = CurrentTimeLabel::Create(this);
654     else if ( sType == "PresentationTimeLabel" )
655         pElement = PresentationTimeLabel::Create(this);
656     else if ( sType == "VerticalSeparator" )
657         pElement.set(new VerticalSeparator(this));
658     else if ( sType == "HorizontalSeparator" )
659         pElement.set(new HorizontalSeparator(this));
660     else if ( sType == "Label" )
661         pElement.set(new Label(this));
662     else if ( sType == "ChangeOrientation" )
663     {
664         mpCurrentContainerPart = std::make_shared<ElementContainerPart>();
665         maElementContainer.push_back(mpCurrentContainerPart);
666         return;
667     }
668     if (pElement.is())
669     {
670         pElement->SetModes( pNormalMode, pMouseOverMode, pSelectedMode, pDisabledMode, pMouseOverSelectedMode);
671         pElement->UpdateState();
672         if (mpCurrentContainerPart)
673             mpCurrentContainerPart->push_back(pElement);
674     }
675 }
676 
Layout(const Reference<rendering::XCanvas> & rxCanvas)677 void PresenterToolBar::Layout (
678     const Reference<rendering::XCanvas>& rxCanvas)
679 {
680     if (maElementContainer.empty())
681         return;
682 
683     mbIsLayoutPending = false;
684 
685     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
686     ::std::vector<geometry::RealSize2D> aPartSizes (maElementContainer.size());
687     geometry::RealSize2D aTotalSize (0,0);
688     bool bIsHorizontal (true);
689     sal_Int32 nIndex (0);
690     double nTotalHorizontalGap (0);
691     sal_Int32 nGapCount (0);
692     for (const auto& rxPart : maElementContainer)
693     {
694         geometry::RealSize2D aSize (CalculatePartSize(rxCanvas, rxPart, bIsHorizontal));
695 
696         // Remember the size of each part for later.
697         aPartSizes[nIndex] = aSize;
698 
699         // Add gaps between elements.
700         if (rxPart->size()>1 && bIsHorizontal)
701         {
702             nTotalHorizontalGap += (rxPart->size() - 1) * gnGapSize;
703             nGapCount += rxPart->size() - 1;
704         }
705 
706         // Orientation changes for each part.
707         bIsHorizontal = !bIsHorizontal;
708         // Width is accumulated.
709         aTotalSize.Width += aSize.Width;
710         // Height is the maximum height of all parts.
711         aTotalSize.Height = ::std::max(aTotalSize.Height, aSize.Height);
712         ++nIndex;
713     }
714     // Add gaps between parts.
715     if (maElementContainer.size() > 1)
716     {
717         nTotalHorizontalGap += (maElementContainer.size() - 1) * gnGapSize;
718         nGapCount += maElementContainer.size()-1;
719     }
720 
721     // Done to introduce gap between the end of the toolbar and the last button
722     aTotalSize.Width += gnGapSize/2;
723 
724     // Calculate the minimal size so that the window size of the tool bar
725     // can be adapted accordingly.
726     maMinimalSize = aTotalSize;
727     maMinimalSize.Width += nTotalHorizontalGap;
728 
729     // Calculate the gaps between elements.
730     double nGapWidth (0);
731     if (nGapCount > 0)
732     {
733         if (aTotalSize.Width + nTotalHorizontalGap > aWindowBox.Width)
734             nTotalHorizontalGap = aWindowBox.Width - aTotalSize.Width;
735         nGapWidth = nTotalHorizontalGap / nGapCount;
736     }
737 
738     // Determine the location of the left edge.
739     double nX (0);
740     switch (meAnchor)
741     {
742         case Left : nX = 0; break;
743         case Center: nX = (aWindowBox.Width - aTotalSize.Width - nTotalHorizontalGap) / 2; break;
744     }
745 
746     // Place the parts.
747     double nY ((aWindowBox.Height - aTotalSize.Height) / 2);
748     bIsHorizontal = true;
749 
750     /* push front or back ? ... */
751     /// check whether RTL interface or not
752     if(!AllSettings::GetLayoutRTL()){
753         nIndex = 0;
754         for (const auto& rxPart : maElementContainer)
755         {
756             geometry::RealRectangle2D aBoundingBox(
757                 nX, nY,
758                 nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height);
759 
760             // Add space for gaps between elements.
761             if (rxPart->size() > 1 && bIsHorizontal)
762                 aBoundingBox.X2 += (rxPart->size() - 1) * nGapWidth;
763 
764             LayoutPart(rxCanvas, rxPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal);
765             bIsHorizontal = !bIsHorizontal;
766             nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth;
767             ++nIndex;
768         }
769     }
770     else {
771         ElementContainer::iterator iPart;
772         ElementContainer::iterator iBegin (maElementContainer.begin());
773         for (iPart=maElementContainer.end()-1, nIndex=2; iPart!=iBegin-1; --iPart, --nIndex)
774         {
775             geometry::RealRectangle2D aBoundingBox(
776                 nX, nY,
777                 nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height);
778 
779             // Add space for gaps between elements.
780             if ((*iPart)->size() > 1)
781                 if (bIsHorizontal)
782                     aBoundingBox.X2 += ((*iPart)->size()-1) * nGapWidth;
783 
784             LayoutPart(rxCanvas, *iPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal);
785             bIsHorizontal = !bIsHorizontal;
786             nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth;
787         }
788     }
789 
790     // The whole window has to be repainted.
791     std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
792     if (!xManager)
793         return;
794     xManager->Invalidate(mxWindow);
795 }
796 
CalculatePartSize(const Reference<rendering::XCanvas> & rxCanvas,const SharedElementContainerPart & rpPart,const bool bIsHorizontal)797 geometry::RealSize2D PresenterToolBar::CalculatePartSize (
798     const Reference<rendering::XCanvas>& rxCanvas,
799     const SharedElementContainerPart& rpPart,
800     const bool bIsHorizontal)
801 {
802     geometry::RealSize2D aTotalSize (0,0);
803 
804     if (mxWindow.is())
805     {
806         // Calculate the summed width of all elements.
807         for (const auto& rxElement : *rpPart)
808         {
809             if (!rxElement)
810                 continue;
811 
812             const awt::Size aBSize (rxElement->GetBoundingSize(rxCanvas));
813             if (bIsHorizontal)
814             {
815                 aTotalSize.Width += aBSize.Width;
816                 if (aBSize.Height > aTotalSize.Height)
817                     aTotalSize.Height = aBSize.Height;
818             }
819             else
820             {
821                 aTotalSize.Height += aBSize.Height;
822                 if (aBSize.Width > aTotalSize.Width)
823                     aTotalSize.Width = aBSize.Width;
824             }
825         }
826     }
827     return aTotalSize;
828 }
829 
LayoutPart(const Reference<rendering::XCanvas> & rxCanvas,const SharedElementContainerPart & rpPart,const geometry::RealRectangle2D & rBoundingBox,const geometry::RealSize2D & rPartSize,const bool bIsHorizontal)830 void PresenterToolBar::LayoutPart (
831     const Reference<rendering::XCanvas>& rxCanvas,
832     const SharedElementContainerPart& rpPart,
833     const geometry::RealRectangle2D& rBoundingBox,
834     const geometry::RealSize2D& rPartSize,
835     const bool bIsHorizontal)
836 {
837     double nGap (0);
838     if (rpPart->size() > 1)
839     {
840         if (bIsHorizontal)
841             nGap = (rBoundingBox.X2 - rBoundingBox.X1 - rPartSize.Width) / (rpPart->size()-1);
842         else
843             nGap = (rBoundingBox.Y2 - rBoundingBox.Y1 - rPartSize.Height) / (rpPart->size()-1);
844     }
845 
846     // Place the elements.
847     double nX (rBoundingBox.X1);
848     double nY (rBoundingBox.Y1);
849 
850     /// check whether RTL interface or not
851     if(!AllSettings::GetLayoutRTL()){
852         for (auto& rxElement : *rpPart)
853         {
854             if (!rxElement)
855                 continue;
856 
857             const awt::Size aElementSize (rxElement->GetBoundingSize(rxCanvas));
858             if (bIsHorizontal)
859             {
860                 if (rxElement->IsFilling())
861                 {
862                     nY = rBoundingBox.Y1;
863                     rxElement->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
864                 }
865                 else
866                     nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
867                 rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
868                 nX += aElementSize.Width + nGap;
869             }
870             else
871             {
872                 if (rxElement->IsFilling())
873                 {
874                     nX = rBoundingBox.X1;
875                     rxElement->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aElementSize.Height));
876                 }
877                 else
878                     nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aElementSize.Width) / 2;
879                 rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
880                 nY += aElementSize.Height + nGap;
881             }
882         }
883     }
884     else {
885         ElementContainerPart::const_iterator iElement;
886         ElementContainerPart::const_iterator iBegin (rpPart->begin());
887 
888         for (iElement=rpPart->end()-1; iElement!=iBegin-1; --iElement)
889         {
890             if (iElement->get() == nullptr)
891                 continue;
892 
893             const awt::Size aElementSize ((*iElement)->GetBoundingSize(rxCanvas));
894             if (bIsHorizontal)
895             {
896                 if ((*iElement)->IsFilling())
897                 {
898                     nY = rBoundingBox.Y1;
899                     (*iElement)->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
900                 }
901                 else
902                     nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
903                 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
904                 nX += aElementSize.Width + nGap;
905             }
906             else
907             {
908                 // reverse presentation time with current time
909                 if (iElement==iBegin){
910                     iElement=iBegin+2;
911                 }
912                 else if (iElement==iBegin+2){
913                     iElement=iBegin;
914                 }
915                 const awt::Size aNewElementSize ((*iElement)->GetBoundingSize(rxCanvas));
916                 if ((*iElement)->IsFilling())
917                 {
918                     nX = rBoundingBox.X1;
919                     (*iElement)->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aNewElementSize.Height));
920                 }
921                 else
922                     nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aNewElementSize.Width) / 2;
923                 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
924                 nY += aNewElementSize.Height + nGap;
925 
926                 // return the index as it was before the reversing
927                 if (iElement==iBegin)
928                     iElement=iBegin+2;
929                 else if (iElement==iBegin+2)
930                     iElement=iBegin;
931             }
932         }
933     }
934 }
935 
Paint(const awt::Rectangle & rUpdateBox,const rendering::ViewState & rViewState)936 void PresenterToolBar::Paint (
937     const awt::Rectangle& rUpdateBox,
938     const rendering::ViewState& rViewState)
939 {
940     OSL_ASSERT(mxCanvas.is());
941 
942     for (const auto& rxPart : maElementContainer)
943     {
944         for (auto& rxElement : *rxPart)
945         {
946             if (rxElement)
947             {
948                 if ( ! rxElement->IsOutside(rUpdateBox))
949                     rxElement->Paint(mxCanvas, rViewState);
950             }
951         }
952     }
953 }
954 
UpdateSlideNumber()955 void PresenterToolBar::UpdateSlideNumber()
956 {
957     if( mxSlideShowController.is() )
958     {
959         for (const auto& rxPart : maElementContainer)
960         {
961             for (auto& rxElement : *rxPart)
962             {
963                 if (rxElement)
964                     rxElement->CurrentSlideHasChanged();
965             }
966         }
967     }
968 }
969 
CheckMouseOver(const css::awt::MouseEvent & rEvent,const bool bOverWindow,const bool bMouseDown)970 void PresenterToolBar::CheckMouseOver (
971     const css::awt::MouseEvent& rEvent,
972     const bool bOverWindow,
973     const bool bMouseDown)
974 {
975     css::awt::MouseEvent rTemp =rEvent;
976     if(AllSettings::GetLayoutRTL()){
977         awt::Rectangle aWindowBox = mxWindow->getPosSize();
978         rTemp.X=aWindowBox.Width-rTemp.X;
979     }
980     for (const auto& rxPart : maElementContainer)
981     {
982         for (auto& rxElement : *rxPart)
983         {
984             if (!rxElement)
985                 continue;
986 
987             awt::Rectangle aBox (rxElement->GetBoundingBox());
988             const bool bIsOver = bOverWindow
989                 && aBox.X <= rTemp.X
990                 && aBox.Width+aBox.X-1 >= rTemp.X
991                 && aBox.Y <= rTemp.Y
992                 && aBox.Height+aBox.Y-1 >= rTemp.Y;
993             rxElement->SetState(
994                 bIsOver,
995                 bIsOver && rTemp.Buttons!=0 && bMouseDown && rTemp.ClickCount>0);
996         }
997     }
998 }
999 
ThrowIfDisposed() const1000 void PresenterToolBar::ThrowIfDisposed() const
1001 {
1002     if (rBHelper.bDisposed || rBHelper.bInDispose)
1003     {
1004         throw lang::DisposedException (
1005             "PresenterToolBar has already been disposed",
1006             const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
1007     }
1008 }
1009 
1010 //===== PresenterToolBarView ==================================================
1011 
PresenterToolBarView(const Reference<XComponentContext> & rxContext,const Reference<XResourceId> & rxViewId,const Reference<frame::XController> & rxController,const::rtl::Reference<PresenterController> & rpPresenterController)1012 PresenterToolBarView::PresenterToolBarView (
1013     const Reference<XComponentContext>& rxContext,
1014     const Reference<XResourceId>& rxViewId,
1015     const Reference<frame::XController>& rxController,
1016     const ::rtl::Reference<PresenterController>& rpPresenterController)
1017     : PresenterToolBarViewInterfaceBase(m_aMutex),
1018       mxPane(),
1019       mxViewId(rxViewId),
1020       mxWindow(),
1021       mxCanvas(),
1022       mpPresenterController(rpPresenterController),
1023       mpToolBar()
1024 {
1025     try
1026     {
1027         Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
1028         Reference<XConfigurationController> xCC(xCM->getConfigurationController(),UNO_SET_THROW);
1029         mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
1030 
1031         mxWindow = mxPane->getWindow();
1032         mxCanvas = mxPane->getCanvas();
1033 
1034         mpToolBar = new PresenterToolBar(
1035             rxContext,
1036             mxWindow,
1037             mxCanvas,
1038             rpPresenterController,
1039             PresenterToolBar::Center);
1040         mpToolBar->Initialize("PresenterScreenSettings/ToolBars/ToolBar");
1041 
1042         if (mxWindow.is())
1043         {
1044             mxWindow->addPaintListener(this);
1045 
1046             Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
1047             if (xPeer.is())
1048                 xPeer->setBackground(util::Color(0xff000000));
1049 
1050             mxWindow->setVisible(true);
1051         }
1052     }
1053     catch (RuntimeException&)
1054     {
1055         mxViewId = nullptr;
1056         throw;
1057     }
1058 }
1059 
~PresenterToolBarView()1060 PresenterToolBarView::~PresenterToolBarView()
1061 {
1062 }
1063 
disposing()1064 void SAL_CALL PresenterToolBarView::disposing()
1065 {
1066     Reference<lang::XComponent> xComponent (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY);
1067     mpToolBar = nullptr;
1068     if (xComponent.is())
1069         xComponent->dispose();
1070 
1071     if (mxWindow.is())
1072     {
1073         mxWindow->removePaintListener(this);
1074         mxWindow = nullptr;
1075     }
1076     mxCanvas = nullptr;
1077     mxViewId = nullptr;
1078     mxPane = nullptr;
1079     mpPresenterController = nullptr;
1080 }
1081 
GetPresenterToolBar() const1082 const ::rtl::Reference<PresenterToolBar>& PresenterToolBarView::GetPresenterToolBar() const
1083 {
1084     return mpToolBar;
1085 }
1086 
1087 //----- XPaintListener --------------------------------------------------------
1088 
windowPaint(const css::awt::PaintEvent & rEvent)1089 void SAL_CALL PresenterToolBarView::windowPaint (const css::awt::PaintEvent& rEvent)
1090 {
1091     awt::Rectangle aWindowBox (mxWindow->getPosSize());
1092     mpPresenterController->GetCanvasHelper()->Paint(
1093         mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
1094         mxCanvas,
1095         rEvent.UpdateRect,
1096         awt::Rectangle(0,0,aWindowBox.Width, aWindowBox.Height),
1097         awt::Rectangle());
1098 }
1099 
1100 //-----  lang::XEventListener -------------------------------------------------
1101 
disposing(const lang::EventObject & rEventObject)1102 void SAL_CALL PresenterToolBarView::disposing (const lang::EventObject& rEventObject)
1103 {
1104     if (rEventObject.Source == mxWindow)
1105         mxWindow = nullptr;
1106 }
1107 
1108 //----- XResourceId -----------------------------------------------------------
1109 
getResourceId()1110 Reference<XResourceId> SAL_CALL PresenterToolBarView::getResourceId()
1111 {
1112     return mxViewId;
1113 }
1114 
isAnchorOnly()1115 sal_Bool SAL_CALL PresenterToolBarView::isAnchorOnly()
1116 {
1117     return false;
1118 }
1119 
1120 //----- XDrawView -------------------------------------------------------------
1121 
setCurrentPage(const Reference<drawing::XDrawPage> & rxSlide)1122 void SAL_CALL PresenterToolBarView::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
1123 {
1124     Reference<drawing::XDrawView> xToolBar (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY);
1125     if (xToolBar.is())
1126         xToolBar->setCurrentPage(rxSlide);
1127 }
1128 
getCurrentPage()1129 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBarView::getCurrentPage()
1130 {
1131     return nullptr;
1132 }
1133 
1134 //===== PresenterToolBar::Element =============================================
1135 
1136 namespace {
1137 
Element(const::rtl::Reference<PresenterToolBar> & rpToolBar)1138 Element::Element (
1139     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1140     : ElementInterfaceBase(m_aMutex),
1141       mpToolBar(rpToolBar),
1142       maLocation(),
1143       maSize(),
1144       mpNormal(),
1145       mpMouseOver(),
1146       mpSelected(),
1147       mpDisabled(),
1148       mpMouseOverSelected(),
1149       mpMode(),
1150       mbIsOver(false),
1151       mbIsPressed(false),
1152       mbIsSelected(false),
1153       mbIsEnabled(true)
1154 {
1155     if (mpToolBar)
1156     {
1157         OSL_ASSERT(mpToolBar->GetPresenterController().is());
1158         OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1159     }
1160 }
1161 
SetModes(const SharedElementMode & rpNormalMode,const SharedElementMode & rpMouseOverMode,const SharedElementMode & rpSelectedMode,const SharedElementMode & rpDisabledMode,const SharedElementMode & rpMouseOverSelectedMode)1162 void Element::SetModes (
1163     const SharedElementMode& rpNormalMode,
1164     const SharedElementMode& rpMouseOverMode,
1165     const SharedElementMode& rpSelectedMode,
1166     const SharedElementMode& rpDisabledMode,
1167     const SharedElementMode& rpMouseOverSelectedMode)
1168 {
1169     mpNormal = rpNormalMode;
1170     mpMouseOver = rpMouseOverMode;
1171     mpSelected = rpSelectedMode;
1172     mpDisabled = rpDisabledMode;
1173     mpMouseOverSelected = rpMouseOverSelectedMode;
1174     mpMode = rpNormalMode;
1175 }
1176 
disposing()1177 void Element::disposing()
1178 {
1179 }
1180 
GetBoundingSize(const Reference<rendering::XCanvas> & rxCanvas)1181 awt::Size const & Element::GetBoundingSize (
1182     const Reference<rendering::XCanvas>& rxCanvas)
1183 {
1184     maSize = CreateBoundingSize(rxCanvas);
1185     return maSize;
1186 }
1187 
GetBoundingBox() const1188 awt::Rectangle Element::GetBoundingBox() const
1189 {
1190     return awt::Rectangle(maLocation.X,maLocation.Y, maSize.Width, maSize.Height);
1191 }
1192 
CurrentSlideHasChanged()1193 void Element::CurrentSlideHasChanged()
1194 {
1195     UpdateState();
1196 }
1197 
SetLocation(const awt::Point & rLocation)1198 void Element::SetLocation (const awt::Point& rLocation)
1199 {
1200     maLocation = rLocation;
1201 }
1202 
SetSize(const geometry::RealSize2D & rSize)1203 void Element::SetSize (const geometry::RealSize2D& rSize)
1204 {
1205     maSize = awt::Size(sal_Int32(0.5+rSize.Width), sal_Int32(0.5+rSize.Height));
1206 }
1207 
SetState(const bool bIsOver,const bool bIsPressed)1208 bool Element::SetState (
1209     const bool bIsOver,
1210     const bool bIsPressed)
1211 {
1212     bool bModified (mbIsOver != bIsOver || mbIsPressed != bIsPressed);
1213     bool bClicked (mbIsPressed && bIsOver && ! bIsPressed);
1214 
1215     mbIsOver = bIsOver;
1216     mbIsPressed = bIsPressed;
1217 
1218     // When the element is disabled then ignore mouse over or selection.
1219     // When the element is selected then ignore mouse over.
1220     if ( ! mbIsEnabled)
1221         mpMode = mpDisabled;
1222     else if (mbIsSelected && mbIsOver)
1223         mpMode = mpMouseOverSelected;
1224     else if (mbIsSelected)
1225         mpMode = mpSelected;
1226     else if (mbIsOver)
1227         mpMode = mpMouseOver;
1228     else
1229         mpMode = mpNormal;
1230 
1231     if (bClicked && mbIsEnabled)
1232     {
1233         if (mpMode)
1234         {
1235             do
1236             {
1237                 if (mpMode->msAction.isEmpty())
1238                     break;
1239 
1240                 if (!mpToolBar)
1241                     break;
1242 
1243                 if (!mpToolBar->GetPresenterController())
1244                     break;
1245 
1246                 mpToolBar->GetPresenterController()->DispatchUnoCommand(mpMode->msAction);
1247                 mpToolBar->RequestLayout();
1248             }
1249             while (false);
1250         }
1251 
1252     }
1253     else if (bModified)
1254     {
1255         Invalidate(true);
1256     }
1257 
1258     return bModified;
1259 }
1260 
Invalidate(const bool bSynchronous)1261 void Element::Invalidate (const bool bSynchronous)
1262 {
1263     OSL_ASSERT(mpToolBar.is());
1264     mpToolBar->InvalidateArea(GetBoundingBox(), bSynchronous);
1265 }
1266 
IsOutside(const awt::Rectangle & rBox)1267 bool Element::IsOutside (const awt::Rectangle& rBox)
1268 {
1269     if (rBox.X >= maLocation.X+maSize.Width)
1270         return true;
1271     else if (rBox.Y >= maLocation.Y+maSize.Height)
1272         return true;
1273     else if (maLocation.X >= rBox.X+rBox.Width)
1274         return true;
1275     else if (maLocation.Y >= rBox.Y+rBox.Height)
1276         return true;
1277     else
1278         return false;
1279 }
1280 
1281 
IsFilling() const1282 bool Element::IsFilling() const
1283 {
1284     return false;
1285 }
1286 
UpdateState()1287 void Element::UpdateState()
1288 {
1289     OSL_ASSERT(mpToolBar);
1290     OSL_ASSERT(mpToolBar->GetPresenterController());
1291 
1292     if (!mpMode)
1293         return;
1294 
1295     util::URL aURL (mpToolBar->GetPresenterController()->CreateURLFromString(mpMode->msAction));
1296     Reference<frame::XDispatch> xDispatch (mpToolBar->GetPresenterController()->GetDispatch(aURL));
1297     if (xDispatch.is())
1298     {
1299         xDispatch->addStatusListener(this, aURL);
1300         xDispatch->removeStatusListener(this, aURL);
1301     }
1302 }
1303 
1304 //----- lang::XEventListener --------------------------------------------------
1305 
disposing(const css::lang::EventObject &)1306 void SAL_CALL Element::disposing (const css::lang::EventObject&) {}
1307 
1308 //----- document::XEventListener ----------------------------------------------
1309 
notifyEvent(const css::document::EventObject &)1310 void SAL_CALL Element::notifyEvent (const css::document::EventObject&)
1311 {
1312     UpdateState();
1313 }
1314 
1315 //----- frame::XStatusListener ------------------------------------------------
1316 
statusChanged(const css::frame::FeatureStateEvent & rEvent)1317 void SAL_CALL Element::statusChanged (const css::frame::FeatureStateEvent& rEvent)
1318 {
1319     bool bIsSelected (mbIsSelected);
1320     bool bIsEnabled (rEvent.IsEnabled);
1321     rEvent.State >>= bIsSelected;
1322 
1323     if (bIsSelected != mbIsSelected || bIsEnabled != mbIsEnabled)
1324     {
1325         mbIsEnabled = bIsEnabled;
1326         mbIsSelected = bIsSelected;
1327         SetState(mbIsOver, mbIsPressed);
1328         mpToolBar->RequestLayout();
1329     }
1330 }
1331 
1332 } // end of anonymous namespace
1333 
1334 //===== ElementMode ===========================================================
1335 
1336 namespace {
1337 
ElementMode()1338 ElementMode::ElementMode()
1339     : mpIcon(),
1340       msAction(),
1341       maText()
1342 {
1343 }
1344 
ReadElementMode(const Reference<beans::XPropertySet> & rxElementProperties,const OUString & rsModeName,std::shared_ptr<ElementMode> const & rpDefaultMode,::sdext::presenter::PresenterToolBar::Context const & rContext)1345 void ElementMode::ReadElementMode (
1346     const Reference<beans::XPropertySet>& rxElementProperties,
1347     const OUString& rsModeName,
1348     std::shared_ptr<ElementMode> const & rpDefaultMode,
1349     ::sdext::presenter::PresenterToolBar::Context const & rContext)
1350 {
1351     try
1352     {
1353     Reference<container::XHierarchicalNameAccess> xNode (
1354         PresenterConfigurationAccess::GetProperty(rxElementProperties, rsModeName),
1355         UNO_QUERY);
1356     Reference<beans::XPropertySet> xProperties (
1357         PresenterConfigurationAccess::GetNodeProperties(xNode, OUString()));
1358     if (!xProperties.is() && rpDefaultMode != nullptr)
1359     {
1360         // The mode is not specified.  Use the given, possibly empty,
1361         // default mode instead.
1362         mpIcon = rpDefaultMode->mpIcon;
1363         msAction = rpDefaultMode->msAction;
1364         maText = rpDefaultMode->maText;
1365     }
1366 
1367     // Read action.
1368     if ( ! (PresenterConfigurationAccess::GetProperty(xProperties, "Action") >>= msAction))
1369         if (rpDefaultMode != nullptr)
1370             msAction = rpDefaultMode->msAction;
1371 
1372     // Read text and font
1373     OUString sText(rpDefaultMode != nullptr ? rpDefaultMode->maText.GetText() : OUString());
1374     PresenterConfigurationAccess::GetProperty(xProperties, "Text") >>= sText;
1375     Reference<container::XHierarchicalNameAccess> xFontNode (
1376         PresenterConfigurationAccess::GetProperty(xProperties, "Font"), UNO_QUERY);
1377     PresenterTheme::SharedFontDescriptor pFont(PresenterTheme::ReadFont(
1378         xFontNode, rpDefaultMode != nullptr ? rpDefaultMode->maText.GetFont()
1379                                             : PresenterTheme::SharedFontDescriptor()));
1380     maText = Text(sText,pFont);
1381 
1382     // Read bitmaps to display as icons.
1383     Reference<container::XHierarchicalNameAccess> xIconNode (
1384         PresenterConfigurationAccess::GetProperty(xProperties, "Icon"), UNO_QUERY);
1385     mpIcon = PresenterBitmapContainer::LoadBitmap(
1386         xIconNode, "", rContext.mxPresenterHelper, rContext.mxCanvas,
1387         rpDefaultMode != nullptr ? rpDefaultMode->mpIcon : SharedBitmapDescriptor());
1388     }
1389     catch(Exception&)
1390     {
1391         OSL_ASSERT(false);
1392     }
1393 }
1394 
1395 } // end of anonymous namespace
1396 
1397 //===== Button ================================================================
1398 
1399 namespace {
1400 
Create(const::rtl::Reference<PresenterToolBar> & rpToolBar)1401 ::rtl::Reference<Element> Button::Create (
1402     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1403 {
1404     ::rtl::Reference<Button> pElement (new Button(rpToolBar));
1405     pElement->Initialize();
1406     return pElement;
1407 }
1408 
Button(const::rtl::Reference<PresenterToolBar> & rpToolBar)1409 Button::Button (
1410     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1411     : Element(rpToolBar),
1412       mbIsListenerRegistered(false)
1413 {
1414     OSL_ASSERT(mpToolBar);
1415     OSL_ASSERT(mpToolBar->GetPresenterController().is());
1416     OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1417 }
1418 
Initialize()1419 void Button::Initialize()
1420 {
1421     mpToolBar->GetPresenterController()->GetWindowManager()->AddLayoutListener(this);
1422     mbIsListenerRegistered = true;
1423 }
1424 
disposing()1425 void Button::disposing()
1426 {
1427     OSL_ASSERT(mpToolBar);
1428     if (mpToolBar && mbIsListenerRegistered)
1429     {
1430         OSL_ASSERT(mpToolBar->GetPresenterController().is());
1431         OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1432 
1433         mbIsListenerRegistered = false;
1434         mpToolBar->GetPresenterController()->GetWindowManager()->RemoveLayoutListener(this);
1435     }
1436     Element::disposing();
1437 }
1438 
Paint(const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState)1439 void Button::Paint (
1440     const Reference<rendering::XCanvas>& rxCanvas,
1441     const rendering::ViewState& rViewState)
1442 {
1443     OSL_ASSERT(rxCanvas.is());
1444 
1445     if (!mpMode)
1446         return;
1447 
1448     if (!mpMode->mpIcon)
1449         return;
1450 
1451     geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1452     sal_Int32 nTextHeight (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1453 
1454     PaintIcon(rxCanvas, nTextHeight, rViewState);
1455     mpMode->maText.Paint(rxCanvas, rViewState, GetBoundingBox());
1456 }
1457 
CreateBoundingSize(const Reference<rendering::XCanvas> & rxCanvas)1458 awt::Size Button::CreateBoundingSize (
1459     const Reference<rendering::XCanvas>& rxCanvas)
1460 {
1461     if (!mpMode)
1462         return awt::Size();
1463 
1464     geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1465 
1466     // tdf#128964 This ensures that if the text of a button changes due to a change in
1467     // the state of the button the other buttons of the toolbar do not move. The button is
1468     // allotted the maximum size so that it doesn't resize during a change of state.
1469     geometry::RealRectangle2D aTextBBoxNormal (mpNormal->maText.GetBoundingBox(rxCanvas));
1470     geometry::RealRectangle2D aTextBBoxMouseOver (mpMouseOver->maText.GetBoundingBox(rxCanvas));
1471     geometry::RealRectangle2D aTextBBoxSelected (mpSelected->maText.GetBoundingBox(rxCanvas));
1472     geometry::RealRectangle2D aTextBBoxDisabled (mpDisabled->maText.GetBoundingBox(rxCanvas));
1473     geometry::RealRectangle2D aTextBBoxMouseOverSelected (mpMouseOverSelected->maText.GetBoundingBox(rxCanvas));
1474     std::vector<sal_Int32> widths;
1475     widths.push_back(sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxNormal.X2 - aTextBBoxNormal.X1));
1476     widths.push_back(sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxMouseOver.X2 - aTextBBoxMouseOver.X1));
1477     widths.push_back(sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxSelected.X2 - aTextBBoxSelected.X1));
1478     widths.push_back(sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxDisabled.X2 - aTextBBoxDisabled.X1));
1479     widths.push_back(sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxMouseOverSelected.X2 - aTextBBoxMouseOverSelected.X1));
1480 
1481     sal_Int32 nTextHeight (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1482     Reference<rendering::XBitmap> xBitmap;
1483     if (mpMode->mpIcon)
1484         xBitmap = mpMode->mpIcon->GetNormalBitmap();
1485     if (xBitmap.is())
1486     {
1487         const sal_Int32 nGap (5);
1488         geometry::IntegerSize2D aSize (xBitmap->getSize());
1489         return awt::Size(
1490             ::std::max(aSize.Width, *std::max_element(widths.begin(), widths.end())),
1491             aSize.Height + nGap + nTextHeight);
1492     }
1493     else
1494     {
1495         return awt::Size(*std::max_element(widths.begin(), widths.end()), nTextHeight);
1496     }
1497 }
1498 
PaintIcon(const Reference<rendering::XCanvas> & rxCanvas,const sal_Int32 nTextHeight,const rendering::ViewState & rViewState)1499 void Button::PaintIcon (
1500     const Reference<rendering::XCanvas>& rxCanvas,
1501     const sal_Int32 nTextHeight,
1502     const rendering::ViewState& rViewState)
1503 {
1504     if (!mpMode)
1505         return;
1506 
1507     Reference<rendering::XBitmap> xBitmap (mpMode->mpIcon->GetBitmap(GetMode()));
1508     if (!xBitmap.is())
1509         return;
1510 
1511     /// check whether RTL interface or not
1512     if(!AllSettings::GetLayoutRTL()){
1513         const sal_Int32 nX (maLocation.X
1514             + (maSize.Width-xBitmap->getSize().Width) / 2);
1515         const sal_Int32 nY (maLocation.Y
1516             + (maSize.Height - nTextHeight - xBitmap->getSize().Height) / 2);
1517         const rendering::RenderState aRenderState(
1518             geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
1519             nullptr,
1520             Sequence<double>(4),
1521             rendering::CompositeOperation::OVER);
1522         rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState);
1523     }
1524     else {
1525         const sal_Int32 nX (maLocation.X
1526             + (maSize.Width+xBitmap->getSize().Width) / 2);
1527         const sal_Int32 nY (maLocation.Y
1528             + (maSize.Height - nTextHeight - xBitmap->getSize().Height) / 2);
1529         const rendering::RenderState aRenderState(
1530             geometry::AffineMatrix2D(-1,0,nX, 0,1,nY),
1531             nullptr,
1532             Sequence<double>(4),
1533             rendering::CompositeOperation::OVER);
1534         rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState);
1535     }
1536 }
1537 
GetMode() const1538 PresenterBitmapDescriptor::Mode Button::GetMode() const
1539 {
1540     if ( ! IsEnabled())
1541         return PresenterBitmapDescriptor::Disabled;
1542     else if (mbIsPressed)
1543         return PresenterBitmapDescriptor::ButtonDown;
1544     else if (mbIsOver)
1545         return PresenterBitmapDescriptor::MouseOver;
1546     else
1547         return PresenterBitmapDescriptor::Normal;
1548 }
1549 
1550 //----- lang::XEventListener --------------------------------------------------
1551 
disposing(const css::lang::EventObject & rEvent)1552 void SAL_CALL Button::disposing (const css::lang::EventObject& rEvent)
1553 {
1554     mbIsListenerRegistered = false;
1555     Element::disposing(rEvent);
1556 }
1557 
1558 } // end of anonymous namespace
1559 
1560 //===== PresenterToolBar::Label ===============================================
1561 
1562 namespace {
1563 
Label(const::rtl::Reference<PresenterToolBar> & rpToolBar)1564 Label::Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1565     : Element(rpToolBar)
1566 {
1567 }
1568 
CreateBoundingSize(const Reference<rendering::XCanvas> & rxCanvas)1569 awt::Size Label::CreateBoundingSize (
1570     const Reference<rendering::XCanvas>& rxCanvas)
1571 {
1572     if (!mpMode)
1573         return awt::Size(0,0);
1574 
1575     geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1576     return awt::Size(
1577         sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.X2 - aTextBBox.X1),
1578         sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1579 }
1580 
SetText(const OUString & rsText)1581 void Label::SetText (const OUString& rsText)
1582 {
1583     OSL_ASSERT(mpToolBar);
1584     if (!mpMode)
1585         return;
1586 
1587     const bool bRequestLayout (mpMode->maText.GetText().getLength() != rsText.getLength());
1588 
1589     mpMode->maText.SetText(rsText);
1590     // Just use the character count for determining whether a layout is
1591     // necessary.  This is an optimization to avoid layouts every time a new
1592     // time value is set on some labels.
1593     if (bRequestLayout)
1594         mpToolBar->RequestLayout();
1595     else
1596         Invalidate(false);
1597 }
1598 
Paint(const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState)1599 void Label::Paint (
1600     const Reference<rendering::XCanvas>& rxCanvas,
1601     const rendering::ViewState& rViewState)
1602 {
1603     OSL_ASSERT(rxCanvas.is());
1604     if (!mpMode)
1605         return;
1606 
1607     mpMode->maText.Paint(rxCanvas, rViewState, GetBoundingBox());
1608 }
1609 
SetState(const bool,const bool)1610 bool Label::SetState (const bool, const bool)
1611 {
1612     // For labels there is no mouse over effect.
1613     return Element::SetState(false, false);
1614 }
1615 
1616 } // end of anonymous namespace
1617 
1618 //===== Text ==================================================================
1619 
1620 namespace {
1621 
Text()1622 Text::Text()
1623     : msText(),
1624       mpFont()
1625 {
1626 }
1627 
Text(const OUString & rsText,const PresenterTheme::SharedFontDescriptor & rpFont)1628 Text::Text (
1629     const OUString& rsText,
1630     const PresenterTheme::SharedFontDescriptor& rpFont)
1631     : msText(rsText),
1632       mpFont(rpFont)
1633 {
1634 }
1635 
SetText(const OUString & rsText)1636 void Text::SetText (const OUString& rsText)
1637 {
1638     msText = rsText;
1639 }
1640 
GetText() const1641 const OUString& Text::GetText() const
1642 {
1643     return msText;
1644 }
1645 
GetFont() const1646 const PresenterTheme::SharedFontDescriptor& Text::GetFont() const
1647 {
1648     return mpFont;
1649 }
1650 
Paint(const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState,const awt::Rectangle & rBoundingBox)1651 void Text::Paint (
1652     const Reference<rendering::XCanvas>& rxCanvas,
1653     const rendering::ViewState& rViewState,
1654     const awt::Rectangle& rBoundingBox)
1655 {
1656     OSL_ASSERT(rxCanvas.is());
1657 
1658     if (msText.isEmpty())
1659         return;
1660     if (!mpFont)
1661         return;
1662 
1663     if ( ! mpFont->mxFont.is())
1664         mpFont->PrepareFont(rxCanvas);
1665     if ( ! mpFont->mxFont.is())
1666         return;
1667 
1668     rendering::StringContext aContext (msText, 0, msText.getLength());
1669 
1670     Reference<rendering::XTextLayout> xLayout (
1671         mpFont->mxFont->createTextLayout(
1672             aContext,
1673             rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1674             0));
1675     geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1676     const double nTextWidth = aBox.X2 - aBox.X1;
1677     const double nY = rBoundingBox.Y + rBoundingBox.Height - aBox.Y2;
1678     const double nX = rBoundingBox.X + (rBoundingBox.Width - nTextWidth)/2;
1679 
1680     rendering::RenderState aRenderState(
1681         geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
1682         nullptr,
1683         Sequence<double>(4),
1684         rendering::CompositeOperation::SOURCE);
1685     PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1686     rxCanvas->drawTextLayout(
1687         xLayout,
1688         rViewState,
1689         aRenderState);
1690 }
1691 
GetBoundingBox(const Reference<rendering::XCanvas> & rxCanvas)1692 geometry::RealRectangle2D Text::GetBoundingBox (const Reference<rendering::XCanvas>& rxCanvas)
1693 {
1694     if (mpFont && !msText.isEmpty())
1695     {
1696         if ( ! mpFont->mxFont.is())
1697             mpFont->PrepareFont(rxCanvas);
1698         if (mpFont->mxFont.is())
1699         {
1700             rendering::StringContext aContext (msText, 0, msText.getLength());
1701             Reference<rendering::XTextLayout> xLayout (
1702                 mpFont->mxFont->createTextLayout(
1703                     aContext,
1704                     rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1705                     0));
1706             return xLayout->queryTextBounds();
1707         }
1708     }
1709     return geometry::RealRectangle2D(0,0,0,0);
1710 }
1711 
1712 //===== TimeFormatter =========================================================
1713 
FormatTime(const oslDateTime & rTime)1714 OUString TimeFormatter::FormatTime (const oslDateTime& rTime)
1715 {
1716     OUStringBuffer sText;
1717 
1718     const sal_Int32 nHours (sal::static_int_cast<sal_Int32>(rTime.Hours));
1719     const sal_Int32 nMinutes (sal::static_int_cast<sal_Int32>(rTime.Minutes));
1720     const sal_Int32 nSeconds(sal::static_int_cast<sal_Int32>(rTime.Seconds));
1721     // Hours
1722     sText.append(nHours);
1723 
1724     sText.append(":");
1725 
1726     // Minutes
1727     const OUString sMinutes (OUString::number(nMinutes));
1728     if (sMinutes.getLength() == 1)
1729         sText.append("0");
1730     sText.append(sMinutes);
1731 
1732     // Seconds
1733     sText.append(":");
1734     const OUString sSeconds (OUString::number(nSeconds));
1735     if (sSeconds.getLength() == 1)
1736         sText.append("0");
1737     sText.append(sSeconds);
1738     return sText.makeStringAndClear();
1739 }
1740 
1741 //===== TimeLabel =============================================================
1742 
TimeLabel(const::rtl::Reference<PresenterToolBar> & rpToolBar)1743 TimeLabel::TimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1744     : Label(rpToolBar),
1745       mpListener()
1746 {
1747 }
1748 
disposing()1749 void SAL_CALL TimeLabel::disposing()
1750 {
1751     PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->RemoveListener(mpListener);
1752     mpListener.reset();
1753 }
1754 
ConnectToTimer()1755 void TimeLabel::ConnectToTimer()
1756 {
1757     mpListener = std::make_shared<Listener>(this);
1758     PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->AddListener(mpListener);
1759 }
1760 
1761 //===== CurrentTimeLabel ======================================================
1762 
Create(const::rtl::Reference<PresenterToolBar> & rpToolBar)1763 ::rtl::Reference<Element> CurrentTimeLabel::Create (
1764     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1765 {
1766     ::rtl::Reference<TimeLabel> pElement(new CurrentTimeLabel(rpToolBar));
1767     pElement->ConnectToTimer();
1768     return pElement;
1769 }
1770 
~CurrentTimeLabel()1771 CurrentTimeLabel::~CurrentTimeLabel()
1772 {
1773 }
1774 
CurrentTimeLabel(const::rtl::Reference<PresenterToolBar> & rpToolBar)1775 CurrentTimeLabel::CurrentTimeLabel (
1776     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1777     : TimeLabel(rpToolBar)
1778 {
1779 }
1780 
TimeHasChanged(const oslDateTime & rCurrentTime)1781 void CurrentTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1782 {
1783     SetText(TimeFormatter::FormatTime(rCurrentTime));
1784     Invalidate(false);
1785 }
1786 
SetModes(const SharedElementMode & rpNormalMode,const SharedElementMode & rpMouseOverMode,const SharedElementMode & rpSelectedMode,const SharedElementMode & rpDisabledMode,const SharedElementMode & rpMouseOverSelectedMode)1787 void CurrentTimeLabel::SetModes (
1788     const SharedElementMode& rpNormalMode,
1789     const SharedElementMode& rpMouseOverMode,
1790     const SharedElementMode& rpSelectedMode,
1791     const SharedElementMode& rpDisabledMode,
1792     const SharedElementMode& rpMouseOverSelectedMode)
1793 {
1794     TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode, rpMouseOverSelectedMode);
1795     SetText(TimeFormatter::FormatTime(PresenterClockTimer::GetCurrentTime()));
1796 }
1797 
1798 //===== PresentationTimeLabel =================================================
1799 
Create(const::rtl::Reference<PresenterToolBar> & rpToolBar)1800 ::rtl::Reference<Element> PresentationTimeLabel::Create (
1801     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1802 {
1803     ::rtl::Reference<TimeLabel> pElement(new PresentationTimeLabel(rpToolBar));
1804     pElement->ConnectToTimer();
1805     return pElement;
1806 }
1807 
~PresentationTimeLabel()1808 PresentationTimeLabel::~PresentationTimeLabel()
1809 {
1810     mpToolBar->GetPresenterController()->SetPresentationTime(nullptr);
1811 }
1812 
PresentationTimeLabel(const::rtl::Reference<PresenterToolBar> & rpToolBar)1813 PresentationTimeLabel::PresentationTimeLabel (
1814     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1815     : TimeLabel(rpToolBar),
1816       maStartTimeValue()
1817 {
1818     restart();
1819     setPauseStatus(false);
1820     TimeValue pauseTime(0,0);
1821     setPauseTimeValue(pauseTime);
1822     mpToolBar->GetPresenterController()->SetPresentationTime(this);
1823 }
1824 
restart()1825 void PresentationTimeLabel::restart()
1826 {
1827     TimeValue pauseTime(0, 0);
1828     setPauseTimeValue(pauseTime);
1829     maStartTimeValue.Seconds = 0;
1830     maStartTimeValue.Nanosec = 0;
1831 }
1832 
isPaused()1833 bool PresentationTimeLabel::isPaused()
1834 {
1835 	return paused;
1836 }
1837 
setPauseStatus(const bool pauseStatus)1838 void PresentationTimeLabel::setPauseStatus(const bool pauseStatus)
1839 {
1840 	paused = pauseStatus;
1841 }
1842 
getPauseTimeValue() const1843 TimeValue PresentationTimeLabel::getPauseTimeValue() const
1844 {
1845 	return pauseTimeValue;
1846 }
1847 
setPauseTimeValue(const TimeValue pauseTime)1848 void PresentationTimeLabel::setPauseTimeValue(const TimeValue pauseTime)
1849 {
1850     //store the time at which the presentation was paused
1851 	pauseTimeValue = pauseTime;
1852 }
1853 
TimeHasChanged(const oslDateTime & rCurrentTime)1854 void PresentationTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1855 {
1856     TimeValue aCurrentTimeValue;
1857     if (!osl_getTimeValueFromDateTime(&rCurrentTime, &aCurrentTimeValue))
1858         return;
1859 
1860     if (maStartTimeValue.Seconds==0 && maStartTimeValue.Nanosec==0)
1861     {
1862         // This method is called for the first time.  Initialize the
1863         // start time.  The start time is rounded to nearest second to
1864         // keep the time updates synchronized with the current time label.
1865         maStartTimeValue = aCurrentTimeValue;
1866         if (maStartTimeValue.Nanosec >= 500000000)
1867             maStartTimeValue.Seconds += 1;
1868         maStartTimeValue.Nanosec = 0;
1869     }
1870 
1871     //The start time value is incremented by the amount of time
1872     //the presentation was paused for in order to continue the
1873     //timer from the same position
1874     if(!isPaused())
1875 	{
1876 		TimeValue pauseTime = getPauseTimeValue();
1877 		if(pauseTime.Seconds != 0 || pauseTime.Nanosec != 0)
1878 		{
1879             TimeValue incrementValue(0, 0);
1880             incrementValue.Seconds = aCurrentTimeValue.Seconds - pauseTime.Seconds;
1881             if(pauseTime.Nanosec > aCurrentTimeValue.Nanosec)
1882             {
1883                 incrementValue.Nanosec = 1000000000 + aCurrentTimeValue.Nanosec - pauseTime.Nanosec;
1884             }
1885             else
1886             {
1887                 incrementValue.Nanosec = aCurrentTimeValue.Nanosec - pauseTime.Nanosec;
1888             }
1889 
1890             maStartTimeValue.Seconds += incrementValue.Seconds;
1891             maStartTimeValue.Nanosec += incrementValue.Nanosec;
1892             if(maStartTimeValue.Nanosec >= 1000000000)
1893             {
1894                 maStartTimeValue.Seconds += 1;
1895                 maStartTimeValue.Nanosec -= 1000000000;
1896             }
1897 
1898             TimeValue pauseTime_(0, 0);
1899             setPauseTimeValue(pauseTime_);
1900         }
1901     }
1902     else
1903     {
1904         TimeValue pauseTime = getPauseTimeValue();
1905         if(pauseTime.Seconds == 0 && pauseTime.Nanosec == 0)
1906         {
1907             setPauseTimeValue(aCurrentTimeValue);
1908         }
1909     }
1910 
1911     TimeValue aElapsedTimeValue;
1912     aElapsedTimeValue.Seconds = aCurrentTimeValue.Seconds - maStartTimeValue.Seconds;
1913     aElapsedTimeValue.Nanosec = aCurrentTimeValue.Nanosec - maStartTimeValue.Nanosec;
1914 
1915     oslDateTime aElapsedDateTime;
1916     if (osl_getDateTimeFromTimeValue(&aElapsedTimeValue, &aElapsedDateTime) && !isPaused())
1917     {
1918         SetText(TimeFormatter::FormatTime(aElapsedDateTime));
1919         Invalidate(false);
1920     }
1921 }
1922 
SetModes(const SharedElementMode & rpNormalMode,const SharedElementMode & rpMouseOverMode,const SharedElementMode & rpSelectedMode,const SharedElementMode & rpDisabledMode,const SharedElementMode & rpMouseOverSelectedMode)1923 void PresentationTimeLabel::SetModes (
1924     const SharedElementMode& rpNormalMode,
1925     const SharedElementMode& rpMouseOverMode,
1926     const SharedElementMode& rpSelectedMode,
1927     const SharedElementMode& rpDisabledMode,
1928     const SharedElementMode& rpMouseOverSelectedMode)
1929 {
1930     TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode, rpMouseOverSelectedMode);
1931 
1932     oslDateTime aStartDateTime;
1933     if (osl_getDateTimeFromTimeValue(&maStartTimeValue, &aStartDateTime))
1934     {
1935         SetText(TimeFormatter::FormatTime(aStartDateTime));
1936     }
1937 }
1938 
1939 //===== VerticalSeparator =====================================================
1940 
VerticalSeparator(const::rtl::Reference<PresenterToolBar> & rpToolBar)1941 VerticalSeparator::VerticalSeparator (
1942     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1943     : Element(rpToolBar)
1944 {
1945 }
1946 
Paint(const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState)1947 void VerticalSeparator::Paint (
1948     const Reference<rendering::XCanvas>& rxCanvas,
1949     const rendering::ViewState& rViewState)
1950 {
1951     OSL_ASSERT(rxCanvas.is());
1952 
1953     awt::Rectangle aBBox (GetBoundingBox());
1954 
1955     rendering::RenderState aRenderState(
1956         geometry::AffineMatrix2D(1,0,aBBox.X, 0,1,aBBox.Y),
1957         nullptr,
1958         Sequence<double>(4),
1959         rendering::CompositeOperation::OVER);
1960     if (mpMode)
1961     {
1962         PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1963         if (pFont)
1964             PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1965     }
1966 
1967     Reference<rendering::XBitmap> xBitmap(mpToolBar->GetPresenterController()->GetPresenterHelper()->loadBitmap("bitmaps/Separator.png", rxCanvas));
1968     if (!xBitmap.is())
1969         return;
1970 
1971     rxCanvas->drawBitmap(
1972         xBitmap,
1973         rViewState,
1974         aRenderState);
1975 }
1976 
CreateBoundingSize(const Reference<rendering::XCanvas> &)1977 awt::Size VerticalSeparator::CreateBoundingSize (
1978     const Reference<rendering::XCanvas>&)
1979 {
1980     return awt::Size(1,20);
1981 }
1982 
IsFilling() const1983 bool VerticalSeparator::IsFilling() const
1984 {
1985     return true;
1986 }
1987 
1988 //===== HorizontalSeparator ===================================================
1989 
HorizontalSeparator(const::rtl::Reference<PresenterToolBar> & rpToolBar)1990 HorizontalSeparator::HorizontalSeparator (
1991     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1992     : Element(rpToolBar)
1993 {
1994 }
1995 
Paint(const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState)1996 void HorizontalSeparator::Paint (
1997     const Reference<rendering::XCanvas>& rxCanvas,
1998     const rendering::ViewState& rViewState)
1999 {
2000     OSL_ASSERT(rxCanvas.is());
2001 
2002     awt::Rectangle aBBox (GetBoundingBox());
2003 
2004     rendering::RenderState aRenderState(
2005         geometry::AffineMatrix2D(1,0,0, 0,1,0),
2006         nullptr,
2007         Sequence<double>(4),
2008         rendering::CompositeOperation::OVER);
2009     if (mpMode)
2010     {
2011         PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
2012         if (pFont)
2013             PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
2014     }
2015 
2016     rxCanvas->fillPolyPolygon(
2017         PresenterGeometryHelper::CreatePolygon(aBBox, rxCanvas->getDevice()),
2018         rViewState,
2019         aRenderState);
2020 }
2021 
CreateBoundingSize(const Reference<rendering::XCanvas> &)2022 awt::Size HorizontalSeparator::CreateBoundingSize (
2023     const Reference<rendering::XCanvas>&)
2024 {
2025     return awt::Size(20,1);
2026 }
2027 
IsFilling() const2028 bool HorizontalSeparator::IsFilling() const
2029 {
2030     return true;
2031 }
2032 
2033 } // end of anonymous namespace
2034 
2035 } // end of namespace ::sdext::presenter
2036 
2037 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2038