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 {
393 // ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
394 // osl::MutexGuard aGuard (m_aMutex);
395
396 if (rEventObject.Source == mxWindow)
397 {
398 mxWindow = NULL;
399 if (mpTimer != NULL)
400 mpTimer->Stop();
401 }
402 }
403
404
405
406
407 //----- XPaintListener --------------------------------------------------------
408
windowPaint(const awt::PaintEvent & rEvent)409 void SAL_CALL PresenterClock::windowPaint (const awt::PaintEvent& rEvent)
410 {
411 (void)rEvent;
412 ThrowIfDisposed();
413 ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
414 Paint(rEvent.UpdateRect);
415 }
416
417
418
419
420 //----- XWindowListener -------------------------------------------------------
421
windowResized(const awt::WindowEvent & rEvent)422 void SAL_CALL PresenterClock::windowResized (const awt::WindowEvent& rEvent)
423 {
424 (void)rEvent;
425 mbIsResizePending = true;
426 }
427
428
429
430
windowMoved(const awt::WindowEvent & rEvent)431 void SAL_CALL PresenterClock::windowMoved (const awt::WindowEvent& rEvent)
432 {
433 (void)rEvent;
434 mbIsResizePending = true;
435 }
436
437
438
439
windowShown(const lang::EventObject & rEvent)440 void SAL_CALL PresenterClock::windowShown (const lang::EventObject& rEvent)
441 {
442 (void)rEvent;
443 mbIsResizePending = true;
444 }
445
446
447
448
windowHidden(const lang::EventObject & rEvent)449 void SAL_CALL PresenterClock::windowHidden (const lang::EventObject& rEvent)
450 {
451 (void)rEvent;
452 }
453
454
455
456
457 //----- XMouseListener --------------------------------------------------------
458
mousePressed(const css::awt::MouseEvent & rEvent)459 void SAL_CALL PresenterClock::mousePressed (const css::awt::MouseEvent& rEvent)
460 {
461 (void)rEvent;
462 if (rEvent.Buttons == awt::MouseButton::LEFT)
463 {
464 SetMode(mnMode+1);
465 }
466 }
467
468
469
470
mouseReleased(const css::awt::MouseEvent & rEvent)471 void SAL_CALL PresenterClock::mouseReleased (const css::awt::MouseEvent& rEvent)
472 {
473 (void)rEvent;
474 }
475
476
477
478
mouseEntered(const css::awt::MouseEvent & rEvent)479 void SAL_CALL PresenterClock::mouseEntered (const css::awt::MouseEvent& rEvent)
480 {
481 (void)rEvent;
482 }
483
484
485
486
mouseExited(const css::awt::MouseEvent & rEvent)487 void SAL_CALL PresenterClock::mouseExited (const css::awt::MouseEvent& rEvent)
488 {
489 (void)rEvent;
490 }
491
492
493
494
495 //----- XResourceId -----------------------------------------------------------
496
getResourceId(void)497 Reference<XResourceId> SAL_CALL PresenterClock::getResourceId (void)
498 {
499 return mxViewId;
500 }
501
502
503
504
isAnchorOnly(void)505 sal_Bool SAL_CALL PresenterClock::isAnchorOnly (void)
506 {
507 return false;
508 }
509
510
511
512
513 //-----------------------------------------------------------------------------
514
Resize(void)515 void PresenterClock::Resize (void)
516 {
517 if (mxPane.is())
518 mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
519 if (mxWindow.is() && mxCanvas.is())
520 {
521 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
522 const awt::Size aWindowSize(aWindowBox.Width,aWindowBox.Height);
523 if (mpClockPainter.get() != NULL)
524 mpClockPainter->Resize(aWindowSize);
525 if (mpClockPainter2.get() != NULL)
526 mpClockPainter2->Resize(aWindowSize);
527 mbIsResizePending = false;
528 }
529 }
530
531
532
533
Paint(const awt::Rectangle & rUpdateBox)534 void PresenterClock::Paint (const awt::Rectangle& rUpdateBox)
535 {
536 if ( ! mxCanvas.is() && mxPane.is())
537 mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
538 if ( ! mxWindow.is()
539 || ! mxCanvas.is()
540 || ! mxCanvas->getDevice().is())
541 {
542 return;
543 }
544
545 try
546 {
547 if (mbIsResizePending)
548 Resize();
549
550 Reference<rendering::XPolyPolygon2D> xUpdatePolygon (
551 PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
552
553 Clear(xUpdatePolygon);
554
555 if (mpClockPainter.get() != NULL)
556 mpClockPainter->Paint(mxCanvas,
557 maViewState,
558 maRenderState,
559 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
560 mnHour,
561 mnMinute,
562 mnSecond,
563 mbIsShowSeconds);
564
565 if (mpClockPainter2.get() != NULL)
566 mpClockPainter2->Paint(
567 mxCanvas,
568 maViewState,
569 maRenderState,
570 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
571 mnHour,
572 mnMinute,
573 mnSecond,
574 mbIsShowSeconds);
575 }
576 catch (RuntimeException& e)
577 {
578 (void)e;
579 }
580
581 // Make the back buffer visible.
582 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
583 if (xSpriteCanvas.is())
584 xSpriteCanvas->updateScreen(sal_False);
585 }
586
587
588
589
Clear(const Reference<rendering::XPolyPolygon2D> & rxUpdatePolygon)590 void PresenterClock::Clear (const Reference<rendering::XPolyPolygon2D>& rxUpdatePolygon)
591 {
592 rendering::RenderState aRenderState = maRenderState;
593 const sal_Int32 nColor (
594 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()));
595 aRenderState.DeviceColor[0] = ((nColor&0x00ff0000) >> 16) / 255.0;
596 aRenderState.DeviceColor[1] = ((nColor&0x0000ff00) >> 8) / 255.0;
597 aRenderState.DeviceColor[2] = ((nColor&0x000000ff) >> 0) / 255.0;
598
599 if (rxUpdatePolygon.is())
600 mxCanvas->fillPolyPolygon(
601 rxUpdatePolygon,
602 maViewState,
603 aRenderState);
604 }
605
606
607
608
SetMode(const sal_Int32 nMode)609 void PresenterClock::SetMode (const sal_Int32 nMode)
610 {
611 mnMode = nMode % 3;
612
613 switch (mnMode)
614 {
615 case 0:
616 mpClockPainter.reset(
617 new AnalogBitmapPainter(
618 mxComponentContext,
619 OUString::createFromAscii("ClockTheme")));
620 mpClockPainter2.reset();
621 break;
622
623 case 1:
624 mpClockPainter.reset();
625 mpClockPainter2.reset(new AnalogDefaultPainter());
626 break;
627
628 case 2:
629 mpClockPainter.reset();
630 mpClockPainter2.reset(new DigitalDefaultPainter(mpPresenterController, mxViewId));
631 break;
632
633 case 3:
634 mpClockPainter.reset(
635 new AnalogBitmapPainter(
636 mxComponentContext,
637 OUString::createFromAscii("ClockTheme")));
638 mpClockPainter2.reset(new AnalogDefaultPainter());
639 break;
640 }
641 Resize();
642 }
643
644
645
646
ThrowIfDisposed(void)647 void PresenterClock::ThrowIfDisposed (void)
648 {
649 if (rBHelper.bDisposed || rBHelper.bInDispose)
650 {
651 throw lang::DisposedException (
652 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
653 "PresenterClock object has already been disposed")),
654 static_cast<uno::XWeak*>(this));
655 }
656 }
657
658
659
660
661 //===== Timer =================================================================
662
Timer(const::rtl::Reference<PresenterClock> & rpClock)663 PresenterClock::Timer::Timer (const ::rtl::Reference<PresenterClock>& rpClock)
664 : OTimer(vos::TTimeValue(10), vos::TTimeValue(100/*ms*/)),
665 mpClock(rpClock)
666 {
667 acquire();
668 start();
669 }
670
671
672
673
~Timer(void)674 PresenterClock::Timer::~Timer (void)
675 {
676 if (mpClock.is())
677 Stop();
678 }
679
680
681
682
Stop(void)683 void PresenterClock::Timer::Stop (void)
684 {
685 mpClock = NULL;
686 stop();
687 release();
688 }
689
690
691
692
onShot(void)693 void SAL_CALL PresenterClock::Timer::onShot (void)
694 {
695 if (mpClock.get() != NULL)
696 mpClock->UpdateTime();
697 }
698
699
700
701 namespace {
702
703 //=============================================================================
704
GetDateTime(oslDateTime & rDateTime)705 bool GetDateTime (oslDateTime& rDateTime)
706 {
707 TimeValue aSystemTime;
708 TimeValue aLocalTime;
709 if (osl_getSystemTime(&aSystemTime))
710 if (osl_getLocalTimeFromSystemTime(&aSystemTime, &aLocalTime))
711 if (osl_getDateTimeFromTimeValue(&aLocalTime, &rDateTime))
712 return true;
713 return false;
714 }
715
716
717
718
719 //===== AnalogDefaultPainter ==================================================
720
721 const double AnalogDefaultPainter::mnRelativeHourHandLength = 0.65;
722 const double AnalogDefaultPainter::mnRelativeHourHandLength2 (-0.1);
723 const double AnalogDefaultPainter::mnRelativeHourHandWidth (0.055);
724 const double AnalogDefaultPainter::mnRelativeMinuteHandLength (-0.2);
725 const double AnalogDefaultPainter::mnRelativeMinuteHandLength2 (0.85);
726 const double AnalogDefaultPainter::mnRelativeMinuteHandWidth (0.025);
727 const double AnalogDefaultPainter::mnRelativeSecondHandLength (-0.25);
728 const double AnalogDefaultPainter::mnRelativeSecondHandLength2 (0.95);
729 const double AnalogDefaultPainter::mnRelativeSecondHandWidth (0.015);
730
AnalogDefaultPainter(void)731 AnalogDefaultPainter::AnalogDefaultPainter (void)
732 : maCenter(0,0),
733 mnOuterRadius(0),
734 maSize(0,0),
735 mxBitmap()
736 {
737 }
738
739
740
741
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)742 void AnalogDefaultPainter::Paint (
743 const Reference<rendering::XCanvas>& rxCanvas,
744 const rendering::ViewState& rViewState,
745 const rendering::RenderState& rRenderState,
746 const util::Color& rBackgroundColor,
747 const sal_Int32 nHour,
748 const sal_Int32 nMinute,
749 const sal_Int32 nSecond,
750 const bool bShowSeconds)
751 {
752 double nInnerRadius (0);
753 double nStrokeWidth (0.1);
754 const double nClockSize (2*mnOuterRadius);
755
756 // Some antialiasing is created by painting into a bitmap twice the
757 // screen size and then scaling it down.
758 const sal_Int32 nSuperSampleFactor (2);
759 if ( ! mxBitmap.is())
760 {
761 mxBitmap = (rxCanvas->getDevice()->createCompatibleBitmap(
762 geometry::IntegerSize2D(
763 maSize.Width*nSuperSampleFactor,
764 maSize.Height*nSuperSampleFactor)));
765 }
766 Reference<rendering::XCanvas> xBitmapCanvas (mxBitmap, UNO_QUERY);
767 rendering::RenderState aRenderState(rRenderState);
768 aRenderState.AffineTransform.m00 = nSuperSampleFactor;
769 aRenderState.AffineTransform.m11 = nSuperSampleFactor;
770
771 // Clear the background.
772 aRenderState.DeviceColor[0] = ((rBackgroundColor&0x00ff0000) >> 16) / 255.0;
773 aRenderState.DeviceColor[1] = ((rBackgroundColor&0x0000ff00) >> 8) / 255.0;
774 aRenderState.DeviceColor[2] = ((rBackgroundColor&0x000000ff) >> 0) / 255.0;
775 Reference<rendering::XPolyPolygon2D> xPolygon (
776 PresenterGeometryHelper::CreatePolygon(
777 awt::Rectangle(0,0,maSize.Width,maSize.Height),
778 xBitmapCanvas->getDevice()));
779 if (xPolygon.is())
780 xBitmapCanvas->fillPolyPolygon(xPolygon, rViewState, aRenderState);
781
782 // Clock face and clock hands are painted in black.
783 aRenderState.DeviceColor[0] = 0;
784 aRenderState.DeviceColor[1] = 0;
785 aRenderState.DeviceColor[2] = 0;
786
787 // Paint the clock face.
788 for (sal_Int32 nHourMark=0; nHourMark<12; ++nHourMark)
789 {
790 if (nHourMark%3 == 0)
791 {
792 nInnerRadius = 0.7 * mnOuterRadius;
793 nStrokeWidth = 0.05 * nClockSize;
794 }
795 else
796 {
797 nInnerRadius = 0.8 * mnOuterRadius;
798 nStrokeWidth = 0.03 * nClockSize;
799 }
800
801 const double nAngle (nHourMark * 2 * M_PI / 12);
802 PaintAngledLine(nAngle, nInnerRadius, mnOuterRadius, nStrokeWidth,
803 xBitmapCanvas, rViewState, aRenderState);
804 }
805
806 // Paint the hour hand.
807 const double nHoursAngle (((nHour%12)+nMinute/60.0) * 2 * M_PI / 12);
808 PaintAngledLine(nHoursAngle,
809 mnRelativeHourHandLength2*mnOuterRadius,
810 mnRelativeHourHandLength*mnOuterRadius,
811 mnRelativeHourHandWidth*nClockSize,
812 xBitmapCanvas, rViewState, aRenderState);
813
814 // Paint the minute hand.
815 const double nMinutesAngle ((nMinute+nSecond/60.0) * 2 * M_PI / 60);
816 PaintAngledLine(nMinutesAngle,
817 mnRelativeMinuteHandLength2*mnOuterRadius,
818 mnRelativeMinuteHandLength*mnOuterRadius,
819 mnRelativeMinuteHandWidth*nClockSize,
820 xBitmapCanvas, rViewState, aRenderState);
821
822 // Optionally paint the second hand.
823 if (bShowSeconds)
824 {
825 const double nSecondsAngle (nSecond * 2 * M_PI / 60);
826 PaintAngledLine(nSecondsAngle,
827 mnRelativeSecondHandLength2*mnOuterRadius,
828 mnRelativeSecondHandLength*mnOuterRadius,
829 mnRelativeSecondHandWidth*nClockSize,
830 xBitmapCanvas, rViewState, aRenderState);
831 }
832
833 aRenderState.AffineTransform.m00 = 1.0 / nSuperSampleFactor;
834 aRenderState.AffineTransform.m11 = 1.0 / nSuperSampleFactor;
835 rxCanvas->drawBitmap(mxBitmap,rViewState,aRenderState);
836 }
837
838
839
840
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)841 void AnalogDefaultPainter::PaintAngledLine (
842 const double nAngle,
843 const double nInnerRadius,
844 const double nOuterRadius,
845 const double nStrokeWidth,
846 const Reference<rendering::XCanvas>& rxCanvas,
847 const rendering::ViewState& rViewState,
848 const rendering::RenderState& rRenderState)
849 {
850 if ( ! rxCanvas.is())
851 return;
852
853 rendering::StrokeAttributes aStrokeAttributes;
854 aStrokeAttributes.StrokeWidth = nStrokeWidth;
855 aStrokeAttributes.StartCapType = rendering::PathCapType::SQUARE;
856 aStrokeAttributes.EndCapType = rendering::PathCapType::SQUARE;
857 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
858 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
859 const double nCos (cos(nAngle - M_PI/2));
860 const double nSin (sin(nAngle - M_PI/2));
861
862 Sequence<Sequence<geometry::RealPoint2D> > aPoints(1);
863 aPoints[0] = Sequence<geometry::RealPoint2D>(2);
864 aPoints[0][0] = geometry::RealPoint2D(
865 maCenter.X + nInnerRadius*nCos + 0.5,
866 maCenter.Y + nInnerRadius*nSin + 0.5);
867 aPoints[0][1] = geometry::RealPoint2D(
868 maCenter.X + nOuterRadius*nCos + 0.5,
869 maCenter.Y + nOuterRadius*nSin + 0.5);
870
871 Reference<rendering::XPolyPolygon2D> xLine (
872 rxCanvas->getDevice()->createCompatibleLinePolyPolygon(aPoints),
873 UNO_QUERY);
874 if ( ! xLine.is())
875 return;
876 rxCanvas->strokePolyPolygon(
877 xLine,
878 rViewState,
879 rRenderState,
880 aStrokeAttributes);
881 }
882
883
884
885
Resize(const awt::Size & rWindowSize)886 void AnalogDefaultPainter::Resize (const awt::Size& rWindowSize)
887 {
888 maSize = rWindowSize;
889 maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
890 mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
891 mxBitmap = NULL;
892 }
893
894
895
896
897 //===== AnalogBitmapPainter ===================================================
898
AnalogBitmapPainter(const Reference<XComponentContext> & rxContext,const OUString & rsThemeName)899 AnalogBitmapPainter::AnalogBitmapPainter (
900 const Reference<XComponentContext>& rxContext,
901 const OUString& rsThemeName)
902 : mxComponentContext(rxContext),
903 msThemeName(rsThemeName),
904 mbThemeLoaded(false),
905 mbThemeLoadingFailed(false),
906 maCenter(),
907 mnOuterRadius(),
908 maFace(),
909 maMinuteHand(),
910 maHourHand()
911 {
912 }
913
914
915
916
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)917 void AnalogBitmapPainter::Paint (
918 const Reference<rendering::XCanvas>& rxCanvas,
919 const rendering::ViewState& rViewState,
920 const rendering::RenderState& rRenderState,
921 const util::Color& rBackgroundColor,
922 const sal_Int32 nHour,
923 const sal_Int32 nMinute,
924 const sal_Int32 nSecond,
925 const bool bShowSeconds)
926 {
927 (void)rBackgroundColor;
928 (void)nSecond;
929 (void)bShowSeconds;
930
931 if ( ! rxCanvas.is())
932 return;
933
934 rendering::RenderState aRenderState = rRenderState;
935
936 try
937 {
938 PrepareBitmaps(rxCanvas);
939
940 if (maFace.mxScaledBitmap.is())
941 {
942 aRenderState.AffineTransform = geometry::AffineMatrix2D(
943 1,0, maCenter.X - maFace.maScaledOffset.X,
944 0,1, maCenter.Y - maFace.maScaledOffset.Y);
945 rxCanvas->drawBitmap(maFace.mxScaledBitmap, rViewState, aRenderState);
946 }
947
948 if (maMinuteHand.mxScaledBitmap.is())
949 {
950 const double nMinuteAngle ((nMinute+nSecond/60.0) * 2.0 * M_PI / 60.0);
951 const double nCos (cos(nMinuteAngle - M_PI/2));
952 const double nSin (sin(nMinuteAngle - M_PI/2));
953 aRenderState.AffineTransform = geometry::AffineMatrix2D(
954 nCos,
955 -nSin,
956 -maMinuteHand.maScaledOffset.X*nCos
957 + maMinuteHand.maScaledOffset.Y*nSin+maCenter.X,
958 nSin,
959 nCos,
960 -maMinuteHand.maScaledOffset.X*nSin
961 - maMinuteHand.maScaledOffset.Y*nCos+maCenter.Y);
962 rxCanvas->drawBitmap(maMinuteHand.mxScaledBitmap, rViewState, aRenderState);
963 }
964
965 if (maHourHand.mxScaledBitmap.is())
966 {
967 const double nHoursAngle ((nHour%12+nMinute/60.0) * 2.0 * M_PI / 12.0);
968 const double nCos (cos(nHoursAngle - M_PI/2));
969 const double nSin (sin(nHoursAngle - M_PI/2));
970 aRenderState.AffineTransform = geometry::AffineMatrix2D(
971 nCos,
972 -nSin,
973 -maHourHand.maScaledOffset.X*nCos+maHourHand.maScaledOffset.Y*nSin+maCenter.X,
974 nSin,
975 nCos,
976 -maHourHand.maScaledOffset.X*nSin-maHourHand.maScaledOffset.Y*nCos+maCenter.Y);
977 rxCanvas->drawBitmap(maHourHand.mxScaledBitmap, rViewState, aRenderState);
978 }
979 }
980 catch(beans::UnknownPropertyException&)
981 {
982 }
983 catch(RuntimeException&)
984 {
985 }
986 }
987
988
989
990
Resize(const awt::Size & rWindowSize)991 void AnalogBitmapPainter::Resize (const awt::Size& rWindowSize)
992 {
993 maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
994 mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
995 maFace.mxScaledBitmap = NULL;
996 maHourHand.mxScaledBitmap = NULL;
997 maMinuteHand.mxScaledBitmap = NULL;
998 }
999
1000
1001
1002
PrepareBitmaps(const Reference<rendering::XCanvas> & rxCanvas)1003 void AnalogBitmapPainter::PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas)
1004 {
1005 if (mbThemeLoadingFailed)
1006 {
1007 // Theme loading has failed previously. Do not try a second time.
1008 return;
1009 }
1010 if ( ! rxCanvas.is())
1011 {
1012 // No canvas => bitmaps can neither be loaded, transformed into the
1013 // right format, nor can they be painted.
1014 return;
1015 }
1016
1017 if ( ! mbThemeLoaded)
1018 {
1019 mbThemeLoaded = true;
1020
1021 // Get access to the clock bitmaps in the configuration.
1022 PresenterConfigurationAccess aConfiguration (
1023 mxComponentContext,
1024 OUString::createFromAscii("org.openoffice.Office.PresenterScreen"),
1025 PresenterConfigurationAccess::READ_ONLY);
1026
1027 Reference<container::XNameAccess> xTheme (GetTheme(aConfiguration));
1028 if (xTheme.is())
1029 LoadBitmaps(aConfiguration, xTheme, rxCanvas);
1030 else
1031 mbThemeLoadingFailed = true;
1032 }
1033
1034 ScaleBitmaps();
1035 }
1036
1037
1038
1039
GetTheme(PresenterConfigurationAccess & rConfiguration)1040 Reference<container::XNameAccess> AnalogBitmapPainter::GetTheme (
1041 PresenterConfigurationAccess& rConfiguration)
1042 {
1043 Reference<container::XNameAccess> xTheme;
1044
1045 // Get root of clock themes.
1046 Reference<container::XHierarchicalNameAccess> xClock (
1047 rConfiguration.GetConfigurationNode(
1048 OUString::createFromAscii("PresenterScreenSettings/AnalogBitmapClock")),
1049 UNO_QUERY);
1050
1051 // Determine the name of the theme to use.
1052 OUString sCurrentThemeName (OUString::createFromAscii("DefaultTheme"));
1053 rConfiguration.GetConfigurationNode(
1054 xClock,
1055 OUString::createFromAscii("CurrentTheme")) >>= sCurrentThemeName;
1056
1057 // Load the clock theme.
1058 Reference<container::XNameAccess> xThemes (
1059 rConfiguration.GetConfigurationNode(
1060 xClock,
1061 OUString::createFromAscii("Themes")),
1062 UNO_QUERY);
1063 if (xThemes.is())
1064 {
1065 xTheme = Reference<container::XNameAccess>(
1066 PresenterConfigurationAccess::Find(
1067 xThemes,
1068 ::boost::bind(&AnalogBitmapPainter::ThemeNameComparator,
1069 this, _1, _2, sCurrentThemeName)),
1070 UNO_QUERY);
1071 }
1072
1073 return xTheme;
1074 }
1075
1076
1077
1078
ThemeNameComparator(const OUString & rsKey,const Reference<container::XNameAccess> & rxCandidate,const OUString & rsCurrentThemeName)1079 bool AnalogBitmapPainter::ThemeNameComparator (
1080 const OUString& rsKey,
1081 const Reference<container::XNameAccess>& rxCandidate,
1082 const OUString& rsCurrentThemeName)
1083 {
1084 (void)rsKey;
1085 if (rxCandidate.is())
1086 {
1087 OUString sThemeName;
1088 if (rxCandidate->getByName(OUString::createFromAscii("ThemeName")) >>= sThemeName)
1089 {
1090 return sThemeName == rsCurrentThemeName;
1091 }
1092 }
1093 return false;
1094 }
1095
1096
1097
1098
1099
LoadBitmaps(PresenterConfigurationAccess & rConfiguration,const Reference<container::XNameAccess> & rxClockTheme,const Reference<rendering::XCanvas> & rxCanvas)1100 void AnalogBitmapPainter::LoadBitmaps (
1101 PresenterConfigurationAccess& rConfiguration,
1102 const Reference<container::XNameAccess>& rxClockTheme,
1103 const Reference<rendering::XCanvas>& rxCanvas)
1104 {
1105 (void)rConfiguration;
1106 // Create the bitmap loader.
1107 Reference<lang::XMultiComponentFactory> xFactory (
1108 mxComponentContext->getServiceManager(), UNO_QUERY);
1109 if ( ! xFactory.is())
1110 return;
1111 Sequence<Any> aArguments(1);
1112 aArguments[0] <<= rxCanvas;
1113 Reference<container::XNameAccess> xBitmapLoader(
1114 xFactory->createInstanceWithArgumentsAndContext(
1115 OUString::createFromAscii("com.sun.star.drawing.PresenterWorkaroundService"),
1116 aArguments,
1117 mxComponentContext),
1118 UNO_QUERY);
1119 if ( ! xBitmapLoader.is())
1120 return;
1121
1122
1123 // Iterate over all entries in the bitmap list and load the bitmaps.
1124 Reference<container::XNameAccess> xBitmaps (
1125 rxClockTheme->getByName(OUString::createFromAscii("Bitmaps")),
1126 UNO_QUERY);
1127 ::std::vector<rtl::OUString> aBitmapProperties (3);
1128 aBitmapProperties[0] = OUString::createFromAscii("FileName");
1129 aBitmapProperties[1] = OUString::createFromAscii("XOffset");
1130 aBitmapProperties[2] = OUString::createFromAscii("YOffset");
1131 PresenterConfigurationAccess::ForAll(
1132 xBitmaps,
1133 aBitmapProperties,
1134 ::boost::bind(&AnalogBitmapPainter::LoadBitmap,
1135 this,
1136 _1,
1137 _2,
1138 xBitmapLoader));
1139 }
1140
1141
1142
1143
LoadBitmap(const OUString & rsKey,const::std::vector<Any> & rValues,const Reference<container::XNameAccess> & rxBitmapLoader)1144 void AnalogBitmapPainter::LoadBitmap (
1145 const OUString& rsKey,
1146 const ::std::vector<Any>& rValues,
1147 const Reference<container::XNameAccess>& rxBitmapLoader)
1148 {
1149 if (rValues.size() == 3)
1150 {
1151 BitmapDescriptor* pDescriptor = NULL;
1152 if (rsKey == OUString::createFromAscii("Face"))
1153 pDescriptor = &maFace;
1154 else if (rsKey == OUString::createFromAscii("HourHand"))
1155 pDescriptor = &maHourHand;
1156 else if (rsKey == OUString::createFromAscii("MinuteHand"))
1157 pDescriptor = &maMinuteHand;
1158
1159 if (pDescriptor == NULL)
1160 return;
1161
1162 OUString sFileName;
1163 if ( ! (rValues[0] >>= sFileName))
1164 return;
1165
1166 rValues[1] >>= pDescriptor->maOffset.X;
1167 rValues[2] >>= pDescriptor->maOffset.Y;
1168
1169 pDescriptor->mxBitmap = Reference<rendering::XBitmap>(
1170 rxBitmapLoader->getByName(sFileName), UNO_QUERY);
1171
1172 if ( ! pDescriptor->mxBitmap.is())
1173 mbThemeLoadingFailed = true;
1174 }
1175 }
1176
1177
1178
1179
ScaleBitmaps(void)1180 void AnalogBitmapPainter::ScaleBitmaps (void)
1181 {
1182 if (mbThemeLoadingFailed)
1183 return;
1184 if ( ! maFace.mxBitmap.is())
1185 return;
1186
1187 const geometry::IntegerSize2D aFaceSize (maFace.mxBitmap->getSize());
1188 const sal_Int32 nSize = std::max(aFaceSize.Width, aFaceSize.Height);
1189 const double nScale = mnOuterRadius*2 / nSize;
1190
1191 BitmapDescriptor* aDescriptors[3] = { &maFace, &maHourHand, &maMinuteHand };
1192 for (int nIndex=0; nIndex<3; ++nIndex)
1193 {
1194 BitmapDescriptor& rDescriptor (*aDescriptors[nIndex]);
1195 if ( ! rDescriptor.mxScaledBitmap.is() && rDescriptor.mxBitmap.is())
1196 {
1197 const geometry::IntegerSize2D aBitmapSize (rDescriptor.mxBitmap->getSize());
1198 rDescriptor.mxScaledBitmap = rDescriptor.mxBitmap->getScaledBitmap(
1199 geometry::RealSize2D(aBitmapSize.Width*nScale, aBitmapSize.Height*nScale),
1200 sal_False);
1201 rDescriptor.maScaledOffset = geometry::RealPoint2D(
1202 rDescriptor.maOffset.X * nScale,
1203 rDescriptor.maOffset.Y * nScale);
1204 }
1205 }
1206 }
1207
1208
1209
1210
1211 //===== DigitalDefaultPainter =================================================
1212
DigitalDefaultPainter(const::rtl::Reference<PresenterController> & rpPresenterController,const Reference<XResourceId> & rxViewId)1213 DigitalDefaultPainter::DigitalDefaultPainter (
1214 const ::rtl::Reference<PresenterController>& rpPresenterController,
1215 const Reference<XResourceId>& rxViewId)
1216 : mpPresenterController(rpPresenterController),
1217 mbIs24HourFormat(false),
1218 mbIsAdaptFontSize(true),
1219 mxFont(),
1220 maWindowSize(0,0),
1221 msViewURL(rxViewId.is() ? rxViewId->getResourceURL() : OUString())
1222 {
1223 }
1224
1225
1226
1227
~DigitalDefaultPainter(void)1228 DigitalDefaultPainter::~DigitalDefaultPainter (void)
1229 {
1230 }
1231
1232
1233
1234
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)1235 void DigitalDefaultPainter::Paint (
1236 const Reference<rendering::XCanvas>& rxCanvas,
1237 const rendering::ViewState& rViewState,
1238 const rendering::RenderState& rRenderState,
1239 const util::Color& rBackgroundColor,
1240 const sal_Int32 nHour,
1241 const sal_Int32 nMinute,
1242 const sal_Int32 nSecond,
1243 const bool bIsShowSeconds)
1244 {
1245 (void)rBackgroundColor;
1246 (void)rRenderState;
1247
1248 if ( ! mxFont.is())
1249 CreateFont(rxCanvas,bIsShowSeconds);
1250 if ( ! mxFont.is())
1251 return;
1252
1253 OUString sText;
1254
1255 if (mbIs24HourFormat)
1256 sText = OUString::valueOf(nHour);
1257 else
1258 {
1259 sText = OUString::valueOf(nHour>12 ? nHour-12 : nHour);
1260 }
1261 sText += OUString::createFromAscii(":");
1262 const OUString sMinutes (OUString::valueOf(nMinute));
1263 switch (sMinutes.getLength())
1264 {
1265 case 1 :
1266 sText += OUString::createFromAscii("0") + sMinutes;
1267 break;
1268 case 2:
1269 sText += sMinutes;
1270 break;
1271
1272 default:
1273 return;
1274 }
1275 if (bIsShowSeconds)
1276 {
1277 sText += OUString::createFromAscii(":");
1278 const OUString sSeconds (OUString::valueOf(nSecond));
1279 switch (sSeconds.getLength())
1280 {
1281 case 1 :
1282 sText += OUString::createFromAscii("0") + sSeconds;
1283 break;
1284 case 2:
1285 sText += sSeconds;
1286 break;
1287
1288 default:
1289 return;
1290 }
1291 }
1292
1293 rendering::StringContext aContext (
1294 sText,
1295 0,
1296 sText.getLength());
1297 Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1298 aContext,
1299 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1300 0));
1301 if ( ! xLayout.is())
1302 return;
1303 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1304
1305
1306 rendering::RenderState aRenderState(
1307 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1308 NULL,
1309 Sequence<double>(4),
1310 rendering::CompositeOperation::SOURCE);
1311
1312 util::Color aFontColor (mpPresenterController->GetViewFontColor(msViewURL));
1313 PresenterCanvasHelper::SetDeviceColor(aRenderState, aFontColor);
1314 aRenderState.AffineTransform.m02
1315 = (maWindowSize.Width - (aBox.X2-aBox.X1+1)) / 2 - aBox.X1;
1316 aRenderState.AffineTransform.m12
1317 = (maWindowSize.Height - (aBox.Y2-aBox.Y1+1)) / 2 - aBox.Y1;
1318 rxCanvas->drawText(
1319 aContext,
1320 mxFont,
1321 rViewState,
1322 aRenderState,
1323 rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
1324 }
1325
1326
1327
1328
Resize(const awt::Size & rSize)1329 void DigitalDefaultPainter::Resize (const awt::Size& rSize)
1330 {
1331 if (maWindowSize.Width != rSize.Width || maWindowSize.Height != rSize.Height)
1332 {
1333 maWindowSize = rSize;
1334 if (mbIsAdaptFontSize)
1335 mxFont = NULL;
1336 }
1337 }
1338
1339
1340
1341
CreateFont(const Reference<rendering::XCanvas> & rxCanvas,const bool bIsShowSeconds)1342 void DigitalDefaultPainter::CreateFont (
1343 const Reference<rendering::XCanvas>& rxCanvas,
1344 const bool bIsShowSeconds)
1345 {
1346 if (rxCanvas.is()
1347 && rxCanvas->getDevice().is()
1348 && maWindowSize.Width>0
1349 && maWindowSize.Height>0)
1350 {
1351 // Create a time template for determinging the right font size.
1352 // Assume that 0 is the widest digit or that all digits have the
1353 // same width.
1354 OUString sTimeTemplate;
1355 // For the case that not all digits have the same width, create
1356 // different templates for 12 and 24 hour mode.
1357 if (mbIs24HourFormat)
1358 sTimeTemplate = OUString::createFromAscii("20");
1359 else
1360 sTimeTemplate = OUString::createFromAscii("10");
1361 if (bIsShowSeconds)
1362 sTimeTemplate += OUString::createFromAscii(":00:00");
1363 else
1364 sTimeTemplate += OUString::createFromAscii(":00");
1365
1366 rendering::StringContext aContext (
1367 sTimeTemplate,
1368 0,
1369 sTimeTemplate.getLength());
1370
1371 // When the font size is adapted to the window size (as large as
1372 // possible without overlapping) then that is done in a four step
1373 // process:
1374 // 1. Create a font in a default size, e.g. 10pt.
1375 // 2. Determine a scale factor from enlarging the text bounding box
1376 // to maximal size inside the window.
1377 // 3. Create a new font by scaling the default size with the factor
1378 // calculated in step 2.
1379 // 4. Text may be rendered differently in different sizes.
1380 // Therefore repeat step 2 and 3 once. More iterations may lead to
1381 // even better results but probably not to visible differences.
1382 rendering::FontRequest aFontRequest (mpPresenterController->GetViewFontRequest(msViewURL));
1383 // TODO: use font from view style from configuration
1384 aFontRequest.CellSize = 10;
1385
1386 for (sal_Int32 nLoop=0; nLoop<3; ++nLoop)
1387 {
1388 mxFont = rxCanvas->createFont(
1389 aFontRequest,
1390 Sequence<beans::PropertyValue>(),
1391 geometry::Matrix2D(1,0,0,1));
1392 if (mxFont.is())
1393 {
1394 Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1395 aContext,
1396 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1397 0));
1398
1399 if ( ! xLayout.is())
1400 break;
1401
1402 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1403 if (aBox.X2<=aBox.X1 || aBox.Y2<=aBox.Y1)
1404 break;
1405 const double nHorizontalFactor = maWindowSize.Width / (aBox.X2-aBox.X1+1);
1406 const double nVerticalFactor = maWindowSize.Height / (aBox.Y2-aBox.Y1+1);
1407 aFontRequest.CellSize *= ::std::min(nHorizontalFactor,nVerticalFactor);
1408 }
1409 }
1410 }
1411 }
1412
1413
1414 } // end of anonymous namespace
1415
1416
1417 } } // end of namespace ::sdext::presenter
1418