sc: copy cache values when clone color conditional format
[LibreOffice.git] / sdext / source / presenter / PresenterToolBar.cxx
blob75a4b75005502c6b2f6db802ae66307465c0b5f4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/settings.hxx>
21 #include "PresenterToolBar.hxx"
23 #include "PresenterBitmapContainer.hxx"
24 #include "PresenterCanvasHelper.hxx"
25 #include "PresenterGeometryHelper.hxx"
26 #include "PresenterPaintManager.hxx"
27 #include "PresenterTimer.hxx"
28 #include "PresenterWindowManager.hxx"
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>
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::drawing::framework;
48 namespace sdext::presenter {
50 const sal_Int32 gnGapSize (20);
52 namespace {
54 class Text
56 public:
57 Text();
58 Text (
59 const OUString& rsText,
60 const PresenterTheme::SharedFontDescriptor& rpFont);
62 void SetText (const OUString& rsText);
63 const OUString& GetText() const;
64 const PresenterTheme::SharedFontDescriptor& GetFont() const;
66 void Paint (
67 const Reference<rendering::XCanvas>& rxCanvas,
68 const rendering::ViewState& rViewState,
69 const awt::Rectangle& rBoundingBox);
71 geometry::RealRectangle2D GetBoundingBox (
72 const Reference<rendering::XCanvas>& rxCanvas);
74 private:
75 OUString msText;
76 PresenterTheme::SharedFontDescriptor mpFont;
79 class ElementMode
81 public:
82 ElementMode();
83 ElementMode(const ElementMode&) = delete;
84 ElementMode& operator=(const ElementMode&) = delete;
86 SharedBitmapDescriptor mpIcon;
87 OUString msAction;
88 Text maText;
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);
96 typedef std::shared_ptr<ElementMode> SharedElementMode;
98 } // end of anonymous namespace
100 class PresenterToolBar::Context
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;
110 //===== PresenterToolBar::Element =============================================
112 namespace {
113 typedef cppu::WeakComponentImplHelper<
114 css::document::XEventListener,
115 css::frame::XStatusListener
116 > ElementInterfaceBase;
118 class Element
119 : private ::cppu::BaseMutex,
120 public ElementInterfaceBase
122 public:
123 explicit Element (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
124 Element(const Element&) = delete;
125 Element& operator=(const Element&) = delete;
127 virtual void SAL_CALL disposing() override;
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();
150 // lang::XEventListener
152 virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
154 // document::XEventListener
156 virtual void SAL_CALL notifyEvent (const css::document::EventObject& rEvent) override;
158 // frame::XStatusListener
160 virtual void SAL_CALL statusChanged (const css::frame::FeatureStateEvent& rEvent) override;
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;
176 virtual awt::Size CreateBoundingSize (
177 const Reference<rendering::XCanvas>& rxCanvas) = 0;
179 bool IsEnabled() const { return mbIsEnabled;}
180 private:
181 bool mbIsEnabled;
184 } // end of anonymous namespace
186 class PresenterToolBar::ElementContainerPart
187 : public ::std::vector<rtl::Reference<Element> >
191 //===== Button ================================================================
193 namespace {
195 class Button : public Element
197 public:
198 static ::rtl::Reference<Element> Create (
199 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
201 virtual void SAL_CALL disposing() override;
203 virtual void Paint (
204 const Reference<rendering::XCanvas>& rxCanvas,
205 const rendering::ViewState& rViewState) override;
207 // lang::XEventListener
209 virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
211 protected:
212 virtual awt::Size CreateBoundingSize (
213 const Reference<rendering::XCanvas>& rxCanvas) override;
215 private:
216 bool mbIsListenerRegistered;
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;
227 //===== Label =================================================================
229 class Label : public Element
231 public:
232 explicit Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
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;
240 protected:
241 virtual awt::Size CreateBoundingSize (
242 const Reference<rendering::XCanvas>& rxCanvas) override;
245 // Some specialized controls.
247 class TimeFormatter
249 public:
250 static OUString FormatTime (const oslDateTime& rTime);
253 class TimeLabel : public Label
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
265 public:
266 explicit Listener (const ::rtl::Reference<TimeLabel>& rxLabel)
267 : mxLabel(rxLabel) {}
268 virtual ~Listener() {}
269 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override
270 { if (mxLabel.is()) mxLabel->TimeHasChanged(rCurrentTime); }
271 private:
272 ::rtl::Reference<TimeLabel> mxLabel;
274 std::shared_ptr<PresenterClockTimer::Listener> mpListener;
277 class CurrentTimeLabel : public TimeLabel
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;
294 class PresentationTimeLabel : public TimeLabel, public IPresentationTime
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 const 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;
319 class VerticalSeparator : public Element
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;
328 protected:
329 virtual awt::Size CreateBoundingSize (
330 const Reference<rendering::XCanvas>& rxCanvas) override;
333 class HorizontalSeparator : public Element
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;
342 protected:
343 virtual awt::Size CreateBoundingSize (
344 const Reference<rendering::XCanvas>& rxCanvas) override;
346 } // end of anonymous namespace
348 //===== PresenterToolBar ======================================================
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 mxWindow(rxWindow),
359 mxCanvas(rxCanvas),
360 mpPresenterController(rpPresenterController),
361 mbIsLayoutPending(false),
362 meAnchor(eAnchor)
366 void PresenterToolBar::Initialize (
367 const OUString& rsConfigurationPath)
371 CreateControls(rsConfigurationPath);
373 if (mxWindow.is())
375 mxWindow->addWindowListener(this);
376 mxWindow->addPaintListener(this);
377 mxWindow->addMouseListener(this);
378 mxWindow->addMouseMotionListener(this);
380 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
381 if (xPeer.is())
382 xPeer->setBackground(util::Color(0xff000000));
384 mxWindow->setVisible(true);
387 mxSlideShowController = mpPresenterController->GetSlideShowController();
388 UpdateSlideNumber();
389 mbIsLayoutPending = true;
391 catch (RuntimeException&)
393 mpCurrentContainerPart.reset();
394 maElementContainer.clear();
395 throw;
399 PresenterToolBar::~PresenterToolBar()
403 void SAL_CALL PresenterToolBar::disposing()
405 if (mxWindow.is())
407 mxWindow->removeWindowListener(this);
408 mxWindow->removePaintListener(this);
409 mxWindow->removeMouseListener(this);
410 mxWindow->removeMouseMotionListener(this);
411 mxWindow = nullptr;
414 // Dispose tool bar elements.
415 for (const auto& rxPart : maElementContainer)
417 OSL_ASSERT(rxPart != nullptr);
418 for (const rtl::Reference<Element>& pElement : *rxPart)
420 if (pElement)
422 Reference<lang::XComponent> xComponent = pElement;
423 if (xComponent.is())
424 xComponent->dispose();
429 mpCurrentContainerPart.reset();
430 maElementContainer.clear();
433 void PresenterToolBar::InvalidateArea (
434 const awt::Rectangle& rRepaintBox,
435 const bool bSynchronous)
437 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
438 if (!xManager)
439 return;
440 xManager->Invalidate(
441 mxWindow,
442 rRepaintBox,
443 bSynchronous);
446 void PresenterToolBar::RequestLayout()
448 mbIsLayoutPending = true;
450 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
451 if (!xManager)
452 return;
454 xManager->Invalidate(mxWindow);
457 geometry::RealSize2D const & PresenterToolBar::GetMinimalSize()
459 if (mbIsLayoutPending)
460 Layout(mxCanvas);
461 return maMinimalSize;
464 const ::rtl::Reference<PresenterController>& PresenterToolBar::GetPresenterController() const
466 return mpPresenterController;
469 const Reference<XComponentContext>& PresenterToolBar::GetComponentContext() const
471 return mxComponentContext;
474 //----- lang::XEventListener -------------------------------------------------
476 void SAL_CALL PresenterToolBar::disposing (const lang::EventObject& rEventObject)
478 if (rEventObject.Source == mxWindow)
479 mxWindow = nullptr;
482 //----- XWindowListener -------------------------------------------------------
484 void SAL_CALL PresenterToolBar::windowResized (const awt::WindowEvent&)
486 mbIsLayoutPending = true;
489 void SAL_CALL PresenterToolBar::windowMoved (const awt::WindowEvent&) {}
491 void SAL_CALL PresenterToolBar::windowShown (const lang::EventObject&)
493 mbIsLayoutPending = true;
496 void SAL_CALL PresenterToolBar::windowHidden (const lang::EventObject&) {}
498 //----- XPaintListener --------------------------------------------------------
499 void SAL_CALL PresenterToolBar::windowPaint (const css::awt::PaintEvent& rEvent)
501 if ( ! mxCanvas.is())
502 return;
504 if ( ! mbIsPresenterViewActive)
505 return;
507 const rendering::ViewState aViewState (
508 geometry::AffineMatrix2D(1,0,0, 0,1,0),
509 PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice()));
511 if (mbIsLayoutPending)
512 Layout(mxCanvas);
514 Paint(rEvent.UpdateRect, aViewState);
516 // Make the back buffer visible.
517 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
518 if (xSpriteCanvas.is())
519 xSpriteCanvas->updateScreen(false);
522 //----- XMouseListener --------------------------------------------------------
523 void SAL_CALL PresenterToolBar::mousePressed (const css::awt::MouseEvent& rEvent)
525 ThrowIfDisposed();
526 CheckMouseOver(rEvent, true, true);
529 void SAL_CALL PresenterToolBar::mouseReleased (const css::awt::MouseEvent& rEvent)
531 ThrowIfDisposed();
532 CheckMouseOver(rEvent, true);
535 void SAL_CALL PresenterToolBar::mouseEntered (const css::awt::MouseEvent& rEvent)
537 ThrowIfDisposed();
538 CheckMouseOver(rEvent, true);
541 void SAL_CALL PresenterToolBar::mouseExited (const css::awt::MouseEvent& rEvent)
543 ThrowIfDisposed();
544 CheckMouseOver(rEvent, false);
547 //----- XMouseMotionListener --------------------------------------------------
549 void SAL_CALL PresenterToolBar::mouseMoved (const css::awt::MouseEvent& rEvent)
551 ThrowIfDisposed();
552 CheckMouseOver(rEvent, true);
555 void SAL_CALL PresenterToolBar::mouseDragged (const css::awt::MouseEvent&)
557 ThrowIfDisposed();
560 //----- XDrawView -------------------------------------------------------------
562 void SAL_CALL PresenterToolBar::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
564 if (rxSlide != mxCurrentSlide)
566 mxCurrentSlide = rxSlide;
567 UpdateSlideNumber();
571 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBar::getCurrentPage()
573 return mxCurrentSlide;
577 void PresenterToolBar::CreateControls (
578 const OUString& rsConfigurationPath)
580 if ( ! mxWindow.is())
581 return;
583 // Expand the macro in the bitmap file names.
584 PresenterConfigurationAccess aConfiguration (
585 mxComponentContext,
586 "/org.openoffice.Office.PresenterScreen/",
587 PresenterConfigurationAccess::READ_ONLY);
589 mpCurrentContainerPart = std::make_shared<ElementContainerPart>();
590 maElementContainer.clear();
591 maElementContainer.push_back(mpCurrentContainerPart);
593 Reference<container::XHierarchicalNameAccess> xToolBarNode (
594 aConfiguration.GetConfigurationNode(rsConfigurationPath),
595 UNO_QUERY);
596 if (!xToolBarNode.is())
597 return;
599 Reference<container::XNameAccess> xEntries (
600 PresenterConfigurationAccess::GetConfigurationNode(xToolBarNode, "Entries"),
601 UNO_QUERY);
602 Context aContext;
603 aContext.mxPresenterHelper = mpPresenterController->GetPresenterHelper();
604 aContext.mxCanvas = mxCanvas;
605 if (xEntries.is()
606 && aContext.mxPresenterHelper.is()
607 && aContext.mxCanvas.is())
609 PresenterConfigurationAccess::ForAll(
610 xEntries,
611 [this, &aContext] (OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
613 return this->ProcessEntry(xProps, aContext);
618 void PresenterToolBar::ProcessEntry (
619 const Reference<beans::XPropertySet>& rxProperties,
620 Context const & rContext)
622 if ( ! rxProperties.is())
623 return;
625 // Type has to be present.
626 OUString sType;
627 if ( ! (PresenterConfigurationAccess::GetProperty(rxProperties, "Type") >>= sType))
628 return;
630 // Read mode specific values.
631 SharedElementMode pNormalMode = std::make_shared<ElementMode>();
632 SharedElementMode pMouseOverMode = std::make_shared<ElementMode>();
633 SharedElementMode pSelectedMode = std::make_shared<ElementMode>();
634 SharedElementMode pDisabledMode = std::make_shared<ElementMode>();
635 SharedElementMode pMouseOverSelectedMode = std::make_shared<ElementMode>();
636 pNormalMode->ReadElementMode(rxProperties, "Normal", pNormalMode, rContext);
637 pMouseOverMode->ReadElementMode(rxProperties, "MouseOver", pNormalMode, rContext);
638 pSelectedMode->ReadElementMode(rxProperties, "Selected", pNormalMode, rContext);
639 pDisabledMode->ReadElementMode(rxProperties, "Disabled", pNormalMode, rContext);
640 pMouseOverSelectedMode->ReadElementMode(rxProperties, "MouseOverSelected", pSelectedMode, rContext);
642 // Create new element.
643 ::rtl::Reference<Element> pElement;
644 if ( sType == "Button" )
645 pElement = Button::Create(this);
646 else if ( sType == "CurrentTimeLabel" )
647 pElement = CurrentTimeLabel::Create(this);
648 else if ( sType == "PresentationTimeLabel" )
649 pElement = PresentationTimeLabel::Create(this);
650 else if ( sType == "VerticalSeparator" )
651 pElement.set(new VerticalSeparator(this));
652 else if ( sType == "HorizontalSeparator" )
653 pElement.set(new HorizontalSeparator(this));
654 else if ( sType == "Label" )
655 pElement.set(new Label(this));
656 else if ( sType == "ChangeOrientation" )
658 mpCurrentContainerPart = std::make_shared<ElementContainerPart>();
659 maElementContainer.push_back(mpCurrentContainerPart);
660 return;
662 if (pElement.is())
664 pElement->SetModes( pNormalMode, pMouseOverMode, pSelectedMode, pDisabledMode, pMouseOverSelectedMode);
665 pElement->UpdateState();
666 if (mpCurrentContainerPart)
667 mpCurrentContainerPart->push_back(pElement);
671 void PresenterToolBar::Layout (
672 const Reference<rendering::XCanvas>& rxCanvas)
674 if (maElementContainer.empty())
675 return;
677 mbIsLayoutPending = false;
679 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
680 ::std::vector<geometry::RealSize2D> aPartSizes (maElementContainer.size());
681 geometry::RealSize2D aTotalSize (0,0);
682 bool bIsHorizontal (true);
683 sal_Int32 nIndex (0);
684 double nTotalHorizontalGap (0);
685 sal_Int32 nGapCount (0);
686 for (const auto& rxPart : maElementContainer)
688 geometry::RealSize2D aSize (CalculatePartSize(rxCanvas, rxPart, bIsHorizontal));
690 // Remember the size of each part for later.
691 aPartSizes[nIndex] = aSize;
693 // Add gaps between elements.
694 if (rxPart->size()>1 && bIsHorizontal)
696 nTotalHorizontalGap += (rxPart->size() - 1) * gnGapSize;
697 nGapCount += rxPart->size() - 1;
700 // Orientation changes for each part.
701 bIsHorizontal = !bIsHorizontal;
702 // Width is accumulated.
703 aTotalSize.Width += aSize.Width;
704 // Height is the maximum height of all parts.
705 aTotalSize.Height = ::std::max(aTotalSize.Height, aSize.Height);
706 ++nIndex;
708 // Add gaps between parts.
709 if (maElementContainer.size() > 1)
711 nTotalHorizontalGap += (maElementContainer.size() - 1) * gnGapSize;
712 nGapCount += maElementContainer.size()-1;
715 // Done to introduce gap between the end of the toolbar and the last button
716 aTotalSize.Width += gnGapSize/2;
718 // Calculate the minimal size so that the window size of the tool bar
719 // can be adapted accordingly.
720 maMinimalSize = aTotalSize;
721 maMinimalSize.Width += nTotalHorizontalGap;
723 // Calculate the gaps between elements.
724 double nGapWidth (0);
725 if (nGapCount > 0)
727 if (aTotalSize.Width + nTotalHorizontalGap > aWindowBox.Width)
728 nTotalHorizontalGap = aWindowBox.Width - aTotalSize.Width;
729 nGapWidth = nTotalHorizontalGap / nGapCount;
732 // Determine the location of the left edge.
733 double nX (0);
734 switch (meAnchor)
736 case Left : nX = 0; break;
737 case Center: nX = (aWindowBox.Width - aTotalSize.Width - nTotalHorizontalGap) / 2; break;
740 // Place the parts.
741 double nY ((aWindowBox.Height - aTotalSize.Height) / 2);
742 bIsHorizontal = true;
744 /* push front or back ? ... */
745 /// check whether RTL interface or not
746 if(!AllSettings::GetLayoutRTL()){
747 nIndex = 0;
748 for (const auto& rxPart : maElementContainer)
750 geometry::RealRectangle2D aBoundingBox(
751 nX, nY,
752 nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height);
754 // Add space for gaps between elements.
755 if (rxPart->size() > 1 && bIsHorizontal)
756 aBoundingBox.X2 += (rxPart->size() - 1) * nGapWidth;
758 LayoutPart(rxCanvas, rxPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal);
759 bIsHorizontal = !bIsHorizontal;
760 nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth;
761 ++nIndex;
764 else {
765 ElementContainer::iterator iPart;
766 ElementContainer::iterator iBegin (maElementContainer.begin());
767 for (iPart=maElementContainer.end()-1, nIndex=2; iPart!=iBegin-1; --iPart, --nIndex)
769 geometry::RealRectangle2D aBoundingBox(
770 nX, nY,
771 nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height);
773 // Add space for gaps between elements.
774 if ((*iPart)->size() > 1)
775 if (bIsHorizontal)
776 aBoundingBox.X2 += ((*iPart)->size()-1) * nGapWidth;
778 LayoutPart(rxCanvas, *iPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal);
779 bIsHorizontal = !bIsHorizontal;
780 nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth;
784 // The whole window has to be repainted.
785 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
786 if (!xManager)
787 return;
788 xManager->Invalidate(mxWindow);
791 geometry::RealSize2D PresenterToolBar::CalculatePartSize (
792 const Reference<rendering::XCanvas>& rxCanvas,
793 const SharedElementContainerPart& rpPart,
794 const bool bIsHorizontal)
796 geometry::RealSize2D aTotalSize (0,0);
798 if (mxWindow.is())
800 // Calculate the summed width of all elements.
801 for (const auto& rxElement : *rpPart)
803 if (!rxElement)
804 continue;
806 const awt::Size aBSize (rxElement->GetBoundingSize(rxCanvas));
807 if (bIsHorizontal)
809 aTotalSize.Width += aBSize.Width;
810 if (aBSize.Height > aTotalSize.Height)
811 aTotalSize.Height = aBSize.Height;
813 else
815 aTotalSize.Height += aBSize.Height;
816 if (aBSize.Width > aTotalSize.Width)
817 aTotalSize.Width = aBSize.Width;
821 return aTotalSize;
824 void PresenterToolBar::LayoutPart (
825 const Reference<rendering::XCanvas>& rxCanvas,
826 const SharedElementContainerPart& rpPart,
827 const geometry::RealRectangle2D& rBoundingBox,
828 const geometry::RealSize2D& rPartSize,
829 const bool bIsHorizontal)
831 double nGap (0);
832 if (rpPart->size() > 1)
834 if (bIsHorizontal)
835 nGap = (rBoundingBox.X2 - rBoundingBox.X1 - rPartSize.Width) / (rpPart->size()-1);
836 else
837 nGap = (rBoundingBox.Y2 - rBoundingBox.Y1 - rPartSize.Height) / (rpPart->size()-1);
840 // Place the elements.
841 double nX (rBoundingBox.X1);
842 double nY (rBoundingBox.Y1);
844 /// check whether RTL interface or not
845 if(!AllSettings::GetLayoutRTL()){
846 for (auto& rxElement : *rpPart)
848 if (!rxElement)
849 continue;
851 const awt::Size aElementSize (rxElement->GetBoundingSize(rxCanvas));
852 if (bIsHorizontal)
854 if (rxElement->IsFilling())
856 nY = rBoundingBox.Y1;
857 rxElement->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
859 else
860 nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
861 rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
862 nX += aElementSize.Width + nGap;
864 else
866 if (rxElement->IsFilling())
868 nX = rBoundingBox.X1;
869 rxElement->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aElementSize.Height));
871 else
872 nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aElementSize.Width) / 2;
873 rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
874 nY += aElementSize.Height + nGap;
878 else {
879 ElementContainerPart::const_iterator iElement;
880 ElementContainerPart::const_iterator iBegin (rpPart->begin());
882 for (iElement=rpPart->end()-1; iElement!=iBegin-1; --iElement)
884 if (iElement->get() == nullptr)
885 continue;
887 const awt::Size aElementSize ((*iElement)->GetBoundingSize(rxCanvas));
888 if (bIsHorizontal)
890 if ((*iElement)->IsFilling())
892 nY = rBoundingBox.Y1;
893 (*iElement)->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
895 else
896 nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
897 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
898 nX += aElementSize.Width + nGap;
900 else
902 // reverse presentation time with current time
903 if (iElement==iBegin){
904 iElement=iBegin+2;
906 else if (iElement==iBegin+2){
907 iElement=iBegin;
909 const awt::Size aNewElementSize ((*iElement)->GetBoundingSize(rxCanvas));
910 if ((*iElement)->IsFilling())
912 nX = rBoundingBox.X1;
913 (*iElement)->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aNewElementSize.Height));
915 else
916 nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aNewElementSize.Width) / 2;
917 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
918 nY += aNewElementSize.Height + nGap;
920 // return the index as it was before the reversing
921 if (iElement==iBegin)
922 iElement=iBegin+2;
923 else if (iElement==iBegin+2)
924 iElement=iBegin;
930 void PresenterToolBar::Paint (
931 const awt::Rectangle& rUpdateBox,
932 const rendering::ViewState& rViewState)
934 OSL_ASSERT(mxCanvas.is());
936 for (const auto& rxPart : maElementContainer)
938 for (auto& rxElement : *rxPart)
940 if (rxElement)
942 if ( ! rxElement->IsOutside(rUpdateBox))
943 rxElement->Paint(mxCanvas, rViewState);
949 void PresenterToolBar::UpdateSlideNumber()
951 if( mxSlideShowController.is() )
953 for (const auto& rxPart : maElementContainer)
955 for (auto& rxElement : *rxPart)
957 if (rxElement)
958 rxElement->CurrentSlideHasChanged();
964 void PresenterToolBar::CheckMouseOver (
965 const css::awt::MouseEvent& rEvent,
966 const bool bOverWindow,
967 const bool bMouseDown)
969 css::awt::MouseEvent rTemp =rEvent;
970 if(AllSettings::GetLayoutRTL()){
971 awt::Rectangle aWindowBox = mxWindow->getPosSize();
972 rTemp.X=aWindowBox.Width-rTemp.X;
974 for (const auto& rxPart : maElementContainer)
976 for (auto& rxElement : *rxPart)
978 if (!rxElement)
979 continue;
981 awt::Rectangle aBox (rxElement->GetBoundingBox());
982 const bool bIsOver = bOverWindow
983 && aBox.X <= rTemp.X
984 && aBox.Width+aBox.X-1 >= rTemp.X
985 && aBox.Y <= rTemp.Y
986 && aBox.Height+aBox.Y-1 >= rTemp.Y;
987 rxElement->SetState(
988 bIsOver,
989 bIsOver && rTemp.Buttons!=0 && bMouseDown && rTemp.ClickCount>0);
994 void PresenterToolBar::ThrowIfDisposed() const
996 if (rBHelper.bDisposed || rBHelper.bInDispose)
998 throw lang::DisposedException (
999 "PresenterToolBar has already been disposed",
1000 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
1004 //===== PresenterToolBarView ==================================================
1006 PresenterToolBarView::PresenterToolBarView (
1007 const Reference<XComponentContext>& rxContext,
1008 const Reference<XResourceId>& rxViewId,
1009 const Reference<frame::XController>& rxController,
1010 const ::rtl::Reference<PresenterController>& rpPresenterController)
1011 : PresenterToolBarViewInterfaceBase(m_aMutex),
1012 mxViewId(rxViewId),
1013 mpPresenterController(rpPresenterController)
1017 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
1018 Reference<XConfigurationController> xCC(xCM->getConfigurationController(),UNO_SET_THROW);
1019 mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
1021 mxWindow = mxPane->getWindow();
1022 mxCanvas = mxPane->getCanvas();
1024 mpToolBar = new PresenterToolBar(
1025 rxContext,
1026 mxWindow,
1027 mxCanvas,
1028 rpPresenterController,
1029 PresenterToolBar::Center);
1030 mpToolBar->Initialize("PresenterScreenSettings/ToolBars/ToolBar");
1032 if (mxWindow.is())
1034 mxWindow->addPaintListener(this);
1036 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
1037 if (xPeer.is())
1038 xPeer->setBackground(util::Color(0xff000000));
1040 mxWindow->setVisible(true);
1043 catch (RuntimeException&)
1045 mxViewId = nullptr;
1046 throw;
1050 PresenterToolBarView::~PresenterToolBarView()
1054 void SAL_CALL PresenterToolBarView::disposing()
1056 Reference<lang::XComponent> xComponent = mpToolBar;
1057 mpToolBar = nullptr;
1058 if (xComponent.is())
1059 xComponent->dispose();
1061 if (mxWindow.is())
1063 mxWindow->removePaintListener(this);
1064 mxWindow = nullptr;
1066 mxCanvas = nullptr;
1067 mxViewId = nullptr;
1068 mxPane = nullptr;
1069 mpPresenterController = nullptr;
1072 const ::rtl::Reference<PresenterToolBar>& PresenterToolBarView::GetPresenterToolBar() const
1074 return mpToolBar;
1077 //----- XPaintListener --------------------------------------------------------
1079 void SAL_CALL PresenterToolBarView::windowPaint (const css::awt::PaintEvent& rEvent)
1081 awt::Rectangle aWindowBox (mxWindow->getPosSize());
1082 mpPresenterController->GetCanvasHelper()->Paint(
1083 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
1084 mxCanvas,
1085 rEvent.UpdateRect,
1086 awt::Rectangle(0,0,aWindowBox.Width, aWindowBox.Height),
1087 awt::Rectangle());
1090 //----- lang::XEventListener -------------------------------------------------
1092 void SAL_CALL PresenterToolBarView::disposing (const lang::EventObject& rEventObject)
1094 if (rEventObject.Source == mxWindow)
1095 mxWindow = nullptr;
1098 //----- XResourceId -----------------------------------------------------------
1100 Reference<XResourceId> SAL_CALL PresenterToolBarView::getResourceId()
1102 return mxViewId;
1105 sal_Bool SAL_CALL PresenterToolBarView::isAnchorOnly()
1107 return false;
1110 //----- XDrawView -------------------------------------------------------------
1112 void SAL_CALL PresenterToolBarView::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
1114 Reference<drawing::XDrawView> xToolBar = mpToolBar;
1115 if (xToolBar.is())
1116 xToolBar->setCurrentPage(rxSlide);
1119 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBarView::getCurrentPage()
1121 return nullptr;
1124 //===== PresenterToolBar::Element =============================================
1126 namespace {
1128 Element::Element (
1129 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1130 : ElementInterfaceBase(m_aMutex),
1131 mpToolBar(rpToolBar),
1132 mbIsOver(false),
1133 mbIsPressed(false),
1134 mbIsSelected(false),
1135 mbIsEnabled(true)
1137 if (mpToolBar)
1139 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1140 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1144 void Element::SetModes (
1145 const SharedElementMode& rpNormalMode,
1146 const SharedElementMode& rpMouseOverMode,
1147 const SharedElementMode& rpSelectedMode,
1148 const SharedElementMode& rpDisabledMode,
1149 const SharedElementMode& rpMouseOverSelectedMode)
1151 mpNormal = rpNormalMode;
1152 mpMouseOver = rpMouseOverMode;
1153 mpSelected = rpSelectedMode;
1154 mpDisabled = rpDisabledMode;
1155 mpMouseOverSelected = rpMouseOverSelectedMode;
1156 mpMode = rpNormalMode;
1159 void Element::disposing()
1163 awt::Size const & Element::GetBoundingSize (
1164 const Reference<rendering::XCanvas>& rxCanvas)
1166 maSize = CreateBoundingSize(rxCanvas);
1167 return maSize;
1170 awt::Rectangle Element::GetBoundingBox() const
1172 return awt::Rectangle(maLocation.X,maLocation.Y, maSize.Width, maSize.Height);
1175 void Element::CurrentSlideHasChanged()
1177 UpdateState();
1180 void Element::SetLocation (const awt::Point& rLocation)
1182 maLocation = rLocation;
1185 void Element::SetSize (const geometry::RealSize2D& rSize)
1187 maSize = awt::Size(sal_Int32(0.5+rSize.Width), sal_Int32(0.5+rSize.Height));
1190 bool Element::SetState (
1191 const bool bIsOver,
1192 const bool bIsPressed)
1194 bool bModified (mbIsOver != bIsOver || mbIsPressed != bIsPressed);
1195 bool bClicked (mbIsPressed && bIsOver && ! bIsPressed);
1197 mbIsOver = bIsOver;
1198 mbIsPressed = bIsPressed;
1200 // When the element is disabled then ignore mouse over or selection.
1201 // When the element is selected then ignore mouse over.
1202 if ( ! mbIsEnabled)
1203 mpMode = mpDisabled;
1204 else if (mbIsSelected && mbIsOver)
1205 mpMode = mpMouseOverSelected;
1206 else if (mbIsSelected)
1207 mpMode = mpSelected;
1208 else if (mbIsOver)
1209 mpMode = mpMouseOver;
1210 else
1211 mpMode = mpNormal;
1213 if (bClicked && mbIsEnabled)
1215 if (mpMode)
1219 if (mpMode->msAction.isEmpty())
1220 break;
1222 if (!mpToolBar)
1223 break;
1225 if (!mpToolBar->GetPresenterController())
1226 break;
1228 mpToolBar->GetPresenterController()->DispatchUnoCommand(mpMode->msAction);
1229 mpToolBar->RequestLayout();
1231 while (false);
1235 else if (bModified)
1237 Invalidate(true);
1240 return bModified;
1243 void Element::Invalidate (const bool bSynchronous)
1245 OSL_ASSERT(mpToolBar.is());
1246 mpToolBar->InvalidateArea(GetBoundingBox(), bSynchronous);
1249 bool Element::IsOutside (const awt::Rectangle& rBox)
1251 if (rBox.X >= maLocation.X+maSize.Width)
1252 return true;
1253 else if (rBox.Y >= maLocation.Y+maSize.Height)
1254 return true;
1255 else if (maLocation.X >= rBox.X+rBox.Width)
1256 return true;
1257 else if (maLocation.Y >= rBox.Y+rBox.Height)
1258 return true;
1259 else
1260 return false;
1264 bool Element::IsFilling() const
1266 return false;
1269 void Element::UpdateState()
1271 OSL_ASSERT(mpToolBar);
1272 OSL_ASSERT(mpToolBar->GetPresenterController());
1274 if (!mpMode)
1275 return;
1277 util::URL aURL (mpToolBar->GetPresenterController()->CreateURLFromString(mpMode->msAction));
1278 Reference<frame::XDispatch> xDispatch (mpToolBar->GetPresenterController()->GetDispatch(aURL));
1279 if (xDispatch.is())
1281 xDispatch->addStatusListener(this, aURL);
1282 xDispatch->removeStatusListener(this, aURL);
1286 //----- lang::XEventListener --------------------------------------------------
1288 void SAL_CALL Element::disposing (const css::lang::EventObject&) {}
1290 //----- document::XEventListener ----------------------------------------------
1292 void SAL_CALL Element::notifyEvent (const css::document::EventObject&)
1294 UpdateState();
1297 //----- frame::XStatusListener ------------------------------------------------
1299 void SAL_CALL Element::statusChanged (const css::frame::FeatureStateEvent& rEvent)
1301 bool bIsSelected (mbIsSelected);
1302 bool bIsEnabled (rEvent.IsEnabled);
1303 rEvent.State >>= bIsSelected;
1305 if (bIsSelected != mbIsSelected || bIsEnabled != mbIsEnabled)
1307 mbIsEnabled = bIsEnabled;
1308 mbIsSelected = bIsSelected;
1309 SetState(mbIsOver, mbIsPressed);
1310 mpToolBar->RequestLayout();
1314 } // end of anonymous namespace
1316 //===== ElementMode ===========================================================
1318 namespace {
1320 ElementMode::ElementMode()
1324 void ElementMode::ReadElementMode (
1325 const Reference<beans::XPropertySet>& rxElementProperties,
1326 const OUString& rsModeName,
1327 std::shared_ptr<ElementMode> const & rpDefaultMode,
1328 ::sdext::presenter::PresenterToolBar::Context const & rContext)
1332 Reference<container::XHierarchicalNameAccess> xNode (
1333 PresenterConfigurationAccess::GetProperty(rxElementProperties, rsModeName),
1334 UNO_QUERY);
1335 Reference<beans::XPropertySet> xProperties (
1336 PresenterConfigurationAccess::GetNodeProperties(xNode, OUString()));
1337 if (!xProperties.is() && rpDefaultMode != nullptr)
1339 // The mode is not specified. Use the given, possibly empty,
1340 // default mode instead.
1341 mpIcon = rpDefaultMode->mpIcon;
1342 msAction = rpDefaultMode->msAction;
1343 maText = rpDefaultMode->maText;
1346 // Read action.
1347 if ( ! (PresenterConfigurationAccess::GetProperty(xProperties, "Action") >>= msAction))
1348 if (rpDefaultMode != nullptr)
1349 msAction = rpDefaultMode->msAction;
1351 // Read text and font
1352 OUString sText(rpDefaultMode != nullptr ? rpDefaultMode->maText.GetText() : OUString());
1353 PresenterConfigurationAccess::GetProperty(xProperties, "Text") >>= sText;
1354 Reference<container::XHierarchicalNameAccess> xFontNode (
1355 PresenterConfigurationAccess::GetProperty(xProperties, "Font"), UNO_QUERY);
1356 PresenterTheme::SharedFontDescriptor pFont(PresenterTheme::ReadFont(
1357 xFontNode, rpDefaultMode != nullptr ? rpDefaultMode->maText.GetFont()
1358 : PresenterTheme::SharedFontDescriptor()));
1359 maText = Text(sText,pFont);
1361 // Read bitmaps to display as icons.
1362 Reference<container::XHierarchicalNameAccess> xIconNode (
1363 PresenterConfigurationAccess::GetProperty(xProperties, "Icon"), UNO_QUERY);
1364 mpIcon = PresenterBitmapContainer::LoadBitmap(
1365 xIconNode, "", rContext.mxPresenterHelper, rContext.mxCanvas,
1366 rpDefaultMode != nullptr ? rpDefaultMode->mpIcon : SharedBitmapDescriptor());
1368 catch(Exception&)
1370 OSL_ASSERT(false);
1374 } // end of anonymous namespace
1376 //===== Button ================================================================
1378 namespace {
1380 ::rtl::Reference<Element> Button::Create (
1381 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1383 ::rtl::Reference<Button> pElement (new Button(rpToolBar));
1384 pElement->Initialize();
1385 return pElement;
1388 Button::Button (
1389 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1390 : Element(rpToolBar),
1391 mbIsListenerRegistered(false)
1393 OSL_ASSERT(mpToolBar);
1394 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1395 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1398 void Button::Initialize()
1400 mpToolBar->GetPresenterController()->GetWindowManager()->AddLayoutListener(this);
1401 mbIsListenerRegistered = true;
1404 void Button::disposing()
1406 OSL_ASSERT(mpToolBar);
1407 if (mpToolBar && mbIsListenerRegistered)
1409 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1410 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1412 mbIsListenerRegistered = false;
1413 mpToolBar->GetPresenterController()->GetWindowManager()->RemoveLayoutListener(this);
1415 Element::disposing();
1418 void Button::Paint (
1419 const Reference<rendering::XCanvas>& rxCanvas,
1420 const rendering::ViewState& rViewState)
1422 OSL_ASSERT(rxCanvas.is());
1424 if (!mpMode)
1425 return;
1427 if (!mpMode->mpIcon)
1428 return;
1430 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1431 sal_Int32 nTextHeight (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1433 PaintIcon(rxCanvas, nTextHeight, rViewState);
1434 mpMode->maText.Paint(rxCanvas, rViewState, GetBoundingBox());
1437 awt::Size Button::CreateBoundingSize (
1438 const Reference<rendering::XCanvas>& rxCanvas)
1440 if (!mpMode)
1441 return awt::Size();
1443 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1445 // tdf#128964 This ensures that if the text of a button changes due to a change in
1446 // the state of the button the other buttons of the toolbar do not move. The button is
1447 // allotted the maximum size so that it doesn't resize during a change of state.
1448 geometry::RealRectangle2D aTextBBoxNormal (mpNormal->maText.GetBoundingBox(rxCanvas));
1449 geometry::RealRectangle2D aTextBBoxMouseOver (mpMouseOver->maText.GetBoundingBox(rxCanvas));
1450 geometry::RealRectangle2D aTextBBoxSelected (mpSelected->maText.GetBoundingBox(rxCanvas));
1451 geometry::RealRectangle2D aTextBBoxDisabled (mpDisabled->maText.GetBoundingBox(rxCanvas));
1452 geometry::RealRectangle2D aTextBBoxMouseOverSelected (mpMouseOverSelected->maText.GetBoundingBox(rxCanvas));
1453 std::vector<sal_Int32> widths
1455 sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxNormal.X2 - aTextBBoxNormal.X1),
1456 sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxMouseOver.X2 - aTextBBoxMouseOver.X1),
1457 sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxSelected.X2 - aTextBBoxSelected.X1),
1458 sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxDisabled.X2 - aTextBBoxDisabled.X1),
1459 sal::static_int_cast<sal_Int32>(0.5 + aTextBBoxMouseOverSelected.X2 - aTextBBoxMouseOverSelected.X1)
1462 sal_Int32 nTextHeight (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1463 Reference<rendering::XBitmap> xBitmap;
1464 if (mpMode->mpIcon)
1465 xBitmap = mpMode->mpIcon->GetNormalBitmap();
1466 if (xBitmap.is())
1468 const sal_Int32 nGap (5);
1469 geometry::IntegerSize2D aSize (xBitmap->getSize());
1470 return awt::Size(
1471 ::std::max(aSize.Width, *std::max_element(widths.begin(), widths.end())),
1472 aSize.Height + nGap + nTextHeight);
1474 else
1476 return awt::Size(*std::max_element(widths.begin(), widths.end()), nTextHeight);
1480 void Button::PaintIcon (
1481 const Reference<rendering::XCanvas>& rxCanvas,
1482 const sal_Int32 nTextHeight,
1483 const rendering::ViewState& rViewState)
1485 if (!mpMode)
1486 return;
1488 Reference<rendering::XBitmap> xBitmap (mpMode->mpIcon->GetBitmap(GetMode()));
1489 if (!xBitmap.is())
1490 return;
1492 /// check whether RTL interface or not
1493 if(!AllSettings::GetLayoutRTL()){
1494 const sal_Int32 nX (maLocation.X
1495 + (maSize.Width-xBitmap->getSize().Width) / 2);
1496 const sal_Int32 nY (maLocation.Y
1497 + (maSize.Height - nTextHeight - xBitmap->getSize().Height) / 2);
1498 const rendering::RenderState aRenderState(
1499 geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
1500 nullptr,
1501 Sequence<double>(4),
1502 rendering::CompositeOperation::OVER);
1503 rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState);
1505 else {
1506 const sal_Int32 nX (maLocation.X
1507 + (maSize.Width+xBitmap->getSize().Width) / 2);
1508 const sal_Int32 nY (maLocation.Y
1509 + (maSize.Height - nTextHeight - xBitmap->getSize().Height) / 2);
1510 const rendering::RenderState aRenderState(
1511 geometry::AffineMatrix2D(-1,0,nX, 0,1,nY),
1512 nullptr,
1513 Sequence<double>(4),
1514 rendering::CompositeOperation::OVER);
1515 rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState);
1519 PresenterBitmapDescriptor::Mode Button::GetMode() const
1521 if ( ! IsEnabled())
1522 return PresenterBitmapDescriptor::Disabled;
1523 else if (mbIsPressed)
1524 return PresenterBitmapDescriptor::ButtonDown;
1525 else if (mbIsOver)
1526 return PresenterBitmapDescriptor::MouseOver;
1527 else
1528 return PresenterBitmapDescriptor::Normal;
1531 //----- lang::XEventListener --------------------------------------------------
1533 void SAL_CALL Button::disposing (const css::lang::EventObject& rEvent)
1535 mbIsListenerRegistered = false;
1536 Element::disposing(rEvent);
1539 } // end of anonymous namespace
1541 //===== PresenterToolBar::Label ===============================================
1543 namespace {
1545 Label::Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1546 : Element(rpToolBar)
1550 awt::Size Label::CreateBoundingSize (
1551 const Reference<rendering::XCanvas>& rxCanvas)
1553 if (!mpMode)
1554 return awt::Size(0,0);
1556 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1557 return awt::Size(
1558 sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.X2 - aTextBBox.X1),
1559 sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1562 void Label::SetText (const OUString& rsText)
1564 OSL_ASSERT(mpToolBar);
1565 if (!mpMode)
1566 return;
1568 const bool bRequestLayout (mpMode->maText.GetText().getLength() != rsText.getLength());
1570 mpMode->maText.SetText(rsText);
1571 // Just use the character count for determining whether a layout is
1572 // necessary. This is an optimization to avoid layouts every time a new
1573 // time value is set on some labels.
1574 if (bRequestLayout)
1575 mpToolBar->RequestLayout();
1576 else
1577 Invalidate(false);
1580 void Label::Paint (
1581 const Reference<rendering::XCanvas>& rxCanvas,
1582 const rendering::ViewState& rViewState)
1584 OSL_ASSERT(rxCanvas.is());
1585 if (!mpMode)
1586 return;
1588 mpMode->maText.Paint(rxCanvas, rViewState, GetBoundingBox());
1591 bool Label::SetState (const bool, const bool)
1593 // For labels there is no mouse over effect.
1594 return Element::SetState(false, false);
1597 } // end of anonymous namespace
1599 //===== Text ==================================================================
1601 namespace {
1603 Text::Text()
1607 Text::Text (
1608 const OUString& rsText,
1609 const PresenterTheme::SharedFontDescriptor& rpFont)
1610 : msText(rsText),
1611 mpFont(rpFont)
1615 void Text::SetText (const OUString& rsText)
1617 msText = rsText;
1620 const OUString& Text::GetText() const
1622 return msText;
1625 const PresenterTheme::SharedFontDescriptor& Text::GetFont() const
1627 return mpFont;
1630 void Text::Paint (
1631 const Reference<rendering::XCanvas>& rxCanvas,
1632 const rendering::ViewState& rViewState,
1633 const awt::Rectangle& rBoundingBox)
1635 OSL_ASSERT(rxCanvas.is());
1637 if (msText.isEmpty())
1638 return;
1639 if (!mpFont)
1640 return;
1642 if ( ! mpFont->mxFont.is())
1643 mpFont->PrepareFont(rxCanvas);
1644 if ( ! mpFont->mxFont.is())
1645 return;
1647 rendering::StringContext aContext (msText, 0, msText.getLength());
1649 Reference<rendering::XTextLayout> xLayout (
1650 mpFont->mxFont->createTextLayout(
1651 aContext,
1652 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1653 0));
1654 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1655 const double nTextWidth = aBox.X2 - aBox.X1;
1656 const double nY = rBoundingBox.Y + rBoundingBox.Height - aBox.Y2;
1657 const double nX = rBoundingBox.X + (rBoundingBox.Width - nTextWidth)/2;
1659 rendering::RenderState aRenderState(
1660 geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
1661 nullptr,
1662 Sequence<double>(4),
1663 rendering::CompositeOperation::SOURCE);
1664 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1665 rxCanvas->drawTextLayout(
1666 xLayout,
1667 rViewState,
1668 aRenderState);
1671 geometry::RealRectangle2D Text::GetBoundingBox (const Reference<rendering::XCanvas>& rxCanvas)
1673 if (mpFont && !msText.isEmpty())
1675 if ( ! mpFont->mxFont.is())
1676 mpFont->PrepareFont(rxCanvas);
1677 if (mpFont->mxFont.is())
1679 rendering::StringContext aContext (msText, 0, msText.getLength());
1680 Reference<rendering::XTextLayout> xLayout (
1681 mpFont->mxFont->createTextLayout(
1682 aContext,
1683 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1684 0));
1685 return xLayout->queryTextBounds();
1688 return geometry::RealRectangle2D(0,0,0,0);
1691 //===== TimeFormatter =========================================================
1693 OUString TimeFormatter::FormatTime (const oslDateTime& rTime)
1695 OUStringBuffer sText;
1697 const sal_Int32 nHours (sal::static_int_cast<sal_Int32>(rTime.Hours));
1698 const sal_Int32 nMinutes (sal::static_int_cast<sal_Int32>(rTime.Minutes));
1699 const sal_Int32 nSeconds(sal::static_int_cast<sal_Int32>(rTime.Seconds));
1700 // Hours
1701 sText.append(nHours);
1703 sText.append(":");
1705 // Minutes
1706 const OUString sMinutes (OUString::number(nMinutes));
1707 if (sMinutes.getLength() == 1)
1708 sText.append("0");
1709 sText.append(sMinutes);
1711 // Seconds
1712 sText.append(":");
1713 const OUString sSeconds (OUString::number(nSeconds));
1714 if (sSeconds.getLength() == 1)
1715 sText.append("0");
1716 sText.append(sSeconds);
1717 return sText.makeStringAndClear();
1720 //===== TimeLabel =============================================================
1722 TimeLabel::TimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1723 : Label(rpToolBar)
1727 void SAL_CALL TimeLabel::disposing()
1729 PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->RemoveListener(mpListener);
1730 mpListener.reset();
1733 void TimeLabel::ConnectToTimer()
1735 mpListener = std::make_shared<Listener>(this);
1736 PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->AddListener(mpListener);
1739 //===== CurrentTimeLabel ======================================================
1741 ::rtl::Reference<Element> CurrentTimeLabel::Create (
1742 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1744 ::rtl::Reference<TimeLabel> pElement(new CurrentTimeLabel(rpToolBar));
1745 pElement->ConnectToTimer();
1746 return pElement;
1749 CurrentTimeLabel::~CurrentTimeLabel()
1753 CurrentTimeLabel::CurrentTimeLabel (
1754 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1755 : TimeLabel(rpToolBar)
1759 void CurrentTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1761 SetText(TimeFormatter::FormatTime(rCurrentTime));
1762 Invalidate(false);
1765 void CurrentTimeLabel::SetModes (
1766 const SharedElementMode& rpNormalMode,
1767 const SharedElementMode& rpMouseOverMode,
1768 const SharedElementMode& rpSelectedMode,
1769 const SharedElementMode& rpDisabledMode,
1770 const SharedElementMode& rpMouseOverSelectedMode)
1772 TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode, rpMouseOverSelectedMode);
1773 SetText(TimeFormatter::FormatTime(PresenterClockTimer::GetCurrentTime()));
1776 //===== PresentationTimeLabel =================================================
1778 ::rtl::Reference<Element> PresentationTimeLabel::Create (
1779 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1781 ::rtl::Reference<TimeLabel> pElement(new PresentationTimeLabel(rpToolBar));
1782 pElement->ConnectToTimer();
1783 return pElement;
1786 PresentationTimeLabel::~PresentationTimeLabel()
1788 mpToolBar->GetPresenterController()->SetPresentationTime(nullptr);
1791 PresentationTimeLabel::PresentationTimeLabel (
1792 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1793 : TimeLabel(rpToolBar),
1794 maStartTimeValue()
1796 restart();
1797 setPauseStatus(false);
1798 TimeValue pauseTime(0,0);
1799 setPauseTimeValue(pauseTime);
1800 mpToolBar->GetPresenterController()->SetPresentationTime(this);
1803 void PresentationTimeLabel::restart()
1805 TimeValue pauseTime(0, 0);
1806 setPauseTimeValue(pauseTime);
1807 maStartTimeValue.Seconds = 0;
1808 maStartTimeValue.Nanosec = 0;
1811 bool PresentationTimeLabel::isPaused()
1813 return paused;
1816 void PresentationTimeLabel::setPauseStatus(const bool pauseStatus)
1818 paused = pauseStatus;
1821 const TimeValue& PresentationTimeLabel::getPauseTimeValue() const
1823 return pauseTimeValue;
1826 void PresentationTimeLabel::setPauseTimeValue(const TimeValue pauseTime)
1828 //store the time at which the presentation was paused
1829 pauseTimeValue = pauseTime;
1832 void PresentationTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1834 TimeValue aCurrentTimeValue;
1835 if (!osl_getTimeValueFromDateTime(&rCurrentTime, &aCurrentTimeValue))
1836 return;
1838 if (maStartTimeValue.Seconds==0 && maStartTimeValue.Nanosec==0)
1840 // This method is called for the first time. Initialize the
1841 // start time. The start time is rounded to nearest second to
1842 // keep the time updates synchronized with the current time label.
1843 maStartTimeValue = aCurrentTimeValue;
1844 if (maStartTimeValue.Nanosec >= 500000000)
1845 maStartTimeValue.Seconds += 1;
1846 maStartTimeValue.Nanosec = 0;
1849 //The start time value is incremented by the amount of time
1850 //the presentation was paused for in order to continue the
1851 //timer from the same position
1852 if(!isPaused())
1854 TimeValue pauseTime = getPauseTimeValue();
1855 if(pauseTime.Seconds != 0 || pauseTime.Nanosec != 0)
1857 TimeValue incrementValue(0, 0);
1858 incrementValue.Seconds = aCurrentTimeValue.Seconds - pauseTime.Seconds;
1859 if(pauseTime.Nanosec > aCurrentTimeValue.Nanosec)
1861 incrementValue.Nanosec = 1000000000 + aCurrentTimeValue.Nanosec - pauseTime.Nanosec;
1863 else
1865 incrementValue.Nanosec = aCurrentTimeValue.Nanosec - pauseTime.Nanosec;
1868 maStartTimeValue.Seconds += incrementValue.Seconds;
1869 maStartTimeValue.Nanosec += incrementValue.Nanosec;
1870 if(maStartTimeValue.Nanosec >= 1000000000)
1872 maStartTimeValue.Seconds += 1;
1873 maStartTimeValue.Nanosec -= 1000000000;
1876 TimeValue pauseTime_(0, 0);
1877 setPauseTimeValue(pauseTime_);
1880 else
1882 TimeValue pauseTime = getPauseTimeValue();
1883 if(pauseTime.Seconds == 0 && pauseTime.Nanosec == 0)
1885 setPauseTimeValue(aCurrentTimeValue);
1889 TimeValue aElapsedTimeValue;
1890 aElapsedTimeValue.Seconds = aCurrentTimeValue.Seconds - maStartTimeValue.Seconds;
1891 aElapsedTimeValue.Nanosec = aCurrentTimeValue.Nanosec - maStartTimeValue.Nanosec;
1893 oslDateTime aElapsedDateTime;
1894 if (osl_getDateTimeFromTimeValue(&aElapsedTimeValue, &aElapsedDateTime) && !isPaused())
1896 SetText(TimeFormatter::FormatTime(aElapsedDateTime));
1897 Invalidate(false);
1901 void PresentationTimeLabel::SetModes (
1902 const SharedElementMode& rpNormalMode,
1903 const SharedElementMode& rpMouseOverMode,
1904 const SharedElementMode& rpSelectedMode,
1905 const SharedElementMode& rpDisabledMode,
1906 const SharedElementMode& rpMouseOverSelectedMode)
1908 TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode, rpMouseOverSelectedMode);
1910 oslDateTime aStartDateTime;
1911 if (osl_getDateTimeFromTimeValue(&maStartTimeValue, &aStartDateTime))
1913 SetText(TimeFormatter::FormatTime(aStartDateTime));
1917 //===== VerticalSeparator =====================================================
1919 VerticalSeparator::VerticalSeparator (
1920 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1921 : Element(rpToolBar)
1925 void VerticalSeparator::Paint (
1926 const Reference<rendering::XCanvas>& rxCanvas,
1927 const rendering::ViewState& rViewState)
1929 OSL_ASSERT(rxCanvas.is());
1931 awt::Rectangle aBBox (GetBoundingBox());
1933 rendering::RenderState aRenderState(
1934 geometry::AffineMatrix2D(1,0,aBBox.X, 0,1,aBBox.Y),
1935 nullptr,
1936 Sequence<double>(4),
1937 rendering::CompositeOperation::OVER);
1938 if (mpMode)
1940 PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1941 if (pFont)
1942 PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1945 Reference<rendering::XBitmap> xBitmap(mpToolBar->GetPresenterController()->GetPresenterHelper()->loadBitmap("bitmaps/Separator.png", rxCanvas));
1946 if (!xBitmap.is())
1947 return;
1949 rxCanvas->drawBitmap(
1950 xBitmap,
1951 rViewState,
1952 aRenderState);
1955 awt::Size VerticalSeparator::CreateBoundingSize (
1956 const Reference<rendering::XCanvas>&)
1958 return awt::Size(1,20);
1961 bool VerticalSeparator::IsFilling() const
1963 return true;
1966 //===== HorizontalSeparator ===================================================
1968 HorizontalSeparator::HorizontalSeparator (
1969 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1970 : Element(rpToolBar)
1974 void HorizontalSeparator::Paint (
1975 const Reference<rendering::XCanvas>& rxCanvas,
1976 const rendering::ViewState& rViewState)
1978 OSL_ASSERT(rxCanvas.is());
1980 awt::Rectangle aBBox (GetBoundingBox());
1982 rendering::RenderState aRenderState(
1983 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1984 nullptr,
1985 Sequence<double>(4),
1986 rendering::CompositeOperation::OVER);
1987 if (mpMode)
1989 PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1990 if (pFont)
1991 PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1994 rxCanvas->fillPolyPolygon(
1995 PresenterGeometryHelper::CreatePolygon(aBBox, rxCanvas->getDevice()),
1996 rViewState,
1997 aRenderState);
2000 awt::Size HorizontalSeparator::CreateBoundingSize (
2001 const Reference<rendering::XCanvas>&)
2003 return awt::Size(20,1);
2006 bool HorizontalSeparator::IsFilling() const
2008 return true;
2011 } // end of anonymous namespace
2013 } // end of namespace ::sdext::presenter
2015 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */