vcl: allow for overriding the default PDF rendering resolution
[LibreOffice.git] / sdext / source / presenter / PresenterToolBar.cxx
blobc62448e0521a1e5944e59f2a3c9723fca222c043
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/settings.hxx>
21 #include "PresenterToolBar.hxx"
23 #include "PresenterBitmapContainer.hxx"
24 #include "PresenterCanvasHelper.hxx"
25 #include "PresenterGeometryHelper.hxx"
26 #include "PresenterPaintManager.hxx"
27 #include "PresenterTimer.hxx"
28 #include "PresenterWindowManager.hxx"
30 #include <cppuhelper/compbase.hxx>
31 #include <com/sun/star/awt/XWindowPeer.hpp>
32 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
33 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
34 #include <com/sun/star/drawing/framework/XPane.hpp>
35 #include <com/sun/star/geometry/AffineMatrix2D.hpp>
36 #include <com/sun/star/rendering/CompositeOperation.hpp>
37 #include <com/sun/star/rendering/RenderState.hpp>
38 #include <com/sun/star/rendering/TextDirection.hpp>
39 #include <com/sun/star/rendering/ViewState.hpp>
40 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
41 #include <com/sun/star/util/Color.hpp>
42 #include <rtl/ustrbuf.hxx>
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::drawing::framework;
48 namespace sdext { namespace presenter {
50 static const sal_Int32 gnGapSize (20);
52 namespace {
54 class Text
56 public:
57 Text();
58 Text (
59 const OUString& rsText,
60 const PresenterTheme::SharedFontDescriptor& rpFont);
62 void SetText (const OUString& rsText);
63 const OUString& GetText() const;
64 const PresenterTheme::SharedFontDescriptor& GetFont() const;
66 void Paint (
67 const Reference<rendering::XCanvas>& rxCanvas,
68 const rendering::ViewState& rViewState,
69 const awt::Rectangle& rBoundingBox);
71 geometry::RealRectangle2D GetBoundingBox (
72 const Reference<rendering::XCanvas>& rxCanvas);
74 private:
75 OUString msText;
76 PresenterTheme::SharedFontDescriptor mpFont;
79 class ElementMode
81 public:
82 ElementMode();
83 ElementMode(const ElementMode&) = delete;
84 ElementMode& operator=(const ElementMode&) = delete;
86 SharedBitmapDescriptor mpIcon;
87 OUString msAction;
88 Text maText;
90 void ReadElementMode (
91 const Reference<beans::XPropertySet>& rxProperties,
92 const OUString& rsModeName,
93 std::shared_ptr<ElementMode> const & rpDefaultMode,
94 ::sdext::presenter::PresenterToolBar::Context const & rContext);
96 typedef std::shared_ptr<ElementMode> SharedElementMode;
98 } // end of anonymous namespace
100 class PresenterToolBar::Context
102 public:
103 Context() = default;
104 Context(const Context&) = delete;
105 Context& operator=(const Context&) = delete;
106 Reference<drawing::XPresenterHelper> mxPresenterHelper;
107 css::uno::Reference<css::rendering::XCanvas> mxCanvas;
110 //===== PresenterToolBar::Element =============================================
112 namespace {
113 typedef cppu::WeakComponentImplHelper<
114 css::document::XEventListener,
115 css::frame::XStatusListener
116 > ElementInterfaceBase;
118 class Element
119 : private ::cppu::BaseMutex,
120 public ElementInterfaceBase
122 public:
123 explicit Element (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
124 Element(const Element&) = delete;
125 Element& operator=(const Element&) = delete;
127 virtual void SAL_CALL disposing() override;
129 virtual void SetModes (
130 const SharedElementMode& rpNormalMode,
131 const SharedElementMode& rpMouseOverMode,
132 const SharedElementMode& rpSelectedMode,
133 const SharedElementMode& rpDisabledMode);
134 void CurrentSlideHasChanged();
135 void SetLocation (const awt::Point& rLocation);
136 void SetSize (const geometry::RealSize2D& rSize);
137 virtual void Paint (
138 const Reference<rendering::XCanvas>& rxCanvas,
139 const rendering::ViewState& rViewState) = 0;
140 awt::Size const & GetBoundingSize (
141 const Reference<rendering::XCanvas>& rxCanvas);
142 awt::Rectangle GetBoundingBox() const;
143 virtual bool SetState (const bool bIsOver, const bool bIsPressed);
144 void Invalidate (const bool bSynchronous);
145 bool IsOutside (const awt::Rectangle& rBox);
146 virtual bool IsFilling() const;
147 void UpdateState();
149 // lang::XEventListener
151 virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
153 // document::XEventListener
155 virtual void SAL_CALL notifyEvent (const css::document::EventObject& rEvent) override;
157 // frame::XStatusListener
159 virtual void SAL_CALL statusChanged (const css::frame::FeatureStateEvent& rEvent) override;
161 protected:
162 ::rtl::Reference<PresenterToolBar> mpToolBar;
163 awt::Point maLocation;
164 awt::Size maSize;
165 SharedElementMode mpNormal;
166 SharedElementMode mpMouseOver;
167 SharedElementMode mpSelected;
168 SharedElementMode mpDisabled;
169 SharedElementMode mpMode;
170 bool mbIsOver;
171 bool mbIsPressed;
172 bool mbIsSelected;
174 virtual awt::Size CreateBoundingSize (
175 const Reference<rendering::XCanvas>& rxCanvas) = 0;
177 bool IsEnabled() const { return mbIsEnabled;}
178 private:
179 bool mbIsEnabled;
182 } // end of anonymous namespace
184 class PresenterToolBar::ElementContainerPart
185 : public ::std::vector<rtl::Reference<Element> >
189 //===== Button ================================================================
191 namespace {
193 class Button : public Element
195 public:
196 static ::rtl::Reference<Element> Create (
197 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
199 virtual void SAL_CALL disposing() override;
201 virtual void Paint (
202 const Reference<rendering::XCanvas>& rxCanvas,
203 const rendering::ViewState& rViewState) override;
205 // lang::XEventListener
207 virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
209 protected:
210 virtual awt::Size CreateBoundingSize (
211 const Reference<rendering::XCanvas>& rxCanvas) override;
213 private:
214 bool mbIsListenerRegistered;
216 Button (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
217 void Initialize();
218 void PaintIcon (
219 const Reference<rendering::XCanvas>& rxCanvas,
220 const sal_Int32 nTextHeight,
221 const rendering::ViewState& rViewState);
222 PresenterBitmapDescriptor::Mode GetMode() const;
225 //===== Label =================================================================
227 class Label : public Element
229 public:
230 explicit Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
232 void SetText (const OUString& rsText);
233 virtual void Paint (
234 const Reference<rendering::XCanvas>& rxCanvas,
235 const rendering::ViewState& rViewState) override;
236 virtual bool SetState (const bool bIsOver, const bool bIsPressed) override;
238 protected:
239 virtual awt::Size CreateBoundingSize (
240 const Reference<rendering::XCanvas>& rxCanvas) override;
243 // Some specialized controls.
245 class TimeFormatter
247 public:
248 static OUString FormatTime (const oslDateTime& rTime);
251 class TimeLabel : public Label
253 public:
254 void ConnectToTimer();
255 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) = 0;
256 protected:
257 explicit TimeLabel(const ::rtl::Reference<PresenterToolBar>& rpToolBar);
258 using Element::disposing;
259 virtual void SAL_CALL disposing() override;
260 private:
261 class Listener : public PresenterClockTimer::Listener
263 public:
264 explicit Listener (const ::rtl::Reference<TimeLabel>& rxLabel)
265 : mxLabel(rxLabel) {}
266 virtual ~Listener() {}
267 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override
268 { if (mxLabel.is()) mxLabel->TimeHasChanged(rCurrentTime); }
269 private:
270 ::rtl::Reference<TimeLabel> mxLabel;
272 std::shared_ptr<PresenterClockTimer::Listener> mpListener;
275 class CurrentTimeLabel : public TimeLabel
277 public:
278 static ::rtl::Reference<Element> Create (
279 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
280 virtual void SetModes (
281 const SharedElementMode& rpNormalMode,
282 const SharedElementMode& rpMouseOverMode,
283 const SharedElementMode& rpSelectedMode,
284 const SharedElementMode& rpDisabledMode) override;
285 private:
286 CurrentTimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
287 virtual ~CurrentTimeLabel() override;
288 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
291 class PresentationTimeLabel : public TimeLabel, public IPresentationTime
293 public:
294 static ::rtl::Reference<Element> Create (
295 const ::rtl::Reference<PresenterToolBar>& rpToolBar);
296 virtual void SetModes (
297 const SharedElementMode& rpNormalMode,
298 const SharedElementMode& rpMouseOverMode,
299 const SharedElementMode& rpSelectedMode,
300 const SharedElementMode& rpDisabledMode) override;
301 virtual void restart() override;
302 private:
303 TimeValue maStartTimeValue;
304 PresentationTimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
305 virtual ~PresentationTimeLabel() override;
306 virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
309 class VerticalSeparator : public Element
311 public:
312 explicit VerticalSeparator (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
313 virtual void Paint (
314 const Reference<rendering::XCanvas>& rxCanvas,
315 const rendering::ViewState& rViewState) override;
316 virtual bool IsFilling() const override;
318 protected:
319 virtual awt::Size CreateBoundingSize (
320 const Reference<rendering::XCanvas>& rxCanvas) override;
323 class HorizontalSeparator : public Element
325 public:
326 explicit HorizontalSeparator (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
327 virtual void Paint (
328 const Reference<rendering::XCanvas>& rxCanvas,
329 const rendering::ViewState& rViewState) override;
330 virtual bool IsFilling() const override;
332 protected:
333 virtual awt::Size CreateBoundingSize (
334 const Reference<rendering::XCanvas>& rxCanvas) override;
336 } // end of anonymous namespace
338 //===== PresenterToolBar ======================================================
340 PresenterToolBar::PresenterToolBar (
341 const Reference<XComponentContext>& rxContext,
342 const css::uno::Reference<css::awt::XWindow>& rxWindow,
343 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
344 const ::rtl::Reference<PresenterController>& rpPresenterController,
345 const Anchor eAnchor)
346 : PresenterToolBarInterfaceBase(m_aMutex),
347 mxComponentContext(rxContext),
348 maElementContainer(),
349 mpCurrentContainerPart(),
350 mxWindow(rxWindow),
351 mxCanvas(rxCanvas),
352 mxSlideShowController(),
353 mxCurrentSlide(),
354 mpPresenterController(rpPresenterController),
355 mbIsLayoutPending(false),
356 meAnchor(eAnchor),
357 maMinimalSize()
361 void PresenterToolBar::Initialize (
362 const OUString& rsConfigurationPath)
366 CreateControls(rsConfigurationPath);
368 if (mxWindow.is())
370 mxWindow->addWindowListener(this);
371 mxWindow->addPaintListener(this);
372 mxWindow->addMouseListener(this);
373 mxWindow->addMouseMotionListener(this);
375 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
376 if (xPeer.is())
377 xPeer->setBackground(util::Color(0xff000000));
379 mxWindow->setVisible(true);
382 mxSlideShowController = mpPresenterController->GetSlideShowController();
383 UpdateSlideNumber();
384 mbIsLayoutPending = true;
386 catch (RuntimeException&)
388 mpCurrentContainerPart.reset();
389 maElementContainer.clear();
390 throw;
394 PresenterToolBar::~PresenterToolBar()
398 void SAL_CALL PresenterToolBar::disposing()
400 if (mxWindow.is())
402 mxWindow->removeWindowListener(this);
403 mxWindow->removePaintListener(this);
404 mxWindow->removeMouseListener(this);
405 mxWindow->removeMouseMotionListener(this);
406 mxWindow = nullptr;
409 // Dispose tool bar elements.
410 for (const auto& rxPart : maElementContainer)
412 OSL_ASSERT(rxPart != nullptr);
413 for (rtl::Reference<Element>& pElement : *rxPart)
415 if (pElement.get() != nullptr)
417 Reference<lang::XComponent> xComponent (
418 static_cast<XWeak*>(pElement.get()), UNO_QUERY);
419 if (xComponent.is())
420 xComponent->dispose();
425 mpCurrentContainerPart.reset();
426 maElementContainer.clear();
429 void PresenterToolBar::InvalidateArea (
430 const awt::Rectangle& rRepaintBox,
431 const bool bSynchronous)
433 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
434 if (!xManager)
435 return;
436 xManager->Invalidate(
437 mxWindow,
438 rRepaintBox,
439 bSynchronous);
442 void PresenterToolBar::RequestLayout()
444 mbIsLayoutPending = true;
446 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
447 if (!xManager)
448 return;
450 xManager->Invalidate(mxWindow);
453 geometry::RealSize2D const & PresenterToolBar::GetMinimalSize()
455 if (mbIsLayoutPending)
456 Layout(mxCanvas);
457 return maMinimalSize;
460 const ::rtl::Reference<PresenterController>& PresenterToolBar::GetPresenterController() const
462 return mpPresenterController;
465 const Reference<XComponentContext>& PresenterToolBar::GetComponentContext() const
467 return mxComponentContext;
470 //----- lang::XEventListener -------------------------------------------------
472 void SAL_CALL PresenterToolBar::disposing (const lang::EventObject& rEventObject)
474 if (rEventObject.Source == mxWindow)
475 mxWindow = nullptr;
478 //----- XWindowListener -------------------------------------------------------
480 void SAL_CALL PresenterToolBar::windowResized (const awt::WindowEvent&)
482 mbIsLayoutPending = true;
485 void SAL_CALL PresenterToolBar::windowMoved (const awt::WindowEvent&) {}
487 void SAL_CALL PresenterToolBar::windowShown (const lang::EventObject&)
489 mbIsLayoutPending = true;
492 void SAL_CALL PresenterToolBar::windowHidden (const lang::EventObject&) {}
494 //----- XPaintListener --------------------------------------------------------
495 void SAL_CALL PresenterToolBar::windowPaint (const css::awt::PaintEvent& rEvent)
497 if ( ! mxCanvas.is())
498 return;
500 if ( ! mbIsPresenterViewActive)
501 return;
503 const rendering::ViewState aViewState (
504 geometry::AffineMatrix2D(1,0,0, 0,1,0),
505 PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice()));
507 if (mbIsLayoutPending)
508 Layout(mxCanvas);
510 Paint(rEvent.UpdateRect, aViewState);
512 // Make the back buffer visible.
513 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
514 if (xSpriteCanvas.is())
515 xSpriteCanvas->updateScreen(false);
518 //----- XMouseListener --------------------------------------------------------
519 void SAL_CALL PresenterToolBar::mousePressed (const css::awt::MouseEvent& rEvent)
521 ThrowIfDisposed();
522 CheckMouseOver(rEvent, true, true);
525 void SAL_CALL PresenterToolBar::mouseReleased (const css::awt::MouseEvent& rEvent)
527 ThrowIfDisposed();
528 CheckMouseOver(rEvent, true);
531 void SAL_CALL PresenterToolBar::mouseEntered (const css::awt::MouseEvent& rEvent)
533 ThrowIfDisposed();
534 CheckMouseOver(rEvent, true);
537 void SAL_CALL PresenterToolBar::mouseExited (const css::awt::MouseEvent& rEvent)
539 ThrowIfDisposed();
540 CheckMouseOver(rEvent, false);
543 //----- XMouseMotionListener --------------------------------------------------
545 void SAL_CALL PresenterToolBar::mouseMoved (const css::awt::MouseEvent& rEvent)
547 ThrowIfDisposed();
548 CheckMouseOver(rEvent, true);
551 void SAL_CALL PresenterToolBar::mouseDragged (const css::awt::MouseEvent&)
553 ThrowIfDisposed();
556 //----- XDrawView -------------------------------------------------------------
558 void SAL_CALL PresenterToolBar::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
560 if (rxSlide != mxCurrentSlide)
562 mxCurrentSlide = rxSlide;
563 UpdateSlideNumber();
567 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBar::getCurrentPage()
569 return mxCurrentSlide;
573 void PresenterToolBar::CreateControls (
574 const OUString& rsConfigurationPath)
576 if ( ! mxWindow.is())
577 return;
579 // Expand the macro in the bitmap file names.
580 PresenterConfigurationAccess aConfiguration (
581 mxComponentContext,
582 "/org.openoffice.Office.PresenterScreen/",
583 PresenterConfigurationAccess::READ_ONLY);
585 mpCurrentContainerPart.reset(new ElementContainerPart);
586 maElementContainer.clear();
587 maElementContainer.push_back(mpCurrentContainerPart);
589 Reference<container::XHierarchicalNameAccess> xToolBarNode (
590 aConfiguration.GetConfigurationNode(rsConfigurationPath),
591 UNO_QUERY);
592 if (!xToolBarNode.is())
593 return;
595 Reference<container::XNameAccess> xEntries (
596 PresenterConfigurationAccess::GetConfigurationNode(xToolBarNode, "Entries"),
597 UNO_QUERY);
598 Context aContext;
599 aContext.mxPresenterHelper = mpPresenterController->GetPresenterHelper();
600 aContext.mxCanvas = mxCanvas;
601 if (xEntries.is()
602 && aContext.mxPresenterHelper.is()
603 && aContext.mxCanvas.is())
605 PresenterConfigurationAccess::ForAll(
606 xEntries,
607 [this, &aContext] (OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
609 return this->ProcessEntry(xProps, aContext);
614 void PresenterToolBar::ProcessEntry (
615 const Reference<beans::XPropertySet>& rxProperties,
616 Context const & rContext)
618 if ( ! rxProperties.is())
619 return;
621 // Type has to be present.
622 OUString sType;
623 if ( ! (PresenterConfigurationAccess::GetProperty(rxProperties, "Type") >>= sType))
624 return;
626 // Read mode specific values.
627 SharedElementMode pNormalMode (new ElementMode());
628 SharedElementMode pMouseOverMode (new ElementMode());
629 SharedElementMode pSelectedMode (new ElementMode());
630 SharedElementMode pDisabledMode (new ElementMode());
631 pNormalMode->ReadElementMode(rxProperties, "Normal", pNormalMode, rContext);
632 pMouseOverMode->ReadElementMode(rxProperties, "MouseOver", pNormalMode, rContext);
633 pSelectedMode->ReadElementMode(rxProperties, "Selected", pNormalMode, rContext);
634 pDisabledMode->ReadElementMode(rxProperties, "Disabled", pNormalMode, rContext);
636 // Create new element.
637 ::rtl::Reference<Element> pElement;
638 if ( sType == "Button" )
639 pElement = Button::Create(this);
640 else if ( sType == "CurrentTimeLabel" )
641 pElement = CurrentTimeLabel::Create(this);
642 else if ( sType == "PresentationTimeLabel" )
643 pElement = PresentationTimeLabel::Create(this);
644 else if ( sType == "VerticalSeparator" )
645 pElement.set(new VerticalSeparator(this));
646 else if ( sType == "HorizontalSeparator" )
647 pElement.set(new HorizontalSeparator(this));
648 else if ( sType == "Label" )
649 pElement.set(new Label(this));
650 else if ( sType == "ChangeOrientation" )
652 mpCurrentContainerPart.reset(new ElementContainerPart);
653 maElementContainer.push_back(mpCurrentContainerPart);
654 return;
656 if (pElement.is())
658 pElement->SetModes( pNormalMode, pMouseOverMode, pSelectedMode, pDisabledMode);
659 pElement->UpdateState();
660 if (mpCurrentContainerPart.get() != nullptr)
661 mpCurrentContainerPart->push_back(pElement);
665 void PresenterToolBar::Layout (
666 const Reference<rendering::XCanvas>& rxCanvas)
668 if (maElementContainer.empty())
669 return;
671 mbIsLayoutPending = false;
673 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
674 ::std::vector<geometry::RealSize2D> aPartSizes (maElementContainer.size());
675 geometry::RealSize2D aTotalSize (0,0);
676 bool bIsHorizontal (true);
677 sal_Int32 nIndex (0);
678 double nTotalHorizontalGap (0);
679 sal_Int32 nGapCount (0);
680 for (const auto& rxPart : maElementContainer)
682 geometry::RealSize2D aSize (CalculatePartSize(rxCanvas, rxPart, bIsHorizontal));
684 // Remember the size of each part for later.
685 aPartSizes[nIndex] = aSize;
687 // Add gaps between elements.
688 if (rxPart->size()>1 && bIsHorizontal)
690 nTotalHorizontalGap += (rxPart->size() - 1) * gnGapSize;
691 nGapCount += rxPart->size() - 1;
694 // Orientation changes for each part.
695 bIsHorizontal = !bIsHorizontal;
696 // Width is accumulated.
697 aTotalSize.Width += aSize.Width;
698 // Height is the maximum height of all parts.
699 aTotalSize.Height = ::std::max(aTotalSize.Height, aSize.Height);
700 ++nIndex;
702 // Add gaps between parts.
703 if (maElementContainer.size() > 1)
705 nTotalHorizontalGap += (maElementContainer.size() - 1) * gnGapSize;
706 nGapCount += maElementContainer.size()-1;
709 // Calculate the minimal size so that the window size of the tool bar
710 // can be adapted accordingly.
711 maMinimalSize = aTotalSize;
712 maMinimalSize.Width += nTotalHorizontalGap;
714 // Calculate the gaps between elements.
715 double nGapWidth (0);
716 if (nGapCount > 0)
718 if (aTotalSize.Width + nTotalHorizontalGap > aWindowBox.Width)
719 nTotalHorizontalGap = aWindowBox.Width - aTotalSize.Width;
720 nGapWidth = nTotalHorizontalGap / nGapCount;
723 // Determine the location of the left edge.
724 double nX (0);
725 switch (meAnchor)
727 case Left : nX = 0; break;
728 case Center: nX = (aWindowBox.Width - aTotalSize.Width - nTotalHorizontalGap) / 2; break;
731 // Place the parts.
732 double nY ((aWindowBox.Height - aTotalSize.Height) / 2);
733 bIsHorizontal = true;
735 /* push front or back ? ... */
736 /// check whether RTL interface or not
737 if(!AllSettings::GetLayoutRTL()){
738 nIndex = 0;
739 for (const auto& rxPart : maElementContainer)
741 geometry::RealRectangle2D aBoundingBox(
742 nX, nY,
743 nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height);
745 // Add space for gaps between elements.
746 if (rxPart->size() > 1 && bIsHorizontal)
747 aBoundingBox.X2 += (rxPart->size() - 1) * nGapWidth;
749 LayoutPart(rxCanvas, rxPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal);
750 bIsHorizontal = !bIsHorizontal;
751 nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth;
752 ++nIndex;
755 else {
756 ElementContainer::iterator iPart;
757 ElementContainer::iterator iBegin (maElementContainer.begin());
758 for (iPart=maElementContainer.end()-1, nIndex=2; iPart!=iBegin-1; --iPart, --nIndex)
760 geometry::RealRectangle2D aBoundingBox(
761 nX, nY,
762 nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height);
764 // Add space for gaps between elements.
765 if ((*iPart)->size() > 1)
766 if (bIsHorizontal)
767 aBoundingBox.X2 += ((*iPart)->size()-1) * nGapWidth;
769 LayoutPart(rxCanvas, *iPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal);
770 bIsHorizontal = !bIsHorizontal;
771 nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth;
775 // The whole window has to be repainted.
776 std::shared_ptr<PresenterPaintManager> xManager(mpPresenterController->GetPaintManager());
777 if (!xManager)
778 return;
779 xManager->Invalidate(mxWindow);
782 geometry::RealSize2D PresenterToolBar::CalculatePartSize (
783 const Reference<rendering::XCanvas>& rxCanvas,
784 const SharedElementContainerPart& rpPart,
785 const bool bIsHorizontal)
787 geometry::RealSize2D aTotalSize (0,0);
789 if (mxWindow.is())
791 // Calculate the summed width of all elements.
792 for (const auto& rxElement : *rpPart)
794 if (rxElement.get() == nullptr)
795 continue;
797 const awt::Size aBSize (rxElement->GetBoundingSize(rxCanvas));
798 if (bIsHorizontal)
800 aTotalSize.Width += aBSize.Width;
801 if (aBSize.Height > aTotalSize.Height)
802 aTotalSize.Height = aBSize.Height;
804 else
806 aTotalSize.Height += aBSize.Height;
807 if (aBSize.Width > aTotalSize.Width)
808 aTotalSize.Width = aBSize.Width;
812 return aTotalSize;
815 void PresenterToolBar::LayoutPart (
816 const Reference<rendering::XCanvas>& rxCanvas,
817 const SharedElementContainerPart& rpPart,
818 const geometry::RealRectangle2D& rBoundingBox,
819 const geometry::RealSize2D& rPartSize,
820 const bool bIsHorizontal)
822 double nGap (0);
823 if (rpPart->size() > 1)
825 if (bIsHorizontal)
826 nGap = (rBoundingBox.X2 - rBoundingBox.X1 - rPartSize.Width) / (rpPart->size()-1);
827 else
828 nGap = (rBoundingBox.Y2 - rBoundingBox.Y1 - rPartSize.Height) / (rpPart->size()-1);
831 // Place the elements.
832 double nX (rBoundingBox.X1);
833 double nY (rBoundingBox.Y1);
835 /// check whether RTL interface or not
836 if(!AllSettings::GetLayoutRTL()){
837 for (auto& rxElement : *rpPart)
839 if (rxElement.get() == nullptr)
840 continue;
842 const awt::Size aElementSize (rxElement->GetBoundingSize(rxCanvas));
843 if (bIsHorizontal)
845 if (rxElement->IsFilling())
847 nY = rBoundingBox.Y1;
848 rxElement->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
850 else
851 nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
852 rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
853 nX += aElementSize.Width + nGap;
855 else
857 if (rxElement->IsFilling())
859 nX = rBoundingBox.X1;
860 rxElement->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aElementSize.Height));
862 else
863 nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aElementSize.Width) / 2;
864 rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
865 nY += aElementSize.Height + nGap;
869 else {
870 ElementContainerPart::const_iterator iElement;
871 ElementContainerPart::const_iterator iEnd (rpPart->end());
872 ElementContainerPart::const_iterator iBegin (rpPart->begin());
874 for (iElement=rpPart->end()-1; iElement!=iBegin-1; --iElement)
876 if (iElement->get() == nullptr)
877 continue;
879 const awt::Size aElementSize ((*iElement)->GetBoundingSize(rxCanvas));
880 if (bIsHorizontal)
882 if ((*iElement)->IsFilling())
884 nY = rBoundingBox.Y1;
885 (*iElement)->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1));
887 else
888 nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2;
889 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
890 nX += aElementSize.Width + nGap;
892 else
894 // reverse presentation time with current time
895 if (iElement==iBegin){
896 iElement=iBegin+2;
898 else if (iElement==iBegin+2){
899 iElement=iBegin;
901 const awt::Size aNewElementSize ((*iElement)->GetBoundingSize(rxCanvas));
902 if ((*iElement)->IsFilling())
904 nX = rBoundingBox.X1;
905 (*iElement)->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aNewElementSize.Height));
907 else
908 nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aNewElementSize.Width) / 2;
909 (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY)));
910 nY += aNewElementSize.Height + nGap;
912 // return the index as it was before the reversing
913 if (iElement==iBegin)
914 iElement=iBegin+2;
915 else if (iElement==iBegin+2)
916 iElement=iBegin;
922 void PresenterToolBar::Paint (
923 const awt::Rectangle& rUpdateBox,
924 const rendering::ViewState& rViewState)
926 OSL_ASSERT(mxCanvas.is());
928 for (const auto& rxPart : maElementContainer)
930 for (auto& rxElement : *rxPart)
932 if (rxElement.get() != nullptr)
934 if ( ! rxElement->IsOutside(rUpdateBox))
935 rxElement->Paint(mxCanvas, rViewState);
941 void PresenterToolBar::UpdateSlideNumber()
943 if( mxSlideShowController.is() )
945 for (const auto& rxPart : maElementContainer)
947 for (auto& rxElement : *rxPart)
949 if (rxElement.get() != nullptr)
950 rxElement->CurrentSlideHasChanged();
956 void PresenterToolBar::CheckMouseOver (
957 const css::awt::MouseEvent& rEvent,
958 const bool bOverWindow,
959 const bool bMouseDown)
961 css::awt::MouseEvent rTemp =rEvent;
962 if(AllSettings::GetLayoutRTL()){
963 awt::Rectangle aWindowBox = mxWindow->getPosSize();
964 rTemp.X=aWindowBox.Width-rTemp.X;
966 for (const auto& rxPart : maElementContainer)
968 for (auto& rxElement : *rxPart)
970 if (rxElement.get() == nullptr)
971 continue;
973 awt::Rectangle aBox (rxElement->GetBoundingBox());
974 const bool bIsOver = bOverWindow
975 && aBox.X <= rTemp.X
976 && aBox.Width+aBox.X-1 >= rTemp.X
977 && aBox.Y <= rTemp.Y
978 && aBox.Height+aBox.Y-1 >= rTemp.Y;
979 rxElement->SetState(
980 bIsOver,
981 bIsOver && rTemp.Buttons!=0 && bMouseDown && rTemp.ClickCount>0);
986 void PresenterToolBar::ThrowIfDisposed() const
988 if (rBHelper.bDisposed || rBHelper.bInDispose)
990 throw lang::DisposedException (
991 "PresenterToolBar has already been disposed",
992 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
996 //===== PresenterToolBarView ==================================================
998 PresenterToolBarView::PresenterToolBarView (
999 const Reference<XComponentContext>& rxContext,
1000 const Reference<XResourceId>& rxViewId,
1001 const Reference<frame::XController>& rxController,
1002 const ::rtl::Reference<PresenterController>& rpPresenterController)
1003 : PresenterToolBarViewInterfaceBase(m_aMutex),
1004 mxPane(),
1005 mxViewId(rxViewId),
1006 mxWindow(),
1007 mxCanvas(),
1008 mpPresenterController(rpPresenterController),
1009 mpToolBar()
1013 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
1014 Reference<XConfigurationController> xCC(xCM->getConfigurationController(),UNO_SET_THROW);
1015 mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
1017 mxWindow = mxPane->getWindow();
1018 mxCanvas = mxPane->getCanvas();
1020 mpToolBar = new PresenterToolBar(
1021 rxContext,
1022 mxWindow,
1023 mxCanvas,
1024 rpPresenterController,
1025 PresenterToolBar::Center);
1026 mpToolBar->Initialize("PresenterScreenSettings/ToolBars/ToolBar");
1028 if (mxWindow.is())
1030 mxWindow->addPaintListener(this);
1032 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
1033 if (xPeer.is())
1034 xPeer->setBackground(util::Color(0xff000000));
1036 mxWindow->setVisible(true);
1039 catch (RuntimeException&)
1041 mxViewId = nullptr;
1042 throw;
1046 PresenterToolBarView::~PresenterToolBarView()
1050 void SAL_CALL PresenterToolBarView::disposing()
1052 Reference<lang::XComponent> xComponent (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY);
1053 mpToolBar = nullptr;
1054 if (xComponent.is())
1055 xComponent->dispose();
1057 if (mxWindow.is())
1059 mxWindow->removePaintListener(this);
1060 mxWindow = nullptr;
1062 mxCanvas = nullptr;
1063 mxViewId = nullptr;
1064 mxPane = nullptr;
1065 mpPresenterController = nullptr;
1068 const ::rtl::Reference<PresenterToolBar>& PresenterToolBarView::GetPresenterToolBar() const
1070 return mpToolBar;
1073 //----- XPaintListener --------------------------------------------------------
1075 void SAL_CALL PresenterToolBarView::windowPaint (const css::awt::PaintEvent& rEvent)
1077 awt::Rectangle aWindowBox (mxWindow->getPosSize());
1078 mpPresenterController->GetCanvasHelper()->Paint(
1079 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
1080 mxCanvas,
1081 rEvent.UpdateRect,
1082 awt::Rectangle(0,0,aWindowBox.Width, aWindowBox.Height),
1083 awt::Rectangle());
1086 //----- lang::XEventListener -------------------------------------------------
1088 void SAL_CALL PresenterToolBarView::disposing (const lang::EventObject& rEventObject)
1090 if (rEventObject.Source == mxWindow)
1091 mxWindow = nullptr;
1094 //----- XResourceId -----------------------------------------------------------
1096 Reference<XResourceId> SAL_CALL PresenterToolBarView::getResourceId()
1098 return mxViewId;
1101 sal_Bool SAL_CALL PresenterToolBarView::isAnchorOnly()
1103 return false;
1106 //----- XDrawView -------------------------------------------------------------
1108 void SAL_CALL PresenterToolBarView::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
1110 Reference<drawing::XDrawView> xToolBar (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY);
1111 if (xToolBar.is())
1112 xToolBar->setCurrentPage(rxSlide);
1115 Reference<drawing::XDrawPage> SAL_CALL PresenterToolBarView::getCurrentPage()
1117 return nullptr;
1120 //===== PresenterToolBar::Element =============================================
1122 namespace {
1124 Element::Element (
1125 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1126 : ElementInterfaceBase(m_aMutex),
1127 mpToolBar(rpToolBar),
1128 maLocation(),
1129 maSize(),
1130 mpNormal(),
1131 mpMouseOver(),
1132 mpSelected(),
1133 mpDisabled(),
1134 mpMode(),
1135 mbIsOver(false),
1136 mbIsPressed(false),
1137 mbIsSelected(false),
1138 mbIsEnabled(true)
1140 if (mpToolBar.get() != nullptr)
1142 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1143 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1147 void Element::SetModes (
1148 const SharedElementMode& rpNormalMode,
1149 const SharedElementMode& rpMouseOverMode,
1150 const SharedElementMode& rpSelectedMode,
1151 const SharedElementMode& rpDisabledMode)
1153 mpNormal = rpNormalMode;
1154 mpMouseOver = rpMouseOverMode;
1155 mpSelected = rpSelectedMode;
1156 mpDisabled = rpDisabledMode;
1157 mpMode = rpNormalMode;
1160 void Element::disposing()
1164 awt::Size const & Element::GetBoundingSize (
1165 const Reference<rendering::XCanvas>& rxCanvas)
1167 maSize = CreateBoundingSize(rxCanvas);
1168 return maSize;
1171 awt::Rectangle Element::GetBoundingBox() const
1173 return awt::Rectangle(maLocation.X,maLocation.Y, maSize.Width, maSize.Height);
1176 void Element::CurrentSlideHasChanged()
1178 UpdateState();
1181 void Element::SetLocation (const awt::Point& rLocation)
1183 maLocation = rLocation;
1186 void Element::SetSize (const geometry::RealSize2D& rSize)
1188 maSize = awt::Size(sal_Int32(0.5+rSize.Width), sal_Int32(0.5+rSize.Height));
1191 bool Element::SetState (
1192 const bool bIsOver,
1193 const bool bIsPressed)
1195 bool bModified (mbIsOver != bIsOver || mbIsPressed != bIsPressed);
1196 bool bClicked (mbIsPressed && bIsOver && ! bIsPressed);
1198 mbIsOver = bIsOver;
1199 mbIsPressed = bIsPressed;
1201 // When the element is disabled then ignore mouse over or selection.
1202 // When the element is selected then ignore mouse over.
1203 if ( ! mbIsEnabled)
1204 mpMode = mpDisabled;
1205 else if (mbIsSelected)
1206 mpMode = mpSelected;
1207 else if (mbIsOver)
1208 mpMode = mpMouseOver;
1209 else
1210 mpMode = mpNormal;
1212 if (bClicked && mbIsEnabled)
1214 if (mpMode.get() != nullptr)
1218 if (mpMode->msAction.isEmpty())
1219 break;
1221 if (mpToolBar.get() == nullptr)
1222 break;
1224 if (mpToolBar->GetPresenterController().get() == nullptr)
1225 break;
1227 mpToolBar->GetPresenterController()->DispatchUnoCommand(mpMode->msAction);
1228 mpToolBar->RequestLayout();
1230 while (false);
1234 else if (bModified)
1236 Invalidate(true);
1239 return bModified;
1242 void Element::Invalidate (const bool bSynchronous)
1244 OSL_ASSERT(mpToolBar.is());
1245 mpToolBar->InvalidateArea(GetBoundingBox(), bSynchronous);
1248 bool Element::IsOutside (const awt::Rectangle& rBox)
1250 if (rBox.X >= maLocation.X+maSize.Width)
1251 return true;
1252 else if (rBox.Y >= maLocation.Y+maSize.Height)
1253 return true;
1254 else if (maLocation.X >= rBox.X+rBox.Width)
1255 return true;
1256 else if (maLocation.Y >= rBox.Y+rBox.Height)
1257 return true;
1258 else
1259 return false;
1263 bool Element::IsFilling() const
1265 return false;
1268 void Element::UpdateState()
1270 OSL_ASSERT(mpToolBar.get() != nullptr);
1271 OSL_ASSERT(mpToolBar->GetPresenterController().get() != nullptr);
1273 if (mpMode.get() == nullptr)
1274 return;
1276 util::URL aURL (mpToolBar->GetPresenterController()->CreateURLFromString(mpMode->msAction));
1277 Reference<frame::XDispatch> xDispatch (mpToolBar->GetPresenterController()->GetDispatch(aURL));
1278 if (xDispatch.is())
1280 xDispatch->addStatusListener(this, aURL);
1281 xDispatch->removeStatusListener(this, aURL);
1285 //----- lang::XEventListener --------------------------------------------------
1287 void SAL_CALL Element::disposing (const css::lang::EventObject&) {}
1289 //----- document::XEventListener ----------------------------------------------
1291 void SAL_CALL Element::notifyEvent (const css::document::EventObject&)
1293 UpdateState();
1296 //----- frame::XStatusListener ------------------------------------------------
1298 void SAL_CALL Element::statusChanged (const css::frame::FeatureStateEvent& rEvent)
1300 bool bIsSelected (mbIsSelected);
1301 bool bIsEnabled (rEvent.IsEnabled);
1302 rEvent.State >>= bIsSelected;
1304 if (bIsSelected != mbIsSelected || bIsEnabled != mbIsEnabled)
1306 mbIsEnabled = bIsEnabled;
1307 mbIsSelected = bIsSelected;
1308 SetState(mbIsOver, mbIsPressed);
1309 mpToolBar->RequestLayout();
1313 } // end of anonymous namespace
1315 //===== ElementMode ===========================================================
1317 namespace {
1319 ElementMode::ElementMode()
1320 : mpIcon(),
1321 msAction(),
1322 maText()
1326 void ElementMode::ReadElementMode (
1327 const Reference<beans::XPropertySet>& rxElementProperties,
1328 const OUString& rsModeName,
1329 std::shared_ptr<ElementMode> const & rpDefaultMode,
1330 ::sdext::presenter::PresenterToolBar::Context const & rContext)
1334 Reference<container::XHierarchicalNameAccess> xNode (
1335 PresenterConfigurationAccess::GetProperty(rxElementProperties, rsModeName),
1336 UNO_QUERY);
1337 Reference<beans::XPropertySet> xProperties (
1338 PresenterConfigurationAccess::GetNodeProperties(xNode, OUString()));
1339 if (!xProperties.is() && rpDefaultMode != nullptr)
1341 // The mode is not specified. Use the given, possibly empty,
1342 // default mode instead.
1343 mpIcon = rpDefaultMode->mpIcon;
1344 msAction = rpDefaultMode->msAction;
1345 maText = rpDefaultMode->maText;
1348 // Read action.
1349 if ( ! (PresenterConfigurationAccess::GetProperty(xProperties, "Action") >>= msAction))
1350 if (rpDefaultMode != nullptr)
1351 msAction = rpDefaultMode->msAction;
1353 // Read text and font
1354 OUString sText(rpDefaultMode != nullptr ? rpDefaultMode->maText.GetText() : OUString());
1355 PresenterConfigurationAccess::GetProperty(xProperties, "Text") >>= sText;
1356 Reference<container::XHierarchicalNameAccess> xFontNode (
1357 PresenterConfigurationAccess::GetProperty(xProperties, "Font"), UNO_QUERY);
1358 PresenterTheme::SharedFontDescriptor pFont(PresenterTheme::ReadFont(
1359 xFontNode, rpDefaultMode != nullptr ? rpDefaultMode->maText.GetFont()
1360 : PresenterTheme::SharedFontDescriptor()));
1361 maText = Text(sText,pFont);
1363 // Read bitmaps to display as icons.
1364 Reference<container::XHierarchicalNameAccess> xIconNode (
1365 PresenterConfigurationAccess::GetProperty(xProperties, "Icon"), UNO_QUERY);
1366 mpIcon = PresenterBitmapContainer::LoadBitmap(
1367 xIconNode, "", rContext.mxPresenterHelper, rContext.mxCanvas,
1368 rpDefaultMode != nullptr ? rpDefaultMode->mpIcon : SharedBitmapDescriptor());
1370 catch(Exception&)
1372 OSL_ASSERT(false);
1376 } // end of anonymous namespace
1378 //===== Button ================================================================
1380 namespace {
1382 ::rtl::Reference<Element> Button::Create (
1383 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1385 ::rtl::Reference<Button> pElement (new Button(rpToolBar));
1386 pElement->Initialize();
1387 return ::rtl::Reference<Element>(pElement.get());
1390 Button::Button (
1391 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1392 : Element(rpToolBar),
1393 mbIsListenerRegistered(false)
1395 OSL_ASSERT(mpToolBar.get() != nullptr);
1396 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1397 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1400 void Button::Initialize()
1402 mpToolBar->GetPresenterController()->GetWindowManager()->AddLayoutListener(this);
1403 mbIsListenerRegistered = true;
1406 void Button::disposing()
1408 OSL_ASSERT(mpToolBar.get() != nullptr);
1409 if (mpToolBar.get() != nullptr
1410 && mbIsListenerRegistered)
1412 OSL_ASSERT(mpToolBar->GetPresenterController().is());
1413 OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is());
1415 mbIsListenerRegistered = false;
1416 mpToolBar->GetPresenterController()->GetWindowManager()->RemoveLayoutListener(this);
1418 Element::disposing();
1421 void Button::Paint (
1422 const Reference<rendering::XCanvas>& rxCanvas,
1423 const rendering::ViewState& rViewState)
1425 OSL_ASSERT(rxCanvas.is());
1427 if (mpMode.get() == nullptr)
1428 return;
1430 if (mpMode->mpIcon.get() == nullptr)
1431 return;
1433 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1434 sal_Int32 nTextHeight (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1436 PaintIcon(rxCanvas, nTextHeight, rViewState);
1437 mpMode->maText.Paint(rxCanvas, rViewState, GetBoundingBox());
1440 awt::Size Button::CreateBoundingSize (
1441 const Reference<rendering::XCanvas>& rxCanvas)
1443 if (mpMode.get() == nullptr)
1444 return awt::Size();
1446 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1447 const sal_Int32 nGap (5);
1448 sal_Int32 nTextHeight (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1449 sal_Int32 nTextWidth (sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.X2 - aTextBBox.X1));
1450 Reference<rendering::XBitmap> xBitmap;
1451 if (mpMode->mpIcon.get() != nullptr)
1452 xBitmap = mpMode->mpIcon->GetNormalBitmap();
1453 if (xBitmap.is())
1455 geometry::IntegerSize2D aSize (xBitmap->getSize());
1456 return awt::Size(
1457 ::std::max(aSize.Width, sal_Int32(0.5 + aTextBBox.X2 - aTextBBox.X1)),
1458 aSize.Height+ nGap + nTextHeight);
1460 else
1461 return awt::Size(nTextWidth,nTextHeight);
1464 void Button::PaintIcon (
1465 const Reference<rendering::XCanvas>& rxCanvas,
1466 const sal_Int32 nTextHeight,
1467 const rendering::ViewState& rViewState)
1469 if (mpMode.get() == nullptr)
1470 return;
1472 Reference<rendering::XBitmap> xBitmap (mpMode->mpIcon->GetBitmap(GetMode()));
1473 if (!xBitmap.is())
1474 return;
1476 /// check whether RTL interface or not
1477 if(!AllSettings::GetLayoutRTL()){
1478 const sal_Int32 nX (maLocation.X
1479 + (maSize.Width-xBitmap->getSize().Width) / 2);
1480 const sal_Int32 nY (maLocation.Y
1481 + (maSize.Height - nTextHeight - xBitmap->getSize().Height) / 2);
1482 const rendering::RenderState aRenderState(
1483 geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
1484 nullptr,
1485 Sequence<double>(4),
1486 rendering::CompositeOperation::OVER);
1487 rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState);
1489 else {
1490 const sal_Int32 nX (maLocation.X
1491 + (maSize.Width+xBitmap->getSize().Width) / 2);
1492 const sal_Int32 nY (maLocation.Y
1493 + (maSize.Height - nTextHeight - xBitmap->getSize().Height) / 2);
1494 const rendering::RenderState aRenderState(
1495 geometry::AffineMatrix2D(-1,0,nX, 0,1,nY),
1496 nullptr,
1497 Sequence<double>(4),
1498 rendering::CompositeOperation::OVER);
1499 rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState);
1503 PresenterBitmapDescriptor::Mode Button::GetMode() const
1505 if ( ! IsEnabled())
1506 return PresenterBitmapDescriptor::Disabled;
1507 else if (mbIsPressed)
1508 return PresenterBitmapDescriptor::ButtonDown;
1509 else if (mbIsOver)
1510 return PresenterBitmapDescriptor::MouseOver;
1511 else
1512 return PresenterBitmapDescriptor::Normal;
1515 //----- lang::XEventListener --------------------------------------------------
1517 void SAL_CALL Button::disposing (const css::lang::EventObject& rEvent)
1519 mbIsListenerRegistered = false;
1520 Element::disposing(rEvent);
1523 } // end of anonymous namespace
1525 //===== PresenterToolBar::Label ===============================================
1527 namespace {
1529 Label::Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1530 : Element(rpToolBar)
1534 awt::Size Label::CreateBoundingSize (
1535 const Reference<rendering::XCanvas>& rxCanvas)
1537 if (mpMode.get() == nullptr)
1538 return awt::Size(0,0);
1540 geometry::RealRectangle2D aTextBBox (mpMode->maText.GetBoundingBox(rxCanvas));
1541 return awt::Size(
1542 sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.X2 - aTextBBox.X1),
1543 sal::static_int_cast<sal_Int32>(0.5 + aTextBBox.Y2 - aTextBBox.Y1));
1546 void Label::SetText (const OUString& rsText)
1548 OSL_ASSERT(mpToolBar.get() != nullptr);
1549 if (mpMode.get() == nullptr)
1550 return;
1552 const bool bRequestLayout (mpMode->maText.GetText().getLength() != rsText.getLength());
1554 mpMode->maText.SetText(rsText);
1555 // Just use the character count for determining whether a layout is
1556 // necessary. This is an optimization to avoid layouts every time a new
1557 // time value is set on some labels.
1558 if (bRequestLayout)
1559 mpToolBar->RequestLayout();
1560 else
1561 Invalidate(false);
1564 void Label::Paint (
1565 const Reference<rendering::XCanvas>& rxCanvas,
1566 const rendering::ViewState& rViewState)
1568 OSL_ASSERT(rxCanvas.is());
1569 if (mpMode.get() == nullptr)
1570 return;
1572 mpMode->maText.Paint(rxCanvas, rViewState, GetBoundingBox());
1575 bool Label::SetState (const bool, const bool)
1577 // For labels there is no mouse over effect.
1578 return Element::SetState(false, false);
1581 } // end of anonymous namespace
1583 //===== Text ==================================================================
1585 namespace {
1587 Text::Text()
1588 : msText(),
1589 mpFont()
1593 Text::Text (
1594 const OUString& rsText,
1595 const PresenterTheme::SharedFontDescriptor& rpFont)
1596 : msText(rsText),
1597 mpFont(rpFont)
1601 void Text::SetText (const OUString& rsText)
1603 msText = rsText;
1606 const OUString& Text::GetText() const
1608 return msText;
1611 const PresenterTheme::SharedFontDescriptor& Text::GetFont() const
1613 return mpFont;
1616 void Text::Paint (
1617 const Reference<rendering::XCanvas>& rxCanvas,
1618 const rendering::ViewState& rViewState,
1619 const awt::Rectangle& rBoundingBox)
1621 OSL_ASSERT(rxCanvas.is());
1623 if (msText.isEmpty())
1624 return;
1625 if (mpFont.get() == nullptr)
1626 return;
1628 if ( ! mpFont->mxFont.is())
1629 mpFont->PrepareFont(rxCanvas);
1630 if ( ! mpFont->mxFont.is())
1631 return;
1633 rendering::StringContext aContext (msText, 0, msText.getLength());
1635 Reference<rendering::XTextLayout> xLayout (
1636 mpFont->mxFont->createTextLayout(
1637 aContext,
1638 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1639 0));
1640 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1641 const double nTextWidth = aBox.X2 - aBox.X1;
1642 const double nY = rBoundingBox.Y + rBoundingBox.Height - aBox.Y2;
1643 const double nX = rBoundingBox.X + (rBoundingBox.Width - nTextWidth)/2;
1645 rendering::RenderState aRenderState(
1646 geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
1647 nullptr,
1648 Sequence<double>(4),
1649 rendering::CompositeOperation::SOURCE);
1650 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1651 rxCanvas->drawTextLayout(
1652 xLayout,
1653 rViewState,
1654 aRenderState);
1657 geometry::RealRectangle2D Text::GetBoundingBox (const Reference<rendering::XCanvas>& rxCanvas)
1659 if (mpFont.get() != nullptr && !msText.isEmpty())
1661 if ( ! mpFont->mxFont.is())
1662 mpFont->PrepareFont(rxCanvas);
1663 if (mpFont->mxFont.is())
1665 rendering::StringContext aContext (msText, 0, msText.getLength());
1666 Reference<rendering::XTextLayout> xLayout (
1667 mpFont->mxFont->createTextLayout(
1668 aContext,
1669 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1670 0));
1671 return xLayout->queryTextBounds();
1674 return geometry::RealRectangle2D(0,0,0,0);
1677 //===== TimeFormatter =========================================================
1679 OUString TimeFormatter::FormatTime (const oslDateTime& rTime)
1681 OUStringBuffer sText;
1683 const sal_Int32 nHours (sal::static_int_cast<sal_Int32>(rTime.Hours));
1684 const sal_Int32 nMinutes (sal::static_int_cast<sal_Int32>(rTime.Minutes));
1685 const sal_Int32 nSeconds(sal::static_int_cast<sal_Int32>(rTime.Seconds));
1686 // Hours
1687 sText.append(OUString::number(nHours));
1689 sText.append(":");
1691 // Minutes
1692 const OUString sMinutes (OUString::number(nMinutes));
1693 if (sMinutes.getLength() == 1)
1694 sText.append("0");
1695 sText.append(sMinutes);
1697 // Seconds
1698 sText.append(":");
1699 const OUString sSeconds (OUString::number(nSeconds));
1700 if (sSeconds.getLength() == 1)
1701 sText.append("0");
1702 sText.append(sSeconds);
1703 return sText.makeStringAndClear();
1706 //===== TimeLabel =============================================================
1708 TimeLabel::TimeLabel (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1709 : Label(rpToolBar),
1710 mpListener()
1714 void SAL_CALL TimeLabel::disposing()
1716 PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->RemoveListener(mpListener);
1717 mpListener.reset();
1720 void TimeLabel::ConnectToTimer()
1722 mpListener.reset(new Listener(this));
1723 PresenterClockTimer::Instance(mpToolBar->GetComponentContext())->AddListener(mpListener);
1726 //===== CurrentTimeLabel ======================================================
1728 ::rtl::Reference<Element> CurrentTimeLabel::Create (
1729 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1731 ::rtl::Reference<TimeLabel> pElement(new CurrentTimeLabel(rpToolBar));
1732 pElement->ConnectToTimer();
1733 return ::rtl::Reference<Element>(pElement.get());
1736 CurrentTimeLabel::~CurrentTimeLabel()
1740 CurrentTimeLabel::CurrentTimeLabel (
1741 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1742 : TimeLabel(rpToolBar)
1746 void CurrentTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1748 SetText(TimeFormatter::FormatTime(rCurrentTime));
1749 Invalidate(false);
1752 void CurrentTimeLabel::SetModes (
1753 const SharedElementMode& rpNormalMode,
1754 const SharedElementMode& rpMouseOverMode,
1755 const SharedElementMode& rpSelectedMode,
1756 const SharedElementMode& rpDisabledMode)
1758 TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode);
1759 SetText(TimeFormatter::FormatTime(PresenterClockTimer::GetCurrentTime()));
1762 //===== PresentationTimeLabel =================================================
1764 ::rtl::Reference<Element> PresentationTimeLabel::Create (
1765 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1767 ::rtl::Reference<TimeLabel> pElement(new PresentationTimeLabel(rpToolBar));
1768 pElement->ConnectToTimer();
1769 return ::rtl::Reference<Element>(pElement.get());
1772 PresentationTimeLabel::~PresentationTimeLabel()
1774 mpToolBar->GetPresenterController()->SetPresentationTime(nullptr);
1777 PresentationTimeLabel::PresentationTimeLabel (
1778 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1779 : TimeLabel(rpToolBar),
1780 maStartTimeValue()
1782 restart();
1783 mpToolBar->GetPresenterController()->SetPresentationTime(this);
1786 void PresentationTimeLabel::restart()
1788 maStartTimeValue.Seconds = 0;
1789 maStartTimeValue.Nanosec = 0;
1792 void PresentationTimeLabel::TimeHasChanged (const oslDateTime& rCurrentTime)
1794 TimeValue aCurrentTimeValue;
1795 if (!osl_getTimeValueFromDateTime(&rCurrentTime, &aCurrentTimeValue))
1796 return;
1798 if (maStartTimeValue.Seconds==0 && maStartTimeValue.Nanosec==0)
1800 // This method is called for the first time. Initialize the
1801 // start time. The start time is rounded to nearest second to
1802 // keep the time updates synchronized with the current time label.
1803 maStartTimeValue = aCurrentTimeValue;
1804 if (maStartTimeValue.Nanosec >= 500000000)
1805 maStartTimeValue.Seconds += 1;
1806 maStartTimeValue.Nanosec = 0;
1809 TimeValue aElapsedTimeValue;
1810 aElapsedTimeValue.Seconds = aCurrentTimeValue.Seconds - maStartTimeValue.Seconds;
1811 aElapsedTimeValue.Nanosec = aCurrentTimeValue.Nanosec - maStartTimeValue.Nanosec;
1813 oslDateTime aElapsedDateTime;
1814 if (osl_getDateTimeFromTimeValue(&aElapsedTimeValue, &aElapsedDateTime))
1816 SetText(TimeFormatter::FormatTime(aElapsedDateTime));
1817 Invalidate(false);
1821 void PresentationTimeLabel::SetModes (
1822 const SharedElementMode& rpNormalMode,
1823 const SharedElementMode& rpMouseOverMode,
1824 const SharedElementMode& rpSelectedMode,
1825 const SharedElementMode& rpDisabledMode)
1827 TimeLabel::SetModes(rpNormalMode, rpMouseOverMode, rpSelectedMode, rpDisabledMode);
1829 oslDateTime aStartDateTime;
1830 if (osl_getDateTimeFromTimeValue(&maStartTimeValue, &aStartDateTime))
1832 SetText(TimeFormatter::FormatTime(aStartDateTime));
1836 //===== VerticalSeparator =====================================================
1838 VerticalSeparator::VerticalSeparator (
1839 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1840 : Element(rpToolBar)
1844 void VerticalSeparator::Paint (
1845 const Reference<rendering::XCanvas>& rxCanvas,
1846 const rendering::ViewState& rViewState)
1848 OSL_ASSERT(rxCanvas.is());
1850 awt::Rectangle aBBox (GetBoundingBox());
1852 rendering::RenderState aRenderState(
1853 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1854 nullptr,
1855 Sequence<double>(4),
1856 rendering::CompositeOperation::OVER);
1857 if (mpMode.get() != nullptr)
1859 PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1860 if (pFont.get() != nullptr)
1861 PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1864 rxCanvas->fillPolyPolygon(
1865 PresenterGeometryHelper::CreatePolygon(aBBox, rxCanvas->getDevice()),
1866 rViewState,
1867 aRenderState);
1870 awt::Size VerticalSeparator::CreateBoundingSize (
1871 const Reference<rendering::XCanvas>&)
1873 return awt::Size(1,20);
1876 bool VerticalSeparator::IsFilling() const
1878 return true;
1881 //===== HorizontalSeparator ===================================================
1883 HorizontalSeparator::HorizontalSeparator (
1884 const ::rtl::Reference<PresenterToolBar>& rpToolBar)
1885 : Element(rpToolBar)
1889 void HorizontalSeparator::Paint (
1890 const Reference<rendering::XCanvas>& rxCanvas,
1891 const rendering::ViewState& rViewState)
1893 OSL_ASSERT(rxCanvas.is());
1895 awt::Rectangle aBBox (GetBoundingBox());
1897 rendering::RenderState aRenderState(
1898 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1899 nullptr,
1900 Sequence<double>(4),
1901 rendering::CompositeOperation::OVER);
1902 if (mpMode.get() != nullptr)
1904 PresenterTheme::SharedFontDescriptor pFont (mpMode->maText.GetFont());
1905 if (pFont.get() != nullptr)
1906 PresenterCanvasHelper::SetDeviceColor(aRenderState, pFont->mnColor);
1909 rxCanvas->fillPolyPolygon(
1910 PresenterGeometryHelper::CreatePolygon(aBBox, rxCanvas->getDevice()),
1911 rViewState,
1912 aRenderState);
1915 awt::Size HorizontalSeparator::CreateBoundingSize (
1916 const Reference<rendering::XCanvas>&)
1918 return awt::Size(20,1);
1921 bool HorizontalSeparator::IsFilling() const
1923 return true;
1926 } // end of anonymous namespace
1928 } } // end of namespace ::sdext::presenter
1930 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */