1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sdext.hxx"
26 
27 #include "PresenterButton.hxx"
28 #include "PresenterCanvasHelper.hxx"
29 #include "PresenterController.hxx"
30 #include "PresenterGeometryHelper.hxx"
31 #include "PresenterPaintManager.hxx"
32 #include "PresenterUIPainter.hxx"
33 #include <com/sun/star/awt/PosSize.hpp>
34 #include <com/sun/star/awt/XWindowPeer.hpp>
35 #include <com/sun/star/drawing/XPresenterHelper.hpp>
36 #include <com/sun/star/rendering/CompositeOperation.hpp>
37 #include <com/sun/star/rendering/TextDirection.hpp>
38 #include <boost/bind.hpp>
39 
40 using namespace ::com::sun::star;
41 using namespace ::com::sun::star::uno;
42 using ::rtl::OUString;
43 
44 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
45 
46 namespace sdext { namespace presenter {
47 
48 const static double gnHorizontalBorder (15);
49 const static double gnVerticalBorder (5);
50 
51 
52 
Create(const css::uno::Reference<css::uno::XComponentContext> & rxComponentContext,const::rtl::Reference<PresenterController> & rpPresenterController,const::boost::shared_ptr<PresenterTheme> & rpTheme,const css::uno::Reference<css::awt::XWindow> & rxParentWindow,const css::uno::Reference<css::rendering::XCanvas> & rxParentCanvas,const OUString & rsConfigurationName)53 ::rtl::Reference<PresenterButton> PresenterButton::Create (
54     const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
55     const ::rtl::Reference<PresenterController>& rpPresenterController,
56     const ::boost::shared_ptr<PresenterTheme>& rpTheme,
57     const css::uno::Reference<css::awt::XWindow>& rxParentWindow,
58     const css::uno::Reference<css::rendering::XCanvas>& rxParentCanvas,
59     const OUString& rsConfigurationName)
60 {
61     Reference<beans::XPropertySet> xProperties (GetConfigurationProperties(
62         rxComponentContext,
63         rsConfigurationName));
64     if (xProperties.is())
65     {
66         OUString sText;
67         OUString sAction;
68         PresenterConfigurationAccess::GetProperty(xProperties, A2S("Text")) >>= sText;
69         PresenterConfigurationAccess::GetProperty(xProperties, A2S("Action")) >>= sAction;
70 
71         PresenterTheme::SharedFontDescriptor pFont;
72         if (rpTheme.get() != NULL)
73             pFont = rpTheme->GetFont(A2S("ButtonFont"));
74 
75         PresenterTheme::SharedFontDescriptor pMouseOverFont;
76         if (rpTheme.get() != NULL)
77             pMouseOverFont = rpTheme->GetFont(A2S("ButtonMouseOverFont"));
78 
79         rtl::Reference<PresenterButton> pButton (
80             new PresenterButton(
81                 rxComponentContext,
82                 rpPresenterController,
83                 rpTheme,
84                 rxParentWindow,
85                 pFont,
86                 pMouseOverFont,
87                 sText,
88                 sAction));
89         pButton->SetCanvas(rxParentCanvas, rxParentWindow);
90         return pButton;
91     }
92     else
93         return NULL;
94 }
95 
96 
97 
98 
PresenterButton(const css::uno::Reference<css::uno::XComponentContext> & rxComponentContext,const::rtl::Reference<PresenterController> & rpPresenterController,const::boost::shared_ptr<PresenterTheme> & rpTheme,const css::uno::Reference<css::awt::XWindow> & rxParentWindow,const PresenterTheme::SharedFontDescriptor & rpFont,const PresenterTheme::SharedFontDescriptor & rpMouseOverFont,const OUString & rsText,const OUString & rsAction)99 PresenterButton::PresenterButton (
100     const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
101     const ::rtl::Reference<PresenterController>& rpPresenterController,
102     const ::boost::shared_ptr<PresenterTheme>& rpTheme,
103     const css::uno::Reference<css::awt::XWindow>& rxParentWindow,
104     const PresenterTheme::SharedFontDescriptor& rpFont,
105     const PresenterTheme::SharedFontDescriptor& rpMouseOverFont,
106     const OUString& rsText,
107     const OUString& rsAction)
108     : PresenterButtonInterfaceBase(m_aMutex),
109       mpPresenterController(rpPresenterController),
110       mpTheme(rpTheme),
111       mxWindow(),
112       mxCanvas(),
113       mxPresenterHelper(),
114       msText(rsText),
115       mpFont(rpFont),
116       mpMouseOverFont(rpMouseOverFont),
117       msAction(rsAction),
118       maCenter(),
119       maButtonSize(-1,-1),
120       meState(PresenterBitmapDescriptor::Normal),
121       mxNormalBitmap(),
122       mxMouseOverBitmap()
123 {
124     try
125     {
126         Reference<lang::XMultiComponentFactory> xFactory (rxComponentContext->getServiceManager());
127         if ( ! xFactory.is())
128             throw RuntimeException();
129 
130         mxPresenterHelper = Reference<drawing::XPresenterHelper>(
131             xFactory->createInstanceWithContext(
132                 OUString::createFromAscii("com.sun.star.comp.Draw.PresenterHelper"),
133                 rxComponentContext),
134             UNO_QUERY_THROW);
135 
136         if (mxPresenterHelper.is())
137             mxWindow = mxPresenterHelper->createWindow(rxParentWindow,
138                 sal_False,
139                 sal_False,
140                 sal_False,
141                 sal_False);
142 
143         // Make the background transparent.
144         Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY_THROW);
145         if (xPeer.is())
146         {
147             xPeer->setBackground(0xff000000);
148         }
149 
150         mxWindow->setVisible(sal_True);
151         mxWindow->addWindowListener(this);
152         mxWindow->addPaintListener(this);
153         mxWindow->addMouseListener(this);
154         mxWindow->addMouseMotionListener(this);
155     }
156     catch (RuntimeException&)
157     {
158     }
159 }
160 
161 
162 
163 
~PresenterButton(void)164 PresenterButton::~PresenterButton (void)
165 {
166 }
167 
168 
169 
170 
disposing(void)171 void SAL_CALL PresenterButton::disposing (void)
172 {
173     if (mxCanvas.is())
174     {
175         Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
176         mxCanvas = NULL;
177         if (xComponent.is())
178             xComponent->dispose();
179     }
180 
181     if (mxWindow.is())
182     {
183         mxWindow->removeWindowListener(this);
184         mxWindow->removePaintListener(this);
185         mxWindow->removeMouseListener(this);
186         mxWindow->removeMouseMotionListener(this);
187         Reference<lang::XComponent> xComponent (mxWindow, UNO_QUERY);
188         mxWindow = NULL;
189         if (xComponent.is())
190             xComponent->dispose();
191     }
192 }
193 
194 
195 
196 
SetCenter(const css::geometry::RealPoint2D & rLocation)197 void PresenterButton::SetCenter (const css::geometry::RealPoint2D& rLocation)
198 {
199     if (mxCanvas.is())
200     {
201         Invalidate();
202 
203         maCenter = rLocation;
204         mxWindow->setPosSize(
205             sal_Int32(0.5 + maCenter.X - maButtonSize.Width/2),
206             sal_Int32(0.5 + maCenter.Y - maButtonSize.Height/2),
207             maButtonSize.Width,
208             maButtonSize.Height,
209             awt::PosSize::POSSIZE);
210 
211         Invalidate();
212     }
213     else
214     {
215         // The button can not be painted but we can at least store the new center.
216         maCenter = rLocation;
217     }
218 }
219 
220 
221 
222 
SetCanvas(const css::uno::Reference<css::rendering::XCanvas> & rxParentCanvas,const css::uno::Reference<css::awt::XWindow> & rxParentWindow)223 void PresenterButton::SetCanvas (
224     const css::uno::Reference<css::rendering::XCanvas>& rxParentCanvas,
225     const css::uno::Reference<css::awt::XWindow>& rxParentWindow)
226 {
227     if (mxCanvas.is())
228     {
229         Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
230         mxCanvas = NULL;
231         if (xComponent.is())
232             xComponent->dispose();
233     }
234 
235     if (mxPresenterHelper.is() && rxParentCanvas.is() && rxParentWindow.is())
236     {
237         mxCanvas = mxPresenterHelper->createSharedCanvas (
238             Reference<rendering::XSpriteCanvas>(rxParentCanvas, UNO_QUERY),
239             rxParentWindow,
240             rxParentCanvas,
241             rxParentWindow,
242             mxWindow);
243         if (mxCanvas.is())
244         {
245             SetupButtonBitmaps();
246             SetCenter(maCenter);
247         }
248     }
249 }
250 
251 
252 
253 
GetSize(void)254 css::geometry::IntegerSize2D PresenterButton::GetSize (void)
255 {
256     if (maButtonSize.Width < 0)
257         CalculateButtonSize();
258     return maButtonSize;
259 }
260 
261 
262 
263 
264 //----- XWindowListener -------------------------------------------------------
265 
windowResized(const css::awt::WindowEvent & rEvent)266 void SAL_CALL PresenterButton::windowResized (const css::awt::WindowEvent& rEvent)
267     throw (css::uno::RuntimeException)
268 {
269     (void)rEvent;
270     ThrowIfDisposed();
271 }
272 
273 
274 
275 
276 
windowMoved(const css::awt::WindowEvent & rEvent)277 void SAL_CALL PresenterButton::windowMoved (const css::awt::WindowEvent& rEvent)
278     throw (css::uno::RuntimeException)
279 {
280     (void)rEvent;
281     ThrowIfDisposed();
282 }
283 
284 
285 
286 
windowShown(const css::lang::EventObject & rEvent)287 void SAL_CALL PresenterButton::windowShown (const css::lang::EventObject& rEvent)
288     throw (css::uno::RuntimeException)
289 {
290     (void)rEvent;
291     ThrowIfDisposed();
292 }
293 
294 
295 
296 
windowHidden(const css::lang::EventObject & rEvent)297 void SAL_CALL PresenterButton::windowHidden (const css::lang::EventObject& rEvent)
298     throw (css::uno::RuntimeException)
299 {
300     (void)rEvent;
301     ThrowIfDisposed();
302 }
303 
304 
305 
306 
307 //----- XPaintListener --------------------------------------------------------
308 
windowPaint(const css::awt::PaintEvent & rEvent)309 void SAL_CALL PresenterButton::windowPaint (const css::awt::PaintEvent& rEvent)
310     throw (css::uno::RuntimeException)
311 {
312     ThrowIfDisposed();
313     if (mxWindow.is() && mxCanvas.is())
314     {
315         Reference<rendering::XBitmap> xBitmap;
316         if (meState == PresenterBitmapDescriptor::MouseOver)
317             xBitmap = mxMouseOverBitmap;
318         else
319             xBitmap = mxNormalBitmap;
320         if ( ! xBitmap.is())
321             return;
322 
323         rendering::ViewState aViewState(
324             geometry::AffineMatrix2D(1,0,0, 0,1,0),
325             NULL);
326         rendering::RenderState aRenderState(
327             geometry::AffineMatrix2D(1,0,0, 0,1,0),
328             PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice()),
329             Sequence<double>(4),
330             rendering::CompositeOperation::SOURCE);
331 
332         mxCanvas->drawBitmap(xBitmap, aViewState, aRenderState);
333 
334         Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
335         if (xSpriteCanvas.is())
336             xSpriteCanvas->updateScreen(sal_False);
337     }
338 }
339 
340 
341 
342 
343 //----- XMouseListener --------------------------------------------------------
344 
mousePressed(const css::awt::MouseEvent & rEvent)345 void SAL_CALL PresenterButton::mousePressed (const css::awt::MouseEvent& rEvent)
346     throw(css::uno::RuntimeException)
347 {
348     (void)rEvent;
349     ThrowIfDisposed();
350 
351     meState = PresenterBitmapDescriptor::ButtonDown;
352 }
353 
354 
355 
356 
mouseReleased(const css::awt::MouseEvent & rEvent)357 void SAL_CALL PresenterButton::mouseReleased (const css::awt::MouseEvent& rEvent)
358     throw(css::uno::RuntimeException)
359 {
360     (void)rEvent;
361     ThrowIfDisposed();
362 
363     if (meState == PresenterBitmapDescriptor::ButtonDown)
364     {
365         OSL_ASSERT(mpPresenterController.get()!=NULL);
366         mpPresenterController->DispatchUnoCommand(msAction);
367 
368         meState = PresenterBitmapDescriptor::Normal;
369         Invalidate();
370     }
371 }
372 
373 
374 
375 
mouseEntered(const css::awt::MouseEvent & rEvent)376 void SAL_CALL PresenterButton::mouseEntered (const css::awt::MouseEvent& rEvent)
377     throw(css::uno::RuntimeException)
378 {
379     (void)rEvent;
380     ThrowIfDisposed();
381     meState = PresenterBitmapDescriptor::MouseOver;
382     Invalidate();
383 }
384 
385 
386 
387 
mouseExited(const css::awt::MouseEvent & rEvent)388 void SAL_CALL PresenterButton::mouseExited (const css::awt::MouseEvent& rEvent)
389     throw(css::uno::RuntimeException)
390 {
391     (void)rEvent;
392     ThrowIfDisposed();
393     meState = PresenterBitmapDescriptor::Normal;
394     Invalidate();
395 }
396 
397 
398 
399 
400 
401 //----- XMouseMotionListener --------------------------------------------------
402 
mouseMoved(const css::awt::MouseEvent & rEvent)403 void SAL_CALL PresenterButton::mouseMoved (const css::awt::MouseEvent& rEvent)
404     throw (css::uno::RuntimeException)
405 {
406     (void)rEvent;
407     ThrowIfDisposed();
408 }
409 
410 
411 
412 
mouseDragged(const css::awt::MouseEvent & rEvent)413 void SAL_CALL PresenterButton::mouseDragged (const css::awt::MouseEvent& rEvent)
414     throw (css::uno::RuntimeException)
415 {
416     (void)rEvent;
417     ThrowIfDisposed();
418 }
419 
420 
421 
422 
423 //----- lang::XEventListener --------------------------------------------------
424 
disposing(const css::lang::EventObject & rEvent)425 void SAL_CALL PresenterButton::disposing (const css::lang::EventObject& rEvent)
426     throw (css::uno::RuntimeException)
427 {
428     if (rEvent.Source == mxWindow)
429         mxWindow = NULL;
430 }
431 
432 
433 
434 
435 //-----------------------------------------------------------------------------
436 
CalculateButtonSize(void)437 css::geometry::IntegerSize2D PresenterButton::CalculateButtonSize (void)
438 {
439     if (mpFont.get()!=NULL && !mpFont->mxFont.is() && mxCanvas.is())
440         mpFont->PrepareFont(mxCanvas);
441     if (mpFont.get()==NULL || !mpFont->mxFont.is())
442         return geometry::IntegerSize2D(-1,-1);
443 
444     geometry::RealSize2D aTextSize (PresenterCanvasHelper::GetTextSize(mpFont->mxFont,msText));
445 
446     return geometry::IntegerSize2D (
447         sal_Int32(0.5 + aTextSize.Width + 2*gnHorizontalBorder),
448         sal_Int32(0.5 + aTextSize.Height + 2*gnVerticalBorder));
449 }
450 
451 
452 
453 
RenderButton(const Reference<rendering::XCanvas> & rxCanvas,const geometry::IntegerSize2D & rSize,const PresenterTheme::SharedFontDescriptor & rpFont,const PresenterBitmapDescriptor::Mode eMode,const SharedBitmapDescriptor & rpLeft,const SharedBitmapDescriptor & rpCenter,const SharedBitmapDescriptor & rpRight)454 void PresenterButton::RenderButton (
455     const Reference<rendering::XCanvas>& rxCanvas,
456     const geometry::IntegerSize2D& rSize,
457     const PresenterTheme::SharedFontDescriptor& rpFont,
458     const PresenterBitmapDescriptor::Mode eMode,
459     const SharedBitmapDescriptor& rpLeft,
460     const SharedBitmapDescriptor& rpCenter,
461     const SharedBitmapDescriptor& rpRight)
462 {
463     if ( ! rxCanvas.is())
464         return;
465 
466     const awt::Rectangle aBox(0,0, rSize.Width, rSize.Height);
467 
468     PresenterUIPainter::PaintHorizontalBitmapComposite (
469         rxCanvas,
470         aBox,
471         aBox,
472         GetBitmap(rpLeft, eMode),
473         GetBitmap(rpCenter, eMode),
474         GetBitmap(rpRight, eMode));
475 
476     if (rpFont.get()==NULL || ! rpFont->mxFont.is())
477         return;
478 
479     const rendering::StringContext aContext (msText, 0, msText.getLength());
480     const Reference<rendering::XTextLayout> xLayout (
481         rpFont->mxFont->createTextLayout(aContext,rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0));
482     const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
483 
484     rendering::RenderState aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0), NULL,
485         Sequence<double>(4), rendering::CompositeOperation::SOURCE);
486     PresenterCanvasHelper::SetDeviceColor(aRenderState, rpFont->mnColor);
487     aRenderState.AffineTransform.m02 = (rSize.Width - aTextBBox.X2 + aTextBBox.X1)/2;
488     aRenderState.AffineTransform.m12 = (rSize.Height - aTextBBox.Y2 + aTextBBox.Y1)/2 - aTextBBox.Y1;
489 
490     rxCanvas->drawText(
491         aContext,
492         rpFont->mxFont,
493         rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), NULL),
494         aRenderState,
495         rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
496 }
497 
498 
499 
500 
Invalidate(void)501 void PresenterButton::Invalidate (void)
502 {
503     mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
504 }
505 
506 
507 
508 
GetBitmap(const SharedBitmapDescriptor & mpIcon,const PresenterBitmapDescriptor::Mode eMode)509 Reference<rendering::XBitmap> PresenterButton::GetBitmap (
510     const SharedBitmapDescriptor& mpIcon,
511     const PresenterBitmapDescriptor::Mode eMode)
512 {
513     if (mpIcon.get() != NULL)
514         return mpIcon->GetBitmap(eMode);
515     else
516     {
517         OSL_ASSERT(mpIcon.get()!=NULL);
518         return NULL;
519     }
520 }
521 
522 
523 
524 
SetupButtonBitmaps(void)525 void PresenterButton::SetupButtonBitmaps (void)
526 {
527     if ( ! mxCanvas.is())
528         return;
529     if ( ! mxCanvas->getDevice().is())
530         return;
531 
532     // Get the bitmaps for the button border.
533     SharedBitmapDescriptor pLeftBitmap (mpTheme->GetBitmap(A2S("ButtonFrameLeft")));
534     SharedBitmapDescriptor pCenterBitmap(mpTheme->GetBitmap(A2S("ButtonFrameCenter")));
535     SharedBitmapDescriptor pRightBitmap(mpTheme->GetBitmap(A2S("ButtonFrameRight")));
536 
537     maButtonSize = CalculateButtonSize();
538 
539     if (maButtonSize.Height<=0 && maButtonSize.Width<= 0)
540         return;
541 
542     mxNormalBitmap = mxCanvas->getDevice()->createCompatibleAlphaBitmap(maButtonSize);
543     Reference<rendering::XCanvas> xCanvas (mxNormalBitmap, UNO_QUERY);
544     if (xCanvas.is())
545         RenderButton(
546             xCanvas,
547             maButtonSize,
548             mpFont,
549             PresenterBitmapDescriptor::Normal,
550             pLeftBitmap,
551             pCenterBitmap,
552             pRightBitmap);
553 
554     mxMouseOverBitmap = mxCanvas->getDevice()->createCompatibleAlphaBitmap(maButtonSize);
555     xCanvas = Reference<rendering::XCanvas>(mxMouseOverBitmap, UNO_QUERY);
556     if (mpMouseOverFont.get()!=NULL && !mpMouseOverFont->mxFont.is() && mxCanvas.is())
557         mpMouseOverFont->PrepareFont(mxCanvas);
558     if (xCanvas.is())
559         RenderButton(
560             xCanvas,
561             maButtonSize,
562             mpMouseOverFont,
563             PresenterBitmapDescriptor::MouseOver,
564             pLeftBitmap,
565             pCenterBitmap,
566             pRightBitmap);
567 }
568 
569 
570 
571 
GetConfigurationProperties(const css::uno::Reference<css::uno::XComponentContext> & rxComponentContext,const OUString & rsConfgurationName)572 Reference<beans::XPropertySet> PresenterButton::GetConfigurationProperties (
573     const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
574     const OUString& rsConfgurationName)
575 {
576     PresenterConfigurationAccess aConfiguration (
577         rxComponentContext,
578         PresenterConfigurationAccess::msPresenterScreenRootName,
579         PresenterConfigurationAccess::READ_ONLY);
580     return Reference<beans::XPropertySet>(
581         PresenterConfigurationAccess::Find (
582             Reference<container::XNameAccess>(
583                 aConfiguration.GetConfigurationNode(A2S("PresenterScreenSettings/Buttons")),
584                 UNO_QUERY),
585             ::boost::bind(&PresenterConfigurationAccess::IsStringPropertyEqual,
586                 rsConfgurationName,
587                 A2S("Name"),
588                 _2)),
589         UNO_QUERY);
590 }
591 
592 
593 
594 
ThrowIfDisposed(void) const595 void PresenterButton::ThrowIfDisposed (void) const
596     throw (::com::sun::star::lang::DisposedException)
597 {
598 	if (rBHelper.bDisposed || rBHelper.bInDispose)
599 	{
600         throw lang::DisposedException (
601             OUString(RTL_CONSTASCII_USTRINGPARAM(
602                 "PresenterButton object has already been disposed")),
603             const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
604     }
605 }
606 
607 
608 } } // end of namespace sdext::presenter
609