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 "PresenterClock.hxx"
28 #include "PresenterConfigurationAccess.hxx"
29 #include "PresenterGeometryHelper.hxx"
30 #include <com/sun/star/awt/InvalidateStyle.hpp>
31 #include <com/sun/star/awt/MouseButton.hpp>
32 #include <com/sun/star/awt/Point.hpp>
33 #include <com/sun/star/awt/XWindowPeer.hpp>
34 #include <com/sun/star/container/XNameAccess.hpp>
35 #include <com/sun/star/deployment/XPackageInformationProvider.hpp>
36 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
37 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
38 #include <com/sun/star/rendering/CompositeOperation.hpp>
39 #include <com/sun/star/rendering/PathCapType.hpp>
40 #include <com/sun/star/rendering/TextDirection.hpp>
41 #include <com/sun/star/rendering/XCanvasFont.hpp>
42 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
43 #include <com/sun/star/util/Color.hpp>
44 #include <osl/mutex.hxx>
45 #include <osl/time.h>
46 #include <rtl/ref.hxx>
47 #include <vos/timer.hxx>
48 #include <boost/bind.hpp>
49 #include <cmath>
50
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::drawing::framework;
54 using ::rtl::OUString;
55
56 namespace sdext { namespace presenter {
57
58
59 /** Wrapper around a library timer.
60 */
61 class PresenterClock::Timer : public vos::OTimer
62 {
63 public:
64 explicit Timer (const ::rtl::Reference<PresenterClock>& rpClock);
65 virtual ~Timer (void);
66
67 void Stop (void);
68
69 protected:
70 virtual void SAL_CALL onShot (void);
71
72 private:
73 ::rtl::Reference<PresenterClock> mpClock;
74 };
75
76
77
78
79 namespace {
80 bool GetDateTime (oslDateTime& rDateTime);
81
82 class BitmapDescriptor
83 {
84 public:
85 Reference<rendering::XBitmap> mxBitmap;
86 awt::Point maOffset;
87 Reference<rendering::XBitmap> mxScaledBitmap;
88 geometry::RealPoint2D maScaledOffset;
89 };
90 }
91
92
93
94
95 class PresenterClock::Painter
96 {
97 public:
98 virtual void Paint (
99 const Reference<rendering::XCanvas>& rxCanvas,
100 const rendering::ViewState& rViewState,
101 const rendering::RenderState& rRenderState,
102 const util::Color& rBackgroundColor,
103 const sal_Int32 nHour,
104 const sal_Int32 nMinute,
105 const sal_Int32 nSecond,
106 const bool bShowSeconds) = 0;
107 virtual void Resize (const awt::Size& rSize) = 0;
108 };
109
110
111
112
113 namespace {
114 class AnalogDefaultPainter : public PresenterClock::Painter
115 {
116 public:
117 AnalogDefaultPainter (void);
~AnalogDefaultPainter(void)118 virtual ~AnalogDefaultPainter (void) {}
119 virtual void Paint (
120 const Reference<rendering::XCanvas>& rxCanvas,
121 const rendering::ViewState& rViewState,
122 const rendering::RenderState& rRenderState,
123 const util::Color& rBackgroundColor,
124 const sal_Int32 nHour,
125 const sal_Int32 nMinute,
126 const sal_Int32 nSecond,
127 const bool bShowSeconds);
128 virtual void Resize (const awt::Size& rSize);
129 private:
130 geometry::RealPoint2D maCenter;
131 double mnOuterRadius;
132 awt::Size maSize;
133 Reference<rendering::XBitmap> mxBitmap;
134
135 /** Relative length (with respect to radius) from center to the tip of
136 the hand.
137 */
138 static const double mnRelativeHourHandLength;
139 /** Relative length (with respect to radius) from center to the
140 oposing end of the tip of the hand.
141 */
142 static const double mnRelativeHourHandLength2;
143 static const double mnRelativeHourHandWidth;
144 static const double mnRelativeMinuteHandLength;
145 static const double mnRelativeMinuteHandLength2;
146 static const double mnRelativeMinuteHandWidth;
147 static const double mnRelativeSecondHandLength;
148 static const double mnRelativeSecondHandLength2;
149 static const double mnRelativeSecondHandWidth;
150
151 void PaintAngledLine (
152 const double nAngle,
153 const double nInnerRadius,
154 const double nOuterRadius,
155 const double nStrokeWidth,
156 const Reference<rendering::XCanvas>& rxCanvas,
157 const rendering::ViewState& rViewState,
158 const rendering::RenderState& rRenderState);
159 };
160
161
162 class AnalogBitmapPainter : public PresenterClock::Painter
163 {
164 public:
165 AnalogBitmapPainter(
166 const Reference<XComponentContext>& rxContext,
167 const OUString& rsThemeName);
~AnalogBitmapPainter(void)168 virtual ~AnalogBitmapPainter (void) {}
169 virtual void Paint (
170 const Reference<rendering::XCanvas>& rxCanvas,
171 const rendering::ViewState& rViewState,
172 const rendering::RenderState& rRenderState,
173 const util::Color& rBackgroundColor,
174 const sal_Int32 nHour,
175 const sal_Int32 nMinute,
176 const sal_Int32 nSecond,
177 const bool bShowSeconds);
178 virtual void Resize (const awt::Size& rSize);
179 private:
180 css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
181 const OUString msThemeName;
182 bool mbThemeLoaded;
183 bool mbThemeLoadingFailed;
184 geometry::RealPoint2D maCenter;
185 double mnOuterRadius;
186 BitmapDescriptor maFace;
187 BitmapDescriptor maMinuteHand;
188 BitmapDescriptor maHourHand;
189
190 void PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas);
191 Reference<container::XNameAccess> GetTheme (
192 PresenterConfigurationAccess& rConfiguration);
193 bool ThemeNameComparator (
194 const ::rtl::OUString& rsKey,
195 const Reference<container::XNameAccess>& rxCandidate,
196 const ::rtl::OUString& rsCurrentThemeName);
197 void LoadBitmaps (
198 PresenterConfigurationAccess& rConfiguration,
199 const Reference<container::XNameAccess>& rxNameAccess,
200 const Reference<rendering::XCanvas>& rxCanvas);
201 void LoadBitmap (
202 const OUString& rsKey,
203 const ::std::vector<Any>& rValues,
204 const Reference<container::XNameAccess>& rxBitmapLoader);
205 void ScaleBitmaps (void);
206 };
207
208
209 class DigitalDefaultPainter : public PresenterClock::Painter
210 {
211 public:
212 DigitalDefaultPainter (
213 const ::rtl::Reference<PresenterController>& rpPresenterController,
214 const Reference<XResourceId>& rxViewId);
215 virtual ~DigitalDefaultPainter (void);
216
217 virtual void Paint (
218 const Reference<rendering::XCanvas>& rxCanvas,
219 const rendering::ViewState& rViewState,
220 const rendering::RenderState& rRenderState,
221 const util::Color& rBackgroundColor,
222 const sal_Int32 nHour,
223 const sal_Int32 nMinute,
224 const sal_Int32 nSecond,
225 const bool bShowSeconds);
226 virtual void Resize (const awt::Size& rSize);
227
228 private:
229 ::rtl::Reference<PresenterController> mpPresenterController;
230 bool mbIs24HourFormat;
231 bool mbIsAdaptFontSize;
232 Reference<rendering::XCanvasFont> mxFont;
233 awt::Size maWindowSize;
234 OUString msViewURL;
235
236 void CreateFont (
237 const Reference<rendering::XCanvas>& rxCanvas,
238 const bool bIsShowSeconds);
239 };
240
241
242 } // end of anonymous namespace
243
244
245
246
247 //===== PresenterClock =================================================================
248
Create(const Reference<XComponentContext> & rxContext,const Reference<XResourceId> & rxViewId,const Reference<frame::XController> & rxController,const::rtl::Reference<PresenterController> & rpPresenterController)249 ::rtl::Reference<PresenterClock> PresenterClock::Create (
250 const Reference<XComponentContext>& rxContext,
251 const Reference<XResourceId>& rxViewId,
252 const Reference<frame::XController>& rxController,
253 const ::rtl::Reference<PresenterController>& rpPresenterController)
254 {
255 ::rtl::Reference<PresenterClock> pClock (new PresenterClock(
256 rxContext,
257 rxViewId,
258 rxController,
259 rpPresenterController));
260 pClock->LateInit();
261 return pClock;
262 }
263
264
265
266
PresenterClock(const Reference<XComponentContext> & rxContext,const Reference<XResourceId> & rxViewId,const Reference<frame::XController> & rxController,const::rtl::Reference<PresenterController> & rpPresenterController)267 PresenterClock::PresenterClock (
268 const Reference<XComponentContext>& rxContext,
269 const Reference<XResourceId>& rxViewId,
270 const Reference<frame::XController>& rxController,
271 const ::rtl::Reference<PresenterController>& rpPresenterController)
272 : PresenterClockInterfaceBase(m_aMutex),
273 mxComponentContext(rxContext),
274 mxViewId(rxViewId),
275 mxWindow(),
276 mxCanvas(),
277 mxPane(),
278 mpPresenterController(rpPresenterController),
279 mbIsResizePending(true),
280 maViewState(),
281 maRenderState(),
282 mpTimer(),
283 mpClockPainter(),
284 mpClockPainter2(),
285 mnMode(1),
286 mnHour(-1),
287 mnMinute(-1),
288 mnSecond(-1),
289 mbIsShowSeconds(true)
290 {
291 SetMode(mnMode);
292
293 maViewState.AffineTransform = geometry::AffineMatrix2D(1,0,0, 0,1,0);
294 maRenderState.AffineTransform = geometry::AffineMatrix2D(1,0,0, 0,1,0);
295 maRenderState.DeviceColor = Sequence<double>(4);
296 PresenterCanvasHelper::SetDeviceColor(maRenderState, util::Color(0x00000000));
297
298 try
299 {
300
301 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
302 Reference<XConfigurationController> xCC (xCM->getConfigurationController(), UNO_QUERY_THROW);
303 mxPane = Reference<XPane>(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
304
305 mxWindow = mxPane->getWindow();
306 if (mxWindow.is())
307 {
308 mxWindow->addPaintListener(this);
309 mxWindow->addWindowListener(this);
310 mxWindow->addMouseListener(this);
311 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
312 if (xPeer.is())
313 xPeer->setBackground(util::Color(0xff000000));
314 mxWindow->setVisible(sal_True);
315 }
316
317 Resize();
318 }
319 catch (RuntimeException&)
320 {
321 disposing();
322 throw;
323 }
324 }
325
326
327
328
~PresenterClock(void)329 PresenterClock::~PresenterClock (void)
330 {
331 }
332
333
334
335
LateInit(void)336 void PresenterClock::LateInit (void)
337 {
338 mpTimer = new Timer(this);
339 }
340
341
342
343
disposing(void)344 void SAL_CALL PresenterClock::disposing (void)
345 {
346 // osl::MutexGuard aGuard (m_aMutex);
347 if (mpTimer != NULL)
348 {
349 mpTimer->Stop();
350 }
351 if (mxWindow.is())
352 {
353 mxWindow->removePaintListener(this);
354 mxWindow->removeWindowListener(this);
355 mxWindow->removeMouseListener(this);
356 mxWindow = NULL;
357 }
358 mxCanvas = NULL;
359 mxViewId = NULL;
360 }
361
362
363
364
UpdateTime(void)365 void PresenterClock::UpdateTime (void)
366 {
367 // Get current time and check whether it is different from last time.
368 oslDateTime aDateTime;
369 if ( ! GetDateTime(aDateTime))
370 return;
371 if (aDateTime.Hours != mnHour
372 || aDateTime.Minutes != mnMinute
373 || aDateTime.Seconds != mnSecond)
374 {
375 mnHour = aDateTime.Hours % 24;
376 mnMinute = aDateTime.Minutes % 60;
377 mnSecond = aDateTime.Seconds % 60;
378
379 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
380 if (xPeer.is())
381 xPeer->invalidate(awt::InvalidateStyle::NOERASE |
382 awt::InvalidateStyle::UPDATE);
383 }
384 }
385
386
387
388
389 //----- lang::XEventListener -------------------------------------------------
390
disposing(const lang::EventObject & rEventObject)391 void SAL_CALL PresenterClock::disposing (const lang::EventObject& rEventObject)
392 throw (RuntimeException)
393 {
394 // ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
395 // osl::MutexGuard aGuard (m_aMutex);
396
397 if (rEventObject.Source == mxWindow)
398 {
399 mxWindow = NULL;
400 if (mpTimer != NULL)
401 mpTimer->Stop();
402 }
403 }
404
405
406
407
408 //----- XPaintListener --------------------------------------------------------
409
windowPaint(const awt::PaintEvent & rEvent)410 void SAL_CALL PresenterClock::windowPaint (const awt::PaintEvent& rEvent)
411 throw (RuntimeException)
412 {
413 (void)rEvent;
414 ThrowIfDisposed();
415 ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
416 Paint(rEvent.UpdateRect);
417 }
418
419
420
421
422 //----- XWindowListener -------------------------------------------------------
423
windowResized(const awt::WindowEvent & rEvent)424 void SAL_CALL PresenterClock::windowResized (const awt::WindowEvent& rEvent)
425 throw (RuntimeException)
426 {
427 (void)rEvent;
428 mbIsResizePending = true;
429 }
430
431
432
433
windowMoved(const awt::WindowEvent & rEvent)434 void SAL_CALL PresenterClock::windowMoved (const awt::WindowEvent& rEvent)
435 throw (RuntimeException)
436 {
437 (void)rEvent;
438 mbIsResizePending = true;
439 }
440
441
442
443
windowShown(const lang::EventObject & rEvent)444 void SAL_CALL PresenterClock::windowShown (const lang::EventObject& rEvent)
445 throw (RuntimeException)
446 {
447 (void)rEvent;
448 mbIsResizePending = true;
449 }
450
451
452
453
windowHidden(const lang::EventObject & rEvent)454 void SAL_CALL PresenterClock::windowHidden (const lang::EventObject& rEvent)
455 throw (RuntimeException)
456 {
457 (void)rEvent;
458 }
459
460
461
462
463 //----- XMouseListener --------------------------------------------------------
464
mousePressed(const css::awt::MouseEvent & rEvent)465 void SAL_CALL PresenterClock::mousePressed (const css::awt::MouseEvent& rEvent)
466 throw (css::uno::RuntimeException)
467 {
468 (void)rEvent;
469 if (rEvent.Buttons == awt::MouseButton::LEFT)
470 {
471 SetMode(mnMode+1);
472 }
473 }
474
475
476
477
mouseReleased(const css::awt::MouseEvent & rEvent)478 void SAL_CALL PresenterClock::mouseReleased (const css::awt::MouseEvent& rEvent)
479 throw (css::uno::RuntimeException)
480 {
481 (void)rEvent;
482 }
483
484
485
486
mouseEntered(const css::awt::MouseEvent & rEvent)487 void SAL_CALL PresenterClock::mouseEntered (const css::awt::MouseEvent& rEvent)
488 throw (css::uno::RuntimeException)
489 {
490 (void)rEvent;
491 }
492
493
494
495
mouseExited(const css::awt::MouseEvent & rEvent)496 void SAL_CALL PresenterClock::mouseExited (const css::awt::MouseEvent& rEvent)
497 throw (css::uno::RuntimeException)
498 {
499 (void)rEvent;
500 }
501
502
503
504
505 //----- XResourceId -----------------------------------------------------------
506
getResourceId(void)507 Reference<XResourceId> SAL_CALL PresenterClock::getResourceId (void)
508 throw (RuntimeException)
509 {
510 return mxViewId;
511 }
512
513
514
515
isAnchorOnly(void)516 sal_Bool SAL_CALL PresenterClock::isAnchorOnly (void)
517 throw (RuntimeException)
518 {
519 return false;
520 }
521
522
523
524
525 //-----------------------------------------------------------------------------
526
Resize(void)527 void PresenterClock::Resize (void)
528 {
529 if (mxPane.is())
530 mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
531 if (mxWindow.is() && mxCanvas.is())
532 {
533 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
534 const awt::Size aWindowSize(aWindowBox.Width,aWindowBox.Height);
535 if (mpClockPainter.get() != NULL)
536 mpClockPainter->Resize(aWindowSize);
537 if (mpClockPainter2.get() != NULL)
538 mpClockPainter2->Resize(aWindowSize);
539 mbIsResizePending = false;
540 }
541 }
542
543
544
545
Paint(const awt::Rectangle & rUpdateBox)546 void PresenterClock::Paint (const awt::Rectangle& rUpdateBox)
547 {
548 if ( ! mxCanvas.is() && mxPane.is())
549 mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
550 if ( ! mxWindow.is()
551 || ! mxCanvas.is()
552 || ! mxCanvas->getDevice().is())
553 {
554 return;
555 }
556
557 try
558 {
559 if (mbIsResizePending)
560 Resize();
561
562 Reference<rendering::XPolyPolygon2D> xUpdatePolygon (
563 PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
564
565 Clear(xUpdatePolygon);
566
567 if (mpClockPainter.get() != NULL)
568 mpClockPainter->Paint(mxCanvas,
569 maViewState,
570 maRenderState,
571 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
572 mnHour,
573 mnMinute,
574 mnSecond,
575 mbIsShowSeconds);
576
577 if (mpClockPainter2.get() != NULL)
578 mpClockPainter2->Paint(
579 mxCanvas,
580 maViewState,
581 maRenderState,
582 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
583 mnHour,
584 mnMinute,
585 mnSecond,
586 mbIsShowSeconds);
587 }
588 catch (RuntimeException& e)
589 {
590 (void)e;
591 }
592
593 // Make the back buffer visible.
594 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
595 if (xSpriteCanvas.is())
596 xSpriteCanvas->updateScreen(sal_False);
597 }
598
599
600
601
Clear(const Reference<rendering::XPolyPolygon2D> & rxUpdatePolygon)602 void PresenterClock::Clear (const Reference<rendering::XPolyPolygon2D>& rxUpdatePolygon)
603 {
604 rendering::RenderState aRenderState = maRenderState;
605 const sal_Int32 nColor (
606 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()));
607 aRenderState.DeviceColor[0] = ((nColor&0x00ff0000) >> 16) / 255.0;
608 aRenderState.DeviceColor[1] = ((nColor&0x0000ff00) >> 8) / 255.0;
609 aRenderState.DeviceColor[2] = ((nColor&0x000000ff) >> 0) / 255.0;
610
611 if (rxUpdatePolygon.is())
612 mxCanvas->fillPolyPolygon(
613 rxUpdatePolygon,
614 maViewState,
615 aRenderState);
616 }
617
618
619
620
SetMode(const sal_Int32 nMode)621 void PresenterClock::SetMode (const sal_Int32 nMode)
622 {
623 mnMode = nMode % 3;
624
625 switch (mnMode)
626 {
627 case 0:
628 mpClockPainter.reset(
629 new AnalogBitmapPainter(
630 mxComponentContext,
631 OUString::createFromAscii("ClockTheme")));
632 mpClockPainter2.reset();
633 break;
634
635 case 1:
636 mpClockPainter.reset();
637 mpClockPainter2.reset(new AnalogDefaultPainter());
638 break;
639
640 case 2:
641 mpClockPainter.reset();
642 mpClockPainter2.reset(new DigitalDefaultPainter(mpPresenterController, mxViewId));
643 break;
644
645 case 3:
646 mpClockPainter.reset(
647 new AnalogBitmapPainter(
648 mxComponentContext,
649 OUString::createFromAscii("ClockTheme")));
650 mpClockPainter2.reset(new AnalogDefaultPainter());
651 break;
652 }
653 Resize();
654 }
655
656
657
658
ThrowIfDisposed(void)659 void PresenterClock::ThrowIfDisposed (void)
660 throw (::com::sun::star::lang::DisposedException)
661 {
662 if (rBHelper.bDisposed || rBHelper.bInDispose)
663 {
664 throw lang::DisposedException (
665 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
666 "PresenterClock object has already been disposed")),
667 static_cast<uno::XWeak*>(this));
668 }
669 }
670
671
672
673
674 //===== Timer =================================================================
675
Timer(const::rtl::Reference<PresenterClock> & rpClock)676 PresenterClock::Timer::Timer (const ::rtl::Reference<PresenterClock>& rpClock)
677 : OTimer(vos::TTimeValue(10), vos::TTimeValue(100/*ms*/)),
678 mpClock(rpClock)
679 {
680 acquire();
681 start();
682 }
683
684
685
686
~Timer(void)687 PresenterClock::Timer::~Timer (void)
688 {
689 if (mpClock.is())
690 Stop();
691 }
692
693
694
695
Stop(void)696 void PresenterClock::Timer::Stop (void)
697 {
698 mpClock = NULL;
699 stop();
700 release();
701 }
702
703
704
705
onShot(void)706 void SAL_CALL PresenterClock::Timer::onShot (void)
707 {
708 if (mpClock.get() != NULL)
709 mpClock->UpdateTime();
710 }
711
712
713
714 namespace {
715
716 //=============================================================================
717
GetDateTime(oslDateTime & rDateTime)718 bool GetDateTime (oslDateTime& rDateTime)
719 {
720 TimeValue aSystemTime;
721 TimeValue aLocalTime;
722 if (osl_getSystemTime(&aSystemTime))
723 if (osl_getLocalTimeFromSystemTime(&aSystemTime, &aLocalTime))
724 if (osl_getDateTimeFromTimeValue(&aLocalTime, &rDateTime))
725 return true;
726 return false;
727 }
728
729
730
731
732 //===== AnalogDefaultPainter ==================================================
733
734 const double AnalogDefaultPainter::mnRelativeHourHandLength = 0.65;
735 const double AnalogDefaultPainter::mnRelativeHourHandLength2 (-0.1);
736 const double AnalogDefaultPainter::mnRelativeHourHandWidth (0.055);
737 const double AnalogDefaultPainter::mnRelativeMinuteHandLength (-0.2);
738 const double AnalogDefaultPainter::mnRelativeMinuteHandLength2 (0.85);
739 const double AnalogDefaultPainter::mnRelativeMinuteHandWidth (0.025);
740 const double AnalogDefaultPainter::mnRelativeSecondHandLength (-0.25);
741 const double AnalogDefaultPainter::mnRelativeSecondHandLength2 (0.95);
742 const double AnalogDefaultPainter::mnRelativeSecondHandWidth (0.015);
743
AnalogDefaultPainter(void)744 AnalogDefaultPainter::AnalogDefaultPainter (void)
745 : maCenter(0,0),
746 mnOuterRadius(0),
747 maSize(0,0),
748 mxBitmap()
749 {
750 }
751
752
753
754
Paint(const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState,const rendering::RenderState & rRenderState,const util::Color & rBackgroundColor,const sal_Int32 nHour,const sal_Int32 nMinute,const sal_Int32 nSecond,const bool bShowSeconds)755 void AnalogDefaultPainter::Paint (
756 const Reference<rendering::XCanvas>& rxCanvas,
757 const rendering::ViewState& rViewState,
758 const rendering::RenderState& rRenderState,
759 const util::Color& rBackgroundColor,
760 const sal_Int32 nHour,
761 const sal_Int32 nMinute,
762 const sal_Int32 nSecond,
763 const bool bShowSeconds)
764 {
765 double nInnerRadius (0);
766 double nStrokeWidth (0.1);
767 const double nClockSize (2*mnOuterRadius);
768
769 // Some antialiasing is created by painting into a bitmap twice the
770 // screen size and then scaling it down.
771 const sal_Int32 nSuperSampleFactor (2);
772 if ( ! mxBitmap.is())
773 {
774 mxBitmap = (rxCanvas->getDevice()->createCompatibleBitmap(
775 geometry::IntegerSize2D(
776 maSize.Width*nSuperSampleFactor,
777 maSize.Height*nSuperSampleFactor)));
778 }
779 Reference<rendering::XCanvas> xBitmapCanvas (mxBitmap, UNO_QUERY);
780 rendering::RenderState aRenderState(rRenderState);
781 aRenderState.AffineTransform.m00 = nSuperSampleFactor;
782 aRenderState.AffineTransform.m11 = nSuperSampleFactor;
783
784 // Clear the background.
785 aRenderState.DeviceColor[0] = ((rBackgroundColor&0x00ff0000) >> 16) / 255.0;
786 aRenderState.DeviceColor[1] = ((rBackgroundColor&0x0000ff00) >> 8) / 255.0;
787 aRenderState.DeviceColor[2] = ((rBackgroundColor&0x000000ff) >> 0) / 255.0;
788 Reference<rendering::XPolyPolygon2D> xPolygon (
789 PresenterGeometryHelper::CreatePolygon(
790 awt::Rectangle(0,0,maSize.Width,maSize.Height),
791 xBitmapCanvas->getDevice()));
792 if (xPolygon.is())
793 xBitmapCanvas->fillPolyPolygon(xPolygon, rViewState, aRenderState);
794
795 // Clock face and clock hands are painted in black.
796 aRenderState.DeviceColor[0] = 0;
797 aRenderState.DeviceColor[1] = 0;
798 aRenderState.DeviceColor[2] = 0;
799
800 // Paint the clock face.
801 for (sal_Int32 nHourMark=0; nHourMark<12; ++nHourMark)
802 {
803 if (nHourMark%3 == 0)
804 {
805 nInnerRadius = 0.7 * mnOuterRadius;
806 nStrokeWidth = 0.05 * nClockSize;
807 }
808 else
809 {
810 nInnerRadius = 0.8 * mnOuterRadius;
811 nStrokeWidth = 0.03 * nClockSize;
812 }
813
814 const double nAngle (nHourMark * 2 * M_PI / 12);
815 PaintAngledLine(nAngle, nInnerRadius, mnOuterRadius, nStrokeWidth,
816 xBitmapCanvas, rViewState, aRenderState);
817 }
818
819 // Paint the hour hand.
820 const double nHoursAngle (((nHour%12)+nMinute/60.0) * 2 * M_PI / 12);
821 PaintAngledLine(nHoursAngle,
822 mnRelativeHourHandLength2*mnOuterRadius,
823 mnRelativeHourHandLength*mnOuterRadius,
824 mnRelativeHourHandWidth*nClockSize,
825 xBitmapCanvas, rViewState, aRenderState);
826
827 // Paint the minute hand.
828 const double nMinutesAngle ((nMinute+nSecond/60.0) * 2 * M_PI / 60);
829 PaintAngledLine(nMinutesAngle,
830 mnRelativeMinuteHandLength2*mnOuterRadius,
831 mnRelativeMinuteHandLength*mnOuterRadius,
832 mnRelativeMinuteHandWidth*nClockSize,
833 xBitmapCanvas, rViewState, aRenderState);
834
835 // Optionally paint the second hand.
836 if (bShowSeconds)
837 {
838 const double nSecondsAngle (nSecond * 2 * M_PI / 60);
839 PaintAngledLine(nSecondsAngle,
840 mnRelativeSecondHandLength2*mnOuterRadius,
841 mnRelativeSecondHandLength*mnOuterRadius,
842 mnRelativeSecondHandWidth*nClockSize,
843 xBitmapCanvas, rViewState, aRenderState);
844 }
845
846 aRenderState.AffineTransform.m00 = 1.0 / nSuperSampleFactor;
847 aRenderState.AffineTransform.m11 = 1.0 / nSuperSampleFactor;
848 rxCanvas->drawBitmap(mxBitmap,rViewState,aRenderState);
849 }
850
851
852
853
PaintAngledLine(const double nAngle,const double nInnerRadius,const double nOuterRadius,const double nStrokeWidth,const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState,const rendering::RenderState & rRenderState)854 void AnalogDefaultPainter::PaintAngledLine (
855 const double nAngle,
856 const double nInnerRadius,
857 const double nOuterRadius,
858 const double nStrokeWidth,
859 const Reference<rendering::XCanvas>& rxCanvas,
860 const rendering::ViewState& rViewState,
861 const rendering::RenderState& rRenderState)
862 {
863 if ( ! rxCanvas.is())
864 return;
865
866 rendering::StrokeAttributes aStrokeAttributes;
867 aStrokeAttributes.StrokeWidth = nStrokeWidth;
868 aStrokeAttributes.StartCapType = rendering::PathCapType::SQUARE;
869 aStrokeAttributes.EndCapType = rendering::PathCapType::SQUARE;
870 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
871 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
872 const double nCos (cos(nAngle - M_PI/2));
873 const double nSin (sin(nAngle - M_PI/2));
874
875 Sequence<Sequence<geometry::RealPoint2D> > aPoints(1);
876 aPoints[0] = Sequence<geometry::RealPoint2D>(2);
877 aPoints[0][0] = geometry::RealPoint2D(
878 maCenter.X + nInnerRadius*nCos + 0.5,
879 maCenter.Y + nInnerRadius*nSin + 0.5);
880 aPoints[0][1] = geometry::RealPoint2D(
881 maCenter.X + nOuterRadius*nCos + 0.5,
882 maCenter.Y + nOuterRadius*nSin + 0.5);
883
884 Reference<rendering::XPolyPolygon2D> xLine (
885 rxCanvas->getDevice()->createCompatibleLinePolyPolygon(aPoints),
886 UNO_QUERY);
887 if ( ! xLine.is())
888 return;
889 rxCanvas->strokePolyPolygon(
890 xLine,
891 rViewState,
892 rRenderState,
893 aStrokeAttributes);
894 }
895
896
897
898
Resize(const awt::Size & rWindowSize)899 void AnalogDefaultPainter::Resize (const awt::Size& rWindowSize)
900 {
901 maSize = rWindowSize;
902 maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
903 mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
904 mxBitmap = NULL;
905 }
906
907
908
909
910 //===== AnalogBitmapPainter ===================================================
911
AnalogBitmapPainter(const Reference<XComponentContext> & rxContext,const OUString & rsThemeName)912 AnalogBitmapPainter::AnalogBitmapPainter (
913 const Reference<XComponentContext>& rxContext,
914 const OUString& rsThemeName)
915 : mxComponentContext(rxContext),
916 msThemeName(rsThemeName),
917 mbThemeLoaded(false),
918 mbThemeLoadingFailed(false),
919 maCenter(),
920 mnOuterRadius(),
921 maFace(),
922 maMinuteHand(),
923 maHourHand()
924 {
925 }
926
927
928
929
Paint(const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState,const rendering::RenderState & rRenderState,const util::Color & rBackgroundColor,const sal_Int32 nHour,const sal_Int32 nMinute,const sal_Int32 nSecond,const bool bShowSeconds)930 void AnalogBitmapPainter::Paint (
931 const Reference<rendering::XCanvas>& rxCanvas,
932 const rendering::ViewState& rViewState,
933 const rendering::RenderState& rRenderState,
934 const util::Color& rBackgroundColor,
935 const sal_Int32 nHour,
936 const sal_Int32 nMinute,
937 const sal_Int32 nSecond,
938 const bool bShowSeconds)
939 {
940 (void)rBackgroundColor;
941 (void)nSecond;
942 (void)bShowSeconds;
943
944 if ( ! rxCanvas.is())
945 return;
946
947 rendering::RenderState aRenderState = rRenderState;
948
949 try
950 {
951 PrepareBitmaps(rxCanvas);
952
953 if (maFace.mxScaledBitmap.is())
954 {
955 aRenderState.AffineTransform = geometry::AffineMatrix2D(
956 1,0, maCenter.X - maFace.maScaledOffset.X,
957 0,1, maCenter.Y - maFace.maScaledOffset.Y);
958 rxCanvas->drawBitmap(maFace.mxScaledBitmap, rViewState, aRenderState);
959 }
960
961 if (maMinuteHand.mxScaledBitmap.is())
962 {
963 const double nMinuteAngle ((nMinute+nSecond/60.0) * 2.0 * M_PI / 60.0);
964 const double nCos (cos(nMinuteAngle - M_PI/2));
965 const double nSin (sin(nMinuteAngle - M_PI/2));
966 aRenderState.AffineTransform = geometry::AffineMatrix2D(
967 nCos,
968 -nSin,
969 -maMinuteHand.maScaledOffset.X*nCos
970 + maMinuteHand.maScaledOffset.Y*nSin+maCenter.X,
971 nSin,
972 nCos,
973 -maMinuteHand.maScaledOffset.X*nSin
974 - maMinuteHand.maScaledOffset.Y*nCos+maCenter.Y);
975 rxCanvas->drawBitmap(maMinuteHand.mxScaledBitmap, rViewState, aRenderState);
976 }
977
978 if (maHourHand.mxScaledBitmap.is())
979 {
980 const double nHoursAngle ((nHour%12+nMinute/60.0) * 2.0 * M_PI / 12.0);
981 const double nCos (cos(nHoursAngle - M_PI/2));
982 const double nSin (sin(nHoursAngle - M_PI/2));
983 aRenderState.AffineTransform = geometry::AffineMatrix2D(
984 nCos,
985 -nSin,
986 -maHourHand.maScaledOffset.X*nCos+maHourHand.maScaledOffset.Y*nSin+maCenter.X,
987 nSin,
988 nCos,
989 -maHourHand.maScaledOffset.X*nSin-maHourHand.maScaledOffset.Y*nCos+maCenter.Y);
990 rxCanvas->drawBitmap(maHourHand.mxScaledBitmap, rViewState, aRenderState);
991 }
992 }
993 catch(beans::UnknownPropertyException&)
994 {
995 }
996 catch(RuntimeException&)
997 {
998 }
999 }
1000
1001
1002
1003
Resize(const awt::Size & rWindowSize)1004 void AnalogBitmapPainter::Resize (const awt::Size& rWindowSize)
1005 {
1006 maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
1007 mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
1008 maFace.mxScaledBitmap = NULL;
1009 maHourHand.mxScaledBitmap = NULL;
1010 maMinuteHand.mxScaledBitmap = NULL;
1011 }
1012
1013
1014
1015
PrepareBitmaps(const Reference<rendering::XCanvas> & rxCanvas)1016 void AnalogBitmapPainter::PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas)
1017 {
1018 if (mbThemeLoadingFailed)
1019 {
1020 // Theme loading has failed previously. Do not try a second time.
1021 return;
1022 }
1023 if ( ! rxCanvas.is())
1024 {
1025 // No canvas => bitmaps can neither be loaded, transformed into the
1026 // right format, nor can they be painted.
1027 return;
1028 }
1029
1030 if ( ! mbThemeLoaded)
1031 {
1032 mbThemeLoaded = true;
1033
1034 // Get access to the clock bitmaps in the configuration.
1035 PresenterConfigurationAccess aConfiguration (
1036 mxComponentContext,
1037 OUString::createFromAscii("org.openoffice.Office.PresenterScreen"),
1038 PresenterConfigurationAccess::READ_ONLY);
1039
1040 Reference<container::XNameAccess> xTheme (GetTheme(aConfiguration));
1041 if (xTheme.is())
1042 LoadBitmaps(aConfiguration, xTheme, rxCanvas);
1043 else
1044 mbThemeLoadingFailed = true;
1045 }
1046
1047 ScaleBitmaps();
1048 }
1049
1050
1051
1052
GetTheme(PresenterConfigurationAccess & rConfiguration)1053 Reference<container::XNameAccess> AnalogBitmapPainter::GetTheme (
1054 PresenterConfigurationAccess& rConfiguration)
1055 {
1056 Reference<container::XNameAccess> xTheme;
1057
1058 // Get root of clock themes.
1059 Reference<container::XHierarchicalNameAccess> xClock (
1060 rConfiguration.GetConfigurationNode(
1061 OUString::createFromAscii("PresenterScreenSettings/AnalogBitmapClock")),
1062 UNO_QUERY);
1063
1064 // Determine the name of the theme to use.
1065 OUString sCurrentThemeName (OUString::createFromAscii("DefaultTheme"));
1066 rConfiguration.GetConfigurationNode(
1067 xClock,
1068 OUString::createFromAscii("CurrentTheme")) >>= sCurrentThemeName;
1069
1070 // Load the clock theme.
1071 Reference<container::XNameAccess> xThemes (
1072 rConfiguration.GetConfigurationNode(
1073 xClock,
1074 OUString::createFromAscii("Themes")),
1075 UNO_QUERY);
1076 if (xThemes.is())
1077 {
1078 xTheme = Reference<container::XNameAccess>(
1079 PresenterConfigurationAccess::Find(
1080 xThemes,
1081 ::boost::bind(&AnalogBitmapPainter::ThemeNameComparator,
1082 this, _1, _2, sCurrentThemeName)),
1083 UNO_QUERY);
1084 }
1085
1086 return xTheme;
1087 }
1088
1089
1090
1091
ThemeNameComparator(const OUString & rsKey,const Reference<container::XNameAccess> & rxCandidate,const OUString & rsCurrentThemeName)1092 bool AnalogBitmapPainter::ThemeNameComparator (
1093 const OUString& rsKey,
1094 const Reference<container::XNameAccess>& rxCandidate,
1095 const OUString& rsCurrentThemeName)
1096 {
1097 (void)rsKey;
1098 if (rxCandidate.is())
1099 {
1100 OUString sThemeName;
1101 if (rxCandidate->getByName(OUString::createFromAscii("ThemeName")) >>= sThemeName)
1102 {
1103 return sThemeName == rsCurrentThemeName;
1104 }
1105 }
1106 return false;
1107 }
1108
1109
1110
1111
1112
LoadBitmaps(PresenterConfigurationAccess & rConfiguration,const Reference<container::XNameAccess> & rxClockTheme,const Reference<rendering::XCanvas> & rxCanvas)1113 void AnalogBitmapPainter::LoadBitmaps (
1114 PresenterConfigurationAccess& rConfiguration,
1115 const Reference<container::XNameAccess>& rxClockTheme,
1116 const Reference<rendering::XCanvas>& rxCanvas)
1117 {
1118 (void)rConfiguration;
1119 // Create the bitmap loader.
1120 Reference<lang::XMultiComponentFactory> xFactory (
1121 mxComponentContext->getServiceManager(), UNO_QUERY);
1122 if ( ! xFactory.is())
1123 return;
1124 Sequence<Any> aArguments(1);
1125 aArguments[0] <<= rxCanvas;
1126 Reference<container::XNameAccess> xBitmapLoader(
1127 xFactory->createInstanceWithArgumentsAndContext(
1128 OUString::createFromAscii("com.sun.star.drawing.PresenterWorkaroundService"),
1129 aArguments,
1130 mxComponentContext),
1131 UNO_QUERY);
1132 if ( ! xBitmapLoader.is())
1133 return;
1134
1135
1136 // Iterate over all entries in the bitmap list and load the bitmaps.
1137 Reference<container::XNameAccess> xBitmaps (
1138 rxClockTheme->getByName(OUString::createFromAscii("Bitmaps")),
1139 UNO_QUERY);
1140 ::std::vector<rtl::OUString> aBitmapProperties (3);
1141 aBitmapProperties[0] = OUString::createFromAscii("FileName");
1142 aBitmapProperties[1] = OUString::createFromAscii("XOffset");
1143 aBitmapProperties[2] = OUString::createFromAscii("YOffset");
1144 PresenterConfigurationAccess::ForAll(
1145 xBitmaps,
1146 aBitmapProperties,
1147 ::boost::bind(&AnalogBitmapPainter::LoadBitmap,
1148 this,
1149 _1,
1150 _2,
1151 xBitmapLoader));
1152 }
1153
1154
1155
1156
LoadBitmap(const OUString & rsKey,const::std::vector<Any> & rValues,const Reference<container::XNameAccess> & rxBitmapLoader)1157 void AnalogBitmapPainter::LoadBitmap (
1158 const OUString& rsKey,
1159 const ::std::vector<Any>& rValues,
1160 const Reference<container::XNameAccess>& rxBitmapLoader)
1161 {
1162 if (rValues.size() == 3)
1163 {
1164 BitmapDescriptor* pDescriptor = NULL;
1165 if (rsKey == OUString::createFromAscii("Face"))
1166 pDescriptor = &maFace;
1167 else if (rsKey == OUString::createFromAscii("HourHand"))
1168 pDescriptor = &maHourHand;
1169 else if (rsKey == OUString::createFromAscii("MinuteHand"))
1170 pDescriptor = &maMinuteHand;
1171
1172 if (pDescriptor == NULL)
1173 return;
1174
1175 OUString sFileName;
1176 if ( ! (rValues[0] >>= sFileName))
1177 return;
1178
1179 rValues[1] >>= pDescriptor->maOffset.X;
1180 rValues[2] >>= pDescriptor->maOffset.Y;
1181
1182 pDescriptor->mxBitmap = Reference<rendering::XBitmap>(
1183 rxBitmapLoader->getByName(sFileName), UNO_QUERY);
1184
1185 if ( ! pDescriptor->mxBitmap.is())
1186 mbThemeLoadingFailed = true;
1187 }
1188 }
1189
1190
1191
1192
ScaleBitmaps(void)1193 void AnalogBitmapPainter::ScaleBitmaps (void)
1194 {
1195 if (mbThemeLoadingFailed)
1196 return;
1197 if ( ! maFace.mxBitmap.is())
1198 return;
1199
1200 const geometry::IntegerSize2D aFaceSize (maFace.mxBitmap->getSize());
1201 const sal_Int32 nSize = std::max(aFaceSize.Width, aFaceSize.Height);
1202 const double nScale = mnOuterRadius*2 / nSize;
1203
1204 BitmapDescriptor* aDescriptors[3] = { &maFace, &maHourHand, &maMinuteHand };
1205 for (int nIndex=0; nIndex<3; ++nIndex)
1206 {
1207 BitmapDescriptor& rDescriptor (*aDescriptors[nIndex]);
1208 if ( ! rDescriptor.mxScaledBitmap.is() && rDescriptor.mxBitmap.is())
1209 {
1210 const geometry::IntegerSize2D aBitmapSize (rDescriptor.mxBitmap->getSize());
1211 rDescriptor.mxScaledBitmap = rDescriptor.mxBitmap->getScaledBitmap(
1212 geometry::RealSize2D(aBitmapSize.Width*nScale, aBitmapSize.Height*nScale),
1213 sal_False);
1214 rDescriptor.maScaledOffset = geometry::RealPoint2D(
1215 rDescriptor.maOffset.X * nScale,
1216 rDescriptor.maOffset.Y * nScale);
1217 }
1218 }
1219 }
1220
1221
1222
1223
1224 //===== DigitalDefaultPainter =================================================
1225
DigitalDefaultPainter(const::rtl::Reference<PresenterController> & rpPresenterController,const Reference<XResourceId> & rxViewId)1226 DigitalDefaultPainter::DigitalDefaultPainter (
1227 const ::rtl::Reference<PresenterController>& rpPresenterController,
1228 const Reference<XResourceId>& rxViewId)
1229 : mpPresenterController(rpPresenterController),
1230 mbIs24HourFormat(false),
1231 mbIsAdaptFontSize(true),
1232 mxFont(),
1233 maWindowSize(0,0),
1234 msViewURL(rxViewId.is() ? rxViewId->getResourceURL() : OUString())
1235 {
1236 }
1237
1238
1239
1240
~DigitalDefaultPainter(void)1241 DigitalDefaultPainter::~DigitalDefaultPainter (void)
1242 {
1243 }
1244
1245
1246
1247
Paint(const Reference<rendering::XCanvas> & rxCanvas,const rendering::ViewState & rViewState,const rendering::RenderState & rRenderState,const util::Color & rBackgroundColor,const sal_Int32 nHour,const sal_Int32 nMinute,const sal_Int32 nSecond,const bool bIsShowSeconds)1248 void DigitalDefaultPainter::Paint (
1249 const Reference<rendering::XCanvas>& rxCanvas,
1250 const rendering::ViewState& rViewState,
1251 const rendering::RenderState& rRenderState,
1252 const util::Color& rBackgroundColor,
1253 const sal_Int32 nHour,
1254 const sal_Int32 nMinute,
1255 const sal_Int32 nSecond,
1256 const bool bIsShowSeconds)
1257 {
1258 (void)rBackgroundColor;
1259 (void)rRenderState;
1260
1261 if ( ! mxFont.is())
1262 CreateFont(rxCanvas,bIsShowSeconds);
1263 if ( ! mxFont.is())
1264 return;
1265
1266 OUString sText;
1267
1268 if (mbIs24HourFormat)
1269 sText = OUString::valueOf(nHour);
1270 else
1271 {
1272 sText = OUString::valueOf(nHour>12 ? nHour-12 : nHour);
1273 }
1274 sText += OUString::createFromAscii(":");
1275 const OUString sMinutes (OUString::valueOf(nMinute));
1276 switch (sMinutes.getLength())
1277 {
1278 case 1 :
1279 sText += OUString::createFromAscii("0") + sMinutes;
1280 break;
1281 case 2:
1282 sText += sMinutes;
1283 break;
1284
1285 default:
1286 return;
1287 }
1288 if (bIsShowSeconds)
1289 {
1290 sText += OUString::createFromAscii(":");
1291 const OUString sSeconds (OUString::valueOf(nSecond));
1292 switch (sSeconds.getLength())
1293 {
1294 case 1 :
1295 sText += OUString::createFromAscii("0") + sSeconds;
1296 break;
1297 case 2:
1298 sText += sSeconds;
1299 break;
1300
1301 default:
1302 return;
1303 }
1304 }
1305
1306 rendering::StringContext aContext (
1307 sText,
1308 0,
1309 sText.getLength());
1310 Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1311 aContext,
1312 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1313 0));
1314 if ( ! xLayout.is())
1315 return;
1316 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1317
1318
1319 rendering::RenderState aRenderState(
1320 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1321 NULL,
1322 Sequence<double>(4),
1323 rendering::CompositeOperation::SOURCE);
1324
1325 util::Color aFontColor (mpPresenterController->GetViewFontColor(msViewURL));
1326 PresenterCanvasHelper::SetDeviceColor(aRenderState, aFontColor);
1327 aRenderState.AffineTransform.m02
1328 = (maWindowSize.Width - (aBox.X2-aBox.X1+1)) / 2 - aBox.X1;
1329 aRenderState.AffineTransform.m12
1330 = (maWindowSize.Height - (aBox.Y2-aBox.Y1+1)) / 2 - aBox.Y1;
1331 rxCanvas->drawText(
1332 aContext,
1333 mxFont,
1334 rViewState,
1335 aRenderState,
1336 rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
1337 }
1338
1339
1340
1341
Resize(const awt::Size & rSize)1342 void DigitalDefaultPainter::Resize (const awt::Size& rSize)
1343 {
1344 if (maWindowSize.Width != rSize.Width || maWindowSize.Height != rSize.Height)
1345 {
1346 maWindowSize = rSize;
1347 if (mbIsAdaptFontSize)
1348 mxFont = NULL;
1349 }
1350 }
1351
1352
1353
1354
CreateFont(const Reference<rendering::XCanvas> & rxCanvas,const bool bIsShowSeconds)1355 void DigitalDefaultPainter::CreateFont (
1356 const Reference<rendering::XCanvas>& rxCanvas,
1357 const bool bIsShowSeconds)
1358 {
1359 if (rxCanvas.is()
1360 && rxCanvas->getDevice().is()
1361 && maWindowSize.Width>0
1362 && maWindowSize.Height>0)
1363 {
1364 // Create a time template for determinging the right font size.
1365 // Assume that 0 is the widest digit or that all digits have the
1366 // same width.
1367 OUString sTimeTemplate;
1368 // For the case that not all digits have the same width, create
1369 // different templates for 12 and 24 hour mode.
1370 if (mbIs24HourFormat)
1371 sTimeTemplate = OUString::createFromAscii("20");
1372 else
1373 sTimeTemplate = OUString::createFromAscii("10");
1374 if (bIsShowSeconds)
1375 sTimeTemplate += OUString::createFromAscii(":00:00");
1376 else
1377 sTimeTemplate += OUString::createFromAscii(":00");
1378
1379 rendering::StringContext aContext (
1380 sTimeTemplate,
1381 0,
1382 sTimeTemplate.getLength());
1383
1384 // When the font size is adapted to the window size (as large as
1385 // possible without overlapping) then that is done in a four step
1386 // process:
1387 // 1. Create a font in a default size, e.g. 10pt.
1388 // 2. Determine a scale factor from enlarging the text bounding box
1389 // to maximal size inside the window.
1390 // 3. Create a new font by scaling the default size with the factor
1391 // calculated in step 2.
1392 // 4. Text may be rendered differently in different sizes.
1393 // Therefore repeat step 2 and 3 once. More iterations may lead to
1394 // even better results but probably not to visible differences.
1395 rendering::FontRequest aFontRequest (mpPresenterController->GetViewFontRequest(msViewURL));
1396 // TODO: use font from view style from configuration
1397 aFontRequest.CellSize = 10;
1398
1399 for (sal_Int32 nLoop=0; nLoop<3; ++nLoop)
1400 {
1401 mxFont = rxCanvas->createFont(
1402 aFontRequest,
1403 Sequence<beans::PropertyValue>(),
1404 geometry::Matrix2D(1,0,0,1));
1405 if (mxFont.is())
1406 {
1407 Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1408 aContext,
1409 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1410 0));
1411
1412 if ( ! xLayout.is())
1413 break;
1414
1415 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1416 if (aBox.X2<=aBox.X1 || aBox.Y2<=aBox.Y1)
1417 break;
1418 const double nHorizontalFactor = maWindowSize.Width / (aBox.X2-aBox.X1+1);
1419 const double nVerticalFactor = maWindowSize.Height / (aBox.Y2-aBox.Y1+1);
1420 aFontRequest.CellSize *= ::std::min(nHorizontalFactor,nVerticalFactor);
1421 }
1422 }
1423 }
1424 }
1425
1426
1427 } // end of anonymous namespace
1428
1429
1430 } } // end of namespace ::sdext::presenter
1431