Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sd / source / console / PresenterToolBar.cxx
blob5e7c770df20896de8cc7c2b31597cd4e47ceff84
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 <utility>
21 #include <vcl/settings.hxx>
22 #include "PresenterToolBar.hxx"
24 #include "PresenterBitmapContainer.hxx"
25 #include "PresenterCanvasHelper.hxx"
26 #include "PresenterGeometryHelper.hxx"
27 #include "PresenterPaintManager.hxx"
28 #include "PresenterTimer.hxx"
29 #include "PresenterWindowManager.hxx"
30 #include <DrawController.hxx>
32 #include <cppuhelper/compbase.hxx>
33 #include <com/sun/star/awt/XWindowPeer.hpp>
34 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
35 #include <com/sun/star/drawing/framework/XPane.hpp>
36 #include <com/sun/star/geometry/AffineMatrix2D.hpp>
37 #include <com/sun/star/rendering/CompositeOperation.hpp>
38 #include <com/sun/star/rendering/RenderState.hpp>
39 #include <com/sun/star/rendering/TextDirection.hpp>
40 #include <com/sun/star/rendering/ViewState.hpp>
41 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
42 #include <com/sun/star/util/Color.hpp>
43 #include <rtl/ustrbuf.hxx>
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::drawing::framework;
49 namespace sdext::presenter {
51 const sal_Int32 gnGapSize (20);
53 namespace {
55 class Text
57 public:
58 Text();
59 Text (
60 OUString sText,
61 PresenterTheme::SharedFontDescriptor pFont);
63 void SetText (const OUString& rsText);
64 const OUString& GetText() const;
65 const PresenterTheme::SharedFontDescriptor& GetFont() const;
67 void Paint (
68 const Reference<rendering::XCanvas>& rxCanvas,
69 const rendering::ViewState& rViewState,
70 const awt::Rectangle& rBoundingBox);
72 geometry::RealRectangle2D GetBoundingBox (
73 const Reference<rendering::XCanvas>& rxCanvas);
75 private:
76 OUString msText;
77 PresenterTheme::SharedFontDescriptor mpFont;
80 class ElementMode
82 public:
83 ElementMode();
84 ElementMode(const ElementMode&) = delete;
85 ElementMode& operator=(const ElementMode&) = delete;
87 SharedBitmapDescriptor mpIcon;
88 OUString msAction;
89 Text maText;
91 void ReadElementMode (
92 const Reference<beans::XPropertySet>& rxProperties,
93 const OUString& rsModeName,
94 std::shared_ptr<ElementMode> const & rpDefaultMode,
95 ::sdext::presenter::PresenterToolBar::Context const & rContext);
97 typedef std::shared_ptr<ElementMode> SharedElementMode;
99 } // end of anonymous namespace
101 class PresenterToolBar::Context
103 public:
104 Context() = default;
105 Context(const Context&) = delete;
106 Context& operator=(const Context&) = delete;
107 Reference<drawing::XPresenterHelper> mxPresenterHelper;
108 css::uno::Reference<css::rendering::XCanvas> mxCanvas;
111 //===== PresenterToolBar::Element =============================================
113 namespace {
114 typedef cppu::WeakComponentImplHelper<
115 css::document::XEventListener,
116 css::frame::XStatusListener
117 > ElementInterfaceBase;
119 class Element
120 : private ::cppu::BaseMutex,
121 public ElementInterfaceBase
123 public:
124 explicit Element (::rtl::Reference<PresenterToolBar> pToolBar);
125 Element(const Element&) = delete;
126 Element& operator=(const Element&) = delete;
128 virtual void SAL_CALL disposing() override;
130 virtual void SetModes (
131 const SharedElementMode& rpNormalMode,
132 const SharedElementMode& rpMouseOverMode,
133 const SharedElementMode& rpSelectedMode,
134 const SharedElementMode& rpDisabledMode,
135 const SharedElementMode& rpMouseOverSelectedMode);
136 void CurrentSlideHasChanged();
137 void SetLocation (const awt::Point& rLocation);
138 void SetSize (const geometry::RealSize2D& rSize);
139 virtual void Paint (
140 const Reference<rendering::XCanvas>& rxCanvas,
141 const rendering::ViewState& rViewState) = 0;
142 awt::Size const & GetBoundingSize (
143 const Reference<rendering::XCanvas>& rxCanvas);
144 awt::Rectangle GetBoundingBox() const;
145 virtual bool SetState (const bool bIsOver, const bool bIsPressed);
146 void Invalidate (const bool bSynchronous);
147 bool IsOutside (const awt::Rectangle& rBox);
148 virtual bool IsFilling() const;
149 void UpdateState();
151 // lang::XEventListener
153 virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
155 // document::XEventListener
157 virtual void SAL_CALL notifyEvent (const css::document::EventObject& rEvent) override;
159 // frame::XStatusListener
161 virtual void SAL_CALL statusChanged (const css::frame::FeatureStateEvent& rEvent) override;
163 protected:
164 ::rtl::Reference<PresenterToolBar> mpToolBar;
165 awt::Point maLocation;
166 awt::Size maSize;
167 SharedElementMode mpNormal;
168 SharedElementMode mpMouseOver;
169 SharedElementMode mpSelected;
170 SharedElementMode mpDisabled;
171 SharedElementMode mpMouseOverSelected;
172 SharedElementMode mpMode;
173 bool mbIsOver;
174 bool mbIsPressed;
175 bool mbIsSelected;
177 virtual awt::Size CreateBoundingSize (
178 const Reference<rendering::XCanvas>& rxCanvas) = 0;
180 bool IsEnabled() const { return mbIsEnabled;}
181 private:
182 bool mbIsEnabled;
185 } // end of anonymous namespace
187 class PresenterToolBar::ElementContainerPart
188 : public ::std::vector<rtl::Reference<Element> >
192 //===== Button ================================================================
194 namespace {
196 class Button : public Element
198 public:
199 static ::rtl::Reference<Element> Create (
200 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
202 virtual void SAL_CALL disposing() override;
204 virtual void Paint (
205 const Reference<rendering::XCanvas>& rxCanvas,
206 const rendering::ViewState& rViewState) override;
208 // lang::XEventListener
210 virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
212 protected:
213 virtual awt::Size CreateBoundingSize (
214 const Reference<rendering::XCanvas>& rxCanvas) override;
216 private:
217 bool mbIsListenerRegistered;
219 Button (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
220 void Initialize();
221 void PaintIcon (
222 const Reference<rendering::XCanvas>& rxCanvas,
223 const sal_Int32 nTextHeight,
224 const rendering::ViewState& rViewState);
225 PresenterBitmapDescriptor::Mode GetMode() const;
228 //===== Label =================================================================
230 class Label : public Element
232 public:
233 explicit Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
235 void SetText (const OUString& rsText);
236 virtual void Paint (
237 const Reference<rendering::XCanvas>& rxCanvas,
238 const rendering::ViewState& rViewState) override;
239 virtual bool SetState (const bool bIsOver, const bool bIsPressed) override;
241 protected:
242 virtual awt::Size CreateBoundingSize (
243 const Reference<rendering::XCanvas>& rxCanvas) override;
246 // Some specialized controls.
248 class TimeFormatter
250 public:
251 static OUString FormatTime (const oslDateTime& rTime);
254 class TimeLabel : public Label
256 public:
257 void ConnectToTimer();
258 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) = 0;
259 protected:
260 explicit TimeLabel(const ::rtl::Reference<PresenterToolBar>& rpToolBar);
261 using Element::disposing;
262 virtual void SAL_CALL disposing() override;
263 private:
264 class Listener : public PresenterClockTimer::Listener
266 public:
267 explicit Listener (::rtl::Reference<TimeLabel> xLabel)
268 : mxLabel(std::move(xLabel)) {}
269 virtual ~Listener() {}
270 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override
271 { if (mxLabel.is()) mxLabel->TimeHasChanged(rCurrentTime); }
272 private:
273 ::rtl::Reference<TimeLabel> mxLabel;
275 std::shared_ptr<PresenterClockTimer::Listener> mpListener;
278 class CurrentTimeLabel : public TimeLabel
280 public:
281 static ::rtl::Reference<Element> Create (
282 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
283 virtual void SetModes (
284 const SharedElementMode& rpNormalMode,
285 const SharedElementMode& rpMouseOverMode,
286 const SharedElementMode& rpSelectedMode,
287 const SharedElementMode& rpDisabledMode,
288 const SharedElementMode& rpMouseOverSelectedMode) override;
289 private:
290 CurrentTimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
291 virtual ~CurrentTimeLabel() override;
292 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
295 class PresentationTimeLabel : public TimeLabel, public IPresentationTime
297 public:
298 static ::rtl::Reference<Element> Create (
299 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
300 virtual void SetModes (
301 const SharedElementMode& rpNormalMode,
302 const SharedElementMode& rpMouseOverMode,
303 const SharedElementMode& rpSelectedMode,
304 const SharedElementMode& rpDisabledMode,
305 const SharedElementMode& rpMouseOverSelectedMode) override;
306 virtual void restart() override;
307 virtual bool isPaused() override;
308 virtual void setPauseStatus(const bool pauseStatus) override;
309 const TimeValue& getPauseTimeValue() const;
310 void setPauseTimeValue(const TimeValue pauseTime);
311 private:
312 TimeValue maStartTimeValue;
313 TimeValue pauseTimeValue;
314 PresentationTimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
315 bool paused;
316 virtual ~PresentationTimeLabel() override;
317 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
320 class VerticalSeparator : public Element
322 public:
323 explicit VerticalSeparator (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
324 virtual void Paint (
325 const Reference<rendering::XCanvas>& rxCanvas,
326 const rendering::ViewState& rViewState) override;
327 virtual bool IsFilling() const override;
329 protected:
330 virtual awt::Size CreateBoundingSize (
331 const Reference<rendering::XCanvas>& rxCanvas) override;
334 class HorizontalSeparator : public Element
336 public:
337 explicit HorizontalSeparator (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
338 virtual void Paint (
339 const Reference<rendering::XCanvas>& rxCanvas,
340 const rendering::ViewState& rViewState) override;
341 virtual bool IsFilling() const override;
343 protected:
344 virtual awt::Size CreateBoundingSize (
345 const Reference<rendering::XCanvas>& rxCanvas) override;
347 } // end of anonymous namespace
349 //===== PresenterToolBar ======================================================
351 PresenterToolBar::PresenterToolBar (
352 const Reference<XComponentContext>& rxContext,
353 css::uno::Reference<css::awt::XWindow> xWindow,
354 css::uno::Reference<css::rendering::XCanvas> xCanvas,
355 ::rtl::Reference<PresenterController> pPresenterController,
356 const Anchor eAnchor)
357 : PresenterToolBarInterfaceBase(m_aMutex),
358 mxComponentContext(rxContext),
359 mxWindow(std::move(xWindow)),
360 mxCanvas(std::move(xCanvas)),
361 mpPresenterController(std::move(pPresenterController)),
362 mbIsLayoutPending(false),
363 meAnchor(eAnchor)
367 void PresenterToolBar::Initialize (
368 const OUString& rsConfigurationPath)
372 CreateControls(rsConfigurationPath);
374 if (mxWindow.is())
376 mxWindow->addWindowListener(this);
377 mxWindow->addPaintListener(this);
378 mxWindow->addMouseListener(this);
379 mxWindow->addMouseMotionListener(this);
381 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
382 if (xPeer.is())
383 xPeer->setBackground(util::Color(0xff000000));
385 mxWindow->setVisible(true);
388 mxSlideShowController = mpPresenterController->GetSlideShowController();
389 UpdateSlideNumber();
390 mbIsLayoutPending = true;
392 catch (RuntimeException&)
394 mpCurrentContainerPart.reset();
395 maElementContainer.clear();
396 throw;
400 PresenterToolBar::~PresenterToolBar()
404 void SAL_CALL PresenterToolBar::disposing()
406 if (mxWindow.is())
408 mxWindow->removeWindowListener(this);
409 mxWindow->removePaintListener(this);
410 mxWindow->removeMouseListener(this);
411 mxWindow->removeMouseMotionListener(this);
412 mxWindow = nullptr;
415 // Dispose tool bar elements.
416 for (const auto& rxPart : maElementContainer)
418 OSL_ASSERT(rxPart != nullptr);
419 for (const rtl::Reference<Element>& pElement : *rxPart)
421 if (pElement)
423 Reference<lang::XComponent> xComponent = pElement;
424 if (xComponent.is())
425 xComponent->dispose();
430 mpCurrentContainerPart.reset();
431 maElementContainer.clear();
434 void PresenterToolBar::InvalidateArea (
435 const awt::Rectangle& rRepaintBox,
436 const bool bSynchronous)
438 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
439 if (!xManager)
440 return;
441 xManager->Invalidate(
442 mxWindow,
443 rRepaintBox,
444 bSynchronous);
447 void PresenterToolBar::RequestLayout()
449 mbIsLayoutPending = true;
451 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
452 if (!xManager)
453 return;
455 xManager->Invalidate(mxWindow);
458 geometry::RealSize2D const & PresenterToolBar::GetMinimalSize()
460 if (mbIsLayoutPending)
461 Layout(mxCanvas);
462 return maMinimalSize;
465 const ::rtl::Reference<PresenterController>& PresenterToolBar::GetPresenterController() const
467 return mpPresenterController;
470 const Reference<XComponentContext>& PresenterToolBar::GetComponentContext() const
472 return mxComponentContext;
475 //----- lang::XEventListener -------------------------------------------------
477 void SAL_CALL PresenterToolBar::disposing (const lang::EventObject& rEventObject)
479 if (rEventObject.Source == mxWindow)
480 mxWindow = nullptr;
483 //----- XWindowListener -------------------------------------------------------
485 void SAL_CALL PresenterToolBar::windowResized (const awt::WindowEvent&)
487 mbIsLayoutPending = true;
490 void SAL_CALL PresenterToolBar::windowMoved (const awt::WindowEvent&) {}
492 void SAL_CALL PresenterToolBar::windowShown (const lang::EventObject&)
494 mbIsLayoutPending = true;
497 void SAL_CALL PresenterToolBar::windowHidden (const lang::EventObject&) {}
499 //----- XPaintListener --------------------------------------------------------
500 void SAL_CALL PresenterToolBar::windowPaint (const css::awt::PaintEvent& rEvent)
502 if ( ! mxCanvas.is())
503 return;
505 if ( ! mbIsPresenterViewActive)
506 return;
508 const rendering::ViewState aViewState (
509 geometry::AffineMatrix2D(1,0,0, 0,1,0),
510 PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice()));
512 if (mbIsLayoutPending)
513 Layout(mxCanvas);
515 Paint(rEvent.UpdateRect, aViewState);
517 // Make the back buffer visible.
518 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
519 if (xSpriteCanvas.is())
520 xSpriteCanvas->updateScreen(false);
523 //----- XMouseListener --------------------------------------------------------
524 void SAL_CALL PresenterToolBar::mousePressed (const css::awt::MouseEvent& rEvent)
526 ThrowIfDisposed();
527 CheckMouseOver(rEvent, true, true);
530 void SAL_CALL PresenterToolBar::mouseReleased (const css::awt::MouseEvent& rEvent)
532 ThrowIfDisposed();
533 CheckMouseOver(rEvent, true);
536 void SAL_CALL PresenterToolBar::mouseEntered (const css::awt::MouseEvent& rEvent)
538 ThrowIfDisposed();
539 CheckMouseOver(rEvent, true);
542 void SAL_CALL PresenterToolBar::mouseExited (const css::awt::MouseEvent& rEvent)
544 ThrowIfDisposed();
545 CheckMouseOver(rEvent, false);
548 //----- XMouseMotionListener --------------------------------------------------
550 void SAL_CALL PresenterToolBar::mouseMoved (const css::awt::MouseEvent& rEvent)
552 ThrowIfDisposed();
553 CheckMouseOver(rEvent, true);
556 void SAL_CALL PresenterToolBar::mouseDragged (const css::awt::MouseEvent&)
558 ThrowIfDisposed();
561 //----- XDrawView -------------------------------------------------------------
563 void SAL_CALL PresenterToolBar::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
565 if (rxSlide != mxCurrentSlide)
567 mxCurrentSlide = rxSlide;
568 UpdateSlideNumber();
572 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBar::getCurrentPage()
574 return mxCurrentSlide;
578 void PresenterToolBar::CreateControls (
579 const OUString& rsConfigurationPath)
581 if ( ! mxWindow.is())
582 return;
584 // Expand the macro in the bitmap file names.
585 PresenterConfigurationAccess aConfiguration (
586 mxComponentContext,
587 "/org.openoffice.Office.PresenterScreen/",
588 PresenterConfigurationAccess::READ_ONLY);
590 mpCurrentContainerPart = std::make_shared<ElementContainerPart>();
591 maElementContainer.clear();
592 maElementContainer.push_back(mpCurrentContainerPart);
594 Reference<container::XHierarchicalNameAccess> xToolBarNode (
595 aConfiguration.GetConfigurationNode(rsConfigurationPath),
596 UNO_QUERY);
597 if (!xToolBarNode.is())
598 return;
600 Reference<container::XNameAccess> xEntries (
601 PresenterConfigurationAccess::GetConfigurationNode(xToolBarNode, "Entries"),
602 UNO_QUERY);
603 Context aContext;
604 aContext.mxPresenterHelper = mpPresenterController->GetPresenterHelper();
605 aContext.mxCanvas = mxCanvas;
606 if (xEntries.is()
607 && aContext.mxPresenterHelper.is()
608 && aContext.mxCanvas.is())
610 PresenterConfigurationAccess::ForAll(
611 xEntries,
612 [this, &aContext] (OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
614 return this->ProcessEntry(xProps, aContext);
619 void PresenterToolBar::ProcessEntry (
620 const Reference<beans::XPropertySet>& rxProperties,
621 Context const & rContext)
623 if ( ! rxProperties.is())
624 return;
626 // Type has to be present.
627 OUString sType;
628 if ( ! (PresenterConfigurationAccess::GetProperty(rxProperties, "Type") >>= sType))
629 return;
631 // Read mode specific values.
632 SharedElementMode pNormalMode = std::make_shared<ElementMode>();
633 SharedElementMode pMouseOverMode = std::make_shared<ElementMode>();
634 SharedElementMode pSelectedMode = std::make_shared<ElementMode>();
635 SharedElementMode pDisabledMode = std::make_shared<ElementMode>();
636 SharedElementMode pMouseOverSelectedMode = std::make_shared<ElementMode>();
637 pNormalMode->ReadElementMode(rxProperties, "Normal", pNormalMode, rContext);
638 pMouseOverMode->ReadElementMode(rxProperties, "MouseOver", pNormalMode, rContext);
639 pSelectedMode->ReadElementMode(rxProperties, "Selected", pNormalMode, rContext);
640 pDisabledMode->ReadElementMode(rxProperties, "Disabled", pNormalMode, rContext);
641 pMouseOverSelectedMode->ReadElementMode(rxProperties, "MouseOverSelected", pSelectedMode, rContext);
643 // Create new element.
644 ::rtl::Reference<Element> pElement;
645 if ( sType == "Button" )
646 pElement = Button::Create(this);
647 else if ( sType == "CurrentTimeLabel" )
648 pElement = CurrentTimeLabel::Create(this);
649 else if ( sType == "PresentationTimeLabel" )
650 pElement = PresentationTimeLabel::Create(this);
651 else if ( sType == "VerticalSeparator" )
652 pElement.set(new VerticalSeparator(this));
653 else if ( sType == "HorizontalSeparator" )
654 pElement.set(new HorizontalSeparator(this));
655 else if ( sType == "Label" )
656 pElement.set(new Label(this));
657 else if ( sType == "ChangeOrientation" )
659 mpCurrentContainerPart = std::make_shared<ElementContainerPart>();
660 maElementContainer.push_back(mpCurrentContainerPart);
661 return;
663 if (pElement.is())
665 pElement->SetModes( pNormalMode, pMouseOverMode, pSelectedMode, pDisabledMode, pMouseOverSelectedMode);
666 pElement->UpdateState();
667 if (mpCurrentContainerPart)
668 mpCurrentContainerPart->push_back(pElement);
672 void PresenterToolBar::Layout (
673 const Reference<rendering::XCanvas>& rxCanvas)
675 if (maElementContainer.empty())
676 return;
678 mbIsLayoutPending = false;
680 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
681 ::std::vector<geometry::RealSize2D> aPartSizes (maElementContainer.size());
682 geometry::RealSize2D aTotalSize (0,0);
683 bool bIsHorizontal (true);
684 sal_Int32 nIndex (0);
685 double nTotalHorizontalGap (0);
686 sal_Int32 nGapCount (0);
687 for (const auto& rxPart : maElementContainer)
689 geometry::RealSize2D aSize (CalculatePartSize(rxCanvas, rxPart, bIsHorizontal));
691 // Remember the size of each part for later.
692 aPartSizes[nIndex] = aSize;
694 // Add gaps between elements.
695 if (rxPart->size()>1 && bIsHorizontal)
697 nTotalHorizontalGap += (rxPart->size() - 1) * gnGapSize;
698 nGapCount += rxPart->size() - 1;
701 // Orientation changes for each part.
702 bIsHorizontal = !bIsHorizontal;
703 // Width is accumulated.
704 aTotalSize.Width += aSize.Width;
705 // Height is the maximum height of all parts.
706 aTotalSize.Height = ::std::max(aTotalSize.Height, aSize.Height);
707 ++nIndex;
709 // Add gaps between parts.
710 if (maElementContainer.size() > 1)
712 nTotalHorizontalGap += (maElementContainer.size() - 1) * gnGapSize;
713 nGapCount += maElementContainer.size()-1;
716 // Done to introduce gap between the end of the toolbar and the last button
717 aTotalSize.Width += gnGapSize/2;
719 // Calculate the minimal size so that the window size of the tool bar
720 // can be adapted accordingly.
721 maMinimalSize = aTotalSize;
722 maMinimalSize.Width += nTotalHorizontalGap;
724 // Calculate the gaps between elements.
725 double nGapWidth (0);
726 if (nGapCount > 0)
728 if (aTotalSize.Width + nTotalHorizontalGap > aWindowBox.Width)
729 nTotalHorizontalGap = aWindowBox.Width - aTotalSize.Width;
730 nGapWidth = nTotalHorizontalGap / nGapCount;
733 // Determine the location of the left edge.
734 double nX (0);
735 switch (meAnchor)
737 case Left : nX = 0; break;
738 case Center: nX = (aWindowBox.Width - aTotalSize.Width - nTotalHorizontalGap) / 2; break;
741 // Place the parts.
742 double nY ((aWindowBox.Height - aTotalSize.Height) / 2);
743 bIsHorizontal = true;
745 /* push front or back ? ... */
746 /// check whether RTL interface or not
747 if(!AllSettings::GetLayoutRTL()){
748 nIndex = 0;
749 for (const auto& rxPart : maElementContainer)
751 geometry::RealRectangle2D aBoundingBox(
752 nX, nY,
753 nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height);
755 // Add space for gaps between elements.
756 if (rxPart->size() > 1 && bIsHorizontal)
757 aBoundingBox.X2 += (rxPart->size() - 1) * nGapWidth;
759 LayoutPart(rxCanvas, rxPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal);
760 bIsHorizontal = !bIsHorizontal;
761 nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth;
762 ++nIndex;
765 else {
766 ElementContainer::iterator iPart;
767 ElementContainer::iterator iBegin (maElementContainer.begin());
768 for (iPart=maElementContainer.end()-1, nIndex=2; iPart!=iBegin-1; --iPart, --nIndex)
770 geometry::RealRectangle2D aBoundingBox(
771 nX, nY,
772 nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height);
774 // Add space for gaps between elements.
775 if ((*iPart)->size() > 1)
776 if (bIsHorizontal)
777 aBoundingBox.X2 += ((*iPart)->size()-1) * nGapWidth;
779 LayoutPart(rxCanvas, *iPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal);
780 bIsHorizontal = !bIsHorizontal;
781 nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth;
785 // The whole window has to be repainted.
786 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
787 if (!xManager)
788 return;
789 xManager->Invalidate(mxWindow);
792 geometry::RealSize2D PresenterToolBar::CalculatePartSize (
793 const Reference<rendering::XCanvas>& rxCanvas,
794 const SharedElementContainerPart& rpPart,
795 const bool bIsHorizontal)
797 geometry::RealSize2D aTotalSize (0,0);
799 if (mxWindow.is())
801 // Calculate the summed width of all elements.
802 for (const auto& rxElement : *rpPart)
804 if (!rxElement)
805 continue;
807 const awt::Size aBSize (rxElement->GetBoundingSize(rxCanvas));
808 if (bIsHorizontal)
810 aTotalSize.Width += aBSize.Width;
811 if (aBSize.Height > aTotalSize.Height)
812 aTotalSize.Height = aBSize.Height;
814 else
816 aTotalSize.Height += aBSize.Height;
817 if (aBSize.Width > aTotalSize.Width)
818 aTotalSize.Width = aBSize.Width;
822 return aTotalSize;
825 void PresenterToolBar::LayoutPart (
826 const Reference<rendering::XCanvas>& rxCanvas,
827 const SharedElementContainerPart& rpPart,
828 const geometry::RealRectangle2D& rBoundingBox,
829 const geometry::RealSize2D& rPartSize,
830 const bool bIsHorizontal)
832 double nGap (0);
833 if (rpPart->size() > 1)
835 if (bIsHorizontal)
836 nGap = (rBoundingBox.X2 - rBoundingBox.X1 - rPartSize.Width) / (rpPart->size()-1);
837 else
838 nGap = (rBoundingBox.Y2 - rBoundingBox.Y1 - rPartSize.Height) / (rpPart->size()-1);
841 // Place the elements.
842 double nX (rBoundingBox.X1);
843 double nY (rBoundingBox.Y1);
845 /// check whether RTL interface or not
846 if(!AllSettings::GetLayoutRTL()){
847 for (auto& rxElement : *rpPart)
849 if (!rxElement)
850 continue;
852 const awt::Size aElementSize (rxElement->GetBoundingSize(rxCanvas));
853 if (bIsHorizontal)
855 if (rxElement->IsFilling())
857 nY = rBoundingBox.Y1;
858 rxElement->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
860 else
861 nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
862 rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
863 nX += aElementSize.Width + nGap;
865 else
867 if (rxElement->IsFilling())
869 nX = rBoundingBox.X1;
870 rxElement->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aElementSize.Height));
872 else
873 nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aElementSize.Width) / 2;
874 rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
875 nY += aElementSize.Height + nGap;
879 else {
880 ElementContainerPart::const_iterator iElement;
881 ElementContainerPart::const_iterator iBegin (rpPart->begin());
883 for (iElement=rpPart->end()-1; iElement!=iBegin-1; --iElement)
885 if (iElement->get() == nullptr)
886 continue;
888 const awt::Size aElementSize ((*iElement)->GetBoundingSize(rxCanvas));
889 if (bIsHorizontal)
891 if ((*iElement)->IsFilling())
893 nY = rBoundingBox.Y1;
894 (*iElement)->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
896 else
897 nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
898 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
899 nX += aElementSize.Width + nGap;
901 else
903 // reverse presentation time with current time
904 if (iElement==iBegin){
905 iElement=iBegin+2;
907 else if (iElement==iBegin+2){
908 iElement=iBegin;
910 const awt::Size aNewElementSize ((*iElement)->GetBoundingSize(rxCanvas));
911 if ((*iElement)->IsFilling())
913 nX = rBoundingBox.X1;
914 (*iElement)->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aNewElementSize.Height));
916 else
917 nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aNewElementSize.Width) / 2;
918 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
919 nY += aNewElementSize.Height + nGap;
921 // return the index as it was before the reversing
922 if (iElement==iBegin)
923 iElement=iBegin+2;
924 else if (iElement==iBegin+2)
925 iElement=iBegin;
931 void PresenterToolBar::Paint (
932 const awt::Rectangle& rUpdateBox,
933 const rendering::ViewState& rViewState)
935 OSL_ASSERT(mxCanvas.is());
937 for (const auto& rxPart : maElementContainer)
939 for (auto& rxElement : *rxPart)
941 if (rxElement)
943 if ( ! rxElement->IsOutside(rUpdateBox))
944 rxElement->Paint(mxCanvas, rViewState);
950 void PresenterToolBar::UpdateSlideNumber()
952 if( mxSlideShowController.is() )
954 for (const auto& rxPart : maElementContainer)
956 for (auto& rxElement : *rxPart)
958 if (rxElement)
959 rxElement->CurrentSlideHasChanged();
965 void PresenterToolBar::CheckMouseOver (
966 const css::awt::MouseEvent& rEvent,
967 const bool bOverWindow,
968 const bool bMouseDown)
970 css::awt::MouseEvent rTemp =rEvent;
971 if(AllSettings::GetLayoutRTL()){
972 awt::Rectangle aWindowBox = mxWindow->getPosSize();
973 rTemp.X=aWindowBox.Width-rTemp.X;
975 for (const auto& rxPart : maElementContainer)
977 for (auto& rxElement : *rxPart)
979 if (!rxElement)
980 continue;
982 awt::Rectangle aBox (rxElement->GetBoundingBox());
983 const bool bIsOver = bOverWindow
984 && aBox.X <= rTemp.X
985 && aBox.Width+aBox.X-1 >= rTemp.X
986 && aBox.Y <= rTemp.Y
987 && aBox.Height+aBox.Y-1 >= rTemp.Y;
988 rxElement->SetState(
989 bIsOver,
990 bIsOver && rTemp.Buttons!=0 && bMouseDown && rTemp.ClickCount>0);
995 void PresenterToolBar::ThrowIfDisposed() const
997 if (rBHelper.bDisposed || rBHelper.bInDispose)
999 throw lang::DisposedException (
1000 "PresenterToolBar has already been disposed",
1001 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
1005 //===== PresenterToolBarView ==================================================
1007 PresenterToolBarView::PresenterToolBarView (
1008 const Reference<XComponentContext>& rxContext,
1009 const Reference<XResourceId>& rxViewId,
1010 const rtl::Reference<::sd::DrawController>& rxController,
1011 const ::rtl::Reference<PresenterController>& rpPresenterController)
1012 : PresenterToolBarViewInterfaceBase(m_aMutex),
1013 mxViewId(rxViewId),
1014 mpPresenterController(rpPresenterController)
1018 Reference<XConfigurationController> xCC(rxController->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 ::rtl::Reference<PresenterToolBar> pToolBar)
1130 : ElementInterfaceBase(m_aMutex),
1131 mpToolBar(std::move(pToolBar)),
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 OUString sText,
1609 PresenterTheme::SharedFontDescriptor pFont)
1610 : msText(std::move(sText)),
1611 mpFont(std::move(pFont))
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(OUString::number(nHours) + ":");
1703 // Minutes
1704 const OUString sMinutes (OUString::number(nMinutes));
1705 if (sMinutes.getLength() == 1)
1706 sText.append("0");
1707 sText.append(sMinutes);
1709 // Seconds
1710 sText.append(":");
1711 const OUString sSeconds (OUString::number(nSeconds));
1712 if (sSeconds.getLength() == 1)
1713 sText.append("0");
1714 sText.append(sSeconds);
1715 return sText.makeStringAndClear();
1718 //===== TimeLabel =============================================================
1720 TimeLabel::TimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1721 : Label(rpToolBar)
1725 void SAL_CALL TimeLabel::disposing()
1727 PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->RemoveListener(mpListener);
1728 mpListener.reset();
1731 void TimeLabel::ConnectToTimer()
1733 mpListener = std::make_shared<Listener>(this);
1734 PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->AddListener(mpListener);
1737 //===== CurrentTimeLabel ======================================================
1739 ::rtl::Reference<Element> CurrentTimeLabel::Create (
1740 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1742 ::rtl::Reference<TimeLabel> pElement(new CurrentTimeLabel(rpToolBar));
1743 pElement->ConnectToTimer();
1744 return pElement;
1747 CurrentTimeLabel::~CurrentTimeLabel()
1751 CurrentTimeLabel::CurrentTimeLabel (
1752 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1753 : TimeLabel(rpToolBar)
1757 void CurrentTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1759 SetText(TimeFormatter::FormatTime(rCurrentTime));
1760 Invalidate(false);
1763 void CurrentTimeLabel::SetModes (
1764 const SharedElementMode& rpNormalMode,
1765 const SharedElementMode& rpMouseOverMode,
1766 const SharedElementMode& rpSelectedMode,
1767 const SharedElementMode& rpDisabledMode,
1768 const SharedElementMode& rpMouseOverSelectedMode)
1770 TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode, rpMouseOverSelectedMode);
1771 SetText(TimeFormatter::FormatTime(PresenterClockTimer::GetCurrentTime()));
1774 //===== PresentationTimeLabel =================================================
1776 ::rtl::Reference<Element> PresentationTimeLabel::Create (
1777 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1779 ::rtl::Reference<TimeLabel> pElement(new PresentationTimeLabel(rpToolBar));
1780 pElement->ConnectToTimer();
1781 return pElement;
1784 PresentationTimeLabel::~PresentationTimeLabel()
1786 mpToolBar->GetPresenterController()->SetPresentationTime(nullptr);
1789 PresentationTimeLabel::PresentationTimeLabel (
1790 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1791 : TimeLabel(rpToolBar),
1792 maStartTimeValue()
1794 restart();
1795 setPauseStatus(false);
1796 TimeValue pauseTime(0,0);
1797 setPauseTimeValue(pauseTime);
1798 mpToolBar->GetPresenterController()->SetPresentationTime(this);
1801 void PresentationTimeLabel::restart()
1803 TimeValue pauseTime(0, 0);
1804 setPauseTimeValue(pauseTime);
1805 maStartTimeValue.Seconds = 0;
1806 maStartTimeValue.Nanosec = 0;
1809 bool PresentationTimeLabel::isPaused()
1811 return paused;
1814 void PresentationTimeLabel::setPauseStatus(const bool pauseStatus)
1816 paused = pauseStatus;
1819 const TimeValue& PresentationTimeLabel::getPauseTimeValue() const
1821 return pauseTimeValue;
1824 void PresentationTimeLabel::setPauseTimeValue(const TimeValue pauseTime)
1826 //store the time at which the presentation was paused
1827 pauseTimeValue = pauseTime;
1830 void PresentationTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1832 TimeValue aCurrentTimeValue;
1833 if (!osl_getTimeValueFromDateTime(&rCurrentTime, &aCurrentTimeValue))
1834 return;
1836 if (maStartTimeValue.Seconds==0 && maStartTimeValue.Nanosec==0)
1838 // This method is called for the first time. Initialize the
1839 // start time. The start time is rounded to nearest second to
1840 // keep the time updates synchronized with the current time label.
1841 maStartTimeValue = aCurrentTimeValue;
1842 if (maStartTimeValue.Nanosec >= 500000000)
1843 maStartTimeValue.Seconds += 1;
1844 maStartTimeValue.Nanosec = 0;
1847 //The start time value is incremented by the amount of time
1848 //the presentation was paused for in order to continue the
1849 //timer from the same position
1850 if(!isPaused())
1852 TimeValue pauseTime = getPauseTimeValue();
1853 if(pauseTime.Seconds != 0 || pauseTime.Nanosec != 0)
1855 TimeValue incrementValue(0, 0);
1856 incrementValue.Seconds = aCurrentTimeValue.Seconds - pauseTime.Seconds;
1857 if(pauseTime.Nanosec > aCurrentTimeValue.Nanosec)
1859 incrementValue.Nanosec = 1000000000 + aCurrentTimeValue.Nanosec - pauseTime.Nanosec;
1861 else
1863 incrementValue.Nanosec = aCurrentTimeValue.Nanosec - pauseTime.Nanosec;
1866 maStartTimeValue.Seconds += incrementValue.Seconds;
1867 maStartTimeValue.Nanosec += incrementValue.Nanosec;
1868 if(maStartTimeValue.Nanosec >= 1000000000)
1870 maStartTimeValue.Seconds += 1;
1871 maStartTimeValue.Nanosec -= 1000000000;
1874 TimeValue pauseTime_(0, 0);
1875 setPauseTimeValue(pauseTime_);
1878 else
1880 TimeValue pauseTime = getPauseTimeValue();
1881 if(pauseTime.Seconds == 0 && pauseTime.Nanosec == 0)
1883 setPauseTimeValue(aCurrentTimeValue);
1887 TimeValue aElapsedTimeValue;
1888 aElapsedTimeValue.Seconds = aCurrentTimeValue.Seconds - maStartTimeValue.Seconds;
1889 aElapsedTimeValue.Nanosec = aCurrentTimeValue.Nanosec - maStartTimeValue.Nanosec;
1891 oslDateTime aElapsedDateTime;
1892 if (osl_getDateTimeFromTimeValue(&aElapsedTimeValue, &aElapsedDateTime) && !isPaused())
1894 SetText(TimeFormatter::FormatTime(aElapsedDateTime));
1895 Invalidate(false);
1899 void PresentationTimeLabel::SetModes (
1900 const SharedElementMode& rpNormalMode,
1901 const SharedElementMode& rpMouseOverMode,
1902 const SharedElementMode& rpSelectedMode,
1903 const SharedElementMode& rpDisabledMode,
1904 const SharedElementMode& rpMouseOverSelectedMode)
1906 TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode, rpMouseOverSelectedMode);
1908 oslDateTime aStartDateTime;
1909 if (osl_getDateTimeFromTimeValue(&maStartTimeValue, &aStartDateTime))
1911 SetText(TimeFormatter::FormatTime(aStartDateTime));
1915 //===== VerticalSeparator =====================================================
1917 VerticalSeparator::VerticalSeparator (
1918 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1919 : Element(rpToolBar)
1923 void VerticalSeparator::Paint (
1924 const Reference<rendering::XCanvas>& rxCanvas,
1925 const rendering::ViewState& rViewState)
1927 OSL_ASSERT(rxCanvas.is());
1929 awt::Rectangle aBBox (GetBoundingBox());
1931 rendering::RenderState aRenderState(
1932 geometry::AffineMatrix2D(1,0,aBBox.X, 0,1,aBBox.Y),
1933 nullptr,
1934 Sequence<double>(4),
1935 rendering::CompositeOperation::OVER);
1936 if (mpMode)
1938 PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1939 if (pFont)
1940 PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1943 Reference<rendering::XBitmap> xBitmap(mpToolBar->GetPresenterController()->GetPresenterHelper()->loadBitmap("bitmaps/Separator.png", rxCanvas));
1944 if (!xBitmap.is())
1945 return;
1947 rxCanvas->drawBitmap(
1948 xBitmap,
1949 rViewState,
1950 aRenderState);
1953 awt::Size VerticalSeparator::CreateBoundingSize (
1954 const Reference<rendering::XCanvas>&)
1956 return awt::Size(1,20);
1959 bool VerticalSeparator::IsFilling() const
1961 return true;
1964 //===== HorizontalSeparator ===================================================
1966 HorizontalSeparator::HorizontalSeparator (
1967 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1968 : Element(rpToolBar)
1972 void HorizontalSeparator::Paint (
1973 const Reference<rendering::XCanvas>& rxCanvas,
1974 const rendering::ViewState& rViewState)
1976 OSL_ASSERT(rxCanvas.is());
1978 awt::Rectangle aBBox (GetBoundingBox());
1980 rendering::RenderState aRenderState(
1981 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1982 nullptr,
1983 Sequence<double>(4),
1984 rendering::CompositeOperation::OVER);
1985 if (mpMode)
1987 PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1988 if (pFont)
1989 PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1992 rxCanvas->fillPolyPolygon(
1993 PresenterGeometryHelper::CreatePolygon(aBBox, rxCanvas->getDevice()),
1994 rViewState,
1995 aRenderState);
1998 awt::Size HorizontalSeparator::CreateBoundingSize (
1999 const Reference<rendering::XCanvas>&)
2001 return awt::Size(20,1);
2004 bool HorizontalSeparator::IsFilling() const
2006 return true;
2009 } // end of anonymous namespace
2011 } // end of namespace ::sdext::presenter
2013 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */