| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sdext.hxx" |
| |
| #include "PresenterClock.hxx" |
| #include "PresenterConfigurationAccess.hxx" |
| #include "PresenterGeometryHelper.hxx" |
| #include <com/sun/star/awt/InvalidateStyle.hpp> |
| #include <com/sun/star/awt/MouseButton.hpp> |
| #include <com/sun/star/awt/Point.hpp> |
| #include <com/sun/star/awt/XWindowPeer.hpp> |
| #include <com/sun/star/container/XNameAccess.hpp> |
| #include <com/sun/star/deployment/XPackageInformationProvider.hpp> |
| #include <com/sun/star/drawing/framework/XControllerManager.hpp> |
| #include <com/sun/star/drawing/framework/XConfigurationController.hpp> |
| #include <com/sun/star/rendering/CompositeOperation.hpp> |
| #include <com/sun/star/rendering/PathCapType.hpp> |
| #include <com/sun/star/rendering/TextDirection.hpp> |
| #include <com/sun/star/rendering/XCanvasFont.hpp> |
| #include <com/sun/star/rendering/XSpriteCanvas.hpp> |
| #include <com/sun/star/util/Color.hpp> |
| #include <osl/mutex.hxx> |
| #include <osl/time.h> |
| #include <rtl/ref.hxx> |
| #include <vos/timer.hxx> |
| #include <boost/bind.hpp> |
| #include <cmath> |
| |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::drawing::framework; |
| using ::rtl::OUString; |
| |
| namespace sdext { namespace presenter { |
| |
| |
| /** Wrapper around a library timer. |
| */ |
| class PresenterClock::Timer : public vos::OTimer |
| { |
| public: |
| explicit Timer (const ::rtl::Reference<PresenterClock>& rpClock); |
| virtual ~Timer (void); |
| |
| void Stop (void); |
| |
| protected: |
| virtual void SAL_CALL onShot (void); |
| |
| private: |
| ::rtl::Reference<PresenterClock> mpClock; |
| }; |
| |
| |
| |
| |
| namespace { |
| bool GetDateTime (oslDateTime& rDateTime); |
| |
| class BitmapDescriptor |
| { |
| public: |
| Reference<rendering::XBitmap> mxBitmap; |
| awt::Point maOffset; |
| Reference<rendering::XBitmap> mxScaledBitmap; |
| geometry::RealPoint2D maScaledOffset; |
| }; |
| } |
| |
| |
| |
| |
| class PresenterClock::Painter |
| { |
| public: |
| virtual void 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) = 0; |
| virtual void Resize (const awt::Size& rSize) = 0; |
| }; |
| |
| |
| |
| |
| namespace { |
| class AnalogDefaultPainter : public PresenterClock::Painter |
| { |
| public: |
| AnalogDefaultPainter (void); |
| virtual ~AnalogDefaultPainter (void) {} |
| virtual void 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); |
| virtual void Resize (const awt::Size& rSize); |
| private: |
| geometry::RealPoint2D maCenter; |
| double mnOuterRadius; |
| awt::Size maSize; |
| Reference<rendering::XBitmap> mxBitmap; |
| |
| /** Relative length (with respect to radius) from center to the tip of |
| the hand. |
| */ |
| static const double mnRelativeHourHandLength; |
| /** Relative length (with respect to radius) from center to the |
| oposing end of the tip of the hand. |
| */ |
| static const double mnRelativeHourHandLength2; |
| static const double mnRelativeHourHandWidth; |
| static const double mnRelativeMinuteHandLength; |
| static const double mnRelativeMinuteHandLength2; |
| static const double mnRelativeMinuteHandWidth; |
| static const double mnRelativeSecondHandLength; |
| static const double mnRelativeSecondHandLength2; |
| static const double mnRelativeSecondHandWidth; |
| |
| void 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); |
| }; |
| |
| |
| class AnalogBitmapPainter : public PresenterClock::Painter |
| { |
| public: |
| AnalogBitmapPainter( |
| const Reference<XComponentContext>& rxContext, |
| const OUString& rsThemeName); |
| virtual ~AnalogBitmapPainter (void) {} |
| virtual void 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); |
| virtual void Resize (const awt::Size& rSize); |
| private: |
| css::uno::Reference<css::uno::XComponentContext> mxComponentContext; |
| const OUString msThemeName; |
| bool mbThemeLoaded; |
| bool mbThemeLoadingFailed; |
| geometry::RealPoint2D maCenter; |
| double mnOuterRadius; |
| BitmapDescriptor maFace; |
| BitmapDescriptor maMinuteHand; |
| BitmapDescriptor maHourHand; |
| |
| void PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas); |
| Reference<container::XNameAccess> GetTheme ( |
| PresenterConfigurationAccess& rConfiguration); |
| bool ThemeNameComparator ( |
| const ::rtl::OUString& rsKey, |
| const Reference<container::XNameAccess>& rxCandidate, |
| const ::rtl::OUString& rsCurrentThemeName); |
| void LoadBitmaps ( |
| PresenterConfigurationAccess& rConfiguration, |
| const Reference<container::XNameAccess>& rxNameAccess, |
| const Reference<rendering::XCanvas>& rxCanvas); |
| void LoadBitmap ( |
| const OUString& rsKey, |
| const ::std::vector<Any>& rValues, |
| const Reference<container::XNameAccess>& rxBitmapLoader); |
| void ScaleBitmaps (void); |
| }; |
| |
| |
| class DigitalDefaultPainter : public PresenterClock::Painter |
| { |
| public: |
| DigitalDefaultPainter ( |
| const ::rtl::Reference<PresenterController>& rpPresenterController, |
| const Reference<XResourceId>& rxViewId); |
| virtual ~DigitalDefaultPainter (void); |
| |
| virtual void 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); |
| virtual void Resize (const awt::Size& rSize); |
| |
| private: |
| ::rtl::Reference<PresenterController> mpPresenterController; |
| bool mbIs24HourFormat; |
| bool mbIsAdaptFontSize; |
| Reference<rendering::XCanvasFont> mxFont; |
| awt::Size maWindowSize; |
| OUString msViewURL; |
| |
| void CreateFont ( |
| const Reference<rendering::XCanvas>& rxCanvas, |
| const bool bIsShowSeconds); |
| }; |
| |
| |
| } // end of anonymous namespace |
| |
| |
| |
| |
| //===== PresenterClock ================================================================= |
| |
| ::rtl::Reference<PresenterClock> PresenterClock::Create ( |
| const Reference<XComponentContext>& rxContext, |
| const Reference<XResourceId>& rxViewId, |
| const Reference<frame::XController>& rxController, |
| const ::rtl::Reference<PresenterController>& rpPresenterController) |
| { |
| ::rtl::Reference<PresenterClock> pClock (new PresenterClock( |
| rxContext, |
| rxViewId, |
| rxController, |
| rpPresenterController)); |
| pClock->LateInit(); |
| return pClock; |
| } |
| |
| |
| |
| |
| PresenterClock::PresenterClock ( |
| const Reference<XComponentContext>& rxContext, |
| const Reference<XResourceId>& rxViewId, |
| const Reference<frame::XController>& rxController, |
| const ::rtl::Reference<PresenterController>& rpPresenterController) |
| : PresenterClockInterfaceBase(m_aMutex), |
| mxComponentContext(rxContext), |
| mxViewId(rxViewId), |
| mxWindow(), |
| mxCanvas(), |
| mxPane(), |
| mpPresenterController(rpPresenterController), |
| mbIsResizePending(true), |
| maViewState(), |
| maRenderState(), |
| mpTimer(), |
| mpClockPainter(), |
| mpClockPainter2(), |
| mnMode(1), |
| mnHour(-1), |
| mnMinute(-1), |
| mnSecond(-1), |
| mbIsShowSeconds(true) |
| { |
| SetMode(mnMode); |
| |
| maViewState.AffineTransform = geometry::AffineMatrix2D(1,0,0, 0,1,0); |
| maRenderState.AffineTransform = geometry::AffineMatrix2D(1,0,0, 0,1,0); |
| maRenderState.DeviceColor = Sequence<double>(4); |
| PresenterCanvasHelper::SetDeviceColor(maRenderState, util::Color(0x00000000)); |
| |
| try |
| { |
| |
| Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW); |
| Reference<XConfigurationController> xCC (xCM->getConfigurationController(), UNO_QUERY_THROW); |
| mxPane = Reference<XPane>(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW); |
| |
| mxWindow = mxPane->getWindow(); |
| if (mxWindow.is()) |
| { |
| mxWindow->addPaintListener(this); |
| mxWindow->addWindowListener(this); |
| mxWindow->addMouseListener(this); |
| Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY); |
| if (xPeer.is()) |
| xPeer->setBackground(util::Color(0xff000000)); |
| mxWindow->setVisible(sal_True); |
| } |
| |
| Resize(); |
| } |
| catch (RuntimeException&) |
| { |
| disposing(); |
| throw; |
| } |
| } |
| |
| |
| |
| |
| PresenterClock::~PresenterClock (void) |
| { |
| } |
| |
| |
| |
| |
| void PresenterClock::LateInit (void) |
| { |
| mpTimer = new Timer(this); |
| } |
| |
| |
| |
| |
| void SAL_CALL PresenterClock::disposing (void) |
| { |
| // osl::MutexGuard aGuard (m_aMutex); |
| if (mpTimer != NULL) |
| { |
| mpTimer->Stop(); |
| } |
| if (mxWindow.is()) |
| { |
| mxWindow->removePaintListener(this); |
| mxWindow->removeWindowListener(this); |
| mxWindow->removeMouseListener(this); |
| mxWindow = NULL; |
| } |
| mxCanvas = NULL; |
| mxViewId = NULL; |
| } |
| |
| |
| |
| |
| void PresenterClock::UpdateTime (void) |
| { |
| // Get current time and check whether it is different from last time. |
| oslDateTime aDateTime; |
| if ( ! GetDateTime(aDateTime)) |
| return; |
| if (aDateTime.Hours != mnHour |
| || aDateTime.Minutes != mnMinute |
| || aDateTime.Seconds != mnSecond) |
| { |
| mnHour = aDateTime.Hours % 24; |
| mnMinute = aDateTime.Minutes % 60; |
| mnSecond = aDateTime.Seconds % 60; |
| |
| Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY); |
| if (xPeer.is()) |
| xPeer->invalidate(awt::InvalidateStyle::NOERASE | |
| awt::InvalidateStyle::UPDATE); |
| } |
| } |
| |
| |
| |
| |
| //----- lang::XEventListener ------------------------------------------------- |
| |
| void SAL_CALL PresenterClock::disposing (const lang::EventObject& rEventObject) |
| throw (RuntimeException) |
| { |
| // ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex()); |
| // osl::MutexGuard aGuard (m_aMutex); |
| |
| if (rEventObject.Source == mxWindow) |
| { |
| mxWindow = NULL; |
| if (mpTimer != NULL) |
| mpTimer->Stop(); |
| } |
| } |
| |
| |
| |
| |
| //----- XPaintListener -------------------------------------------------------- |
| |
| void SAL_CALL PresenterClock::windowPaint (const awt::PaintEvent& rEvent) |
| throw (RuntimeException) |
| { |
| (void)rEvent; |
| ThrowIfDisposed(); |
| ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex()); |
| Paint(rEvent.UpdateRect); |
| } |
| |
| |
| |
| |
| //----- XWindowListener ------------------------------------------------------- |
| |
| void SAL_CALL PresenterClock::windowResized (const awt::WindowEvent& rEvent) |
| throw (RuntimeException) |
| { |
| (void)rEvent; |
| mbIsResizePending = true; |
| } |
| |
| |
| |
| |
| void SAL_CALL PresenterClock::windowMoved (const awt::WindowEvent& rEvent) |
| throw (RuntimeException) |
| { |
| (void)rEvent; |
| mbIsResizePending = true; |
| } |
| |
| |
| |
| |
| void SAL_CALL PresenterClock::windowShown (const lang::EventObject& rEvent) |
| throw (RuntimeException) |
| { |
| (void)rEvent; |
| mbIsResizePending = true; |
| } |
| |
| |
| |
| |
| void SAL_CALL PresenterClock::windowHidden (const lang::EventObject& rEvent) |
| throw (RuntimeException) |
| { |
| (void)rEvent; |
| } |
| |
| |
| |
| |
| //----- XMouseListener -------------------------------------------------------- |
| |
| void SAL_CALL PresenterClock::mousePressed (const css::awt::MouseEvent& rEvent) |
| throw (css::uno::RuntimeException) |
| { |
| (void)rEvent; |
| if (rEvent.Buttons == awt::MouseButton::LEFT) |
| { |
| SetMode(mnMode+1); |
| } |
| } |
| |
| |
| |
| |
| void SAL_CALL PresenterClock::mouseReleased (const css::awt::MouseEvent& rEvent) |
| throw (css::uno::RuntimeException) |
| { |
| (void)rEvent; |
| } |
| |
| |
| |
| |
| void SAL_CALL PresenterClock::mouseEntered (const css::awt::MouseEvent& rEvent) |
| throw (css::uno::RuntimeException) |
| { |
| (void)rEvent; |
| } |
| |
| |
| |
| |
| void SAL_CALL PresenterClock::mouseExited (const css::awt::MouseEvent& rEvent) |
| throw (css::uno::RuntimeException) |
| { |
| (void)rEvent; |
| } |
| |
| |
| |
| |
| //----- XResourceId ----------------------------------------------------------- |
| |
| Reference<XResourceId> SAL_CALL PresenterClock::getResourceId (void) |
| throw (RuntimeException) |
| { |
| return mxViewId; |
| } |
| |
| |
| |
| |
| sal_Bool SAL_CALL PresenterClock::isAnchorOnly (void) |
| throw (RuntimeException) |
| { |
| return false; |
| } |
| |
| |
| |
| |
| //----------------------------------------------------------------------------- |
| |
| void PresenterClock::Resize (void) |
| { |
| if (mxPane.is()) |
| mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY); |
| if (mxWindow.is() && mxCanvas.is()) |
| { |
| const awt::Rectangle aWindowBox (mxWindow->getPosSize()); |
| const awt::Size aWindowSize(aWindowBox.Width,aWindowBox.Height); |
| if (mpClockPainter.get() != NULL) |
| mpClockPainter->Resize(aWindowSize); |
| if (mpClockPainter2.get() != NULL) |
| mpClockPainter2->Resize(aWindowSize); |
| mbIsResizePending = false; |
| } |
| } |
| |
| |
| |
| |
| void PresenterClock::Paint (const awt::Rectangle& rUpdateBox) |
| { |
| if ( ! mxCanvas.is() && mxPane.is()) |
| mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY); |
| if ( ! mxWindow.is() |
| || ! mxCanvas.is() |
| || ! mxCanvas->getDevice().is()) |
| { |
| return; |
| } |
| |
| try |
| { |
| if (mbIsResizePending) |
| Resize(); |
| |
| Reference<rendering::XPolyPolygon2D> xUpdatePolygon ( |
| PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice())); |
| |
| Clear(xUpdatePolygon); |
| |
| if (mpClockPainter.get() != NULL) |
| mpClockPainter->Paint(mxCanvas, |
| maViewState, |
| maRenderState, |
| mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()), |
| mnHour, |
| mnMinute, |
| mnSecond, |
| mbIsShowSeconds); |
| |
| if (mpClockPainter2.get() != NULL) |
| mpClockPainter2->Paint( |
| mxCanvas, |
| maViewState, |
| maRenderState, |
| mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()), |
| mnHour, |
| mnMinute, |
| mnSecond, |
| mbIsShowSeconds); |
| } |
| catch (RuntimeException& e) |
| { |
| (void)e; |
| } |
| |
| // Make the back buffer visible. |
| Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); |
| if (xSpriteCanvas.is()) |
| xSpriteCanvas->updateScreen(sal_False); |
| } |
| |
| |
| |
| |
| void PresenterClock::Clear (const Reference<rendering::XPolyPolygon2D>& rxUpdatePolygon) |
| { |
| rendering::RenderState aRenderState = maRenderState; |
| const sal_Int32 nColor ( |
| mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL())); |
| aRenderState.DeviceColor[0] = ((nColor&0x00ff0000) >> 16) / 255.0; |
| aRenderState.DeviceColor[1] = ((nColor&0x0000ff00) >> 8) / 255.0; |
| aRenderState.DeviceColor[2] = ((nColor&0x000000ff) >> 0) / 255.0; |
| |
| if (rxUpdatePolygon.is()) |
| mxCanvas->fillPolyPolygon( |
| rxUpdatePolygon, |
| maViewState, |
| aRenderState); |
| } |
| |
| |
| |
| |
| void PresenterClock::SetMode (const sal_Int32 nMode) |
| { |
| mnMode = nMode % 3; |
| |
| switch (mnMode) |
| { |
| case 0: |
| mpClockPainter.reset( |
| new AnalogBitmapPainter( |
| mxComponentContext, |
| OUString::createFromAscii("ClockTheme"))); |
| mpClockPainter2.reset(); |
| break; |
| |
| case 1: |
| mpClockPainter.reset(); |
| mpClockPainter2.reset(new AnalogDefaultPainter()); |
| break; |
| |
| case 2: |
| mpClockPainter.reset(); |
| mpClockPainter2.reset(new DigitalDefaultPainter(mpPresenterController, mxViewId)); |
| break; |
| |
| case 3: |
| mpClockPainter.reset( |
| new AnalogBitmapPainter( |
| mxComponentContext, |
| OUString::createFromAscii("ClockTheme"))); |
| mpClockPainter2.reset(new AnalogDefaultPainter()); |
| break; |
| } |
| Resize(); |
| } |
| |
| |
| |
| |
| void PresenterClock::ThrowIfDisposed (void) |
| throw (::com::sun::star::lang::DisposedException) |
| { |
| if (rBHelper.bDisposed || rBHelper.bInDispose) |
| { |
| throw lang::DisposedException ( |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "PresenterClock object has already been disposed")), |
| static_cast<uno::XWeak*>(this)); |
| } |
| } |
| |
| |
| |
| |
| //===== Timer ================================================================= |
| |
| PresenterClock::Timer::Timer (const ::rtl::Reference<PresenterClock>& rpClock) |
| : OTimer(vos::TTimeValue(10), vos::TTimeValue(100/*ms*/)), |
| mpClock(rpClock) |
| { |
| acquire(); |
| start(); |
| } |
| |
| |
| |
| |
| PresenterClock::Timer::~Timer (void) |
| { |
| if (mpClock.is()) |
| Stop(); |
| } |
| |
| |
| |
| |
| void PresenterClock::Timer::Stop (void) |
| { |
| mpClock = NULL; |
| stop(); |
| release(); |
| } |
| |
| |
| |
| |
| void SAL_CALL PresenterClock::Timer::onShot (void) |
| { |
| if (mpClock.get() != NULL) |
| mpClock->UpdateTime(); |
| } |
| |
| |
| |
| namespace { |
| |
| //============================================================================= |
| |
| bool GetDateTime (oslDateTime& rDateTime) |
| { |
| TimeValue aSystemTime; |
| TimeValue aLocalTime; |
| if (osl_getSystemTime(&aSystemTime)) |
| if (osl_getLocalTimeFromSystemTime(&aSystemTime, &aLocalTime)) |
| if (osl_getDateTimeFromTimeValue(&aLocalTime, &rDateTime)) |
| return true; |
| return false; |
| } |
| |
| |
| |
| |
| //===== AnalogDefaultPainter ================================================== |
| |
| const double AnalogDefaultPainter::mnRelativeHourHandLength = 0.65; |
| const double AnalogDefaultPainter::mnRelativeHourHandLength2 (-0.1); |
| const double AnalogDefaultPainter::mnRelativeHourHandWidth (0.055); |
| const double AnalogDefaultPainter::mnRelativeMinuteHandLength (-0.2); |
| const double AnalogDefaultPainter::mnRelativeMinuteHandLength2 (0.85); |
| const double AnalogDefaultPainter::mnRelativeMinuteHandWidth (0.025); |
| const double AnalogDefaultPainter::mnRelativeSecondHandLength (-0.25); |
| const double AnalogDefaultPainter::mnRelativeSecondHandLength2 (0.95); |
| const double AnalogDefaultPainter::mnRelativeSecondHandWidth (0.015); |
| |
| AnalogDefaultPainter::AnalogDefaultPainter (void) |
| : maCenter(0,0), |
| mnOuterRadius(0), |
| maSize(0,0), |
| mxBitmap() |
| { |
| } |
| |
| |
| |
| |
| void AnalogDefaultPainter::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) |
| { |
| double nInnerRadius (0); |
| double nStrokeWidth (0.1); |
| const double nClockSize (2*mnOuterRadius); |
| |
| // Some antialiasing is created by painting into a bitmap twice the |
| // screen size and then scaling it down. |
| const sal_Int32 nSuperSampleFactor (2); |
| if ( ! mxBitmap.is()) |
| { |
| mxBitmap = (rxCanvas->getDevice()->createCompatibleBitmap( |
| geometry::IntegerSize2D( |
| maSize.Width*nSuperSampleFactor, |
| maSize.Height*nSuperSampleFactor))); |
| } |
| Reference<rendering::XCanvas> xBitmapCanvas (mxBitmap, UNO_QUERY); |
| rendering::RenderState aRenderState(rRenderState); |
| aRenderState.AffineTransform.m00 = nSuperSampleFactor; |
| aRenderState.AffineTransform.m11 = nSuperSampleFactor; |
| |
| // Clear the background. |
| aRenderState.DeviceColor[0] = ((rBackgroundColor&0x00ff0000) >> 16) / 255.0; |
| aRenderState.DeviceColor[1] = ((rBackgroundColor&0x0000ff00) >> 8) / 255.0; |
| aRenderState.DeviceColor[2] = ((rBackgroundColor&0x000000ff) >> 0) / 255.0; |
| Reference<rendering::XPolyPolygon2D> xPolygon ( |
| PresenterGeometryHelper::CreatePolygon( |
| awt::Rectangle(0,0,maSize.Width,maSize.Height), |
| xBitmapCanvas->getDevice())); |
| if (xPolygon.is()) |
| xBitmapCanvas->fillPolyPolygon(xPolygon, rViewState, aRenderState); |
| |
| // Clock face and clock hands are painted in black. |
| aRenderState.DeviceColor[0] = 0; |
| aRenderState.DeviceColor[1] = 0; |
| aRenderState.DeviceColor[2] = 0; |
| |
| // Paint the clock face. |
| for (sal_Int32 nHourMark=0; nHourMark<12; ++nHourMark) |
| { |
| if (nHourMark%3 == 0) |
| { |
| nInnerRadius = 0.7 * mnOuterRadius; |
| nStrokeWidth = 0.05 * nClockSize; |
| } |
| else |
| { |
| nInnerRadius = 0.8 * mnOuterRadius; |
| nStrokeWidth = 0.03 * nClockSize; |
| } |
| |
| const double nAngle (nHourMark * 2 * M_PI / 12); |
| PaintAngledLine(nAngle, nInnerRadius, mnOuterRadius, nStrokeWidth, |
| xBitmapCanvas, rViewState, aRenderState); |
| } |
| |
| // Paint the hour hand. |
| const double nHoursAngle (((nHour%12)+nMinute/60.0) * 2 * M_PI / 12); |
| PaintAngledLine(nHoursAngle, |
| mnRelativeHourHandLength2*mnOuterRadius, |
| mnRelativeHourHandLength*mnOuterRadius, |
| mnRelativeHourHandWidth*nClockSize, |
| xBitmapCanvas, rViewState, aRenderState); |
| |
| // Paint the minute hand. |
| const double nMinutesAngle ((nMinute+nSecond/60.0) * 2 * M_PI / 60); |
| PaintAngledLine(nMinutesAngle, |
| mnRelativeMinuteHandLength2*mnOuterRadius, |
| mnRelativeMinuteHandLength*mnOuterRadius, |
| mnRelativeMinuteHandWidth*nClockSize, |
| xBitmapCanvas, rViewState, aRenderState); |
| |
| // Optionally paint the second hand. |
| if (bShowSeconds) |
| { |
| const double nSecondsAngle (nSecond * 2 * M_PI / 60); |
| PaintAngledLine(nSecondsAngle, |
| mnRelativeSecondHandLength2*mnOuterRadius, |
| mnRelativeSecondHandLength*mnOuterRadius, |
| mnRelativeSecondHandWidth*nClockSize, |
| xBitmapCanvas, rViewState, aRenderState); |
| } |
| |
| aRenderState.AffineTransform.m00 = 1.0 / nSuperSampleFactor; |
| aRenderState.AffineTransform.m11 = 1.0 / nSuperSampleFactor; |
| rxCanvas->drawBitmap(mxBitmap,rViewState,aRenderState); |
| } |
| |
| |
| |
| |
| void AnalogDefaultPainter::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) |
| { |
| if ( ! rxCanvas.is()) |
| return; |
| |
| rendering::StrokeAttributes aStrokeAttributes; |
| aStrokeAttributes.StrokeWidth = nStrokeWidth; |
| aStrokeAttributes.StartCapType = rendering::PathCapType::SQUARE; |
| aStrokeAttributes.EndCapType = rendering::PathCapType::SQUARE; |
| aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; |
| aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; |
| const double nCos (cos(nAngle - M_PI/2)); |
| const double nSin (sin(nAngle - M_PI/2)); |
| |
| Sequence<Sequence<geometry::RealPoint2D> > aPoints(1); |
| aPoints[0] = Sequence<geometry::RealPoint2D>(2); |
| aPoints[0][0] = geometry::RealPoint2D( |
| maCenter.X + nInnerRadius*nCos + 0.5, |
| maCenter.Y + nInnerRadius*nSin + 0.5); |
| aPoints[0][1] = geometry::RealPoint2D( |
| maCenter.X + nOuterRadius*nCos + 0.5, |
| maCenter.Y + nOuterRadius*nSin + 0.5); |
| |
| Reference<rendering::XPolyPolygon2D> xLine ( |
| rxCanvas->getDevice()->createCompatibleLinePolyPolygon(aPoints), |
| UNO_QUERY); |
| if ( ! xLine.is()) |
| return; |
| rxCanvas->strokePolyPolygon( |
| xLine, |
| rViewState, |
| rRenderState, |
| aStrokeAttributes); |
| } |
| |
| |
| |
| |
| void AnalogDefaultPainter::Resize (const awt::Size& rWindowSize) |
| { |
| maSize = rWindowSize; |
| maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0); |
| mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2; |
| mxBitmap = NULL; |
| } |
| |
| |
| |
| |
| //===== AnalogBitmapPainter =================================================== |
| |
| AnalogBitmapPainter::AnalogBitmapPainter ( |
| const Reference<XComponentContext>& rxContext, |
| const OUString& rsThemeName) |
| : mxComponentContext(rxContext), |
| msThemeName(rsThemeName), |
| mbThemeLoaded(false), |
| mbThemeLoadingFailed(false), |
| maCenter(), |
| mnOuterRadius(), |
| maFace(), |
| maMinuteHand(), |
| maHourHand() |
| { |
| } |
| |
| |
| |
| |
| void AnalogBitmapPainter::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) |
| { |
| (void)rBackgroundColor; |
| (void)nSecond; |
| (void)bShowSeconds; |
| |
| if ( ! rxCanvas.is()) |
| return; |
| |
| rendering::RenderState aRenderState = rRenderState; |
| |
| try |
| { |
| PrepareBitmaps(rxCanvas); |
| |
| if (maFace.mxScaledBitmap.is()) |
| { |
| aRenderState.AffineTransform = geometry::AffineMatrix2D( |
| 1,0, maCenter.X - maFace.maScaledOffset.X, |
| 0,1, maCenter.Y - maFace.maScaledOffset.Y); |
| rxCanvas->drawBitmap(maFace.mxScaledBitmap, rViewState, aRenderState); |
| } |
| |
| if (maMinuteHand.mxScaledBitmap.is()) |
| { |
| const double nMinuteAngle ((nMinute+nSecond/60.0) * 2.0 * M_PI / 60.0); |
| const double nCos (cos(nMinuteAngle - M_PI/2)); |
| const double nSin (sin(nMinuteAngle - M_PI/2)); |
| aRenderState.AffineTransform = geometry::AffineMatrix2D( |
| nCos, |
| -nSin, |
| -maMinuteHand.maScaledOffset.X*nCos |
| + maMinuteHand.maScaledOffset.Y*nSin+maCenter.X, |
| nSin, |
| nCos, |
| -maMinuteHand.maScaledOffset.X*nSin |
| - maMinuteHand.maScaledOffset.Y*nCos+maCenter.Y); |
| rxCanvas->drawBitmap(maMinuteHand.mxScaledBitmap, rViewState, aRenderState); |
| } |
| |
| if (maHourHand.mxScaledBitmap.is()) |
| { |
| const double nHoursAngle ((nHour%12+nMinute/60.0) * 2.0 * M_PI / 12.0); |
| const double nCos (cos(nHoursAngle - M_PI/2)); |
| const double nSin (sin(nHoursAngle - M_PI/2)); |
| aRenderState.AffineTransform = geometry::AffineMatrix2D( |
| nCos, |
| -nSin, |
| -maHourHand.maScaledOffset.X*nCos+maHourHand.maScaledOffset.Y*nSin+maCenter.X, |
| nSin, |
| nCos, |
| -maHourHand.maScaledOffset.X*nSin-maHourHand.maScaledOffset.Y*nCos+maCenter.Y); |
| rxCanvas->drawBitmap(maHourHand.mxScaledBitmap, rViewState, aRenderState); |
| } |
| } |
| catch(beans::UnknownPropertyException&) |
| { |
| } |
| catch(RuntimeException&) |
| { |
| } |
| } |
| |
| |
| |
| |
| void AnalogBitmapPainter::Resize (const awt::Size& rWindowSize) |
| { |
| maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0); |
| mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2; |
| maFace.mxScaledBitmap = NULL; |
| maHourHand.mxScaledBitmap = NULL; |
| maMinuteHand.mxScaledBitmap = NULL; |
| } |
| |
| |
| |
| |
| void AnalogBitmapPainter::PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas) |
| { |
| if (mbThemeLoadingFailed) |
| { |
| // Theme loading has failed previously. Do not try a second time. |
| return; |
| } |
| if ( ! rxCanvas.is()) |
| { |
| // No canvas => bitmaps can neither be loaded, transformed into the |
| // right format, nor can they be painted. |
| return; |
| } |
| |
| if ( ! mbThemeLoaded) |
| { |
| mbThemeLoaded = true; |
| |
| // Get access to the clock bitmaps in the configuration. |
| PresenterConfigurationAccess aConfiguration ( |
| mxComponentContext, |
| OUString::createFromAscii("org.openoffice.Office.PresenterScreen"), |
| PresenterConfigurationAccess::READ_ONLY); |
| |
| Reference<container::XNameAccess> xTheme (GetTheme(aConfiguration)); |
| if (xTheme.is()) |
| LoadBitmaps(aConfiguration, xTheme, rxCanvas); |
| else |
| mbThemeLoadingFailed = true; |
| } |
| |
| ScaleBitmaps(); |
| } |
| |
| |
| |
| |
| Reference<container::XNameAccess> AnalogBitmapPainter::GetTheme ( |
| PresenterConfigurationAccess& rConfiguration) |
| { |
| Reference<container::XNameAccess> xTheme; |
| |
| // Get root of clock themes. |
| Reference<container::XHierarchicalNameAccess> xClock ( |
| rConfiguration.GetConfigurationNode( |
| OUString::createFromAscii("PresenterScreenSettings/AnalogBitmapClock")), |
| UNO_QUERY); |
| |
| // Determine the name of the theme to use. |
| OUString sCurrentThemeName (OUString::createFromAscii("DefaultTheme")); |
| rConfiguration.GetConfigurationNode( |
| xClock, |
| OUString::createFromAscii("CurrentTheme")) >>= sCurrentThemeName; |
| |
| // Load the clock theme. |
| Reference<container::XNameAccess> xThemes ( |
| rConfiguration.GetConfigurationNode( |
| xClock, |
| OUString::createFromAscii("Themes")), |
| UNO_QUERY); |
| if (xThemes.is()) |
| { |
| xTheme = Reference<container::XNameAccess>( |
| PresenterConfigurationAccess::Find( |
| xThemes, |
| ::boost::bind(&AnalogBitmapPainter::ThemeNameComparator, |
| this, _1, _2, sCurrentThemeName)), |
| UNO_QUERY); |
| } |
| |
| return xTheme; |
| } |
| |
| |
| |
| |
| bool AnalogBitmapPainter::ThemeNameComparator ( |
| const OUString& rsKey, |
| const Reference<container::XNameAccess>& rxCandidate, |
| const OUString& rsCurrentThemeName) |
| { |
| (void)rsKey; |
| if (rxCandidate.is()) |
| { |
| OUString sThemeName; |
| if (rxCandidate->getByName(OUString::createFromAscii("ThemeName")) >>= sThemeName) |
| { |
| return sThemeName == rsCurrentThemeName; |
| } |
| } |
| return false; |
| } |
| |
| |
| |
| |
| |
| void AnalogBitmapPainter::LoadBitmaps ( |
| PresenterConfigurationAccess& rConfiguration, |
| const Reference<container::XNameAccess>& rxClockTheme, |
| const Reference<rendering::XCanvas>& rxCanvas) |
| { |
| (void)rConfiguration; |
| // Create the bitmap loader. |
| Reference<lang::XMultiComponentFactory> xFactory ( |
| mxComponentContext->getServiceManager(), UNO_QUERY); |
| if ( ! xFactory.is()) |
| return; |
| Sequence<Any> aArguments(1); |
| aArguments[0] <<= rxCanvas; |
| Reference<container::XNameAccess> xBitmapLoader( |
| xFactory->createInstanceWithArgumentsAndContext( |
| OUString::createFromAscii("com.sun.star.drawing.PresenterWorkaroundService"), |
| aArguments, |
| mxComponentContext), |
| UNO_QUERY); |
| if ( ! xBitmapLoader.is()) |
| return; |
| |
| |
| // Iterate over all entries in the bitmap list and load the bitmaps. |
| Reference<container::XNameAccess> xBitmaps ( |
| rxClockTheme->getByName(OUString::createFromAscii("Bitmaps")), |
| UNO_QUERY); |
| ::std::vector<rtl::OUString> aBitmapProperties (3); |
| aBitmapProperties[0] = OUString::createFromAscii("FileName"); |
| aBitmapProperties[1] = OUString::createFromAscii("XOffset"); |
| aBitmapProperties[2] = OUString::createFromAscii("YOffset"); |
| PresenterConfigurationAccess::ForAll( |
| xBitmaps, |
| aBitmapProperties, |
| ::boost::bind(&AnalogBitmapPainter::LoadBitmap, |
| this, |
| _1, |
| _2, |
| xBitmapLoader)); |
| } |
| |
| |
| |
| |
| void AnalogBitmapPainter::LoadBitmap ( |
| const OUString& rsKey, |
| const ::std::vector<Any>& rValues, |
| const Reference<container::XNameAccess>& rxBitmapLoader) |
| { |
| if (rValues.size() == 3) |
| { |
| BitmapDescriptor* pDescriptor = NULL; |
| if (rsKey == OUString::createFromAscii("Face")) |
| pDescriptor = &maFace; |
| else if (rsKey == OUString::createFromAscii("HourHand")) |
| pDescriptor = &maHourHand; |
| else if (rsKey == OUString::createFromAscii("MinuteHand")) |
| pDescriptor = &maMinuteHand; |
| |
| if (pDescriptor == NULL) |
| return; |
| |
| OUString sFileName; |
| if ( ! (rValues[0] >>= sFileName)) |
| return; |
| |
| rValues[1] >>= pDescriptor->maOffset.X; |
| rValues[2] >>= pDescriptor->maOffset.Y; |
| |
| pDescriptor->mxBitmap = Reference<rendering::XBitmap>( |
| rxBitmapLoader->getByName(sFileName), UNO_QUERY); |
| |
| if ( ! pDescriptor->mxBitmap.is()) |
| mbThemeLoadingFailed = true; |
| } |
| } |
| |
| |
| |
| |
| void AnalogBitmapPainter::ScaleBitmaps (void) |
| { |
| if (mbThemeLoadingFailed) |
| return; |
| if ( ! maFace.mxBitmap.is()) |
| return; |
| |
| const geometry::IntegerSize2D aFaceSize (maFace.mxBitmap->getSize()); |
| const sal_Int32 nSize = std::max(aFaceSize.Width, aFaceSize.Height); |
| const double nScale = mnOuterRadius*2 / nSize; |
| |
| BitmapDescriptor* aDescriptors[3] = { &maFace, &maHourHand, &maMinuteHand }; |
| for (int nIndex=0; nIndex<3; ++nIndex) |
| { |
| BitmapDescriptor& rDescriptor (*aDescriptors[nIndex]); |
| if ( ! rDescriptor.mxScaledBitmap.is() && rDescriptor.mxBitmap.is()) |
| { |
| const geometry::IntegerSize2D aBitmapSize (rDescriptor.mxBitmap->getSize()); |
| rDescriptor.mxScaledBitmap = rDescriptor.mxBitmap->getScaledBitmap( |
| geometry::RealSize2D(aBitmapSize.Width*nScale, aBitmapSize.Height*nScale), |
| sal_False); |
| rDescriptor.maScaledOffset = geometry::RealPoint2D( |
| rDescriptor.maOffset.X * nScale, |
| rDescriptor.maOffset.Y * nScale); |
| } |
| } |
| } |
| |
| |
| |
| |
| //===== DigitalDefaultPainter ================================================= |
| |
| DigitalDefaultPainter::DigitalDefaultPainter ( |
| const ::rtl::Reference<PresenterController>& rpPresenterController, |
| const Reference<XResourceId>& rxViewId) |
| : mpPresenterController(rpPresenterController), |
| mbIs24HourFormat(false), |
| mbIsAdaptFontSize(true), |
| mxFont(), |
| maWindowSize(0,0), |
| msViewURL(rxViewId.is() ? rxViewId->getResourceURL() : OUString()) |
| { |
| } |
| |
| |
| |
| |
| DigitalDefaultPainter::~DigitalDefaultPainter (void) |
| { |
| } |
| |
| |
| |
| |
| void DigitalDefaultPainter::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) |
| { |
| (void)rBackgroundColor; |
| (void)rRenderState; |
| |
| if ( ! mxFont.is()) |
| CreateFont(rxCanvas,bIsShowSeconds); |
| if ( ! mxFont.is()) |
| return; |
| |
| OUString sText; |
| |
| if (mbIs24HourFormat) |
| sText = OUString::valueOf(nHour); |
| else |
| { |
| sText = OUString::valueOf(nHour>12 ? nHour-12 : nHour); |
| } |
| sText += OUString::createFromAscii(":"); |
| const OUString sMinutes (OUString::valueOf(nMinute)); |
| switch (sMinutes.getLength()) |
| { |
| case 1 : |
| sText += OUString::createFromAscii("0") + sMinutes; |
| break; |
| case 2: |
| sText += sMinutes; |
| break; |
| |
| default: |
| return; |
| } |
| if (bIsShowSeconds) |
| { |
| sText += OUString::createFromAscii(":"); |
| const OUString sSeconds (OUString::valueOf(nSecond)); |
| switch (sSeconds.getLength()) |
| { |
| case 1 : |
| sText += OUString::createFromAscii("0") + sSeconds; |
| break; |
| case 2: |
| sText += sSeconds; |
| break; |
| |
| default: |
| return; |
| } |
| } |
| |
| rendering::StringContext aContext ( |
| sText, |
| 0, |
| sText.getLength()); |
| Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout( |
| aContext, |
| rendering::TextDirection::WEAK_LEFT_TO_RIGHT, |
| 0)); |
| if ( ! xLayout.is()) |
| return; |
| geometry::RealRectangle2D aBox (xLayout->queryTextBounds()); |
| |
| |
| rendering::RenderState aRenderState( |
| geometry::AffineMatrix2D(1,0,0, 0,1,0), |
| NULL, |
| Sequence<double>(4), |
| rendering::CompositeOperation::SOURCE); |
| |
| util::Color aFontColor (mpPresenterController->GetViewFontColor(msViewURL)); |
| PresenterCanvasHelper::SetDeviceColor(aRenderState, aFontColor); |
| aRenderState.AffineTransform.m02 |
| = (maWindowSize.Width - (aBox.X2-aBox.X1+1)) / 2 - aBox.X1; |
| aRenderState.AffineTransform.m12 |
| = (maWindowSize.Height - (aBox.Y2-aBox.Y1+1)) / 2 - aBox.Y1; |
| rxCanvas->drawText( |
| aContext, |
| mxFont, |
| rViewState, |
| aRenderState, |
| rendering::TextDirection::WEAK_LEFT_TO_RIGHT); |
| } |
| |
| |
| |
| |
| void DigitalDefaultPainter::Resize (const awt::Size& rSize) |
| { |
| if (maWindowSize.Width != rSize.Width || maWindowSize.Height != rSize.Height) |
| { |
| maWindowSize = rSize; |
| if (mbIsAdaptFontSize) |
| mxFont = NULL; |
| } |
| } |
| |
| |
| |
| |
| void DigitalDefaultPainter::CreateFont ( |
| const Reference<rendering::XCanvas>& rxCanvas, |
| const bool bIsShowSeconds) |
| { |
| if (rxCanvas.is() |
| && rxCanvas->getDevice().is() |
| && maWindowSize.Width>0 |
| && maWindowSize.Height>0) |
| { |
| // Create a time template for determinging the right font size. |
| // Assume that 0 is the widest digit or that all digits have the |
| // same width. |
| OUString sTimeTemplate; |
| // For the case that not all digits have the same width, create |
| // different templates for 12 and 24 hour mode. |
| if (mbIs24HourFormat) |
| sTimeTemplate = OUString::createFromAscii("20"); |
| else |
| sTimeTemplate = OUString::createFromAscii("10"); |
| if (bIsShowSeconds) |
| sTimeTemplate += OUString::createFromAscii(":00:00"); |
| else |
| sTimeTemplate += OUString::createFromAscii(":00"); |
| |
| rendering::StringContext aContext ( |
| sTimeTemplate, |
| 0, |
| sTimeTemplate.getLength()); |
| |
| // When the font size is adapted to the window size (as large as |
| // possible without overlapping) then that is done in a four step |
| // process: |
| // 1. Create a font in a default size, e.g. 10pt. |
| // 2. Determine a scale factor from enlarging the text bounding box |
| // to maximal size inside the window. |
| // 3. Create a new font by scaling the default size with the factor |
| // calculated in step 2. |
| // 4. Text may be rendered differently in different sizes. |
| // Therefore repeat step 2 and 3 once. More iterations may lead to |
| // even better results but probably not to visible differences. |
| rendering::FontRequest aFontRequest (mpPresenterController->GetViewFontRequest(msViewURL)); |
| // TODO: use font from view style from configuration |
| aFontRequest.CellSize = 10; |
| |
| for (sal_Int32 nLoop=0; nLoop<3; ++nLoop) |
| { |
| mxFont = rxCanvas->createFont( |
| aFontRequest, |
| Sequence<beans::PropertyValue>(), |
| geometry::Matrix2D(1,0,0,1)); |
| if (mxFont.is()) |
| { |
| Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout( |
| aContext, |
| rendering::TextDirection::WEAK_LEFT_TO_RIGHT, |
| 0)); |
| |
| if ( ! xLayout.is()) |
| break; |
| |
| geometry::RealRectangle2D aBox (xLayout->queryTextBounds()); |
| if (aBox.X2<=aBox.X1 || aBox.Y2<=aBox.Y1) |
| break; |
| const double nHorizontalFactor = maWindowSize.Width / (aBox.X2-aBox.X1+1); |
| const double nVerticalFactor = maWindowSize.Height / (aBox.Y2-aBox.Y1+1); |
| aFontRequest.CellSize *= ::std::min(nHorizontalFactor,nVerticalFactor); |
| } |
| } |
| } |
| } |
| |
| |
| } // end of anonymous namespace |
| |
| |
| } } // end of namespace ::sdext::presenter |