LibreOffice Module sdext (master)  1
PresenterButton.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "PresenterButton.hxx"
22 #include "PresenterController.hxx"
25 #include "PresenterUIPainter.hxx"
26 #include <com/sun/star/awt/PosSize.hpp>
27 #include <com/sun/star/awt/XWindowPeer.hpp>
28 #include <com/sun/star/drawing/XPresenterHelper.hpp>
29 #include <com/sun/star/rendering/CompositeOperation.hpp>
30 #include <com/sun/star/rendering/TextDirection.hpp>
31 
32 using namespace ::com::sun::star;
33 using namespace ::com::sun::star::uno;
34 
35 namespace sdext::presenter {
36 
37 const double gnHorizontalBorder (15);
38 const double gnVerticalBorder (5);
39 
41  const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
42  const ::rtl::Reference<PresenterController>& rpPresenterController,
43  const std::shared_ptr<PresenterTheme>& rpTheme,
44  const css::uno::Reference<css::awt::XWindow>& rxParentWindow,
45  const css::uno::Reference<css::rendering::XCanvas>& rxParentCanvas,
46  const OUString& rsConfigurationName)
47 {
49  rxComponentContext,
50  rsConfigurationName));
51  if (xProperties.is())
52  {
53  OUString sText;
54  OUString sAction;
55  PresenterConfigurationAccess::GetProperty(xProperties, "Text") >>= sText;
56  PresenterConfigurationAccess::GetProperty(xProperties, "Action") >>= sAction;
57 
59  if (rpTheme != nullptr)
60  pFont = rpTheme->GetFont("ButtonFont");
61 
63  if (rpTheme != nullptr)
64  pMouseOverFont = rpTheme->GetFont("ButtonMouseOverFont");
65 
67  new PresenterButton(
68  rxComponentContext,
69  rpPresenterController,
70  rpTheme,
71  rxParentWindow,
72  pFont,
73  pMouseOverFont,
74  sText,
75  sAction));
76  pButton->SetCanvas(rxParentCanvas, rxParentWindow);
77  return pButton;
78  }
79  else
80  return nullptr;
81 }
82 
84  const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
85  const ::rtl::Reference<PresenterController>& rpPresenterController,
86  const std::shared_ptr<PresenterTheme>& rpTheme,
87  const css::uno::Reference<css::awt::XWindow>& rxParentWindow,
89  const PresenterTheme::SharedFontDescriptor& rpMouseOverFont,
90  const OUString& rsText,
91  const OUString& rsAction)
93  mpPresenterController(rpPresenterController),
94  mpTheme(rpTheme),
95  msText(rsText),
96  mpFont(rpFont),
97  mpMouseOverFont(rpMouseOverFont),
98  msAction(rsAction),
99  maButtonSize(-1,-1),
101 {
102  try
103  {
104  Reference<lang::XMultiComponentFactory> xFactory (rxComponentContext->getServiceManager());
105  if ( ! xFactory.is())
106  throw RuntimeException();
107 
108  mxPresenterHelper.set(
109  xFactory->createInstanceWithContext(
110  "com.sun.star.comp.Draw.PresenterHelper",
111  rxComponentContext),
112  UNO_QUERY_THROW);
113 
114  if (mxPresenterHelper.is())
115  mxWindow = mxPresenterHelper->createWindow(rxParentWindow,
116  false,
117  false,
118  false,
119  false);
120 
121  // Make the background transparent.
122  Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY_THROW);
123  xPeer->setBackground(0xff000000);
124 
125  mxWindow->setVisible(true);
126  mxWindow->addPaintListener(this);
127  mxWindow->addMouseListener(this);
128  }
129  catch (RuntimeException&)
130  {
131  }
132 }
133 
135 {
136 }
137 
139 {
140  if (mxCanvas.is())
141  {
142  Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
143  mxCanvas = nullptr;
144  if (xComponent.is())
145  xComponent->dispose();
146  }
147 
148  if (mxWindow.is())
149  {
150  mxWindow->removePaintListener(this);
151  mxWindow->removeMouseListener(this);
153  mxWindow = nullptr;
154  if (xComponent.is())
155  xComponent->dispose();
156  }
157 }
158 
159 void PresenterButton::SetCenter (const css::geometry::RealPoint2D& rLocation)
160 {
161  if (mxCanvas.is())
162  {
163  Invalidate();
164 
165  maCenter = rLocation;
166  mxWindow->setPosSize(
167  sal_Int32(0.5 + maCenter.X - maButtonSize.Width/2),
168  sal_Int32(0.5 + maCenter.Y - maButtonSize.Height/2),
169  maButtonSize.Width,
170  maButtonSize.Height,
171  awt::PosSize::POSSIZE);
172 
173  Invalidate();
174  }
175  else
176  {
177  // The button can not be painted but we can at least store the new center.
178  maCenter = rLocation;
179  }
180 }
181 
183  const css::uno::Reference<css::rendering::XCanvas>& rxParentCanvas,
184  const css::uno::Reference<css::awt::XWindow>& rxParentWindow)
185 {
186  if (mxCanvas.is())
187  {
188  Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
189  mxCanvas = nullptr;
190  if (xComponent.is())
191  xComponent->dispose();
192  }
193 
194  if (!(mxPresenterHelper.is() && rxParentCanvas.is() && rxParentWindow.is()))
195  return;
196 
197  mxCanvas = mxPresenterHelper->createSharedCanvas (
198  Reference<rendering::XSpriteCanvas>(rxParentCanvas, UNO_QUERY),
199  rxParentWindow,
200  rxParentCanvas,
201  rxParentWindow,
202  mxWindow);
203  if (mxCanvas.is())
204  {
207  }
208 }
209 
210 css::geometry::IntegerSize2D const & PresenterButton::GetSize()
211 {
212  if (maButtonSize.Width < 0)
214  return maButtonSize;
215 }
216 
217 //----- XPaintListener --------------------------------------------------------
218 
219 void SAL_CALL PresenterButton::windowPaint (const css::awt::PaintEvent& rEvent)
220 {
221  ThrowIfDisposed();
222  if (!(mxWindow.is() && mxCanvas.is()))
223  return;
224 
225  Reference<rendering::XBitmap> xBitmap;
227  xBitmap = mxMouseOverBitmap;
228  else
229  xBitmap = mxNormalBitmap;
230  if ( ! xBitmap.is())
231  return;
232 
233  rendering::ViewState aViewState(
234  geometry::AffineMatrix2D(1,0,0, 0,1,0),
235  nullptr);
236  rendering::RenderState aRenderState(
237  geometry::AffineMatrix2D(1,0,0, 0,1,0),
238  PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice()),
239  Sequence<double>(4),
240  rendering::CompositeOperation::SOURCE);
241 
242  mxCanvas->drawBitmap(xBitmap, aViewState, aRenderState);
243 
244  Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
245  if (xSpriteCanvas.is())
246  xSpriteCanvas->updateScreen(false);
247 }
248 
249 //----- XMouseListener --------------------------------------------------------
250 
251 void SAL_CALL PresenterButton::mousePressed (const css::awt::MouseEvent&)
252 {
253  ThrowIfDisposed();
255 }
256 
257 void SAL_CALL PresenterButton::mouseReleased (const css::awt::MouseEvent&)
258 {
259  ThrowIfDisposed();
260 
262  {
263  OSL_ASSERT(mpPresenterController);
264  mpPresenterController->DispatchUnoCommand(msAction);
265 
267  Invalidate();
268  }
269 }
270 
271 void SAL_CALL PresenterButton::mouseEntered (const css::awt::MouseEvent&)
272 {
273  ThrowIfDisposed();
275  Invalidate();
276 }
277 
278 void SAL_CALL PresenterButton::mouseExited (const css::awt::MouseEvent&)
279 {
280  ThrowIfDisposed();
282  Invalidate();
283 }
284 
285 //----- lang::XEventListener --------------------------------------------------
286 
287 void SAL_CALL PresenterButton::disposing (const css::lang::EventObject& rEvent)
288 {
289  if (rEvent.Source == mxWindow)
290  mxWindow = nullptr;
291 }
292 
293 
294 css::geometry::IntegerSize2D PresenterButton::CalculateButtonSize()
295 {
296  if (mpFont && !mpFont->mxFont.is() && mxCanvas.is())
297  mpFont->PrepareFont(mxCanvas);
298  if (!mpFont || !mpFont->mxFont.is())
299  return geometry::IntegerSize2D(-1,-1);
300 
301  geometry::RealSize2D aTextSize (PresenterCanvasHelper::GetTextSize(mpFont->mxFont,msText));
302 
303  return geometry::IntegerSize2D (
304  sal_Int32(0.5 + aTextSize.Width + 2*gnHorizontalBorder),
305  sal_Int32(0.5 + aTextSize.Height + 2*gnVerticalBorder));
306 }
307 
309  const Reference<rendering::XCanvas>& rxCanvas,
310  const geometry::IntegerSize2D& rSize,
313  const SharedBitmapDescriptor& rpLeft,
314  const SharedBitmapDescriptor& rpCenter,
315  const SharedBitmapDescriptor& rpRight)
316 {
317  if ( ! rxCanvas.is())
318  return;
319 
320  const awt::Rectangle aBox(0,0, rSize.Width, rSize.Height);
321 
323  rxCanvas,
324  aBox,
325  aBox,
326  GetBitmap(rpLeft, eMode),
327  GetBitmap(rpCenter, eMode),
328  GetBitmap(rpRight, eMode));
329 
330  if (!rpFont || ! rpFont->mxFont.is())
331  return;
332 
333  const rendering::StringContext aContext (msText, 0, msText.getLength());
334  const Reference<rendering::XTextLayout> xLayout (
335  rpFont->mxFont->createTextLayout(aContext,rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0));
336  const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
337 
338  rendering::RenderState aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr,
339  Sequence<double>(4), rendering::CompositeOperation::SOURCE);
340  PresenterCanvasHelper::SetDeviceColor(aRenderState, rpFont->mnColor);
341 
342  aRenderState.AffineTransform.m02 = (rSize.Width - aTextBBox.X2 + aTextBBox.X1)/2;
343  aRenderState.AffineTransform.m12 = (rSize.Height - aTextBBox.Y2 + aTextBBox.Y1)/2 - aTextBBox.Y1;
344 
346  rxCanvas->drawTextLayout(
347  xLayout,
348  rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
349  aRenderState);
350 }
351 
353 {
354  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
355 }
356 
357 Reference<rendering::XBitmap> PresenterButton::GetBitmap (
360 {
361  if (mpIcon)
362  return mpIcon->GetBitmap(eMode);
363  else
364  {
365  OSL_ASSERT(mpIcon);
366  return nullptr;
367  }
368 }
369 
371 {
372  if ( ! mxCanvas.is())
373  return;
374  if ( ! mxCanvas->getDevice().is())
375  return;
376 
377  // Get the bitmaps for the button border.
378  SharedBitmapDescriptor pLeftBitmap (mpTheme->GetBitmap("ButtonFrameLeft"));
379  SharedBitmapDescriptor pCenterBitmap(mpTheme->GetBitmap("ButtonFrameCenter"));
380  SharedBitmapDescriptor pRightBitmap(mpTheme->GetBitmap("ButtonFrameRight"));
381 
383 
384  if (maButtonSize.Height<=0 && maButtonSize.Width<= 0)
385  return;
386 
387  mxNormalBitmap = mxCanvas->getDevice()->createCompatibleAlphaBitmap(maButtonSize);
388  Reference<rendering::XCanvas> xCanvas (mxNormalBitmap, UNO_QUERY);
389  if (xCanvas.is())
390  RenderButton(
391  xCanvas,
392  maButtonSize,
393  mpFont,
395  pLeftBitmap,
396  pCenterBitmap,
397  pRightBitmap);
398 
399  mxMouseOverBitmap = mxCanvas->getDevice()->createCompatibleAlphaBitmap(maButtonSize);
400  xCanvas.set(mxMouseOverBitmap, UNO_QUERY);
401  if (mpMouseOverFont && !mpMouseOverFont->mxFont.is() && mxCanvas.is())
402  mpMouseOverFont->PrepareFont(mxCanvas);
403  if (xCanvas.is())
404  RenderButton(
405  xCanvas,
406  maButtonSize,
409  pLeftBitmap,
410  pCenterBitmap,
411  pRightBitmap);
412 }
413 
415  const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
416  const OUString& rsConfigurationName)
417 {
418  PresenterConfigurationAccess aConfiguration (
419  rxComponentContext,
425  aConfiguration.GetConfigurationNode("PresenterScreenSettings/Buttons"),
426  UNO_QUERY),
427  [&rsConfigurationName](OUString const&, uno::Reference<beans::XPropertySet> const& xProps) -> bool
428  {
430  rsConfigurationName, "Name", xProps);
431  }),
432  UNO_QUERY);
433 }
434 
436 {
437  if (rBHelper.bDisposed || rBHelper.bInDispose)
438  {
439  throw lang::DisposedException (
440  "PresenterButton object has already been disposed",
441  const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
442  }
443 }
444 
445 } // end of namespace sdext::presenter
446 
447 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::rendering::XBitmap > mxNormalBitmap
There is one bitmap for the normal state, one for a mouse over effect and one to show that a button h...
std::shared_ptr< FontDescriptor > SharedFontDescriptor
static css::uno::Any GetProperty(const css::uno::Reference< css::beans::XPropertySet > &rxProperties, const OUString &rsKey)
This method wraps a call to getPropertyValue() and returns an empty Any instead of throwing an except...
const PresenterTheme::SharedFontDescriptor mpFont
css::uno::Reference< css::rendering::XBitmap > mxMouseOverBitmap
PresenterButton(const PresenterButton &)=delete
css::uno::Reference< css::rendering::XCanvas > mxCanvas
::rtl::Reference< PresenterController > mpPresenterController
::cppu::WeakComponentImplHelper< css::awt::XPaintListener, css::awt::XMouseListener > PresenterButtonInterfaceBase
const PresenterTheme::SharedFontDescriptor mpMouseOverFont
PresenterBitmapDescriptor::Mode meState
css::geometry::IntegerSize2D maButtonSize
SharedBitmapDescriptor mpIcon
virtual void SAL_CALL windowPaint(const css::awt::PaintEvent &rEvent) override
css::uno::Reference< css::drawing::XPresenterHelper > mxPresenterHelper
std::shared_ptr< PresenterBitmapContainer::BitmapDescriptor > SharedBitmapDescriptor
This class gives access to the configuration.
std::mutex m_aMutex
virtual void SAL_CALL mouseExited(const css::awt::MouseEvent &rEvent) override
void SetCenter(const css::geometry::RealPoint2D &rLocation)
static void PaintHorizontalBitmapComposite(const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const css::awt::Rectangle &rRepaintBox, const css::awt::Rectangle &rBoundingBox, const css::uno::Reference< css::rendering::XBitmap > &rxLeftBitmap, const css::uno::Reference< css::rendering::XBitmap > &rxRepeatableCenterBitmap, const css::uno::Reference< css::rendering::XBitmap > &rxRightBitmap)
virtual void SAL_CALL disposing() override
static css::uno::Reference< css::rendering::XBitmap > GetBitmap(const SharedBitmapDescriptor &mpIcon, const PresenterBitmapDescriptor::Mode eMode)
static css::uno::Any Find(const css::uno::Reference< css::container::XNameAccess > &rxContainer, const Predicate &rPredicate)
css::geometry::IntegerSize2D const & GetSize()
css::geometry::RealPoint2D maCenter
void RenderButton(const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const css::geometry::IntegerSize2D &rSize, const PresenterTheme::SharedFontDescriptor &rFont, const PresenterBitmapDescriptor::Mode eMode, const SharedBitmapDescriptor &rpLeft, const SharedBitmapDescriptor &rpCenter, const SharedBitmapDescriptor &rpRight)
css::uno::Any GetConfigurationNode(const OUString &rsPathToNode)
Return a configuration node below the root of the called object.
static css::uno::Reference< css::beans::XPropertySet > GetConfigurationProperties(const css::uno::Reference< css::uno::XComponentContext > &rxComponentContext, const OUString &rsConfigurationName)
void SetCanvas(const css::uno::Reference< css::rendering::XCanvas > &rxParentCanvas, const css::uno::Reference< css::awt::XWindow > &rxParentWindow)
static bool IsStringPropertyEqual(std::u16string_view rsValue, const OUString &rsPropertyName, const css::uno::Reference< css::beans::XPropertySet > &rxNode)
static css::uno::Reference< css::rendering::XPolyPolygon2D > CreatePolygon(const css::awt::Rectangle &rBox, const css::uno::Reference< css::rendering::XGraphicDevice > &rxDevice)
virtual void SAL_CALL mousePressed(const css::awt::MouseEvent &rEvent) override
css::geometry::IntegerSize2D CalculateButtonSize()
PresenterTheme::SharedFontDescriptor mpFont
rtl::Reference< PresenterController > mpPresenterController
const OUString msText
OUString msAction
virtual void SAL_CALL mouseReleased(const css::awt::MouseEvent &rEvent) override
css::uno::Reference< css::awt::XWindow > mxWindow
static void SetDeviceColor(css::rendering::RenderState &rRenderState, const css::util::Color aColor)
static css::geometry::RealSize2D GetTextSize(const css::uno::Reference< css::rendering::XCanvasFont > &rxFont, const OUString &rsText)
const double gnHorizontalBorder(15)
Reference< XSingleServiceFactory > xFactory
virtual void SAL_CALL mouseEntered(const css::awt::MouseEvent &rEvent) override
const double gnVerticalBorder(5)
static::rtl::Reference< PresenterButton > Create(const css::uno::Reference< css::uno::XComponentContext > &rxComponentContext, const ::rtl::Reference< PresenterController > &rpPresenterController, const std::shared_ptr< PresenterTheme > &rpTheme, const css::uno::Reference< css::awt::XWindow > &rxParentWindow, const css::uno::Reference< css::rendering::XCanvas > &rxParentCanvas, const OUString &rsConfigurationName)
std::shared_ptr< PresenterTheme > mpTheme