bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sdext / source / presenter / PresenterToolBar.cxx
blob5d065da4454e024905ed66e59cb7e1f415e80e4c
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/svapp.hxx>
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 "PresenterPaneBase.hxx"
29 #include "PresenterPaneFactory.hxx"
30 #include "PresenterTimer.hxx"
31 #include "PresenterWindowManager.hxx"
33 #include <cppuhelper/compbase.hxx>
34 #include <com/sun/star/awt/FontDescriptor.hpp>
35 #include <com/sun/star/awt/PosSize.hpp>
36 #include <com/sun/star/awt/XWindowPeer.hpp>
37 #include <com/sun/star/deployment/XPackageInformationProvider.hpp>
38 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
39 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
40 #include <com/sun/star/drawing/framework/XPane.hpp>
41 #include <com/sun/star/geometry/AffineMatrix2D.hpp>
42 #include <com/sun/star/lang/XServiceName.hpp>
43 #include <com/sun/star/rendering/CompositeOperation.hpp>
44 #include <com/sun/star/rendering/RenderState.hpp>
45 #include <com/sun/star/rendering/TextDirection.hpp>
46 #include <com/sun/star/rendering/ViewState.hpp>
47 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
48 #include <com/sun/star/text/XTextRange.hpp>
49 #include <com/sun/star/util/Color.hpp>
50 #include <com/sun/star/util/XURLTransformer.hpp>
51 #include <rtl/ustrbuf.hxx>
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::drawing::framework;
57 namespace sdext { namespace presenter {
59 static const sal_Int32 gnGapSize (20);
61 namespace {
63 class Text
65 public:
66 Text();
67 Text (
68 const OUString& rsText,
69 const PresenterTheme::SharedFontDescriptor& rpFont);
71 void SetText (const OUString& rsText);
72 const OUString& GetText() const;
73 const PresenterTheme::SharedFontDescriptor& GetFont() const;
75 void Paint (
76 const Reference<rendering::XCanvas>& rxCanvas,
77 const rendering::ViewState& rViewState,
78 const awt::Rectangle& rBoundingBox);
80 geometry::RealRectangle2D GetBoundingBox (
81 const Reference<rendering::XCanvas>& rxCanvas);
83 private:
84 OUString msText;
85 PresenterTheme::SharedFontDescriptor mpFont;
88 class ElementMode
90 public:
91 ElementMode();
92 ElementMode(const ElementMode&) = delete;
93 ElementMode& operator=(const ElementMode&) = delete;
95 SharedBitmapDescriptor mpIcon;
96 OUString msAction;
97 Text maText;
99 void ReadElementMode (
100 const Reference<beans::XPropertySet>& rxProperties,
101 const OUString& rsModeName,
102 std::shared_ptr<ElementMode> const & rpDefaultMode,
103 ::sdext::presenter::PresenterToolBar::Context const & rContext);
105 typedef std::shared_ptr<ElementMode> SharedElementMode;
107 } // end of anonymous namespace
109 class PresenterToolBar::Context
111 public:
112 Context() = default;
113 Context(const Context&) = delete;
114 Context& operator=(const Context&) = delete;
115 Reference<drawing::XPresenterHelper> mxPresenterHelper;
116 css::uno::Reference<css::rendering::XCanvas> mxCanvas;
119 //===== PresenterToolBar::Element =============================================
121 namespace {
122 typedef cppu::WeakComponentImplHelper<
123 css::document::XEventListener,
124 css::frame::XStatusListener
125 > ElementInterfaceBase;
127 class Element
128 : private ::cppu::BaseMutex,
129 public ElementInterfaceBase
131 public:
132 explicit Element (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
133 Element(const Element&) = delete;
134 Element& operator=(const Element&) = delete;
136 virtual void SAL_CALL disposing() override;
138 virtual void SetModes (
139 const SharedElementMode& rpNormalMode,
140 const SharedElementMode& rpMouseOverMode,
141 const SharedElementMode& rpSelectedMode,
142 const SharedElementMode& rpDisabledMode);
143 void CurrentSlideHasChanged();
144 void SetLocation (const awt::Point& rLocation);
145 void SetSize (const geometry::RealSize2D& rSize);
146 virtual void Paint (
147 const Reference<rendering::XCanvas>& rxCanvas,
148 const rendering::ViewState& rViewState) = 0;
149 awt::Size const & GetBoundingSize (
150 const Reference<rendering::XCanvas>& rxCanvas);
151 awt::Rectangle GetBoundingBox() const;
152 virtual bool SetState (const bool bIsOver, const bool bIsPressed);
153 void Invalidate (const bool bSynchronous);
154 bool IsOutside (const awt::Rectangle& rBox);
155 virtual bool IsFilling() const;
156 void UpdateState();
158 // lang::XEventListener
160 virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
162 // document::XEventListener
164 virtual void SAL_CALL notifyEvent (const css::document::EventObject& rEvent) override;
166 // frame::XStatusListener
168 virtual void SAL_CALL statusChanged (const css::frame::FeatureStateEvent& rEvent) override;
170 protected:
171 ::rtl::Reference<PresenterToolBar> mpToolBar;
172 awt::Point maLocation;
173 awt::Size maSize;
174 SharedElementMode mpNormal;
175 SharedElementMode mpMouseOver;
176 SharedElementMode mpSelected;
177 SharedElementMode mpDisabled;
178 SharedElementMode mpMode;
179 bool mbIsOver;
180 bool mbIsPressed;
181 bool mbIsSelected;
183 virtual awt::Size CreateBoundingSize (
184 const Reference<rendering::XCanvas>& rxCanvas) = 0;
186 bool IsEnabled() const { return mbIsEnabled;}
187 private:
188 bool mbIsEnabled;
191 } // end of anonymous namespace
193 class PresenterToolBar::ElementContainerPart
194 : public ::std::vector<rtl::Reference<Element> >
198 //===== Button ================================================================
200 namespace {
202 class Button : public Element
204 public:
205 static ::rtl::Reference<Element> Create (
206 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
208 virtual void SAL_CALL disposing() override;
210 virtual void Paint (
211 const Reference<rendering::XCanvas>& rxCanvas,
212 const rendering::ViewState& rViewState) override;
214 // lang::XEventListener
216 virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
218 protected:
219 virtual awt::Size CreateBoundingSize (
220 const Reference<rendering::XCanvas>& rxCanvas) override;
222 private:
223 bool mbIsListenerRegistered;
225 Button (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
226 void Initialize();
227 void PaintIcon (
228 const Reference<rendering::XCanvas>& rxCanvas,
229 const sal_Int32 nTextHeight,
230 const rendering::ViewState& rViewState);
231 PresenterBitmapDescriptor::Mode GetMode() const;
234 //===== Label =================================================================
236 class Label : public Element
238 public:
239 explicit Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
241 void SetText (const OUString& rsText);
242 virtual void Paint (
243 const Reference<rendering::XCanvas>& rxCanvas,
244 const rendering::ViewState& rViewState) override;
245 virtual bool SetState (const bool bIsOver, const bool bIsPressed) override;
247 protected:
248 virtual awt::Size CreateBoundingSize (
249 const Reference<rendering::XCanvas>& rxCanvas) override;
252 // Some specialized controls.
254 class TimeFormatter
256 public:
257 static OUString FormatTime (const oslDateTime& rTime);
260 class TimeLabel : public Label
262 public:
263 void ConnectToTimer();
264 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) = 0;
265 protected:
266 explicit TimeLabel(const ::rtl::Reference<PresenterToolBar>& rpToolBar);
267 using Element::disposing;
268 virtual void SAL_CALL disposing() override;
269 private:
270 class Listener : public PresenterClockTimer::Listener
272 public:
273 explicit Listener (const ::rtl::Reference<TimeLabel>& rxLabel)
274 : mxLabel(rxLabel) {}
275 virtual ~Listener() {}
276 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override
277 { if (mxLabel.is()) mxLabel->TimeHasChanged(rCurrentTime); }
278 private:
279 ::rtl::Reference<TimeLabel> mxLabel;
281 std::shared_ptr<PresenterClockTimer::Listener> mpListener;
284 class CurrentTimeLabel : public TimeLabel
286 public:
287 static ::rtl::Reference<Element> Create (
288 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
289 virtual void SetModes (
290 const SharedElementMode& rpNormalMode,
291 const SharedElementMode& rpMouseOverMode,
292 const SharedElementMode& rpSelectedMode,
293 const SharedElementMode& rpDisabledMode) override;
294 private:
295 CurrentTimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
296 virtual ~CurrentTimeLabel() override;
297 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
300 class PresentationTimeLabel : public TimeLabel, public IPresentationTime
302 public:
303 static ::rtl::Reference<Element> Create (
304 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
305 virtual void SetModes (
306 const SharedElementMode& rpNormalMode,
307 const SharedElementMode& rpMouseOverMode,
308 const SharedElementMode& rpSelectedMode,
309 const SharedElementMode& rpDisabledMode) override;
310 virtual void restart() override;
311 private:
312 TimeValue maStartTimeValue;
313 PresentationTimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
314 virtual ~PresentationTimeLabel() override;
315 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
318 class VerticalSeparator : public Element
320 public:
321 explicit VerticalSeparator (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
322 virtual void Paint (
323 const Reference<rendering::XCanvas>& rxCanvas,
324 const rendering::ViewState& rViewState) override;
325 virtual bool IsFilling() const override;
327 protected:
328 virtual awt::Size CreateBoundingSize (
329 const Reference<rendering::XCanvas>& rxCanvas) override;
332 class HorizontalSeparator : public Element
334 public:
335 explicit HorizontalSeparator (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
336 virtual void Paint (
337 const Reference<rendering::XCanvas>& rxCanvas,
338 const rendering::ViewState& rViewState) override;
339 virtual bool IsFilling() const override;
341 protected:
342 virtual awt::Size CreateBoundingSize (
343 const Reference<rendering::XCanvas>& rxCanvas) override;
345 } // end of anonymous namespace
347 //===== PresenterToolBar ======================================================
349 PresenterToolBar::PresenterToolBar (
350 const Reference<XComponentContext>& rxContext,
351 const css::uno::Reference<css::awt::XWindow>& rxWindow,
352 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
353 const ::rtl::Reference<PresenterController>& rpPresenterController,
354 const Anchor eAnchor)
355 : PresenterToolBarInterfaceBase(m_aMutex),
356 mxComponentContext(rxContext),
357 maElementContainer(),
358 mpCurrentContainerPart(),
359 mxWindow(rxWindow),
360 mxCanvas(rxCanvas),
361 mxSlideShowController(),
362 mxCurrentSlide(),
363 mpPresenterController(rpPresenterController),
364 mbIsLayoutPending(false),
365 meAnchor(eAnchor),
366 maMinimalSize()
370 void PresenterToolBar::Initialize (
371 const OUString& rsConfigurationPath)
375 CreateControls(rsConfigurationPath);
377 if (mxWindow.is())
379 mxWindow->addWindowListener(this);
380 mxWindow->addPaintListener(this);
381 mxWindow->addMouseListener(this);
382 mxWindow->addMouseMotionListener(this);
384 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
385 if (xPeer.is())
386 xPeer->setBackground(util::Color(0xff000000));
388 mxWindow->setVisible(true);
391 mxSlideShowController = mpPresenterController->GetSlideShowController();
392 UpdateSlideNumber();
393 mbIsLayoutPending = true;
395 catch (RuntimeException&)
397 mpCurrentContainerPart.reset();
398 maElementContainer.clear();
399 throw;
403 PresenterToolBar::~PresenterToolBar()
407 void SAL_CALL PresenterToolBar::disposing()
409 if (mxWindow.is())
411 mxWindow->removeWindowListener(this);
412 mxWindow->removePaintListener(this);
413 mxWindow->removeMouseListener(this);
414 mxWindow->removeMouseMotionListener(this);
415 mxWindow = nullptr;
418 // Dispose tool bar elements.
419 for (const auto& rxPart : maElementContainer)
421 OSL_ASSERT(rxPart != nullptr);
422 for (rtl::Reference<Element>& pElement : *rxPart)
424 if (pElement.get() != nullptr)
426 Reference<lang::XComponent> xComponent (
427 static_cast<XWeak*>(pElement.get()), UNO_QUERY);
428 if (xComponent.is())
429 xComponent->dispose();
434 mpCurrentContainerPart.reset();
435 maElementContainer.clear();
438 void PresenterToolBar::InvalidateArea (
439 const awt::Rectangle& rRepaintBox,
440 const bool bSynchronous)
442 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
443 if (!xManager)
444 return;
445 xManager->Invalidate(
446 mxWindow,
447 rRepaintBox,
448 bSynchronous);
451 void PresenterToolBar::RequestLayout()
453 mbIsLayoutPending = true;
455 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
456 if (!xManager)
457 return;
459 xManager->Invalidate(mxWindow);
462 geometry::RealSize2D const & PresenterToolBar::GetMinimalSize()
464 if (mbIsLayoutPending)
465 Layout(mxCanvas);
466 return maMinimalSize;
469 const ::rtl::Reference<PresenterController>& PresenterToolBar::GetPresenterController() const
471 return mpPresenterController;
474 const Reference<XComponentContext>& PresenterToolBar::GetComponentContext() const
476 return mxComponentContext;
479 //----- lang::XEventListener -------------------------------------------------
481 void SAL_CALL PresenterToolBar::disposing (const lang::EventObject& rEventObject)
483 if (rEventObject.Source == mxWindow)
484 mxWindow = nullptr;
487 //----- XWindowListener -------------------------------------------------------
489 void SAL_CALL PresenterToolBar::windowResized (const awt::WindowEvent&)
491 mbIsLayoutPending = true;
494 void SAL_CALL PresenterToolBar::windowMoved (const awt::WindowEvent&) {}
496 void SAL_CALL PresenterToolBar::windowShown (const lang::EventObject&)
498 mbIsLayoutPending = true;
501 void SAL_CALL PresenterToolBar::windowHidden (const lang::EventObject&) {}
503 //----- XPaintListener --------------------------------------------------------
504 void SAL_CALL PresenterToolBar::windowPaint (const css::awt::PaintEvent& rEvent)
506 if ( ! mxCanvas.is())
507 return;
509 if ( ! mbIsPresenterViewActive)
510 return;
512 const rendering::ViewState aViewState (
513 geometry::AffineMatrix2D(1,0,0, 0,1,0),
514 PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice()));
516 if (mbIsLayoutPending)
517 Layout(mxCanvas);
519 Paint(rEvent.UpdateRect, aViewState);
521 // Make the back buffer visible.
522 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
523 if (xSpriteCanvas.is())
524 xSpriteCanvas->updateScreen(false);
527 //----- XMouseListener --------------------------------------------------------
528 void SAL_CALL PresenterToolBar::mousePressed (const css::awt::MouseEvent& rEvent)
530 ThrowIfDisposed();
531 CheckMouseOver(rEvent, true, true);
534 void SAL_CALL PresenterToolBar::mouseReleased (const css::awt::MouseEvent& rEvent)
536 ThrowIfDisposed();
537 CheckMouseOver(rEvent, true);
540 void SAL_CALL PresenterToolBar::mouseEntered (const css::awt::MouseEvent& rEvent)
542 ThrowIfDisposed();
543 CheckMouseOver(rEvent, true);
546 void SAL_CALL PresenterToolBar::mouseExited (const css::awt::MouseEvent& rEvent)
548 ThrowIfDisposed();
549 CheckMouseOver(rEvent, false);
552 //----- XMouseMotionListener --------------------------------------------------
554 void SAL_CALL PresenterToolBar::mouseMoved (const css::awt::MouseEvent& rEvent)
556 ThrowIfDisposed();
557 CheckMouseOver(rEvent, true);
560 void SAL_CALL PresenterToolBar::mouseDragged (const css::awt::MouseEvent&)
562 ThrowIfDisposed();
565 //----- XDrawView -------------------------------------------------------------
567 void SAL_CALL PresenterToolBar::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
569 if (rxSlide != mxCurrentSlide)
571 mxCurrentSlide = rxSlide;
572 UpdateSlideNumber();
576 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBar::getCurrentPage()
578 return mxCurrentSlide;
582 void PresenterToolBar::CreateControls (
583 const OUString& rsConfigurationPath)
585 if ( ! mxWindow.is())
586 return;
588 // Expand the macro in the bitmap file names.
589 PresenterConfigurationAccess aConfiguration (
590 mxComponentContext,
591 "/org.openoffice.Office.PresenterScreen/",
592 PresenterConfigurationAccess::READ_ONLY);
594 mpCurrentContainerPart.reset(new ElementContainerPart);
595 maElementContainer.clear();
596 maElementContainer.push_back(mpCurrentContainerPart);
598 Reference<container::XHierarchicalNameAccess> xToolBarNode (
599 aConfiguration.GetConfigurationNode(rsConfigurationPath),
600 UNO_QUERY);
601 if (!xToolBarNode.is())
602 return;
604 Reference<container::XNameAccess> xEntries (
605 PresenterConfigurationAccess::GetConfigurationNode(xToolBarNode, "Entries"),
606 UNO_QUERY);
607 Context aContext;
608 aContext.mxPresenterHelper = mpPresenterController->GetPresenterHelper();
609 aContext.mxCanvas = mxCanvas;
610 if (xEntries.is()
611 && aContext.mxPresenterHelper.is()
612 && aContext.mxCanvas.is())
614 PresenterConfigurationAccess::ForAll(
615 xEntries,
616 [this, &aContext] (OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
618 return this->ProcessEntry(xProps, aContext);
623 void PresenterToolBar::ProcessEntry (
624 const Reference<beans::XPropertySet>& rxProperties,
625 Context const & rContext)
627 if ( ! rxProperties.is())
628 return;
630 // Type has to be present.
631 OUString sType;
632 if ( ! (PresenterConfigurationAccess::GetProperty(rxProperties, "Type") >>= sType))
633 return;
635 // Read mode specific values.
636 SharedElementMode pNormalMode (new ElementMode());
637 SharedElementMode pMouseOverMode (new ElementMode());
638 SharedElementMode pSelectedMode (new ElementMode());
639 SharedElementMode pDisabledMode (new ElementMode());
640 pNormalMode->ReadElementMode(rxProperties, "Normal", pNormalMode, rContext);
641 pMouseOverMode->ReadElementMode(rxProperties, "MouseOver", pNormalMode, rContext);
642 pSelectedMode->ReadElementMode(rxProperties, "Selected", pNormalMode, rContext);
643 pDisabledMode->ReadElementMode(rxProperties, "Disabled", pNormalMode, rContext);
645 // Create new element.
646 ::rtl::Reference<Element> pElement;
647 if ( sType == "Button" )
648 pElement = Button::Create(this);
649 else if ( sType == "CurrentTimeLabel" )
650 pElement = CurrentTimeLabel::Create(this);
651 else if ( sType == "PresentationTimeLabel" )
652 pElement = PresentationTimeLabel::Create(this);
653 else if ( sType == "VerticalSeparator" )
654 pElement.set(new VerticalSeparator(this));
655 else if ( sType == "HorizontalSeparator" )
656 pElement.set(new HorizontalSeparator(this));
657 else if ( sType == "Label" )
658 pElement.set(new Label(this));
659 else if ( sType == "ChangeOrientation" )
661 mpCurrentContainerPart.reset(new ElementContainerPart);
662 maElementContainer.push_back(mpCurrentContainerPart);
663 return;
665 if (pElement.is())
667 pElement->SetModes( pNormalMode, pMouseOverMode, pSelectedMode, pDisabledMode);
668 pElement->UpdateState();
669 if (mpCurrentContainerPart.get() != nullptr)
670 mpCurrentContainerPart->push_back(pElement);
674 void PresenterToolBar::Layout (
675 const Reference<rendering::XCanvas>& rxCanvas)
677 if (maElementContainer.empty())
678 return;
680 mbIsLayoutPending = false;
682 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
683 ::std::vector<geometry::RealSize2D> aPartSizes (maElementContainer.size());
684 geometry::RealSize2D aTotalSize (0,0);
685 bool bIsHorizontal (true);
686 sal_Int32 nIndex (0);
687 double nTotalHorizontalGap (0);
688 sal_Int32 nGapCount (0);
689 for (const auto& rxPart : maElementContainer)
691 geometry::RealSize2D aSize (CalculatePartSize(rxCanvas, rxPart, bIsHorizontal));
693 // Remember the size of each part for later.
694 aPartSizes[nIndex] = aSize;
696 // Add gaps between elements.
697 if (rxPart->size()>1 && bIsHorizontal)
699 nTotalHorizontalGap += (rxPart->size() - 1) * gnGapSize;
700 nGapCount += rxPart->size() - 1;
703 // Orientation changes for each part.
704 bIsHorizontal = !bIsHorizontal;
705 // Width is accumulated.
706 aTotalSize.Width += aSize.Width;
707 // Height is the maximum height of all parts.
708 aTotalSize.Height = ::std::max(aTotalSize.Height, aSize.Height);
709 ++nIndex;
711 // Add gaps between parts.
712 if (maElementContainer.size() > 1)
714 nTotalHorizontalGap += (maElementContainer.size() - 1) * gnGapSize;
715 nGapCount += maElementContainer.size()-1;
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)
756 if (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.get() == nullptr)
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.get() == nullptr)
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 iEnd (rpPart->end());
882 ElementContainerPart::const_iterator iBegin (rpPart->begin());
884 for (iElement=rpPart->end()-1; iElement!=iBegin-1; --iElement)
886 if (iElement->get() == nullptr)
887 continue;
889 const awt::Size aElementSize ((*iElement)->GetBoundingSize(rxCanvas));
890 if (bIsHorizontal)
892 if ((*iElement)->IsFilling())
894 nY = rBoundingBox.Y1;
895 (*iElement)->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
897 else
898 nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
899 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
900 nX += aElementSize.Width + nGap;
902 else
904 // reverse presentation time with current time
905 if (iElement==iBegin){
906 iElement=iBegin+2;
908 else if (iElement==iBegin+2){
909 iElement=iBegin;
911 const awt::Size aNewElementSize ((*iElement)->GetBoundingSize(rxCanvas));
912 if ((*iElement)->IsFilling())
914 nX = rBoundingBox.X1;
915 (*iElement)->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aNewElementSize.Height));
917 else
918 nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aNewElementSize.Width) / 2;
919 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
920 nY += aNewElementSize.Height + nGap;
922 // return the index as it was before the reversing
923 if (iElement==iBegin)
924 iElement=iBegin+2;
925 else if (iElement==iBegin+2)
926 iElement=iBegin;
932 void PresenterToolBar::Paint (
933 const awt::Rectangle& rUpdateBox,
934 const rendering::ViewState& rViewState)
936 OSL_ASSERT(mxCanvas.is());
938 for (const auto& rxPart : maElementContainer)
940 for (auto& rxElement : *rxPart)
942 if (rxElement.get() != nullptr)
944 if ( ! rxElement->IsOutside(rUpdateBox))
945 rxElement->Paint(mxCanvas, rViewState);
951 void PresenterToolBar::UpdateSlideNumber()
953 if( mxSlideShowController.is() )
955 for (const auto& rxPart : maElementContainer)
957 for (auto& rxElement : *rxPart)
959 if (rxElement.get() != nullptr)
960 rxElement->CurrentSlideHasChanged();
966 void PresenterToolBar::CheckMouseOver (
967 const css::awt::MouseEvent& rEvent,
968 const bool bOverWindow,
969 const bool bMouseDown)
971 css::awt::MouseEvent rTemp =rEvent;
972 if(AllSettings::GetLayoutRTL()){
973 awt::Rectangle aWindowBox = mxWindow->getPosSize();
974 rTemp.X=aWindowBox.Width-rTemp.X;
976 for (const auto& rxPart : maElementContainer)
978 for (auto& rxElement : *rxPart)
980 if (rxElement.get() == nullptr)
981 continue;
983 awt::Rectangle aBox (rxElement->GetBoundingBox());
984 const bool bIsOver = bOverWindow
985 && aBox.X <= rTemp.X
986 && aBox.Width+aBox.X-1 >= rTemp.X
987 && aBox.Y <= rTemp.Y
988 && aBox.Height+aBox.Y-1 >= rTemp.Y;
989 rxElement->SetState(
990 bIsOver,
991 bIsOver && rTemp.Buttons!=0 && bMouseDown && rTemp.ClickCount>0);
996 void PresenterToolBar::ThrowIfDisposed() const
998 if (rBHelper.bDisposed || rBHelper.bInDispose)
1000 throw lang::DisposedException (
1001 "PresenterToolBar has already been disposed",
1002 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
1006 //===== PresenterToolBarView ==================================================
1008 PresenterToolBarView::PresenterToolBarView (
1009 const Reference<XComponentContext>& rxContext,
1010 const Reference<XResourceId>& rxViewId,
1011 const Reference<frame::XController>& rxController,
1012 const ::rtl::Reference<PresenterController>& rpPresenterController)
1013 : PresenterToolBarViewInterfaceBase(m_aMutex),
1014 mxPane(),
1015 mxViewId(rxViewId),
1016 mxWindow(),
1017 mxCanvas(),
1018 mpPresenterController(rpPresenterController),
1019 mpToolBar()
1023 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
1024 Reference<XConfigurationController> xCC(xCM->getConfigurationController(),UNO_SET_THROW);
1025 mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
1027 mxWindow = mxPane->getWindow();
1028 mxCanvas = mxPane->getCanvas();
1030 mpToolBar = new PresenterToolBar(
1031 rxContext,
1032 mxWindow,
1033 mxCanvas,
1034 rpPresenterController,
1035 PresenterToolBar::Center);
1036 mpToolBar->Initialize("PresenterScreenSettings/ToolBars/ToolBar");
1038 if (mxWindow.is())
1040 mxWindow->addPaintListener(this);
1042 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
1043 if (xPeer.is())
1044 xPeer->setBackground(util::Color(0xff000000));
1046 mxWindow->setVisible(true);
1049 catch (RuntimeException&)
1051 mxViewId = nullptr;
1052 throw;
1056 PresenterToolBarView::~PresenterToolBarView()
1060 void SAL_CALL PresenterToolBarView::disposing()
1062 Reference<lang::XComponent> xComponent (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY);
1063 mpToolBar = nullptr;
1064 if (xComponent.is())
1065 xComponent->dispose();
1067 if (mxWindow.is())
1069 mxWindow->removePaintListener(this);
1070 mxWindow = nullptr;
1072 mxCanvas = nullptr;
1073 mxViewId = nullptr;
1074 mxPane = nullptr;
1075 mpPresenterController = nullptr;
1078 const ::rtl::Reference<PresenterToolBar>& PresenterToolBarView::GetPresenterToolBar() const
1080 return mpToolBar;
1083 //----- XPaintListener --------------------------------------------------------
1085 void SAL_CALL PresenterToolBarView::windowPaint (const css::awt::PaintEvent& rEvent)
1087 awt::Rectangle aWindowBox (mxWindow->getPosSize());
1088 mpPresenterController->GetCanvasHelper()->Paint(
1089 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
1090 mxCanvas,
1091 rEvent.UpdateRect,
1092 awt::Rectangle(0,0,aWindowBox.Width, aWindowBox.Height),
1093 awt::Rectangle());
1096 //----- lang::XEventListener -------------------------------------------------
1098 void SAL_CALL PresenterToolBarView::disposing (const lang::EventObject& rEventObject)
1100 if (rEventObject.Source == mxWindow)
1101 mxWindow = nullptr;
1104 //----- XResourceId -----------------------------------------------------------
1106 Reference<XResourceId> SAL_CALL PresenterToolBarView::getResourceId()
1108 return mxViewId;
1111 sal_Bool SAL_CALL PresenterToolBarView::isAnchorOnly()
1113 return false;
1116 //----- XDrawView -------------------------------------------------------------
1118 void SAL_CALL PresenterToolBarView::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
1120 Reference<drawing::XDrawView> xToolBar (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY);
1121 if (xToolBar.is())
1122 xToolBar->setCurrentPage(rxSlide);
1125 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBarView::getCurrentPage()
1127 return nullptr;
1130 //===== PresenterToolBar::Element =============================================
1132 namespace {
1134 Element::Element (
1135 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1136 : ElementInterfaceBase(m_aMutex),
1137 mpToolBar(rpToolBar),
1138 maLocation(),
1139 maSize(),
1140 mpNormal(),
1141 mpMouseOver(),
1142 mpSelected(),
1143 mpDisabled(),
1144 mpMode(),
1145 mbIsOver(false),
1146 mbIsPressed(false),
1147 mbIsSelected(false),
1148 mbIsEnabled(true)
1150 if (mpToolBar.get() != nullptr)
1152 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1153 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1157 void Element::SetModes (
1158 const SharedElementMode& rpNormalMode,
1159 const SharedElementMode& rpMouseOverMode,
1160 const SharedElementMode& rpSelectedMode,
1161 const SharedElementMode& rpDisabledMode)
1163 mpNormal = rpNormalMode;
1164 mpMouseOver = rpMouseOverMode;
1165 mpSelected = rpSelectedMode;
1166 mpDisabled = rpDisabledMode;
1167 mpMode = rpNormalMode;
1170 void Element::disposing()
1174 awt::Size const & Element::GetBoundingSize (
1175 const Reference<rendering::XCanvas>& rxCanvas)
1177 maSize = CreateBoundingSize(rxCanvas);
1178 return maSize;
1181 awt::Rectangle Element::GetBoundingBox() const
1183 return awt::Rectangle(maLocation.X,maLocation.Y, maSize.Width, maSize.Height);
1186 void Element::CurrentSlideHasChanged()
1188 UpdateState();
1191 void Element::SetLocation (const awt::Point& rLocation)
1193 maLocation = rLocation;
1196 void Element::SetSize (const geometry::RealSize2D& rSize)
1198 maSize = awt::Size(sal_Int32(0.5+rSize.Width), sal_Int32(0.5+rSize.Height));
1201 bool Element::SetState (
1202 const bool bIsOver,
1203 const bool bIsPressed)
1205 bool bModified (mbIsOver != bIsOver || mbIsPressed != bIsPressed);
1206 bool bClicked (mbIsPressed && bIsOver && ! bIsPressed);
1208 mbIsOver = bIsOver;
1209 mbIsPressed = bIsPressed;
1211 // When the element is disabled then ignore mouse over or selection.
1212 // When the element is selected then ignore mouse over.
1213 if ( ! mbIsEnabled)
1214 mpMode = mpDisabled;
1215 else if (mbIsSelected)
1216 mpMode = mpSelected;
1217 else if (mbIsOver)
1218 mpMode = mpMouseOver;
1219 else
1220 mpMode = mpNormal;
1222 if (bClicked && mbIsEnabled)
1224 if (mpMode.get() != nullptr)
1228 if (mpMode->msAction.isEmpty())
1229 break;
1231 if (mpToolBar.get() == nullptr)
1232 break;
1234 if (mpToolBar->GetPresenterController().get() == nullptr)
1235 break;
1237 mpToolBar->GetPresenterController()->DispatchUnoCommand(mpMode->msAction);
1238 mpToolBar->RequestLayout();
1240 while (false);
1244 else if (bModified)
1246 Invalidate(true);
1249 return bModified;
1252 void Element::Invalidate (const bool bSynchronous)
1254 OSL_ASSERT(mpToolBar.is());
1255 mpToolBar->InvalidateArea(GetBoundingBox(), bSynchronous);
1258 bool Element::IsOutside (const awt::Rectangle& rBox)
1260 if (rBox.X >= maLocation.X+maSize.Width)
1261 return true;
1262 else if (rBox.Y >= maLocation.Y+maSize.Height)
1263 return true;
1264 else if (maLocation.X >= rBox.X+rBox.Width)
1265 return true;
1266 else if (maLocation.Y >= rBox.Y+rBox.Height)
1267 return true;
1268 else
1269 return false;
1273 bool Element::IsFilling() const
1275 return false;
1278 void Element::UpdateState()
1280 OSL_ASSERT(mpToolBar.get() != nullptr);
1281 OSL_ASSERT(mpToolBar->GetPresenterController().get() != nullptr);
1283 if (mpMode.get() == nullptr)
1284 return;
1286 util::URL aURL (mpToolBar->GetPresenterController()->CreateURLFromString(mpMode->msAction));
1287 Reference<frame::XDispatch> xDispatch (mpToolBar->GetPresenterController()->GetDispatch(aURL));
1288 if (xDispatch.is())
1290 xDispatch->addStatusListener(this, aURL);
1291 xDispatch->removeStatusListener(this, aURL);
1295 //----- lang::XEventListener --------------------------------------------------
1297 void SAL_CALL Element::disposing (const css::lang::EventObject&) {}
1299 //----- document::XEventListener ----------------------------------------------
1301 void SAL_CALL Element::notifyEvent (const css::document::EventObject&)
1303 UpdateState();
1306 //----- frame::XStatusListener ------------------------------------------------
1308 void SAL_CALL Element::statusChanged (const css::frame::FeatureStateEvent& rEvent)
1310 bool bIsSelected (mbIsSelected);
1311 bool bIsEnabled (rEvent.IsEnabled);
1312 rEvent.State >>= bIsSelected;
1314 if (bIsSelected != mbIsSelected || bIsEnabled != mbIsEnabled)
1316 mbIsEnabled = bIsEnabled;
1317 mbIsSelected = bIsSelected;
1318 SetState(mbIsOver, mbIsPressed);
1319 mpToolBar->RequestLayout();
1323 } // end of anonymous namespace
1325 //===== ElementMode ===========================================================
1327 namespace {
1329 ElementMode::ElementMode()
1330 : mpIcon(),
1331 msAction(),
1332 maText()
1336 void ElementMode::ReadElementMode (
1337 const Reference<beans::XPropertySet>& rxElementProperties,
1338 const OUString& rsModeName,
1339 std::shared_ptr<ElementMode> const & rpDefaultMode,
1340 ::sdext::presenter::PresenterToolBar::Context const & rContext)
1344 Reference<container::XHierarchicalNameAccess> xNode (
1345 PresenterConfigurationAccess::GetProperty(rxElementProperties, rsModeName),
1346 UNO_QUERY);
1347 Reference<beans::XPropertySet> xProperties (
1348 PresenterConfigurationAccess::GetNodeProperties(xNode, OUString()));
1349 if (!xProperties.is() && rpDefaultMode != nullptr)
1351 // The mode is not specified. Use the given, possibly empty,
1352 // default mode instead.
1353 mpIcon = rpDefaultMode->mpIcon;
1354 msAction = rpDefaultMode->msAction;
1355 maText = rpDefaultMode->maText;
1358 // Read action.
1359 if ( ! (PresenterConfigurationAccess::GetProperty(xProperties, "Action") >>= msAction))
1360 if (rpDefaultMode != nullptr)
1361 msAction = rpDefaultMode->msAction;
1363 // Read text and font
1364 OUString sText(rpDefaultMode != nullptr ? rpDefaultMode->maText.GetText() : OUString());
1365 PresenterConfigurationAccess::GetProperty(xProperties, "Text") >>= sText;
1366 Reference<container::XHierarchicalNameAccess> xFontNode (
1367 PresenterConfigurationAccess::GetProperty(xProperties, "Font"), UNO_QUERY);
1368 PresenterTheme::SharedFontDescriptor pFont(PresenterTheme::ReadFont(
1369 xFontNode, rpDefaultMode != nullptr ? rpDefaultMode->maText.GetFont()
1370 : PresenterTheme::SharedFontDescriptor()));
1371 maText = Text(sText,pFont);
1373 // Read bitmaps to display as icons.
1374 Reference<container::XHierarchicalNameAccess> xIconNode (
1375 PresenterConfigurationAccess::GetProperty(xProperties, "Icon"), UNO_QUERY);
1376 mpIcon = PresenterBitmapContainer::LoadBitmap(
1377 xIconNode, "", rContext.mxPresenterHelper, rContext.mxCanvas,
1378 rpDefaultMode != nullptr ? rpDefaultMode->mpIcon : SharedBitmapDescriptor());
1380 catch(Exception&)
1382 OSL_ASSERT(false);
1386 } // end of anonymous namespace
1388 //===== Button ================================================================
1390 namespace {
1392 ::rtl::Reference<Element> Button::Create (
1393 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1395 ::rtl::Reference<Button> pElement (new Button(rpToolBar));
1396 pElement->Initialize();
1397 return ::rtl::Reference<Element>(pElement.get());
1400 Button::Button (
1401 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1402 : Element(rpToolBar),
1403 mbIsListenerRegistered(false)
1405 OSL_ASSERT(mpToolBar.get() != nullptr);
1406 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1407 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1410 void Button::Initialize()
1412 mpToolBar->GetPresenterController()->GetWindowManager()->AddLayoutListener(this);
1413 mbIsListenerRegistered = true;
1416 void Button::disposing()
1418 OSL_ASSERT(mpToolBar.get() != nullptr);
1419 if (mpToolBar.get() != nullptr
1420 && mbIsListenerRegistered)
1422 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1423 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1425 mbIsListenerRegistered = false;
1426 mpToolBar->GetPresenterController()->GetWindowManager()->RemoveLayoutListener(this);
1428 Element::disposing();
1431 void Button::Paint (
1432 const Reference<rendering::XCanvas>& rxCanvas,
1433 const rendering::ViewState& rViewState)
1435 OSL_ASSERT(rxCanvas.is());
1437 if (mpMode.get() == nullptr)
1438 return;
1440 if (mpMode->mpIcon.get() == nullptr)
1441 return;
1443 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1444 sal_Int32 nTextHeight (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1446 PaintIcon(rxCanvas, nTextHeight, rViewState);
1447 mpMode->maText.Paint(rxCanvas, rViewState, GetBoundingBox());
1450 awt::Size Button::CreateBoundingSize (
1451 const Reference<rendering::XCanvas>& rxCanvas)
1453 if (mpMode.get() == nullptr)
1454 return awt::Size();
1456 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1457 const sal_Int32 nGap (5);
1458 sal_Int32 nTextHeight (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1459 sal_Int32 nTextWidth (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.X2 - aTextBBox.X1));
1460 Reference<rendering::XBitmap> xBitmap;
1461 if (mpMode->mpIcon.get() != nullptr)
1462 xBitmap = mpMode->mpIcon->GetNormalBitmap();
1463 if (xBitmap.is())
1465 geometry::IntegerSize2D aSize (xBitmap->getSize());
1466 return awt::Size(
1467 ::std::max(aSize.Width, sal_Int32(0.5 + aTextBBox.X2 - aTextBBox.X1)),
1468 aSize.Height+ nGap + nTextHeight);
1470 else
1471 return awt::Size(nTextWidth,nTextHeight);
1474 void Button::PaintIcon (
1475 const Reference<rendering::XCanvas>& rxCanvas,
1476 const sal_Int32 nTextHeight,
1477 const rendering::ViewState& rViewState)
1479 if (mpMode.get() == nullptr)
1480 return;
1482 Reference<rendering::XBitmap> xBitmap (mpMode->mpIcon->GetBitmap(GetMode()));
1483 if (!xBitmap.is())
1484 return;
1486 /// check whether RTL interface or not
1487 if(!AllSettings::GetLayoutRTL()){
1488 const sal_Int32 nX (maLocation.X
1489 + (maSize.Width-xBitmap->getSize().Width) / 2);
1490 const sal_Int32 nY (maLocation.Y
1491 + (maSize.Height - nTextHeight - xBitmap->getSize().Height) / 2);
1492 const rendering::RenderState aRenderState(
1493 geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
1494 nullptr,
1495 Sequence<double>(4),
1496 rendering::CompositeOperation::OVER);
1497 rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState);
1499 else {
1500 const sal_Int32 nX (maLocation.X
1501 + (maSize.Width+xBitmap->getSize().Width) / 2);
1502 const sal_Int32 nY (maLocation.Y
1503 + (maSize.Height - nTextHeight - xBitmap->getSize().Height) / 2);
1504 const rendering::RenderState aRenderState(
1505 geometry::AffineMatrix2D(-1,0,nX, 0,1,nY),
1506 nullptr,
1507 Sequence<double>(4),
1508 rendering::CompositeOperation::OVER);
1509 rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState);
1513 PresenterBitmapDescriptor::Mode Button::GetMode() const
1515 if ( ! IsEnabled())
1516 return PresenterBitmapDescriptor::Disabled;
1517 else if (mbIsPressed)
1518 return PresenterBitmapDescriptor::ButtonDown;
1519 else if (mbIsOver)
1520 return PresenterBitmapDescriptor::MouseOver;
1521 else
1522 return PresenterBitmapDescriptor::Normal;
1525 //----- lang::XEventListener --------------------------------------------------
1527 void SAL_CALL Button::disposing (const css::lang::EventObject& rEvent)
1529 mbIsListenerRegistered = false;
1530 Element::disposing(rEvent);
1533 } // end of anonymous namespace
1535 //===== PresenterToolBar::Label ===============================================
1537 namespace {
1539 Label::Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1540 : Element(rpToolBar)
1544 awt::Size Label::CreateBoundingSize (
1545 const Reference<rendering::XCanvas>& rxCanvas)
1547 if (mpMode.get() == nullptr)
1548 return awt::Size(0,0);
1550 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1551 return awt::Size(
1552 sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.X2 - aTextBBox.X1),
1553 sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1556 void Label::SetText (const OUString& rsText)
1558 OSL_ASSERT(mpToolBar.get() != nullptr);
1559 if (mpMode.get() == nullptr)
1560 return;
1562 const bool bRequestLayout (mpMode->maText.GetText().getLength() != rsText.getLength());
1564 mpMode->maText.SetText(rsText);
1565 // Just use the character count for determining whether a layout is
1566 // necessary. This is an optimization to avoid layouts every time a new
1567 // time value is set on some labels.
1568 if (bRequestLayout)
1569 mpToolBar->RequestLayout();
1570 else
1571 Invalidate(false);
1574 void Label::Paint (
1575 const Reference<rendering::XCanvas>& rxCanvas,
1576 const rendering::ViewState& rViewState)
1578 OSL_ASSERT(rxCanvas.is());
1579 if (mpMode.get() == nullptr)
1580 return;
1582 mpMode->maText.Paint(rxCanvas, rViewState, GetBoundingBox());
1585 bool Label::SetState (const bool, const bool)
1587 // For labels there is no mouse over effect.
1588 return Element::SetState(false, false);
1591 } // end of anonymous namespace
1593 //===== Text ==================================================================
1595 namespace {
1597 Text::Text()
1598 : msText(),
1599 mpFont()
1603 Text::Text (
1604 const OUString& rsText,
1605 const PresenterTheme::SharedFontDescriptor& rpFont)
1606 : msText(rsText),
1607 mpFont(rpFont)
1611 void Text::SetText (const OUString& rsText)
1613 msText = rsText;
1616 const OUString& Text::GetText() const
1618 return msText;
1621 const PresenterTheme::SharedFontDescriptor& Text::GetFont() const
1623 return mpFont;
1626 void Text::Paint (
1627 const Reference<rendering::XCanvas>& rxCanvas,
1628 const rendering::ViewState& rViewState,
1629 const awt::Rectangle& rBoundingBox)
1631 OSL_ASSERT(rxCanvas.is());
1633 if (msText.isEmpty())
1634 return;
1635 if (mpFont.get() == nullptr)
1636 return;
1638 if ( ! mpFont->mxFont.is())
1639 mpFont->PrepareFont(rxCanvas);
1640 if ( ! mpFont->mxFont.is())
1641 return;
1643 rendering::StringContext aContext (msText, 0, msText.getLength());
1645 Reference<rendering::XTextLayout> xLayout (
1646 mpFont->mxFont->createTextLayout(
1647 aContext,
1648 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1649 0));
1650 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1651 const double nTextWidth = aBox.X2 - aBox.X1;
1652 const double nY = rBoundingBox.Y + rBoundingBox.Height - aBox.Y2;
1653 const double nX = rBoundingBox.X + (rBoundingBox.Width - nTextWidth)/2;
1655 rendering::RenderState aRenderState(
1656 geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
1657 nullptr,
1658 Sequence<double>(4),
1659 rendering::CompositeOperation::SOURCE);
1660 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1661 rxCanvas->drawTextLayout(
1662 xLayout,
1663 rViewState,
1664 aRenderState);
1667 geometry::RealRectangle2D Text::GetBoundingBox (const Reference<rendering::XCanvas>& rxCanvas)
1669 if (mpFont.get() != nullptr && !msText.isEmpty())
1671 if ( ! mpFont->mxFont.is())
1672 mpFont->PrepareFont(rxCanvas);
1673 if (mpFont->mxFont.is())
1675 rendering::StringContext aContext (msText, 0, msText.getLength());
1676 Reference<rendering::XTextLayout> xLayout (
1677 mpFont->mxFont->createTextLayout(
1678 aContext,
1679 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1680 0));
1681 return xLayout->queryTextBounds();
1684 return geometry::RealRectangle2D(0,0,0,0);
1687 //===== TimeFormatter =========================================================
1689 OUString TimeFormatter::FormatTime (const oslDateTime& rTime)
1691 OUStringBuffer sText;
1693 const sal_Int32 nHours (sal::static_int_cast<sal_Int32>(rTime.Hours));
1694 const sal_Int32 nMinutes (sal::static_int_cast<sal_Int32>(rTime.Minutes));
1695 const sal_Int32 nSeconds(sal::static_int_cast<sal_Int32>(rTime.Seconds));
1696 // Hours
1697 sText.append(OUString::number(nHours));
1699 sText.append(":");
1701 // Minutes
1702 const OUString sMinutes (OUString::number(nMinutes));
1703 if (sMinutes.getLength() == 1)
1704 sText.append("0");
1705 sText.append(sMinutes);
1707 // Seconds
1708 sText.append(":");
1709 const OUString sSeconds (OUString::number(nSeconds));
1710 if (sSeconds.getLength() == 1)
1711 sText.append("0");
1712 sText.append(sSeconds);
1713 return sText.makeStringAndClear();
1716 //===== TimeLabel =============================================================
1718 TimeLabel::TimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1719 : Label(rpToolBar),
1720 mpListener()
1724 void SAL_CALL TimeLabel::disposing()
1726 PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->RemoveListener(mpListener);
1727 mpListener.reset();
1730 void TimeLabel::ConnectToTimer()
1732 mpListener.reset(new Listener(this));
1733 PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->AddListener(mpListener);
1736 //===== CurrentTimeLabel ======================================================
1738 ::rtl::Reference<Element> CurrentTimeLabel::Create (
1739 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1741 ::rtl::Reference<TimeLabel> pElement(new CurrentTimeLabel(rpToolBar));
1742 pElement->ConnectToTimer();
1743 return ::rtl::Reference<Element>(pElement.get());
1746 CurrentTimeLabel::~CurrentTimeLabel()
1750 CurrentTimeLabel::CurrentTimeLabel (
1751 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1752 : TimeLabel(rpToolBar)
1756 void CurrentTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1758 SetText(TimeFormatter::FormatTime(rCurrentTime));
1759 Invalidate(false);
1762 void CurrentTimeLabel::SetModes (
1763 const SharedElementMode& rpNormalMode,
1764 const SharedElementMode& rpMouseOverMode,
1765 const SharedElementMode& rpSelectedMode,
1766 const SharedElementMode& rpDisabledMode)
1768 TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode);
1769 SetText(TimeFormatter::FormatTime(PresenterClockTimer::GetCurrentTime()));
1772 //===== PresentationTimeLabel =================================================
1774 ::rtl::Reference<Element> PresentationTimeLabel::Create (
1775 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1777 ::rtl::Reference<TimeLabel> pElement(new PresentationTimeLabel(rpToolBar));
1778 pElement->ConnectToTimer();
1779 return ::rtl::Reference<Element>(pElement.get());
1782 PresentationTimeLabel::~PresentationTimeLabel()
1784 mpToolBar->GetPresenterController()->SetPresentationTime(nullptr);
1787 PresentationTimeLabel::PresentationTimeLabel (
1788 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1789 : TimeLabel(rpToolBar),
1790 maStartTimeValue()
1792 restart();
1793 mpToolBar->GetPresenterController()->SetPresentationTime(this);
1796 void PresentationTimeLabel::restart()
1798 maStartTimeValue.Seconds = 0;
1799 maStartTimeValue.Nanosec = 0;
1802 void PresentationTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1804 TimeValue aCurrentTimeValue;
1805 if (!osl_getTimeValueFromDateTime(&rCurrentTime, &aCurrentTimeValue))
1806 return;
1808 if (maStartTimeValue.Seconds==0 && maStartTimeValue.Nanosec==0)
1810 // This method is called for the first time. Initialize the
1811 // start time. The start time is rounded to nearest second to
1812 // keep the time updates synchronized with the current time label.
1813 maStartTimeValue = aCurrentTimeValue;
1814 if (maStartTimeValue.Nanosec >= 500000000)
1815 maStartTimeValue.Seconds += 1;
1816 maStartTimeValue.Nanosec = 0;
1819 TimeValue aElapsedTimeValue;
1820 aElapsedTimeValue.Seconds = aCurrentTimeValue.Seconds - maStartTimeValue.Seconds;
1821 aElapsedTimeValue.Nanosec = aCurrentTimeValue.Nanosec - maStartTimeValue.Nanosec;
1823 oslDateTime aElapsedDateTime;
1824 if (osl_getDateTimeFromTimeValue(&aElapsedTimeValue, &aElapsedDateTime))
1826 SetText(TimeFormatter::FormatTime(aElapsedDateTime));
1827 Invalidate(false);
1831 void PresentationTimeLabel::SetModes (
1832 const SharedElementMode& rpNormalMode,
1833 const SharedElementMode& rpMouseOverMode,
1834 const SharedElementMode& rpSelectedMode,
1835 const SharedElementMode& rpDisabledMode)
1837 TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode);
1839 oslDateTime aStartDateTime;
1840 if (osl_getDateTimeFromTimeValue(&maStartTimeValue, &aStartDateTime))
1842 SetText(TimeFormatter::FormatTime(aStartDateTime));
1846 //===== VerticalSeparator =====================================================
1848 VerticalSeparator::VerticalSeparator (
1849 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1850 : Element(rpToolBar)
1854 void VerticalSeparator::Paint (
1855 const Reference<rendering::XCanvas>& rxCanvas,
1856 const rendering::ViewState& rViewState)
1858 OSL_ASSERT(rxCanvas.is());
1860 awt::Rectangle aBBox (GetBoundingBox());
1862 rendering::RenderState aRenderState(
1863 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1864 nullptr,
1865 Sequence<double>(4),
1866 rendering::CompositeOperation::OVER);
1867 if (mpMode.get() != nullptr)
1869 PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1870 if (pFont.get() != nullptr)
1871 PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1874 rxCanvas->fillPolyPolygon(
1875 PresenterGeometryHelper::CreatePolygon(aBBox, rxCanvas->getDevice()),
1876 rViewState,
1877 aRenderState);
1880 awt::Size VerticalSeparator::CreateBoundingSize (
1881 const Reference<rendering::XCanvas>&)
1883 return awt::Size(1,20);
1886 bool VerticalSeparator::IsFilling() const
1888 return true;
1891 //===== HorizontalSeparator ===================================================
1893 HorizontalSeparator::HorizontalSeparator (
1894 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1895 : Element(rpToolBar)
1899 void HorizontalSeparator::Paint (
1900 const Reference<rendering::XCanvas>& rxCanvas,
1901 const rendering::ViewState& rViewState)
1903 OSL_ASSERT(rxCanvas.is());
1905 awt::Rectangle aBBox (GetBoundingBox());
1907 rendering::RenderState aRenderState(
1908 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1909 nullptr,
1910 Sequence<double>(4),
1911 rendering::CompositeOperation::OVER);
1912 if (mpMode.get() != nullptr)
1914 PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1915 if (pFont.get() != nullptr)
1916 PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1919 rxCanvas->fillPolyPolygon(
1920 PresenterGeometryHelper::CreatePolygon(aBBox, rxCanvas->getDevice()),
1921 rViewState,
1922 aRenderState);
1925 awt::Size HorizontalSeparator::CreateBoundingSize (
1926 const Reference<rendering::XCanvas>&)
1928 return awt::Size(20,1);
1931 bool HorizontalSeparator::IsFilling() const
1933 return true;
1936 } // end of anonymous namespace
1938 } } // end of namespace ::sdext::presenter
1940 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */