vcl: allow for overriding the default PDF rendering resolution
[LibreOffice.git] / sdext / source / presenter / PresenterButton.cxx
blob099a99411d47eba3c7ec0310dc03d655a596f487
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 "PresenterButton.hxx"
21 #include "PresenterCanvasHelper.hxx"
22 #include "PresenterController.hxx"
23 #include "PresenterGeometryHelper.hxx"
24 #include "PresenterPaintManager.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>
32 using namespace ::com::sun::star;
33 using namespace ::com::sun::star::uno;
35 namespace sdext { namespace presenter {
37 const static double gnHorizontalBorder (15);
38 const static double gnVerticalBorder (5);
40 ::rtl::Reference<PresenterButton> PresenterButton::Create (
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)
48 Reference<beans::XPropertySet> xProperties (GetConfigurationProperties(
49 rxComponentContext,
50 rsConfigurationName));
51 if (xProperties.is())
53 OUString sText;
54 OUString sAction;
55 PresenterConfigurationAccess::GetProperty(xProperties, "Text") >>= sText;
56 PresenterConfigurationAccess::GetProperty(xProperties, "Action") >>= sAction;
58 PresenterTheme::SharedFontDescriptor pFont;
59 if (rpTheme != nullptr)
60 pFont = rpTheme->GetFont("ButtonFont");
62 PresenterTheme::SharedFontDescriptor pMouseOverFont;
63 if (rpTheme != nullptr)
64 pMouseOverFont = rpTheme->GetFont("ButtonMouseOverFont");
66 rtl::Reference<PresenterButton> pButton (
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;
79 else
80 return nullptr;
83 PresenterButton::PresenterButton (
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,
88 const PresenterTheme::SharedFontDescriptor& rpFont,
89 const PresenterTheme::SharedFontDescriptor& rpMouseOverFont,
90 const OUString& rsText,
91 const OUString& rsAction)
92 : PresenterButtonInterfaceBase(m_aMutex),
93 mpPresenterController(rpPresenterController),
94 mpTheme(rpTheme),
95 mxWindow(),
96 mxCanvas(),
97 mxPresenterHelper(),
98 msText(rsText),
99 mpFont(rpFont),
100 mpMouseOverFont(rpMouseOverFont),
101 msAction(rsAction),
102 maCenter(),
103 maButtonSize(-1,-1),
104 meState(PresenterBitmapDescriptor::Normal),
105 mxNormalBitmap(),
106 mxMouseOverBitmap()
110 Reference<lang::XMultiComponentFactory> xFactory (rxComponentContext->getServiceManager());
111 if ( ! xFactory.is())
112 throw RuntimeException();
114 mxPresenterHelper.set(
115 xFactory->createInstanceWithContext(
116 "com.sun.star.comp.Draw.PresenterHelper",
117 rxComponentContext),
118 UNO_QUERY_THROW);
120 if (mxPresenterHelper.is())
121 mxWindow = mxPresenterHelper->createWindow(rxParentWindow,
122 false,
123 false,
124 false,
125 false);
127 // Make the background transparent.
128 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY_THROW);
129 xPeer->setBackground(0xff000000);
131 mxWindow->setVisible(true);
132 mxWindow->addPaintListener(this);
133 mxWindow->addMouseListener(this);
135 catch (RuntimeException&)
140 PresenterButton::~PresenterButton()
144 void SAL_CALL PresenterButton::disposing()
146 if (mxCanvas.is())
148 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
149 mxCanvas = nullptr;
150 if (xComponent.is())
151 xComponent->dispose();
154 if (mxWindow.is())
156 mxWindow->removePaintListener(this);
157 mxWindow->removeMouseListener(this);
158 Reference<lang::XComponent> xComponent = mxWindow;
159 mxWindow = nullptr;
160 if (xComponent.is())
161 xComponent->dispose();
165 void PresenterButton::SetCenter (const css::geometry::RealPoint2D& rLocation)
167 if (mxCanvas.is())
169 Invalidate();
171 maCenter = rLocation;
172 mxWindow->setPosSize(
173 sal_Int32(0.5 + maCenter.X - maButtonSize.Width/2),
174 sal_Int32(0.5 + maCenter.Y - maButtonSize.Height/2),
175 maButtonSize.Width,
176 maButtonSize.Height,
177 awt::PosSize::POSSIZE);
179 Invalidate();
181 else
183 // The button can not be painted but we can at least store the new center.
184 maCenter = rLocation;
188 void PresenterButton::SetCanvas (
189 const css::uno::Reference<css::rendering::XCanvas>& rxParentCanvas,
190 const css::uno::Reference<css::awt::XWindow>& rxParentWindow)
192 if (mxCanvas.is())
194 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
195 mxCanvas = nullptr;
196 if (xComponent.is())
197 xComponent->dispose();
200 if (!(mxPresenterHelper.is() && rxParentCanvas.is() && rxParentWindow.is()))
201 return;
203 mxCanvas = mxPresenterHelper->createSharedCanvas (
204 Reference<rendering::XSpriteCanvas>(rxParentCanvas, UNO_QUERY),
205 rxParentWindow,
206 rxParentCanvas,
207 rxParentWindow,
208 mxWindow);
209 if (mxCanvas.is())
211 SetupButtonBitmaps();
212 SetCenter(maCenter);
216 css::geometry::IntegerSize2D const & PresenterButton::GetSize()
218 if (maButtonSize.Width < 0)
219 CalculateButtonSize();
220 return maButtonSize;
223 //----- XPaintListener --------------------------------------------------------
225 void SAL_CALL PresenterButton::windowPaint (const css::awt::PaintEvent& rEvent)
227 ThrowIfDisposed();
228 if (!(mxWindow.is() && mxCanvas.is()))
229 return;
231 Reference<rendering::XBitmap> xBitmap;
232 if (meState == PresenterBitmapDescriptor::MouseOver)
233 xBitmap = mxMouseOverBitmap;
234 else
235 xBitmap = mxNormalBitmap;
236 if ( ! xBitmap.is())
237 return;
239 rendering::ViewState aViewState(
240 geometry::AffineMatrix2D(1,0,0, 0,1,0),
241 nullptr);
242 rendering::RenderState aRenderState(
243 geometry::AffineMatrix2D(1,0,0, 0,1,0),
244 PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice()),
245 Sequence<double>(4),
246 rendering::CompositeOperation::SOURCE);
248 mxCanvas->drawBitmap(xBitmap, aViewState, aRenderState);
250 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
251 if (xSpriteCanvas.is())
252 xSpriteCanvas->updateScreen(false);
255 //----- XMouseListener --------------------------------------------------------
257 void SAL_CALL PresenterButton::mousePressed (const css::awt::MouseEvent&)
259 ThrowIfDisposed();
260 meState = PresenterBitmapDescriptor::ButtonDown;
263 void SAL_CALL PresenterButton::mouseReleased (const css::awt::MouseEvent&)
265 ThrowIfDisposed();
267 if (meState == PresenterBitmapDescriptor::ButtonDown)
269 OSL_ASSERT(mpPresenterController.get()!=nullptr);
270 mpPresenterController->DispatchUnoCommand(msAction);
272 meState = PresenterBitmapDescriptor::Normal;
273 Invalidate();
277 void SAL_CALL PresenterButton::mouseEntered (const css::awt::MouseEvent&)
279 ThrowIfDisposed();
280 meState = PresenterBitmapDescriptor::MouseOver;
281 Invalidate();
284 void SAL_CALL PresenterButton::mouseExited (const css::awt::MouseEvent&)
286 ThrowIfDisposed();
287 meState = PresenterBitmapDescriptor::Normal;
288 Invalidate();
291 //----- lang::XEventListener --------------------------------------------------
293 void SAL_CALL PresenterButton::disposing (const css::lang::EventObject& rEvent)
295 if (rEvent.Source == mxWindow)
296 mxWindow = nullptr;
300 css::geometry::IntegerSize2D PresenterButton::CalculateButtonSize()
302 if (mpFont.get()!=nullptr && !mpFont->mxFont.is() && mxCanvas.is())
303 mpFont->PrepareFont(mxCanvas);
304 if (mpFont.get()==nullptr || !mpFont->mxFont.is())
305 return geometry::IntegerSize2D(-1,-1);
307 geometry::RealSize2D aTextSize (PresenterCanvasHelper::GetTextSize(mpFont->mxFont,msText));
309 return geometry::IntegerSize2D (
310 sal_Int32(0.5 + aTextSize.Width + 2*gnHorizontalBorder),
311 sal_Int32(0.5 + aTextSize.Height + 2*gnVerticalBorder));
314 void PresenterButton::RenderButton (
315 const Reference<rendering::XCanvas>& rxCanvas,
316 const geometry::IntegerSize2D& rSize,
317 const PresenterTheme::SharedFontDescriptor& rpFont,
318 const PresenterBitmapDescriptor::Mode eMode,
319 const SharedBitmapDescriptor& rpLeft,
320 const SharedBitmapDescriptor& rpCenter,
321 const SharedBitmapDescriptor& rpRight)
323 if ( ! rxCanvas.is())
324 return;
326 const awt::Rectangle aBox(0,0, rSize.Width, rSize.Height);
328 PresenterUIPainter::PaintHorizontalBitmapComposite (
329 rxCanvas,
330 aBox,
331 aBox,
332 GetBitmap(rpLeft, eMode),
333 GetBitmap(rpCenter, eMode),
334 GetBitmap(rpRight, eMode));
336 if (rpFont.get()==nullptr || ! rpFont->mxFont.is())
337 return;
339 const rendering::StringContext aContext (msText, 0, msText.getLength());
340 const Reference<rendering::XTextLayout> xLayout (
341 rpFont->mxFont->createTextLayout(aContext,rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0));
342 const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
344 rendering::RenderState aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr,
345 Sequence<double>(4), rendering::CompositeOperation::SOURCE);
346 PresenterCanvasHelper::SetDeviceColor(aRenderState, rpFont->mnColor);
348 aRenderState.AffineTransform.m02 = (rSize.Width - aTextBBox.X2 + aTextBBox.X1)/2;
349 aRenderState.AffineTransform.m12 = (rSize.Height - aTextBBox.Y2 + aTextBBox.Y1)/2 - aTextBBox.Y1;
351 /// this is responsible of the close button
352 rxCanvas->drawTextLayout(
353 xLayout,
354 rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
355 aRenderState);
358 void PresenterButton::Invalidate()
360 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
363 Reference<rendering::XBitmap> PresenterButton::GetBitmap (
364 const SharedBitmapDescriptor& mpIcon,
365 const PresenterBitmapDescriptor::Mode eMode)
367 if (mpIcon.get() != nullptr)
368 return mpIcon->GetBitmap(eMode);
369 else
371 OSL_ASSERT(mpIcon.get()!=nullptr);
372 return nullptr;
376 void PresenterButton::SetupButtonBitmaps()
378 if ( ! mxCanvas.is())
379 return;
380 if ( ! mxCanvas->getDevice().is())
381 return;
383 // Get the bitmaps for the button border.
384 SharedBitmapDescriptor pLeftBitmap (mpTheme->GetBitmap("ButtonFrameLeft"));
385 SharedBitmapDescriptor pCenterBitmap(mpTheme->GetBitmap("ButtonFrameCenter"));
386 SharedBitmapDescriptor pRightBitmap(mpTheme->GetBitmap("ButtonFrameRight"));
388 maButtonSize = CalculateButtonSize();
390 if (maButtonSize.Height<=0 && maButtonSize.Width<= 0)
391 return;
393 mxNormalBitmap = mxCanvas->getDevice()->createCompatibleAlphaBitmap(maButtonSize);
394 Reference<rendering::XCanvas> xCanvas (mxNormalBitmap, UNO_QUERY);
395 if (xCanvas.is())
396 RenderButton(
397 xCanvas,
398 maButtonSize,
399 mpFont,
400 PresenterBitmapDescriptor::Normal,
401 pLeftBitmap,
402 pCenterBitmap,
403 pRightBitmap);
405 mxMouseOverBitmap = mxCanvas->getDevice()->createCompatibleAlphaBitmap(maButtonSize);
406 xCanvas.set(mxMouseOverBitmap, UNO_QUERY);
407 if (mpMouseOverFont.get()!=nullptr && !mpMouseOverFont->mxFont.is() && mxCanvas.is())
408 mpMouseOverFont->PrepareFont(mxCanvas);
409 if (xCanvas.is())
410 RenderButton(
411 xCanvas,
412 maButtonSize,
413 mpMouseOverFont,
414 PresenterBitmapDescriptor::MouseOver,
415 pLeftBitmap,
416 pCenterBitmap,
417 pRightBitmap);
420 Reference<beans::XPropertySet> PresenterButton::GetConfigurationProperties (
421 const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
422 const OUString& rsConfgurationName)
424 PresenterConfigurationAccess aConfiguration (
425 rxComponentContext,
426 PresenterConfigurationAccess::msPresenterScreenRootName,
427 PresenterConfigurationAccess::READ_ONLY);
428 return Reference<beans::XPropertySet>(
429 PresenterConfigurationAccess::Find (
430 Reference<container::XNameAccess>(
431 aConfiguration.GetConfigurationNode("PresenterScreenSettings/Buttons"),
432 UNO_QUERY),
433 [&rsConfgurationName](OUString const&, uno::Reference<beans::XPropertySet> const& xProps) -> bool
435 return PresenterConfigurationAccess::IsStringPropertyEqual(
436 rsConfgurationName, "Name", xProps);
438 UNO_QUERY);
441 void PresenterButton::ThrowIfDisposed() const
443 if (rBHelper.bDisposed || rBHelper.bInDispose)
445 throw lang::DisposedException (
446 "PresenterButton object has already been disposed",
447 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
451 } } // end of namespace sdext::presenter
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */